diff --git a/fakesmc/FakeSMC-Info.plist b/fakesmc/FakeSMC-Info.plist new file mode 100644 index 0000000..06aca0f --- /dev/null +++ b/fakesmc/FakeSMC-Info.plist @@ -0,0 +1,254 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + IOKitPersonalities + + SMC Device Emulator + + CFBundleIdentifier + org.netkas.${PRODUCT_NAME} + Configuration + + Keys + + $Num + + ui8 + + AQ== + + + ACID + + ch8* + + ur48RcADEEM= + + + ALI0 + + {ali + + BgECAA== + + + ALRV + + ui16 + + AAE= + + + ALV0 + + {alv + + AQEDtwCjABVq9A== + + + CLKH + + {clh + + AABwgAABGUA= + + + CLKT + + ui32 + + AAByGw== + + + EPCI + + flag + + AQ== + + + FNum + + ui8 + + AA== + + + LSOF + + flag + + AQ== + + + LSSB + + {lso + + AQE= + + + LsNM + + ui8 + + AQ== + + + LsbV + + {rev + + AQQKAAY= + + + MOST + + ui16 + + gAM= + + + MSDW + + ui8 + + AQ== + + + MSPS + + {msp + + AA== + + + MSSD + + si8 + + Aw== + + + NATJ + + ui8 + + AA== + + + NATi + + ui16 + 0000 + + NTOK + + ui8 + + AQ== + + + NVPR + + ui8 + + AA== + + + OSK0 + + ch8* + + b3VyaGFyZHdvcmtieXRoZXNld29y + ZHNndWFyZGVkcGw= + + + OSK1 + + ch8* + + ZWFzZWRvbnRzdGVhbChjKUFwcGxl + Q29tcHV0ZXJJbmM= + + + REV + + {rev + + ATAPAAAD + + + RGEN + + ui8 + + Ag== + + + RMde + + char + + QQ== + + + RPlt + + ch8* + m82 + + + debug + + smc-compatible + smc-napa + + IOClass + ${PRODUCT_NAME} + IOMatchCategory + IOACPIPlatformDevice + IOProviderClass + AppleACPIPlatformExpert + IOResourceMatch + ACPI + + + OSBundleCompatibleVersion + 3.3.0 + OSBundleLibraries + + com.apple.iokit.IOACPIFamily + 1.0.0d1 + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.mach + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + + OSBundleRequired + Root + + diff --git a/fakesmc/FakeSMC-pre106-info.plist b/fakesmc/FakeSMC-pre106-info.plist new file mode 100644 index 0000000..9582045 --- /dev/null +++ b/fakesmc/FakeSMC-pre106-info.plist @@ -0,0 +1,140 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleName + ${PRODUCT_NAME} + CFBundleIdentifier + org.netkas.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + 3.3.1 + CFBundleSignature + ???? + CFBundleVersion + 3.3.1 + IOKitPersonalities + + SMC Device Emulator + + CFBundleIdentifier + org.netkas.${PRODUCT_NAME} + IOClass + ${PRODUCT_NAME} + IOMatchCategory + IOACPIPlatformDevice + IOProviderClass + AppleACPIPlatformExpert + IOResourceMatch + ACPI + Configuration + + smc-compatible + smc-napa + debug + + Keys + + ACID + + ch8* + ur48RcADEEM= + + CLKT + + ui32 + AAByGw== + + CLKH + + {clh + AABwgAABGUA= + + LSOF + + flag + AQ== + + LSSB + + {lso + AQE= + + MOST + + ui16 + gAM= + + MSSD + + si8 + Aw== + + MSPS + + {msp + AA== + + NATJ + + ui8 + AA== + + NATi + + ui16 + 0000 + + NTOK + + ui8 + AQ== + + NVPR + + ui8 + AA== + + OSK0 + + ch8* + b3VyaGFyZHdvcmtieXRoZXNld29yZHNndWFyZGVkcGw= + + OSK1 + + ch8* + ZWFzZWRvbnRzdGVhbChjKUFwcGxlQ29tcHV0ZXJJbmM= + + REV + + {rev + ATAPAAAD + + + + + + OSBundleLibraries + + com.apple.iokit.IOACPIFamily + 1.0.0d1 + com.apple.kernel.6.0 + 7.9.9 + com.apple.kernel.iokit + 7.9.9 + com.apple.kernel.libkern + 7.9.9 + + OSBundleCompatibleVersion + 3.3.0 + OSBundleRequired + Root + + diff --git a/fakesmc/FakeSMC.cpp b/fakesmc/FakeSMC.cpp new file mode 100644 index 0000000..d3e79d5 --- /dev/null +++ b/fakesmc/FakeSMC.cpp @@ -0,0 +1,56 @@ +#include "FakeSMC.h" + +#ifndef Debug +#define Debug FALSE +#endif + +#define LogPrefix "FakeSMC: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +#define super IOService +OSDefineMetaClassAndStructors (FakeSMC, IOService) + +bool FakeSMC::init(OSDictionary *dictionary) { + return super::init(dictionary); +} + +IOService *FakeSMC::probe(IOService *provider, SInt32 *score) { + if (!super::probe(provider, score)) { + return 0; + } + InfoLog("opensource SMC device emulator by netkas (C) 2009"); + InfoLog("plugins & plugins support modifications by mozodojo, usr-sse2, slice (C) 2010"); + + return this; +} + +bool FakeSMC::start(IOService *provider) { + if (!super::start(provider)) { + return false; + } + + if (!(smcDevice = new FakeSMCDevice)) { + InfoLog("failed to create smcDevice"); + return false; + } + + if (!smcDevice->init(provider, OSDynamicCast(OSDictionary, getProperty("Configuration")))) { + InfoLog("failed to init smcDevice"); + return false; + } + + smcDevice->registerService(); + registerService(); + + return true; +} + +void FakeSMC::stop(IOService *provider) { + super::stop(provider); +} + +void FakeSMC::free() { + super::free(); +} diff --git a/fakesmc/FakeSMC.h b/fakesmc/FakeSMC.h new file mode 100644 index 0000000..fb9a388 --- /dev/null +++ b/fakesmc/FakeSMC.h @@ -0,0 +1,26 @@ +#ifndef _VIRTUALSMC_H +#define _VIRTUALSMC_H + +#include +#include +#include +#include +#include "FakeSMCDevice.h" +#include "FakeSMCKey.h" +#include "definitions.h" + + +class FakeSMC : public IOService { + OSDeclareDefaultStructors(FakeSMC) +private: + FakeSMCDevice *smcDevice; + +public: + virtual bool init(OSDictionary *dictionary = 0); + virtual void free(void); + virtual IOService *probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual void stop(IOService *provider); +}; + +#endif diff --git a/fakesmc/FakeSMCDevice.cpp b/fakesmc/FakeSMCDevice.cpp new file mode 100644 index 0000000..d869f2a --- /dev/null +++ b/fakesmc/FakeSMCDevice.cpp @@ -0,0 +1,955 @@ +/* + * FakeSMCDevice.cpp + * FakeSMC + * + * Created by Vladimir on 20.08.09. + * Copyright 2009 netkas. All rights reserved. + * + */ + +#include "FakeSMCDevice.h" +#include "definitions.h" +#include "utils.h" + +#include +#include + + +#ifndef Debug +#define Debug FALSE +#endif + +#define LogPrefix "FakeSMCDevice: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +#define super IOACPIPlatformDevice +OSDefineMetaClassAndStructors (FakeSMCDevice, IOACPIPlatformDevice) + +void FakeSMCDevice::applesmc_io_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) { + struct AppleSMCStatus *s = (struct AppleSMCStatus *)opaque; + //DebugLog("CMD Write B: %#x = %#x", addr, val); + switch(val) { + case APPLESMC_READ_CMD: + s->status = 0x0c; + break; + case APPLESMC_WRITE_CMD: + s->status = 0x0c; + break; + case APPLESMC_GET_KEY_BY_INDEX_CMD: + s->status = 0x0c; + break; + case APPLESMC_GET_KEY_TYPE_CMD: + s->status = 0x0c; + break; + } + s->cmd = val; + s->read_pos = 0; + s->data_pos = 0; + s->key_index = 0; + // bzero(s->key_info, 6); +} + +void FakeSMCDevice::applesmc_fill_data(struct AppleSMCStatus *s) { + char name[5]; + + snprintf(name, 5, "%c%c%c%c", s->key[0], s->key[1], s->key[2], s->key[3]); + + if (FakeSMCKey *key = getKey(name)) { + bcopy(key->getValue(), s->value, key->getSize()); + return; + } + + if (debug) { + WarningLog("key not found %c%c%c%c, length - %x\n", + s->key[0], + s->key[1], + s->key[2], + s->key[3], + s->data_len); + } + s->status_1e=0x84; +} + +const char * FakeSMCDevice::applesmc_get_key_by_index(uint32_t index, struct AppleSMCStatus *s) { + FakeSMCKey *key = getKey(index); + if (key) { + return key->getName(); + } + + if (debug) { + WarningLog("key by count %x is not found",index); + } + + s->status_1e=0x84; + s->status = 0x00; + + return 0; +} + +void FakeSMCDevice::applesmc_fill_info(struct AppleSMCStatus *s) { + FakeSMCKey *key = getKey((char *)s->key); + if (key) { + s->key_info[0] = key->getSize(); + s->key_info[5] = 0; + + const char* typ = key->getType(); + UInt64 len = strlen(typ); + + for (int i=0; i<4; i++) { + if (ikey_info[i+1] = typ[i]; + } else { + s->key_info[i+1] = 0; + } + } + + return; + } + + if (debug) { + WarningLog("key info not found %c%c%c%c, length - %x", + s->key[0], + s->key[1], + s->key[2], + s->key[3], + s->data_len); + } + + s->status_1e=0x84; +} + +void FakeSMCDevice::applesmc_io_data_writeb(void *opaque, uint32_t addr, uint32_t val) +{ + struct AppleSMCStatus *s = (struct AppleSMCStatus *)opaque; + //IOLog("APPLESMC: DATA Write B: %#x = %#x\n", addr, val); + switch(s->cmd) { + case APPLESMC_READ_CMD: + if (s->read_pos < 4) { + s->key[s->read_pos] = val; + s->status = 0x04; + } else if (s->read_pos == 4) { + s->data_len = val; + s->status = 0x05; + s->data_pos = 0; + //IOLog("APPLESMC: Key = %c%c%c%c Len = %d\n", s->key[0], s->key[1], s->key[2], s->key[3], val); + applesmc_fill_data(s); + } + s->read_pos++; + break; + case APPLESMC_WRITE_CMD: + // IOLog("FakeSMC: attempting to write(WRITE_CMD) to io port value %x ( %c )\n", val, val); + if (s->read_pos < 4) { + s->key[s->read_pos] = val; + s->status = 0x04; + } else if (s->read_pos == 4) { + s->status = 0x05; + s->data_pos=0; + s->data_len = val; + //IOLog("FakeSMC: System Tried to write Key = %c%c%c%c Len = %d\n", s->key[0], s->key[1], s->key[2], s->key[3], val); + } else if ( s->data_pos < s->data_len ) { + s->value[s->data_pos] = val; + s->data_pos++; + s->status = 0x05; + if (s->data_pos == s->data_len) { + s->status = 0x00; + char name[5]; + + snprintf(name, 5, "%c%c%c%c", s->key[0], s->key[1], s->key[2], s->key[3]); + + // IOLog("FakeSMC: adding Key = %c%c%c%c Len = %d\n", s->key[0], s->key[1], s->key[2], s->key[3], s->data_len); + FakeSMCKey *key = addKeyWithValue(name, 0, s->data_len, s->value); + bzero(s->value, 255); + if (key) { + saveKeyToNVRAM(key); + } + } + }; + s->read_pos++; + break; + case APPLESMC_GET_KEY_BY_INDEX_CMD: + //IOLog("FakeSMC: System Tried to write GETKEYBYINDEX = %x (%c) at pos %x\n",val , val, s->read_pos); + if (s->read_pos < 4) { + s->key_index += val << (24 - s->read_pos * 8); + s->status = 0x04; + s->read_pos++; + }; + if (s->read_pos == 4) { + s->status = 0x05; + //IOLog("FakeSMC: trying to find key by index %x\n", s->key_index); + const char * key = applesmc_get_key_by_index(s->key_index, s); + if (key) { + bcopy(key, s->key, 4); + } + } + + break; + case APPLESMC_GET_KEY_TYPE_CMD: + //IOLog("FakeSMC: System Tried to write GETKEYTYPE = %x (%c) at pos %x\n",val , val, s->read_pos); + if (s->read_pos < 4) { + s->key[s->read_pos] = val; + s->status = 0x04; + }; + s->read_pos++; + if (s->read_pos == 4) { + s->data_len = 6; ///s->data_len = val ; ? val should be 6 here too + s->status = 0x05; + s->data_pos=0; + applesmc_fill_info(s); + } + break; + } +} + +uint32_t FakeSMCDevice::applesmc_io_data_readb(void *opaque, uint32_t addr1) { + struct AppleSMCStatus *s = (struct AppleSMCStatus *)opaque; + uint8_t retval = 0; + switch(s->cmd) { + case APPLESMC_READ_CMD: + if (s->data_pos < s->data_len) { + retval = s->value[s->data_pos]; + //IOLog("APPLESMC: READ_DATA[%d] = %#hhx\n", s->data_pos, retval); + s->data_pos++; + if (s->data_pos == s->data_len) { + s->status = 0x00; + bzero(s->value, 255); + //IOLog("APPLESMC: EOF\n"); + } else { + s->status = 0x05; + } + } + break; + case APPLESMC_WRITE_CMD: + //InfoLog("attempting to read(WRITE_CMD) from io port"); + s->status = 0x00; + break; + case APPLESMC_GET_KEY_BY_INDEX_CMD: ///shouldnt be here if status == 0 + //IOLog("FakeSMC:System Tried to read GETKEYBYINDEX = %x (%c) , at pos %d\n", retval, s->key[s->data_pos], s->key[s->data_pos], s->data_pos); + if (s->status == 0) return 0; //sanity check + if (s->data_pos < 4) { + retval = s->key[s->data_pos]; + s->data_pos++; + } + if (s->data_pos == 4) { + s->status = 0x00; + } + break; + case APPLESMC_GET_KEY_TYPE_CMD: + //IOLog("FakeSMC:System Tried to read GETKEYTYPE = %x , at pos %d\n", s->key_info[s->data_pos], s->data_pos); + if (s->data_pos < s->data_len) { + retval = s->key_info[s->data_pos]; + s->data_pos++; + if (s->data_pos == s->data_len) { + s->status = 0x00; + bzero(s->key_info, 6); + //IOLog("APPLESMC: EOF\n"); + } else { + s->status = 0x05; + } + } + break; + } + //IOLog("APPLESMC: DATA Read b: %#x = %#x\n", addr1, retval); + return retval; +} + +uint32_t FakeSMCDevice::applesmc_io_cmd_readb(void *opaque, uint32_t addr1) { + //IOLog("APPLESMC: CMD Read B: %#x\n", addr1); + return ((struct AppleSMCStatus*)opaque)->status; +} + +UInt32 FakeSMCDevice::ioRead32(UInt16 offset, IOMemoryMap * map) { + UInt32 value=0; + /* + UInt16 base = 0; + + if (map) { + base = map->getPhysicalAddress(); + } + + DebugLog("ioread32 called"); + */ + return (value); +} + +UInt16 FakeSMCDevice::ioRead16(UInt16 offset, IOMemoryMap * map) { + UInt16 value=0; + /* + UInt16 base = 0; + + if (map) { + base = map->getPhysicalAddress(); + } + + DebugLog("ioread16 called"); + */ + + return (value); +} + +UInt8 FakeSMCDevice::ioRead8(UInt16 offset, IOMemoryMap * map) { + UInt8 value = 0; + UInt16 base = 0; + struct AppleSMCStatus *s = (struct AppleSMCStatus *)status; + //IODelay(10); + + if (map) { + base = map->getVirtualAddress(); + } + + if ((base + offset) == APPLESMC_DATA_PORT) { + value=applesmc_io_data_readb(status, base+offset); + } + + if ((base+offset) == APPLESMC_CMD_PORT) { + value=applesmc_io_cmd_readb(status, base+offset); + } + + if ((base+offset) == APPLESMC_ERROR_CODE_PORT) { + if (s->status_1e != 0) { + value = s->status_1e; + s->status_1e = 0x00; + //IOLog("generating error %x\n", value); + } else { + value = 0x0; + } + } + /* + if (((base+offset) != APPLESMC_DATA_PORT) && ((base+offset) != APPLESMC_CMD_PORT)) { + IOLog("ioread8 to port %x.\n", base+offset); + } + + DebugLog("ioread8 called"); + */ + return (value); +} + +void FakeSMCDevice::ioWrite32(UInt16 offset, UInt32 value, IOMemoryMap * map) { + /* + UInt16 base = 0; + if (map) { + base = map->getPhysicalAddress(); + } + DebugLog("iowrite32 called"); + */ +} + +void FakeSMCDevice::ioWrite16(UInt16 offset, UInt16 value, IOMemoryMap * map) { + /* + UInt16 base = 0; + + if (map) { + base = map->getPhysicalAddress(); + } + + DebugLog("iowrite16 called"); + */ +} + +void FakeSMCDevice::ioWrite8(UInt16 offset, UInt8 value, IOMemoryMap * map) { + UInt16 base = 0; + IODelay(10); + if (map) base = map->getVirtualAddress(); + + if ((base+offset) == APPLESMC_DATA_PORT) { + applesmc_io_data_writeb(status, base+offset, value); + } + + if ((base+offset) == APPLESMC_CMD_PORT) applesmc_io_cmd_writeb(status, base+offset,value); + /* + outb(base + offset, value); + if (((base+offset) != APPLESMC_DATA_PORT) && ((base+offset) != APPLESMC_CMD_PORT)) { + IOLog("iowrite8 to port %x.\n", base+offset); + } + DebugLog("iowrite8 called"); + */ +} + +bool FakeSMCDevice::init(IOService *platform, OSDictionary *properties) { + if (!super::init(platform, 0, 0)) { + return false; + } + + status = (AppleSMCStatus *) IOMalloc(sizeof(struct AppleSMCStatus)); + bzero((void*)status, sizeof(struct AppleSMCStatus)); + + debug = false; + interrupt_handler=0; + dtNvram = 0; + + //platformFunctionLock = IOLockAlloc(); + char argBuf[16]; + if (PE_parse_boot_argn("-withREV", &argBuf, sizeof(argBuf))) { + isRevLess = false; + } else if (PE_parse_boot_argn("-noREV", &argBuf, sizeof(argBuf))) { + isRevLess = true; + } else { + IORegistryEntry * rootNode = IORegistryEntry::fromPath("/efi/platform", gIODTPlane); + if (rootNode) { + OSData *data = OSDynamicCast(OSData, rootNode->getProperty("Model")); + OSData *model = OSData::withCapacity(32); // 15 should be enough.. + const unsigned char* raw = static_cast(data->getBytesNoCopy()); + + for (int i = 0; i < data->getLength(); i += 2) { + model->appendByte(raw[i], 1); + } + + isRevLess = isModelREVLess((const char *)model->getBytesNoCopy()); + } + } + + keys = OSArray::withCapacity(0); + values = OSDictionary::withCapacity(0); + + sharpKEY = FakeSMCKey::withValue("#KEY", "ui32", 4, "\1"); + keys->setObject(sharpKEY); + + loadKeysFromDictionary(OSDynamicCast(OSDictionary, properties->getObject("Keys"))); + loadKeysFromClover(platform); + + this->setName("SMC"); + + const char * nodeName = "APP0001"; + this->setProperty("name",(void *)nodeName, (UInt32)strlen(nodeName)+1); + + if (OSString *smccomp = OSDynamicCast(OSString, properties->getObject("smc-compatible"))) { + this->setProperty("compatible",(void *)smccomp->getCStringNoCopy(), smccomp->getLength()+1); + } else { + const char * nodeComp = "smc-napa"; + this->setProperty("compatible",(void *)nodeComp, (UInt32)strlen(nodeComp)+1); + } + + this->setProperty("_STA", (unsigned long long)0x0000000b, 32); + + if (OSBoolean *debugkey = OSDynamicCast(OSBoolean, properties->getObject("debug"))) { + this->setDebug(debugkey->getValue()); + } else { + this->setDebug(true); + } + + IODeviceMemory::InitElement rangeList[1]; + + rangeList[0].start = 0x300; + rangeList[0].length = 0x20; + + if (OSArray *array = IODeviceMemory::arrayFromList(rangeList, 1)) { + this->setDeviceMemory(array); + array->release(); + } else { + WarningLog("failed to create Device memory array"); + return false; + } + + OSArray *controllers = OSArray::withCapacity(1); + if (!controllers) { + WarningLog("failed to create controllers array"); + return false; + } + + OSArray *specifiers = OSArray::withCapacity(1); + if (!specifiers) { + WarningLog("failed to create specifiers array"); + return false; + } + + UInt64 line = 0x06; + OSData *tmpData = OSData::withBytes( &line, sizeof(line)); + if (!tmpData) { + WarningLog("failed to create tmpdata"); + return false; + } + + OSSymbol *gIntelPICName = (OSSymbol *)OSSymbol::withCStringNoCopy("io-apic-0"); + specifiers->setObject(tmpData); + controllers->setObject(gIntelPICName); + + this->setProperty(gIOInterruptControllersKey, controllers) && + this->setProperty( gIOInterruptSpecifiersKey, specifiers); + + this->attachToParent(platform, gIOServicePlane); + + if (IORegistryEntry *options = OSDynamicCast(IORegistryEntry, + IORegistryEntry::fromPath("/options", gIODTPlane))) { + if (IODTNVRAM *nvram = OSDynamicCast(IODTNVRAM, options)) { + dtNvram = nvram; + } else { + WarningLog("Registry entry /options can't be casted to IONVRAM."); + } + } + + InfoLog("successfully initialized"); + return true; +} + +IOReturn FakeSMCDevice::setProperties(OSObject * properties) { + OSDictionary * messageDict = OSDynamicCast(OSDictionary, properties); + if (messageDict) { + OSString *name = OSDynamicCast(OSString, messageDict->getObject(kFakeSMCDeviceUpdateKeyValue)); + if (name) { + FakeSMCKey *key = getKey(name->getCStringNoCopy()); + if (key) { + values->setObject(key->getName(), OSData::withBytes(key->getValue(), key->getSize())); + this->setProperty(kFakeSMCDeviceValues, OSDictionary::withDictionary(values)); + return kIOReturnSuccess; + } + } else { + OSString * tmpString = OSDynamicCast(OSString, + messageDict->getObject(kFakeSMCDevicePopulateValues)); + if (tmpString) { + OSCollectionIterator *iterator = OSCollectionIterator::withCollection(keys); + if (iterator) { + while (true) { + FakeSMCKey *key = OSDynamicCast(FakeSMCKey, iterator->getNextObject()); + if (!key) { + break; + } + values->setObject(key->getName(), OSData::withBytes(key->getValue(), key->getSize())); + iterator->release(); + } + + this->setProperty(kFakeSMCDeviceValues, OSDictionary::withDictionary(values)); + + return kIOReturnSuccess; + } + } else { + OSArray * list = OSDynamicCast(OSArray, messageDict->getObject(kFakeSMCDevicePopulateList)); + if (list) { + OSIterator *iterator = OSCollectionIterator::withCollection(list); + if (iterator) { + while (true){ + FakeSMCKey *key; + const OSSymbol *keyName = (const OSSymbol *)iterator->getNextObject(); + if (!keyName) { + break; + } + key = getKey(keyName->getCStringNoCopy()); + if (key) { + values->setObject(key->getName(), OSData::withBytes(key->getValue(), key->getSize())); + } + } + + this->setProperty(kFakeSMCDeviceValues, OSDictionary::withDictionary(values)); + + iterator->release(); + + return kIOReturnSuccess; + } + } + } + } + } + + return kIOReturnUnsupported; +} + +void FakeSMCDevice::loadKeysFromClover(IOService *platform) { + IORegistryEntry * rootNode; + OSData *data; + + UInt32 SMCConfig; + UInt8 Mobile; + char Platform[8]; + char PlatformB[8]; + UInt8 SMCRevision[6]; + UInt8 WakeType; + UInt16 ClockWake; + + rootNode = fromPath("/efi/platform", gIODTPlane); + if (rootNode) { + /* + don't add 'REV ', 'RBr ' and EPCI if for these models and newer: + MacBookPro15,1 + MacBookAir8,1 + Macmini8,1 + iMacPro1,1 + // the list is going to increase? + */ + + data = OSDynamicCast(OSData, rootNode->getProperty("RPlt")); + if (data) { + /*if (isRevLess) { + rootNode->removeProperty("RPlt"); + } else {*/ + bcopy(data->getBytesNoCopy(), Platform, 8); + InfoLog("SMC Platform: %s", Platform); + this->addKeyWithValue("RPlt", "ch8*", 8, Platform); + //} + } + + //we propose that RBr always follow RPlt and no additional check + data = OSDynamicCast(OSData, rootNode->getProperty("RBr")); + if (data) { + if (isRevLess) { + rootNode->removeProperty("RBr"); + } else { + bcopy(data->getBytesNoCopy(), PlatformB, 8); + InfoLog("SMC Branch: %s", PlatformB); + this->addKeyWithValue("RBr ", "ch8*", 8, PlatformB); + } + } + data = OSDynamicCast(OSData, rootNode->getProperty("REV")); + if (data) { + if (isRevLess) { + rootNode->removeProperty("REV"); + } else { + bcopy(data->getBytesNoCopy(), SMCRevision, 6); + InfoLog("SMC Revision set to: %01x.%02xf%02x", SMCRevision[0], SMCRevision[1], SMCRevision[5]); + this->addKeyWithValue("REV ", "{rev", 6, SMCRevision); + } + } + data = OSDynamicCast(OSData, rootNode->getProperty("EPCI")); + if (data) { + if (isRevLess) { + rootNode->removeProperty("EPCI"); + } else { + SMCConfig = *(UInt32*)data->getBytesNoCopy(); + InfoLog("SMC ConfigID set to: %02x %02x %02x %02x", + (unsigned int)SMCConfig & 0xFF, + (unsigned int)(SMCConfig >> 8) & 0xFF, + (unsigned int)(SMCConfig >> 16) & 0xFF, + (unsigned int)(SMCConfig >> 24) & 0xFF); + this->addKeyWithValue("EPCI", "ui32", 4, data->getBytesNoCopy()); + } + } + data = OSDynamicCast(OSData, rootNode->getProperty("BEMB")); + if (data) { + Mobile = *(UInt8*)data->getBytesNoCopy(); + InfoLog("Mobile Platform: %d", Mobile); + this->addKeyWithValue("BEMB", "flag", 1, data->getBytesNoCopy()); + } + data = OSDynamicCast(OSData, rootNode->getProperty("WKTP")); + if (data) { + WakeType = *(UInt8*)data->getBytesNoCopy(); + InfoLog("Wake type: %d", WakeType); + this->addKeyWithValue("WKTP", "ui8 ", 1, data->getBytesNoCopy()); + } + data = OSDynamicCast(OSData, rootNode->getProperty("CLWK")); + if (data) { + ClockWake = *(UInt16*)data->getBytesNoCopy(); + InfoLog("Wake clock: %d", ClockWake); + this->addKeyWithValue("CLWK", "ui16", 2, data->getBytesNoCopy()); + } + } +} + +void FakeSMCDevice::loadKeysFromDictionary(OSDictionary *dictionary) { + if (dictionary) { + OSIterator *iterator = OSCollectionIterator::withCollection(dictionary); + if (iterator) { + while (true) { + const OSSymbol *key = (const OSSymbol *)iterator->getNextObject(); + if (!key) { + break; + } + OSArray *array = OSDynamicCast(OSArray, dictionary->getObject(key)); + if (array) { + OSIterator *aiterator = OSCollectionIterator::withCollection(array); + if (aiterator) { + OSString *type = OSDynamicCast(OSString, aiterator->getNextObject()); + OSData *value = OSDynamicCast(OSData, aiterator->getNextObject()); + + if (type && value) { + if (!isRevLess || + (isRevLess && + strncmp(key->getCStringNoCopy(), "REV ", strlen("REV ")) != 0 && + strncmp(key->getCStringNoCopy(), "EPCI", strlen("EPCI")) != 0 && + strncmp(key->getCStringNoCopy(), "RBr ", strlen("RBr ")) != 0)) { + this->addKeyWithValue(key->getCStringNoCopy(), + type->getCStringNoCopy(), + value->getLength(), + value->getBytesNoCopy()); + } + } + aiterator->release(); + } + } + key = 0; + } + iterator->release(); + } + InfoLog("%d preconfigured key(s) added", keys->getCount()); + } else { + WarningLog("no preconfigured keys found"); + } +} + +UInt32 FakeSMCDevice::getCount() { + return keys->getCount(); +} + +void FakeSMCDevice::updateSharpKey() { + UInt32 count = keys->getCount(); + char value[] = { count << 24, count << 16, count << 8, count }; + sharpKEY->setValueFromBuffer(value, 4); +} + +FakeSMCKey *FakeSMCDevice::addKeyWithValue(const char *name, + const char *type, + unsigned char size, + const void *value) { + FakeSMCKey *key = getKey(name); + if (key) { + key->setValueFromBuffer(value, size); + DebugLog("updating value for key %s, type: %s, size: %d", name, type, size); + return key; + } + + DebugLog("adding key %s with value, type: %s, size: %d", name, type, size); + key = FakeSMCKey::withValue(name, type, size, value); + if (key) { + keys->setObject(key); + updateSharpKey(); + return key; + } + + WarningLog("can't create key %s", name); + return 0; +} + +FakeSMCKey *FakeSMCDevice::addKeyWithHandler(const char *name, + const char *type, + unsigned char size, + IOService *handler) { + FakeSMCKey *key = getKey(name); + if (key) { + key->setHandler(handler); + DebugLog("changing handler for key %s, type: %s, size: %d", name, type, size); + return key; + } + + DebugLog("adding key %s with handler, type: %s, size: %d", name, type, size); + key = FakeSMCKey::withHandler(name, type, size, handler); + if (key) { + keys->setObject(key); + updateSharpKey(); + return key; + } + + WarningLog("can't create key %s", name); + return 0; +} + +void FakeSMCDevice::saveKeyToNVRAM(FakeSMCKey *key) { + if (dtNvram != 0) { + char name[32]; + + snprintf(name, 32, "%s-%s-%s", kFakeSMCKeyPropertyPrefix, key->getName(), key->getType()); + + const OSSymbol *tempName = OSSymbol::withCString(name); + + dtNvram->setProperty(tempName, OSData::withBytes(key->getValue(), key->getSize())); + + OSSafeReleaseNULL(tempName); + //OSSafeRelease(nvram); + } + /* + if (entry) { + entry->release(); + } + */ +} + +FakeSMCKey *FakeSMCDevice::getKey(const char * name) { + OSCollectionIterator *iterator = OSCollectionIterator::withCollection(keys); + if (iterator) { + UInt32 key1 = *((uint32_t*)name); + FakeSMCKey *key; + while (true) { + key = OSDynamicCast(FakeSMCKey, iterator->getNextObject()); + if (!key) { + break; + } + UInt32 key2 = *((uint32_t*)key->getName()); + if (key1 == key2) { + iterator->release(); + return key; + } + } + iterator->release(); + } + + DebugLog("key %s not found", name); + return 0; +} + +FakeSMCKey *FakeSMCDevice::getKey(unsigned int index) { + FakeSMCKey *key = OSDynamicCast(FakeSMCKey, keys->getObject(index)); + if (key) { + return key; + } + + DebugLog("key with index %d not found", index); + return 0; +} + +void FakeSMCDevice::setDebug(bool debug_val) { + debug = debug_val; +} + +IOReturn FakeSMCDevice::registerInterrupt(int source, + OSObject *target, + IOInterruptAction handler, + void *refCon) { + interrupt_refcon = refCon; + interrupt_target = target; + interrupt_handler = handler; + interrupt_source = source; + //IOLog("register interrupt called for source %x\n", source); + return kIOReturnSuccess; +} + +IOReturn FakeSMCDevice::unregisterInterrupt(int source) { + return kIOReturnSuccess; +} + +IOReturn FakeSMCDevice::getInterruptType(int source, int *interruptType) { + return kIOReturnSuccess; +} + +IOReturn FakeSMCDevice::enableInterrupt(int source) { + return kIOReturnSuccess; +} + +IOReturn FakeSMCDevice::disableInterrupt(int source) { + return kIOReturnSuccess; +} + +IOReturn FakeSMCDevice::causeInterrupt(int source) { + if (interrupt_handler) { + interrupt_handler(interrupt_target, interrupt_refcon, this, interrupt_source); + } + + return kIOReturnSuccess; +} + +IOReturn FakeSMCDevice::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4) { + //IOLockLock(platformFunctionLock); + FakeSMCKey *key = NULL; + IOReturn result = kIOReturnUnsupported; + const char *name; + const void *data; + + do { + if (functionName->isEqualTo(kFakeSMCSetKeyValue)) { + name = (const char *)param1; + unsigned char size = (UInt64)param2; + data = (const void *)param3; + + if (name && data && size > 0) { + key = OSDynamicCast(FakeSMCKey, getKey(name)); + if (key && key->setValueFromBuffer(data, size)){ + result = kIOReturnSuccess; + break; + } + result = kIOReturnError; + break; + } + result = kIOReturnBadArgument; + } else if (functionName->isEqualTo(kFakeSMCAddKeyHandler)) { + name = (const char *)param1; + const char *type = (const char *)param2; + unsigned char size = (UInt64)param3; + IOService *handler = (IOService *)param4; + + if (name && type && size > 0) { + DebugLog("adding key %s with handler, type %s, size %d", name, type, size); + + if (addKeyWithHandler(name, type, size, handler)) { + result = kIOReturnSuccess; + break; + } + result = kIOReturnError; + break; + } + + result = kIOReturnBadArgument; + } else if (functionName->isEqualTo(kFakeSMCGetKeyHandler)) { + result = kIOReturnBadArgument; + if (param1) { + name = (const char *)param1; + + result = kIOReturnError; + key = OSDynamicCast(FakeSMCKey, getKey(name)); + if (key && key->getHandler()) { + + result = kIOReturnBadArgument; + + if (param2) { + /* + IOService **handler = (IOService **)param2; + IOService *keyHandler = key->getHandler(); + bcopy((void*)keyHandler, (void*)handler, sizeof(handler)); + memcpy(handler, keyHandler, sizeof(*handler)); + */ + *(IOService **)param2 = key->getHandler(); + result = kIOReturnSuccess; + } + } + } + } else if (functionName->isEqualTo(kFakeSMCRemoveKeyHandler)) { + result = kIOReturnBadArgument; + + if (param1) { + result = kIOReturnError; + OSCollectionIterator *iterator = OSCollectionIterator::withCollection(keys); + if (iterator) { + IOService *handler = (IOService *)param1; + while (true) { + key = OSDynamicCast(FakeSMCKey, iterator->getNextObject()); + if (!key) { + break; + } + if (key->getHandler() == handler) { + key->setHandler(NULL); + } + } + result = kIOReturnSuccess; + OSSafeReleaseNULL(iterator); + } + } + } else if (functionName->isEqualTo(kFakeSMCAddKeyValue)) { + name = (const char *)param1; + const char *type = (const char *)param2; + unsigned char size = (UInt64)param3; + const void *value = (const void *)param4; + + if (name && type && size > 0) { + DebugLog("adding key %s with value, type %s, size %d", name, type, size); + if (addKeyWithValue(name, type, size, value)) { + result = kIOReturnSuccess; + break; + } + result = kIOReturnError; + break; + } + result = kIOReturnBadArgument; + } else if (functionName->isEqualTo(kFakeSMCGetKeyValue)) { + name = (const char *)param1; + UInt8 *size = (UInt8*)param2; + const void **value = (const void **)param3; + + if (name) { + key = getKey(name); + if (key) { + *size = key->getSize(); + *value = key->getValue(); + result = kIOReturnSuccess; + break; + } + result = kIOReturnError; + break; + } + result = kIOReturnBadArgument; + break; + } + } while (0); + + //IOLockUnlock(platformFunctionLock); + return result; +} diff --git a/fakesmc/FakeSMCDevice.h b/fakesmc/FakeSMCDevice.h new file mode 100644 index 0000000..277f55a --- /dev/null +++ b/fakesmc/FakeSMCDevice.h @@ -0,0 +1,125 @@ +/* + * FakeSMCDevice.h + * FakeSMC + * + * Created by Vladimir on 20.08.09. + * Copyright 2009 netkas. All rights reserved. + * + */ + +#ifndef _FAKESMCDEVICE_h +#define _FAKESMCDEVICE_h + +#include +#include +#include +#include "FakeSMCKey.h" + +#define APPLESMC_DATA_PORT 0x300 + +#define APPLESMC_CMD_PORT 0x304 +#define APPLESMC_ERROR_CODE_PORT 0x31e +#define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */ +#define APPLESMC_MAX_DATA_LENGTH 32 + +#define APPLESMC_READ_CMD 0x10 +#define APPLESMC_WRITE_CMD 0x11 +#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12 +#define APPLESMC_GET_KEY_TYPE_CMD 0x13 + +struct AppleSMCStatus { + uint8_t cmd; + uint8_t status; + uint8_t key[4]; + uint8_t read_pos; + uint8_t data_len; + uint8_t data_pos; + uint8_t value[255]; + uint8_t charactic[4]; + uint8_t status_1e; + uint32_t key_index; + uint8_t key_info[6]; +}; + +class FakeSMCDevice : public IOACPIPlatformDevice { + OSDeclareDefaultStructors( FakeSMCDevice ) + +private: + OSObject *interrupt_target; + IOInterruptAction interrupt_handler; + void *interrupt_refcon; + int interrupt_source; + + struct AppleSMCStatus *status; + + IODTNVRAM *dtNvram; + + OSArray *keys; + OSDictionary *values; + FakeSMCKey *sharpKEY; + + bool debug; + bool isRevLess = false; // default + IOLock *platformFunctionLock; + + virtual void applesmc_io_cmd_writeb(void *opaque, uint32_t addr, uint32_t val); + virtual void applesmc_io_data_writeb(void *opaque, uint32_t addr, uint32_t val); + virtual uint32_t applesmc_io_data_readb(void *opaque, uint32_t addr1); + virtual uint32_t applesmc_io_cmd_readb(void *opaque, uint32_t addr1); + virtual const char *applesmc_get_key_by_index(uint32_t index, struct AppleSMCStatus *s); + virtual void applesmc_fill_data(struct AppleSMCStatus *s); + virtual void applesmc_fill_info(struct AppleSMCStatus *s); + +public: + virtual void ioWrite32( UInt16 offset, UInt32 value, IOMemoryMap * map = 0 ); + virtual void ioWrite16( UInt16 offset, UInt16 value, IOMemoryMap * map = 0 ); + virtual void ioWrite8( UInt16 offset, UInt8 value, IOMemoryMap * map = 0 ); + virtual UInt32 ioRead32( UInt16 offset, IOMemoryMap * map = 0 ); + virtual UInt16 ioRead16( UInt16 offset, IOMemoryMap * map = 0 ); + virtual UInt8 ioRead8( UInt16 offset, IOMemoryMap * map = 0 ); + + virtual IOReturn registerInterrupt(int source, + OSObject *target, + IOInterruptAction handler, + void *refCon = 0); + + virtual IOReturn unregisterInterrupt(int source); + virtual IOReturn getInterruptType(int source, int *interruptType); + virtual IOReturn enableInterrupt(int source); + virtual IOReturn disableInterrupt(int source); + virtual IOReturn causeInterrupt(int source); + + virtual bool init(IOService *platform, OSDictionary *properties); + virtual IOReturn setProperties(OSObject * properties); + + virtual void loadKeysFromDictionary(OSDictionary *dictionary); + virtual void loadKeysFromClover(IOService *platform); + //virtual FakeSMCKey *addKey(const char *name, const char *type, unsigned char size); + virtual FakeSMCKey *addKeyWithValue(const char *name, + const char *type, + unsigned char size, + const void *value); + + virtual FakeSMCKey *addKeyWithHandler(const char *name, + const char *type, + unsigned char size, + IOService *handler); + + virtual void saveKeyToNVRAM(FakeSMCKey *key); + virtual FakeSMCKey *getKey(const char *name); + virtual FakeSMCKey *getKey(unsigned int index); + virtual UInt32 getCount(void); + + virtual void updateSharpKey(void); + + virtual void setDebug(bool debug_val); + + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); +}; + +#endif diff --git a/fakesmc/FakeSMCKey.cpp b/fakesmc/FakeSMCKey.cpp new file mode 100644 index 0000000..f6ec8b0 --- /dev/null +++ b/fakesmc/FakeSMCKey.cpp @@ -0,0 +1,229 @@ +/* + * FakeSMCKey.cpp + * FakeSMC + * + * Created by mozo on 03/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +#include "FakeSMC.h" + +#include +#include + +#ifndef Debug +#define Debug FALSE +#endif + +#define LogPrefix "FakeSMCKey: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +#define super OSObject +OSDefineMetaClassAndStructors(FakeSMCKey, OSObject) + +IOService *FakeSMCKey::getHandler() { + return handler; +}; + +void FakeSMCKey::copySymbol(const char *from, char* to) { + bzero(to, 5); + size_t len = strlen(from); + bcopy(from, to, len > 4 ? 4 : len); +} + +FakeSMCKey *FakeSMCKey::withValue(const char *aName, + const char *aType, + unsigned char aSize, + const void *aValue) { + FakeSMCKey *me = new FakeSMCKey; + + if (me && !me->init(aName, aType, aSize, aValue)) { + me->release(); + return 0; + } + + return me; +} + +FakeSMCKey *FakeSMCKey::withHandler(const char *aName, + const char *aType, + unsigned char aSize, + IOService *aHandler) { + FakeSMCKey *me = new FakeSMCKey; + + if (me && !me->init(aName, aType, aSize, 0, aHandler)) { + me->release(); + return 0; + } + + return me; +} + +bool FakeSMCKey::init(const char * aName, + const char * aType, + unsigned char aSize, + const void *aValue, + IOService * aHandler) { + if (!super::init()) { + return false; + } + + if (!aName || strlen(aName) == 0 || !(name = (char *)IOMalloc(5))) { + return false; + } + + copySymbol(aName, name); + size = aSize; + + if (!(type = (char *)IOMalloc(5))) { + return false; + } + + if (!aType || strlen(aType) == 0) { + switch (size) { + case 1: + copySymbol("ui8", type); + break; + case 2: + copySymbol("ui16", type); + break; + case 4: + copySymbol("ui32", type); + break; + default: + copySymbol("ch8*", type); + break; + } + } else { + copySymbol(aType, type); + } + + if (size == 0) { + size++; + } + + if (!(value = IOMalloc(size))) { + return false; + } + + if (aValue) { + bcopy(aValue, value, size); + } else { + bzero(value, size); + } + + handler = aHandler; + return true; +} + +void FakeSMCKey::free() { + if (name) { + IOFree(name, 5); + } + + if (type) { + IOFree(type, 5); + } + + if (value) { + IOFree(value, size); + } + super::free(); +} + +const char *FakeSMCKey::getName() { + return name; +}; + +const char *FakeSMCKey::getType() { + return type; +}; + +unsigned char FakeSMCKey::getSize() { + return size; +}; + +const void *FakeSMCKey::getValue() { + if (handler) { + IOReturn result = handler->callPlatformFunction(kFakeSMCGetValueCallback, + false, (void *)name, + (void *)value, + (void *)(long long)size, + 0); + + if (kIOReturnSuccess != result) { + WarningLog("value update request callback error for key %s, return 0x%x", name, result); + } + } + + return value; +}; + +bool FakeSMCKey::setValueFromBuffer(const void *aBuffer, unsigned char aSize) { + if (!aBuffer || aSize == 0) { + return false; + } + + if (aSize != size) { + if (value) { + IOFree(value, size); + } + + size = aSize; + + if (!(value = IOMalloc(size))) { + return false; + } + } + + bcopy(aBuffer, value, size); + + if (handler) { + IOReturn result = handler->callPlatformFunction(kFakeSMCSetValueCallback, + false, + (void *)name, + (void *)value, + (void *)(long long)size, + 0); + + if (kIOReturnSuccess != result) { + WarningLog("value changed event callback error for key %s, return 0x%x", name, result); + } + } + + return true; +} + +bool FakeSMCKey::setHandler(IOService *aHandler) { + if (!aHandler) { + return false; + } + + handler = aHandler; + return true; +} + +/* + void FakeSMCKey::removeHandler() { + handler = NULL; + return; + } +*/ + +bool FakeSMCKey::isEqualTo(const char *aKey) { + return strncmp(name, aKey, 4) == 0; +} + +bool FakeSMCKey::isEqualTo(FakeSMCKey *aKey) { + return (aKey && aKey->isEqualTo(name)); +} + +bool FakeSMCKey::isEqualTo(const OSMetaClassBase *anObject) { + if (FakeSMCKey *aKey = OSDynamicCast(FakeSMCKey, anObject)) { + return isEqualTo(aKey); + } + return false; +} diff --git a/fakesmc/FakeSMCKey.h b/fakesmc/FakeSMCKey.h new file mode 100644 index 0000000..4ea9f17 --- /dev/null +++ b/fakesmc/FakeSMCKey.h @@ -0,0 +1,66 @@ +/* + * FakeSMCKey.h + * FakeSMC + * + * Created by mozo on 03/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +#ifndef _FAKESMCKEY_H +#define _FAKESMCKEY_H + +#include +#include +#include +#include +#include + +class FakeSMCKey : public OSObject { + OSDeclareDefaultStructors(FakeSMCKey) + +protected: + static void copySymbol(const char *from, char* to); + + char * name; + char * type; + unsigned char size; + void * value; + IOService * handler; + +public: + static FakeSMCKey *withValue(const char *aName, + const char *aType, + unsigned char aSize, + const void *aValue); + + static FakeSMCKey *withHandler(const char *aName, + const char *aType, + unsigned char aSize, + IOService *aHandler); + + // Not for general use. Use withCallback or withValue instance creation method + virtual bool init(const char * aName, + const char * aType, + unsigned char aSize, + const void *aValue, + IOService *aHandler = 0); + + virtual void free(); + + const char *getName(); + const char *getType(); + unsigned char getSize(); + const void *getValue(); + + bool setValueFromBuffer(const void *aBuffer, unsigned char aSize); + bool setHandler(IOService *aHandler); + IOService *getHandler(); + + bool isEqualTo(const char *aKey); + bool isEqualTo(FakeSMCKey *aKey); + bool isEqualTo(const OSMetaClassBase *anObject); +}; + + +#endif diff --git a/hwmonitor/AppDelegate.h b/hwmonitor/AppDelegate.h new file mode 100644 index 0000000..e990b7b --- /dev/null +++ b/hwmonitor/AppDelegate.h @@ -0,0 +1,50 @@ +// +// AppDelegate.h +// HWMonitor +// +// Created by mozo,Navi on 20.10.11. +// Copyright (c) 2011 mozodojo. All rights reserved. +// + +#import +#import "ISPSmartController.h" +#include "HWMonitorSensor.h" + + +@interface AppDelegate : NSObject { + NSStatusItem * statusItem; + NSFont * statusItemFont; + NSDictionary* statusItemAttributes; + + NSMutableArray * sensorsList; + NSDictionary * DisksList; + NSDictionary * SSDList; + NSDictionary * BatteriesList; + + ISPSmartController * smartController; + + BOOL isMenuVisible; + BOOL smart; + int menusCount; + int lastMenusCount; + + NSDate * lastcall; + + IBOutlet NSMenu * statusMenu; + NSFont * statusMenuFont; + NSDictionary* statusMenuAttributes; +} + +@property (assign) IBOutlet NSMenuItem *startAtLoginItem; + +- (void)updateTitles; +- (HWMonitorSensor *)addSensorWithKey:(NSString *)key + andType:(NSString *)aType + andCaption:(NSString *)caption + intoGroup:(SensorGroup)group; + +- (void)insertFooterAndTitle:(NSString *)title andImage:(NSImage *) img; + +- (void)menuItemClicked:(id)sender; + +@end diff --git a/hwmonitor/AppDelegate.m b/hwmonitor/AppDelegate.m new file mode 100755 index 0000000..cdd097e --- /dev/null +++ b/hwmonitor/AppDelegate.m @@ -0,0 +1,468 @@ +// +// AppDelegate.m +// HWMonitor +// +// Created by mozo,Navi on 20.10.11. +// Copyright (c) 2011 mozo. All rights reserved. +// +// Francesco Renga (vector sigma) 2017, read battery from common path +// + +#import "AppDelegate.h" +#import "NSString+TruncateToWidth.h" +#import "IOBatteryStatus.h" +#include "../utils/definitions.h" + +#define LOG_NULL_VALUES 0 + +@implementation AppDelegate + +#define SMART_UPDATE_INTERVAL 5*60 + +- (id) init { + if (self = [super init]) { + lastcall = [NSDate date]; + } + return self; +} + +- (void)updateTitles { + NSDictionary *pb = [IOBatteryStatus getIOPMPowerSource]; + NSEnumerator * enumerator = nil; + HWMonitorSensor * sensor = nil; + + NSMutableString * statusString = [[NSMutableString alloc] init]; + int count = 0; + + NSMutableDictionary * values; + + values = [NSMutableDictionary dictionaryWithCapacity:0]; + + if(smart) { + if (fabs([lastcall timeIntervalSinceNow]) > SMART_UPDATE_INTERVAL) { + lastcall = [NSDate date]; + [smartController update]; + } + [values addEntriesFromDictionary:[smartController getSSDLife]]; + [values addEntriesFromDictionary:[smartController getDataSet /*:1*/]]; + } + + NSDictionary * temp = [IOBatteryStatus getAllBatteriesLevel]; + if ([temp count] >0) { + [values addEntriesFromDictionary:temp]; + BOOL __block needFooter = YES; + [temp enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + BOOL found = NO; + NSEnumerator * sensorsEnumerator = [sensorsList objectEnumerator]; + HWMonitorSensor * localSensor; + while (localSensor = (HWMonitorSensor *)[sensorsEnumerator nextObject]) { + if ([key isEqualToString:[localSensor key]]) { + found = YES; + needFooter = NO; + } + } + if(!found){ + [self addSensorWithKey:key andType:@TYPE_FPE2 andCaption:key intoGroup:BatterySensorsGroup]; + } + }]; + if(needFooter) { + [self insertFooterAndTitle:NSLocalizedString(@"BATTERIES",nil) + andImage:[NSImage imageNamed:@"modern-battery-icon"]]; + } + } + + if (values) { + enumerator = [sensorsList objectEnumerator]; + + while (sensor = (HWMonitorSensor *)[enumerator nextObject]) { + NSString * value = nil; + if ([[sensor key] isEqualToString:@KEY_BAT0_VOLTAGE] || [[sensor key] isEqualToString:@KEY_BAT0_AMPERAGE]) { + if (pb) { + int v = ([[sensor key] isEqualToString:@KEY_BAT0_VOLTAGE] ? + [IOBatteryStatus getBatteryVoltageFrom:pb] : + [IOBatteryStatus getBatteryAmperageFrom:pb]); + + if (v > BAT0_NOT_FOUND) { + value = [NSString stringWithFormat:@"%d", v]; + } else { + [[(NSMenuItem *)[sensor object] menu] removeItem:(NSMenuItem *)[sensor object]]; + } + } else { + // workaround for VoodooBatterySMC when no battery is present + value = nil; + [[(NSMenuItem *)[sensor object] menu] removeItem:(NSMenuItem *)[sensor object]]; + } + } else { + value = [sensor formatedValue: + [values objectForKey:[sensor key]] ? + [values objectForKey:[sensor key]] : + [HWMonitorSensor readValueForKey:[sensor key]]]; + } + + if ((value != nil) && ![value isEqualToString:@""]) { + if (isMenuVisible) { + // Update menu item title + NSString * str = [[sensor caption] stringByPaddingToLength:28 withString:@" " startingAtIndex:0]; + + if(![[(NSMenuItem *)[sensor object] title] isEqualToString:str]) { + [(NSMenuItem *)[sensor object] setTitle:[NSString stringWithFormat:@"%@%@",str,value]]; + } + } + + if ([sensor favorite]) { + [statusString appendString:@" "]; + [statusString appendString:value]; + count++; + } + } + } + } + + //if (count > 0) { /* let update the title */ + // Update status bar title + NSMutableAttributedString * title = [[NSMutableAttributedString alloc] initWithString:statusString attributes:statusItemAttributes]; + [title addAttribute:NSFontAttributeName value:statusItemFont range:NSMakeRange(0, [title length])]; + [statusItem setAttributedTitle:title]; + + //} +} + +- (HWMonitorSensor *)addSensorWithKey:(NSString *)key andType:(NSString *) aType andCaption:(NSString *)caption intoGroup:(SensorGroup)group +{ + if(group == HDSmartTempSensorGroup || + group == HDSmartLifeSensorGroup || + [HWMonitorSensor readValueForKey:key] || + group == BatterySensorsGroup) { + caption = [caption stringByTruncatingToWidth:180.0f withFont:statusMenuFont]; + HWMonitorSensor * sensor = [[HWMonitorSensor alloc] initWithKey:key andType: aType andGroup:group withCaption:caption]; + + [sensor setFavorite:[[NSUserDefaults standardUserDefaults] boolForKey:key]]; + + NSMenuItem * menuItem = [[NSMenuItem alloc] initWithTitle:caption action:nil keyEquivalent:@""]; + + [menuItem setRepresentedObject:sensor]; + [menuItem setAction:@selector(menuItemClicked:)]; + [menuItem setState:[sensor favorite]? YES : NO]; + + [statusMenu insertItem:menuItem atIndex:menusCount++]; + + [sensor setObject:menuItem]; + + [sensorsList addObject:sensor]; + return sensor; + + } + return NULL; +} + +- (void)insertFooterAndTitle:(NSString *)title andImage:(NSImage *)img { + if (lastMenusCount < menusCount) { + NSMenuItem * titleItem = [[NSMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""]; + if(img) { + [titleItem setImage:img]; + } + [titleItem setEnabled:NO]; + //[titleItem setIndentationLevel:1]; + + [statusMenu insertItem:titleItem atIndex:lastMenusCount]; menusCount++; + [statusMenu insertItem:[NSMenuItem separatorItem] atIndex:menusCount++]; + lastMenusCount = menusCount; + } +} + +// Events + +- (void)menuWillOpen:(NSMenu *)menu { + isMenuVisible = YES; + [self updateTitles]; +} + +- (void)menuDidClose:(NSMenu *)menu { + isMenuVisible = NO; +} + +- (void)menuItemClicked:(id)sender { + NSMenuItem * menuItem = (NSMenuItem *)sender; + + [menuItem setState:![menuItem state]]; + HWMonitorSensor * sensor = (HWMonitorSensor *)[menuItem representedObject]; + [sensor setFavorite:[menuItem state]]; + + [self updateTitles]; + + [[NSUserDefaults standardUserDefaults] setBool:[menuItem state] forKey:[sensor key]]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + + if (![NSUserDefaults.standardUserDefaults objectForKey:@"runAtLoginWasSet"]) { + [self toggleLaunchAtStartup:nil]; + } + + self.startAtLoginItem.state = [self isLaunchAtStartup] ? NSOnState : NSOffState; + + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: + [self methodSignatureForSelector:@selector(updateTitles)]]; + [invocation setTarget:self]; + [invocation setSelector:@selector(updateTitles)]; + [[NSRunLoop mainRunLoop] addTimer:[NSTimer timerWithTimeInterval:3 invocation:invocation repeats:YES] forMode:NSRunLoopCommonModes]; + + [self updateTitles]; +} + +- (void)awakeFromNib { + menusCount = 0; + lastcall = [NSDate date]; + smartController = [[ISPSmartController alloc] init]; + if (smartController) { + smart = YES; + [smartController getPartitions]; + [smartController update]; + DisksList = [smartController getDataSet /*:1*/]; + SSDList = [smartController getSSDLife]; + } + + BatteriesList = [IOBatteryStatus getAllBatteriesLevel]; + + statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; + [statusItem setMenu:statusMenu]; + [statusItem setHighlightMode:YES]; + + NSString *statusImage; + NSString *statusImageAlternate; + NSString *macOSppearance = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"]; + + // Check if the status icon must be normal or dark + if ([macOSppearance isEqualToString:@"Dark"]) { + statusImage = @"temperature_small_dark"; + statusImageAlternate = @"temperature_small_dark"; + } else { + statusImage = @"temperature_small"; + statusImageAlternate = @"temperature_small_dark"; + } + + [statusItem setImage:[NSImage imageNamed:statusImage]]; + [statusItem setAlternateImage:[NSImage imageNamed:statusImageAlternate]]; + + statusItemFont = [NSFont fontWithName:@"Lucida Grande Bold" size:9.0]; + + NSMutableParagraphStyle * style = [[NSMutableParagraphStyle alloc] init]; + [style setLineSpacing:0]; + + statusItemAttributes = [NSDictionary dictionaryWithObject:style forKey:NSParagraphStyleAttributeName]; + + statusMenuFont = [NSFont fontWithName:@"Menlo" size:11]; + [statusMenu setFont:statusMenuFont]; + + style = [[NSMutableParagraphStyle alloc] init]; + [style setTabStops:[NSArray array]]; + [style addTabStop:[[NSTextTab alloc] initWithType:NSRightTabStopType location:190.0]]; + //[style setDefaultTabInterval:390.0]; + statusMenuAttributes = [NSDictionary dictionaryWithObject:style forKey:NSParagraphStyleAttributeName]; + + // Init sensors + sensorsList = [[NSMutableArray alloc] init]; + lastMenusCount = menusCount; + //Temperatures + NSString* type; + + for (int i=0; i<0xA; i++) { + [self addSensorWithKey:[NSString stringWithFormat:@KEY_FORMAT_CPU_DIODE_TEMPERATURE,i] andType: ((type = [HWMonitorSensor getTypeOfKey:[NSString stringWithFormat:@KEY_FORMAT_CPU_DIODE_TEMPERATURE,i]]) ? type : @TYPE_SP78) andCaption:[[NSString alloc] initWithFormat:@"CPU %X Diode",i] intoGroup:TemperatureSensorGroup ]; + //there was TC%XH, I change to TC%XC + [self addSensorWithKey:[NSString stringWithFormat:@KEY_FORMAT_CPU_DIE_CORE_TEMPERATURE,i] andType: ((type = [HWMonitorSensor getTypeOfKey:[NSString stringWithFormat:@KEY_FORMAT_CPU_DIE_CORE_TEMPERATURE,i]]) ? type : @TYPE_SP78) andCaption:[[NSString alloc] initWithFormat:@"CPU %X Core",i] intoGroup:TemperatureSensorGroup ]; + } + [self addSensorWithKey:@KEY_CPU_PROXIMITY_TEMPERATURE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_CPU_PROXIMITY_TEMPERATURE]) ? type : @TYPE_SP78) andCaption:NSLocalizedString( @"CPU Proximity", nil) intoGroup:TemperatureSensorGroup ]; + [self addSensorWithKey:@KEY_CPU_HEATSINK_TEMPERATURE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_CPU_HEATSINK_TEMPERATURE]) ? type : @TYPE_SP78) andCaption:NSLocalizedString( @"CPU Heatsink", nil) intoGroup:TemperatureSensorGroup ]; + [self addSensorWithKey:@KEY_NORTHBRIDGE_TEMPERATURE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_NORTHBRIDGE_TEMPERATURE]) ? type : @TYPE_SP78) andCaption:NSLocalizedString(@"Motherboard",nil) intoGroup:TemperatureSensorGroup ]; + [self addSensorWithKey:@KEY_DIMM_TEMPERATURE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_DIMM_TEMPERATURE]) ? type : @TYPE_SP78) andCaption:NSLocalizedString(@"DIMM 0",nil) intoGroup:TemperatureSensorGroup ]; + [self addSensorWithKey:@KEY_DIMM2_TEMPERATURE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_DIMM2_TEMPERATURE]) ? type : @TYPE_SP78) andCaption:NSLocalizedString(@"DIMM 1",nil) intoGroup:TemperatureSensorGroup ]; + [self addSensorWithKey:@KEY_AMBIENT_TEMPERATURE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_AMBIENT_TEMPERATURE]) ? type : @TYPE_SP78) andCaption:NSLocalizedString(@"Ambient",nil) intoGroup:TemperatureSensorGroup ]; + + for (int i=0; i<0xA; i++) { + [self addSensorWithKey:[NSString stringWithFormat:@KEY_FORMAT_GPU_DIODE_TEMPERATURE,i] andType: ((type = [HWMonitorSensor getTypeOfKey:[NSString stringWithFormat:@KEY_FORMAT_GPU_DIODE_TEMPERATURE,i]]) ? type : @TYPE_SP78) andCaption:[[NSString alloc] initWithFormat:NSLocalizedString(@"GPU %X Core",nil) ,i] intoGroup:TemperatureSensorGroup ]; + [self addSensorWithKey:[NSString stringWithFormat:@KEY_FORMAT_GPU_BOARD_TEMPERATURE,i] andType: ((type = [HWMonitorSensor getTypeOfKey:[NSString stringWithFormat:@KEY_FORMAT_GPU_BOARD_TEMPERATURE,i]]) ? type : @TYPE_SP78) andCaption:[[NSString alloc] initWithFormat:NSLocalizedString(@"GPU %X Board",nil),i] intoGroup:TemperatureSensorGroup ]; + [self addSensorWithKey:[NSString stringWithFormat:@KEY_FORMAT_GPU_PROXIMITY_TEMPERATURE,i] andType: ((type = [HWMonitorSensor getTypeOfKey:[NSString stringWithFormat:@KEY_FORMAT_GPU_PROXIMITY_TEMPERATURE,i]]) ? type : @TYPE_SP78) andCaption:[[NSString alloc] initWithFormat:NSLocalizedString(@"GPU %X Proximity",nil),i] intoGroup:TemperatureSensorGroup ]; + } + + [self insertFooterAndTitle:NSLocalizedString( @"TEMPERATURES",nil) andImage:[NSImage imageNamed:@"temp_alt_small"]]; + + for (int i=0; i<16; i++) { + [self addSensorWithKey:[[NSString alloc] initWithFormat:@KEY_FORMAT_NON_APPLE_CPU_FREQUENCY,i] andType: @TYPE_FREQ andCaption:[[NSString alloc] initWithFormat:NSLocalizedString(@"CPU %X",nil),i] intoGroup:FrequencySensorGroup ]; + } + + // + for (int i=0; i<0xA; i++) { + [self addSensorWithKey:[[NSString alloc] initWithFormat:@KEY_FAKESMC_FORMAT_GPU_FREQUENCY,i] andType: @TYPE_FREQ andCaption:[[NSString alloc] initWithFormat:NSLocalizedString(@"GPU %X Core",nil) ,i] intoGroup:FrequencySensorGroup ]; + [self addSensorWithKey:[[NSString alloc] initWithFormat:@KEY_FAKESMC_FORMAT_GPU_SHADER_FREQUENCY,i] andType: @TYPE_FREQ andCaption:[[NSString alloc] initWithFormat:NSLocalizedString(@"GPU %X Shaders",nil) ,i] intoGroup:FrequencySensorGroup ]; + + // Temporary disable GPU ROP and Memory reporting + [self addSensorWithKey:[[NSString alloc] initWithFormat:@KEY_FAKESMC_FORMAT_GPU_MEMORY_FREQUENCY,i] andType: @TYPE_FREQ andCaption:[[NSString alloc] initWithFormat:NSLocalizedString(@"GPU %X Memory",nil) ,i] intoGroup:FrequencySensorGroup ]; + // [self addSensorWithKey:[[NSString alloc] initWithFormat:@KEY_FAKESMC_FORMAT_GPU_ROP_FREQUENCY,i] andType: @TYPE_SP78 andCaption:[[NSString alloc] initWithFormat:NSLocalizedString(@"GPU %X ROP",nil) ,i] intoGroup:FrequencySensorGroup ]; + // + [self insertFooterAndTitle:NSLocalizedString(@"FREQUENCIES",nil) andImage:[NSImage imageNamed:@"freq_small"]]; + } + //Multipliers + + for (int i=0; i<0xA; i++) { + [self addSensorWithKey:[[NSString alloc] initWithFormat:@KEY_FORMAT_NON_APPLE_CPU_MULTIPLIER,i] andType: @TYPE_FP4C andCaption:[[NSString alloc] initWithFormat:NSLocalizedString(@"CPU %X Multiplier",nil),i] intoGroup:MultiplierSensorGroup ]; + } + [self addSensorWithKey:@KEY_NON_APPLE_PACKAGE_MULTIPLIER andType: @TYPE_FP4C andCaption:NSLocalizedString(@"CPU Package Multiplier",nil) intoGroup:MultiplierSensorGroup ]; + + [self insertFooterAndTitle:NSLocalizedString(@"MULTIPLIERS",nil)andImage:[NSImage imageNamed:@"multiply_small"]]; + + // Voltages + + [self addSensorWithKey:@KEY_CPU_VOLTAGE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_CPU_VOLTAGE]) ? type : @TYPE_FP2E) andCaption:NSLocalizedString(@"CPU Voltage",nil) intoGroup:VoltageSensorGroup ]; + [self addSensorWithKey:@KEY_CPU_VRM_SUPPLY0 andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_CPU_VRM_SUPPLY0]) ? type : @TYPE_FP2E) andCaption:NSLocalizedString(@"CPU VRM Voltage",nil) intoGroup:VoltageSensorGroup ]; + [self addSensorWithKey:@KEY_MEMORY_VOLTAGE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_MEMORY_VOLTAGE]) ? type : @TYPE_FP2E) andCaption:NSLocalizedString(@"DIMM Voltage",nil) intoGroup:VoltageSensorGroup ]; + [self addSensorWithKey:@KEY_12V_VOLTAGE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_12V_VOLTAGE]) ? type : @TYPE_SP4B) andCaption:NSLocalizedString(@"+12V Bus Voltage",nil) intoGroup:VoltageSensorGroup ]; + [self addSensorWithKey:@KEY_5VC_VOLTAGE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_5VC_VOLTAGE]) ? type : @TYPE_SP4B) andCaption:NSLocalizedString(@"+5V Bus Voltage",nil) intoGroup:VoltageSensorGroup ]; + [self addSensorWithKey:@KEY_N12VC_VOLTAGE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_N12VC_VOLTAGE]) ? type : @TYPE_SP4B) andCaption:NSLocalizedString(@"-12V Bus Voltage",nil) intoGroup:VoltageSensorGroup ]; + [self addSensorWithKey:@KEY_5VSB_VOLTAGE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_5VSB_VOLTAGE]) ? type : @TYPE_SP4B) andCaption:NSLocalizedString(@"-5V Bus Voltage",nil) intoGroup:VoltageSensorGroup ]; + [self addSensorWithKey:@KEY_3VCC_VOLTAGE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_3VCC_VOLTAGE]) ? type : @TYPE_FP2E) andCaption:NSLocalizedString(@"3.3 VCC Voltage",nil) intoGroup:VoltageSensorGroup ]; + [self addSensorWithKey:@KEY_3VSB_VOLTAGE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_3VSB_VOLTAGE]) ? type : @TYPE_FP2E) andCaption:NSLocalizedString(@"3.3 VSB Voltage",nil) intoGroup:VoltageSensorGroup ]; + [self addSensorWithKey:@KEY_AVCC_VOLTAGE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_AVCC_VOLTAGE]) ? type : @TYPE_FP2E) andCaption:NSLocalizedString(@"3.3 AVCC Voltage",nil) intoGroup:VoltageSensorGroup ]; + + for (int i=0; i<0xA; i++) { + [self addSensorWithKey:[NSString stringWithFormat:@KEY_FORMAT_GPU_VOLTAGE,i] andType: ((type = [HWMonitorSensor getTypeOfKey:[NSString stringWithFormat:@KEY_FORMAT_GPU_VOLTAGE,i]]) ? type : @TYPE_FP2E) andCaption:[[NSString alloc] initWithFormat:NSLocalizedString(@"GPU %X Voltage",nil) ,i] intoGroup:VoltageSensorGroup ]; + } + + [self insertFooterAndTitle:NSLocalizedString(@"VOLTAGES",nil) andImage:[NSImage imageNamed:@"voltage_small"]]; + // + // Fans + // + for (int i=0; i<10; i++) { + FanTypeDescStruct * fds; + NSData * keydata = [HWMonitorSensor readValueForKey:[[NSString alloc] initWithFormat:@KEY_FORMAT_FAN_ID,i]]; + NSString * caption; + if(keydata) { + fds = (FanTypeDescStruct*)[keydata bytes]; + caption = [[[NSString alloc] initWithBytes: fds->strFunction length: DIAG_FUNCTION_STR_LEN encoding: NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[[NSCharacterSet letterCharacterSet] invertedSet]]; + } else { + caption = @""; + } + if([caption length] <= 0) { + caption = [[NSString alloc] initWithFormat:@"Fan %d",i]; + } + [self addSensorWithKey:[NSString stringWithFormat:@KEY_FORMAT_FAN_SPEED,i] andType: ((type = [HWMonitorSensor getTypeOfKey:[NSString stringWithFormat:@KEY_FORMAT_FAN_SPEED,i]]) ? type : @TYPE_FPE2) andCaption:caption intoGroup:TachometerSensorGroup ]; + } + + [self insertFooterAndTitle:NSLocalizedString(@"FANS",nil) andImage:[NSImage imageNamed:@"fan_small"]]; + // + // Disks + // + NSEnumerator * DisksEnumerator = [DisksList keyEnumerator]; + id nextDisk; + while (nextDisk = [DisksEnumerator nextObject]) { + [self addSensorWithKey:nextDisk andType: @TYPE_FPE2 andCaption:nextDisk intoGroup:HDSmartTempSensorGroup]; + } + + [self insertFooterAndTitle:NSLocalizedString(@"HARD DRIVES TEMPERATURES",nil) andImage:[NSImage imageNamed:@"hd_small"]]; + // + // SSD Life + // + if (SSDList != nil) { + NSEnumerator * SSDEnumerator = [SSDList keyEnumerator]; + id nextSSD; + while (nextSSD = [SSDEnumerator nextObject]) { + [self addSensorWithKey:nextSSD andType: @TYPE_FPE2 andCaption:nextSSD intoGroup:HDSmartLifeSensorGroup]; + } + + [self insertFooterAndTitle:NSLocalizedString(@"SSD LIFE",nil) andImage:[NSImage imageNamed:@"ssd_small"]]; + } + // + // Battery + // + [self addSensorWithKey:@KEY_BAT0_VOLTAGE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_BAT0_VOLTAGE]) ? type : @TYPE_UI16) andCaption:NSLocalizedString(@"Battery Voltage, mV",nil) intoGroup:BatterySensorsGroup ]; + //KEY_BAT0_AMPERAGE + [self addSensorWithKey:@KEY_BAT0_AMPERAGE andType: ((type = [HWMonitorSensor getTypeOfKey:@KEY_BAT0_AMPERAGE]) ? type : @TYPE_SI16) andCaption:NSLocalizedString(@"Battery Amperage, mA",nil) intoGroup:BatterySensorsGroup ]; + + + NSEnumerator * BatteryEnumerator = [BatteriesList keyEnumerator]; + id nextBattery; + + while (nextBattery = [BatteryEnumerator nextObject]) { + [self addSensorWithKey:nextBattery andType:@TYPE_FPE2 andCaption:nextBattery intoGroup:BatterySensorsGroup]; + } + + [self insertFooterAndTitle:NSLocalizedString(@"BATTERIES",nil) andImage:[NSImage imageNamed:@"modern-battery-icon"]]; + + if (![sensorsList count]) { + NSMenuItem * item = [[NSMenuItem alloc]initWithTitle:@"No sensors found or FakeSMCDevice unavailable" action:nil keyEquivalent:@""]; + + [item setEnabled:NO]; + + [statusMenu insertItem:item atIndex:0]; + } +} + +#pragma mark launch at start up +- (BOOL)isLaunchAtStartup { + // See if the app is currently in LoginItems. + LSSharedFileListItemRef itemRef = [self itemRefInLoginItems]; + // Store away that boolean. + BOOL isInList = itemRef != nil; + // Release the reference if it exists. + if (itemRef != nil) CFRelease(itemRef); + + return isInList; +} + +- (IBAction)toggleLaunchAtStartup:(NSMenuItem *)sender { + // Toggle the state. + BOOL shouldBeToggled = ![self isLaunchAtStartup]; + // Get the LoginItems list. + LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); + if (loginItemsRef == nil) return; + if (shouldBeToggled) { + // Add the app to the LoginItems list. + CFURLRef appUrl = (__bridge CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; + LSSharedFileListItemRef itemRef = LSSharedFileListInsertItemURL(loginItemsRef, kLSSharedFileListItemLast, NULL, NULL, appUrl, NULL, NULL); + if (itemRef) CFRelease(itemRef); + } + else { + // Remove the app from the LoginItems list. + LSSharedFileListItemRef itemRef = [self itemRefInLoginItems]; + LSSharedFileListItemRemove(loginItemsRef,itemRef); + if (itemRef != nil) CFRelease(itemRef); + } + CFRelease(loginItemsRef); + + self.startAtLoginItem.state = [self isLaunchAtStartup] ? NSOnState : NSOffState; + + [NSUserDefaults.standardUserDefaults setBool:YES forKey:@"runAtLoginWasSet"]; + [NSUserDefaults.standardUserDefaults synchronize]; +} + +- (LSSharedFileListItemRef)itemRefInLoginItems { + LSSharedFileListItemRef res = nil; + + // Get the app's URL. + NSURL *bundleURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; + // Get the LoginItems list. + LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); + if (loginItemsRef == nil) return nil; + // Iterate over the LoginItems. + NSArray *loginItems = (__bridge NSArray *)LSSharedFileListCopySnapshot(loginItemsRef, nil); + for (id item in loginItems) { + LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)(item); + CFURLRef itemURLRef; + if (LSSharedFileListItemResolve(itemRef, 0, &itemURLRef, NULL) == noErr) { + // Again, use toll-free bridging. + NSURL *itemURL = (__bridge NSURL *)itemURLRef; + if ([itemURL isEqual:bundleURL]) { + res = itemRef; + break; + } + } + } + // Retain the LoginItem reference. + if (res != nil) CFRetain(res); + CFRelease(loginItemsRef); + CFRelease((__bridge CFTypeRef)(loginItems)); + + return res; +} +@end + diff --git a/hwmonitor/English.lproj/Credits.rtf b/hwmonitor/English.lproj/Credits.rtf new file mode 100755 index 0000000..46576ef --- /dev/null +++ b/hwmonitor/English.lproj/Credits.rtf @@ -0,0 +1,29 @@ +{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} +{\colortbl;\red255\green255\blue255;} +\paperw9840\paperh8400 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f0\b\fs24 \cf0 Engineering: +\b0 \ + Some people\ +\ + +\b Human Interface Design: +\b0 \ + Some other people\ +\ + +\b Testing: +\b0 \ + Hopefully not nobody\ +\ + +\b Documentation: +\b0 \ + Whoever\ +\ + +\b With special thanks to: +\b0 \ + Mom\ +} diff --git a/hwmonitor/English.lproj/InfoPlist.strings b/hwmonitor/English.lproj/InfoPlist.strings new file mode 100755 index 0000000..477b28f --- /dev/null +++ b/hwmonitor/English.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/hwmonitor/English.lproj/Localizable.strings b/hwmonitor/English.lproj/Localizable.strings new file mode 100644 index 0000000..072458c --- /dev/null +++ b/hwmonitor/English.lproj/Localizable.strings @@ -0,0 +1,7 @@ +/* + Localizable.strings + HWSensors + + Created by Navi on 21.02.12. + Copyright (c) 2012 . All rights reserved. +*/ diff --git a/hwmonitor/English.lproj/MainMenu.xib b/hwmonitor/English.lproj/MainMenu.xib new file mode 100755 index 0000000..f4cf687 --- /dev/null +++ b/hwmonitor/English.lproj/MainMenu.xib @@ -0,0 +1,684 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hwmonitor/English.lproj/default.icns b/hwmonitor/English.lproj/default.icns new file mode 100755 index 0000000..23751dd Binary files /dev/null and b/hwmonitor/English.lproj/default.icns differ diff --git a/hwmonitor/HWMonitorSMC-Info.plist b/hwmonitor/HWMonitorSMC-Info.plist new file mode 100644 index 0000000..0fc3096 --- /dev/null +++ b/hwmonitor/HWMonitorSMC-Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + monitor-icon.icns + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.3.4 + CFBundleSignature + ???? + CFBundleVersion + 1.3.4 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + LSUIElement + + NSHumanReadableCopyright + Copyright © 2011-2018 mozo,Navi. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/hwmonitor/HWMonitorSMC.xcodeproj/project.pbxproj b/hwmonitor/HWMonitorSMC.xcodeproj/project.pbxproj new file mode 100644 index 0000000..9062b71 --- /dev/null +++ b/hwmonitor/HWMonitorSMC.xcodeproj/project.pbxproj @@ -0,0 +1,492 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1252AC891CF5A04700109431 /* ssd_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 1252AC881CF5A04600109431 /* ssd_small.png */; }; + 1260E4A516C4E759006515EB /* default.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1260E4A116C4E759006515EB /* default.icns */; }; + 1260E4A616C4E759006515EB /* fan_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 1260E4A216C4E759006515EB /* fan_small.png */; }; + 1260E4A716C4E759006515EB /* freq_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 1260E4A316C4E759006515EB /* freq_small.png */; }; + 1260E4A816C4E759006515EB /* hd_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 1260E4A416C4E759006515EB /* hd_small.png */; }; + 1260E4AA16C4E774006515EB /* HWMonitorSensor.m in Sources */ = {isa = PBXBuildFile; fileRef = 1260E4A916C4E774006515EB /* HWMonitorSensor.m */; }; + 1260E4AE16C4E786006515EB /* IOBatteryStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 1260E4AD16C4E786006515EB /* IOBatteryStatus.m */; }; + 1260E4B016C4E78C006515EB /* ISPSmartController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1260E4AF16C4E78C006515EB /* ISPSmartController.m */; }; + 1260E4B516C4E7A2006515EB /* modern-battery-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 1260E4B116C4E7A2006515EB /* modern-battery-icon.png */; }; + 1260E4B616C4E7A2006515EB /* monitor_icon_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 1260E4B216C4E7A2006515EB /* monitor_icon_small.png */; }; + 1260E4B716C4E7A2006515EB /* monitor-icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1260E4B316C4E7A2006515EB /* monitor-icon.icns */; }; + 1260E4B816C4E7A2006515EB /* multiply_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 1260E4B416C4E7A2006515EB /* multiply_small.png */; }; + 1260E4BC16C4E7DD006515EB /* NSString+TruncateToWidth.m in Sources */ = {isa = PBXBuildFile; fileRef = 1260E4BB16C4E7DD006515EB /* NSString+TruncateToWidth.m */; }; + 1260E4BF16C4E7E5006515EB /* smc.c in Sources */ = {isa = PBXBuildFile; fileRef = 1260E4BD16C4E7E5006515EB /* smc.c */; }; + 1260E4C316C4E7F1006515EB /* temp_alt_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 1260E4C016C4E7F1006515EB /* temp_alt_small.png */; }; + 1260E4C416C4E7F1006515EB /* temperature_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 1260E4C116C4E7F1006515EB /* temperature_small.png */; }; + 1260E4C516C4E7F1006515EB /* voltage_small.png in Resources */ = {isa = PBXBuildFile; fileRef = 1260E4C216C4E7F1006515EB /* voltage_small.png */; }; + 12BDC50B16C96E6C001EC9D9 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12BDC50A16C96E6C001EC9D9 /* IOKit.framework */; }; + 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; }; + 256AC3DA0F4B6AC300CF3369 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 256AC3D90F4B6AC300CF3369 /* AppDelegate.m */; }; + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; + 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + 955EA9611FF402EE00A24005 /* temperature_small_dark.png in Resources */ = {isa = PBXBuildFile; fileRef = 955EA9601FF402EE00A24005 /* temperature_small_dark.png */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 1252AC861CF58D9A00109431 /* definitions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = definitions.h; path = ../utils/definitions.h; sourceTree = ""; }; + 1252AC881CF5A04600109431 /* ssd_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ssd_small.png; sourceTree = ""; }; + 1260E4A116C4E759006515EB /* default.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = default.icns; sourceTree = ""; }; + 1260E4A216C4E759006515EB /* fan_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = fan_small.png; sourceTree = ""; }; + 1260E4A316C4E759006515EB /* freq_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = freq_small.png; sourceTree = ""; }; + 1260E4A416C4E759006515EB /* hd_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = hd_small.png; sourceTree = ""; }; + 1260E4A916C4E774006515EB /* HWMonitorSensor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HWMonitorSensor.m; sourceTree = ""; }; + 1260E4AD16C4E786006515EB /* IOBatteryStatus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IOBatteryStatus.m; sourceTree = ""; }; + 1260E4AF16C4E78C006515EB /* ISPSmartController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ISPSmartController.m; sourceTree = ""; }; + 1260E4B116C4E7A2006515EB /* modern-battery-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "modern-battery-icon.png"; sourceTree = ""; }; + 1260E4B216C4E7A2006515EB /* monitor_icon_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = monitor_icon_small.png; sourceTree = ""; }; + 1260E4B316C4E7A2006515EB /* monitor-icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = "monitor-icon.icns"; sourceTree = ""; }; + 1260E4B416C4E7A2006515EB /* multiply_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = multiply_small.png; sourceTree = ""; }; + 1260E4BA16C4E7DD006515EB /* NSString+TruncateToWidth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+TruncateToWidth.h"; sourceTree = ""; }; + 1260E4BB16C4E7DD006515EB /* NSString+TruncateToWidth.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+TruncateToWidth.m"; sourceTree = ""; }; + 1260E4BD16C4E7E5006515EB /* smc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = smc.c; sourceTree = ""; }; + 1260E4BE16C4E7E5006515EB /* smc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = smc.h; sourceTree = ""; }; + 1260E4C016C4E7F1006515EB /* temp_alt_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = temp_alt_small.png; sourceTree = ""; }; + 1260E4C116C4E7F1006515EB /* temperature_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = temperature_small.png; sourceTree = ""; }; + 1260E4C216C4E7F1006515EB /* voltage_small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voltage_small.png; sourceTree = ""; }; + 1260E4C616C4E802006515EB /* HWMonitorSensor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HWMonitorSensor.h; sourceTree = ""; }; + 1260E4C716C4E80B006515EB /* IOBatteryStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOBatteryStatus.h; sourceTree = ""; }; + 1260E4C816C4E812006515EB /* ISPSmartController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISPSmartController.h; sourceTree = ""; }; + 1260E64416C92E4E006515EB /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 12BDC50A16C96E6C001EC9D9 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = ../../../../../../../../System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; + 1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; + 256AC3D80F4B6AC300CF3369 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 256AC3D90F4B6AC300CF3369 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 256AC3F00F4B6AF500CF3369 /* HWMonitorSMC_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HWMonitorSMC_Prefix.pch; sourceTree = ""; }; + 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 8D1107310486CEB800E47090 /* HWMonitorSMC-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "HWMonitorSMC-Info.plist"; sourceTree = ""; }; + 8D1107320486CEB800E47090 /* HWMonitorSMC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HWMonitorSMC.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 955EA9601FF402EE00A24005 /* temperature_small_dark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = temperature_small_dark.png; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D11072E0486CEB800E47090 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 12BDC50B16C96E6C001EC9D9 /* IOKit.framework in Frameworks */, + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + 256AC3D80F4B6AC300CF3369 /* AppDelegate.h */, + 256AC3D90F4B6AC300CF3369 /* AppDelegate.m */, + ); + name = Classes; + sourceTree = ""; + }; + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 1260E64416C92E4E006515EB /* IOKit.framework */, + 29B97324FDCFA39411CA2CEA /* AppKit.framework */, + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, + 29B97325FDCFA39411CA2CEA /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D1107320486CEB800E47090 /* HWMonitorSMC.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* HWMonitorSMC */ = { + isa = PBXGroup; + children = ( + 12BDC50A16C96E6C001EC9D9 /* IOKit.framework */, + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = HWMonitorSMC; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 1252AC861CF58D9A00109431 /* definitions.h */, + 256AC3F00F4B6AF500CF3369 /* HWMonitorSMC_Prefix.pch */, + 29B97316FDCFA39411CA2CEA /* main.m */, + 1260E4C616C4E802006515EB /* HWMonitorSensor.h */, + 1260E4A916C4E774006515EB /* HWMonitorSensor.m */, + 1260E4C716C4E80B006515EB /* IOBatteryStatus.h */, + 1260E4AD16C4E786006515EB /* IOBatteryStatus.m */, + 1260E4C816C4E812006515EB /* ISPSmartController.h */, + 1260E4AF16C4E78C006515EB /* ISPSmartController.m */, + 1260E4BA16C4E7DD006515EB /* NSString+TruncateToWidth.h */, + 1260E4BB16C4E7DD006515EB /* NSString+TruncateToWidth.m */, + 1260E4BD16C4E7E5006515EB /* smc.c */, + 1260E4BE16C4E7E5006515EB /* smc.h */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + 1260E4A116C4E759006515EB /* default.icns */, + 1260E4A216C4E759006515EB /* fan_small.png */, + 1260E4A316C4E759006515EB /* freq_small.png */, + 1260E4A416C4E759006515EB /* hd_small.png */, + 1260E4B116C4E7A2006515EB /* modern-battery-icon.png */, + 1260E4B216C4E7A2006515EB /* monitor_icon_small.png */, + 1260E4B316C4E7A2006515EB /* monitor-icon.icns */, + 1260E4B416C4E7A2006515EB /* multiply_small.png */, + 1252AC881CF5A04600109431 /* ssd_small.png */, + 1260E4C016C4E7F1006515EB /* temp_alt_small.png */, + 1260E4C116C4E7F1006515EB /* temperature_small.png */, + 955EA9601FF402EE00A24005 /* temperature_small_dark.png */, + 1260E4C216C4E7F1006515EB /* voltage_small.png */, + 8D1107310486CEB800E47090 /* HWMonitorSMC-Info.plist */, + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, + 1DDD58140DA1D0A300B32029 /* MainMenu.xib */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D1107260486CEB800E47090 /* HWMonitorSMC */ = { + isa = PBXNativeTarget; + buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "HWMonitorSMC" */; + buildPhases = ( + 8D1107290486CEB800E47090 /* Resources */, + 8D11072C0486CEB800E47090 /* Sources */, + 8D11072E0486CEB800E47090 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = HWMonitorSMC; + productInstallPath = "$(HOME)/Applications"; + productName = HWMonitorSMC; + productReference = 8D1107320486CEB800E47090 /* HWMonitorSMC.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0900; + }; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "HWMonitorSMC" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* HWMonitorSMC */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D1107260486CEB800E47090 /* HWMonitorSMC */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D1107290486CEB800E47090 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, + 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */, + 1260E4A516C4E759006515EB /* default.icns in Resources */, + 1260E4A616C4E759006515EB /* fan_small.png in Resources */, + 1260E4A716C4E759006515EB /* freq_small.png in Resources */, + 1260E4A816C4E759006515EB /* hd_small.png in Resources */, + 1260E4B516C4E7A2006515EB /* modern-battery-icon.png in Resources */, + 1260E4B616C4E7A2006515EB /* monitor_icon_small.png in Resources */, + 1260E4B716C4E7A2006515EB /* monitor-icon.icns in Resources */, + 1260E4B816C4E7A2006515EB /* multiply_small.png in Resources */, + 1260E4C316C4E7F1006515EB /* temp_alt_small.png in Resources */, + 1260E4C416C4E7F1006515EB /* temperature_small.png in Resources */, + 1260E4C516C4E7F1006515EB /* voltage_small.png in Resources */, + 1252AC891CF5A04700109431 /* ssd_small.png in Resources */, + 955EA9611FF402EE00A24005 /* temperature_small_dark.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D11072C0486CEB800E47090 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072D0486CEB800E47090 /* main.m in Sources */, + 256AC3DA0F4B6AC300CF3369 /* AppDelegate.m in Sources */, + 1260E4AA16C4E774006515EB /* HWMonitorSensor.m in Sources */, + 1260E4AE16C4E786006515EB /* IOBatteryStatus.m in Sources */, + 1260E4B016C4E78C006515EB /* ISPSmartController.m in Sources */, + 1260E4BC16C4E7DD006515EB /* NSString+TruncateToWidth.m in Sources */, + 1260E4BF16C4E7E5006515EB /* smc.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C165DFE840E0CC02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 1DDD58140DA1D0A300B32029 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 1DDD58150DA1D0A300B32029 /* English */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + C01FCF4B08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO; + CLANG_WARN_FLOAT_CONVERSION = NO; + CLANG_WARN_OBJCPP_ARC_ABI = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = NO; + CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO; + CLANG_WARN_OBJC_RECEIVER_WEAK = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = HWMonitorSMC_Prefix.pch; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = NO; + GCC_VERSION = ""; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO; + GCC_WARN_ABOUT_MISSING_NEWLINE = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = NO; + GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; + GCC_WARN_SIGN_COMPARE = NO; + GCC_WARN_STRICT_SELECTOR_MATCH = NO; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_LABEL = NO; + GCC_WARN_UNUSED_PARAMETER = NO; + INFOPLIST_FILE = "HWMonitorSMC-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + MACOSX_DEPLOYMENT_TARGET = 10.6; + PRODUCT_NAME = HWMonitorSMC; + SDKROOT = macosx; + }; + name = Debug; + }; + C01FCF4C08A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO; + CLANG_WARN_FLOAT_CONVERSION = NO; + CLANG_WARN_OBJCPP_ARC_ABI = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = NO; + CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO; + CLANG_WARN_OBJC_RECEIVER_WEAK = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = HWMonitorSMC_Prefix.pch; + GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = NO; + GCC_VERSION = ""; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO; + GCC_WARN_ABOUT_MISSING_NEWLINE = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = NO; + GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; + GCC_WARN_SIGN_COMPARE = NO; + GCC_WARN_STRICT_SELECTOR_MATCH = NO; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_LABEL = NO; + GCC_WARN_UNUSED_PARAMETER = NO; + INFOPLIST_FILE = "HWMonitorSMC-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + MACOSX_DEPLOYMENT_TARGET = 10.6; + PRODUCT_NAME = HWMonitorSMC; + SDKROOT = macosx; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CLANG_X86_VECTOR_INSTRUCTIONS = sse3; + CODE_SIGN_IDENTITY = "-"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.6; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = ""; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CLANG_X86_VECTOR_INSTRUCTIONS = sse3; + CODE_SIGN_IDENTITY = "-"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = ""; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.6; + SDKROOT = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "HWMonitorSMC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4B08A954540054247B /* Debug */, + C01FCF4C08A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "HWMonitorSMC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/hwmonitor/HWMonitorSMC.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/hwmonitor/HWMonitorSMC.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..fcde8c6 --- /dev/null +++ b/hwmonitor/HWMonitorSMC.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/hwmonitor/HWMonitorSMC.xcodeproj/project.xcworkspace/xcshareddata/HWMonitorSMC.xcscmblueprint b/hwmonitor/HWMonitorSMC.xcodeproj/project.xcworkspace/xcshareddata/HWMonitorSMC.xcscmblueprint new file mode 100644 index 0000000..7b5fb2b --- /dev/null +++ b/hwmonitor/HWMonitorSMC.xcodeproj/project.xcworkspace/xcshareddata/HWMonitorSMC.xcscmblueprint @@ -0,0 +1,25 @@ +{ + "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "2e15404a-8354-49a5-8ee8-3805ff3cba1c", + "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { + "2e15404a-8354-49a5-8ee8-3805ff3cba1c" : { + + } + }, + "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { + "2e15404a-8354-49a5-8ee8-3805ff3cba1c" : 0 + }, + "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "52C130FE-8019-43DF-A163-D5925FE8B035", + "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { + "2e15404a-8354-49a5-8ee8-3805ff3cba1c" : "hwsensors3\/" + }, + "DVTSourceControlWorkspaceBlueprintNameKey" : "HWMonitorSMC", + "DVTSourceControlWorkspaceBlueprintVersion" : 204, + "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "trunk\/hwmonitor\/HWMonitorSMC.xcodeproj", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "svn+ssh:\/\/svn.code.sf.net\/p\/hwsensors\/hwsensors3\/code3", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Subversion", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "2e15404a-8354-49a5-8ee8-3805ff3cba1c" + } + ] +} \ No newline at end of file diff --git a/hwmonitor/HWMonitorSMC.xcodeproj/xcshareddata/xcschemes/HWMonitorSMC.xcscheme b/hwmonitor/HWMonitorSMC.xcodeproj/xcshareddata/xcschemes/HWMonitorSMC.xcscheme new file mode 100644 index 0000000..7035bbf --- /dev/null +++ b/hwmonitor/HWMonitorSMC.xcodeproj/xcshareddata/xcschemes/HWMonitorSMC.xcscheme @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hwmonitor/HWMonitorSMC.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist b/hwmonitor/HWMonitorSMC.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..cc243d1 --- /dev/null +++ b/hwmonitor/HWMonitorSMC.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + HWMonitorSMC.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 8D1107260486CEB800E47090 + + primary + + + + + diff --git a/hwmonitor/HWMonitorSMC_Prefix.pch b/hwmonitor/HWMonitorSMC_Prefix.pch new file mode 100644 index 0000000..4ccbc32 --- /dev/null +++ b/hwmonitor/HWMonitorSMC_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'HWMonitorSMC' target in the 'HWMonitorSMC' project +// + +#ifdef __OBJC__ +#import +#endif diff --git a/hwmonitor/HWMonitorSensor.h b/hwmonitor/HWMonitorSensor.h new file mode 100755 index 0000000..2029538 --- /dev/null +++ b/hwmonitor/HWMonitorSensor.h @@ -0,0 +1,64 @@ +// +// NSSensor.h +// HWSensors +// +// Created by mozo,Navi on 22.10.11. +// Copyright (c) 2011 mozo. All rights reserved. +// + +#import +#import "ISPSmartController.h" + +enum { + TemperatureSensorGroup = 1, + VoltageSensorGroup = 2, + TachometerSensorGroup = 3, + FrequencySensorGroup = 4, + MultiplierSensorGroup = 5, + HDSmartTempSensorGroup = 6, + BatterySensorsGroup = 7, + HDSmartLifeSensorGroup = 8, + +}; +typedef NSUInteger SensorGroup; + +@interface HWMonitorSensor : NSObject { + NSString * key; + NSString * type; + SensorGroup group; + NSString * caption; + id object; + BOOL favorite; + + // instance vars for the below @property + NSString * _key; + NSString * _type; + SensorGroup _group; + NSString * _caption; + id _object; + BOOL _favorite; +} + +@property (readwrite, retain) NSString * key; +@property (readwrite, retain) NSString * type; +@property (readwrite, assign) SensorGroup group; +@property (readwrite, retain) NSString * caption; +@property (readwrite, retain) id object; +@property (readwrite, assign) BOOL favorite; + + + ++ (unsigned int) swapBytes:(unsigned int) value; + ++ (NSData *)readValueForKey:(NSString *)key; ++ (NSString* )getTypeOfKey:(NSString*)key; + +- (HWMonitorSensor *)initWithKey:(NSString *)aKey + andType: aType + andGroup:(NSUInteger)aGroup + withCaption:(NSString *)aCaption; + +- (NSString *)formatedValue:(NSData *)value; + +@end + diff --git a/hwmonitor/HWMonitorSensor.m b/hwmonitor/HWMonitorSensor.m new file mode 100755 index 0000000..1b27d03 --- /dev/null +++ b/hwmonitor/HWMonitorSensor.m @@ -0,0 +1,235 @@ +// +// NSSensor.m +// HWSensors +// +// Created by mozo on 22.10.11. +// Copyright (c) 2011 mozo. All rights reserved. +// + +#import "HWMonitorSensor.h" + +#include "../utils/definitions.h" +#include "smc.h" + +//#define SMC_ACCESS +#define BIT(x) (1 << (x)) +#define bit_get(x, y) ((x) & (y)) +#define bit_clear(x, y) ((x) &= (~y)) + + +int getIndexOfHexChar(char); +float decodeNumericValue(NSData*, NSString*); + +int getIndexOfHexChar(char c) { + return c > 96 && c < 103 ? c - 87 : c > 47 && c < 58 ? c - 48 : 0; +} + +float decodeNumericValue(NSData* _data, NSString*_type) +{ + if (_type && _data && [_type length] >= 3) { + if (([_type characterAtIndex:0] == 'u' || + [_type characterAtIndex:0] == 's') + && [_type characterAtIndex:1] == 'i') { + BOOL signd = [_type characterAtIndex:0] == 's'; + + switch ([_type characterAtIndex:2]) { + case '8': + if ([_data length] == 1) { + UInt8 encoded = 0; + + bcopy([_data bytes], &encoded, 1); + + if (signd && bit_get(encoded, BIT(7))) { + bit_clear(encoded, BIT(7)); + return -encoded; + } + + return encoded; + } + break; + + case '1': + if ([_type characterAtIndex:3] == '6' && [_data length] == 2) { + UInt16 encoded = 0; + + bcopy([_data bytes], &encoded, 2); + + encoded = OSSwapBigToHostInt16(encoded); + + if (signd && bit_get(encoded, BIT(15))) { + bit_clear(encoded, BIT(15)); + return -encoded; + } + + return encoded; + } + break; + + case '3': + if ([_type characterAtIndex:3] == '2' && [_data length] == 4) { + UInt32 encoded = 0; + + bcopy([_data bytes], &encoded, 4); + + encoded = OSSwapBigToHostInt32(encoded); + + if (signd && bit_get(encoded, BIT(31))) { + bit_clear(encoded, BIT(31)); + return -encoded; + } + + return encoded; + } + break; + } + } + else if (([_type characterAtIndex:0] == 'f' || + [_type characterAtIndex:0] == 's') && + [_type characterAtIndex:1] == 'p' && [_data length] == 2) { + UInt16 encoded = 0; + + bcopy([_data bytes], &encoded, 2); + + UInt8 i = getIndexOfHexChar([_type characterAtIndex:2]); + UInt8 f = getIndexOfHexChar([_type characterAtIndex:3]); + + if ((i + f) != (([_type characterAtIndex:0] == 's') ? 15 : 16) ) + return 0; + + UInt16 swapped = OSSwapBigToHostInt16(encoded); + + BOOL signd = [_type characterAtIndex:0] == 's'; + BOOL minus = !!(bit_get(swapped, BIT(15))); + + if (signd && minus) bit_clear(swapped, BIT(15)); + + return ((float)swapped / (float)BIT(f)) * (signd && minus ? -1 : 1); + } + } + + return 0; +} + +@implementation HWMonitorSensor + +@synthesize key; +@synthesize type; +@synthesize group; +@synthesize caption; +@synthesize object; +@synthesize favorite; + ++ (unsigned int)swapBytes:(unsigned int)value { + return ((value & 0xff00) >> 8) | ((value & 0xff) << 8); +} + + ++ (NSData *) readValueForKey:(NSString *)key { + SMCOpen(&conn); + + UInt32Char_t readkey = "\0"; + strncpy(readkey, + [key cStringUsingEncoding:NSASCIIStringEncoding]==NULL + ? "" + : [key cStringUsingEncoding:NSASCIIStringEncoding],4); + + readkey[4]=0; + SMCVal_t val; + + kern_return_t result = SMCReadKey(readkey, &val); + if (result != kIOReturnSuccess) { + return NULL; + } + SMCClose(conn); + if (val.dataSize > 0) { + return [NSData dataWithBytes:val.bytes length:val.dataSize]; + } + return nil; + +} + ++ (NSString *) getTypeOfKey:(NSString *)key { + SMCOpen(&conn); + + UInt32Char_t readkey = "\0"; + strncpy(readkey,[key cStringUsingEncoding:NSASCIIStringEncoding]==NULL + ? "" + : [key cStringUsingEncoding:NSASCIIStringEncoding],4); + + readkey[4]=0; + SMCVal_t val; + + kern_return_t result = SMCReadKey(readkey, &val); + if (result != kIOReturnSuccess) + return NULL; + SMCClose(conn); + if (val.dataSize > 0) + return [NSString stringWithFormat:@"%.4s", val.dataType]; + return nil; +} + + +- (HWMonitorSensor *)initWithKey:(NSString *)aKey + andType: aType + andGroup:(NSUInteger)aGroup + withCaption:(NSString *)aCaption { + self.type = aType; + self.key = aKey; + self.group = aGroup; + self.caption = aCaption; + + return self; +} + +- (NSString *) formatedValue:(NSData *)value { + if (value != nil) { + float v = decodeNumericValue(value, type); + switch (self.group) { + case TemperatureSensorGroup: + return [[NSString alloc] initWithFormat:@"%2d°",(int)v]; + + case HDSmartTempSensorGroup: { + unsigned int t = 0; + bcopy([value bytes], &t, 2); + //t = [NSSensor swapBytes:t] >> 8; + return [[NSString alloc] initWithFormat:@"%d°",t]; + } + + case BatterySensorsGroup: { + NSInteger * t; + t = (NSInteger*)[value bytes]; + return [[NSString alloc] initWithFormat:@"%ld",*t]; + } + + case HDSmartLifeSensorGroup: { + NSInteger * l; + l = (NSInteger*)[value bytes]; + return [[NSString alloc] initWithFormat:@"%ld%%",*l]; + } + + case VoltageSensorGroup: + return [[NSString alloc] initWithFormat:@"%2.3fV", v]; + + case TachometerSensorGroup: + return [[NSString alloc] initWithFormat:@"%drpm",(int)v]; + + case FrequencySensorGroup: { + unsigned int MHZ = 0; + bcopy([value bytes], &MHZ, 2); + MHZ = [HWMonitorSensor swapBytes:MHZ]; + return [[NSString alloc] initWithFormat:@"%dMHz",MHZ]; + } + + case MultiplierSensorGroup: { + unsigned int mlt = 0; + bcopy([value bytes], &mlt, 2); + return [[NSString alloc] initWithFormat:@"x%1.1f",(float)mlt / 10.0]; + } break; + } + } + + return @"-"; +} + +@end + diff --git a/hwmonitor/IOBatteryStatus.h b/hwmonitor/IOBatteryStatus.h new file mode 100644 index 0000000..78140b2 --- /dev/null +++ b/hwmonitor/IOBatteryStatus.h @@ -0,0 +1,31 @@ +// +// IOBatteryStatus.h +// HWSensors +// +// Created by Navi on 04.01.13. +// +// + +#import + +@interface IOBatteryStatus : NSObject + ++ (BOOL)keyboardAvailable; ++ (BOOL)trackpadAvailable; ++ (BOOL)mouseAvailable; + ++ (NSString *)getKeyboardName; ++ (NSString *)getTrackpadName; ++ (NSString *)getMouseName; + ++ (NSInteger )getKeyboardBatteryLevel; ++ (NSInteger )getTrackpadBatteryLevel; ++ (NSInteger )getMouseBatteryLevel; + ++ (NSDictionary *)getIOPMPowerSource; ++ (int)getBatteryVoltageFrom:(NSDictionary *)IOPMPowerSource; ++ (int)getBatteryAmperageFrom:(NSDictionary *)IOPMPowerSource; + ++ (NSDictionary *)getAllBatteriesLevel; + +@end diff --git a/hwmonitor/IOBatteryStatus.m b/hwmonitor/IOBatteryStatus.m new file mode 100644 index 0000000..4a4776e --- /dev/null +++ b/hwmonitor/IOBatteryStatus.m @@ -0,0 +1,180 @@ +// +// IOBatteryStatus.m +// HWSensors +// +// Created by Navi on 04.01.13. +// +// + +#import +#import "IOBatteryStatus.h" +#include "../utils/definitions.h" + +@implementation IOBatteryStatus + ++ (BOOL)keyboardAvailable { + io_service_t service = IOServiceGetMatchingService(0, IOServiceNameMatching("AppleBluetoothHIDKeyboard")); + BOOL value = service ? YES : NO; + IOObjectRelease(service); + return value; +} + ++ (BOOL)trackpadAvailable { + io_service_t service = IOServiceGetMatchingService(0, IOServiceNameMatching("BNBTrackpadDevice")); + BOOL value = service ? YES : NO; + IOObjectRelease(service); + return value; +} + ++ (BOOL)mouseAvailable { + io_service_t service = IOServiceGetMatchingService(0, IOServiceNameMatching("BNBMouseDevice")); + BOOL value = service ? YES : NO; + IOObjectRelease(service); + return value; +} + ++ (NSString *)getKeyboardName { + io_service_t service = IOServiceGetMatchingService(0, IOServiceNameMatching("AppleBluetoothHIDKeyboard")); + NSString * value = nil; + + if (!service ) { + return nil; + } + value = CFBridgingRelease(IORegistryEntryCreateCFProperty(service, CFSTR("Product"), kCFAllocatorDefault, 0)); + + IOObjectRelease(service); + return value; +} + ++ (NSString *)getTrackpadName { + io_service_t service = IOServiceGetMatchingService(0, IOServiceNameMatching("BNBTrackpadDevice")); + NSString * value = nil; + + if (!service ) { + return nil; + } + + value = CFBridgingRelease(IORegistryEntryCreateCFProperty(service, CFSTR("Product"), kCFAllocatorDefault, 0)); + + IOObjectRelease(service); + return value; +} + ++ (NSString *)getMouseName { + io_service_t service = IOServiceGetMatchingService(0, IOServiceNameMatching("BNBMouseDevice")); + NSString * value = nil; + + if (!service ) { + return nil; + } + + value = CFBridgingRelease(IORegistryEntryCreateCFProperty(service, CFSTR("Product"), kCFAllocatorDefault, 0)); + + IOObjectRelease(service); + return value; +} + ++ (NSInteger )getKeyboardBatteryLevel { + io_service_t service = IOServiceGetMatchingService(0, IOServiceNameMatching("AppleBluetoothHIDKeyboard")); + + + if (!service ) { + return 0; //nil; + } + +NSNumber * percent = CFBridgingRelease(IORegistryEntryCreateCFProperty(service, + CFSTR("BatteryPercent, "), + kCFAllocatorDefault, 0)); + + IOObjectRelease(service); + return [percent integerValue]; +} + ++ (NSInteger )getTrackpadBatteryLevel { + io_service_t service = IOServiceGetMatchingService(0, IOServiceNameMatching("BNBTrackpadDevice")); + + + if (!service ) { + return 0; //nil; + } + NSNumber * percent = CFBridgingRelease(IORegistryEntryCreateCFProperty(service, + CFSTR("BatteryPercent"), + kCFAllocatorDefault, 0)); + + IOObjectRelease(service); + return [percent integerValue]; +} + ++ (NSInteger )getMouseBatteryLevel { + io_service_t service = IOServiceGetMatchingService(0, IOServiceNameMatching("BNBMouseDevice")); + + + if (!service ) { + return 0; //nil; + } + NSNumber * percent = CFBridgingRelease(IORegistryEntryCreateCFProperty(service, + CFSTR("BatteryPercent"), + kCFAllocatorDefault, 0)); + + IOObjectRelease(service); + return [percent integerValue]; +} + + ++ (NSDictionary *)getAllBatteriesLevel { + NSMutableDictionary * dataset = [[NSMutableDictionary alloc] initWithCapacity:0]; + NSInteger value = 0; + if([IOBatteryStatus keyboardAvailable]) { + value = [IOBatteryStatus getKeyboardBatteryLevel]; + [dataset setValue:[NSData dataWithBytes:&value length:sizeof(value)] forKey:[IOBatteryStatus getKeyboardName]]; + } + if([IOBatteryStatus trackpadAvailable]) { + value = [IOBatteryStatus getTrackpadBatteryLevel]; + [dataset setValue: [NSData dataWithBytes:&value length:sizeof(value)] forKey:[IOBatteryStatus getTrackpadName]]; + } + if([IOBatteryStatus mouseAvailable]) { + value = [IOBatteryStatus getMouseBatteryLevel]; + [dataset setValue:[NSData dataWithBytes:&value length:sizeof(value)] forKey:[IOBatteryStatus getMouseName]]; + } + return dataset; +} + ++ (NSDictionary *)getIOPMPowerSource { + CFMutableDictionaryRef matching , properties = NULL; + io_registry_entry_t entry = 0; + matching = IOServiceMatching( "IOPMPowerSource" ); + entry = IOServiceGetMatchingService( kIOMasterPortDefault , matching ); + IORegistryEntryCreateCFProperties( entry , &properties , NULL , 0 ); + + NSDictionary * dict = CFBridgingRelease(properties); + IOObjectRelease( entry ); + return dict; +} + +// Voltage measured in mV ++ (int)getBatteryVoltageFrom:(NSDictionary *)IOPMPowerSource { + int ret = BAT0_NOT_FOUND; + if (IOPMPowerSource && [IOPMPowerSource objectForKey:@kIOPMPSVoltageKey]) { + if ([IOPMPowerSource objectForKey:@kIOPMPSBatteryInstalledKey] != nil && + [[IOPMPowerSource objectForKey:@kIOPMPSBatteryInstalledKey] boolValue] == YES) { + ret = [[IOPMPowerSource objectForKey:@kIOPMPSVoltageKey] intValue]; + } + } + return ret; +} + +// Capacity measured in mA ++ (int) getBatteryAmperageFrom:(NSDictionary *)IOPMPowerSource { + int ret = BAT0_NOT_FOUND; + if (IOPMPowerSource && [IOPMPowerSource objectForKey:@kIOPMPSAmperageKey]) { + if ([IOPMPowerSource objectForKey:@kIOPMPSBatteryInstalledKey] != nil && + [[IOPMPowerSource objectForKey:@kIOPMPSBatteryInstalledKey] boolValue] == YES) { + int mA = [[IOPMPowerSource objectForKey:@kIOPMPSAmperageKey] intValue]; + ret = (mA > 0) ? mA : (0 - mA); + } + } + return ret; +} + +@end + diff --git a/hwmonitor/ISPSmartController.h b/hwmonitor/ISPSmartController.h new file mode 100644 index 0000000..8b72f51 --- /dev/null +++ b/hwmonitor/ISPSmartController.h @@ -0,0 +1,33 @@ +// +// ISPSmartController.h +// iStatPro +// +// Created by Buffy on 11/06/07. +// Copyright 2007 . All rights reserved. +// + +#import +#include +#include + + +#define kATADefaultSectorSize 512 +#define kWindowSMARTsDriveTempAttribute 194 +#define kWindowSMARTsDriveTempAttribute2 190 +#define kSMARTsDriveWearLevelingCount 177 +#define kSMARTAttributeCount 30 + +@interface ISPSmartController : NSObject { + NSMutableArray *diskData; + NSMutableArray *latestData; + NSArray *temps; + NSArray *disksStatus; + NSMutableDictionary *partitionData; + NSNumber *temp; + NSNumber *life; +} +- (void)getPartitions; +- (void)update; +- (NSDictionary *)getDataSet /*:(int)degrees*/; +- (NSDictionary *)getSSDLife; +@end diff --git a/hwmonitor/ISPSmartController.m b/hwmonitor/ISPSmartController.m new file mode 100644 index 0000000..765a77f --- /dev/null +++ b/hwmonitor/ISPSmartController.m @@ -0,0 +1,518 @@ +// +// ISPSmartController.m +// iStatPro +// +// Created by Buffy on 11/06/07. +// Copyright 2007 . All rights reserved. +// + +#import "ISPSmartController.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#import "NSString+TruncateToWidth.h" + +/* +static inline int convertTemperature(int format, int value) { + if(format == 0) + return value; + + if(format == 1){ + return (value * 2) - ((value * 2) * 1 / 10) + 32; + } + + if(format == 2){ + return value + 273.15; + } + + return value; +} +*/ +void SwapASCIIString(UInt16 *buffer, UInt16 length); + +@implementation ISPSmartController + +#if defined(__BIG_ENDIAN__) +#define SwapASCIIHostToBig(x,y) +#elif defined(__LITTLE_ENDIAN__) +#define SwapASCIIHostToBig(x,y) SwapASCIIString( ( UInt16 * ) x,y) +#else +#error Unknown endianness. +#endif + +typedef struct IOATASmartAttribute { + UInt8 attributeId; + UInt16 flag; + UInt8 current; + UInt8 worst; + UInt8 rawvalue[6]; + UInt8 reserv; +} __attribute__ ((packed)) IOATASmartAttribute; + +typedef struct IOATASmartVendorSpecificData { + UInt16 revisonNumber; + IOATASmartAttribute vendorAttributes [kSMARTAttributeCount]; +} __attribute__ ((packed)) IOATASmartVendorSpecificData; + + +typedef struct IOATASmartThresholdAttribute { + UInt8 attributeId; + UInt8 ThresholdValue; + UInt8 Reserved[10]; +} __attribute__ ((packed)) IOATASmartThresholdAttribute; + +typedef struct IOATASmartVendorSpecificDataThresholds { + UInt16 revisonNumber; + IOATASmartThresholdAttribute ThresholdEntries [kSMARTAttributeCount]; +} __attribute__ ((packed)) IOATASmartVendorSpecificDataThresholds; + + +void SwapASCIIString(UInt16 *buffer, UInt16 length) { + int index; + for ( index = 0; index < length / 2; index ++ ) { + buffer[index] = OSSwapInt16 ( buffer[index] ); + } +} + + +- (int)VerifyIdentifyData: (UInt16 *) buffer { + UInt8 checkSum = -1; + UInt32 index = 0; + UInt8 * ptr = ( UInt8 * ) buffer; + + if((buffer[255] & 0x00FF) != kChecksumValidCookie) + return checkSum; + + checkSum = 0; + + for (index = 0; index < 512; index++) + checkSum += ptr[index]; + + return checkSum; +} + +- (NSMutableDictionary *)getDiskInfo: ( IOATASMARTInterface **) smartInterface { + IOReturn error = kIOReturnSuccess; + UInt8 * buffer = NULL; + UInt32 length = kATADefaultSectorSize; + UInt16 * words = NULL; + int checksum = 0; + BOOL isSMARTSupported = NO; + + buffer = (UInt8 *) malloc(kATADefaultSectorSize); + if(buffer == NULL) { + return nil; + } + + bzero(buffer, kATADefaultSectorSize); + error = (*smartInterface)->GetATAIdentifyData( smartInterface,buffer,kATADefaultSectorSize,&length ); + if(error != kIOReturnSuccess) { + if (buffer) { + free(buffer); + } + return nil; + } + + checksum = [self VerifyIdentifyData:( UInt16 * ) buffer]; + + if(checksum != 0) { + if (buffer) { + free(buffer); + } + return nil; + } + + buffer[94] = 0; + buffer[40] = 0; + SwapASCIIHostToBig (&buffer[54], 40); + + NSString *model = nil; + NSString *serial = nil; + + model = [[NSString stringWithCString:(char *)&buffer[54] encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + serial = [NSString stringWithCString:(char *)&buffer[20] encoding:NSUTF8StringEncoding]; + + if(model == nil || serial == nil) { + if (buffer) { + free(buffer); + } + return nil; + } + + words = (UInt16 *) buffer; + + isSMARTSupported = words[kATAIdentifyCommandSetSupported] & kATASupportsSMARTMask; + if(isSMARTSupported) { + NSMutableDictionary *data = [[NSMutableDictionary alloc] init]; + if(model != nil) { + [data setObject:model forKey:@"model"]; + } + + if(serial != nil) { + [data setObject:serial forKey:@"serial"]; + } + + if (buffer) { + free(buffer); + } + + return data; + } + + if (buffer) { + free(buffer); + } + + return nil; +} + +- (NSNumber *)getSMARTLifeForInterface:(IOATASMARTInterface **)smartInterface { + IOReturn error = kIOReturnSuccess; + Boolean conditionExceeded = false; + ATASMARTData smartData; + IOATASmartVendorSpecificData smartDataVendorSpecifics; + ATASMARTDataThresholds smartThresholds; + IOATASmartVendorSpecificDataThresholds smartThresholdVendorSpecifics; + ATASMARTLogDirectory smartLogDirectory; + + bzero(&smartData, sizeof(smartData)); + bzero(&smartDataVendorSpecifics, sizeof(smartDataVendorSpecifics)); + bzero(&smartThresholds, sizeof(smartThresholds)); + bzero(&smartThresholdVendorSpecifics, sizeof(smartThresholdVendorSpecifics)); + bzero(&smartLogDirectory, sizeof(smartLogDirectory)); + + BOOL foundLife = NO; + // NSNumber *life = nil; + + error = (*smartInterface)->SMARTEnableDisableOperations(smartInterface, true); + if(error != kIOReturnSuccess) { + (*smartInterface)->SMARTEnableDisableAutosave(smartInterface, false); + (*smartInterface)->SMARTEnableDisableOperations(smartInterface, false); + return [NSNumber numberWithInt:0]; + } + + error = (*smartInterface)->SMARTEnableDisableAutosave(smartInterface, true); + if(error != kIOReturnSuccess) { + (*smartInterface)->SMARTEnableDisableAutosave(smartInterface, false); + (*smartInterface)->SMARTEnableDisableOperations(smartInterface, false); + return [NSNumber numberWithInt:0]; + } + + error = (*smartInterface)->SMARTReturnStatus(smartInterface, &conditionExceeded); + if(error != kIOReturnSuccess) { + (*smartInterface)->SMARTEnableDisableAutosave(smartInterface, false); + (*smartInterface)->SMARTEnableDisableOperations(smartInterface, false); + return [NSNumber numberWithInt:0]; + } + + error = (*smartInterface)->SMARTReadData(smartInterface, &smartData); + if (error == kIOReturnSuccess) { + error = (*smartInterface)->SMARTValidateReadData(smartInterface, &smartData); + if (error == kIOReturnSuccess) { + smartDataVendorSpecifics = *((IOATASmartVendorSpecificData *)&(smartData.vendorSpecific1)); + int currentAttributeIndex = 0; + for (currentAttributeIndex = 0; currentAttributeIndex < kSMARTAttributeCount; currentAttributeIndex++) { + IOATASmartAttribute currentAttribute = smartDataVendorSpecifics.vendorAttributes[currentAttributeIndex]; + if (currentAttribute.attributeId == kSMARTsDriveWearLevelingCount) { + UInt8 raw = currentAttribute.current; + life = [NSNumber numberWithUnsignedInt:raw]; + foundLife = YES; + break; + } + } + } + } + + (*smartInterface)->SMARTEnableDisableAutosave(smartInterface, false); + (*smartInterface)->SMARTEnableDisableOperations(smartInterface, false); + + if(foundLife && life != nil && [life intValue] > 0) { + return life; + } + return nil; +} + +- (NSNumber *)getSMARTTempForInterface:(IOATASMARTInterface **)smartInterface { + IOReturn error = kIOReturnSuccess; + Boolean conditionExceeded = false; + ATASMARTData smartData; + IOATASmartVendorSpecificData smartDataVendorSpecifics; + ATASMARTDataThresholds smartThresholds; + IOATASmartVendorSpecificDataThresholds smartThresholdVendorSpecifics; + ATASMARTLogDirectory smartLogDirectory; + + bzero(&smartData, sizeof(smartData)); + bzero(&smartDataVendorSpecifics, sizeof(smartDataVendorSpecifics)); + bzero(&smartThresholds, sizeof(smartThresholds)); + bzero(&smartThresholdVendorSpecifics, sizeof(smartThresholdVendorSpecifics)); + bzero(&smartLogDirectory, sizeof(smartLogDirectory)); + + BOOL foundTemperature = NO; + // NSNumber *temperature = nil; + + // [smartResultsDict setObject:[NSNumber numberWithBool:NO] forKey:kWindowSMARTsDeviceOkKeyString]; + + error = (*smartInterface)->SMARTEnableDisableOperations(smartInterface, true); + if(error != kIOReturnSuccess) { + (*smartInterface)->SMARTEnableDisableAutosave(smartInterface, false); + (*smartInterface)->SMARTEnableDisableOperations(smartInterface, false); + return [NSNumber numberWithInt:0]; + } + + error = (*smartInterface)->SMARTEnableDisableAutosave(smartInterface, true); + if(error != kIOReturnSuccess) { + (*smartInterface)->SMARTEnableDisableAutosave(smartInterface, false); + (*smartInterface)->SMARTEnableDisableOperations(smartInterface, false); + return [NSNumber numberWithInt:0]; + } + + error = (*smartInterface)->SMARTReturnStatus(smartInterface, &conditionExceeded); + if(error != kIOReturnSuccess) { + (*smartInterface)->SMARTEnableDisableAutosave(smartInterface, false); + (*smartInterface)->SMARTEnableDisableOperations(smartInterface, false); + return [NSNumber numberWithInt:0]; + } + + // if (!conditionExceeded) + // [smartResultsDict setObject:[NSNumber numberWithBool:YES] forKey:kWindowSMARTsDeviceOkKeyString]; + + error = (*smartInterface)->SMARTReadData(smartInterface, &smartData); + if (error == kIOReturnSuccess) { + error = (*smartInterface)->SMARTValidateReadData(smartInterface, &smartData); + if (error == kIOReturnSuccess) { + smartDataVendorSpecifics = *((IOATASmartVendorSpecificData *)&(smartData.vendorSpecific1)); + int currentAttributeIndex = 0; + for (currentAttributeIndex = 0; currentAttributeIndex < kSMARTAttributeCount; currentAttributeIndex++) { + IOATASmartAttribute currentAttribute = smartDataVendorSpecifics.vendorAttributes[currentAttributeIndex]; + if (currentAttribute.attributeId == kWindowSMARTsDriveTempAttribute || + currentAttribute.attributeId == kWindowSMARTsDriveTempAttribute2) { + UInt8 raw = currentAttribute.rawvalue[0]; + temp = [NSNumber numberWithUnsignedInt:raw]; + foundTemperature = YES; + break; + } + if (currentAttribute.attributeId == kSMARTsDriveWearLevelingCount) { + UInt8 raw = currentAttribute.current; + life = [NSNumber numberWithUnsignedInt:raw]; + // foundLife = YES; + break; + } + + } + } + } + + (*smartInterface)->SMARTEnableDisableAutosave(smartInterface, false); + (*smartInterface)->SMARTEnableDisableOperations(smartInterface, false); + + if(foundTemperature && temp != nil && [temp intValue] > 0) { + return temp; + } + return nil; +} + +- (void)getSMARTData:(io_service_t) object { + IOCFPlugInInterface ** cfPlugInInterface = NULL; + IOATASMARTInterface ** smartInterface = NULL; + SInt32 score = 0; + HRESULT herr = S_OK; + IOReturn err = kIOReturnSuccess; + + err = IOCreatePlugInInterfaceForService(object, + kIOATASMARTUserClientTypeID, + kIOCFPlugInInterfaceID, + &cfPlugInInterface, + &score); + + if(err != kIOReturnSuccess ) { + return; + } + + + herr = ( *cfPlugInInterface )->QueryInterface (cfPlugInInterface, + CFUUIDGetUUIDBytes ( kIOATASMARTInterfaceID ), + ( LPVOID ) &smartInterface ); + if(herr != S_OK ) { + IODestroyPlugInInterface ( cfPlugInInterface ); + cfPlugInInterface = NULL; + return; + } + + NSMutableDictionary *diskInfo = [self getDiskInfo:smartInterface]; + if(diskInfo != nil) { + [self getSMARTTempForInterface:smartInterface]; + + CFTypeRef cfName = IORegistryEntrySearchCFProperty(object, kIOServicePlane, CFSTR("BSD Name"), kCFAllocatorDefault, kIORegistryIterateRecursively); + NSString * bsdName = CFBridgingRelease(cfName); + + if(bsdName) { + if([partitionData objectForKey:bsdName]) { + [diskInfo setObject:[partitionData objectForKey:bsdName] forKey:@"partitions"]; + } + // CFRelease(bsdName); + } + if(temp != nil) { + [diskInfo setObject:temp forKey:@"temp"]; + [diskData addObject:diskInfo]; + } + //[diskInfo release]; + /* NSNumber *life = [self getSMARTLifeForInterface:smartInterface]; */ + if (life != nil) { + [diskInfo setObject:life forKey:@"life"]; + [diskData addObject:diskInfo]; + } + } + + ( *smartInterface )->Release ( smartInterface ); + smartInterface = NULL; + + IODestroyPlugInInterface ( cfPlugInInterface ); + cfPlugInInterface = NULL; +} + +- (void)update { + diskData = [[NSMutableArray alloc] init]; + IOReturn error = kIOReturnSuccess; + NSMutableDictionary *matchingDict = [[NSMutableDictionary alloc] initWithCapacity:8]; + NSMutableDictionary *subDict = [[NSMutableDictionary alloc] initWithCapacity:8]; + io_iterator_t iter = IO_OBJECT_NULL; + io_object_t obj = IO_OBJECT_NULL; + + [subDict setObject:[NSNumber numberWithBool:YES] forKey:[NSString stringWithCString:kIOPropertySMARTCapableKey encoding:NSUTF8StringEncoding]]; + [matchingDict setObject:subDict forKey:[NSString stringWithCString:kIOPropertyMatchKey encoding:NSUTF8StringEncoding]]; + + error = IOServiceGetMatchingServices (kIOMasterPortDefault, CFBridgingRetain(matchingDict), &iter); + if (error == kIOReturnSuccess) { + while ((obj = IOIteratorNext(iter)) != IO_OBJECT_NULL) { + [self getSMARTData:obj]; + IOObjectRelease(obj); + } + } + + if ([diskData count] == 0) { + iter = IO_OBJECT_NULL; + matchingDict = CFBridgingRelease(IOServiceMatching("IOATABlockStorageDevice")); + + error = IOServiceGetMatchingServices (kIOMasterPortDefault, CFBridgingRetain(matchingDict), &iter); + if (error == kIOReturnSuccess) { + while ((obj = IOIteratorNext(iter)) != IO_OBJECT_NULL) { + [self getSMARTData:obj]; + IOObjectRelease(obj); + } + } + } + + IOObjectRelease(iter); + iter = IO_OBJECT_NULL; + latestData = diskData; +} + +- (NSDictionary *)getDataSet /*:(int)degrees*/ { + // NSString *degreesSuffix = [NSString stringWithUTF8String:"\xC2\xB0"]; + // if(degrees == 2) + // degreesSuffix = @"K"; + + NSMutableDictionary *formattedTemps = [[NSMutableDictionary alloc] init]; + unsigned long x; + for(x=0;x<[latestData count];x++) { + NSMutableDictionary *diskInfo = [latestData objectAtIndex:x]; + if (diskInfo != nil) { + NSNumber *tempInfo = [diskInfo objectForKey:@"temp"]; + if (tempInfo != nil) { + unsigned long value = [tempInfo intValue]; + //value = convertTemperature(degrees, value); + + NSString *name; + if([diskInfo objectForKey:@"partitions"]) + name = [NSString stringWithFormat:@"%@", [[diskInfo objectForKey:@"partitions"] componentsJoinedByString:@", "]]; + else + name = [NSString stringWithFormat:@"%@ s/n %@", [[diskInfo objectForKey:@"model"] stringByTrimmingLeadingWhitespace],[[diskInfo objectForKey:@"serial"] stringByTrimmingLeadingWhitespace] ]; + + + [formattedTemps setObject:[NSData dataWithBytes:&value length:sizeof( value)] forKey:name]; + // [diskInfo setObject:life forKey:@"life"]; + // [diskData addObject:diskInfo]; + } + } + } + return formattedTemps; +} + +- (NSDictionary *)getSSDLife { + NSMutableDictionary *formattedLife = [[NSMutableDictionary alloc] init]; + unsigned long x; + for(x=0;x<[latestData count];x++) { + NSMutableDictionary *diskInfo = [latestData objectAtIndex:x]; + if (diskInfo != nil) { + NSNumber *lifeInfo = [diskInfo objectForKey:@"life"]; + if (lifeInfo != nil) { + unsigned long value = [lifeInfo intValue]; + NSString *name; + if([diskInfo objectForKey:@"partitions"]) + name = [NSString stringWithFormat:@"_%@", [[diskInfo objectForKey:@"partitions"] componentsJoinedByString:@"_"]]; + else + name = [NSString stringWithFormat:@"%@ s/n:%@", [[diskInfo objectForKey:@"model"] stringByTrimmingLeadingWhitespace],[[diskInfo objectForKey:@"serial"] stringByTrimmingLeadingWhitespace] ]; + + [formattedLife setObject:[NSData dataWithBytes:&value length:sizeof(value)] forKey:name]; + } + } + } + return formattedLife; +} + + +- (void)getPartitions { + if(partitionData) { + [partitionData removeAllObjects]; + } + + partitionData = [[NSMutableDictionary alloc] init]; + + + NSString *path; + BOOL first = YES; + NSEnumerator *mountedPathsEnumerator = [[[NSWorkspace sharedWorkspace] mountedLocalVolumePaths] objectEnumerator]; + while (path = [mountedPathsEnumerator nextObject] ) { + struct statfs buffer; + int returnnewCode = statfs([path fileSystemRepresentation],&buffer); + if ( returnnewCode == 0 ) { + NSRange start = [path rangeOfString:@"/Volumes/"]; + if(first == NO && start.length == 0){ + continue; + } + + if(first) + first = NO; + + NSString *name = [[NSString stringWithFormat:@"%s",buffer.f_mntfromname] lastPathComponent]; + + if([name hasPrefix:@"disk"] && [name length] > 4) { + NSString *newName = [name substringFromIndex:4]; + NSRange paritionLocation = [newName rangeOfString:@"s"]; + if(paritionLocation.length != 0) { + name = [NSString stringWithFormat:@"disk%@",[newName substringToIndex: paritionLocation.location]]; + } + } + + if([partitionData objectForKey:name]) { + [[partitionData objectForKey:name] addObject:[[NSFileManager defaultManager] displayNameAtPath:path]]; + } else { + NSMutableArray *paritions = [[NSMutableArray alloc] init]; + [paritions addObject:[[NSFileManager defaultManager] displayNameAtPath:path]]; + [partitionData setObject:paritions forKey:name]; + + } + } + } +} + +@end diff --git a/hwmonitor/NSString+TruncateToWidth.h b/hwmonitor/NSString+TruncateToWidth.h new file mode 100755 index 0000000..095dc34 --- /dev/null +++ b/hwmonitor/NSString+TruncateToWidth.h @@ -0,0 +1,18 @@ +// +// NSString.h +// HWSensors +// +// Created by Natan Zalkin on 18/02/12. +// Copyright (c) 2012 natan.zalkin@gmail.com. All rights reserved. +// +// Original code http://iphonedevelopertips.com/cocoa/truncate-an-nsstring-and-append-an-ellipsis-respecting-the-font-size.html +// + +#import + +@interface NSString (TruncateToWidth) + +- (NSString*)stringByTruncatingToWidth:(CGFloat)width withFont:(NSFont *)font; +- (NSString*)stringByTrimmingLeadingWhitespace; + +@end diff --git a/hwmonitor/NSString+TruncateToWidth.m b/hwmonitor/NSString+TruncateToWidth.m new file mode 100755 index 0000000..be7a062 --- /dev/null +++ b/hwmonitor/NSString+TruncateToWidth.m @@ -0,0 +1,59 @@ +// +// NSString.m +// HWSensors +// +// Created by Natan Zalkin on 18/02/12. +// Copyright (c) 2012 natan.zalkin@gmail.com. All rights reserved. +// +// Original code http://iphonedevelopertips.com/cocoa/truncate-an-nsstring-and-append-an-ellipsis-respecting-the-font-size.html +// + +#import "NSString+TruncateToWidth.h" + +@implementation NSString (TruncateToWidth) + +- (NSString*)stringByTruncatingToWidth:(CGFloat)width withFont:(NSFont *)font { + // Create copy that will be the returned result + NSMutableAttributedString * truncatedString = [[NSMutableAttributedString alloc] initWithString: self]; + + [truncatedString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, [truncatedString length])]; + + NSMutableAttributedString * ellipsis = [[NSMutableAttributedString alloc] initWithString:@"…"]; + + [ellipsis addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, [ellipsis length])]; + + // Make sure string is longer than requested width + if ([truncatedString size].width > width) { + // Accommodate for ellipsis we'll tack on the end + width -= [ellipsis size].width; + + // Get range for last character in string + NSRange range = {truncatedString.length - 1, 1}; + + // Loop, deleting characters until string fits within width + while ([truncatedString size].width > width) { + // Delete character at end + [truncatedString deleteCharactersInRange:range]; + + // Move back another character + range.location--; + } + + // Append ellipsis + [truncatedString replaceCharactersInRange:range withAttributedString:ellipsis]; + } + + return [NSString stringWithString:[truncatedString string]]; +} + +- (NSString*)stringByTrimmingLeadingWhitespace { + NSUInteger i = 0; + + while ((i < [self length]) + && [[NSCharacterSet whitespaceCharacterSet] characterIsMember:[self characterAtIndex:i]]) { + i++; + } + return [self substringFromIndex:i]; +} + +@end diff --git a/hwmonitor/default.icns b/hwmonitor/default.icns new file mode 100644 index 0000000..23751dd Binary files /dev/null and b/hwmonitor/default.icns differ diff --git a/hwmonitor/fan_small.png b/hwmonitor/fan_small.png new file mode 100644 index 0000000..3934cbb Binary files /dev/null and b/hwmonitor/fan_small.png differ diff --git a/hwmonitor/freq_small.png b/hwmonitor/freq_small.png new file mode 100644 index 0000000..c3893c9 Binary files /dev/null and b/hwmonitor/freq_small.png differ diff --git a/hwmonitor/hd_small.png b/hwmonitor/hd_small.png new file mode 100644 index 0000000..d4a94fa Binary files /dev/null and b/hwmonitor/hd_small.png differ diff --git a/hwmonitor/main.m b/hwmonitor/main.m new file mode 100755 index 0000000..2057f9a --- /dev/null +++ b/hwmonitor/main.m @@ -0,0 +1,14 @@ +// +// main.m +// HWMonitor +// +// Created by Natan Zalkin on 20.10.11. +// Copyright (c) 2011 . All rights reserved. +// + +#import + +int main(int argc, char *argv[]) { + return NSApplicationMain(argc, (const char **)argv); +} + diff --git a/hwmonitor/modern-battery-icon.png b/hwmonitor/modern-battery-icon.png new file mode 100644 index 0000000..b7ee605 Binary files /dev/null and b/hwmonitor/modern-battery-icon.png differ diff --git a/hwmonitor/monitor-icon.icns b/hwmonitor/monitor-icon.icns new file mode 100755 index 0000000..0d9723b Binary files /dev/null and b/hwmonitor/monitor-icon.icns differ diff --git a/hwmonitor/monitor_icon_small.png b/hwmonitor/monitor_icon_small.png new file mode 100644 index 0000000..7751340 Binary files /dev/null and b/hwmonitor/monitor_icon_small.png differ diff --git a/hwmonitor/multiply_small.png b/hwmonitor/multiply_small.png new file mode 100644 index 0000000..688482e Binary files /dev/null and b/hwmonitor/multiply_small.png differ diff --git a/hwmonitor/ru.lproj/Localizable.strings b/hwmonitor/ru.lproj/Localizable.strings new file mode 100644 index 0000000..32d292d --- /dev/null +++ b/hwmonitor/ru.lproj/Localizable.strings @@ -0,0 +1,40 @@ +/* + Localizable.strings + HWSensors + + Created by Navi on 21.02.12. + Copyright (c) 2012 . All rights reserved. +*/ +"TEMPERATURES"="ТЕМПЕРАТУРЫ"; +"FREQUENCIES"="ЧАСТОТЫ"; +"MULTIPLIERS"="МНОЖИТЕЛИ"; +"VOLTAGES"="НАПРЯЖЕНИЯ"; +"FANS"="ВЕНТИЛЯТОРЫ"; +"HARD DRIVES TEMPERATURES"="ТЕМПЕРАТУРЫ ДИСКОВ"; +"BATTERIES"="ЗАРЯД БАТАРЕЙ"; +"CPU Heatsink"="Радиатор ЦПУ"; +"CPU Proximity"="Датчик ЦПУ"; +"CPU %X Diode"="ЦПУ %X"; +"CPU %X Core"="Ядро ЦПУ %X"; +"GPU %X Board" = "GPU %X, радиатор "; +"GPU %X Core" = "GPU %X, ядро "; +"GPU %X Proximity" = "GPU %X, радиатор"; +"GPU %X Shaders"="GPU %X, шейдеры"; +"GPU %X Memory"="GPU %X, память"; +"GPU %X ROP"="GPU %X, ROP"; +"Motherboard"="Чипсет"; +"Memory"="Модули памяти"; +"Ambient"="Корпус"; +"CPU Package Multiplier"="Общий множитель ЦПУ"; +"CPU %X Multiplier"="Множитель ЦПУ %X"; +"CPU Voltage"="Вольтаж ЦПУ"; +"CPU VRM Voltage"="Шина ЦПУ"; +"DIMM Voltage"="Шина модулей DIMM"; +"+12V Bus Voltage"="Шина +12В"; +"+5V Bus Voltage"="Шина +5В"; +"-12V Bus Voltage"="Шина -12В"; +"-5V Bus Voltage"="Шина -5В"; +"3.3 VCC Voltage"="Шина 3.3В VCC"; +"3.3 VSB Voltage"="Шина 3.3В VSB"; +"Battery Voltage"="Шина батареи"; +"GPU %X Voltage"="Вольтаж GPU %X"; diff --git a/hwmonitor/ru.lproj/MainMenu.xib b/hwmonitor/ru.lproj/MainMenu.xib new file mode 100755 index 0000000..b961256 --- /dev/null +++ b/hwmonitor/ru.lproj/MainMenu.xib @@ -0,0 +1,3258 @@ + + + + 1070 + 11D50b + 1938 + 1138.32 + 568.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 1938 + + + NSUserDefaultsController + NSMenu + NSMenuItem + NSCustomObject + + + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + + NSApplication + + + FirstResponder + + + NSApplication + + + AMainMenu + + + + HWMonitor + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + HWMonitor + + + + About HWMonitor + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Preferences… + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + Services + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide HWMonitor + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit HWMonitor + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + submenuAction: + + File + + + + New + n + 1048576 + 2147483647 + + + + + + Open… + o + 1048576 + 2147483647 + + + + + + Open Recent + + 1048576 + 2147483647 + + + submenuAction: + + Open Recent + + + + Clear Menu + + 1048576 + 2147483647 + + + + + _NSRecentDocumentsMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Close + w + 1048576 + 2147483647 + + + + + + Save… + s + 1048576 + 2147483647 + + + + + + Revert to Saved + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Page Setup... + P + 1179648 + 2147483647 + + + + + + + Print… + p + 1048576 + 2147483647 + + + + + + + + + Edit + + 1048576 + 2147483647 + + + submenuAction: + + Edit + + + + Undo + z + 1048576 + 2147483647 + + + + + + Redo + Z + 1179648 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Cut + x + 1048576 + 2147483647 + + + + + + Copy + c + 1048576 + 2147483647 + + + + + + Paste + v + 1048576 + 2147483647 + + + + + + Paste and Match Style + V + 1572864 + 2147483647 + + + + + + Delete + + 1048576 + 2147483647 + + + + + + Select All + a + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Find + + 1048576 + 2147483647 + + + submenuAction: + + Find + + + + Find… + f + 1048576 + 2147483647 + + + 1 + + + + Find and Replace… + f + 1572864 + 2147483647 + + + 12 + + + + Find Next + g + 1048576 + 2147483647 + + + 2 + + + + Find Previous + G + 1179648 + 2147483647 + + + 3 + + + + Use Selection for Find + e + 1048576 + 2147483647 + + + 7 + + + + Jump to Selection + j + 1048576 + 2147483647 + + + + + + + + + Spelling and Grammar + + 1048576 + 2147483647 + + + submenuAction: + + Spelling and Grammar + + + + Show Spelling and Grammar + : + 1048576 + 2147483647 + + + + + + Check Document Now + ; + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Check Spelling While Typing + + 1048576 + 2147483647 + + + + + + Check Grammar With Spelling + + 1048576 + 2147483647 + + + + + + Correct Spelling Automatically + + 2147483647 + + + + + + + + + Substitutions + + 1048576 + 2147483647 + + + submenuAction: + + Substitutions + + + + Show Substitutions + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Smart Copy/Paste + f + 1048576 + 2147483647 + + + 1 + + + + Smart Quotes + g + 1048576 + 2147483647 + + + 2 + + + + Smart Dashes + + 2147483647 + + + + + + Smart Links + G + 1179648 + 2147483647 + + + 3 + + + + Text Replacement + + 2147483647 + + + + + + + + + Transformations + + 2147483647 + + + submenuAction: + + Transformations + + + + Make Upper Case + + 2147483647 + + + + + + Make Lower Case + + 2147483647 + + + + + + Capitalize + + 2147483647 + + + + + + + + + Speech + + 1048576 + 2147483647 + + + submenuAction: + + Speech + + + + Start Speaking + + 1048576 + 2147483647 + + + + + + Stop Speaking + + 1048576 + 2147483647 + + + + + + + + + + + + Format + + 2147483647 + + + submenuAction: + + Format + + + + Font + + 2147483647 + + + submenuAction: + + Font + + + + Show Fonts + t + 1048576 + 2147483647 + + + + + + Bold + b + 1048576 + 2147483647 + + + 2 + + + + Italic + i + 1048576 + 2147483647 + + + 1 + + + + Underline + u + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Bigger + + + 1048576 + 2147483647 + + + 3 + + + + Smaller + - + 1048576 + 2147483647 + + + 4 + + + + YES + YES + + + 2147483647 + + + + + + Kern + + 2147483647 + + + submenuAction: + + Kern + + + + Use Default + + 2147483647 + + + + + + Use None + + 2147483647 + + + + + + Tighten + + 2147483647 + + + + + + Loosen + + 2147483647 + + + + + + + + + Ligature + + 2147483647 + + + submenuAction: + + Ligature + + + + Use Default + + 2147483647 + + + + + + Use None + + 2147483647 + + + + + + Use All + + 2147483647 + + + + + + + + + Baseline + + 2147483647 + + + submenuAction: + + Baseline + + + + Use Default + + 2147483647 + + + + + + Superscript + + 2147483647 + + + + + + Subscript + + 2147483647 + + + + + + Raise + + 2147483647 + + + + + + Lower + + 2147483647 + + + + + + + + + YES + YES + + + 2147483647 + + + + + + Show Colors + C + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Copy Style + c + 1572864 + 2147483647 + + + + + + Paste Style + v + 1572864 + 2147483647 + + + + + _NSFontMenu + + + + + Text + + 2147483647 + + + submenuAction: + + Text + + + + Align Left + { + 1048576 + 2147483647 + + + + + + Center + | + 1048576 + 2147483647 + + + + + + Justify + + 2147483647 + + + + + + Align Right + } + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Writing Direction + + 2147483647 + + + submenuAction: + + Writing Direction + + + + YES + Paragraph + + 2147483647 + + + + + + CURlZmF1bHQ + + 2147483647 + + + + + + CUxlZnQgdG8gUmlnaHQ + + 2147483647 + + + + + + CVJpZ2h0IHRvIExlZnQ + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + YES + Selection + + 2147483647 + + + + + + CURlZmF1bHQ + + 2147483647 + + + + + + CUxlZnQgdG8gUmlnaHQ + + 2147483647 + + + + + + CVJpZ2h0IHRvIExlZnQ + + 2147483647 + + + + + + + + + YES + YES + + + 2147483647 + + + + + + Show Ruler + + 2147483647 + + + + + + Copy Ruler + c + 1310720 + 2147483647 + + + + + + Paste Ruler + v + 1310720 + 2147483647 + + + + + + + + + + + + View + + 1048576 + 2147483647 + + + submenuAction: + + View + + + + Show Toolbar + t + 1572864 + 2147483647 + + + + + + Customize Toolbar… + + 1048576 + 2147483647 + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + Window + + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 2147483647 + + + submenuAction: + + Help + + + + HWMonitor Help + ? + 1048576 + 2147483647 + + + + + _NSHelpMenu + + + + _NSMainMenu + + + + + + + Закрыть HWMonitor + + 2147483647 + + NSImage + NSStopProgressTemplate + + + + + + YES + + + AppDelegate + + + NSFontManager + + + YES + + + + + + + terminate: + + + + 449 + + + + terminate: + + + + 684 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 495 + + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + print: + + + + 86 + + + + runPageLayout: + + + + 87 + + + + clearRecentDocuments: + + + + 127 + + + + performClose: + + + + 193 + + + + toggleContinuousSpellChecking: + + + + 222 + + + + undo: + + + + 223 + + + + copy: + + + + 224 + + + + checkSpelling: + + + + 225 + + + + paste: + + + + 226 + + + + stopSpeaking: + + + + 227 + + + + cut: + + + + 228 + + + + showGuessPanel: + + + + 230 + + + + redo: + + + + 231 + + + + selectAll: + + + + 232 + + + + startSpeaking: + + + + 233 + + + + delete: + + + + 235 + + + + performZoom: + + + + 240 + + + + performFindPanelAction: + + + + 241 + + + + centerSelectionInVisibleArea: + + + + 245 + + + + toggleGrammarChecking: + + + + 347 + + + + toggleSmartInsertDelete: + + + + 355 + + + + toggleAutomaticQuoteSubstitution: + + + + 356 + + + + toggleAutomaticLinkDetection: + + + + 357 + + + + saveDocument: + + + + 362 + + + + revertDocumentToSaved: + + + + 364 + + + + runToolbarCustomizationPalette: + + + + 365 + + + + toggleToolbarShown: + + + + 366 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + unhideAllApplications: + + + + 370 + + + + newDocument: + + + + 373 + + + + openDocument: + + + + 374 + + + + raiseBaseline: + + + + 426 + + + + lowerBaseline: + + + + 427 + + + + copyFont: + + + + 428 + + + + subscript: + + + + 429 + + + + superscript: + + + + 430 + + + + tightenKerning: + + + + 431 + + + + underline: + + + + 432 + + + + orderFrontColorPanel: + + + + 433 + + + + useAllLigatures: + + + + 434 + + + + loosenKerning: + + + + 435 + + + + pasteFont: + + + + 436 + + + + unscript: + + + + 437 + + + + useStandardKerning: + + + + 438 + + + + useStandardLigatures: + + + + 439 + + + + turnOffLigatures: + + + + 440 + + + + turnOffKerning: + + + + 441 + + + + toggleAutomaticSpellingCorrection: + + + + 456 + + + + orderFrontSubstitutionsPanel: + + + + 458 + + + + toggleAutomaticDashSubstitution: + + + + 461 + + + + toggleAutomaticTextReplacement: + + + + 463 + + + + uppercaseWord: + + + + 464 + + + + capitalizeWord: + + + + 467 + + + + lowercaseWord: + + + + 468 + + + + pasteAsPlainText: + + + + 486 + + + + performFindPanelAction: + + + + 487 + + + + performFindPanelAction: + + + + 488 + + + + performFindPanelAction: + + + + 489 + + + + showHelp: + + + + 493 + + + + alignCenter: + + + + 518 + + + + pasteRuler: + + + + 519 + + + + toggleRuler: + + + + 520 + + + + alignRight: + + + + 521 + + + + copyRuler: + + + + 522 + + + + alignJustified: + + + + 523 + + + + alignLeft: + + + + 524 + + + + makeBaseWritingDirectionNatural: + + + + 525 + + + + makeBaseWritingDirectionLeftToRight: + + + + 526 + + + + makeBaseWritingDirectionRightToLeft: + + + + 527 + + + + makeTextWritingDirectionNatural: + + + + 528 + + + + makeTextWritingDirectionLeftToRight: + + + + 529 + + + + makeTextWritingDirectionRightToLeft: + + + + 530 + + + + performFindPanelAction: + + + + 535 + + + + addFontTrait: + + + + 421 + + + + addFontTrait: + + + + 422 + + + + modifyFont: + + + + 423 + + + + orderFrontFontPanel: + + + + 424 + + + + modifyFont: + + + + 425 + + + + statusMenu + + + + 679 + + + + delegate + + + + 685 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + + + + + + + + + + + + 19 + + + + + + + + 56 + + + + + + + + 217 + + + + + + + + 83 + + + + + + + + 81 + + + + + + + + + + + + + + + + + 75 + + + + + 78 + + + + + 72 + + + + + 82 + + + + + 124 + + + + + + + + 77 + + + + + 73 + + + + + 79 + + + + + 112 + + + + + 74 + + + + + 125 + + + + + + + + 126 + + + + + 205 + + + + + + + + + + + + + + + + + + + + + + 202 + + + + + 198 + + + + + 207 + + + + + 214 + + + + + 199 + + + + + 203 + + + + + 197 + + + + + 206 + + + + + 215 + + + + + 218 + + + + + + + + 216 + + + + + + + + 200 + + + + + + + + + + + + + 219 + + + + + 201 + + + + + 204 + + + + + 220 + + + + + + + + + + + + + 213 + + + + + 210 + + + + + 221 + + + + + 208 + + + + + 209 + + + + + 57 + + + + + + + + + + + + + + + + + + 58 + + + + + 134 + + + + + 150 + + + + + 136 + + + + + 144 + + + + + 129 + + + + + 143 + + + + + 236 + + + + + 131 + + + + + + + + 149 + + + + + 145 + + + + + 130 + + + + + 24 + + + + + + + + + + + 92 + + + + + 5 + + + + + 239 + + + + + 23 + + + + + 295 + + + + + + + + 296 + + + + + + + + + 297 + + + + + 298 + + + + + 211 + + + + + + + + 212 + + + + + + + + + 195 + + + + + 196 + + + + + 346 + + + + + 348 + + + + + + + + 349 + + + + + + + + + + + + + + 350 + + + + + 351 + + + + + 354 + + + + + 375 + + + + + + + + 376 + + + + + + + + + 377 + + + + + + + + 388 + + + + + + + + + + + + + + + + + + + + + + + 389 + + + + + 390 + + + + + 391 + + + + + 392 + + + + + 393 + + + + + 394 + + + + + 395 + + + + + 396 + + + + + 397 + + + + + + + + 398 + + + + + + + + 399 + + + + + + + + 400 + + + + + 401 + + + + + 402 + + + + + 403 + + + + + 404 + + + + + 405 + + + + + + + + + + + + 406 + + + + + 407 + + + + + 408 + + + + + 409 + + + + + 410 + + + + + 411 + + + + + + + + + + 412 + + + + + 413 + + + + + 414 + + + + + 415 + + + + + + + + + + + 416 + + + + + 417 + + + + + 418 + + + + + 419 + + + + + 420 + + + + + 450 + + + + + + + + 451 + + + + + + + + + + 452 + + + + + 453 + + + + + 454 + + + + + 457 + + + + + 459 + + + + + 460 + + + + + 462 + + + + + 465 + + + + + 466 + + + + + 485 + + + + + 490 + + + + + + + + 491 + + + + + + + + 492 + + + + + 494 + + + + + 496 + + + + + + + + 497 + + + + + + + + + + + + + + + + + 498 + + + + + 499 + + + + + 500 + + + + + 501 + + + + + 502 + + + + + 503 + + + + + + + + 504 + + + + + 505 + + + + + 506 + + + + + 507 + + + + + 508 + + + + + + + + + + + + + + + + 509 + + + + + 510 + + + + + 511 + + + + + 512 + + + + + 513 + + + + + 514 + + + + + 515 + + + + + 516 + + + + + 517 + + + + + 534 + + + + + 536 + + + + + + + + 662 + + + + + 683 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 700 + + + + + AppDelegate + NSObject + + statusMenu + NSMenu + + + statusMenu + + statusMenu + NSMenu + + + + IBProjectSource + ./Classes/AppDelegate.h + + + + NSDocument + + id + id + id + id + id + id + + + + printDocument: + id + + + revertDocumentToSaved: + id + + + runPageLayout: + id + + + saveDocument: + id + + + saveDocumentAs: + id + + + saveDocumentTo: + id + + + + IBProjectSource + ./Classes/NSDocument.h + + + + + 0 + IBCocoaFramework + YES + 3 + + {11, 11} + {10, 3} + {11, 11} + + + diff --git a/hwmonitor/smc.c b/hwmonitor/smc.c new file mode 100644 index 0000000..bd6fcfc --- /dev/null +++ b/hwmonitor/smc.c @@ -0,0 +1,199 @@ +/* + * Apple System Management Control (SMC) Tool + * Copyright (C) 2006 devnull + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +/* +cc ./smc.c -o smcutil -framework IOKit -framework CoreFoundation -Wno-four-char-constants -Wall -g -arch i386 + */ +#include +#include +#include +#include +#include +#include +//#include "OSTypes.h" +#include +//#include +//#include +//#define CF_OPEN_SOURCE 1 +//#include "OSTypes.h" +//#include "IOKitLib.h" + +#include "smc.h" + +io_connect_t conn; + +UInt32 _strtoul(char *str, int size, int base) { + UInt32 total = 0; + int i; + + for (i = 0; i < size; i++) { + if (base == 16) + total += str[i] << (size - 1 - i) * 8; + else + /*total += (unsigned char) (str[i] << (size - 1 - i) * 8);*/ + total += (((UInt32)str[i] & 0xFF) << (size - 1 - i) * 8); + } + return total; +} + +void _ultostr(char *str, UInt32 val) { + str[0] = '\0'; + snprintf(str, 5, "%c%c%c%c", + (unsigned int) val >> 24, + (unsigned int) val >> 16, + (unsigned int) val >> 8, + (unsigned int) val); +} + +float _strtof(char *str, int size, int e) { + float total = 0; + int i; + + for (i = 0; i < size; i++) { + if (i == (size - 1)) { + total += (str[i] & 0xff) >> e; + } else { + total += str[i] << (size - 1 - i) * (8 - e); + } + } + return total; +} + + + +kern_return_t SMCOpen(io_connect_t *conn) { + kern_return_t result; + mach_port_t masterPort; + io_iterator_t iterator; + io_object_t device; + + result = IOMasterPort(MACH_PORT_NULL, &masterPort); + if (result != kIOReturnSuccess) { + printf("Error: IOMasterPort() = %08x\n", result); + return 1; + } + + CFMutableDictionaryRef matchingDictionary = IOServiceMatching("AppleSMC"); + result = IOServiceGetMatchingServices(masterPort, matchingDictionary, &iterator); + if (result != kIOReturnSuccess) { + printf("Error: IOServiceGetMatchingServices() = %08x\n", result); + return 1; + } + + device = IOIteratorNext(iterator); + IOObjectRelease((io_object_t)iterator); + if (device == 0) { + printf("Error: no SMC found\n"); + return 1; + } + + result = IOServiceOpen(device, mach_task_self(), 0, conn); + IOObjectRelease(device); + if (result != kIOReturnSuccess) { + printf("Error: IOServiceOpen() = %08x\n", result); + return 1; + } + + return kIOReturnSuccess; +} + +kern_return_t SMCClose(io_connect_t conn) { + return IOServiceClose(conn); +} + + +kern_return_t SMCCall(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure) { + size_t structureInputSize; + size_t structureOutputSize; + + structureInputSize = sizeof(SMCKeyData_t); + structureOutputSize = sizeof(SMCKeyData_t); + + return IOConnectCallStructMethod( + conn, + index, + inputStructure, + structureInputSize, + outputStructure, + &structureOutputSize + ); +} + +kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t *val) { + kern_return_t result; + SMCKeyData_t inputStructure; + SMCKeyData_t outputStructure; + + memset(&inputStructure, 0, sizeof(SMCKeyData_t)); + memset(&outputStructure, 0, sizeof(SMCKeyData_t)); + memset(val, 0, sizeof(SMCVal_t)); + + inputStructure.key = _strtoul(key, 4, 16); + snprintf(val->key, 5, "%s", key); + inputStructure.data8 = SMC_CMD_READ_KEYINFO; + + result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure); + if (result != kIOReturnSuccess) + return result; + + val->dataSize = outputStructure.keyInfo.dataSize; + _ultostr(val->dataType, outputStructure.keyInfo.dataType); + inputStructure.keyInfo.dataSize = val->dataSize; + inputStructure.data8 = SMC_CMD_READ_BYTES; + + result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure); + if (result != kIOReturnSuccess) { + return result; + } + + memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes)); + return kIOReturnSuccess; +} + +kern_return_t SMCWriteKey(SMCVal_t writeVal) { + kern_return_t result; + SMCKeyData_t inputStructure; + SMCKeyData_t outputStructure; + + SMCVal_t readVal; + + result = SMCReadKey(writeVal.key, &readVal); + if (result != kIOReturnSuccess) { + return result; + } + + if (readVal.dataSize != writeVal.dataSize) { + // return kIOReturnError; + writeVal.dataSize = readVal.dataSize; + } + + memset(&inputStructure, 0, sizeof(SMCKeyData_t)); + memset(&outputStructure, 0, sizeof(SMCKeyData_t)); + + inputStructure.key = _strtoul(writeVal.key, 4, 16); + inputStructure.data8 = SMC_CMD_WRITE_BYTES; + inputStructure.keyInfo.dataSize = writeVal.dataSize; + memcpy(inputStructure.bytes, writeVal.bytes, sizeof(writeVal.bytes)); + + result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure); + if (result != kIOReturnSuccess) { + return result; + } + + return kIOReturnSuccess; +} diff --git a/hwmonitor/smc.h b/hwmonitor/smc.h new file mode 100644 index 0000000..b394df8 --- /dev/null +++ b/hwmonitor/smc.h @@ -0,0 +1,102 @@ +/* + * Apple System Management Control (SMC) Tool + * Copyright (C) 2006 devnull + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __SMC_H__ +#define __SMC_H__ +#endif + +#define VERSION "0.01" + +#define OP_NONE 0 +#define OP_LIST 1 +#define OP_READ 2 +#define OP_READ_FAN 3 +#define OP_WRITE 4 +#define OP_BRUTEFORCE 5 + +#define KERNEL_INDEX_SMC 2 + +#define SMC_CMD_READ_BYTES 5 +#define SMC_CMD_WRITE_BYTES 6 +#define SMC_CMD_READ_INDEX 8 +#define SMC_CMD_READ_KEYINFO 9 +#define SMC_CMD_READ_PLIMIT 11 +#define SMC_CMD_READ_VERS 12 + +#define DATATYPE_FPE2 "fpe2" +#define DATATYPE_UINT8 "ui8 " +#define DATATYPE_UINT16 "ui16" +#define DATATYPE_UINT32 "ui32" + +typedef struct { + char major; + char minor; + char build; + char reserved[1]; + UInt16 release; +} SMCKeyData_vers_t; + +typedef struct { + UInt16 version; + UInt16 length; + UInt32 cpuPLimit; + UInt32 gpuPLimit; + UInt32 memPLimit; +} SMCKeyData_pLimitData_t; + +typedef struct { + UInt32 dataSize; + UInt32 dataType; + char dataAttributes; +} SMCKeyData_keyInfo_t; + +typedef char SMCBytes_t[32]; + +typedef struct { + UInt32 key; + SMCKeyData_vers_t vers; + SMCKeyData_pLimitData_t pLimitData; + SMCKeyData_keyInfo_t keyInfo; + char result; + char status; + char data8; + UInt32 data32; + SMCBytes_t bytes; +} SMCKeyData_t; + +typedef char UInt32Char_t[5]; + +typedef struct { + UInt32Char_t key; + UInt32 dataSize; + UInt32Char_t dataType; + SMCBytes_t bytes; +} SMCVal_t; + +extern io_connect_t conn; + +kern_return_t SMCWriteKey(SMCVal_t writeVal); +kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t *val); +kern_return_t SMCCall(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure); +kern_return_t SMCClose(io_connect_t conn); +kern_return_t SMCOpen(io_connect_t *conn); + +UInt32 _strtoul(char *str, int size, int base); +void _ultostr(char *str, UInt32 val); +float _strtof(char *str, int size, int e); diff --git a/hwmonitor/ssd_small.png b/hwmonitor/ssd_small.png new file mode 100644 index 0000000..11cbb18 Binary files /dev/null and b/hwmonitor/ssd_small.png differ diff --git a/hwmonitor/temp_alt_small.png b/hwmonitor/temp_alt_small.png new file mode 100644 index 0000000..c0acfe6 Binary files /dev/null and b/hwmonitor/temp_alt_small.png differ diff --git a/hwmonitor/temperature_small.png b/hwmonitor/temperature_small.png new file mode 100644 index 0000000..815864e Binary files /dev/null and b/hwmonitor/temperature_small.png differ diff --git a/hwmonitor/temperature_small_dark.png b/hwmonitor/temperature_small_dark.png new file mode 100644 index 0000000..924701e Binary files /dev/null and b/hwmonitor/temperature_small_dark.png differ diff --git a/hwmonitor/temperature_small_grey.png b/hwmonitor/temperature_small_grey.png new file mode 100644 index 0000000..cb1c73f Binary files /dev/null and b/hwmonitor/temperature_small_grey.png differ diff --git a/hwmonitor/voltage_small.png b/hwmonitor/voltage_small.png new file mode 100644 index 0000000..a126dd8 Binary files /dev/null and b/hwmonitor/voltage_small.png differ diff --git a/plugins/ACPIMonitor/ACPIMonitor-Info.plist b/plugins/ACPIMonitor/ACPIMonitor-Info.plist new file mode 100644 index 0000000..4e5041e --- /dev/null +++ b/plugins/ACPIMonitor/ACPIMonitor-Info.plist @@ -0,0 +1,79 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + IOKitPersonalities + + ACPI Monitoring Plugin + + CFBundleIdentifier + org.slice.${PRODUCT_NAME} + FanNames + + System Fan + CPU Fan + Power Fan + Intake Fan + Exhaust Fan + Fan 6 + Fan 7 + Fan 8 + Fan 9 + Fan 10 + + IOClass + ACPIMonitor + IOMatchCategory + ${PRODUCT_NAME} + IONameMatch + + monitor + + IOProviderClass + IOACPIPlatformDevice + keysToAdd + + MSLD + MSLD-1 + TCRR + TA0P + TCRW + TA1P + + + + OSBundleLibraries + + com.apple.iokit.IOACPIFamily + 1.2.0 + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.mach + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + OSBundleRequired + Root + + diff --git a/plugins/ACPIMonitor/ACPIMonitor-pre106-Info.plist b/plugins/ACPIMonitor/ACPIMonitor-pre106-Info.plist new file mode 100644 index 0000000..cb022ac --- /dev/null +++ b/plugins/ACPIMonitor/ACPIMonitor-pre106-Info.plist @@ -0,0 +1,68 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.slice.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + IOKitPersonalities + + ACPI Monitoring Plugin + + CFBundleIdentifier + org.slice.${PRODUCT_NAME} + IOClass + ACPIMonitor + IOMatchCategory + ${PRODUCT_NAME} + IONameMatch + + monitor + + IOProviderClass + IOACPIPlatformDevice + Fan Names + + System Fan + Processor Fan + Power Fan + Intake Fan + Exhaust Fan + + keysToAdd + + TCRK + TW0P + + + + OSBundleLibraries + + org.netkas.FakeSMC + 3.1.0 + com.apple.iokit.IOACPIFamily + 1.0.0d1 + com.apple.kernel.6.0 + 7.9.9 + com.apple.kernel.iokit + 7.9.9 + com.apple.kernel.libkern + 7.9.9 + + OSBundleRequired + Root + + diff --git a/plugins/ACPIMonitor/ACPIMonitor.cpp b/plugins/ACPIMonitor/ACPIMonitor.cpp new file mode 100644 index 0000000..71c863e --- /dev/null +++ b/plugins/ACPIMonitor/ACPIMonitor.cpp @@ -0,0 +1,442 @@ +/* + * ACPIMonitor.cpp + * HWSensors + * + * Created by mozo on 12/11/10. + * Copyright 2010 Slice. All rights reserved. + * + */ + +#include "ACPIMonitor.h" +#include "../../fakesmc/FakeSMC.h" +#include "../../utils/utils.h" + +#define Debug FALSE + +#define LogPrefix "ACPIMonitor: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +#define super IOService +OSDefineMetaClassAndStructors(ACPIMonitor, IOService) + +bool ACPIMonitor::addSensor(const char* method, const char* key, const char* type, unsigned long long size) { + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)key, + (void *)type, + (void *)size, + (void *)this)) { + if (sensors && sensors->setObject(key, OSString::withCString(method))) { + InfoLog("%s registered", method); + return true; + } + } + return false; +} +// for example addTachometer("FAN0", "System Fan"); +bool ACPIMonitor::addTachometer(const char* method, const char* id) { + UInt8 length = 0; + void * data = 0; + + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, + true, + (void *)KEY_FAN_NUMBER, + (void *)&length, + (void *)&data, + 0)) { + length = 0; + + bcopy(data, &length, 1); + + char name[5]; + + snprintf(name, 5, KEY_FORMAT_FAN_SPEED, length); + + if (addSensor(method, name, TYPE_FPE2, 2)) { + if (id) { + FanTypeDescStruct fds; + snprintf(name, 5, KEY_FORMAT_FAN_ID, length); + fds.type = FAN_PWM_TACH; + fds.ui8Zone = 1; + fds.location = LEFT_LOWER_FRONT; + strncpy(fds.strFunction, id, DIAG_FUNCTION_STR_LEN); + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyValue, + false, + (void *)name, + (void *)TYPE_FDESC, + (void *)((UInt64)sizeof(fds)), + (void *)&fds)) { + + WarningLog("error adding tachometer id value"); + } + } + length++; + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCSetKeyValue, + true, + (void *)KEY_FAN_NUMBER, + (void *)1, + (void *)&length, 0)) { + WarningLog("error updating FNum value"); + } + + return true; + } + } else { + WarningLog("error reading FNum value"); + } + + return false; +} + +IOService* ACPIMonitor::probe(IOService *provider, SInt32 *score) { + if (super::probe(provider, score) != this) { return 0; } + + return this; +} + +bool ACPIMonitor::start(IOService * provider) { + if (!provider || !super::start(provider)) { return false; } + + if (!(fakeSMC = waitForService(serviceMatching(kFakeSMCDeviceService)))) { + WarningLog("Can't locate fake SMC device, kext will not load"); + return false; + } + char key[5]; + acpiDevice = (IOACPIPlatformDevice *)provider; + + //Here is Fan in ACPI + OSArray* fanNames = OSDynamicCast(OSArray, getProperty("FanNames")); + + for (int i=0; i<10; i++) { + snprintf(key, 5, "FAN%X", i); + + if (kIOReturnSuccess == acpiDevice->validateObject(key)) { + OSString* name = NULL; + + if (fanNames) { + name = OSDynamicCast(OSString, fanNames->getObject(i)); + } + + if (!addTachometer(key, name ? name->getCStringNoCopy() : 0)) { + WarningLog("Can't add tachometer sensor, key %s", key); + } + } else { + snprintf(key, 5, "FTN%X", i); + if (kIOReturnSuccess == acpiDevice->validateObject(key)){ + OSString* name = NULL; + + if (fanNames) { + name = OSDynamicCast(OSString, fanNames->getObject(i)); + } + + if (!addTachometer(key, name ? name->getCStringNoCopy() : 0)) { + WarningLog("Can't add tachometer sensor, key %s", key); + } + } else { + break; + } + } + } + + //Next step - temperature keys + if (kIOReturnSuccess == acpiDevice->validateObject("TCPU")) { + addSensor("TCPU", KEY_CPU_HEATSINK_TEMPERATURE, TYPE_SP78, 2); //Th0H + } + + if (kIOReturnSuccess == acpiDevice->validateObject("TSYS")) { + addSensor("TSYS", KEY_NORTHBRIDGE_TEMPERATURE, TYPE_SP78, 2); //TN0P + } + + if (kIOReturnSuccess == acpiDevice->validateObject("TDIM")) { + addSensor("TDIM", KEY_DIMM_TEMPERATURE, TYPE_SP78, 2); //Tm0P + } + + if (kIOReturnSuccess == acpiDevice->validateObject("TAMB")) { + addSensor("TAMB", KEY_AMBIENT_TEMPERATURE, TYPE_SP78, 2); //TA0P + } + + if (kIOReturnSuccess == acpiDevice->validateObject("TCPP")) { + addSensor("TCPP", KEY_CPU_PROXIMITY_TEMPERATURE, TYPE_SP78, 2); //TC0P + } + // We should add also GPU reading stuff for those who has no supported plug in but have the value on EC registers + + + + //Voltage + if (kIOReturnSuccess == acpiDevice->validateObject("VCPU")) { + addSensor("VCPU", KEY_CPU_VOLTAGE, TYPE_FP2E, 2); //VC0C + } + + if (kIOReturnSuccess == acpiDevice->validateObject("VMEM")) { + addSensor("VMEM", KEY_MEMORY_VOLTAGE, TYPE_FP2E, 2); //VM0R + } + + if (kIOReturnSuccess == acpiDevice->validateObject("VP0R")) { + addSensor("VP0R", KEY_12V_VOLTAGE, TYPE_SP4B, 2); //VP0R + } + + if (kIOReturnSuccess == acpiDevice->validateObject("VSN0")) { + addSensor("VSN0", KEY_N12VC_VOLTAGE, TYPE_SP4B, 2); //Vp0C + } + + if (kIOReturnSuccess == acpiDevice->validateObject("VSN1")) { + addSensor("VSN1", KEY_5VC_VOLTAGE, TYPE_SP4B, 2); //Vp1C + } + + if (kIOReturnSuccess == acpiDevice->validateObject("VSN2")) { + addSensor("VSN2", KEY_5VSB_VOLTAGE, TYPE_SP4B, 2); //Vp2C" + } + + if (kIOReturnSuccess == acpiDevice->validateObject("VSN3")) { + addSensor("VSN3", KEY_3VCC_VOLTAGE, TYPE_FP2E, 2); //Vp3C" + } + + if (kIOReturnSuccess == acpiDevice->validateObject("VSN4")) { + addSensor("VSN4", KEY_3VSB_VOLTAGE, TYPE_FP2E, 2); //Vp4C" + } + + if (kIOReturnSuccess == acpiDevice->validateObject("VSN5")) { + addSensor("VSN5", KEY_AVCC_VOLTAGE, TYPE_FP2E, 2); //Vp5C" + } + + //Amperage + if (kIOReturnSuccess == acpiDevice->validateObject("ISN0")) { + addSensor("ISN0", "ICAC", TYPE_UI16, 2); + } + + if (kIOReturnSuccess == acpiDevice->validateObject("ISN1")) { + addSensor("ISN1", "Ip0C", TYPE_UI16, 2); + } + + if (kIOReturnSuccess == acpiDevice->validateObject("ISN2")) { + addSensor("ISN2", "Ip1C", TYPE_UI16, 2); + } + + if (kIOReturnSuccess == acpiDevice->validateObject("ISN3")) { + addSensor("ISN3", "Ip2C", TYPE_UI16, 2); + } + + //Power + if (kIOReturnSuccess == acpiDevice->validateObject("PSN0")) { + addSensor("PSN0", "PC0C", TYPE_UI16, 2); + } + + if (kIOReturnSuccess == acpiDevice->validateObject("PSN1")) { + addSensor("PSN1", "PC1C", TYPE_UI16, 2); + } + + // AC Power/Battery + if (kIOReturnSuccess == acpiDevice->validateObject("ACDC")) { // Power Source Read AC/Battery + addSensor("ACDC", "ACEN", TYPE_UI8, 1); + addSensor("ACDC", "ACFP", TYPE_FLAG, 1); + addSensor("ACDC", "ACIN", TYPE_FLAG, 1); + } + // TODO real SMC returns ACID only when AC is plugged, if not is zeroed, so hardcoding it in plist is not OK IMHO + // Same goes for ACIC, but no idea how we can get the AC current value.. + + // Here if ACDC returns 0 we need to set the on battery BATP flag + + // Battery stuff, need to implement rest of the keys once I figure those + if (kIOReturnSuccess == acpiDevice->validateObject("BAK0")) { // Battery 0 Current + addSensor("BAK0", "B0AC", TYPE_SI16, 2); + } + + if (kIOReturnSuccess == acpiDevice->validateObject("BAK1")) { // Battery 0 Voltage + addSensor("BAK1", "B0AV", TYPE_UI16, 2); + } + + //Keys from info.plist + OSDictionary *keysToAdd = 0; + + keysToAdd = OSDynamicCast(OSDictionary, getProperty("keysToAdd")); + if (keysToAdd) { + OSIterator *iter = OSCollectionIterator::withCollection(keysToAdd); + if (iter) { + const OSSymbol *dictKey = 0; + while ((dictKey = (const OSSymbol *)iter->getNextObject())) { + char acpiName[5]; + snprintf(acpiName, 5, "%s", dictKey->getCStringNoCopy()); + //WarningLog(" Found key %s", acpiName); + OSString *tmpString = OSDynamicCast(OSString, keysToAdd->getObject(dictKey)); + if (tmpString) { + char aKey[8]; + snprintf(aKey, 8, "%s", tmpString->getCStringNoCopy()); + InfoLog("Custom name=%s key=%s", acpiName, aKey); + if (kIOReturnSuccess == acpiDevice->validateObject(acpiName)) { + if (aKey[0] == 'F') { + if (!addTachometer(aKey, acpiName)) { + WarningLog("Can't add tachometer sensor, key %s", aKey); + } + } else { + const char *Type = TYPE_UI16; + int Size = 2; + if (aKey[4] == '-') { + int Len = aKey[5] - '0'; + aKey[4] = '\0'; + aKey[5] = '\0'; + switch (Len) { + case 0: + Type = TYPE_FLAG; + Size = 1; + break; + case 1: + Type = TYPE_UI8; + Size = 1; + break; + case 4: + Type = TYPE_UI32; + Size = 4; + break; + case 3: + Type = TYPE_SP78; + Size = 2; + break; + case 2: + default: + Type = TYPE_UI16; + break; + } + } + addSensor(acpiName, aKey, Type, Size); + } + } + } else { + WarningLog(" no value for key %s", acpiName); + } + } + } else { + WarningLog(" can't interate keysToAdd"); + } + } else { + WarningLog(" keysToAdd not found"); + } + + registerService(0); + + return true; +} + + +bool ACPIMonitor::init(OSDictionary *properties) { + if (!super::init(properties)) { + return false; + } + + if (!(sensors = OSDictionary::withCapacity(0))) { + return false; + } + + return true; +} + +void ACPIMonitor::stop(IOService* provider) { + sensors->flushCollection(); + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCRemoveKeyHandler, + true, + this, + NULL, + NULL, + NULL)) { + WarningLog("Can't remove key handler"); + IOSleep(500); + } + + super::stop(provider); +} + +void ACPIMonitor::free() { + sensors->release(); + + super::free(); +} + +#define MEGA10 10000000ull +IOReturn ACPIMonitor::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4) { + const char* name = (const char*)param1; + void * data = param2; + UInt64 size = (UInt64)param3; + //callPlatformFunction(kFakeSMCAddKeyHandler, false, (void *)key, (void *)type, (void *)size, (void *)this)) + OSString* key; +#if __LP64__ + UInt64 value = 0; +#else + UInt32 value; +#endif + UInt16 val = 0; + + if (functionName->isEqualTo(kFakeSMCSetValueCallback)) { + if (name && data) { + key = OSDynamicCast(OSString, sensors->getObject(name)); + if (key) { + InfoLog("Writing key=%s by method=%s value=%x", name, key->getCStringNoCopy(), *(UInt16*)data); + OSObject * params[1]; + if (key->getChar(0) == 'F') { + val = decode_fpe2(*(UInt16*)data); + } else { + val = *(UInt16*)data; + } + params[0] = OSDynamicCast(OSObject, OSNumber::withNumber((unsigned long long)val, 32)); + return acpiDevice->evaluateInteger(key->getCStringNoCopy(), &value, params, 1); + + /* + virtual IOReturn evaluateInteger( const OSSymbol * objectName, + UInt32 * resultInt32, + OSObject * params[] = 0, + IOItemCount paramCount = 0, + IOOptionBits options = 0 ); + flags_num = OSNumber::withNumber((unsigned long long)flags, 32); + */ + + } + return kIOReturnBadArgument; + } + return kIOReturnBadArgument; + } + + if (functionName->isEqualTo(kFakeSMCGetValueCallback)) { + if (name && data) { + key = OSDynamicCast(OSString, sensors->getObject(name)); //ACPI name + if (key) { + if (kIOReturnSuccess == acpiDevice->evaluateInteger(key->getCStringNoCopy(), &value)) { + val = 0; + if (key->getChar(0) == 'V') { + if (key->getChar(3) <= '2' || key->getChar(3) == 'R') { + val = encode_sp4b(value); //VSN 0 1 2 R + } else { + val = encode_fp2e(value); + } + } else if (key->getChar(0) == 'F') { + if (key->getChar(1) == 'A') { + val = encode_fpe2(value); + } else { + if (key->getChar(1) == 'T') { + val = value?encode_fpe2(MEGA10 / value):0; + } else { + val = value; + } + } + } else { + val = value; + } + bcopy(&val, data, size); + return kIOReturnSuccess; + } + } + return kIOReturnBadArgument; + } + + //DebugLog("bad argument key name or data"); + return kIOReturnBadArgument; + } + + return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); +} diff --git a/plugins/ACPIMonitor/ACPIMonitor.h b/plugins/ACPIMonitor/ACPIMonitor.h new file mode 100644 index 0000000..4aa2ef4 --- /dev/null +++ b/plugins/ACPIMonitor/ACPIMonitor.h @@ -0,0 +1,40 @@ +/* + * ACPIMonitor.h + * HWSensors + * + * Created by Slice. + * + */ + +#include +#include "IOKit/acpi/IOACPIPlatformDevice.h" +#include + +class ACPIMonitor : public IOService +{ + OSDeclareDefaultStructors(ACPIMonitor) +private: + IOService* fakeSMC; + IOACPIPlatformDevice* acpiDevice; + OSDictionary* sensors; + + bool addSensor(const char* method, + const char* key, + const char* type, + unsigned long long size); + bool addTachometer(const char* method, const char* caption); + +public: + virtual IOService* probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual bool init(OSDictionary *properties=0); + virtual void free(void); + virtual void stop(IOService *provider); + + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); +}; diff --git a/plugins/ACPIMonitor/SSDT-Monitor.dsl b/plugins/ACPIMonitor/SSDT-Monitor.dsl new file mode 100644 index 0000000..9b20f5f --- /dev/null +++ b/plugins/ACPIMonitor/SSDT-Monitor.dsl @@ -0,0 +1,77 @@ +/* + * Intel ACPI Component Architecture + * AML/ASL+ Disassembler version 20160729-64 + * Copyright (c) 2000 - 2016 Intel Corporation + * + * Disassembling to symbolic ASL+ operators + * + * Disassembly of /Volumes/MacHD/Applications/0App/DarwinDumper_3.0.4_13.01_20.19.19_MacBookPro10,1_AMI_X64_4837_High Sierra_17G4015_sergey/ACPI Tables/AML/SSDT-2.aml, Sun Jan 13 20:23:34 2019 + * + * Original Table Header: + * Signature "SSDT" + * Length 0x0000016C (364) + * Revision 0x02 + * Checksum 0xAE + * OEM ID "APPLE " + * OEM Table ID "Monitor" + * OEM Revision 0x00001000 (4096) + * Compiler ID "INTL" + * Compiler Version 0x20160729 (538314537) + */ +DefinitionBlock ("", "SSDT", 2, "APPLE ", "Monitor", 0x00001000) +{ + External (_SB_.ADP1._PSR, MethodObj) // 0 Arguments + External (_SB_.LID0, DeviceObj) + External (_SB_.LID0._LID, MethodObj) // 0 Arguments + External (_SB_.PCI0.LPCB.EC, DeviceObj) + External (_TZ_.THM_._TMP, MethodObj) // 0 Arguments + + Scope (\_SB.PCI0.LPCB.EC) + { + Device (FSAM) + { + Name (_HID, EisaId ("APP0111")) // _HID: Hardware ID + Name (_CID, "monitor") // _CID: Compatible ID + Name (PLID, 0xFFFF) //save previous LID status + Name (PPSR, 0xFFFF) + Name (BPSR, 0xFFFF) + Method (MSLD, 0, NotSerialized) + { + Local0 = \_SB.LID0._LID () + If (Local0 != PLID) + { + PLID = Local0 + Notify (\_SB.LID0, 0x80) // Status Change + } + + Return (Local0 ^ One) + } + + Method (TSYS, 0, NotSerialized) + { + Local1 = MSLD () + Local0 = \_TZ.THM._TMP () + Local0 &= 0x7F + Return (Local0) + } + + Method (ACDC, 0, NotSerialized) + { + Local0 = \_SB.ADP1._PSR () + If (Local0 != PPSR) + { + PPSR = Local0 + BPSR = (PPSR ^ One) + } + + Return (PPSR) /* \_SB_.PCI0.LPCB.EC.FSAM.PPSR */ + } + + // Method (BATP, 0, NotSerialized) + // { + // Return (BPSR) /* \_SB_.PCI0.LPCB.EC.FSAM.BPSR */ + // } + } + } +} + diff --git a/plugins/CPUSensors/AmdCPUMonitor/AmdCPUMonitor-Info.plist b/plugins/CPUSensors/AmdCPUMonitor/AmdCPUMonitor-Info.plist new file mode 100644 index 0000000..54836a6 --- /dev/null +++ b/plugins/CPUSensors/AmdCPUMonitor/AmdCPUMonitor-Info.plist @@ -0,0 +1,53 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + IOKitPersonalities + + AMD CPU Monitor + + CFBundleIdentifier + org.slice.sensor.${PRODUCT_NAME} + IOClass + AmdCPUMonitor + IOMatchCategory + AmdCPUMonitor + IOProbeScore + 500 + IOProviderClass + IOResources + IOResourceMatch + IOKit + + + OSBundleLibraries + + com.apple.iokit.IOPCIFamily + 2.4 + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + + diff --git a/plugins/CPUSensors/AmdCPUMonitor/AmdCPUMonitor-pre106-Info.plist b/plugins/CPUSensors/AmdCPUMonitor/AmdCPUMonitor-pre106-Info.plist new file mode 100644 index 0000000..b52e53a --- /dev/null +++ b/plugins/CPUSensors/AmdCPUMonitor/AmdCPUMonitor-pre106-Info.plist @@ -0,0 +1,55 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.slice.sensor.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + IOKitPersonalities + + Intel Thermal Management Controller + + CFBundleIdentifier + org.slice.sensor.${PRODUCT_NAME} + IOClass + IntelTMC + IOProbeScore + 500 + IOMatchCategory + IntelTMC + IOProviderClass + IOResources + IOResourceMatch + IOKit + + + OSBundleLibraries + + org.netkas.FakeSMC + 3.1.0 + com.apple.iokit.IOACPIFamily + 1.0.0d1 + com.apple.iokit.IOPCIFamily + 2.4 + com.apple.kernel.6.0 + 7.9.9 + com.apple.kernel.iokit + 7.9.9 + com.apple.kernel.libkern + 7.9.9 + + + diff --git a/plugins/CPUSensors/AmdCPUMonitor/AmdCPUMonitor.cpp b/plugins/CPUSensors/AmdCPUMonitor/AmdCPUMonitor.cpp new file mode 100644 index 0000000..a17a908 --- /dev/null +++ b/plugins/CPUSensors/AmdCPUMonitor/AmdCPUMonitor.cpp @@ -0,0 +1,168 @@ +/* + * AmdCPUMonitor.cpp + * HWSensors + * + * Copyright 2014 Slice. All rights reserved. + * First created at 25.02.2014 + */ + +#include "AmdCPUMonitor.h" +#include "FakeSMC.h" + + +#define super IOService +OSDefineMetaClassAndStructors(AmdCPUMonitor, IOService) + +bool AmdCPUMonitor::addSensor(const char* key, + const char* type, + unsigned int size, + int index) { + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, (void *)key, + (void *)type, + (void *)(long long)size, + (void *)this)) { + return sensors->setObject(key, OSNumber::withNumber(index, 32)); + } + return false; +} + +IOService* AmdCPUMonitor::probe(IOService *provider, SInt32 *score) { + if (super::probe(provider, score) != this) { return 0; } + UInt32 vendor_id = 0, device_id = 0, class_id = 0; + if (OSDictionary * dictionary = serviceMatching(kGenericPCIDevice)) { + if (OSIterator * iterator = getMatchingServices(dictionary)) { + + IOPCIDevice* device = 0; + + while ((device = OSDynamicCast(IOPCIDevice, iterator->getNextObject()))) { + OSData *data = OSDynamicCast(OSData, device->getProperty(fVendor)); + if (data) { + vendor_id = *(UInt32*)data->getBytesNoCopy(); + } + + data = OSDynamicCast(OSData, device->getProperty(fDevice)); + if (data) { + device_id = *(UInt32*)data->getBytesNoCopy(); + } + + data = OSDynamicCast(OSData, device->getProperty(fClass)); + if (data) { + class_id = *(UInt32*)data->getBytesNoCopy(); + } + + if (((vendor_id==0x1022) && ((device_id & 0xF0FF)== 0x1003)) || + ((vendor_id==0x1022) && (device_id== 0x1463))) { //Rizen + InfoLog("found AMD Miscellaneous Control id=%x class_id=%x", (UInt16)device_id, class_id); + VCard = device; + } + } + } + } + return this; +} + +bool AmdCPUMonitor::start(IOService * provider) { + if (!provider || !super::start(provider)) { return false; } + + if (!(fakeSMC = waitForService(serviceMatching(kFakeSMCDeviceService)))) { + WarningLog("Can't locate fake SMC device, kext will not load"); + return false; + } + if (!VCard) { + return false; + } + + char name[5]; + snprintf(name, 5, KEY_CPU_PROXIMITY_TEMPERATURE); + + UInt8 length = 0; + void * data = 0; + + IOReturn result = fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, + true, (void *)name, + (void *)&length, + (void *)&data, 0); + + if (kIOReturnSuccess == result) { + WarningLog("Key TC0P already exists, kext will not load"); + return false; + } + + if (addSensor(name, TYPE_SP78, 2, 0)) { + InfoLog(" AMD CPU temperature sensor added"); + } + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, (void *)name, + (void *)TYPE_SP78, + (void *)2, this)) { + WarningLog("Can't add key to fake SMC device, kext will not load"); + return false; + } + + return true; +} + + +bool AmdCPUMonitor::init(OSDictionary *properties) { + if (!super::init(properties)) { + return false; + } + + if (!(sensors = OSDictionary::withCapacity(0))) { + return false; + } + + return true; +} + +void AmdCPUMonitor::stop (IOService* provider) { + sensors->flushCollection(); + super::stop(provider); +} + +void AmdCPUMonitor::free () { + sensors->release(); + super::free(); +} + +IOReturn AmdCPUMonitor::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4 ) { + //UInt16 t; + UInt32 value=0; + + if (functionName->isEqualTo(kFakeSMCGetValueCallback)) { + const char* name = (const char*)param1; + void* data = param2; + + if (name && data) { + switch (name[0]) { + case 'T': + if (strcasecmp(name, KEY_CPU_PROXIMITY_TEMPERATURE) == 0) { + value = (VCard->configRead32(0xA4) >> 21) / 8; + bcopy(&value, data, 2); + + return kIOReturnSuccess; + } + break; + default: + return kIOReturnBadArgument; + } + + //bcopy(&value, data, 2); + + return kIOReturnSuccess; + } + + //DebugLog("bad argument key name or data"); + + return kIOReturnBadArgument; + } + + return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); +} diff --git a/plugins/CPUSensors/AmdCPUMonitor/AmdCPUMonitor.h b/plugins/CPUSensors/AmdCPUMonitor/AmdCPUMonitor.h new file mode 100644 index 0000000..c8caf84 --- /dev/null +++ b/plugins/CPUSensors/AmdCPUMonitor/AmdCPUMonitor.h @@ -0,0 +1,90 @@ +/* + * AmdCPUMonitor.h + * HWSensors + * + * Created by Sergey on 19.12.10 with templates of Mozodojo. + * Copyright 2010 Slice. + * + */ + +#include +#include +#include + +#define kGenericPCIDevice "IOPCIDevice" +#define kTimeoutMSecs 1000 +#define fVendor "vendor-id" +#define fDevice "device-id" +#define fClass "class-code" +#define kIOPCIConfigBaseAddress0 0x10 + +//Intel Ibex Peak PCH and Intel Cougar Point +#define TBAR 0x10 /* OS address */ +#define TBARB 0x40 /* BIOS address */ +//on the BAR +#define TSIU 0x00 /* wait for 0, read T, then write 1 to release */ +#define TSE 0x01 /* enable thermometer -> 0xB8 */ +#define TSTR 0x03 /* Thermal Sensor Thermometer Read 1byte 00-7F*/ +#define TRC 0x1A /* enable mask for sensors 0x91FF */ +#define PTV 0x60 /* Processor Max Temperature Value 2bytes*/ +#define DTV 0xB0 /* DIMM Temperature Value 4bytes 4values for DIMM0,1,2,3*/ +#define ITV 0xD8 /* Internal Temperature Value 4bytes byte0=PCH byte1=GPU*/ +// +//Intel Ibex Peak PCH only +#define CTV1 0x30 /* Core Temperature Value 1 2bytes >>6 for Celsius*/ +#define CTV2 0x32 /* Core Temperature Value 2 2bytes*/ +#define CEV1 0x34 /* Core Energy Value 1 4bytes CEV1/65535*1000 = mW */ +#define MGTV 0x58 /* Graphics Temperature Value 8bytes ???*/ +/* + #define kMCHBAR 0x40 + #define TSC1 0x1001 + #define TSS1 0x1004 + #define TR1 0x1006 + #define RTR1 0x1008 + #define TIC1 0x100B + #define TSC2 0x1041 + #define TSS2 0x1044 + #define TR2 0x1046 + #define RTR2 0x1048 + #define TIC2 0x104B + */ + + +#define INVID8(offset) (mmio_base[offset]) +#define INVID16(offset) OSReadLittleInt16((mmio_base), offset) +#define INVID(offset) OSReadLittleInt32((mmio_base), offset) +#define OUTVID(offset,val) OSWriteLittleInt32((mmio_base), offset, val) + +#define Debug FALSE + +#define LogPrefix "AmdCPUMonitor: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +class AmdCPUMonitor : public IOService { + OSDeclareDefaultStructors(AmdCPUMonitor) +private: + IOService* fakeSMC; + OSDictionary* sensors; + volatile UInt8* mmio_base; + int numCard; //numCard=0 if only one Video, but may be any other value + IOPCIDevice * VCard; + IOMemoryMap * mmio; + + bool addSensor(const char* key, const char* type, unsigned int size, int index); + +public: + virtual IOService* probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual bool init(OSDictionary *properties=0); + virtual void free(void); + virtual void stop(IOService *provider); + + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); +}; diff --git a/plugins/CPUSensors/AmdCPUMonitor/English.lproj/InfoPlist.strings b/plugins/CPUSensors/AmdCPUMonitor/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..88f65cf --- /dev/null +++ b/plugins/CPUSensors/AmdCPUMonitor/English.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/plugins/CPUSensors/IntelCPUMonitor/IntelCPUMonitor-Info.plist b/plugins/CPUSensors/IntelCPUMonitor/IntelCPUMonitor-Info.plist new file mode 100644 index 0000000..4b00446 --- /dev/null +++ b/plugins/CPUSensors/IntelCPUMonitor/IntelCPUMonitor-Info.plist @@ -0,0 +1,55 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + IOKitPersonalities + + Intel CPU Monitor Plugin + + CFBundleIdentifier + org.slice.IntelCPUMonitor + IOClass + IntelCPUMonitor + IOMatchCategory + IntelCPUMonitor + IOProviderClass + IOResources + IOResourceMatch + IOKit + TjMax + 0 + + + OSBundleLibraries + + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.mach + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + OSBundleRequired + Root + + diff --git a/plugins/CPUSensors/IntelCPUMonitor/IntelCPUMonitor-pre106-Info.plist b/plugins/CPUSensors/IntelCPUMonitor/IntelCPUMonitor-pre106-Info.plist new file mode 100644 index 0000000..21ed73a --- /dev/null +++ b/plugins/CPUSensors/IntelCPUMonitor/IntelCPUMonitor-pre106-Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.mozodojo.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + IOKitPersonalities + + Intel CPU Monitor Plugin + + CFBundleIdentifier + org.mozodojo.IntelCPUMonitor + IOClass + IntelCPUMonitor + IOMatchCategory + IntelCPUMonitor + IOProviderClass + IOResources + IOResourceMatch + IOKit + + + OSBundleLibraries + + org.netkas.FakeSMC + 3.1.0 + com.apple.iokit.IOACPIFamily + 1.0.0d1 + com.apple.kernel.6.0 + 7.9.9 + com.apple.kernel.iokit + 7.9.9 + com.apple.kernel.libkern + 7.9.9 + + + diff --git a/plugins/CPUSensors/IntelCPUMonitor/IntelCPUMonitor.cpp b/plugins/CPUSensors/IntelCPUMonitor/IntelCPUMonitor.cpp new file mode 100644 index 0000000..70a91f1 --- /dev/null +++ b/plugins/CPUSensors/IntelCPUMonitor/IntelCPUMonitor.cpp @@ -0,0 +1,806 @@ +/* + * IntelCPUMonitor.cpp + * HWSensors + * + * Created by Slice on 20.12.10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +#include "IntelCPUMonitor.h" +#include "FakeSMC.h" +#include "../../../utils/utils.h" + +#define Debug FALSE + +#define LogPrefix "IntelCPUMonitor: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + + +static UInt8 GlobalThermalValue[MaxCpuCount]; +static bool GlobalThermalValueIsObsolete[MaxCpuCount]; +static PState GlobalState[MaxCpuCount]; +static UInt64 GlobalState64; //it is for package +static UInt16 InitFlags[MaxCpuCount]; +static UInt64 UCC[MaxCpuCount]; +static UInt64 UCR[MaxCpuCount]; +static UInt64 lastUCC[MaxCpuCount]; +static UInt64 lastUCR[MaxCpuCount]; + +const UInt32 Kilo = 1000; //Slice +const UInt32 Mega = Kilo * 1000; +//const UInt32 Giga = Mega * 1000; + + +inline UInt32 BaseOperatingFreq(void) { + UInt64 msr = rdmsr64(MSR_PLATFORM_INFO); + return (msr & 0xFF00) >> 8; +} + +inline UInt64 ReadUCC(void) { + UInt32 lo,hi; + rdpmc(0x40000001, lo, hi); + return ((UInt64)hi << 32 ) | lo; +} + +inline UInt64 ReadUCR(void) { + UInt32 lo,hi; + rdpmc(0x40000002, lo, hi); + return ((UInt64)hi << 32 )| lo; +} + +inline void initPMCCounters(UInt8 cpu) { + if (cpu < MaxCpuCount) { + if (!InitFlags[cpu]) { + wrmsr64(MSR_PERF_FIXED_CTR_CTRL, 0x222ll); + wrmsr64(MSR_PERF_GLOBAL_CTRL, 0x7ll << 32); + InitFlags[cpu]=true; + } + } +} + +inline void IntelWaitForSts(void) { + UInt32 inline_timeout = 100000; + while (rdmsr64(MSR_IA32_PERF_STS) & (1 << 21)) { + if (!inline_timeout--) { break; } + } +} + +void UCState(__unused void * magic) { + volatile UInt32 i = cpu_number(); + if (i < MaxCpuCount) { + initPMCCounters(i); + lastUCC[i]=UCC[i]; + lastUCR[i]=UCR[i]; + UCC[i]=ReadUCC(); + UCR[i]=ReadUCR(); + } +} + +void IntelState(__unused void * magic) { + volatile UInt32 i = cpu_number(); + if (i < MaxCpuCount) { + UInt64 msr = rdmsr64(MSR_IA32_PERF_STS); + GlobalState[i].Control = msr & 0xFFFF; + GlobalState64 = msr; + } +} + +void IntelThermal(__unused void * magic) { + volatile UInt32 i = cpu_number(); + if (i < MaxCpuCount) { + UInt64 msr = rdmsr64(MSR_IA32_THERM_STATUS); + // UInt64 E2 = rdmsr64(0xE2); //Check for E2 lock + if (msr & 0x80000000) { + GlobalThermalValue[i] = (msr >> 16) & 0x7F; + /* + if (E2 & 0x8000) { + GlobalThermalValue[i] -= 50; + } + */ + GlobalThermalValueIsObsolete[i]=false; + } + } +} + +void IntelState2(__unused void * magic) { + volatile UInt32 i = cpu_number() >> 1; + if (i < MaxCpuCount) { + UInt64 msr = rdmsr64(MSR_IA32_PERF_STS); + GlobalState[i].Control = msr & 0xFFFF; + GlobalState64 = msr; + } +} + +void IntelThermal2(__unused void * magic) { + volatile UInt32 i = cpu_number() >> 1; + if (i < MaxCpuCount) { + UInt64 msr = rdmsr64(MSR_IA32_THERM_STATUS); + if (msr & 0x80000000) { + GlobalThermalValue[i] = (msr >> 16) & 0x7F; + GlobalThermalValueIsObsolete[i]=false; + } + } +} + +// Power states! +enum { + kMyOnPowerState = 1 +}; + +static IOPMPowerState myTwoStates[2] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +#define super IOService +OSDefineMetaClassAndStructors(IntelCPUMonitor, IOService) + +bool IntelCPUMonitor::init(OSDictionary *properties) { + DebugLog("Initialising..."); + + if (!super::init(properties)) { + return false; + } + + return true; +} + +IOService* IntelCPUMonitor::probe(IOService *provider, SInt32 *score) { + // bool RPltSet = false; + DebugLog("Probing..."); + + if (super::probe(provider, score) != this) { return 0; } + + InfoLog("Based on code by mercurysquad, superhai (C)2008. Turbostates measurement added by Navi"); +// InfoLog("at probe 0xE2 = 0x%llx\n", rdmsr64(0xE2)); + + cpuid_update_generic_info(); + + if (strcmp(cpuid_info()->cpuid_vendor, CPUID_VID_INTEL) != 0) { + WarningLog("No Intel processor found, kext will not load"); + return 0; + } + + if (!(cpuid_info()->cpuid_features & CPUID_FEATURE_MSR)) { + WarningLog("Processor does not support Model Specific Registers, kext will not load"); + return 0; + } + + count = cpuid_info()->core_count;//cpuid_count_cores(); + threads = cpuid_info()->thread_count; + //uint64_t msr = rdmsr64(MSR_CORE_THREAD_COUNT); //nehalem only + //uint64_t m2 = msr >> 32; + + if (count == 0) { + WarningLog("CPUs not found, kext will not load"); + return 0; + } + + CpuFamily = cpuid_info()->cpuid_family; + CpuModel = cpuid_info()->cpuid_model; + CpuStepping = cpuid_info()->cpuid_stepping; + CpuMobile = false; + userTjmax = 0; + if (OSNumber* number = OSDynamicCast(OSNumber, getProperty("TjMax"))) { + // User defined Tjmax + userTjmax = number->unsigned32BitValue(); + IOLog("User defined TjMax=%d\n", (int)userTjmax); + // snprintf(Platform, 4, "n"); + } + /* + if (OSString* name = OSDynamicCast(OSString, getProperty("RPlt"))) { + snprintf(Platform, 4, "%s", name ? name->getCStringNoCopy() : "n"); + if ((Platform[0] != 'n') && (Platform[0] != 'N')) { + RPltSet = true; + } + } + */ + // Calculating Tjmax + switch (CpuFamily) { + case 0x06: { + switch (CpuModel) { + case CPU_MODEL_PENTIUM_M: + case CPU_MODEL_CELERON: + tjmax[0] = 100; + CpuMobile = true; + /* + if (!RPltSet) { + snprintf(Platform, 4, "M70"); + RPltSet = true; + } + */ + break; + case CPU_MODEL_YONAH: + tjmax[0] = 85; + if (rdmsr64(0x17) & (1<<28)) { + CpuMobile = true; + } + /* + if (!RPltSet) { + snprintf(Platform, 4, "K22"); + RPltSet = true; + } + */ + break; + case CPU_MODEL_MEROM: // Intel Core (65nm) + if (rdmsr64(0x17) & (1<<28)) { + CpuMobile = true; + } + switch (CpuStepping) { + case 0x02: // G0 + tjmax[0] = 80; //why 95? + //snprintf(Platform, 4, "M71"); + break; + case 0x06: // B2 + switch (count) { + case 2: + tjmax[0] = 80; break; + case 4: + tjmax[0] = 90; break; + default: + tjmax[0] = 85; break; + } + //tjmax[0] = 80; + break; + case 0x0B: // G0 + tjmax[0] = 90; break; + case 0x0A: + case 0x0D: // M0 + if (CpuMobile) { + tjmax[0] = 100; + } else { + tjmax[0] = 85; + } + break; + default: + tjmax[0] = 85; break; + } + /* + if (!RPltSet) { + snprintf(Platform, 4, "M75"); + RPltSet = true; + } + */ + break; + case CPU_MODEL_PENRYN: // Intel Core (45nm) + // Mobile CPU ? + if (rdmsr64(0x17) & (1<<28)) { //mobile + CpuMobile = true; + tjmax[0] = 105; + /* + if (!RPltSet) { + snprintf(Platform, 4, "M82"); + RPltSet = true; + } + */ + } else { + switch (CpuStepping) { + case 7: + tjmax[0] = 95; + break; + default: + tjmax[0] = 100; + break; + } + /* + if (!RPltSet) { + snprintf(Platform, 4, "K36"); + RPltSet = true; + } + */ + } + break; + case CPU_MODEL_ATOM: // Intel Atom (45nm) + switch (CpuStepping) { + case 0x02: // C0 + tjmax[0] = 100; break; + case 0x0A: // A0, B0 + tjmax[0] = 100; break; + default: + tjmax[0] = 90; break; + } + /* + if (!RPltSet) { + snprintf(Platform, 4, "T9"); + RPltSet = true; + } + */ + break; + case CPU_MODEL_NEHALEM: + case CPU_MODEL_FIELDS: + case CPU_MODEL_DALES: + case CPU_MODEL_DALES_32NM: + case CPU_MODEL_WESTMERE: + case CPU_MODEL_NEHALEM_EX: + case CPU_MODEL_WESTMERE_EX: + case CPU_MODEL_SANDY_BRIDGE: + case CPU_MODEL_IVY_BRIDGE: + case CPU_MODEL_JAKETOWN: + case CPU_MODEL_HASWELL: + case CPU_MODEL_HASWELL_MB: + case CPU_MODEL_HASWELL_ULT: + case CPU_MODEL_HASWELL_ULX: + case CPU_MODEL_HASWELL_U5: + case CPU_MODEL_IVY_BRIDGE_E5: + case CPU_MODEL_BROADWELL_HQ: + case CPU_MODEL_AIRMONT: + case CPU_MODEL_AVOTON: + case CPU_MODEL_SKYLAKE_U: + case CPU_MODEL_BROADWELL_E5: + case CPU_MODEL_BROADWELL_DE: + case CPU_MODEL_KNIGHT: + case CPU_MODEL_MOOREFIELD: + case CPU_MODEL_GOLDMONT: + case CPU_MODEL_ATOM_X3: + case CPU_MODEL_SKYLAKE_D: + case CPU_MODEL_SKYLAKE_X: + case CPU_MODEL_CANNONLAKE: + case CPU_MODEL_XEON_MILL: + case CPU_MODEL_KABYLAKE1: + case CPU_MODEL_KABYLAKE2: { + nehalemArch = true; + for (int i = 0; i < count; i++) { + tjmax[i] = (rdmsr64(MSR_IA32_TEMPERATURE_TARGET) >> 16) & 0xFF; + } + + } + // snprintf(Platform, 4, "T9"); + break; + default: + WarningLog("Unsupported Intel processor found ID=0x%02x, kext will not load", (unsigned int)CpuModel); + return 0; + } + } + break; + default: + WarningLog("Unknown Intel family processor found ID=0x%02x, kext will not load", (unsigned int)CpuFamily); + return 0; + } + + SandyArch = (CpuModel == CPU_MODEL_SANDY_BRIDGE) || + (CpuModel == CPU_MODEL_JAKETOWN) || + /* (CpuModel == CPU_MODEL_HASWELL) || + (CpuModel == CPU_MODEL_IVY_BRIDGE_E5) || + (CpuModel == CPU_MODEL_HASWELL_MB) || + (CpuModel == CPU_MODEL_HASWELL_ULT) || + (CpuModel == CPU_MODEL_HASWELL_ULX) || */ + (CpuModel >= CPU_MODEL_IVY_BRIDGE); + if (SandyArch) { + BaseFreqRatio = BaseOperatingFreq(); + + DebugLog("Base Ratio = %d", (unsigned int)BaseFreqRatio); + } + /* + if (!RPltSet) { + if (SandyArch) { + if (CpuMobile) { + snprintf(Platform, 4, "k90i"); + } else { + snprintf(Platform, 4, "k62"); + } + } else { + snprintf(Platform, 4, "T9"); + } + RPltSet = true; + } + */ + if (userTjmax != 0) { + for (int i = 0; i < count; i++) { + tjmax[i] = userTjmax; + } + } else { + for (int i = 0; i < count; i++) { + if (!nehalemArch) { + tjmax[i] = tjmax[0]; + } + } + } + + for (int i = 0; i < count; i++) { + key[i] = (char*)IOMalloc(5); + if (i > 15) { + for (char c = 'G'; c <= 'Z'; c++) { + int l = (int)c - 55; + if (l == i) { + snprintf(key[i], 5, "TC%cD", c); + } + } + } else { + snprintf(key[i], 5, "TC%XD", i); + } + } + // InfoLog("Platform string %s", Platform); + return this; +} + +bool IntelCPUMonitor::start(IOService * provider) { + IORegistryEntry * rootNode; + DebugLog("Starting..."); + + if (!super::start(provider)) { return false; } + + // Join power management so that we can get a notification early during + // wakeup to re-sample our battery data. We don't actually power manage + // any devices. + PMinit(); + registerPowerDriver(this, myTwoStates, 2); + provider->joinPMtree(this); + + if (!(fakeSMC = waitForService(serviceMatching(kFakeSMCDeviceService)))) { + WarningLog("Can't locate fake SMC device, kext will not load"); + return false; + } + + InfoLog("CPU family 0x%x, model 0x%x, stepping 0x%x, cores %d, threads %d", cpuid_info()->cpuid_family, cpuid_info()->cpuid_model, cpuid_info()->cpuid_stepping, count, cpuid_info()->thread_count); + InfoLog("at start 0xE2 = 0x%llx\n", rdmsr64(0xE2)); + rootNode = fromPath("/efi/platform", gIODTPlane); + if (rootNode) { + OSData *tmpNumber = OSDynamicCast(OSData, rootNode->getProperty("FSBFrequency")); + BusClock = *((UInt64*) tmpNumber->getBytesNoCopy()); + FSBClock = BusClock << 2; + InfoLog("Using efi"); + } else { + FSBClock = gPEClockFrequencyInfo.bus_frequency_max_hz; + BusClock = FSBClock >> 2; + InfoLog("Using bus_frequency_max_hz"); + } + + if (!SandyArch) { + BusClock = BusClock / Mega; // I Don't like this crap - i'll write mine + } else { + float v = (float)BusClock / (float)Mega; + BusClock = (int)(v < 0 ? (v - 0.5) : (v + 0.5)); + } + FSBClock = FSBClock / Mega; + InfoLog("BusClock=%dMHz FSB=%dMHz", (int)(BusClock), (int)(FSBClock)); + // InfoLog("Platform string %s", Platform); + + if (!(WorkLoop = getWorkLoop())) { return false; } + + if (!(TimerEventSource = IOTimerEventSource::timerEventSource(this, + OSMemberFunctionCast(IOTimerEventSource::Action, + this, + &IntelCPUMonitor::loopTimerEvent)))) { + return false; + } + + + if (kIOReturnSuccess != WorkLoop->addEventSource(TimerEventSource)) { + return false; + } + + Activate(); + + if (!nehalemArch) { + InfoLog("CPU Tjmax %d", tjmax[0]); + } else { + for (int i = 0; i < count; i++) { + InfoLog("CPU%X Tjmax %d", i, tjmax[i]); + } + } + + for (int i = 0; i < count; i++) { + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)key[i], + (void *)"sp78", + (void *)2, + this)) { + WarningLog("Can't add key to fake SMC device, kext will not load"); + return false; + } + + char keyF[5]; + + if (i > 15) { + for (char c = 'G'; c <= 'Z'; c++) { + int l = (int)c - 55; + if (l == i) { + snprintf(keyF, 5, "FRC%c", c); + } + } + } else { + snprintf(keyF, 5, "FRC%X", i); + } + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)keyF, + (void *)"freq", + (void *)2, + this)) { + WarningLog("Can't add Frequency key to fake SMC device"); + } + + if (!nehalemArch and !SandyArch) { + char keyM[5]; + snprintf(keyM, 5, KEY_FORMAT_NON_APPLE_CPU_MULTIPLIER, i); + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)keyM, + (void *)TYPE_UI16, + (void *)2, + this)) { + WarningLog("Can't add key to fake SMC device"); + //return false; + } + } + + if (!nehalemArch || SandyArch) { // Voltage is impossible for Nehalem + char keyV[5]; + snprintf(keyV, 5, KEY_CPU_VOLTAGE); + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)keyV, + (void *)"fp2e", + (void *)2, + this)) { + WarningLog("Can't add Voltage key to fake SMC device"); + } + } + /* but Voltage is possible on SandyBridge! + * MSR_PERF_STATUS[47:32] * (float) 1/(2^13). //there is a mistake in Intel datasheet [37:32] + * MSR 00000198  0000-2764-0000-2800 + */ + } + if (nehalemArch || SandyArch) { + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, false, (void *)KEY_NON_APPLE_PACKAGE_MULTIPLIER, (void *)TYPE_UI16, (void *)2, this)) { + WarningLog("Can't add key to fake SMC device"); + //return false; + } + } + + /* + if (Platform[0] != 'n') { + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, false, (void *)"RPlt", (void *)"ch8*", (void *)6, this)) { + WarningLog("Can't add Platform key to fake SMC device"); + } + } + */ + + return true; +} + +void IntelCPUMonitor::stop(IOService* provider) { + DebugLog("Stoping..."); + Deactivate(); + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCRemoveKeyHandler, true, this, NULL, NULL, NULL)) { + WarningLog("Can't remove key handler"); + IOSleep(500); + } + + super::stop(provider); +} + +void IntelCPUMonitor::free() { + DebugLog("Freeing..."); + super::free (); +} + +void IntelCPUMonitor::Activate(void) { + if (Active) { return; } + + Active = true; + loopTimerEvent(); + //InfoLog("Monitoring started"); +} + +void IntelCPUMonitor::Deactivate(void) { + if (!Active) { return; } + + if (TimerEventSource) + TimerEventSource->cancelTimeout(); + + Active = false; + + // InfoLog("Monitoring stopped"); +} + +IOReturn IntelCPUMonitor::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4) { + UInt64 magic = 0; + if (functionName->isEqualTo(kFakeSMCGetValueCallback)) { + const char* name = (const char*)param1; + void * data = param2; + //UInt32 size = (UInt64)param3; + //InfoLog("key %s is called", name); + if (name && data) { + UInt16 value=0; + int index; + + switch (name[0]) { + case 'T': + index = name[2] >= 'A' ? name[2] - 65 : name[2] - 48; + if (index >= 0 && index < count) { + if (threads > count) { + mp_rendezvous_no_intrs(IntelThermal2, &magic); + } else { + mp_rendezvous_no_intrs(IntelThermal, &magic); + } + value = tjmax[index] - GlobalThermalValue[index]; + } else { + //DebugLog("cpu index out of bounds"); + return kIOReturnBadArgument; + } + break; + case 'M': + if (strcasecmp(name, KEY_NON_APPLE_PACKAGE_MULTIPLIER) == 0) { + value = GlobalState[0].Control; + if (SandyArch) { + value = (value >> 8) * 10; + } else if (nehalemArch) { + value = value * 10; + } else { + value=0; + } + + bcopy(&value, data, 2); + + return kIOReturnSuccess; + } else { + index = name[2] >= 'A' ? name[2] - 65 : name[2] - 48; + if (index >= 0 && index < count) { + + value = GlobalState[index].Control; + + float mult = float(((value >> 8) & 0x1f)) + 0.5f * float((value >> 14) & 1); + value = mult * 10.0f; + } else { + return kIOReturnBadArgument; + } + } + break; + case 'F': + if ((name[1] != 'R') || (name[2] != 'C')) { + return kIOReturnBadArgument; + } + index = name[3] >= 'A' ? name[3] - 65 : name[3] - 48; + if (index >= 0 && index < count) { + value = swap_value(Frequency[index]); + //InfoLog("Frequency = %d", value); + //InfoLog("GlobalState: FID=%x VID=%x", GlobalState[index].FID, GlobalState[index].FID); + } + break; + case 'V': + value = encode_fp2e(Voltage); + break; + case 'R': + if ((name[1] != 'P') || (name[2] != 'l') || (name[3] != 't')) { + return kIOReturnBadArgument; + } + bcopy(Platform, data, 4); + return kIOReturnSuccess; + default: + return kIOReturnBadArgument; + } + + bcopy(&value, data, 2); + return kIOReturnSuccess; + } + + //DebugLog("bad argument key name or data"); + + return kIOReturnBadArgument; + } + + return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); +} + +IOReturn IntelCPUMonitor::loopTimerEvent(void) { + //Please, don't remove this timer! If frequency is read in OnKeyRead function, then the CPU is loaded by smcK-Stat-i and + //goes to a higher P-State in this moment, displays high frequency and switches back to low frequency. + UInt32 magic = 0; + + if (LoopLock) { + return kIOReturnTimeout; + } + LoopLock = true; + if (SandyArch) { + mp_rendezvous_no_intrs(UCState, &magic); + IOSleep(2); + mp_rendezvous_no_intrs(UCState, &magic); + } + + // State Readout + if (threads > count) { + mp_rendezvous_no_intrs(IntelState2, &magic); + } else { + mp_rendezvous_no_intrs(IntelState, &magic); + } + + for (UInt32 i = 0; i < count; i++) { + Frequency[i] = IntelGetFrequency(i); + if (SandyArch) { + //value in millivolts + Voltage = GlobalState64 >> 35; + } else if (!nehalemArch) { + Voltage = IntelGetVoltage(GlobalState[i].VID); + } else { + Voltage = 1000; + } + } + + LoopLock = false; + TimerEventSource->setTimeoutMS(1000); + return kIOReturnSuccess; +} + +UInt32 IntelCPUMonitor::IntelGetFrequency(UInt8 cpu_id) +{ + UInt32 multiplier, frequency=0; + UInt8 fid = 0; + if (SandyArch) { + fid = GlobalState[cpu_id].FID; + UInt64 deltaUCC = lastUCC[cpu_id] > UCC[cpu_id] ? 0xFFFFFFFFFFFFFFFFll - lastUCC[cpu_id] + UCC[cpu_id] : UCC[cpu_id] - lastUCC[cpu_id]; + UInt64 deltaUCR = lastUCR[cpu_id] > UCR[cpu_id] ? 0xFFFFFFFFFFFFFFFFll - lastUCR[cpu_id] + UCR[cpu_id] : UCR[cpu_id] - lastUCR[cpu_id]; + + if (deltaUCR > 0) { + float num = (float)deltaUCC*BaseFreqRatio / (float)deltaUCR; + int n = (int)(num < 0 ? (num - 0.5) : (num + 0.5)); + return (UInt32)BusClock * n; + } + + } + + if (!nehalemArch) { + fid = GlobalState[cpu_id].FID; + multiplier = fid & 0x1f; // = 0x08 + int half = (fid & 0x40)?1:0; // = 0x01 + int dfsb = (fid & 0x80)?1:0; // = 0x00 + UInt32 fsb = (UInt32)BusClock >> dfsb; + UInt32 halffsb = (UInt32)BusClock >> 1; // = 200 + frequency = (multiplier * fsb); // = 3200 + return (frequency + (half * halffsb)); // = 3200 + 200 = 3400 + } else { + if (!SandyArch) { + fid = GlobalState[cpu_id].VID; + } + multiplier = fid & 0x3f; + frequency = (multiplier * (UInt32)BusClock); + return (frequency); + } +} + +UInt32 IntelCPUMonitor::IntelGetVoltage(UInt16 vid) { //no nehalem + switch (CpuModel) { + case CPU_MODEL_PENTIUM_M: + case CPU_MODEL_CELERON: + return 700 + ((vid & 0x3F) << 4); + break; + case CPU_MODEL_YONAH: + return (1425 + ((vid & 0x3F) * 25)) >> 1; + break; + case CPU_MODEL_MEROM: //Conroe?! + return (1650 + ((vid & 0x3F) * 25)) >> 1; + break; + case CPU_MODEL_PENRYN: + case CPU_MODEL_ATOM: + //vid=0x22 (~vid& 0x3F)=0x1d=29 ret=1137 + return (1500 - (((~vid & 0x3F) * 25) >> 1)); + break; + default: + return 0; + break; + } + return 0; +} + +IOReturn IntelCPUMonitor::setPowerState(unsigned long which,IOService *whom) { + if (kMyOnPowerState == which) { + // Init PMC Fixed Counters once more + DebugLog( "awaken, resetting counters"); + bzero(UCC, sizeof(UCC)); + bzero(lastUCC, sizeof(lastUCC)); + bzero(UCR, sizeof(UCR)); + bzero(lastUCR, sizeof(lastUCR)); + bzero(InitFlags, sizeof(InitFlags)); + } + return IOPMAckImplied; +} diff --git a/plugins/CPUSensors/IntelCPUMonitor/IntelCPUMonitor.h b/plugins/CPUSensors/IntelCPUMonitor/IntelCPUMonitor.h new file mode 100644 index 0000000..b6b95e6 --- /dev/null +++ b/plugins/CPUSensors/IntelCPUMonitor/IntelCPUMonitor.h @@ -0,0 +1,101 @@ +/* + * IntelCPUMonitor.h + * HWSensors + * + * Created by Slice on 20.12.10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../../utils/cpuid.h" + +#define MSR_IA32_THERM_STATUS 0x019C +#define MSR_IA32_PERF_STATUS 0x0198; +#define MSR_IA32_TEMPERATURE_TARGET 0x01A2 +#define MSR_PERF_FIXED_CTR_CTRL (0x38d) +#define MSR_PERF_GLOBAL_CTRL (0x38f) +//#define MSR_PLATFORM_INFO 0xCE; + +#define MaxCpuCount 128 +#define MaxPStateCount 32 + +extern "C" { + void mp_rendezvous_no_intrs(void (*action_func)(void *), void * arg); + int cpu_number(void); +}; + +struct PState { + union { + UInt16 Control; + struct { + UInt8 VID; // Voltage ID + UInt8 FID; // Frequency ID + }; + }; + + UInt8 DID; // DID + UInt8 CID; // Compare ID +// UInt32 Max; +}; + +class IntelCPUMonitor : public IOService { + OSDeclareDefaultStructors(IntelCPUMonitor) +public: + UInt32 Frequency[MaxCpuCount]; + UInt32 Voltage; //in millivolts + UInt32 BaseFreqRatio; + +private: + bool Active; + bool LoopLock; + UInt64 BusClock; + UInt64 FSBClock; + UInt32 CpuFamily; + UInt32 CpuModel; + UInt32 CpuStepping; + bool CpuMobile; + UInt8 count; + UInt8 threads; + UInt8 tjmax[MaxCpuCount]; + UInt32 userTjmax; + char* key[MaxCpuCount]; + char Platform[4]; + bool nehalemArch; + bool SandyArch; + IOService* fakeSMC; + void Activate(void); + void Deactivate(void); + UInt32 IntelGetFrequency(UInt8 fid); + UInt32 IntelGetVoltage(UInt16 vid); + + IOWorkLoop * WorkLoop; + IOTimerEventSource * TimerEventSource; + + +public: + virtual bool init(OSDictionary *properties=0); + virtual IOService* probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual void stop(IOService *provider); + virtual void free(void); + virtual IOReturn setPowerState(unsigned long which, IOService *whom); + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); + virtual IOReturn loopTimerEvent(void); +}; diff --git a/plugins/GPUSensors/GeforceSensors/GeForceSensors-Info.plist b/plugins/GPUSensors/GeforceSensors/GeForceSensors-Info.plist new file mode 100755 index 0000000..bdf02f5 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/GeForceSensors-Info.plist @@ -0,0 +1,57 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + IOKitPersonalities + + Nouveau nVidia Cards Monitoring Plugin + + CFBundleIdentifier + org.kozlek.${PRODUCT_NAME} + IOClass + GeforceSensors + IOMatchCategory + ${PRODUCT_NAME} + IOProbeScore + 1000 + IOProviderClass + IOResources + IOResourceMatch + IOKit + + + OSBundleLibraries + + com.apple.iokit.IOPCIFamily + 2.4 + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.mach + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + OSBundleRequired + Root + + diff --git a/plugins/GPUSensors/GeforceSensors/GeForceSensors-Prefix.pch b/plugins/GPUSensors/GeforceSensors/GeForceSensors-Prefix.pch new file mode 100755 index 0000000..73d717a --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/GeForceSensors-Prefix.pch @@ -0,0 +1,4 @@ +// +// Prefix header for all source files of the 'NVClockX' target in the 'NVClockX' project +// + diff --git a/plugins/GPUSensors/GeforceSensors/GeforceSensors.cpp b/plugins/GPUSensors/GeforceSensors/GeforceSensors.cpp new file mode 100755 index 0000000..1b84c74 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/GeforceSensors.cpp @@ -0,0 +1,594 @@ +/* + * GeforceSensors.cpp + * HWSensors + * + * Created by kozlek on 19/04/12. + * Copyright 2010 Natan Zalkin . All rights reserved. + * + */ + +/* + * Copyright 2007-2008 Nouveau Project + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "GeforceSensors.h" + +#include "../../../fakesmc/FakeSMC.h" +#include "../../../utils/definitions.h" +#include "../../../utils/utils.h" + +#include "nouveau.h" +//#include "nvclock_i2c.h" +bool is_digit(char c); + +#define Debug FALSE + +#define LogPrefix "GeForceSensors: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +#define kNouveauPWMSensor 1000 +#define kNouveauCoreTemperatureSensor 1001 +#define kNouveauBoardTemperatureSensor 1002 + +#define kGenericPCIDevice "IOPCIDevice" +#define kTimeoutMSecs 1000 +#define fVendor "vendor-id" +#define fDevice "device-id" +#define fClass "class-code" +#define kIOPCIConfigBaseAddress0 0x10 + + +#define super IOService +OSDefineMetaClassAndStructors(GeforceSensors, IOService) + + +bool is_digit(char c) { + if (((c>='0')&&(c<='9'))||((c>='a')&&(c<='f'))||((c>='A')&&(c<='F'))) { + return true; + } + + return false; +} + +bool GeforceSensors::addSensor(const char* key, const char* type, unsigned int size, int index) { + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + true, + (void *)key, + (void *)type, + (void *)(long long)size, + (void *)this)) { + if (sensors->setObject(key, OSNumber::withNumber(index, 32))) { + return true; + } else { + WarningLog("%s key sensor not set", key); + return 0; + } + } + + WarningLog("%s key sensor not added", key); + + return 0; +} + +int GeforceSensors::addTachometer(int index, const char* id) { + UInt8 length = 0; + void * data = 0; + + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, + false, + (void *)KEY_FAN_NUMBER, + (void *)&length, + (void *)&data, 0)) { + char name[5]; + char key[5]; + + bcopy(data, &length, 1); + snprintf(name, 5, KEY_FORMAT_FAN_SPEED, length); + + if (addSensor(name, TYPE_FPE2, 2, index)) { + if (id) { + FanTypeDescStruct fds; + snprintf(key, 5, KEY_FORMAT_FAN_ID, length); + fds.type = FAN_PWM_TACH; + fds.ui8Zone = 1; + fds.location = LEFT_LOWER_FRONT; + strncpy(fds.strFunction, id, DIAG_FUNCTION_STR_LEN); + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyValue, + false, + (void *)key, + (void *)TYPE_FDESC, + (void *)((UInt64)sizeof(fds)), + (void *)&fds)) { + + WarningLog("error adding tachometer id value"); + } + } + + length++; + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCSetKeyValue, + false, + (void *)KEY_FAN_NUMBER, + (void *)1, + (void *)&length, + 0)) { + WarningLog("error updating FNum value"); + } + + return length-1; + } + } else { + WarningLog("error reading FNum value"); + } + + return -1; +} + +//float GeforceSensors::getSensorValue(FakeSMCSensor *sensor) +//{ +// switch (sensor->getGroup()) { +// case kFakeSMCTemperatureSensor: +// return card.temp_get(&card); +// +// case kNouveauCoreTemperatureSensor: +// return card.core_temp_get(&card); +// +// case kNouveauBoardTemperatureSensor: +// return card.board_temp_get(&card); +// +// case kFakeSMCFrequencySensor: +// return card.clocks_get(&card, sensor->getIndex()) / 1000.0f; +// +// case kNouveauPWMSensor: +// return card.fan_pwm_get(&card); +// +// case kFakeSMCTachometerSensor: +// return card.fan_rpm_get(&card); // count ticks for 500ms +// +// case kFakeSMCVoltageSensor: +// return (float)card.voltage_get(&card) / 1000000.0f; +// } +// +// return 0; +//} + +bool GeforceSensors::init(OSDictionary *properties) { + // DebugLog("Initialising..."); + + if (!super::init(properties)) { + return false; + } + + if (!(sensors = OSDictionary::withCapacity(0))) { + return false; + } + + return true; +} + +IOService* GeforceSensors::probe(IOService *provider, SInt32 *score) { + UInt32 vendor_id, device_id, class_id; + DebugLog("Probing..."); + + if (super::probe(provider, score) != this) { return 0; } + + s8 ret = 0; + if (OSDictionary * dictionary = serviceMatching(kGenericPCIDevice)) { + if (OSIterator * iterator = getMatchingServices(dictionary)) { + // ret = 1; + IOPCIDevice* device = 0; + do { + device = OSDynamicCast(IOPCIDevice, iterator->getNextObject()); + if (!device) { + break; + } + OSData *data = OSDynamicCast(OSData, device->getProperty(fVendor)); + vendor_id = 0; + if (data) { + vendor_id = *(UInt32*)data->getBytesNoCopy(); + } + + device_id = 0; + data = OSDynamicCast(OSData, device->getProperty(fDevice)); + if (data) { + device_id = *(UInt32*)data->getBytesNoCopy(); + } + + class_id = 0; + data = OSDynamicCast(OSData, device->getProperty(fClass)); + if (data) { + class_id = *(UInt32*)data->getBytesNoCopy(); + } + + if ((vendor_id==0x10de) && (class_id == 0x030000)) { + InfoLog("found %x Nvidia chip", (unsigned int)device_id); + card.pcidev = device; + card.device_id = device_id; + ret = 1; //TODO - count a number of cards + card.card_index = ret; + break; + } + } while (device); + } + } + + if (ret) { + return this; + } else { + return 0; + } + + return this; +} + +SInt8 GeforceSensors::getVacantGPUIndex() { + //Find card number + char key[5]; + UInt8 length = 0; + void * data = 0; + + + for (UInt8 i = 0; i <= 0xf; i++) { + + snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, i); + // if (isKeyHandled(key)) continue; + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, + true, + (void *)key, + (void *)&length, + (void *)&data, 0)) { + continue; + } + + snprintf(key, 5, KEY_FORMAT_GPU_HEATSINK_TEMPERATURE, i); + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, + true, + (void *)key, + (void *)&length, + (void *)&data, + 0)) { + continue; + } + + snprintf(key, 5, KEY_FORMAT_GPU_PROXIMITY_TEMPERATURE, i); + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, + true, + (void *)key, + (void *)&length, + (void *)&data, + 0)) { + continue; + } + + snprintf(key, 5, KEY_FORMAT_GPU_VOLTAGE, i); + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, + true, + (void *)key, + (void *)&length, + (void *)&data, + 0)) { + continue; + } + + snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_FREQUENCY, i); + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, + true, + (void *)key, + (void *)&length, + (void *)&data, + 0)) { + continue; + } + + return i; + } + + return false; +} + +bool GeforceSensors::start(IOService * provider) { + DebugLog("Starting..."); + + if (!super::start(provider)) { + return false; + } + + if (!(fakeSMC = waitForService(serviceMatching(kFakeSMCDeviceService)))) { + WarningLog("Can't locate fake SMC device, kext will not load"); + return false; + } + + InfoLog("GeforceSensors by kozlek (C) 2012"); + + struct nouveau_device *device = &card; + + //Find card number + card.card_index = getVacantGPUIndex(); + + if (card.card_index < 0) { + nv_error(device, "failed to obtain vacant GPU index\n"); + return true; + } + + // map device memory + // device->pcidev = (IOPCIDevice*)provider; + if (device->pcidev) { + device->pcidev->setMemoryEnable(true); + + if ((device->mmio = device->pcidev->mapDeviceMemoryWithIndex(0))) { + nv_debug(device, "memory mapped successfully\n"); + } else { + nv_error(device, "failed to map memory\n"); + return true; + } + } else { + nv_error(device, "failed to assign PCI device\n"); + return true; + } + + // identify chipset + if (!nouveau_identify(device)) { + return true; + } + // shadow and parse bios + + //try to load bios from registry first from "vbios" property created by bootloader + if (OSData *vbios = OSDynamicCast(OSData, provider->getProperty("vbios"))) { + device->bios.size = vbios->getLength(); + device->bios.data = (u8*)IOMalloc(card.bios.size); + memcpy(device->bios.data, vbios->getBytesNoCopy(), device->bios.size); + } + + if (nouveau_bios_score(device, true) < 1) { + if (!nouveau_bios_shadow(device)) { + if (device->bios.data && device->bios.size) { + IOFree(card.bios.data, card.bios.size); + device->bios.data = NULL; + device->bios.size = 0; + } + nv_error(device, "unable to shadow VBIOS\n"); + return true; + } + } + + nouveau_vbios_init(device); + nouveau_bios_parse(device); + + // initialize funcs and variables + if (!nouveau_init(device)) { + nv_error(device, "unable to initialize monitoring driver\n"); + return false; + } + + nv_info(device, "chipset: %s (NV%02X) bios: %02x.%02x.%02x.%02x\n", + device->cname, + (unsigned int)device->chipset, + device->bios.version.major, + device->bios.version.chip, + device->bios.version.minor, + device->bios.version.micro); + + if (device->card_type < NV_C0) { + // init i2c structures + nouveau_i2c_create(device); + + // setup nouveau i2c sensors + nouveau_i2c_probe(device); + } + + // Register sensors + char key[5]; + + if (card.core_temp_get || card.board_temp_get) { + nv_debug(device, "registering i2c temperature sensors...\n"); + + if (card.core_temp_get && card.board_temp_get) { + snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index); + this->addSensor(key, TYPE_SP78, 2, 0); + + snprintf(key, 5, KEY_FORMAT_GPU_HEATSINK_TEMPERATURE, card.card_index); + addSensor(key, TYPE_SP78, 2, 0); + } else if (card.core_temp_get) { + snprintf(key, 5, KEY_FORMAT_GPU_PROXIMITY_TEMPERATURE, card.card_index); + addSensor(key, TYPE_SP78, 2, 0); + } else if (card.board_temp_get) { + snprintf(key, 5, KEY_FORMAT_GPU_PROXIMITY_TEMPERATURE, card.card_index); + addSensor(key, TYPE_SP78, 2, 0); + } + } else if (card.temp_get) { + nv_debug(device, "registering temperature sensors...\n"); + + snprintf(key, 5, KEY_FORMAT_GPU_PROXIMITY_TEMPERATURE, card.card_index); + addSensor(key, TYPE_SP78, 2, 0); + } + + if (card.clocks_get) { + nv_debug(device, "registering clocks sensors...\n"); + + if (card.clocks_get(&card, nouveau_clock_core) > 0) { + snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_FREQUENCY, card.card_index); + addSensor(key, TYPE_FREQ, TYPE_UI32_SIZE, nouveau_clock_core); + } + + if (card.clocks_get(&card, nouveau_clock_shader) > 0) { + snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_SHADER_FREQUENCY, card.card_index); + addSensor(key, TYPE_FREQ, TYPE_UI32_SIZE, nouveau_clock_shader); + } + + if (card.clocks_get(&card, nouveau_clock_rop) > 0) { + snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_ROP_FREQUENCY, card.card_index); + addSensor(key, TYPE_FREQ, TYPE_UI32_SIZE, nouveau_clock_rop); + } + + if (card.clocks_get(&card, nouveau_clock_memory) > 0) { + snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_MEMORY_FREQUENCY, card.card_index); + addSensor(key, TYPE_FREQ, TYPE_UI32_SIZE, nouveau_clock_memory); + } + } + + if (card.fan_pwm_get || card.fan_rpm_get) { + nv_debug(device, "registering PWM sensors...\n"); + + if (card.fan_rpm_get && card.fan_rpm_get(device) > 0) { + char title[6]; + snprintf (title, 6, "GPU %X", card.card_index + 1); + + UInt8 fanIndex = 0; + + if (addTachometer( fanIndex, title)) { + if (card.fan_pwm_get && card.fan_pwm_get(device) > 0) { + snprintf(key, 5, KEY_FAKESMC_FORMAT_GPUPWM, fanIndex); + addSensor(key, TYPE_UI8, TYPE_UI8_SIZE, 0); + } + } + } + } + + if (card.voltage_get && card.voltage.supported) { + nv_debug(device, "registering voltage sensors...\n"); + snprintf(key, 5, KEY_FORMAT_GPU_VOLTAGE, card.card_index); + addSensor(key, TYPE_FP2E, TYPE_FPXX_SIZE, 0); + } + + nv_info(device, "started\n"); + + return true; +} + +void GeforceSensors::stop (IOService* provider) { + DebugLog("Stoping..."); + + sensors->flushCollection(); + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCRemoveKeyHandler, + true, + this, + NULL, + NULL, + NULL)) { + WarningLog("Can't remove key handler"); + IOSleep(500); + } + + super::stop(provider); +} + +void GeforceSensors::free(void) { + if (card.mmio) { + OSSafeReleaseNULL(card.mmio); + } + if (card.bios.data) { + IOFree(card.bios.data, card.bios.size); + card.bios.data = 0; + } + + sensors->release(); + + super::free(); +} + +IOReturn GeforceSensors::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4) { + if (functionName->isEqualTo(kFakeSMCGetValueCallback)) { + const char* key = (const char*)param1; + char * data = (char*)param2; + // UInt32 size = (UInt64)param3; + + if (key && data) { + OSNumber *number = OSDynamicCast(OSNumber, sensors->getObject(key)); + if (number) { + + // UInt32 index = number->unsigned16BitValue(); + // + // if (index < nvclock.num_cards) { + // + // if (!set_card(index)){ + // char buf[80]; + // WarningLog("%s", get_error(buf, 80)); + // return kIOReturnSuccess; + // } + + UInt32 value = 0; + + switch (key[0]) { + case 'T': + switch (key[3]) { + case 'D': + case 'P': + value = card.temp_get(&card); + break; + case 'H': + value = card.core_temp_get(&card); + break; + } + //bcopy(&value, data, 2); + memcpy(data, &value, 2); + break; + case 'C': + switch (key[3]) { + case 'C': + value=swap_value((UInt16)(card.clocks_get(&card, nouveau_clock_core) / 1000.0f)); + //bcopy(&value, data, 2); + memcpy(data, &value, 4); + break; + case 'S': + value=swap_value((UInt16)(card.clocks_get(&card, nouveau_clock_shader) / 1000.0f)); + //bcopy(&value, data, 2); + memcpy(data, &value, 4); + break; + case 'M': + value=swap_value((UInt16)(card.clocks_get(&card, nouveau_clock_memory) / 1000.0f)); + //bcopy(&value, data, 2); + memcpy(data, &value, 4); + break; + case 'R': + value=swap_value((UInt16)(card.clocks_get(&card, nouveau_clock_rop) / 1000.0f)); + //bcopy(&value, data, 2); + memcpy(data, &value, 4); + break; + } + case 'V': + switch (key[3]) { + case 'G': + // value = encode_fp2e( (float)card.voltage_get(&card) / 1000000.0f); + //encode_fp2e has input as mV, output is V in fixed format + value = encode_fp2e( (float)card.voltage_get(&card) / 1000.0f); // Fix for fp2e encoding + //bcopy(&value, data, 2); + memcpy(data, &value, 2); + break; + } + } + return kIOReturnSuccess; + } + } + return kIOReturnBadArgument; + } + + return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); +} + diff --git a/plugins/GPUSensors/GeforceSensors/GeforceSensors.h b/plugins/GPUSensors/GeforceSensors/GeforceSensors.h new file mode 100755 index 0000000..23fac39 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/GeforceSensors.h @@ -0,0 +1,81 @@ +/* + * GeforceSensors.h + * HWSensors + * + * Created by kozlek on 19/04/12. + * Copyright 2010 Natan Zalkin . All rights reserved. + * + */ + +/* + * Copyright 2007-2008 Nouveau Project + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "SuperIOFamily.h" + +//#include "FakeSMCPlugin.h" +#include "nouveau.h" +#include "xf86i2c.h" + +class GeforceSensors : public IOService +{ + OSDeclareDefaultStructors(GeforceSensors) + +private: + IOService * fakeSMC; + OSDictionary * sensors; + + nouveau_device card; + + I2CDevPtr i2c_sensor; + int i2c_get_board_temp(I2CDevPtr dev); + int i2c_get_gpu_temp(I2CDevPtr dev); + int i2c_get_fanspeed_rpm(I2CDevPtr dev); + float i2c_get_fanspeed_pwm(I2CDevPtr dev); + int i2c_get_fanspeed_mode(I2CDevPtr dev); + + bool addSensor(const char* key, const char* type, unsigned int size, int index); + int addTachometer(int index, const char* id); + +protected: + // virtual float getSensorValue(FakeSMCSensor *sensor); + SInt8 getVacantGPUIndex(); + +public: + virtual bool init(OSDictionary *properties=0); + virtual IOService* probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual void stop(IOService *provider); + virtual void free(void); + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); +}; diff --git a/plugins/GPUSensors/GeforceSensors/adt7473.cpp b/plugins/GPUSensors/GeforceSensors/adt7473.cpp new file mode 100755 index 0000000..c5c33dd --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/adt7473.cpp @@ -0,0 +1,214 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2005 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * ADT7473 hardware monitoring + */ + +#include "nouveau_definitions.h" + +#include "nvclock_i2c.h" + +/* various defines for register offsets and such are needed */ +#define ADT7473_REG_LOCAL_TEMP 0x26 +#define ADT7473_REG_LOCAL_TEMP_OFFSET 0x70 +#define ADT7473_REG_REMOTE_TEMP 0x25 +#define ADT7473_REG_REMOTE_TEMP_OFFSET 0x71 + +#define ADT7473_REG_PWM1_CFG 0x5c +#define ADT7473_REG_PWM1_DUTYCYCLE 0x30 +#define ADT7473_REG_PWM1_MAX_DUTYCYCLE 0x38 +#define ADT7473_REG_PWM1_MIN_DUTYCYCLE 0x64 + +#define ADT7473_REG_TACH1_LB 0x28 +#define ADT7473_REG_TACH1_HB 0x29 + +#define ADT7473_REG_CFG5 0x7c + +#define ADT7473_REG_MAN_ID 0x3e +#define AD_MAN_ID 0x41 +#define ADT7473_REG_DEVID2 0x3F +#define ADT7473_REG_CHIP_ID 0x3d +#define ADT7473_CHIP_ID 0x73 + +/* This function should return the chip type .. */ +int adt7473_detect(I2CDevPtr dev) +{ + I2CByte man_id, dev_id, chip_id; + + xf86I2CReadByte(dev, ADT7473_REG_MAN_ID, &man_id); + xf86I2CReadByte(dev, ADT7473_REG_DEVID2, &dev_id); + + if (man_id != AD_MAN_ID || (dev_id & 0xf8) != 0x68) + return 0; + + xf86I2CReadByte(dev, ADT7473_REG_CHIP_ID, &chip_id); + + if (chip_id == 0x73) { + dev->chip_id = ADT7473; + dev->chip_name = (char*)STRDUP("Analog Devices ADT7473", sizeof("Analog Devices ADT7473")); + return 1; + } + else if (chip_id == 0x75 && dev->SlaveAddr / 2 == 0x2e) { + dev->chip_id = ADT7473; + dev->chip_name = (char*)STRDUP("Analog Devices ADT7475", sizeof("Analog Devices ADT7475")); + return 1; + } + else if (chip_id == 0x76) { + dev->chip_id = ADT7473; + dev->chip_name = (char*)STRDUP("Analog Devices ADT7476", sizeof("Analog Devices ADT7476")); + return 1; + } + else if ((dev_id & 0xfc) == 0x6c) { + dev->chip_id = ADT7473; + dev->chip_name = (char*)STRDUP("Analog Devices ADT7490", sizeof("Analog Devices ADT7490")); + return 1; + } + + return 0; +} + +int adt7473_get_board_temp(nouveau_device *device) +{ + I2CByte temp; + I2CByte cfg; + + xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_LOCAL_TEMP, &temp); + + /* Check if the sensor uses 2-complement or offset-64 mode */ + xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_CFG5, &cfg); + if(cfg & 0x1) + return (int)((char)temp); + else + return temp - 64; +} + +int adt7473_get_gpu_temp(nouveau_device *device) +{ + I2CByte temp; + I2CByte cfg; + int offset = 0; + + /* The temperature needs to be corrected using an offset which is stored in the bios. + / If no bios has been parsed we fall back to a default value. + */ + if(device->bios.data) + { + offset = device->sensor_constants.offset_constant;//nv_card->bios->sensor_cfg.temp_correction; + } + else + { + /* We add a 10C offset to the temperature though this isn't conform + / the ADT7473 datasheet. The reason we add this is to show a temperature + / similar to the internal gpu sensor. Right now the board and gpu + / temperature as reported by the sensor are about the same (there's + / a difference between the two or 3-4C). Most likely the internal gpu + / temperature is a bit higher and assuming the temperature as reported + / by the internal sensor is correct adding a 10C offset is a good solution. + / Add an offset of 8C for 8*00/GTX2*0 cards but it doesn't seem 100% correct though. + / It could be that +7C is more correct for 8800GT cards. + */ + if(device->card_type == NV_40) + offset = 10; + else if(device->card_type == NV_50) + offset = 8; + } + + xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_REMOTE_TEMP, &temp); + + /* Check if the sensor uses 2-complement or offset-64 mode */ + + xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_CFG5, &cfg); + if(cfg & 0x1) + return (int)((char)temp + offset); + else + return temp - 64 + offset; +} + +int adt7473_get_fanspeed_rpm(nouveau_device *device) +{ + I2CByte count_lb, count_hb; + int count; + + xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_TACH1_LB, &count_lb); + xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_TACH1_HB, &count_hb); + count = (count_hb << 8) | count_lb; + + /* GT200 boards seem to use two phases instead of a single, the fan speed is twice as high */ + if((device->chipset & 0x1f0) >= 0xA0) + count *= 2; + + /* GF100 boards seem to use four phases... */ + if(device->card_type == NV_C0) + count *= 4; + + /* RPM = 60*90k pulses / (number of counts that fit in a pulse) */ + return 90000*60/count; +} + +int adt7473_get_fanspeed_pwm(nouveau_device *device) +{ + I2CByte value; + + xf86I2CReadByte(device->nvclock_i2c_sensor, ADT7473_REG_PWM1_DUTYCYCLE, &value); + return ((float)value*100/255); +} + +int adt7473_set_fanspeed_pwm(I2CDevPtr dev, float speed) +{ + I2CByte value = (int)speed * 255/100; + I2CByte cfg, max_dutycycle; + + xf86I2CReadByte(dev, ADT7473_REG_PWM1_CFG, &cfg); + cfg |= 0xe0; /* Put PWM1 in manual mode; this disables automatic control */ + xf86I2CWriteByte(dev, ADT7473_REG_PWM1_CFG, cfg); + + /* If the MAX dutycycle is lower than 0xff (100%), set it to 0xff */ + xf86I2CReadByte(dev, ADT7473_REG_PWM1_MAX_DUTYCYCLE, &max_dutycycle); + if(max_dutycycle < 0xff) + xf86I2CWriteByte(dev, ADT7473_REG_PWM1_MAX_DUTYCYCLE, 0xff); + + xf86I2CWriteByte(dev, ADT7473_REG_PWM1_DUTYCYCLE, value); + return 1; +} + +int adt7473_get_fanspeed_mode(I2CDevPtr dev) { + I2CByte cfg; + xf86I2CReadByte(dev, ADT7473_REG_PWM1_CFG, &cfg); + + if(cfg & (0x6 << 5)) return 0; /* auto */ + if(cfg & (0x7 << 5)) return 1; /* manual */ + + return -1; /* something went wrong */ +} + +void adt7473_set_fanspeed_mode(I2CDevPtr dev, int mode) { + I2CByte cfg; + xf86I2CReadByte(dev, ADT7473_REG_PWM1_CFG, &cfg); + + /* Clear the pwm1 config bits */ + cfg&=~(0xF << 5); + + if(mode==1) + cfg|=0x7 << 5; /* manual */ + else + cfg|=0x6 << 5; /* auto */ + + xf86I2CWriteByte(dev, ADT7473_REG_PWM1_CFG, cfg); +} diff --git a/plugins/GPUSensors/GeforceSensors/f75375.cpp b/plugins/GPUSensors/GeforceSensors/f75375.cpp new file mode 100755 index 0000000..e611b35 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/f75375.cpp @@ -0,0 +1,167 @@ +/* Fintek F75375 sensor module + / Copyright(C) 2005, Matt Wright + */ + +#include +#include "nvclock_i2c.h" +#include "f75375.h" + +int f75375_detect(I2CDevPtr dev) +{ + I2CByte nvl, nvh; + + xf86I2CReadByte(dev, FINTEK_VENDOR1, &nvl); + xf86I2CReadByte(dev, FINTEK_VENDOR2, &nvh); + + if (MERGE_BYTE(nvh, nvl) != 0x3419) + { + return 0; + } + + xf86I2CReadByte(dev, ASUS_NV40_CHIPID_H, &nvh); + xf86I2CReadByte(dev, ASUS_NV40_CHIPID_L, &nvl); + + if (MERGE_BYTE(nvh, nvl) == 0x0306) + { + dev->chip_id = F75375; + dev->chip_name = (char*)STRDUP("Fintek F75375S", sizeof("Fintek F75375S")); + return 1; + } + if (MERGE_BYTE(nvh, nvl) == 0x0204) + { + dev->chip_id = F75375; + dev->chip_name = (char*)STRDUP("Fintek F75373S", sizeof("Fintek F75375S")); + return 1; + } + return 0; +} + + +int f75375_get_gpu_temp(nouveau_device *device) +{ + I2CByte nvh; + + xf86I2CReadByte(device->nvclock_i2c_sensor, F75375S_TEMP_GPU, &nvh); + return (int)nvh; +} + + +int f75375_get_fanspeed_rpm(nouveau_device *device) +{ + I2CByte nvh, nvl; + int rpm; + + xf86I2CReadByte(device->nvclock_i2c_sensor, F75375S_FAN1_COUNT_H, &nvh); + xf86I2CReadByte(device->nvclock_i2c_sensor, F75375S_FAN1_COUNT_L, &nvl); + + rpm = FAN_TO_RPM(nvh, nvl); + + return rpm; +} + + +int f75375_get_board_temp(nouveau_device *device) +{ + I2CByte nvh; + + xf86I2CReadByte(device->nvclock_i2c_sensor, F75375S_TEMP_RAM, &nvh); + return (int)nvh; +} + + +int f75375_set_fanspeed_rpm(I2CDevPtr dev, int desired_rpm) +{ + I2CByte nvh, nvl; + int desired_count; + + desired_count = RPM_TO_FAN(desired_rpm); + + nvh = (desired_count>>8) & 0x00ff; + nvl = (desired_count) & 0x00ff; + + xf86I2CWriteByte(dev, F75375S_FAN1_EXPECT_H, nvh); + xf86I2CWriteByte(dev, F75375S_FAN1_EXPECT_L, nvl); + return 1; +} + + +int f75375_set_gpu_tempctl(I2CDevPtr dev, fan_vtemp speeds) +{ + for (int i=0; i<4; i++) + { + xf86I2CWriteByte(dev, F75375S_VT1_B1 + i, speeds.temp[i]); + } + + for (int i=0; i<5; i++) + { + I2CByte nvh, nvl; + int temp_speed; + + + temp_speed = RPM_TO_FAN(speeds.speed[i]); + + nvh = (temp_speed >> 8) & 0x00ff; + nvl = (temp_speed) & 0x00ff; + + xf86I2CWriteByte(dev, F75375S_VT1_S1_H + (i*2), nvh); + xf86I2CWriteByte(dev, F75375S_VT1_S1_L + (i*2), nvl); + } + + return 0; +} + + +int f75375_get_gpu_tempctl(I2CDevPtr dev, fan_vtemp *speeds) +{ + I2CByte nvh, nvl; + int i; + + for (i=0; i<4; i++) + { + xf86I2CReadByte(dev, F75375S_VT1_B1 + i, &nvl); + speeds->temp[i] = (int)nvl; + } + + for (i=0; i<5; i++) + { + xf86I2CReadByte(dev, F75375S_VT1_S1_H + (i*2), &nvh); + xf86I2CReadByte(dev, F75375S_VT1_S1_L + (i*2), &nvl); + speeds->speed[i] = FAN_TO_RPM(nvh, nvl); + } + + return 0; +} + + +int f75375_get_gpu_fanmode(I2CDevPtr dev) +{ + I2CByte mode; + + xf86I2CReadByte(dev, F75375S_FAN1_MODE, &mode); + return (int)mode; +} + + +int f75375_set_gpu_fanmode(I2CDevPtr dev, I2CByte mode) +{ + xf86I2CWriteByte(dev, F75375S_FAN1_MODE, (I2CByte)mode); + return 0; +} + + +int f75375_get_fanspeed_pwm(nouveau_device *device) +{ + I2CByte speed; + + xf86I2CReadByte(device->nvclock_i2c_sensor, F75375S_FAN1_PWM, &speed); + return (float)speed*100/256; +} + + +int f75375_set_fanspeed_pwm(I2CDevPtr dev, float speed) +{ + I2CByte value = (I2CByte)(speed * 255/100); + + xf86I2CWriteByte(dev, F75375S_FAN1_PWM, value); + return 0; +} diff --git a/plugins/GPUSensors/GeforceSensors/f75375.h b/plugins/GPUSensors/GeforceSensors/f75375.h new file mode 100755 index 0000000..2afd8a5 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/f75375.h @@ -0,0 +1,71 @@ +/* Fintek F75375 sensor module +/ Copyright(C) 2005, Matt Wright +*/ +//#include "nvclock.h" +#include "nvclock_i2c.h" + +int debug; +typedef struct _fan_vtemp +{ + int temp[4]; + int speed[5]; +} fan_vtemp; + + +#define dbg_printf(x) if (debug==1) IOLog(x) + +#define MODE_SPEED 0x00 +#define MODE_TEMP 0x10 +#define MODE_PWM 0x20 + +int f75375_get_gpu_fanmode(I2CDevPtr dev); +int f75375_set_gpu_fanmode(I2CDevPtr dev, I2CByte mode); +int f75375_set_gpu_tempctl(I2CDevPtr dev, fan_vtemp speeds); +int f75375_get_gpu_tempctl(I2CDevPtr dev, fan_vtemp *speeds); + +#define FINTEK_VENDOR1 0x5d +#define FINTEK_VENDOR2 0x5e + +#define ASUS_NV40_CHIPID_H 0x5a +#define ASUS_NV40_CHIPID_L 0x5b + +#define F75375S_VRAM_VCC 0x10 +#define F75375S_VRAM_V1 0x11 +#define F75375S_VRAM_V2 0x12 +#define F75375S_VRAM_V3 0x13 +#define F75375S_VRAM_TEMP1 0x14 +#define F75375S_VRAM_TEMP2 0x15 +#define F75375S_VRAM_FAN1_MSB 0x16 +#define F75375S_VRAM_FAN1_LSB 0x17 +#define F75375S_VRAM_FAN2_MSB 0x18 +#define F75375S_VRAM_FAN2_LSB 0x19 + +#define F75375S_FAN1_PWM 0x76 +#define F75375S_FAN1_COUNT_H 0x16 +#define F75375S_FAN1_COUNT_L 0x17 +#define F75375S_FAN1_MODE 0x60 +#define F75375S_FAN1_EXPECT_H 0x74 +#define F75375S_FAN1_EXPECT_L 0x75 + +#define F75375S_TEMP_GPU 0x14 +#define F75375S_TEMP_RAM 0x15 + +#define F75375S_VT1_B1 0xa0 +#define F75375S_VT1_B2 0xa1 +#define F75375S_VT1_B3 0xa2 +#define F75375S_VT1_B4 0xa3 + +#define F75375S_VT1_S1_H 0xa4 +#define F75375S_VT1_S1_L 0xa5 +#define F75375S_VT1_S2_H 0xa6 +#define F75375S_VT1_S2_L 0xa7 +#define F75375S_VT1_S3_H 0xa8 +#define F75375S_VT1_S3_L 0xa9 +#define F75375S_VT1_S4_H 0xaa +#define F75375S_VT1_S4_L 0xab +#define F75375S_VT1_S5_H 0xac +#define F75375S_VT1_S5_L 0xad + +#define FAN_TO_RPM(msb, lsb) (1500000/((msb<<8)+lsb)) +#define RPM_TO_FAN(x) (1500000/x) +#define MERGE_BYTE(msb, lsb) ((msb<<8)+lsb) diff --git a/plugins/GPUSensors/GeforceSensors/gm100.cpp b/plugins/GPUSensors/GeforceSensors/gm100.cpp new file mode 100755 index 0000000..0ec164c --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/gm100.cpp @@ -0,0 +1,164 @@ +// +// gm100.cpp +// HWSensors +// +// Created by Kozlek on 05.04.14. +// +// + + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "gm100.h" + +#include "nouveau.h" +#include "nv50.h" +#include "nva3.h" +#include "nv84.h" +#include "nvd0.h" +#include "nve0.h" +#include "nouveau_therm.h" + +bool gm100_identify(struct nouveau_device *device) { + switch (device->chipset) { + case 0x117: + device->cname = "GM107"; + // device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + // device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; + // device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass; + // device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; + // device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; + // device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; + // device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + // device->oclass[NVDEV_SUBDEV_DEVINIT] = gm107_devinit_oclass; + // device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; + // device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; + // device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; + // device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; + // device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; + // device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; + // device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; + // device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + // device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + // device->oclass[NVDEV_SUBDEV_PWR ] = nv108_pwr_oclass; + // + //#if 0 + // device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; + //#endif + // device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass; + // device->oclass[NVDEV_ENGINE_FIFO ] = nv108_fifo_oclass; + // device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; + // device->oclass[NVDEV_ENGINE_GR ] = gm107_graph_oclass; + // device->oclass[NVDEV_ENGINE_DISP ] = gm107_disp_oclass; + // device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; + //#if 0 + // device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; + //#endif + // device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; + //#if 0 + // device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass; + // device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; + // device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; + //#endif + break; + case 0x124: + device->cname = "GM204"; + // device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + // device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass; + // device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; + // device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; + //#if 0 + // /* looks to be some non-trivial changes */ + // device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; + // /* priv ring says no to 0x10eb14 writes */ + // device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; + //#endif + // device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + // device->oclass[NVDEV_SUBDEV_DEVINIT] = gm204_devinit_oclass; + // device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; + // device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; + // device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; + // device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; + // device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; + // device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; + // device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; + // device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + // device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; + // device->oclass[NVDEV_SUBDEV_PWR ] = nv108_pwr_oclass; + //#if 0 + // device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; + //#endif + // device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass; + //#if 0 + // device->oclass[NVDEV_ENGINE_FIFO ] = nv108_fifo_oclass; + // device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; + // device->oclass[NVDEV_ENGINE_GR ] = gm107_graph_oclass; + //#endif + // device->oclass[NVDEV_ENGINE_DISP ] = gm204_disp_oclass; + //#if 0 + // device->oclass[NVDEV_ENGINE_COPY0 ] = &gm204_copy0_oclass; + // device->oclass[NVDEV_ENGINE_COPY1 ] = &gm204_copy1_oclass; + // device->oclass[NVDEV_ENGINE_COPY2 ] = &gm204_copy2_oclass; + // device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass; + // device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; + // device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; + //#endif + // nv_fatal(device, "GM204 not supported yet\n"); + return true; + case 0x126: + device->cname = "GM206"; + return true; + case 0x120: + device->cname = "GM200"; + return true; + + default: + nv_fatal(device, "unknown Maxwell chipset 0x%x\n", device->chipset); + return false; + } + + return true; +} + +static int gm107_fan_pwm_get(struct nouveau_device *device, int line, u32 *divs, u32 *duty) { + *divs = nv_rd32(device, 0x10eb20) & 0x1fff; + *duty = nv_rd32(device, 0x10eb24) & 0x1fff; + return 0; +} + +void gm100_init(struct nouveau_device *device) { + nvd0_therm_init(device); + + device->gpio_find = nouveau_gpio_find; + device->gpio_get = nouveau_gpio_get; + device->gpio_sense = nvd0_gpio_sense; + device->temp_get = nv84_temp_get; + device->clocks_get = nve0_clock_read; + // device->voltage_get = nouveau_voltage_get; + device->pwm_get = gm107_fan_pwm_get; + device->fan_pwm_get = nouveau_therm_fan_pwm_get; + // device->fan_init = nva3_therm_init; + device->fan_rpm_get = nva3_therm_fan_sense; +} diff --git a/plugins/GPUSensors/GeforceSensors/gm100.h b/plugins/GPUSensors/GeforceSensors/gm100.h new file mode 100755 index 0000000..c0dc22e --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/gm100.h @@ -0,0 +1,15 @@ +// +// gm100.h +// HWSensors +// +// Created by Kozlek on 05.04.14. +// +// + +#ifndef HWSensors_gm100_h +#define HWSensors_gm100_h + +bool gm100_identify(struct nouveau_device *device); +void gm100_init(struct nouveau_device *device); + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/gp100.cpp b/plugins/GPUSensors/GeforceSensors/gp100.cpp new file mode 100644 index 0000000..f51cae9 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/gp100.cpp @@ -0,0 +1,80 @@ +// +// gp100.cpp +// HWSensors +// +// Created by Natan Zalkin on 17/12/2016. +// +// +/* + * Copyright 2017 Rhys Kidd + */ + +#include "gp100.h" + +#include "nouveau.h" +#include "nv50.h" +#include "nva3.h" +#include "nv84.h" +#include "nvd0.h" +#include "nve0.h" +#include "nouveau_therm.h" + +static int +gp100_temp_get(struct nouveau_device *device) { + u32 tsensor = nv_rd32(device, 0x020460); //Linux sources uses 20460 + u32 inttemp = (tsensor & 0x0001fff8); + + /* device SHADOWed */ + if (tsensor & 0x40000000) { + nv_info(device, "reading temperature from SHADOWed sensor\n"); + } + + /* device valid */ + if (tsensor & 0x20000000) { + return (inttemp >> 8); + } else { + return -ENODEV; + } +} + +bool gp100_identify(struct nouveau_device *device) { + switch (device->chipset) { + case 0x130: + device->cname = "GP100"; + break; + case 0x132: + device->cname = "GP102"; + break; + case 0x134: + device->cname = "GP104"; + break; + case 0x136: + device->cname = "GP106"; + break; + case 0x137: + device->cname = "GP107"; + break; + case 0x138: + case 0x13b: + device->cname = "GP108"; + break; + default: + nv_fatal(device, "unknown Pascal chipset 0x%x\n", device->chipset); + return false; + } + return true; +} + +void gp100_init(struct nouveau_device *device) { + nvd0_therm_init(device); + + device->gpio_find = nouveau_gpio_find; + device->gpio_get = nouveau_gpio_get; + device->gpio_sense = nvd0_gpio_sense; + device->temp_get = gp100_temp_get; //nv84_temp_get; + // device->clocks_get = nve0_clock_read; + // //device->voltage_get = nouveau_voltage_get; + device->pwm_get = nvd0_fan_pwm_get; //gm107_fan_pwm_get; + device->fan_pwm_get = nouveau_therm_fan_pwm_get; + device->fan_rpm_get = nva3_therm_fan_sense; +} diff --git a/plugins/GPUSensors/GeforceSensors/gp100.h b/plugins/GPUSensors/GeforceSensors/gp100.h new file mode 100644 index 0000000..5014b53 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/gp100.h @@ -0,0 +1,15 @@ +// +// gp100.h +// HWSensors +// +// Created by Natan Zalkin on 17/12/2016. +// +// + +#ifndef HWSensors_gp100_hpp +#define HWSensors_gp100_hpp + +bool gp100_identify(struct nouveau_device *device); +void gp100_init(struct nouveau_device *device); + +#endif /* HWSensors_gp100_hpp */ diff --git a/plugins/GPUSensors/GeforceSensors/i2c_algo_bit.cpp b/plugins/GPUSensors/GeforceSensors/i2c_algo_bit.cpp new file mode 100755 index 0000000..9b1586b --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/i2c_algo_bit.cpp @@ -0,0 +1,613 @@ +// +// i2c_algo_bit.cpp +// HWSensors +// +// Created by Kozlek on 13.08.12. +// +// + +//#include +#include "i2c_algo_bit.h" +#include "timer.h" + +/* ----- global defines ----------------------------------------------- */ + +static int bit_test = 0; /* see if the line-setting functions work */ + +#define bit_dbg(level, dev, format, args...) do {IOLog("LinuxI2C (algo_bit)L " format, ##args);} while (0) + +#define udelay(x) IODelay(x) +#define yield() IOSleep(0) + +#define KERN_WARNING "[kernwarn]" + +/* --- setting states on the bus with the right timing: --------------- */ + +#define setsda(adap, val) adap->setsda(adap->data, val) +#define setscl(adap, val) adap->setscl(adap->data, val) +#define getsda(adap) adap->getsda(adap->data) +#define getscl(adap) adap->getscl(adap->data) + +static inline void sdalo(struct i2c_algo_bit_data *adap) { + setsda(adap, 0); + udelay((adap->udelay + 1) / 2); +} + +static inline void sdahi(struct i2c_algo_bit_data *adap) { + setsda(adap, 1); + udelay((adap->udelay + 1) / 2); +} + +static inline void scllo(struct i2c_algo_bit_data *adap) { + setscl(adap, 0); + udelay(adap->udelay / 2); +} + +/* + * Raise scl line, and do checking for delays. This is necessary for slower + * devices. + */ +static int sclhi(struct i2c_algo_bit_data *adap) { + setscl(adap, 1); + + /* Not all adapters have scl sense line... */ + if (!adap->getscl) { + goto done; + } + + u64 end; + + end = ptimer_read() + adap->timeout * NSEC_PER_USEC; + + while (!getscl(adap)) { + /* This hw knows how to read the clock line, so we wait + * until it actually gets high. This is safer as some + * chips may hold it low ("clock stretching") while they + * are processing data internally. + */ + if (end - ptimer_read() <= 0) { + /* Test one last time, as we may have been preempted + * between last check and timeout test. + */ + if (getscl(adap)) { + break; + } + return -ETIMEDOUT; + } + cpu_relax(); + } + //#ifdef DEBUG + // if (jiffies != start && i2c_debug >= 3) + // pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go " + // "high\n", jiffies - start); + //#endif + +done: + udelay(adap->udelay); + return 0; +} + + +/* --- other auxiliary functions -------------------------------------- */ +static void i2c_start(struct i2c_algo_bit_data *adap) { + /* assert: scl, sda are high */ + setsda(adap, 0); + udelay(adap->udelay); + scllo(adap); +} + +static void i2c_repstart(struct i2c_algo_bit_data *adap) { + /* assert: scl is low */ + sdahi(adap); + sclhi(adap); + setsda(adap, 0); + udelay(adap->udelay); + scllo(adap); +} + + +static void i2c_stop(struct i2c_algo_bit_data *adap) { + /* assert: scl is low */ + sdalo(adap); + sclhi(adap); + setsda(adap, 1); + udelay(adap->udelay); +} + + +/* send a byte without start cond., look for arbitration, + check ackn. from slave */ +/* returns: + * 1 if the device acknowledged + * 0 if the device did not ack + * -ETIMEDOUT if an error occurred (while raising the scl line) + */ +static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c) { + struct i2c_algo_bit_data *adap = (struct i2c_algo_bit_data *)i2c_adap->algo_data; + + /* assert: scl is low */ + for (int i = 7; i >= 0; i--) { + int sb = (c >> i) & 1; + setsda(adap, sb); + udelay((adap->udelay + 1) / 2); + if (sclhi(adap) < 0) { /* timed out */ + bit_dbg(1, i2c_adap, "i2c_outb: 0x%02x, " + "timeout at bit #%d\n", (int)c, i); + return -ETIMEDOUT; + } + /* FIXME do arbitration here: + * if (sb && !getsda(adap)) -> ouch! Get out of here. + * + * Report a unique code, so higher level code can retry + * the whole (combined) message and *NOT* issue STOP. + */ + scllo(adap); + } + sdahi(adap); + if (sclhi(adap) < 0) { /* timeout */ + bit_dbg(1, i2c_adap, "i2c_outb: 0x%02x, " + "timeout at ack\n", (int)c); + return -ETIMEDOUT; + } + + /* read ack: SDA should be pulled down by slave, or it may + * NAK (usually to report problems with the data we wrote). + */ + int ack = !getsda(adap); /* ack: sda is pulled low -> success */ + bit_dbg(2, i2c_adap, "i2c_outb: 0x%02x %s\n", (int)c, ack ? "A" : "NA"); + + scllo(adap); + return ack; + /* assert: scl is low (sda undef) */ +} + + +static int i2c_inb(struct i2c_adapter *i2c_adap) { + /* read byte via i2c port, without start/stop sequence */ + /* acknowledge is sent in i2c_read. */ + unsigned char indata = 0; + struct i2c_algo_bit_data *adap = (struct i2c_algo_bit_data *)i2c_adap->algo_data; + + /* assert: scl is low */ + sdahi(adap); + for (int i = 0; i < 8; i++) { + if (sclhi(adap) < 0) { /* timeout */ + bit_dbg(1, i2c_adap, "i2c_inb: timeout at bit " + "#%d\n", 7 - i); + return -ETIMEDOUT; + } + indata *= 2; + if (getsda(adap)) { + indata |= 0x01; + } + setscl(adap, 0); + udelay(i == 7 ? adap->udelay / 2 : adap->udelay); + } + /* assert: scl is low */ + return indata; +} + +/* + * Sanity check for the adapter hardware - check the reaction of + * the bus lines only if it seems to be idle. + */ +static int test_bus(struct i2c_adapter *i2c_adap) { + struct i2c_algo_bit_data *adap = (struct i2c_algo_bit_data *)i2c_adap->algo_data; + const char *name = i2c_adap->name; + int scl, sda, ret; + + if (adap->pre_xfer) { + ret = adap->pre_xfer(i2c_adap); + if (ret < 0) + return -ENODEV; + } + + if (adap->getscl == NULL) { + pr_info("%s: Testing SDA only, SCL is not readable\n", name); + } + + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (!scl || !sda) { + printk(KERN_WARNING "%s: bus seems to be busy (scl=%d, sda=%d)\n", name, scl, sda); + goto bailout; + } + + sdalo(adap); + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (sda) { + printk(KERN_WARNING "%s: SDA stuck high!\n", name); + goto bailout; + } + if (!scl) { + printk(KERN_WARNING "%s: SCL unexpected low " + "while pulling SDA low!\n", name); + goto bailout; + } + + sdahi(adap); + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (!sda) { + printk(KERN_WARNING "%s: SDA stuck low!\n", name); + goto bailout; + } + if (!scl) { + printk(KERN_WARNING "%s: SCL unexpected low " + "while pulling SDA high!\n", name); + goto bailout; + } + + scllo(adap); + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 0 : getscl(adap); + if (scl) { + printk(KERN_WARNING "%s: SCL stuck high!\n", name); + goto bailout; + } + if (!sda) { + printk(KERN_WARNING "%s: SDA unexpected low " + "while pulling SCL low!\n", name); + goto bailout; + } + + sclhi(adap); + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (!scl) { + printk(KERN_WARNING "%s: SCL stuck low!\n", name); + goto bailout; + } + if (!sda) { + printk(KERN_WARNING "%s: SDA unexpected low " + "while pulling SCL high!\n", name); + goto bailout; + } + + if (adap->post_xfer) { + adap->post_xfer(i2c_adap); + } + + pr_info("%s: Test OK\n", name); + return 0; +bailout: + sdahi(adap); + sclhi(adap); + + if (adap->post_xfer) + adap->post_xfer(i2c_adap); + + return -ENODEV; +} + +/* ----- Utility functions + */ + +/* try_address tries to contact a chip for a number of + * times before it gives up. + * return values: + * 1 chip answered + * 0 chip did not answer + * -x transmission error + */ +static int try_address(struct i2c_adapter *i2c_adap, + unsigned char addr, int retries) { + struct i2c_algo_bit_data *adap = (struct i2c_algo_bit_data *)i2c_adap->algo_data; + int i, ret = 0; + + for (i = 0; i <= retries; i++) { + ret = i2c_outb(i2c_adap, addr); + if (ret == 1 || i == retries) + break; + bit_dbg(3, i2c_adap, "emitting stop condition\n"); + i2c_stop(adap); + udelay(adap->udelay); + yield(); + bit_dbg(3, i2c_adap, "emitting start condition\n"); + i2c_start(adap); + } + if (i && ret) { + bit_dbg(1, i2c_adap, "Used %d tries to %s client at " + "0x%02x: %s\n", i + 1, + addr & 1 ? "read from" : "write to", addr >> 1, + ret == 1 ? "success" : "failed, timeout?"); + } + return ret; +} + +static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { + const unsigned char *temp = msg->buf; + int count = msg->len; + unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; + int wrcount = 0; + + while (count > 0) { + int retval = i2c_outb(i2c_adap, *temp); + + /* OK/ACK; or ignored NAK */ + if ((retval > 0) || (nak_ok && (retval == 0))) { + count--; + temp++; + wrcount++; + + /* A slave NAKing the master means the slave didn't like + * something about the data it saw. For example, maybe + * the SMBus PEC was wrong. + */ + } else if (retval == 0) { + dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n"); + return -EIO; + + /* Timeout; or (someday) lost arbitration + * + * FIXME Lost ARB implies retrying the transaction from + * the first message, after the "winning" master issues + * its STOP. As a rule, upper layer code has no reason + * to know or care about this ... it is *NOT* an error. + */ + } else { + dev_err(&i2c_adap->dev, "sendbytes: error %d\n", + retval); + return retval; + } + } + return wrcount; +} + +static int acknak(struct i2c_adapter *i2c_adap, int is_ack) { + struct i2c_algo_bit_data *adap = (struct i2c_algo_bit_data *)i2c_adap->algo_data; + + /* assert: sda is high */ + if (is_ack) { /* send ack */ + setsda(adap, 0); + } + udelay((adap->udelay + 1) / 2); + if (sclhi(adap) < 0) { /* timeout */ + dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n"); + return -ETIMEDOUT; + } + scllo(adap); + return 0; +} + +static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { + int rdcount = 0; /* counts bytes read */ + unsigned char *temp = msg->buf; + int count = msg->len; + const unsigned flags = msg->flags; + + while (count > 0) { + int inval = i2c_inb(i2c_adap); + if (inval >= 0) { + *temp = inval; + rdcount++; + } else { /* read timed out */ + break; + } + temp++; + count--; + + /* Some SMBus transactions require that we receive the + transaction length as the first read byte. */ + if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) { + if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { + if (!(flags & I2C_M_NO_RD_ACK)) { + acknak(i2c_adap, 0); + } + dev_err(&i2c_adap->dev, "readbytes: invalid " + "block length (%d)\n", inval); + return -EPROTO; + } + /* The original count value accounts for the extra + bytes, that is, either 1 for a regular transaction, + or 2 for a PEC transaction. */ + count += inval; + msg->len += inval; + } + + bit_dbg(2, i2c_adap, "readbytes: 0x%02x %s\n", + inval, + (flags & I2C_M_NO_RD_ACK) + ? "(no ack/nak)" + : (count ? "A" : "NA")); + + if (!(flags & I2C_M_NO_RD_ACK)) { + inval = acknak(i2c_adap, count); + if (inval < 0) { + return inval; + } + } + } + return rdcount; +} + +/* doAddress initiates the transfer by generating the start condition (in + * try_address) and transmits the address in the necessary format to handle + * reads, writes as well as 10bit-addresses. + * returns: + * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set + * -x an error occurred (like: -ENXIO if the device did not answer, or + * -ETIMEDOUT, for example if the lines are stuck...) + */ +static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { + unsigned short flags = msg->flags; + unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; + struct i2c_algo_bit_data *adap = (struct i2c_algo_bit_data *)i2c_adap->algo_data; + + unsigned char addr; + int ret, retries; + + retries = nak_ok ? 0 : i2c_adap->retries; + + if (flags & I2C_M_TEN) { + /* a ten bit address */ + addr = 0xf0 | ((msg->addr >> 7) & 0x06); + bit_dbg(2, i2c_adap, "addr0: %d\n", addr); + /* try extended address code...*/ + ret = try_address(i2c_adap, addr, retries); + if ((ret != 1) && !nak_ok) { + dev_err(&i2c_adap->dev, + "died at extended address code\n"); + return -ENXIO; + } + /* the remaining 8 bit address */ + ret = i2c_outb(i2c_adap, msg->addr & 0xff); + if ((ret != 1) && !nak_ok) { + /* the chip did not ack / xmission error occurred */ + dev_err(&i2c_adap->dev, "died at 2nd address code\n"); + return -ENXIO; + } + if (flags & I2C_M_RD) { + bit_dbg(3, i2c_adap, "emitting repeated " + "start condition\n"); + i2c_repstart(adap); + /* okay, now switch into reading mode */ + addr |= 0x01; + ret = try_address(i2c_adap, addr, retries); + if ((ret != 1) && !nak_ok) { + dev_err(&i2c_adap->dev, + "died at repeated address code\n"); + return -EIO; + } + } + } else { /* normal 7bit address */ + addr = msg->addr << 1; + if (flags & I2C_M_RD) + addr |= 1; + if (flags & I2C_M_REV_DIR_ADDR) + addr ^= 1; + ret = try_address(i2c_adap, addr, retries); + if ((ret != 1) && !nak_ok) { + return -ENXIO; + } + } + + return 0; +} + +static int bit_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) { + struct i2c_msg *pmsg; + struct i2c_algo_bit_data *adap = (struct i2c_algo_bit_data *)i2c_adap->algo_data; + int i, ret; + unsigned short nak_ok; + + if (adap->pre_xfer) { + ret = adap->pre_xfer(i2c_adap); + if (ret < 0) + return ret; + } + + bit_dbg(3, i2c_adap, "emitting start condition\n"); + i2c_start(adap); + for (i = 0; i < num; i++) { + pmsg = &msgs[i]; + nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; + if (!(pmsg->flags & I2C_M_NOSTART)) { + if (i) { + bit_dbg(3, i2c_adap, "emitting " + "repeated start condition\n"); + i2c_repstart(adap); + } + ret = bit_doAddress(i2c_adap, pmsg); + if ((ret != 0) && !nak_ok) { + bit_dbg(1, i2c_adap, "NAK from " + "device addr 0x%02x msg #%d\n", + msgs[i].addr, i); + goto bailout; + } + } + if (pmsg->flags & I2C_M_RD) { + /* read bytes into buffer*/ + ret = readbytes(i2c_adap, pmsg); + if (ret >= 1) + bit_dbg(2, i2c_adap, "read %d byte%s\n", + ret, ret == 1 ? "" : "s"); + if (ret < pmsg->len) { + if (ret >= 0) { + ret = -EIO; + } + goto bailout; + } + } else { + /* write bytes from buffer */ + ret = sendbytes(i2c_adap, pmsg); + if (ret >= 1) + bit_dbg(2, i2c_adap, "wrote %d byte%s\n", + ret, ret == 1 ? "" : "s"); + if (ret < pmsg->len) { + if (ret >= 0) { + ret = -EIO; + } + goto bailout; + } + } + } + ret = i; + +bailout: + bit_dbg(3, i2c_adap, "emitting stop condition\n"); + i2c_stop(adap); + + if (adap->post_xfer) { + adap->post_xfer(i2c_adap); + } + return ret; +} + +static u32 bit_func(struct i2c_adapter *adap) { + return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; +} + + +/* -----exported algorithm data: ------------------------------------- */ + +const struct i2c_algorithm i2c_bit_algo = {bit_xfer, NULL, bit_func}; +//EXPORT_SYMBOL(i2c_bit_algo); + +/* + * registering functions to load algorithms at runtime + */ +static int __i2c_bit_add_bus(struct i2c_adapter *adap, + int (*add_adapter)(struct i2c_adapter *)) { + struct i2c_algo_bit_data *bit_adap = (struct i2c_algo_bit_data *)adap->algo_data; + int ret; + + if (bit_test) { + ret = test_bus(adap); + if (bit_test >= 2 && ret < 0) { + return -ENODEV; + } + } + + /* register new adapter to i2c module... */ + adap->algo = &i2c_bit_algo; + adap->retries = 3; + + if (add_adapter) { + ret = add_adapter(adap); + if (ret < 0) { + return ret; + } + } + + /* Complain if SCL can't be read */ + if (bit_adap->getscl == NULL) { + dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n"); + dev_warn(&adap->dev, "Bus may be unreliable\n"); + } + return 0; +} + +int i2c_bit_add_bus(struct i2c_adapter *adap) { + return __i2c_bit_add_bus(adap, NULL/*i2c_add_adapter*/); +} +//EXPORT_SYMBOL(i2c_bit_add_bus); + +int i2c_bit_add_numbered_bus(struct i2c_adapter *adap) { + return __i2c_bit_add_bus(adap, NULL/*i2c_add_numbered_adapter*/); +} +//EXPORT_SYMBOL(i2c_bit_add_numbered_bus); diff --git a/plugins/GPUSensors/GeforceSensors/i2c_algo_bit.h b/plugins/GPUSensors/GeforceSensors/i2c_algo_bit.h new file mode 100755 index 0000000..6a1773c --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/i2c_algo_bit.h @@ -0,0 +1,42 @@ +// +// i2c_algo_bit.h +// HWSensors +// +// Created by Kozlek on 13.08.12. +// +// + +#ifndef __HWSensors__i2c_algo_bit__ +#define __HWSensors__i2c_algo_bit__ + +#include "linux_definitions.h" +#include "i2c_base.h" + +/* --- Defines for bit-adapters --------------------------------------- */ +/* + * This struct contains the hw-dependent functions of bit-style adapters to + * manipulate the line states, and to init any hw-specific features. This is + * only used if you have more than one hw-type of adapter running. + */ +struct i2c_algo_bit_data { + void *data; /* private data for lowlevel routines */ + void (*setsda) (void *data, int state); + void (*setscl) (void *data, int state); + int (*getsda) (void *data); + int (*getscl) (void *data); + int (*pre_xfer) (struct i2c_adapter *); + void (*post_xfer) (struct i2c_adapter *); + + /* local settings */ + int udelay; /* half clock cycle time in us, + minimum 2 us for fast-mode I2C, + minimum 5 us for standard-mode I2C and SMBus, + maximum 50 us for SMBus */ + int timeout; /* in jiffies */ +}; + +int i2c_bit_add_bus(struct i2c_adapter *); +int i2c_bit_add_numbered_bus(struct i2c_adapter *); +extern const struct i2c_algorithm i2c_bit_algo; + +#endif /* defined(__HWSensors__i2c_algo_bit__) */ diff --git a/plugins/GPUSensors/GeforceSensors/i2c_base.cpp b/plugins/GPUSensors/GeforceSensors/i2c_base.cpp new file mode 100755 index 0000000..2a570d5 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/i2c_base.cpp @@ -0,0 +1,95 @@ +// +// i2c_base.cpp +// HWSensors +// +// Created by Kozlek on 13.08.12. +// +// + +#include "i2c_base.h" +#include "timer.h" + +/* ---------------------------------------------------- + * the functional interface to the i2c busses. + * ---------------------------------------------------- + */ + +/** + * __i2c_transfer - unlocked flavor of i2c_transfer + * @adap: Handle to I2C bus + * @msgs: One or more messages to execute before STOP is issued to + * terminate the operation; each message begins with a START. + * @num: Number of messages to be executed. + * + * Returns negative errno, else the number of messages executed. + * + * Adapter lock must be held when calling this function. No debug logging + * takes place. adap->algo->master_xfer existence isn't checked. + */ +int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { + int ret, try1; + + /* Retry automatically on arbitration loss */ + u64 end; + + end = ptimer_read() + adap->timeout * NSEC_PER_USEC; + + for (ret = 0, try1 = 0; try1 <= adap->retries; try1++) { + ret = adap->algo->master_xfer(adap, msgs, num); + + IOLog("GeforceSensors: _i2c_transfer=%d\n", ret); + + if (ret != -EAGAIN) { + break; + } + + if (end - ptimer_read() <= 0) { + break; + } + } + + return ret; +} + +/** + * i2c_transfer - execute a single or combined I2C message + * @adap: Handle to I2C bus + * @msgs: One or more messages to execute before STOP is issued to + * terminate the operation; each message begins with a START. + * @num: Number of messages to be executed. + * + * Returns negative errno, else the number of messages executed. + * + * Note that there is no requirement that each message be sent to + * the same slave address, although that is the most common model. + */ +int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { + /* REVISIT the fault reporting model here is weak: + * + * - When we get an error after receiving N bytes from a slave, + * there is no way to report "N". + * + * - When we get a NAK after transmitting N bytes to a slave, + * there is no way to report "N" ... or to let the master + * continue executing the rest of this combined message, if + * that's the appropriate response. + * + * - When for example "num" is two and we successfully complete + * the first message but get an error part way through the + * second, it's unclear whether that should be reported as + * one (discarding status on the second message) or errno + * (discarding status on the first one). + */ + + if (adap->algo->master_xfer) { + int ret = __i2c_transfer(adap, msgs, num); + + //IOLog("NouveauI2C: i2c_transfer=%d\n", ret); + + return ret; + } else { + IOLog("GeforceSensors: I2C level transfers not supported\n"); + return -EOPNOTSUPP; + } +} +//EXPORT_SYMBOL(i2c_transfer); diff --git a/plugins/GPUSensors/GeforceSensors/i2c_base.h b/plugins/GPUSensors/GeforceSensors/i2c_base.h new file mode 100755 index 0000000..c5c90fa --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/i2c_base.h @@ -0,0 +1,129 @@ +// +// i2c_base.h +// HWSensors +// +// Created by Kozlek on 13.08.12. +// +// + +#ifndef __HWSensors__i2c_base__ +#define __HWSensors__i2c_base__ + +#include "linux_definitions.h" + +struct i2c_msg { + u16 addr; /* slave address */ + u16 flags; +#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */ +#define I2C_M_RD 0x0001 /* read data, from slave to master */ +#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */ +#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */ +#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */ +#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */ +#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ +#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ + u16 len; /* msg length */ + u8 *buf; /* pointer to msg data */ +}; + +/* To determine what functionality is present */ + +#define I2C_FUNC_I2C 0x00000001 +#define I2C_FUNC_10BIT_ADDR 0x00000002 +#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_IGNORE_NAK etc. */ +#define I2C_FUNC_SMBUS_PEC 0x00000008 +#define I2C_FUNC_NOSTART 0x00000010 /* I2C_M_NOSTART */ +#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_QUICK 0x00010000 +#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 +#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 +#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 +#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 +#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 +#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 +#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 +#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 +#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 +#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ +#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ + +#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ +I2C_FUNC_SMBUS_WRITE_BYTE) +#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ +I2C_FUNC_SMBUS_WRITE_BYTE_DATA) +#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ +I2C_FUNC_SMBUS_WRITE_WORD_DATA) +#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ +I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) +#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ +I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) + +#define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | \ +I2C_FUNC_SMBUS_BYTE | \ +I2C_FUNC_SMBUS_BYTE_DATA | \ +I2C_FUNC_SMBUS_WORD_DATA | \ +I2C_FUNC_SMBUS_PROC_CALL | \ +I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ +I2C_FUNC_SMBUS_I2C_BLOCK | \ +I2C_FUNC_SMBUS_PEC) + +/* + * Data for SMBus Messages + */ +#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ + +struct i2c_adapter; + +struct i2c_algorithm { + /* If an adapter algorithm can't do I2C-level access, set master_xfer + to NULL. If an adapter algorithm can do SMBus access, set + smbus_xfer. If set to NULL, the SMBus protocol is simulated + using common I2C messages */ + /* master_xfer should return the number of messages successfully + processed, or a negative value on error */ + int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num); + int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data); + + /* To determine what the adapter supports */ + u32 (*functionality) (struct i2c_adapter *); +}; + +struct i2c_adapter { + //struct module *owner; + //unsigned int class; /* classes to allow probing for */ + const struct i2c_algorithm *algo; /* the algorithm to access the bus */ + void *algo_data; + + bool lock; + /* data fields that are valid for all devices */ + //struct rt_mutex bus_lock; + + int timeout; /* in jiffies */ + int retries; + //struct device dev; /* the adapter device */ + + int nr; + char name[48]; + //struct completion dev_released; + + //struct mutex userspace_clients_lock; + //struct list_head userspace_clients; +}; + +struct i2c_board_info { + char type[I2C_NAME_SIZE]; + unsigned short flags; + unsigned short addr; + void *platform_data; + //struct dev_archdata *archdata; + //struct device_node *of_node; + int irq; +}; + +int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); +int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); + +#endif /* defined(__HWSensors__i2c_base__) */ diff --git a/plugins/GPUSensors/GeforceSensors/linux_definitions.h b/plugins/GPUSensors/GeforceSensors/linux_definitions.h new file mode 100755 index 0000000..855f154 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/linux_definitions.h @@ -0,0 +1,159 @@ +// +// linux_definitions.h +// HWSensors +// +// Created by Kozlek on 13.08.12. +// +// + +#ifndef HWSensors_linux_definitions_h +#define HWSensors_linux_definitions_h + +#include + +#define EPERM 1 // Operation not permitted +#define ENOENT 2 // No such file or directory +#define ESRCH 3 // No such process +#define EINTR 4 // Interrupted system call +#define EIO 5 // Input/output error +#define ENXIO 6 // Device not configured +#define E2BIG 7 // Argument list too long +#define ENOEXEC 8 // Exec format error +#define EBADF 9 // Bad file number +#define ECHILD 10 // No spawned processes +#define EAGAIN 11 // Resource temporarily unavailable +#define ENOMEM 12 // Cannot allocate memory +#define EACCES 13 // Access denied +#define EFAULT 14 // Bad address +#define ENOTBLK 15 // Not block device +#define EBUSY 16 // Device busy +#define EEXIST 17 // File exist +#define EXDEV 18 // Cross-device link +#define ENODEV 19 // Operation not supported by device +#define ENOTDIR 20 // Not a directory +#define EISDIR 21 // Is a directory +#define EINVAL 22 // Invalid argument +#define ENFILE 23 // Too many open files in system +#define EMFILE 24 // Too many files open +#define ENOTTY 25 // Inappropriate ioctl for device +#define ETXTBSY 26 // Unknown error +#define EFBIG 27 // File too large +#define ENOSPC 28 // No space left on device +#define ESPIPE 29 // Illegal seek +#define EROFS 30 // Read-only file system +#define EMLINK 31 // Too many links +#define EPIPE 32 // Broken pipe +#define EDOM 33 // Numerical arg out of domain +#define ERANGE 34 // Result too large +#define EUCLEAN 35 // Structure needs cleaning +#define EDEADLK 36 // Resource deadlock avoided +#define EUNKNOWN 37 // Unknown error +#define ENAMETOOLONG 38 // File name too long +#define ENOLCK 39 // No locks available +#define ENOSYS 40 // Function not implemented +#define ENOTEMPTY 41 // Directory not empty +#define EILSEQ 42 // Invalid multibyte sequence + +// +// Sockets errors +// + +#define EWOULDBLOCK 45 // Operation would block +#define EINPROGRESS 46 // Operation now in progress +#define EALREADY 47 // Operation already in progress +#define ENOTSOCK 48 // Socket operation on nonsocket +#define EDESTADDRREQ 49 // Destination address required +#define EMSGSIZE 50 // Message too long +#define EPROTOTYPE 51 // Protocol wrong type for socket +#define ENOPROTOOPT 52 // Bad protocol option +#define EPROTONOSUPPORT 53 // Protocol not supported +#define ESOCKTNOSUPPORT 54 // Socket type not supported +#define EOPNOTSUPP 55 // Operation not supported +#define EPFNOSUPPORT 56 // Protocol family not supported +#define EAFNOSUPPORT 57 // Address family not supported +#define EADDRINUSE 58 // Address already in use +#define EADDRNOTAVAIL 59 // Cannot assign requested address +#define ENETDOWN 60 // Network is down +#define ENETUNREACH 61 // Network is unreachable +#define ENETRESET 62 // Network dropped connection on reset +#define ECONNABORTED 63 // Connection aborted +#define ECONNRESET 64 // Connection reset by peer +#define ENOBUFS 65 // No buffer space available +#define EISCONN 66 // Socket is already connected +#define ENOTCONN 67 // Socket is not connected +#define ESHUTDOWN 68 // Cannot send after socket shutdown +#define ETOOMANYREFS 69 // Too many references +#define ETIMEDOUT 70 // Operation timed out +#define ECONNREFUSED 71 // Connection refused +#define ELOOP 72 // Cannot translate name +#define EWSNAMETOOLONG 73 // Name component or name was too long +#define EHOSTDOWN 74 // Host is down +#define EHOSTUNREACH 75 // No route to host +#define EWSNOTEMPTY 76 // Cannot remove a directory that is not empty +#define EPROCLIM 77 // Too many processes +#define EUSERS 78 // Ran out of quota +#define EDQUOT 79 // Ran out of disk quota +#define ESTALE 80 // File handle reference is no longer available +#define EREMOTE 81 // Item is not available locally + +// +// Resolver errors +// + +#define EHOSTNOTFOUND 82 // Host not found +#define ETRYAGAIN 83 // Nonauthoritative host not found +#define ENORECOVERY 84 // A nonrecoverable error occured +#define ENODATA 85 // Valid name, no data record of requested type + +// +// Misc. error codes +// + +#define EPROTO 86 // Protocol error +#define ECHKSUM 87 // Checksum error +#define EBADSLT 88 // Invalid slot +#define EREMOTEIO 89 // Remote I/O error + +// +// Error code aliases +// + +#define ETIMEOUT ETIMEDOUT +#define EBUF ENOBUFS +#define EROUTE ENETUNREACH +#define ECONN ENOTCONN +#define ERST ECONNRESET +#define EABORT ECONNABORTED + +typedef UInt8 u8; +typedef UInt16 u16; +typedef UInt32 u32; +typedef UInt64 u64; +typedef SInt8 s8; +typedef SInt16 s16; +typedef SInt32 s32; +typedef SInt64 s64; + +#define pr_err(format, args...) do {IOLog("LinuxI2C(pr_err): " format, ##args);} while (0) +#define pr_debug(format, args...) do {IOLog("LinuxI2C(pr_debug): " format, ##args);} while (0) +#define dev_err(dev, format, args...) do {IOLog("LinuxI2C(dev_err): " format, ##args);} while (0) +#define dev_warn(dev, format, args...) do {IOLog("LinuxI2C(dev_warn): " format, ##args);} while (0) +#define printk(format, args...) do {IOLog("LinuxI2C(printk): " format, ##args);} while (0) +#define pr_info(format, args...) do {IOLog("LinuxI2C(pr_info): " format, ##args);} while (0) + +/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ +static inline void rep_nop(void) +{ + __asm__ __volatile__("rep;nop": : :"memory"); +} + +#define cpu_relax() rep_nop() + +#define I2C_NAME_SIZE 20 + +#define min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1: __min2; }) + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/list.h b/plugins/GPUSensors/GeforceSensors/list.h new file mode 100755 index 0000000..eede40a --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/list.h @@ -0,0 +1,715 @@ +// +// list.h +// HWSensors +// +// Created by Kozlek on 13.08.12. +// +// + +#ifndef HWSensors_list_h +#define HWSensors_list_h + +#define container_of(ptr, type, member) ({ \ +const typeof( ((type *)0)->member ) *__mptr = (ptr); \ +(type *)( (char *)__mptr - offsetof(type,member) );}) + +#define POISON_POINTER_DELTA 0 +#define LIST_POISON1 (void *) (0x00100100 + POISON_POINTER_DELTA) +#define LIST_POISON2 (void *) (0x00200200 + POISON_POINTER_DELTA) + +struct list_head { + struct list_head *next, *prev; +}; + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ +struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) { + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +#ifndef CONFIG_DEBUG_LIST +static inline void __list_add(struct list_head *newl, + struct list_head *prev, + struct list_head *next) { + next->prev = newl; + newl->next = next; + newl->prev = prev; + prev->next = newl; +} +#else +extern void __list_add(struct list_head *newl, + struct list_head *prev, + struct list_head *next); +#endif + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *newl, struct list_head *head) { + __list_add(newl, head, head->next); +} + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *newl, struct list_head *head) { + __list_add(newl, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) { + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +#ifndef CONFIG_DEBUG_LIST +static inline void __list_del_entry(struct list_head *entry) { + __list_del(entry->prev, entry->next); +} + +static inline void list_del(struct list_head *entry) { + __list_del(entry->prev, entry->next); + entry->next = (struct list_head *)LIST_POISON1; + entry->prev = (struct list_head *)LIST_POISON2; +} +#else +extern void __list_del_entry(struct list_head *entry); +extern void list_del(struct list_head *entry); +#endif + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *newl) { + newl->next = old->next; + newl->next->prev = newl; + newl->prev = old->prev; + newl->prev->next = newl; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *newl) { + list_replace(old, newl); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) { + __list_del_entry(entry); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) { + __list_del_entry(list); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) { + __list_del_entry(list); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) { + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) { + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) { + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +/** + * list_rotate_left - rotate the list to the left + * @head: the head of the list + */ +static inline void list_rotate_left(struct list_head *head) { + if (!list_empty(head)) { + struct list_head *first = head->next; + list_move_tail(first, head); + } +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) { + return !list_empty(head) && (head->next == head->prev); +} + +static inline void __list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) { + struct list_head *new_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; +} + +/** + * list_cut_position - cut a list into two + * @list: a new list to add all removed entries + * @head: a list with entries + * @entry: an entry within head, could be the head itself + * and if so we won't cut the list + * + * This helper moves the initial part of @head, up to and + * including @entry, from @head to @list. You should + * pass on @entry an element you know is on @head. @list + * should be an empty list or a list you do not care about + * losing its data. + * + */ +static inline void list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) { + if (list_empty(head)) { + return; + } + if (list_is_singular(head) && + (head->next != entry && head != entry)) { + return; + } + if (entry == head) { + INIT_LIST_HEAD(list); + } else { + __list_cut_position(list, head, entry); + } +} + +static inline void __list_splice(const struct list_head *list, + struct list_head *prev, + struct list_head *next) { + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** + * list_splice - join two lists, this is designed for stacks + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(const struct list_head *list, + struct list_head *head) { + if (!list_empty(list)) { + __list_splice(list, head, head->next); + } +} + +/** + * list_splice_tail - join two lists, each list being a queue + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) { + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + } +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) { + if (!list_empty(list)) { + __list_splice(list, head, head->next); + INIT_LIST_HEAD(list); + } +} + +/** + * list_splice_tail_init - join two lists and reinitialise the emptied list + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +static inline void list_splice_tail_init(struct list_head *list, + struct list_head *head) { + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ +container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ +list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ +for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant doesn't differ from list_for_each() any more. + * We don't do prefetching in either case. + */ +#define __list_for_each(pos, head) \ +for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ +for (pos = (head)->prev; pos != (head); pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ +for (pos = (head)->next, n = pos->next; pos != (head); \ +pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ +for (pos = (head)->prev, n = pos->prev; \ +pos != (head); \ +pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ +for (pos = list_entry((head)->next, typeof(*pos), member); \ +&pos->member != (head); \ +pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ +for (pos = list_entry((head)->prev, typeof(*pos), member); \ +&pos->member != (head); \ +pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ +((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ +for (pos = list_entry(pos->member.next, typeof(*pos), member); \ +&pos->member != (head); \ +pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ +for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ +&pos->member != (head); \ +pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ +for (; &pos->member != (head); \ +pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ +for (pos = list_entry((head)->next, typeof(*pos), member), \ +n = list_entry(pos->member.next, typeof(*pos), member); \ +&pos->member != (head); \ +pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue - continue list iteration safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ +for (pos = list_entry(pos->member.next, typeof(*pos), member), \ +n = list_entry(pos->member.next, typeof(*pos), member); \ +&pos->member != (head); \ +pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from - iterate over list from current point safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ +for (n = list_entry(pos->member.next, typeof(*pos), member); \ +&pos->member != (head); \ +pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ +for (pos = list_entry((head)->prev, typeof(*pos), member), \ +n = list_entry(pos->member.prev, typeof(*pos), member); \ +&pos->member != (head); \ +pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +/** + * list_safe_reset_next - reset a stale list_for_each_entry_safe loop + * @pos: the loop cursor used in the list_for_each_entry_safe loop + * @n: temporary storage used in list_for_each_entry_safe + * @member: the name of the list_struct within the struct. + * + * list_safe_reset_next is not safe to use in general if the list may be + * modified concurrently (eg. the lock is dropped in the loop body). An + * exception to this is if the cursor element (pos) is pinned in the list, + * and list_safe_reset_next is called after re-taking the lock and before + * completing the current iteration of the loop body. + */ +#define list_safe_reset_next(pos, n, member) \ +n = list_entry(pos->member.next, typeof(*pos), member) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE(struct hlist_node *h) { + h->next = NULL; + h->pprev = NULL; +} + +static inline int hlist_unhashed(const struct hlist_node *h) { + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) { + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) { + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) { + next->pprev = pprev; + } +} + +static inline void hlist_del(struct hlist_node *n) { + __hlist_del(n); + n->next = (struct hlist_node *)LIST_POISON1; + n->pprev = (struct hlist_node **)LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) { + if (!hlist_unhashed(n)) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { + struct hlist_node *first = h->first; + n->next = first; + if (first) { + first->pprev = &n->next; + } + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) { + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) { + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) { + next->next->pprev = &next->next; + } +} + +/* after that we'll appear to be on some hlist and hlist_del will work */ +static inline void hlist_add_fake(struct hlist_node *n) { + n->pprev = &n->next; +} + +/* + * Move a list from one list head to another. Fixup the pprev + * reference of the first entry if it exists. + */ +static inline void hlist_move_list(struct hlist_head *old, + struct hlist_head *newl) { + newl->first = old->first; + if (newl->first) { + newl->first->pprev = &newl->first; + } + old->first = NULL; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ +for (pos = (head)->first; pos ; pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ +for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ +pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ +for (pos = (head)->first; \ +pos && \ +({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ +pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ +for (pos = (pos)->next; \ +pos && \ +({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ +pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ +for (; pos && \ +({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ +pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ +for (pos = (head)->first; \ +pos && ({ n = pos->next; 1; }) && \ +({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ +pos = n) + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/lm99.cpp b/plugins/GPUSensors/GeforceSensors/lm99.cpp new file mode 100755 index 0000000..227b82a --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/lm99.cpp @@ -0,0 +1,221 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2005 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * LM99 hardware monitoring + */ + +#include "nouveau_definitions.h" + +#include "nvclock_i2c.h" + +/* various defines for register offsets and such are needed */ + +#define LM99_REG_LOCAL_TEMP 0x00 +#define LM99_REG_REMOTE_TEMP 0x01 +#define LM99_REG_MAN_ID 0xfe +#define NATSEM_MAN_ID 0x01 +#define MAXIM_MAN_ID 0x4d +#define MAX6659_REG_R_REMOTE_EMERG 0x16 +#define MAX6696_REG_R_STATUS2 0x12 +#define LM99_REG_CHIP_ID 0xff +#define LM90_REG_R_CONFIG1 0x03 +#define LM90_REG_R_CONFIG2 0xBF +#define LM90_REG_R_CONVRATE 0x04 + +/* This function should return the chip type .. */ +int lm99_detect(I2CDevPtr dev) +{ + I2CByte man_id, chip_id, config1, config2, convrate, address = dev->SlaveAddr / 2; + const char *name = NULL; + + if (!xf86I2CReadByte(dev, LM99_REG_MAN_ID, &man_id) || !xf86I2CReadByte(dev, LM99_REG_CHIP_ID, &chip_id) || !xf86I2CReadByte(dev, LM90_REG_R_CONFIG1, &config1) || !xf86I2CReadByte(dev, LM90_REG_R_CONVRATE, &convrate)) + return 0; + + if (man_id == 0x01 || man_id == 0x5C || man_id == 0x41) { + if (!xf86I2CReadByte(dev, LM90_REG_R_CONVRATE, &config2)) + return 0; + } else config2 = 0; + + if ((address == 0x4C || address == 0x4D) && man_id == 0x01) { /* National Semiconductor */ + if ((config1 & 0x2A) == 0x00 && (config2 & 0xF8) == 0x00 && convrate <= 0x09) { + if ((address == 0x4C) && ((chip_id & 0xF0) == 0x20)) { /* LM90 */ + name = "National Semiconductor LM90"; + dev->chip_id = LM99; + } else if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */ + name = "National Semiconductor LM89"; + dev->chip_id = LM99; + } else if ((address == 0x4C) && ((chip_id & 0xF0) == 0x10)) { /* LM86 */ + name = "National Semiconductor LM86"; + dev->chip_id = LM99; + } + } + } + else if ((address == 0x4C || address == 0x4D) && man_id == 0x41) { /* Analog Devices */ + if ((chip_id & 0xF0) == 0x40 /* ADM1032 */ && (config1 & 0x3F) == 0x00 && convrate <= 0x0A) { + name = "Analog Devices ADM1032"; + dev->chip_id = LM99; + /* + * The ADM1032 supports PEC, but only if combined + * transactions are not used. + */ + // if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + // info->flags |= I2C_CLIENT_PEC; + } else if (chip_id == 0x51 /* ADT7461 */ && (config1 & 0x1B) == 0x00 && convrate <= 0x0A) { + name = "Analog Devices ADT7461"; + dev->chip_id = LM99; + } else if (chip_id == 0x57 /* ADT7461A, NCT1008 */ && (config1 & 0x1B) == 0x00 && convrate <= 0x0A) { + name = "Analog Devices ADT7461A"; + dev->chip_id = MAX6559; + } + } else if (man_id == 0x4D) { /* Maxim */ + I2CByte emerg, emerg2, status2; + + /* + * We read MAX6659_REG_R_REMOTE_EMERG twice, and re-read + * LM90_REG_R_MAN_ID in between. If MAX6659_REG_R_REMOTE_EMERG + * exists, both readings will reflect the same value. Otherwise, + * the readings will be different. + */ + if (!xf86I2CReadByte(dev, MAX6659_REG_R_REMOTE_EMERG, &emerg) || !xf86I2CReadByte(dev, LM99_REG_MAN_ID, &man_id) || !xf86I2CReadByte(dev, MAX6659_REG_R_REMOTE_EMERG, &emerg2) || !xf86I2CReadByte (dev, MAX6696_REG_R_STATUS2, &status2)) + return 0; + + /* + * The MAX6657, MAX6658 and MAX6659 do NOT have a chip_id + * register. Reading from that address will return the last + * read value, which in our case is those of the man_id + * register. Likewise, the config1 register seems to lack a + * low nibble, so the value will be those of the previous + * read, so in our case those of the man_id register. + * MAX6659 has a third set of upper temperature limit registers. + * Those registers also return values on MAX6657 and MAX6658, + * thus the only way to detect MAX6659 is by its address. + * For this reason it will be mis-detected as MAX6657 if its + * address is 0x4C. + */ + if (chip_id == man_id && (address == 0x4C || address == 0x4D || address == 0x4E) && (config1 & 0x1F) == (man_id & 0x0F) && convrate <= 0x09) { + if (address == 0x4C) + name = "Maxim MAX6657"; + else + name = "Maxim MAX6659"; + dev->chip_id = MAX6559; + } + /* + * Even though MAX6695 and MAX6696 do not have a chip ID + * register, reading it returns 0x01. Bit 4 of the config1 + * register is unused and should return zero when read. Bit 0 of + * the status2 register is unused and should return zero when + * read. + * + * MAX6695 and MAX6696 have an additional set of temperature + * limit registers. We can detect those chips by checking if + * one of those registers exists. + */ + else if (chip_id == 0x01 && (config1 & 0x10) == 0x00 && (status2 & 0x01) == 0x00 && emerg == emerg2 && convrate <= 0x07) { + name = "Maxim MAX6696"; + dev->chip_id = MAX6559; + } + /* + * The chip_id register of the MAX6680 and MAX6681 holds the + * revision of the chip. The lowest bit of the config1 register + * is unused and should return zero when read, so should the + * second to last bit of config1 (software reset). + */ + else if (chip_id == 0x01 && (config1 & 0x03) == 0x00 && convrate <= 0x07) { + name = "Maxim MAX6680"; + dev->chip_id = LM99; + } + /* + * The chip_id register of the MAX6646/6647/6649 holds the + * revision of the chip. The lowest 6 bits of the config1 + * register are unused and should return zero when read. + */ + else if (chip_id == 0x59 && (config1 & 0x3f) == 0x00 && convrate <= 0x07) { + name = "Maxim MAX6646"; + dev->chip_id = MAX6559; + } + } else if (address == 0x4C && man_id == 0x5C) { /* Winbond/Nuvoton */ + if ((config1 & 0x2A) == 0x00 && (config2 & 0xF8) == 0x00) { + if (chip_id == 0x01 /* W83L771W/G */ && convrate <= 0x09) { + name = "Winbond/Nuvoton W83l771"; + dev->chip_id = MAX6559; + } else if ((chip_id & 0xFE) == 0x10 /* W83L771AWG/ASG */ && convrate <= 0x08) { + name = "Winbond/Nuvoton W83l771"; + dev->chip_id = LM99; + } + } + } else if (address >= 0x48 && address <= 0x4F && man_id == 0xA1) { /* NXP Semiconductor/Philips */ + if (chip_id == 0x00 && (config1 & 0x2A) == 0x00 && (config2 & 0xFE) == 0x00 && convrate <= 0x09) { + name = "NXP Semiconductor/Philips SA56004"; + dev->chip_id = LM99; + } + } else if ((address == 0x4C || address == 0x4D) && man_id == 0x47) { /* GMT */ + if (chip_id == 0x01 /* G781 */ && (config1 & 0x3F) == 0x00 && convrate <= 0x08) { + name = "GMT G781"; + dev->chip_id = LM99; + } + } + + if (!name) /* identification failed */ + return 0; + + dev->chip_name = STRDUP(name, sizeof(name)); + + return 1; +} + +int lm99_get_board_temp(nouveau_device *device) +{ + I2CByte temp; + xf86I2CReadByte(device->nvclock_i2c_sensor, LM99_REG_LOCAL_TEMP, &temp); + return temp; +} + +int lm99_get_gpu_temp(nouveau_device *device) +{ + I2CByte temp; + + xf86I2CReadByte(device->nvclock_i2c_sensor, LM99_REG_REMOTE_TEMP, &temp); + + /* Cards with lm99 chips need an offset of 16C according to the datasheets. */ + if(device->nvclock_i2c_sensor->chip_id == LM99) + { + temp += 16; + } + + /* The temperature needs to be corrected using an offset which is stored in the bios. + / If no bios has been parsed we fall back to a default value. + */ + if(device->bios.data) + { + temp += device->sensor_constants.offset_constant; //nv_card->bios->sensor_cfg.temp_correction; + } + else + { + /* An extra offset of 10C seems to be needed on Geforce6800 cards to match nvidia-settings. + / Last but not least Geforce6600GT boards containing an LM99 sensor seem to need a +5C offset. + */ + if(device->chipset == 0x43) + temp += 5; + else if(device->card_type == NV_40) + temp += 10; + } + + return temp; +} diff --git a/plugins/GPUSensors/GeforceSensors/nouveau.cpp b/plugins/GPUSensors/GeforceSensors/nouveau.cpp new file mode 100755 index 0000000..c79b33d --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau.cpp @@ -0,0 +1,154 @@ +// +// nouveau.c +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nouveau.h" +#include "nv40.h" +#include "nv50.h" +#include "nva3.h" +#include "nvc0.h" +#include "nve0.h" +#include "gm100.h" +#include "gp100.h" +#include "nouveau_therm.h" +#include "nouveau_volt.h" + +bool nouveau_identify(struct nouveau_device *device) +{ + /* identify the chipset */ + + nv_debug(device, "identifying the chipset\n"); + + /* read boot0 and strapping information */ + UInt32 boot0 = nv_rd32(device, 0x000000); //0x0c1e00a1 = Fermi + UInt32 strap = nv_rd32(device, 0x101000); + + /* determine chipset and derive architecture from it */ + if ((boot0 & 0x1f000000) > 0) { + device->chipset = (boot0 & 0x1ff00000) >> 20; + switch (device->chipset & 0x1f0) { + case 0x40: + case 0x60: device->card_type = NV_40; break; + case 0x50: + case 0x80: + case 0x90: + case 0xa0: device->card_type = NV_50; break; + case 0xc0: device->card_type = NV_C0; break; + case 0xd0: device->card_type = NV_D0; break; + case 0xe0: + case 0xf0: + case 0x100: device->card_type = NV_E0; break; + case 0x110: + case 0x120: device->card_type = GM100; break; + case 0x130: device->card_type = GP100; break; + default: + break; + } + } + + bool ret = FALSE; + + switch (device->card_type) { + case NV_40: ret = nv40_identify(device); break; + case NV_50: ret = nv50_identify(device); break; + case NV_C0: + case NV_D0: ret = nvc0_identify(device); break; + case NV_E0: ret = nve0_identify(device); break; + case GM100: ret = gm100_identify(device); break; + case GP100: ret = gp100_identify(device); break; + default: break; + } + + if (!ret) { + nv_error(device, "unknown chipset, 0x%08x\n", (unsigned int)boot0); + return false; + } + + nv_debug(device, "BOOT0 : 0x%08x\n", (unsigned int)boot0); + nv_debug(device, "chipset: %s (NV%02X) family: NV%02X\n", + device->cname, (unsigned int)device->chipset, (unsigned int)device->card_type); + /* determine frequency of timing crystal */ + if ( device->chipset < 0x17 || + (device->chipset >= 0x20 && device->chipset <= 0x25)) + strap &= 0x00000040; + else + strap &= 0x00400040; + + switch (strap) { + case 0x00000000: device->crystal = 13500; break; + case 0x00000040: device->crystal = 14318; break; + case 0x00400000: device->crystal = 27000; break; + case 0x00400040: device->crystal = 25000; break; + default: //impossible + device->crystal = 27000; break; + } + + nv_debug(device, "crystal freq: %dKHz\n", (unsigned int)device->crystal); + + return true; +} + +bool nouveau_init(struct nouveau_device *device) +{ + int ret; + + nv_debug(device, "initializing monitoring driver\n"); + + switch (device->card_type) { + case NV_40: nv40_init(device); break; + case NV_50: nv50_init(device); break; + case NV_C0: + case NV_D0: nvc0_init(device); break; + case NV_E0: nve0_init(device); break; + case GM100: gm100_init(device); break; + case GP100: gp100_init(device); break; + default: break; + } + + // attempt to locate a drivable fan + ret = device->gpio_find(device, 0, DCB_GPIO_FAN, 0xff, &device->fan_pwm); + if (ret < 0) + device->fan_pwm.func = DCB_GPIO_UNUSED; + + /* attempt to detect a tachometer connection */ + ret = device->gpio_find(device, 0, DCB_GPIO_FAN_SENSE, 0xff, &device->fan_tach); + if (ret < 0) + device->fan_tach.func = DCB_GPIO_UNUSED; + + /*if (device->gpio_init) + device->gpio_init(device);*/ + + /* parse aux tables from vbios */ + nouveau_volt_init(device); + nouveau_therm_init(device); + + return true; +} diff --git a/plugins/GPUSensors/GeforceSensors/nouveau.h b/plugins/GPUSensors/GeforceSensors/nouveau.h new file mode 100755 index 0000000..75e9224 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau.h @@ -0,0 +1,152 @@ +// +// nouveau.h +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +#ifndef HWSensors_nouveau_h +#define HWSensors_nouveau_h + +#include + +#include "nouveau_definitions.h" +#include "nouveau_bios.h" +#include "nouveau_gpio.h" +#include "nouveau_volt.h" +#include "nouveau_i2c.h" + +enum nouveau_clock_source { //enum nv_clk_src + nouveau_clock_core = 1, + nouveau_clock_shader = 2, + nouveau_clock_memory = 3, + nouveau_clock_rop = 4, + nouveau_clock_copy = 5, + nouveau_clock_daemon = 6, + nouveau_clock_vdec = 7, + nouveau_clock_dom6 = 8, + nouveau_clock_unka0 = 9, /* nva3:nvc0 */ + nouveau_clock_hub01 = 10, /* nvc0- */ + nouveau_clock_hub06 = 11, /* nvc0- */ + nouveau_clock_hub07 = 12, /* nvc0- */ + nouveau_clock_mpll = 13, + nouveau_clock_mpllsrc = 14, + nouveau_clock_mpllref = 15 +}; + +struct nouveau_pm_temp_sensor_constants { + s16 slope_mult; + s16 slope_div; + s16 offset_num; + s16 offset_den; + s8 offset_constant; +}; + +enum nouveau_card_type { + NV_NA = 0x000, + NV_04 = 0x004, + NV_40 = 0x040, + NV_50 = 0x050, + NV_C0 = 0x0c0, + NV_D0 = 0x0d0, + NV_E0 = 0x0e0, + GM100 = 0x110, + GP100 = 0x130, +}; + +typedef struct _I2CDevRec *I2CDevPtr; + +struct nouveau_device { + IOPCIDevice *pcidev; + IOMemoryMap *mmio; + + const char *name; + const char *cname; + + nouveau_card_type card_type; + s8 card_index; + + u32 device_id; + u32 chipset; + u32 crystal; + + nouveau_bios bios; + nvbios vbios; + + nouveau_pm_temp_sensor_constants sensor_constants; + nouveau_pm_voltage voltage; + nouveau_i2c i2c; + + I2CDevPtr nvclock_i2c_sensor; + + dcb_gpio_func fan_pwm; + dcb_gpio_func fan_tach; + + int (*gpio_sense)(struct nouveau_device *, int line); + int (*gpio_find)(struct nouveau_device *, int idx, u8 tag, u8 line, struct dcb_gpio_func *); + int (*gpio_get)(struct nouveau_device *, int idx, u8 tag, u8 line); + + int (*pwm_get)(struct nouveau_device *, int line, u32*, u32*); + + int (*clocks_get)(struct nouveau_device *, u8 source); + int (*voltage_get)(struct nouveau_device *); + int (*temp_get)(struct nouveau_device *); + int (*core_temp_get)(struct nouveau_device *); + int (*board_temp_get)(struct nouveau_device *); + int (*fan_sense)(struct nouveau_device *); +// int (*fan_init)(struct nouveau_device *); + int (*fan_pwm_get)(struct nouveau_device *); + int (*fan_rpm_get)(struct nouveau_device *); +}; + +inline u8 nv_rd08(nouveau_device *device, u32 addr) +{ + u8 data = *(volatile u8 *)(device->mmio->getVirtualAddress() + addr); + nv_spam(device, "nv_rd08 0x%06x 0x%02x\n", (unsigned int)addr, data); + return data; +} + +inline u16 nv_rd16(nouveau_device *device, u32 addr) +{ + u16 data = _OSReadInt16((volatile void *)device->mmio->getVirtualAddress(), addr); + nv_spam(device, "nv_rd16 0x%06x 0x%04x\n", (unsigned int)addr, data); + return data; +} + +inline u32 nv_rd32(nouveau_device *device, u32 addr) +{ + u32 data = _OSReadInt32((volatile void *)device->mmio->getVirtualAddress(), addr); + nv_spam(device, "nv_rd32 0x%06x 0x%08x\n", (unsigned int)addr, (unsigned int)data); + return data; +} + +inline void nv_wr08(nouveau_device *device, u32 addr, u8 data) +{ + nv_spam(device, "nv_wr08 0x%06x 0x%02x\n", (unsigned int)addr, data); + *(volatile u8 *)(device->mmio->getVirtualAddress() + addr) = data; +} + +inline void nv_wr16(nouveau_device *device, u32 addr, u16 data) +{ + nv_spam(device, "nv_wr16 0x%06x 0x%04x\n", (unsigned int)addr, data); + _OSWriteInt16((volatile void *)device->mmio->getVirtualAddress(), addr, data); +} + +inline void nv_wr32(nouveau_device *device, u32 addr, u32 data) +{ + nv_spam(device, "nv_wr32 0x%06x 0x%08x\n", (unsigned int)addr, (unsigned int)data); + _OSWriteInt32((volatile void *)device->mmio->getVirtualAddress(), addr, data); +} + +inline u32 nv_mask(nouveau_device *device, u32 addr, u32 mask, u32 data) +{ + u32 temp = nv_rd32(device, addr); + nv_wr32(device, addr, (temp & ~mask) | data); + return temp; +} + +bool nouveau_identify(struct nouveau_device *device); +bool nouveau_init(struct nouveau_device *device); + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_bios.cpp b/plugins/GPUSensors/GeforceSensors/nouveau_bios.cpp new file mode 100755 index 0000000..7948f9e --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_bios.cpp @@ -0,0 +1,604 @@ +// +// nouveau_bios.c +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nouveau_bios.h" + +#include "nouveau_definitions.h" +#include "nouveau.h" + +u8 nv_ro08(struct nouveau_device *device, u32 addr) { + return device->bios.data[addr]; +} + +u16 nv_ro16(struct nouveau_device *device, u32 addr) { + return *(u16 *)&device->bios.data[addr]; +} + +u32 nv_ro32(struct nouveau_device *device, u32 addr) { + return *(u32 *)&device->bios.data[addr]; +} + +void nv_wo08(struct nouveau_device *device, u32 addr, u8 data) { + device->bios.data[addr] = data; +} + +void nv_wo16(struct nouveau_device *device, u32 addr, u16 data) { + *(u16 *)&device->bios.data[addr] = data; +} + +void nv_wo32(struct nouveau_device *device, u32 addr, u32 data) { + *(u16 *)&device->bios.data[addr] = data; +} + +static inline int nv_memcmp(struct nouveau_device *device, u32 addr, const char *str, u32 len) { + unsigned char c1, c2; + + while (len--) { + c1 = nv_ro08(device, addr++); + c2 = *(str++); + if (c1 != c2) { + return c1 - c2; + } + } + return 0; +} + +u16 nouveau_dcb_table(struct nouveau_device *device, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { + u16 dcb = 0x0000; + + if (device->card_type > NV_04) { + dcb = nv_ro16(device, 0x36); + } + + if (!dcb) { + nv_warn(device, "DCB table not found\n"); + return dcb; + } + + *ver = nv_ro08(device, dcb); + + if (*ver >= 0x42) { + nv_warn(device, "DCB *ver 0x%02x unknown\n", *ver); + return 0x0000; + } else if (*ver >= 0x30) { + if (nv_ro32(device, dcb + 6) == 0x4edcbdcb) { + *hdr = nv_ro08(device, dcb + 1); + *cnt = nv_ro08(device, dcb + 2); + *len = nv_ro08(device, dcb + 3); + return dcb; + } + } else if (*ver >= 0x20) { + if (nv_ro32(device, dcb + 4) == 0x4edcbdcb) { + u16 i2c = nv_ro16(device, dcb + 2); + *hdr = 8; + *cnt = (i2c - dcb) / 8; + *len = 8; + return dcb; + } + } else if (*ver >= 0x15) { + if (!nv_memcmp(device, dcb - 7, "DEV_REC", 7)) { + u16 i2c = nv_ro16(device, dcb + 2); + *hdr = 4; + *cnt = (i2c - dcb) / 10; + *len = 10; + return dcb; + } + } else { + /* + * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but + * always has the same single (crt) entry, even when tv-out + * present, so the conclusion is this version cannot really + * be used. + * + * v1.2 tables (some NV6/10, and NV15+) normally have the + * same 5 entries, which are not specific to the card and so + * no use. + * + * v1.2 does have an I2C table that read_dcb_i2c_table can + * handle, but cards exist (nv11 in #14821) with a bad i2c + * table pointer, so use the indices parsed in + * parse_bmp_structure. + * + * v1.1 (NV5+, maybe some NV4) is entirely unhelpful + */ + nv_warn(device, "DCB contains no useful data\n"); + return 0x0000; + } + + nv_warn(device, "DCB header validation failed\n"); + return 0x0000; +} + +static u8 nvbios_checksum(const u8 *data, int size) { + u8 sum = 0; + while (size--) { + sum += *data++; + } + return sum; +} + +static u16 nvbios_findstr(const u8 *data, int size, const char *str, int len) { + int i, j; + + for (i = 0; i <= (size - len); i++) { + for (j = 0; j < len; j++) { + if ((char)data[i + j] != str[j]) { + break; + } + } + + if (j == len) { + return i; + } + } + + return 0; +} + +int nouveau_bios_score(struct nouveau_device *device, const bool writeable) +{ + if (device->bios.size < 3 || !device->bios.data || device->bios.data[0] != 0x55 || device->bios.data[1] != 0xAA) { + nv_debug(device, "VBIOS signature not found\n"); + return 0; + } + + if (nvbios_checksum((u8*)device->bios.data, min_t(u32, device->bios.data[2] * 512, device->bios.size))) { + nv_debug(device, "VBIOS checksum invalid\n"); + /* if a ro image is somewhat bad, it's probably all rubbish */ + return writeable ? 2 : 1; + } + + nv_debug(device, "VBIOS appears to be valid\n"); + return 3; +} + +static void nouveau_bios_shadow_pramin(struct nouveau_device *device) +{ + u32 bar0 = 0; + int i; + + nv_debug(device, "shadowing bios from PRAMIN\n"); + + if (device->card_type >= NV_50) { + u64 addr = (u64)(nv_rd32(device, 0x619f04) & 0xffffff00) << 8; + if (!addr) { + addr = (u64)nv_rd32(device, 0x001700) << 16; + addr += 0xf0000; + } + + bar0 = nv_mask(device, 0x001700, 0xffffffff, (u32)(addr >> 16)); + } + + /* bail if no rom signature */ + if (nv_rd08(device, 0x700000) != 0x55 || + nv_rd08(device, 0x700001) != 0xaa) + goto out; + + device->bios.size = nv_rd08(device, 0x700002) * 512; + device->bios.data = (u8*)IOMalloc(device->bios.size); + + if (device->bios.data) { + for (i = 0; i < device->bios.size; i++) + //device->bios.data[i] = nv_rd08(device, 0x700000 + i); + nv_wo08(device, i, nv_rd08(device, 0x700000 + i)); + } + +out: + if (device->card_type >= NV_50) + nv_wr32(device, 0x001700, bar0); +} + +static void nouveau_bios_shadow_prom(struct nouveau_device *device) +{ + u32 pcireg, access; + u16 pcir; + int i; + + nv_debug(device, "shadowing bios from PROM\n"); + + /* enable access to rom */ + if (device->card_type >= NV_50) + pcireg = 0x088050; + else + pcireg = 0x001850; + access = nv_mask(device, pcireg, 0x00000001, 0x00000000); + + /* bail if no rom signature, with a workaround for a PROM reading + * issue on some chipsets. the first read after a period of + * inactivity returns the wrong result, so retry the first header + * byte a few times before giving up as a workaround + */ + i = 16; + do { + if (nv_rd08(device, 0x300000) == 0x55) + break; + } while (i--); + + if (!i || nv_rd08(device, 0x300001) != 0xaa) + goto out; + + /* additional check (see note below) - read PCI record header */ + pcir = nv_rd08(device, 0x300018) | + nv_rd08(device, 0x300019) << 8; + if (nv_rd08(device, 0x300000 + pcir) != 'P' || + nv_rd08(device, 0x300001 + pcir) != 'C' || + nv_rd08(device, 0x300002 + pcir) != 'I' || + nv_rd08(device, 0x300003 + pcir) != 'R') + goto out; + + /* read entire bios image to system memory */ + device->bios.size = nv_rd08(device, 0x300002) * 512; + device->bios.data = (u8*)IOMalloc(device->bios.size); + if (device->bios.data) { + for (i = 0; i < device->bios.size; i++) + //device->bios.data[i] = nv_rd08(device, 0x300000 + i); + nv_wo08(device, i, nv_rd08(device, 0x300000 + i)); + } + +out: + /* disable access to rom */ + nv_wr32(device, pcireg, access); +} + +void nouveau_vbios_init(struct nouveau_device *device) +{ + device->vbios.data = device->bios.data; + device->vbios.length = device->bios.size; +} + +bool nouveau_bios_shadow(struct nouveau_device *device) +{ + nv_debug(device, "trying to shadow bios\n"); + + nouveau_bios_shadow_pramin(device); + + if (device->bios.data && nouveau_bios_score(device, true) > 1) { + nv_debug(device, "VBIOS successfully read from PRAMIN\n"); + nouveau_vbios_init(device); + return true; + } + + nouveau_bios_shadow_prom(device); + + if (device->bios.data && nouveau_bios_score(device, false) > 1) { + nv_debug(device, "VBIOS successfully read from PROM\n"); + nouveau_vbios_init(device); + return true; + } + + return false; +} + +static inline u16 +bmp_version(struct nouveau_device *device) +{ + if (device->bios.bmp_offset) { + return nv_ro08(device, device->bios.bmp_offset + 5) << 8 | + nv_ro08(device, device->bios.bmp_offset + 6); + } + + return 0x0000; +} + +int nouveau_bit_entry(struct nouveau_device *device, u8 id, struct bit_entry *bit) +{ + if (device->bios.bit_offset) { + u8 entries = nv_ro08(device, device->bios.bit_offset + 10); + u32 entry = device->bios.bit_offset + 12; + while (entries--) { + if (nv_ro08(device, entry + 0) == id) { + bit->id = nv_ro08(device, entry + 0); + bit->version = nv_ro08(device, entry + 1); + bit->length = nv_ro16(device, entry + 2); + bit->offset = nv_ro16(device, entry + 4); + return 0; + } + + entry += nv_ro08(device, device->bios.bit_offset + 9); + } + + return -ENOENT; + } + + return -EINVAL; +} + +struct bit_table { + const char id; + int (* const parse_fn)(struct drm_device *, struct nvbios *, struct bit_entry *); +}; + +#define BIT_TABLE(id, funcid) ((struct bit_table){ id, parse_bit_##funcid##_tbl_entry }) + +int nouveau_bit_table(struct nouveau_device *device, u8 id, struct bit_entry *bit) +{ + struct nvbios *bios = &device->vbios; + u8 entries, *entry; + + if (!bios || !(bios->data) || (bios->type != NVBIOS_BIT)) { + return -ENODEV; + } + + entries = bios->data[bios->offset + 10]; + entry = &bios->data[bios->offset + 12]; + while (entries--) { + if (entry[0] == id) { + bit->id = entry[0]; + bit->version = entry[1]; + bit->length = ROM16(entry[2]); + bit->offset = ROM16(entry[4]); + bit->data = ROMPTR(device, entry[4]); + return 0; + } + + entry += bios->data[bios->offset + 9]; + } + + return -ENOENT; +} + +static bool nouveau_parse_vbios_struct(struct nouveau_device *device) +{ + struct nvbios *bios = &device->vbios; + const uint8_t bit_signature[] = { 0xff, 0xb8, 'B', 'I', 'T' }; + const uint8_t bmp_signature[] = { 0xff, 0x7f, 'N', 'V', 0x0 }; + int offset; + + offset = nvbios_findstr(bios->data, bios->length, (char*)bit_signature, sizeof(bit_signature)); + if (offset) { + //nv_info(device, "BIT BIOS found\n"); + bios->type = NVBIOS_BIT; + bios->offset = offset; + return true; //parse_bit_structure(device, offset + 6); + } + + offset = nvbios_findstr(bios->data, bios->length, (char*)bmp_signature, sizeof(bmp_signature)); + if (offset) { + //nv_info(device, "BMP BIOS found\n"); + bios->type = NVBIOS_BMP; + bios->offset = offset; + return true; //parse_bmp_structure(device, bios, offset); + } + + //nv_error(device, "No known BIOS signature found\n"); + + return false; +} + +void nouveau_bios_parse(struct nouveau_device *device) +{ + struct nouveau_bios *bios = &device->bios; + + if (!bios->data) + return; + + nv_debug(device, "parsing VBIOS\n"); + + /* detect type of vbios we're dealing with */ + bios->bmp_offset = nvbios_findstr((u8*)bios->data, bios->size, + "\xff\x7f""NV\0", 5); + if (bios->bmp_offset) { + nv_info(device, "VBIOS BMP version %x.%x\n", + bmp_version(device) >> 8, + bmp_version(device) & 0xff); + } + + bios->bit_offset = nvbios_findstr((u8*)bios->data, bios->size, + "\xff\xb8""BIT", 5); + if (bios->bit_offset) + nv_debug(device, "VBIOS BIT signature found\n"); + + struct bit_entry bit_i; + + /* determine the vbios version number */ + if (!nouveau_bit_entry(device, 'i', &bit_i) && bit_i.length >= 4) { + bios->version.major = nv_ro08(device, bit_i.offset + 3); + bios->version.chip = nv_ro08(device, bit_i.offset + 2); + bios->version.minor = nv_ro08(device, bit_i.offset + 1); + bios->version.micro = nv_ro08(device, bit_i.offset + 0); + } else + if (bmp_version(device)) { + bios->version.major = nv_ro08(device, bios->bmp_offset + 13); + bios->version.chip = nv_ro08(device, bios->bmp_offset + 12); + bios->version.minor = nv_ro08(device, bios->bmp_offset + 11); + bios->version.micro = nv_ro08(device, bios->bmp_offset + 10); + } + + nv_debug(device, "VBIOS version %02x.%02x.%02x.%02x\n", + bios->version.major, bios->version.chip, + bios->version.minor, bios->version.micro); + + nouveau_parse_vbios_struct(device); +} + +u16 nouveau_dcb_i2c_table(struct nouveau_device *device, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + u16 i2c = 0x0000; + u16 dcb = nouveau_dcb_table(device, ver, hdr, cnt, len); + if (dcb) { + if (*ver >= 0x15) + i2c = nv_ro16(device, dcb + 2); + if (*ver >= 0x30) + i2c = nv_ro16(device, dcb + 4); + } + + if (i2c && *ver >= 0x30) { + *ver = nv_ro08(device, i2c + 0); + *hdr = nv_ro08(device, i2c + 1); + *cnt = nv_ro08(device, i2c + 2); + *len = nv_ro08(device, i2c + 3); + } else { + //*ver = *ver; /* use DCB version */ + *hdr = 0; + *cnt = 16; + *len = 4; + } + + return i2c; +} + +static u16 nouveau_dcb_i2c_entry(struct nouveau_device *device, u8 idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt; + u16 i2c = nouveau_dcb_i2c_table(device, ver, &hdr, &cnt, len); + if (i2c && idx < cnt) + return i2c + hdr + (idx * *len); + return 0x0000; +} + +int nouveau_dcb_i2c_parse(struct nouveau_device *device, u8 idx, struct dcb_i2c_entry *info) +{ + u8 ver, len; + u16 ent = nouveau_dcb_i2c_entry(device, idx, &ver, &len); + if (ent) { + info->data = nv_ro32(device, ent + 0); + info->type = (dcb_i2c_type)nv_ro08(device, ent + 3); + if (ver < 0x30) { + info->type &= 0x07; + if (info->type == 0x07) + info->type = 0xff; + } + + switch (info->type) { + case DCB_I2C_NV04_BIT: + info->drive = nv_ro08(device, ent + 0); + info->sense = nv_ro08(device, ent + 1); + return 0; + case DCB_I2C_NV4E_BIT: + info->drive = nv_ro08(device, ent + 1); + return 0; + case DCB_I2C_NVIO_BIT: + case DCB_I2C_NVIO_AUX: + info->drive = nv_ro08(device, ent + 0); + return 0; + case DCB_I2C_UNUSED: + return 0; + default: + nv_warn(device, "unknown i2c type %d\n", info->type); + info->type = DCB_I2C_UNUSED; + return 0; + } + } + + if (device->bios.bmp_offset && idx < 2) { + /* BMP (from v4.0 has i2c info in the structure, it's in a + * fixed location on earlier VBIOS + */ + if (nv_ro08(device, device->bios.bmp_offset + 5) < 4) + ent = 0x0048; + else + ent = 0x0036 + device->bios.bmp_offset; + + if (idx == 0) { + info->drive = nv_ro08(device, ent + 4); + if (!info->drive) info->drive = 0x3f; + info->sense = nv_ro08(device, ent + 5); + if (!info->sense) info->sense = 0x3e; + } else + if (idx == 1) { + info->drive = nv_ro08(device, ent + 6); + if (!info->drive) info->drive = 0x37; + info->sense = nv_ro08(device, ent + 7); + if (!info->sense) info->sense = 0x36; + } + + info->type = DCB_I2C_NV04_BIT; + return 0; + } + + return -ENOENT; +} + +static u16 extdev_table(struct nouveau_device *device, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) +{ + u8 dcb_ver, dcb_hdr, dcb_cnt, dcb_len; + u16 dcb, extdev = 0; + + dcb = nouveau_dcb_table(device, &dcb_ver, &dcb_hdr, &dcb_cnt, &dcb_len); + if (!dcb || (dcb_ver != 0x30 && dcb_ver != 0x40)) + return 0x0000; + + extdev = nv_ro16(device, dcb + 18); + if (!extdev) + return 0x0000; + + *ver = nv_ro08(device, extdev + 0); + *hdr = nv_ro08(device, extdev + 1); + *cnt = nv_ro08(device, extdev + 2); + *len = nv_ro08(device, extdev + 3); + + return extdev + *hdr; +} + +static u16 nvbios_extdev_entry(struct nouveau_device *device, int idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt; + u16 extdev = extdev_table(device, ver, &hdr, len, &cnt); + if (extdev && idx < cnt) + return extdev + idx * *len; + return 0x0000; +} + +static void extdev_parse_entry(struct nouveau_device *device, u16 offset, struct nvbios_extdev_func *entry) +{ + entry->type = nv_ro08(device, offset + 0); + entry->addr = nv_ro08(device, offset + 1); + entry->bus = (nv_ro08(device, offset + 2) >> 4) & 1; +} + +int nvbios_extdev_parse(struct nouveau_device *device, int idx, struct nvbios_extdev_func *func) +{ + u8 ver, len; + u16 entry; + + if (!(entry = nvbios_extdev_entry(device, idx, &ver, &len))) + return -EINVAL; + + extdev_parse_entry(device, entry, func); + + return 0; +} + +int nvbios_extdev_find(struct nouveau_device *device, enum nvbios_extdev_type type, struct nvbios_extdev_func *func) +{ + u8 ver, len, i; + u16 entry; + + i = 0; + while (!(entry = nvbios_extdev_entry(device, i++, &ver, &len))) { + extdev_parse_entry(device, entry, func); + if (func->type == type) + return 0; + } + + return -EINVAL; +} diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_bios.h b/plugins/GPUSensors/GeforceSensors/nouveau_bios.h new file mode 100755 index 0000000..c7da5d4 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_bios.h @@ -0,0 +1,262 @@ +// +// nouveau_bios.h +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +#ifndef HWSensors_nouveau_bios_h +#define HWSensors_nouveau_bios_h + +#include "nouveau_definitions.h" + +#define DCB_MAX_NUM_ENTRIES 16 +#define DCB_MAX_NUM_I2C_ENTRIES 16 +#define DCB_MAX_NUM_GPIO_ENTRIES 32 +#define DCB_MAX_NUM_CONNECTOR_ENTRIES 16 + +#define DCB_LOC_ON_CHIP 0 + +#define ROM16(x) OSSwapLittleToHostInt16(*(u16 *)&(x)) +#define ROM32(x) OSSwapLittleToHostInt32(*(u32 *)&(x)) +#define ROM48(x) ({ u8 *p = &(x); (u64)ROM16(p[4]) << 32 | ROM32(p[0]); }) +#define ROM64(x) OSSwapLittleToHostInt64(*(u64 *)&(x)) +#define ROMPTR(d,x) ({ \ +ROM16(x) ? &d->vbios.data[ROM16(x)] : NULL; \ +}) + +struct bit_entry { + uint8_t id; + uint8_t version; + uint16_t length; + uint16_t offset; + uint8_t *data; +}; + +struct nouveau_bios_version { + u8 major; + u8 chip; + u8 minor; + u8 micro; +}; + +struct nouveau_bios { + u32 size; + u8 *data; + + u32 bmp_offset; + u32 bit_offset; + + nouveau_bios_version version; +}; + +enum dcb_output_type { + DCB_OUTPUT_ANALOG = 0x0, + DCB_OUTPUT_TV = 0x1, + DCB_OUTPUT_TMDS = 0x2, + DCB_OUTPUT_LVDS = 0x3, + DCB_OUTPUT_DP = 0x6, + DCB_OUTPUT_EOL = 0xe, + DCB_OUTPUT_UNUSED = 0xf, + DCB_OUTPUT_ANY = -1, +}; + +struct sor_conf { + int link; +}; + +struct dcb_output { + int index; /* may not be raw dcb index if merging has happened */ + enum dcb_output_type type; + uint8_t i2c_index; + uint8_t heads; + uint8_t connector; + uint8_t bus; + uint8_t location; + uint8_t or_or; + bool duallink_possible; + union { + struct sor_conf sorconf; + struct { + int maxfreq; + } crtconf; + struct { + struct sor_conf sor; + bool use_straps_for_mode; + bool use_acpi_for_edid; + bool use_power_scripts; + } lvdsconf; + struct { + bool has_component_output; + } tvconf; + struct { + struct sor_conf sor; + int link_nr; + int link_bw; + } dpconf; + struct { + struct sor_conf sor; + int slave_addr; + } tmdsconf; + }; + bool i2c_upper_default; +}; + +struct dcb_table { + uint8_t version; + int entries; + struct dcb_output entry[DCB_MAX_NUM_ENTRIES]; +}; + +enum nvbios_type { + NVBIOS_BMP, + NVBIOS_BIT +}; + +struct nvbios { + enum nvbios_type type; + uint16_t offset; + uint32_t length; + uint8_t *data; + + uint8_t chip_version; + + uint32_t dactestval; + uint32_t tvdactestval; + uint8_t digital_min_front_porch; + bool fp_no_ddc; + + //spinlock_t lock; + + bool execute; + + uint8_t major_version; + uint8_t feature_byte; + bool is_mobile; + + uint32_t fmaxvco, fminvco; + + bool old_style_init; + uint16_t init_script_tbls_ptr; + uint16_t extra_init_script_tbl_ptr; + uint16_t macro_index_tbl_ptr; + uint16_t macro_tbl_ptr; + uint16_t condition_tbl_ptr; + uint16_t io_condition_tbl_ptr; + uint16_t io_flag_condition_tbl_ptr; + uint16_t init_function_tbl_ptr; + + uint16_t pll_limit_tbl_ptr; + uint16_t ram_restrict_tbl_ptr; + uint8_t ram_restrict_group_count; + + uint16_t some_script_ptr; /* BIT I + 14 */ + uint16_t init96_tbl_ptr; /* BIT I + 16 */ + + struct dcb_table dcb; + + struct { + int crtchead; + } state; + + struct { + struct dcb_output *output; + int crtc; + uint16_t script_table_ptr; + } display; + + struct { + uint16_t fptablepointer; /* also used by tmds */ + uint16_t fpxlatetableptr; + int xlatwidth; + uint16_t lvdsmanufacturerpointer; + uint16_t fpxlatemanufacturertableptr; + uint16_t mode_ptr; + uint16_t xlated_entry; + bool power_off_for_reset; + bool reset_after_pclk_change; + bool dual_link; + bool link_c_increment; + bool if_is_24bit; + int duallink_transition_clk; + uint8_t strapless_is_24bit; + uint8_t *edid; + + /* will need resetting after suspend */ + int last_script_invoc; + bool lvds_init_run; + } fp; + + struct { + uint16_t output0_script_ptr; + uint16_t output1_script_ptr; + } tmds; + + struct { + uint16_t mem_init_tbl_ptr; + uint16_t sdr_seq_tbl_ptr; + uint16_t ddr_seq_tbl_ptr; + + struct { + uint8_t crt, tv, panel; + } i2c_indices; + + uint16_t lvds_single_a_script_ptr; + } legacy; +}; + +u8 nv_ro08(struct nouveau_device *device, u32 addr); +u16 nv_ro16(struct nouveau_device *device, u32 addr); +u32 nv_ro32(struct nouveau_device *device, u32 addr); +void nv_wo08(struct nouveau_device *device, u32 addr, u8 data); +void nv_wo16(struct nouveau_device *device, u32 addr, u16 data); +void nv_wo32(struct nouveau_device *device, u32 addr, u32 data); + +u16 nouveau_dcb_table(struct nouveau_device *device, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +int nouveau_bit_entry(struct nouveau_device *device, u8 id, struct bit_entry *bit); +int nouveau_bit_table(struct nouveau_device *, u8 id, struct bit_entry *); + +int nouveau_bios_score(struct nouveau_device *device, const bool writeable); +bool nouveau_bios_shadow(struct nouveau_device *device); +void nouveau_vbios_init(struct nouveau_device *device); +void nouveau_bios_parse(struct nouveau_device *device); + +enum dcb_i2c_type { + DCB_I2C_NV04_BIT = 0, + DCB_I2C_NV4E_BIT = 4, + DCB_I2C_NVIO_BIT = 5, + DCB_I2C_NVIO_AUX = 6, + DCB_I2C_UNUSED = 0xff +}; + +struct dcb_i2c_entry { + u8 type; + u8 drive; + u8 sense; + u32 data; +}; + +u16 nouveau_dcb_i2c_table(struct nouveau_device *device, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +int nouveau_dcb_i2c_parse(struct nouveau_device *device, u8 idx, struct dcb_i2c_entry *info); + +enum nvbios_extdev_type { + NVBIOS_EXTDEV_LM89 = 0x02, + NVBIOS_EXTDEV_VT1103M = 0x40, + NVBIOS_EXTDEV_PX3540 = 0x41, + NVBIOS_EXTDEV_VT1105M = 0x42, /* or close enough... */ + NVBIOS_EXTDEV_ADT7473 = 0x70, /* can also be a LM64 */ + NVBIOS_EXTDEV_HDCP_EEPROM = 0x90, + NVBIOS_EXTDEV_NONE = 0xff, +}; + +struct nvbios_extdev_func { + u8 type; + u8 addr; + u8 bus; +}; + +int nvbios_extdev_parse(struct nouveau_device *, int, struct nvbios_extdev_func *); +int nvbios_extdev_find(struct nouveau_device *, enum nvbios_extdev_type, struct nvbios_extdev_func *); + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_definitions.h b/plugins/GPUSensors/GeforceSensors/nouveau_definitions.h new file mode 100755 index 0000000..263c3a6 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_definitions.h @@ -0,0 +1,28 @@ +// +// nouveau_definitions.h +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +#ifndef HWSensors_nouveau_definitions_h +#define HWSensors_nouveau_definitions_h + +#include "linux_definitions.h" + +//#define NV_DEBUG_ENABLED false +#define NV_TRACE_ENABLED false +#define NV_SPAM_ENABLED false + +#define nv_prefix "GeForceSensors" + +#define nv_fatal(o,f,a...) do { if (1) { IOLog ("%s (%d): [Fatal] " f, nv_prefix, (o)->card_index, ##a); } } while(0) +#define nv_error(o,f,a...) do { if (1) { IOLog ("%s (%d): [Error] " f, nv_prefix, (o)->card_index, ##a); } } while(0) +#define nv_warn(o,f,a...) do { if (1) { IOLog ("%s (%d): [Warning] " f, nv_prefix, (o)->card_index, ##a); } } while(0) +#define nv_info(o,f,a...) do { if (1) { IOLog ("%s (%d): " f, nv_prefix, o->card_index, ##a); } } while(0) +#define nv_debug(o,f,a...) do { if (NV_DEBUG_ENABLED) { IOLog ("%s (%d): [Debug] " f, nv_prefix, (o)->card_index, ##a); } } while(0) +#define nv_trace(o,f,a...) do { if (NV_TRACE_ENABLED) { IOLog ("%s (%d): [Trace] " f, nv_prefix, (o)->card_index, ##a); } } while(0) +#define nv_spam(o,f,a...) do { if (NV_SPAM_ENABLED) { IOLog ("%s (%d): [Spam] " f, nv_prefix, (o)->card_index, ##a); } } while(0) + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_gpio.cpp b/plugins/GPUSensors/GeforceSensors/nouveau_gpio.cpp new file mode 100755 index 0000000..a4ade06 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_gpio.cpp @@ -0,0 +1,205 @@ +// +// nouveau_gpio.cpp +// HWSensors +// +// Created by Kozlek on 10.08.12. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nouveau_gpio.h" +#include "nouveau_xpio.h" +#include "nouveau.h" +#include "nouveau_bios.h" + +u16 dcb_gpio_table(struct nouveau_device *device, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + u16 data = 0x0000; + u16 dcb = nouveau_dcb_table(device, ver, hdr, cnt, len); + if (dcb) { + if (*ver >= 0x30 && *hdr >= 0x0c) + data = nv_ro16(device, dcb + 0x0a); + else + if (*ver >= 0x22 && nv_ro08(device, dcb - 1) >= 0x13) + data = nv_ro16(device, dcb - 0x0f); + + if (data) { + *ver = nv_ro08(device, data + 0x00); + if (*ver < 0x30) { + *hdr = 3; + *cnt = nv_ro08(device, data + 0x02); + *len = nv_ro08(device, data + 0x01); + } else + if (*ver <= 0x41) { + *hdr = nv_ro08(device, data + 0x01); + *cnt = nv_ro08(device, data + 0x02); + *len = nv_ro08(device, data + 0x03); + } else { + data = 0x0000; + } + } + } + return data; +} + +static u16 dcb_gpio_entry(struct nouveau_device *device, int idx, int ent, u8 *ver, u8 *len) +{ + u8 hdr, cnt, xver; /* use gpio version for xpio entry parsing */ + u16 gpio; + + if (!idx--) + gpio = dcb_gpio_table(device, ver, &hdr, &cnt, len); + else + gpio = dcb_xpio_table(device, idx, &xver, &hdr, &cnt, len); + + if (gpio && ent < cnt) + return gpio + hdr + (ent * *len); + return 0x0000; +} + +static u16 dcb_gpio_parse(struct nouveau_device *device, int idx, int ent, u8 *ver, u8 *len, struct dcb_gpio_func *gpio) +{ + u16 data = dcb_gpio_entry(device, idx, ent, ver, len); + if (data) { + if (*ver < 0x40) { + u16 info = nv_ro16(device, data); + // *gpio = (struct dcb_gpio_func) + ((struct dcb_gpio_func *)(gpio))->line = (info & 0x001f) >> 0; + ((struct dcb_gpio_func *)(gpio))->func = (info & 0x07e0) >> 5; + ((struct dcb_gpio_func *)(gpio))->log[0] = (info & 0x1800) >> 11; + ((struct dcb_gpio_func *)(gpio))->log[1] = (info & 0x6000) >> 13; + ((struct dcb_gpio_func *)(gpio))->param = !!(info & 0x8000); + // }; + } else + if (*ver < 0x41) { + u32 info = nv_ro32(device, data); + // *gpio = (struct dcb_gpio_func) { + ((struct dcb_gpio_func *)(gpio))->line = (info & 0x0000001f) >> 0; + ((struct dcb_gpio_func *)(gpio))->func = (info & 0x0000ff00) >> 8; + ((struct dcb_gpio_func *)(gpio))->log[0] = (info & 0x18000000) >> 27; + ((struct dcb_gpio_func *)(gpio))->log[1] = (info & 0x60000000) >> 29; + ((struct dcb_gpio_func *)(gpio))->param = !!(info & 0x80000000); + // }; + } else { + u32 info = nv_ro32(device, data + 0); + u8 info1 = nv_ro32(device, data + 4); + // *gpio = (struct dcb_gpio_func) { + ((struct dcb_gpio_func *)(gpio))->line = (info & 0x0000003f) >> 0; + ((struct dcb_gpio_func *)(gpio))->func = (info & 0x0000ff00) >> 8; + ((struct dcb_gpio_func *)(gpio))->log[0] = (info1 & 0x30) >> 4; + ((struct dcb_gpio_func *)(gpio))->log[1] = (info1 & 0xc0) >> 6; + ((struct dcb_gpio_func *)(gpio))->param = !!(info & 0x80000000); + // }; + } + } + + return data; +} + +static int nouveau_gpio_sense(struct nouveau_device *device, int idx, int line) +{ + if (!device->gpio_sense) { + nv_debug(device, "hardware GPIO sense function not set\n"); + return -EINVAL; + } + + return device->gpio_sense(device, line); +} + +static u16 dcb_gpio_match(struct nouveau_device *device, int idx, u8 func, u8 line, u8 *ver, u8 *len, struct dcb_gpio_func *gpio) +{ + u8 hdr, cnt, i = 0; + u16 data; + + while ((data = dcb_gpio_parse(device, idx, i++, ver, len, gpio))) { + if ((line == 0xff || line == gpio->line) && + (func == 0xff || func == gpio->func)) + return data; + } + + /* DCB 2.2, fixed TVDAC GPIO data */ + if ((data = nouveau_dcb_table(device, ver, &hdr, &cnt, len))) { + if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) { + u8 conf = nv_ro08(device, data - 5); + u8 addr = nv_ro08(device, data - 4); + if (conf & 0x01) { + // *gpio = (struct dcb_gpio_func) { + ((struct dcb_gpio_func *)(gpio))->func = DCB_GPIO_TVDAC0; + ((struct dcb_gpio_func *)(gpio))->line = addr >> 4; + ((struct dcb_gpio_func *)(gpio))->log[0] = !!(conf & 0x02); + ((struct dcb_gpio_func *)(gpio))->log[1] = !(conf & 0x02); + // }; + *ver = 0x00; + return data; + } + } + } + + return 0x0000; +} + +int nouveau_gpio_find(struct nouveau_device *device, int idx, u8 tag, u8 line, struct dcb_gpio_func *func) +{ + u8 ver, len; + u16 data; + + if (line == 0xff && tag == 0xff) + return -EINVAL; + + data = dcb_gpio_match(device, idx, tag, line, &ver, &len, func); + if (data) + return 0; + + // /* Apple iMac G4 NV18 */ + // if (nv_device_match(nv_object(gpio), 0x0189, 0x10de, 0x0010)) { + // if (tag == DCB_GPIO_TVDAC0) { + // *func = (struct dcb_gpio_func) { + // .func = DCB_GPIO_TVDAC0, + // .line = 4, + // .log[0] = 0, + // .log[1] = 1, + // }; + // return 0; + // } + // } + + return -EINVAL; +} + +int nouveau_gpio_get(struct nouveau_device *device, int idx, u8 tag, u8 line) +{ + struct dcb_gpio_func func; + int ret; + + ret = nouveau_gpio_find(device, idx, tag, line, &func); + if (ret == 0) { + ret = nouveau_gpio_sense(device, idx, func.line); + if (ret >= 0) + ret = (ret == (func.log[1] & 1)); + } + + return ret; +} diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_gpio.h b/plugins/GPUSensors/GeforceSensors/nouveau_gpio.h new file mode 100755 index 0000000..8cc96af --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_gpio.h @@ -0,0 +1,49 @@ +// +// nouveau_gpio.h +// HWSensors +// +// Created by Kozlek on 10.08.12. +// +// + +#ifndef __HWSensors__nouveau_gpio__ +#define __HWSensors__nouveau_gpio__ + +#include "nouveau_definitions.h" + +enum dcb_gpio_func_name { + DCB_GPIO_PANEL_POWER = 0x01, + DCB_GPIO_TVDAC0 = 0x0c, + DCB_GPIO_TVDAC1 = 0x2d, + DCB_GPIO_FAN = 0x09, + DCB_GPIO_FAN_SENSE = 0x3d, + DCB_GPIO_UNUSED = 0xff, + DCB_GPIO_VID0 = 0x04, + DCB_GPIO_VID1 = 0x05, + DCB_GPIO_VID2 = 0x06, + DCB_GPIO_VID3 = 0x1a, + DCB_GPIO_VID4 = 0x73, + DCB_GPIO_VID5 = 0x74, + DCB_GPIO_VID6 = 0x75, + DCB_GPIO_VID7 = 0x76, +}; + +struct dcb_gpio_func { + u8 func; + u8 line; + u8 log[2]; + + /* so far, "param" seems to only have an influence on PWM-related + * GPIOs such as FAN_CONTROL and PANEL_BACKLIGHT_LEVEL. + * if param equals 1, hardware PWM is available + * if param equals 0, the host should toggle the GPIO itself + */ + u8 param; +}; + +u16 dcb_gpio_table(struct nouveau_device *device, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); + +int nouveau_gpio_find(struct nouveau_device *device, int idx, u8 tag, u8 line, struct dcb_gpio_func *func); +int nouveau_gpio_get(struct nouveau_device *device, int idx, u8 tag, u8 line); + +#endif /* defined(__HWSensors__nouveau_gpio__) */ diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_i2c._base.cpp b/plugins/GPUSensors/GeforceSensors/nouveau_i2c._base.cpp new file mode 100755 index 0000000..c2abecf --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_i2c._base.cpp @@ -0,0 +1,568 @@ +// +// nouveau_i2c.cpp +// HWSensors +// +// Created by Kozlek on 11.08.12. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nouveau_i2c.h" + +#include "nouveau.h" +#include "vga.h" + +#include "nvclock_i2c.h" + +int nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg) +{ + u8 val; + struct i2c_msg msgs[] = { + { + addr, + 0, + 1, + ® + }, + { + addr, + I2C_M_RD, + 1, + &val + }, + }; + + int ret = i2c_transfer(&port->adapter, msgs, 2); + if (ret != 2) + return -EIO; + + return val; +} + +int nv_wri2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg, u8 val) +{ + struct i2c_msg msgs[] = { + { + addr, + 0, + 1, + ® + }, + { + addr, + 0, + 1, + &val + }, + }; + + int ret = i2c_transfer(&port->adapter, msgs, 2); + if (ret != 2) + return -EIO; + + return 0; +} + +bool nv_probe_i2c(struct nouveau_i2c_port *port, u8 addr) +{ + u8 buf = 0; + struct i2c_msg msgs[] = { + { + addr, + 0, + 1, + &addr, + }, + { + addr, + I2C_M_RD, + 1, + &buf, + } + }; + + return i2c_transfer(&port->adapter, msgs, 2) == 2; +} + +struct nouveau_i2c_port *nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index) +{ + struct nouveau_device *device = i2c->device; + struct nouveau_i2c_port *port; + + if (index == NV_I2C_DEFAULT(0) || + index == NV_I2C_DEFAULT(1)) { + u8 ver, hdr, cnt, len; + u16 dcb = nouveau_dcb_i2c_table(device, &ver, &hdr, &cnt, &len); + if (dcb && ver >= 0x30) { + u8 auxidx = nv_ro08(device, dcb + 4); + if (index != NV_I2C_DEFAULT(0)) + index = (auxidx & 0x0f) >> 0; + else + index = (auxidx & 0xf0) >> 4; + } else { + index = 2; + } + } + + list_for_each_entry(port, &i2c->ports, head) { + if (port->index == index) + break; + } + + if (&port->head == &i2c->ports) + return NULL; + + if (device->card_type >= NV_50 && (port->dcb & 0x00000100)) { + u32 reg = 0x00e500, val; + if (port->type == 6) { + reg += port->drive * 0x50; + val = 0x2002; + } else { + reg += ((port->dcb & 0x1e00) >> 9) * 0x50; + val = 0xe001; + } + + /* nfi, but neither auxch or i2c work if it's 1 */ + nv_mask(device, reg + 0x0c, 0x00000001, 0x00000000); + /* nfi, but switches auxch vs normal i2c */ + nv_mask(device, reg + 0x00, 0x0000f003, val); + } + + return port; +} + +static int nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what, struct i2c_board_info *info, bool (*match)(struct nouveau_i2c_port *, struct i2c_board_info *)) +{ + struct nouveau_device *device = i2c->device; + struct nouveau_i2c_port *port = nouveau_i2c_find(i2c, index); + int i; + + if (!port) { + nv_debug(device, "no bus when probing %s on %d\n", what, index); + return -ENODEV; + } + + nv_debug(device, "probing %ss on bus: %d\n", what, port->index); + +#ifdef CONFIG_NOUVEAU_I2C_NVCLOCK + /* Unlock the extended CRTC registers to get i2c working */ + nvclock_i2c_lock_unlock(device, 0); + + /* On NV40 cards the i2c busses can be disabled */ + if(device->card_type == NV_40) + { + volatile unsigned char *PCIO = (volatile unsigned char*)(device->mmio->getVirtualAddress() + 0x00601000); + PCIO[0x3d4] = 0x49; + PCIO[0x3d5] |= 0x4; /* Unlock the i2c busses */ + } + + I2CBusPtr bus = nvclock_i2c_create_bus_ptr(device, STRDUP(what, (int)strlen(what)), port->drive); +#endif + + for (i = 0; info[i].addr; i++) { + +#ifdef CONFIG_NOUVEAU_I2C_NVCLOCK + info[i].platform_data = (void*)bus; + + if(xf86I2CProbeAddress(bus, info[i].addr << 1) && (!match || match(port, &info[i]))) { +#else + if (nv_probe_i2c(port, info[i].addr) && (!match || match(port, &info[i]))) { +#endif + +#ifdef CONFIG_NOUVEAU_I2C_NVCLOCK + nvclock_i2c_lock_unlock(device, 1); +#endif + nv_info(device, "found i2c %s: %s\n", what, info[i].type); + return i; + } + } + +#ifdef CONFIG_NOUVEAU_I2C_NVCLOCK + nvclock_i2c_lock_unlock(device, 1); + xf86DestroyI2CBusRec(bus, true, true); +#endif + + nv_debug(device, "no i2c devices found.\n"); + + return -ENODEV; + } + + void nouveau_i2c_drive_scl(void *data, int state) + { + struct nouveau_i2c_port *port = (struct nouveau_i2c_port *)data; + + if (port->type == DCB_I2C_NV04_BIT) { + u8 val = nv_rdvgac(port->i2c, 0, port->drive); + if (state) val |= 0x20; + else val &= 0xdf; + nv_wrvgac(port->i2c, 0, port->drive, val | 0x01); + } else if (port->type == DCB_I2C_NV4E_BIT) { + nv_mask(port->i2c->device, port->drive, 0x2f, state ? 0x21 : 0x01); + } else if (port->type == DCB_I2C_NVIO_BIT) { + if (state) port->state |= 0x01; + else port->state &= 0xfe; + nv_wr32(port->i2c->device, port->drive, 4 | port->state); + } + } + + void nouveau_i2c_drive_sda(void *data, int state) + { + struct nouveau_i2c_port *port = (struct nouveau_i2c_port *)data; + + if (port->type == DCB_I2C_NV04_BIT) { + u8 val = nv_rdvgac(port->i2c, 0, port->drive); + if (state) val |= 0x10; + else val &= 0xef; + nv_wrvgac(port->i2c, 0, port->drive, val | 0x01); + } else if (port->type == DCB_I2C_NV4E_BIT) { + nv_mask(port->i2c->device, port->drive, 0x1f, state ? 0x11 : 0x01); + } else if (port->type == DCB_I2C_NVIO_BIT) { + if (state) port->state |= 0x02; + else port->state &= 0xfd; + nv_wr32(port->i2c->device, port->drive, 4 | port->state); + } + } + + int nouveau_i2c_sense_scl(void *data) + { + struct nouveau_i2c_port *port = (struct nouveau_i2c_port *)data; + struct nouveau_device *device = port->i2c->device; + + if (port->type == DCB_I2C_NV04_BIT) { + return !!(nv_rdvgac(device, 0, port->sense) & 0x04); + } else if (port->type == DCB_I2C_NV4E_BIT) { + return !!(nv_rd32(device, port->sense) & 0x00040000); + } else if (port->type == DCB_I2C_NVIO_BIT) { + if (device->card_type < NV_D0) + return !!(nv_rd32(device, port->sense) & 0x01); + else + return !!(nv_rd32(device, port->sense) & 0x10); + } + + return 0; + } + + int nouveau_i2c_sense_sda(void *data) + { + struct nouveau_i2c_port *port = (struct nouveau_i2c_port *)data; + struct nouveau_device *device = port->i2c->device; + + if (port->type == DCB_I2C_NV04_BIT) { + return !!(nv_rdvgac(device, 0, port->sense) & 0x08); + } else if (port->type == DCB_I2C_NV4E_BIT) { + return !!(nv_rd32(device, port->sense) & 0x00080000); + } else if (port->type == DCB_I2C_NVIO_BIT) { + if (device->card_type < NV_D0) + return !!(nv_rd32(device, port->sense) & 0x02); + else + return !!(nv_rd32(device, port->sense) & 0x20); + } + + return 0; + } + + static const u32 nv50_i2c_port[] = { + 0x00e138, 0x00e150, + 0x00e168, 0x00e180, + 0x00e254, 0x00e274, + 0x00e764, 0x00e780, + 0x00e79c, 0x00e7b8 + }; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) + + bool nouveau_i2c_create(struct nouveau_device *device) + { + struct nouveau_i2c_port *port; + struct nouveau_i2c *i2c = &device->i2c; + struct dcb_i2c_entry info; + int ret, i = -1; + + i2c->device = device; + i2c->find = nouveau_i2c_find; + i2c->identify = nouveau_i2c_identify; + + INIT_LIST_HEAD(&i2c->ports); + + nv_debug(device, "parsing i2c dcb table\n"); + + while (!nouveau_dcb_i2c_parse(device, ++i, &info)) { + if (info.type == DCB_I2C_UNUSED) + continue; + + port = (struct nouveau_i2c_port *)IOMalloc(sizeof(nouveau_i2c_port)); + + if (!port) { + nv_error(device, "failed port memory alloc at %d\n", i); + break; + } + + port->type = info.type; + + switch (port->type) { + case DCB_I2C_NV04_BIT: + port->drive = info.drive; + port->sense = info.sense; + break; + case DCB_I2C_NV4E_BIT: + port->drive = 0x600800 + info.drive; + port->sense = port->drive; + break; + case DCB_I2C_NVIO_BIT: + port->drive = info.drive & 0x0f; + if (device->card_type < NV_D0) { + if (port->drive >= ARRAY_SIZE(nv50_i2c_port)) + break; + port->drive = nv50_i2c_port[port->drive]; + port->sense = port->drive; + } else { + port->drive = 0x00d014 + (port->drive * 0x20); + port->sense = port->drive; + } + break; + case DCB_I2C_NVIO_AUX: + port->drive = info.drive & 0x0f; + port->sense = port->drive; + port->adapter.algo = &nouveau_i2c_aux_algo; + break; + default: + break; + } + + if (!port->adapter.algo && !port->drive) { + nv_error(device, "I2C%d: type %d index %x/%x unknown\n", + i, port->type, (unsigned int)port->drive, (unsigned int)port->sense); + IOFree(port, sizeof(struct nouveau_i2c_port)); + continue; + } + + snprintf(port->adapter.name, sizeof(port->adapter.name), + "nouveau-%d-%x-%x-%x-%d", port->type, (unsigned int)info.drive, (unsigned int)port->drive, (unsigned int)port->sense, i); + + //port->adapter.owner = this; + //port->adapter.dev.parent = &device->pdev->dev; + port->i2c = i2c; + port->index = i; + port->dcb = info.data; + //i2c_set_adapdata(&port->adapter, i2c); + + if (port->adapter.algo != &nouveau_i2c_aux_algo) { + nouveau_i2c_drive_scl(port, 0); + nouveau_i2c_drive_sda(port, 1); + nouveau_i2c_drive_scl(port, 1); + + if (CONFIG_NOUVEAU_I2C_INTERNAL) { + port->adapter.algo = &nouveau_i2c_bit_algo; + ret = 0; //i2c_add_adapter(&port->adapter); + } else { + port->adapter.algo_data = &port->bit; + port->bit.udelay = 10; + port->bit.timeout = 2200; + port->bit.data = port; + port->bit.setsda = nouveau_i2c_drive_sda; + port->bit.setscl = nouveau_i2c_drive_scl; + port->bit.getsda = nouveau_i2c_sense_sda; + port->bit.getscl = nouveau_i2c_sense_scl; + ret = i2c_bit_add_bus(&port->adapter); + } + } else { + port->adapter.algo = &nouveau_i2c_aux_algo; + ret = 0; //i2c_add_adapter(&port->adapter); + } + + if (ret) { + nv_error(device, "I2C%d: failed register: %d\n", i, ret); + IOFree(port, sizeof(struct nouveau_i2c_port)); + continue; + } + + nv_debug(device, "adding i2c port %s\n", port->adapter.name); + + list_add_tail(&port->head, &i2c->ports); + } + + return 0; + } + + static bool probe_monitoring_device(struct nouveau_i2c_port *i2c, struct i2c_board_info *info) + { +#if CONFIG_NOUVEAU_I2C_NVCLOCK + nouveau_device *device = i2c->i2c->device; + + I2CBusPtr bus = (I2CBusPtr)info->platform_data; + I2CSlaveAddr addr = info->addr << 1; + + I2CDevPtr dev = nvclock_i2c_probe_device(bus, addr, "%1i:%02X", bus, addr); + + if (dev) { + if (!strncmp(info->type, "w83l785ts", sizeof("w83l785ts"))) { + if(!w83l785r_detect(dev)) return false; + } + else if (!strncmp(info->type, "w83781d", sizeof("w83781d"))) { + if(!w83781d_detect(dev)) return false; + } + else if (!strncmp(info->type, "adt7473", sizeof("adt7473"))) { + if(!adt7473_detect(dev)) return false; + } + else if (!strncmp(info->type, "f75375", sizeof("f75375"))) { + if(!f75375_detect(dev)) return false; + } + else if (!strncmp(info->type, "lm99", sizeof("lm99")) || + !strncmp(info->type, "lm90", sizeof("lm90")) || + !strncmp(info->type, "lm63", sizeof("lm63"))) { + if(!lm99_detect(dev)) return false; + } + + + device->nvclock_i2c_sensor = dev; + + nv_debug(device, "found device: %s\n", device->nvclock_i2c_sensor->chip_name); + + switch(device->nvclock_i2c_sensor->chip_id) + { + case LM99: + case MAX6559: + device->board_temp_get = lm99_get_board_temp; + device->core_temp_get = lm99_get_gpu_temp; + break; + case F75375: + device->board_temp_get = f75375_get_board_temp; + device->core_temp_get = f75375_get_gpu_temp; + device->fan_rpm_get = f75375_get_fanspeed_rpm; + device->fan_pwm_get = f75375_get_fanspeed_pwm; + break; + case W83781D: + device->board_temp_get = w83781d_get_board_temp; + device->core_temp_get = w83781d_get_gpu_temp; + device->fan_rpm_get = w83781d_get_fanspeed_rpm; + //device->get_i2c_fanspeed_pwm = w83781d_get_fanspeed_pwm; + break; + case W83L785R: + device->board_temp_get = w83l785r_get_board_temp; + device->core_temp_get = w83l785r_get_gpu_temp; + device->fan_rpm_get = w83l785r_get_fanspeed_rpm; + device->fan_pwm_get = w83l785r_get_fanspeed_pwm; + break; + case ADT7473: + device->board_temp_get = adt7473_get_board_temp; + device->core_temp_get = adt7473_get_gpu_temp; + device->fan_rpm_get = adt7473_get_fanspeed_rpm; + device->fan_pwm_get = adt7473_get_fanspeed_pwm; + break; + default: + break; + } + } + return true; +#else + struct i2c_client *client; + + request_module("%s%s", I2C_MODULE_PREFIX, info->type); + + client = i2c_new_device(&i2c->adapter, info); + if (!client) + return false; + + if (!client->driver || client->driver->detect(client, info)) { + i2c_unregister_device(client); + return false; + } + + return true; +#endif + } + +#define I2C_BOARD_INFO(dev_type, dev_addr) \ +dev_type, 0, dev_addr, 0, 0 + + void nouveau_i2c_probe(struct nouveau_device *device) + { + struct nouveau_i2c *i2c = &device->i2c; + struct nvbios_extdev_func extdev_entry; + + struct i2c_board_info info[] = { + { I2C_BOARD_INFO("w83l785ts", 0x2d) }, + { I2C_BOARD_INFO("w83781d", 0x2d) }, + { I2C_BOARD_INFO("adt7473", 0x2e) }, + { I2C_BOARD_INFO("adt7473", 0x2d) }, + { I2C_BOARD_INFO("adt7473", 0x2c) }, + { I2C_BOARD_INFO("f75375", 0x2e) }, + { I2C_BOARD_INFO("lm99", 0x4c) }, + { I2C_BOARD_INFO("lm90", 0x4c) }, + { I2C_BOARD_INFO("lm90", 0x4d) }, + { I2C_BOARD_INFO("adm1021", 0x18) }, + { I2C_BOARD_INFO("adm1021", 0x19) }, + { I2C_BOARD_INFO("adm1021", 0x1a) }, + { I2C_BOARD_INFO("adm1021", 0x29) }, + { I2C_BOARD_INFO("adm1021", 0x2a) }, + { I2C_BOARD_INFO("adm1021", 0x2b) }, + { I2C_BOARD_INFO("adm1021", 0x4c) }, + { I2C_BOARD_INFO("adm1021", 0x4d) }, + { I2C_BOARD_INFO("adm1021", 0x4e) }, + { I2C_BOARD_INFO("lm63", 0x18) }, + { I2C_BOARD_INFO("lm63", 0x4e) }, + { } + }; + + if (!nvbios_extdev_find(device, NVBIOS_EXTDEV_LM89, &extdev_entry)) { + struct i2c_board_info board[] = { + { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, + { } + }; + + if(i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", board, probe_monitoring_device) >= 0) + return; + } + + if (!nvbios_extdev_find(device, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) { + struct i2c_board_info board[] = { + { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, + { } + }; + + if(i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",board, probe_monitoring_device) >= 0) + return; + } + + /* The vbios doesn't provide the address of an exisiting monitoring + device. Let's try our static list. + */ + if (i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", info, probe_monitoring_device) < 0) + i2c->identify(i2c, NV_I2C_DEFAULT(1), "monitoring device", info, probe_monitoring_device); + + // struct i2c_board_info info[] = { + // { "w83l785ts", 0x0, 0x2d, NULL, 0 }, + // { "w83781d", 0x0, 0x2d, NULL, 0 }, + // { "adt7473", 0x0, 0x2e, NULL, 0 }, + // { "f75375", 0x0, 0x2e, NULL, 0 }, + // { "lm99", 0x0, 0x4c, NULL, 0 }, + // { } + // }; + // + // i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", info, probe_monitoring_device); + // i2c->identify(i2c, NV_I2C_DEFAULT(1), "monitoring device", info, probe_monitoring_device); + } + diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_i2c.h b/plugins/GPUSensors/GeforceSensors/nouveau_i2c.h new file mode 100755 index 0000000..aea5c5b --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_i2c.h @@ -0,0 +1,68 @@ +// +// nouveau_i2c.h +// HWSensors +// +// Created by Kozlek on 11.08.12. +// +// + +#ifndef __HWSensors__nouveau_i2c__ +#define __HWSensors__nouveau_i2c__ + +#include "nouveau_definitions.h" +#include "i2c_algo_bit.h" +#include "list.h" + +#define CONFIG_NOUVEAU_I2C_INTERNAL TRUE +#define CONFIG_NOUVEAU_I2C_NVCLOCK TRUE + +#define NV_I2C_PORT(n) (0x00 + (n)) +#define NV_I2C_DEFAULT(n) (0x80 + (n)) + +struct nouveau_i2c; + +struct nouveau_i2c_port { + struct i2c_adapter adapter; + struct nouveau_i2c *i2c; + struct i2c_algo_bit_data bit; + struct list_head head; + u8 index; + u8 type; + u32 dcb; + u32 drive; + u32 sense; + u32 state; +}; + +struct nouveau_i2c { + struct nouveau_device *device; + + struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); + int (*identify)(struct nouveau_i2c *, int index, + const char *what, struct i2c_board_info *, + bool (*match)(struct nouveau_i2c_port *, + struct i2c_board_info *)); + struct list_head ports; +}; + +struct nouveau_i2c_port *nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index); + +void nouveau_i2c_drive_scl(void *, int); +void nouveau_i2c_drive_sda(void *, int); +int nouveau_i2c_sense_scl(void *); +int nouveau_i2c_sense_sda(void *); + +int nv_rdi2cr(struct nouveau_i2c_port *, u8 addr, u8 reg); +int nv_wri2cr(struct nouveau_i2c_port *, u8 addr, u8 reg, u8 val); +bool nv_probe_i2c(struct nouveau_i2c_port *, u8 addr); + +int nv_rdaux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size); +int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size); + +extern const struct i2c_algorithm nouveau_i2c_bit_algo; +extern const struct i2c_algorithm nouveau_i2c_aux_algo; + +bool nouveau_i2c_create(struct nouveau_device *device); +void nouveau_i2c_probe(struct nouveau_device *device); + +#endif /* defined(__HWSensors__nouveau_i2c__) */ diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_i2c_aux.cpp b/plugins/GPUSensors/GeforceSensors/nouveau_i2c_aux.cpp new file mode 100755 index 0000000..92ee2a7 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_i2c_aux.cpp @@ -0,0 +1,218 @@ +// +// nouveau_i2c_aux.cpp +// HWSensors +// +// Created by Kozlek on 13.08.12. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nouveau_i2c.h" +#include "nouveau.h" + +/****************************************************************************** + * aux channel util functions + *****************************************************************************/ +#define AUX_DBG(fmt, args...) nv_debug(aux->device, "AUXCH(%d): " fmt, ch, ##args) +#define AUX_ERR(fmt, args...) nv_error(aux->device, "AUXCH(%d): " fmt, ch, ##args) + +static void +auxch_fini(struct nouveau_i2c *aux, int ch) +{ + nv_mask(aux->device, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); +} + +static int +auxch_init(struct nouveau_i2c *aux, int ch) +{ + const u32 unksel = 1; /* nfi which to use, or if it matters.. */ + const u32 ureq = unksel ? 0x00100000 : 0x00200000; + const u32 urep = unksel ? 0x01000000 : 0x02000000; + u32 ctrl, timeout; + + /* wait up to 1ms for any previous transaction to be done... */ + timeout = 1000; + do { + ctrl = nv_rd32(aux->device, 0x00e4e4 + (ch * 0x50)); + IODelay(1); + if (!timeout--) { + nv_error(aux->device, "begin idle timeout 0x%08x", (unsigned int)ctrl); + return -EBUSY; + } + } while (ctrl & 0x03010000); + + /* set some magic, and wait up to 1ms for it to appear */ + nv_mask(aux->device, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); + timeout = 1000; + do { + ctrl = nv_rd32(aux->device, 0x00e4e4 + (ch * 0x50)); + IODelay(1); + if (!timeout--) { + nv_error(aux->device, "magic wait 0x%08x\n", (unsigned int)ctrl); + auxch_fini(aux, ch); + return -EBUSY; + } + } while ((ctrl & 0x03000000) != urep); + + return 0; +} + +static int +auxch_tx(struct nouveau_i2c *aux, int ch, u8 type, u32 addr, u8 *data, u8 size) +{ + u32 ctrl, stat, timeout, retries; + u32 xbuf[4] = {}; + int ret, i; + + nv_debug(aux->device, "%d: 0x%08x %d\n", type, (unsigned int)addr, size); + + ret = auxch_init(aux, ch); + if (ret) + goto out; + + stat = nv_rd32(aux->device, 0x00e4e8 + (ch * 0x50)); + if (!(stat & 0x10000000)) { + nv_debug(aux->device, "sink not detected\n"); + ret = -ENXIO; + goto out; + } + + if (!(type & 1)) { + memcpy(xbuf, data, size); + for (i = 0; i < 16; i += 4) { + nv_debug(aux->device, "wr 0x%08x\n", (unsigned int)xbuf[i / 4]); + nv_wr32(aux->device, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); + } + } + + ctrl = nv_rd32(aux->device, 0x00e4e4 + (ch * 0x50)); + ctrl &= ~0x0001f0ff; + ctrl |= type << 12; + ctrl |= size - 1; + nv_wr32(aux->device, 0x00e4e0 + (ch * 0x50), addr); + + /* retry transaction a number of times on failure... */ + ret = -EREMOTEIO; + for (retries = 0; retries < 32; retries++) { + /* reset, and delay a while if this is a retry */ + nv_wr32(aux->device, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); + nv_wr32(aux->device, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); + if (retries) + IODelay(400); + + /* transaction request, wait up to 1ms for it to complete */ + nv_wr32(aux->device, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); + + timeout = 1000; + do { + ctrl = nv_rd32(aux->device, 0x00e4e4 + (ch * 0x50)); + IODelay(1); + if (!timeout--) { + nv_error(aux->device, "tx req timeout 0x%08x\n", (unsigned int)ctrl); + goto out; + } + } while (ctrl & 0x00010000); + + /* read status, and check if transaction completed ok */ + stat = nv_mask(aux->device, 0x00e4e8 + (ch * 0x50), 0, 0); + if (!(stat & 0x000f0f00)) { + ret = 0; + break; + } + + nv_debug(aux->device, "%02d 0x%08x 0x%08x\n", (int)retries, (unsigned int)ctrl, (unsigned int)stat); + } + + if (type & 1) { + for (i = 0; i < 16; i += 4) { + xbuf[i / 4] = nv_rd32(aux->device, 0x00e4d0 + (ch * 0x50) + i); + nv_debug(aux->device, "rd 0x%08x\n", (unsigned int)xbuf[i / 4]); + } + memcpy(data, xbuf, size); + } + +out: + auxch_fini(aux, ch); + return ret; +} + +int +nv_rdaux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size) +{ + return auxch_tx(auxch->i2c, auxch->drive, 9, addr, data, size); +} + +int +nv_wraux(struct nouveau_i2c_port *auxch, u32 addr, u8 *data, u8 size) +{ + return auxch_tx(auxch->i2c, auxch->drive, 8, addr, data, size); +} + +static int +aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct nouveau_i2c_port *auxch = (struct nouveau_i2c_port *)adap; + struct i2c_msg *msg = msgs; + int ret, mcnt = num; + + while (mcnt--) { + u8 remaining = msg->len; + u8 *ptr = msg->buf; + + while (remaining) { + u8 cnt = (remaining > 16) ? 16 : remaining; + u8 cmd; + + if (msg->flags & I2C_M_RD) + cmd = 1; + else + cmd = 0; + + if (mcnt || remaining > 16) + cmd |= 4; /* MOT */ + + ret = auxch_tx(auxch->i2c, auxch->drive, cmd, + msg->addr, ptr, cnt); + if (ret < 0) + return ret; + + ptr += cnt; + remaining -= cnt; + } + + msg++; + } + + return num; +} + +static u32 +aux_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +const struct i2c_algorithm nouveau_i2c_aux_algo = {aux_xfer, NULL, aux_func}; diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_i2c_bit.cpp b/plugins/GPUSensors/GeforceSensors/nouveau_i2c_bit.cpp new file mode 100755 index 0000000..7238fe6 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_i2c_bit.cpp @@ -0,0 +1,253 @@ +// +// nouveau_i2c_bit.cpp +// HWSensors +// +// Created by Kozlek on 13.08.12. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nouveau_i2c.h" +#include "nouveau.h" + +#ifdef CONFIG_NOUVEAU_I2C_INTERNAL +#define T_TIMEOUT 2200000 +#define T_RISEFALL 2000 +#define T_HOLD 10000 + +static inline void +i2c_drive_scl(struct nouveau_i2c_port *port, int state) +{ + nouveau_i2c_drive_scl(port, state); +} + +static inline void +i2c_drive_sda(struct nouveau_i2c_port *port, int state) +{ + nouveau_i2c_drive_sda(port, state); +} + +static inline int +i2c_sense_scl(struct nouveau_i2c_port *port) +{ + return nouveau_i2c_sense_scl(port); +} + +static inline int +i2c_sense_sda(struct nouveau_i2c_port *port) +{ + return nouveau_i2c_sense_sda(port); +} + +static void +i2c_delay(struct nouveau_i2c_port *port, u32 nsec) +{ + //IODelay((nsec + 500) / 1000); + IOPause(nsec + 500); +} + +static bool +i2c_raise_scl(struct nouveau_i2c_port *port) +{ + u32 timeout = T_TIMEOUT / T_RISEFALL; + + i2c_drive_scl(port, 1); + do { + i2c_delay(port, T_RISEFALL); + } while (!i2c_sense_scl(port) && --timeout); + + return timeout != 0; +} + +static int +i2c_start(struct nouveau_i2c_port *port) +{ + int ret = 0; + + port->state = i2c_sense_scl(port); + port->state |= i2c_sense_sda(port) << 1; + if (port->state != 3) { + i2c_drive_scl(port, 0); + i2c_drive_sda(port, 1); + if (!i2c_raise_scl(port)) + ret = -EBUSY; + } + + i2c_drive_sda(port, 0); + i2c_delay(port, T_HOLD); + i2c_drive_scl(port, 0); + i2c_delay(port, T_HOLD); + + nv_trace(port->i2c->device, "i2c_start=%d\n", ret); + + return ret; +} + +static void +i2c_stop(struct nouveau_i2c_port *port) +{ + i2c_drive_scl(port, 0); + i2c_drive_sda(port, 0); + i2c_delay(port, T_RISEFALL); + + i2c_drive_scl(port, 1); + i2c_delay(port, T_HOLD); + i2c_drive_sda(port, 1); + i2c_delay(port, T_HOLD); +} + +static int +i2c_bitw(struct nouveau_i2c_port *port, int sda) +{ + i2c_drive_sda(port, sda); + i2c_delay(port, T_RISEFALL); + + if (!i2c_raise_scl(port)) { + nv_trace(port->i2c->device, "i2c_bitw timed out\n"); + return -ETIMEDOUT; + } + + i2c_delay(port, T_HOLD); + + i2c_drive_scl(port, 0); + i2c_delay(port, T_HOLD); + return 0; +} + +static int +i2c_bitr(struct nouveau_i2c_port *port) +{ + int sda; + + i2c_drive_sda(port, 1); + i2c_delay(port, T_RISEFALL); + + if (!i2c_raise_scl(port)) { + nv_trace(port->i2c->device, "i2c_bitr timed out\n"); + return -ETIMEDOUT; + } + i2c_delay(port, T_HOLD); + + sda = i2c_sense_sda(port); + + i2c_drive_scl(port, 0); + i2c_delay(port, T_HOLD); + return sda; +} + +static int +i2c_get_byte(struct nouveau_i2c_port *port, u8 *byte, bool last) +{ + int ret; + + *byte = 0; + for (int i = 7; i >= 0; i--) { + int bit = i2c_bitr(port); + if (bit < 0) + return bit; + *byte |= bit << i; + } + + ret = i2c_bitw(port, last ? 1 : 0); + + nv_trace(port->i2c->device, "i2c_get_byte=%d\n", ret); + + return ret; +} + +static int +i2c_put_byte(struct nouveau_i2c_port *port, u8 byte) +{ + int i, ret; + for (i = 7; i >= 0; i--) { + ret = i2c_bitw(port, !!(byte & (1 << i))); + if (ret < 0) + return ret; + } + + ret = i2c_bitr(port); + if (ret == 1) /* nack */ + ret = -EIO; + + nv_trace(port->i2c->device, "i2c_put_byte=%d\n", ret); + + return ret; +} + +static int +i2c_addr(struct nouveau_i2c_port *port, struct i2c_msg *msg) +{ + u32 addr = msg->addr << 1; + if (msg->flags & I2C_M_RD) + addr |= 1; + return i2c_put_byte(port, addr); +} + +static int +i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct nouveau_i2c_port *port = (struct nouveau_i2c_port *)adap; + struct i2c_msg *msg = msgs; + int ret = 0, mcnt = num; + + while (!ret && mcnt--) { + u8 remaining = msg->len; + u8 *ptr = msg->buf; + + ret = i2c_start(port); + + if (ret == 0) + ret = i2c_addr(port, msg); + + if (msg->flags & I2C_M_RD) { + while (!ret && remaining--) + ret = i2c_get_byte(port, ptr++, !remaining); + } else { + while (!ret && remaining--) + ret = i2c_put_byte(port, *ptr++); + } + + msg++; + } + + i2c_stop(port); + return (ret < 0) ? ret : num; +} +#else +static int +i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + return -ENODEV; +} +#endif + +static u32 +i2c_bit_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +const struct i2c_algorithm nouveau_i2c_bit_algo = {i2c_bit_xfer, NULL, i2c_bit_func}; diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_therm.cpp b/plugins/GPUSensors/GeforceSensors/nouveau_therm.cpp new file mode 100755 index 0000000..363ac78 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_therm.cpp @@ -0,0 +1,240 @@ +// +// nouveau_temp.c +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +/* + * Copyright 2010 PathScale inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Martin Peres + */ + +#include "nouveau.h" +#include "nouveau_bios.h" + +#include "nouveau_therm.h" + +#include "timer.h" + +static u16 therm_table(struct nouveau_device *device, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) +{ + struct bit_entry bit_P; + u16 therm = 0; + + if (!nouveau_bit_entry(device, 'P', &bit_P)) { + if (bit_P.version == 1) + therm = nv_ro16(device, bit_P.offset + 12); + else if (bit_P.version == 2) + therm = nv_ro16(device, bit_P.offset + 16); + else + nv_error(device, + "unknown offset for thermal in BIT P %d\n", + bit_P.version); + } + + /* exit now if we haven't found the thermal table */ + if (!therm) + return 0x0000; + + *ver = nv_ro08(device, therm + 0); + *hdr = nv_ro08(device, therm + 1); + *len = nv_ro08(device, therm + 2); + *cnt = nv_ro08(device, therm + 3); + + return therm + nv_ro08(device, therm + 1); +} + +static u16 nvbios_therm_entry(struct nouveau_device *device, int idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt; + u16 therm = therm_table(device, ver, &hdr, len, &cnt); + + if (therm && idx < cnt) + return therm + idx * *len; + + return 0x0000; +} + +static int nvbios_therm_sensor_parse(struct nouveau_device *device, nvbios_therm_sensor *sensor) +{ +// s8 thrs_section, + s8 sensor_section, offset; + u8 ver, len, i; + u16 entry; + + + /* Read the entries from the table */ +// thrs_section = 0; + sensor_section = -1; + i = 0; + while ((entry = nvbios_therm_entry(device, i++, &ver, &len))) { + s16 value = nv_ro16(device, entry + 1); + + switch (nv_ro08(device, entry + 0)) { + case 0x0: +// thrs_section = value; + if (value > 0) + return 0; /* we do not try to support ambient */ + break; + case 0x01: + sensor_section++; + if (sensor_section == 0) { + offset = ((s8) nv_ro08(device, entry + 2)) / 2; + sensor->offset_constant = offset; + } + break; + + case 0x04: + // if (thrs_section == 0) { + // sensor->thrs_critical.temp = (value & 0xff0) >> 4; + // sensor->thrs_critical.hysteresis = value & 0xf; + // } + break; + + case 0x07: + // if (thrs_section == 0) { + // sensor->thrs_down_clock.temp = (value & 0xff0) >> 4; + // sensor->thrs_down_clock.hysteresis = value & 0xf; + // } + break; + + case 0x08: + // if (thrs_section == 0) { + // sensor->thrs_fan_boost.temp = (value & 0xff0) >> 4; + // sensor->thrs_fan_boost.hysteresis = value & 0xf; + // } + break; + + case 0x10: + if (sensor_section == 0) + sensor->offset_num = value; + break; + + case 0x11: + if (sensor_section == 0) + sensor->offset_den = value; + break; + + case 0x12: + if (sensor_section == 0) + sensor->slope_mult = value; + break; + + case 0x13: + if (sensor_section == 0) + sensor->slope_div = value; + break; + case 0x32: + // if (thrs_section == 0) { + // sensor->thrs_shutdown.temp = (value & 0xff0) >> 4; + // sensor->thrs_shutdown.hysteresis = value & 0xf; + // } + break; + } + } + + return 0; +} + +void nouveau_therm_init(struct nouveau_device *device) +{ + nouveau_pm_temp_sensor_constants *sensor = &device->sensor_constants; + nvbios_therm_sensor bios_sensor; + + /* store some safe defaults */ + sensor->offset_constant = 0; + sensor->offset_num = 0; + sensor->offset_den = 1; + sensor->slope_mult = 1; + sensor->slope_div = 1; + + if (!nvbios_therm_sensor_parse(device, &bios_sensor)) { + sensor->slope_mult = bios_sensor.slope_mult; + sensor->slope_div = bios_sensor.slope_div; + sensor->offset_num = bios_sensor.offset_num; + sensor->offset_den = bios_sensor.offset_den; + sensor->offset_constant = bios_sensor.offset_constant; + } +} + +int nouveau_therm_fan_pwm_get(struct nouveau_device *device) +{ + u32 divs, duty; + + if (device->fan_pwm.func != DCB_GPIO_UNUSED) { + int ret = device->pwm_get(device, device->fan_pwm.line, &divs, &duty); + if (ret == 0 && divs) { + divs = max(divs, duty); + if (device->card_type <= NV_40 || (device->fan_pwm.log[0] & 1)) + duty = divs - duty; + return (duty * 100) / divs; + } + + //return device->gpio_get(device, 0, device->fan_pwm.func, device->fan_pwm.line) * 100; + } + + return 0; +} + +#define THERM_FAN_SENSE_CYCLES 8 + +int nouveau_therm_fan_rpm_get(struct nouveau_device *device) +{ + u32 cycles, cur, prev, stop = THERM_FAN_SENSE_CYCLES * 4 + 1; + u64 start, interval; + + if (device->fan_tach.func != DCB_GPIO_UNUSED) { + /* Time a complete rotation and extrapolate to RPM: + * When the fan spins, it changes the value of GPIO FAN_SENSE. + * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation. + */ + start = ptimer_read(); + + prev = device->gpio_get(device, 0, device->fan_tach.func, device->fan_tach.line); + cycles = 0; + do { + IODelay(750); /* supports 0 < rpm < 7500 */ + + cur = device->gpio_get(device, 0, device->fan_tach.func, device->fan_tach.line); + if (prev != cur) { + if (!start) + start = ptimer_read(); + cycles++; + prev = cur; + } + + interval = ptimer_read() - start; + + } while (cycles < stop && interval < 500000000); + + if (interval) { + return (u32)(((u64)60000000000LL * (((u64)cycles - 1) / 4)) / interval); + } else + return 0; + } + + nv_debug(device, "DCB_GPIO_FAN_SENSE func not found\n"); + + return 0; +} diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_therm.h b/plugins/GPUSensors/GeforceSensors/nouveau_therm.h new file mode 100755 index 0000000..3d615b6 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_therm.h @@ -0,0 +1,30 @@ +// +// nouveau_temp.h +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +#ifndef HWSensors_nouveau_temp_h +#define HWSensors_nouveau_temp_h + +#include "linux_definitions.h" + +struct nvbios_therm_sensor { + /* diode */ + s16 slope_mult; + s16 slope_div; + s16 offset_num; + s16 offset_den; + s8 offset_constant; +}; + +void nouveau_therm_init(struct nouveau_device *device); +int nouveau_therm_fan_pwm_get(struct nouveau_device *device); +int nouveau_therm_fan_rpm_get(struct nouveau_device *device); + +int nouveau_fan_pwm_get(struct nouveau_device *device); +int nouveau_fan_rpm_get(struct nouveau_device *device); + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_volt.cpp b/plugins/GPUSensors/GeforceSensors/nouveau_volt.cpp new file mode 100755 index 0000000..8259e53 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_volt.cpp @@ -0,0 +1,205 @@ +// +// nouveau_volt.c +// HWSensors +// +// Created by Kozlek on 10.08.12. +// +// + +/* + * Copyright 2010 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nouveau_volt.h" +#include "nouveau.h" + +static const u8 vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 }; +static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]); + +void nouveau_volt_init(struct nouveau_device *device) +{ + struct dcb_gpio_func func; + struct bit_entry P; + u8 *volt = NULL, *entry; + int i, headerlen, recordlen, entries, vidmask, vidshift; + + if (!(device->vbios.data)) { + volt = 0; + } else if (device->vbios.type == NVBIOS_BIT) { + if (nouveau_bit_table(device, 'P', &P)) + return; + + if (P.version == 1) + volt = ROMPTR(device, P.data[16]); + else + if (P.version == 2) + volt = ROMPTR(device, P.data[12]); + else { + nv_warn(device, "unknown volt for BIT P %d\n", P.version); + } + } else { + if (device->vbios.data[device->vbios.offset + 6] < 0x27) { + nv_debug(device, "BMP version too old for voltage\n"); + return; + } + volt = ROMPTR(device, device->vbios.data[device->vbios.offset + 0x98]); + } + + if (!volt) { + nv_debug(device, "voltage table pointer invalid\n"); + return; + } + + switch (volt[0]) { + case 0x10: + case 0x11: + case 0x12: + headerlen = 5; + recordlen = volt[1]; + entries = volt[2]; + vidshift = 0; + vidmask = volt[4]; + break; + case 0x20: + headerlen = volt[1]; + recordlen = volt[3]; + entries = volt[2]; + vidshift = 0; /* could be vidshift like 0x30? */ + vidmask = volt[5]; + break; + case 0x30: + headerlen = volt[1]; + recordlen = volt[2]; + entries = volt[3]; + vidmask = volt[4]; + /* no longer certain what volt[5] is, if it's related to + * the vid shift then it's definitely not a function of + * how many bits are set. + * + * after looking at a number of nva3+ vbios images, they + * all seem likely to have a static shift of 2.. lets + * go with that for now until proven otherwise. + */ + vidshift = 2; + break; + case 0x40: + headerlen = volt[1]; + recordlen = volt[2]; + entries = volt[3]; /* not a clue what the entries are for.. */ + vidmask = volt[11]; /* guess.. */ + vidshift = 0; + break; + default: + nv_debug(device, "voltage table 0x%02x unknown\n", volt[0]); + return; + } + + /* validate vid mask */ + device->voltage.vid_mask = vidmask; + if (!device->voltage.vid_mask) { + nv_debug(device, "voltage vidmask is insane 0x%02x\n", vidmask); + return; + } + + i = 0; + while (vidmask) { + if (i > nr_vidtag) { + nv_debug(device, "vid bit %d unknown\n", i); + return; + } + + if (nouveau_gpio_find(device, 0, vidtag[i], 0xff, &func)) { + nv_debug(device, "vid bit %d has no gpio tag\n", i); + return; + } + + vidmask >>= 1; + i++; + } + + /* parse vbios entries into common format */ + device->voltage.version = volt[0]; + if (device->voltage.version < 0x40) { + device->voltage.nr_level = entries; + // device->voltage.level = (nouveau_pm_voltage_level*)IOMalloc(device->voltage.nr_level * sizeof(nouveau_pm_voltage_level)); + device->voltage.level = new nouveau_pm_voltage_level[device->voltage.nr_level]; + if (!device->voltage.level) { + nv_debug(device, "can't allocate voltage structure\n"); + return; + } + + entry = volt + headerlen; + for (i = 0; i < entries; i++, entry += recordlen) { + device->voltage.level[i].voltage = entry[0] * 10000; + device->voltage.level[i].vid = entry[1] >> vidshift; + } + } else { + u32 volt_uv = ROM32(volt[4]); + s16 step_uv = ROM16(volt[8]); + u8 vid; + + device->voltage.nr_level = device->voltage.vid_mask + 1; + // device->voltage.level = (nouveau_pm_voltage_level*)IOMalloc(device->voltage.nr_level * sizeof(nouveau_pm_voltage_level)); + device->voltage.level = new nouveau_pm_voltage_level[device->voltage.nr_level]; + + if (!device->voltage.level) { + nv_debug(device, "can't allocate voltage structure\n"); + return; + } + + for (vid = 0; vid <= device->voltage.vid_mask; vid++) { + device->voltage.level[vid].voltage = volt_uv; + device->voltage.level[vid].vid = vid; + volt_uv += step_uv; + } + } + + device->voltage.supported = true; +} + +static int nouveau_volt_lvl_lookup(struct nouveau_device *device, int vid) +{ + int i; + + for (i = 0; i < device->voltage.nr_level; i++) { + if (device->voltage.level[i].vid == vid) + return device->voltage.level[i].voltage; + } + + return 0; +} + +int nouveau_voltage_get(struct nouveau_device *device) +{ + u8 vid = 0; + int i; + + for (i = 0; i < nr_vidtag; i++) { + if (!(device->voltage.vid_mask & (1 << i))) + continue; + + vid |= nouveau_gpio_get(device, 0, vidtag[i], 0xff) << i; + } + + return nouveau_volt_lvl_lookup(device, vid); +} diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_volt.h b/plugins/GPUSensors/GeforceSensors/nouveau_volt.h new file mode 100755 index 0000000..3569db2 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_volt.h @@ -0,0 +1,31 @@ +// +// nouveau_volt.h +// HWSensors +// +// Created by Kozlek on 10.08.12. +// +// + +#ifndef HWSensors_nouveau_volt_h +#define HWSensors_nouveau_volt_h + +#include "nouveau_definitions.h" + +struct nouveau_pm_voltage_level { + u32 voltage; /* microvolts */ + u8 vid; +}; + +struct nouveau_pm_voltage { + bool supported; + u8 version; + u8 vid_mask; + + struct nouveau_pm_voltage_level *level; + int nr_level; +}; + +void nouveau_volt_init(struct nouveau_device *); +int nouveau_voltage_get(struct nouveau_device *device); + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_xpio.cpp b/plugins/GPUSensors/GeforceSensors/nouveau_xpio.cpp new file mode 100755 index 0000000..631190c --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_xpio.cpp @@ -0,0 +1,81 @@ +// +// nouveau_xpio.cpp +// HWSensors +// +// Created by Kozlek on 08.12.12. +// +// + +#include "nouveau_xpio.h" + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nouveau_gpio.h" +#include "nouveau_xpio.h" +#include "nouveau.h" +#include "nouveau_bios.h" + +static u16 dcb_xpiod_table(struct nouveau_device *device, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + u16 data = dcb_gpio_table(device, ver, hdr, cnt, len); + if (data && *ver >= 0x40 && *hdr >= 0x06) { + u16 xpio = nv_ro16(device, data + 0x04); + if (xpio) { + *ver = nv_ro08(device, data + 0x00); + *hdr = nv_ro08(device, data + 0x01); + *cnt = nv_ro08(device, data + 0x02); + *len = nv_ro08(device, data + 0x03); + return xpio; + } + } + return 0x0000; +} + +u16 dcb_xpio_table(struct nouveau_device *device, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) +{ + u16 data = dcb_xpiod_table(device, ver, hdr, cnt, len); + if (data && idx < *cnt) { + u16 xpio = nv_ro16(device, data + *hdr + (idx * *len)); + if (xpio) { + *ver = nv_ro08(device, data + 0x00); + *hdr = nv_ro08(device, data + 0x01); + *cnt = nv_ro08(device, data + 0x02); + *len = nv_ro08(device, data + 0x03); + return xpio; + } + } + return 0x0000; +} + +/*static u16 dcb_xpio_parse(struct nouveau_device *device, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_xpio *info) +{ + u16 data = dcb_xpio_table(device, idx, ver, hdr, cnt, len); + if (data && *len >= 6) { + info->type = nv_ro08(device, data + 0x04); + info->addr = nv_ro08(device, data + 0x05); + info->flags = nv_ro08(device, data + 0x06); + } + return 0x0000; +}*/ \ No newline at end of file diff --git a/plugins/GPUSensors/GeforceSensors/nouveau_xpio.h b/plugins/GPUSensors/GeforceSensors/nouveau_xpio.h new file mode 100755 index 0000000..a240478 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nouveau_xpio.h @@ -0,0 +1,22 @@ +// +// nouveau_xpio.h +// HWSensors +// +// Created by Kozlek on 08.12.12. +// +// + +#ifndef __HWSensors__nouveau_xpio__ +#define __HWSensors__nouveau_xpio__ + +#include "nouveau_definitions.h" + +struct nvbios_xpio { + u8 type; + u8 addr; + u8 flags; +}; + +u16 dcb_xpio_table(struct nouveau_device *device, u8 idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); + +#endif /* defined(__HWSensors__nouveau_xpio__) */ diff --git a/plugins/GPUSensors/GeforceSensors/nv10.cpp b/plugins/GPUSensors/GeforceSensors/nv10.cpp new file mode 100755 index 0000000..cd4b9b6 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nv10.cpp @@ -0,0 +1,59 @@ +// +// nv10.cpp +// HWSensors +// +// Created by Kozlek on 10.08.12. +// +// + +/* + * Copyright (C) 2009 Francisco Jerez. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "nv10.h" + +#include "nouveau_definitions.h" +#include "nouveau.h" + +int nv10_gpio_sense(struct nouveau_device *device, int line) +{ + if (line < 2) { + line = line * 16; + line = nv_rd32(device, 0x00600818) >> line; + return !!(line & 0x0100); + } else + if (line < 10) { + line = (line - 2) * 4; + line = nv_rd32(device, 0x0060081c) >> line; + return !!(line & 0x04); + } else + if (line < 14) { + line = (line - 10) * 4; + line = nv_rd32(device, 0x00600850) >> line; + return !!(line & 0x04); + } + + return -EINVAL; +} diff --git a/plugins/GPUSensors/GeforceSensors/nv10.h b/plugins/GPUSensors/GeforceSensors/nv10.h new file mode 100755 index 0000000..f574f2f --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nv10.h @@ -0,0 +1,14 @@ +// +// nv10.h +// HWSensors +// +// Created by Kozlek on 10.08.12. +// +// + +#ifndef __HWSensors__nv10__ +#define __HWSensors__nv10__ + +int nv10_gpio_sense(struct nouveau_device *device, int line); + +#endif /* defined(__HWSensors__nv10__) */ diff --git a/plugins/GPUSensors/GeforceSensors/nv40.cpp b/plugins/GPUSensors/GeforceSensors/nv40.cpp new file mode 100755 index 0000000..f6f5b92 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nv40.cpp @@ -0,0 +1,255 @@ +// +// nv40.c +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nouveau.h" +#include "nv40.h" +#include "nv10.h" +#include "nouveau_therm.h" + +bool nv40_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0x40: + device->cname = "NV40"; + break; + case 0x41: + device->cname = "NV41"; + break; + case 0x42: + device->cname = "NV42"; + break; + case 0x43: + device->cname = "NV43"; + break; + case 0x45: + device->cname = "NV45"; + break; + case 0x47: + device->cname = "G70"; + break; + case 0x49: + device->cname = "G71"; + break; + case 0x4b: + device->cname = "G73"; + break; + case 0x44: + device->cname = "NV44"; + break; + case 0x46: + device->cname = "G72"; + break; + case 0x4a: + device->cname = "NV44A"; + break; + case 0x4c: + device->cname = "C61"; + break; + case 0x4e: + device->cname = "C51"; + break; + case 0x63: + device->cname = "C73"; + break; + case 0x67: + device->cname = "C67"; + break; + case 0x68: + device->cname = "C68"; + break; + default: + nv_fatal(device, "unknown Curie chipset\n"); + return false; + } + + return true; +} + +void nv40_init(struct nouveau_device *device) +{ + device->gpio_sense = nv10_gpio_sense; + device->gpio_find = nouveau_gpio_find; + device->gpio_get = nouveau_gpio_get; + + device->temp_get = nv40_temp_get; + device->clocks_get = nv40_clocks_get; + device->pwm_get = nv40_fan_pwm_get; + //device->voltage_get = nouveau_voltage_get; + device->fan_pwm_get = nouveau_therm_fan_pwm_get; + device->fan_rpm_get = nouveau_therm_fan_rpm_get; + + // Reset temperature sensor + nv40_sensor_setup(device); +} + +static u32 read_pll_1(struct nouveau_device *device, u32 reg) +{ + u32 ctrl = nv_rd32(device, reg + 0x00); + int P = (ctrl & 0x00070000) >> 16; + int N = (ctrl & 0x0000ff00) >> 8; + int M = (ctrl & 0x000000ff) >> 0; + u32 ref = 27000, clk = 0; + + if (ctrl & 0x80000000) + clk = ref * N / M; + + return clk >> P; +} + +static u32 read_pll_2(struct nouveau_device *device, u32 reg) +{ + u32 ctrl = nv_rd32(device, reg + 0x00); + u32 coef = nv_rd32(device, reg + 0x04); + int N2 = (coef & 0xff000000) >> 24; + int M2 = (coef & 0x00ff0000) >> 16; + int N1 = (coef & 0x0000ff00) >> 8; + int M1 = (coef & 0x000000ff) >> 0; + int P = (ctrl & 0x00070000) >> 16; + u32 ref = 27000, clk = 0; + + if ((ctrl & 0x80000000) && M1) { + clk = ref * N1 / M1; + if ((ctrl & 0x40000100) == 0x40000000) { + if (M2) + clk = clk * N2 / M2; + else + clk = 0; + } + } + + return clk >> P; +} + +static u32 read_clk(struct nouveau_device *device, u32 src) +{ + switch (src) { + case 3: + return read_pll_2(device, 0x004000); + case 2: + return read_pll_1(device, 0x004008); + default: + break; + } + + return 0; +} + +int nv40_clocks_get(struct nouveau_device *device, u8 source) +{ + u32 ctrl = nv_rd32(device, 0x00c040); + + switch (source) { + case nouveau_clock_core: + return read_clk(device, (ctrl & 0x00000003) >> 0); + + case nouveau_clock_shader: + return read_clk(device, (ctrl & 0x00000030) >> 4); + + case nouveau_clock_memory: + return read_pll_2(device, 0x4020); + + default: + return 0; + } +} + +int nv40_sensor_setup(struct nouveau_device *device) +{ + /* enable ADC readout and disable the ALARM threshold */ + if (device->chipset >= 0x46) { + nv_mask(device, 0x15b8, 0x80000000, 0); + nv_wr32(device, 0x15b0, 0x80003fff); + IOSleep(20); + return nv_rd32(device, 0x15b4) & 0x3fff; + } else { + nv_wr32(device, 0x15b0, 0xff); + IOSleep(20); + return nv_rd32(device, 0x15b4) & 0xff; + } +} + +int nv40_temp_get(struct nouveau_device *device) +{ + //struct nouveau_pm *pm = nouveau_pm(dev); + struct nouveau_pm_temp_sensor_constants *sensor = &device->sensor_constants; + int core_temp; + + if (device->chipset >= 0x46) { + nv_wr32(device, 0x15b0, 0x80003fff); + core_temp = nv_rd32(device, 0x15b4) & 0x3fff; + } else { + nv_wr32(device, 0x15b0, 0xff); + core_temp = nv_rd32(device, 0x15b4) & 0xff; + } + + /* Setup the sensor if the temperature is 0 */ + if (core_temp == 0) + core_temp = nv40_sensor_setup(device); + + if (sensor->slope_div == 0) + sensor->slope_div = 1; + if (sensor->offset_den == 0) + sensor->offset_den = 1; + if (sensor->slope_mult < 1) + sensor->slope_mult = 1; + + core_temp = core_temp * sensor->slope_mult / sensor->slope_div; + core_temp = core_temp + sensor->offset_num / sensor->offset_den; + core_temp = core_temp + sensor->offset_constant - 8; + + return core_temp; +} + +int nv40_fan_pwm_get(struct nouveau_device *device, int line, u32 *divs, u32 *duty) +{ + if (line == 2) { + u32 reg = nv_rd32(device, 0x0010f0); + if (reg & 0x80000000) { + *duty = (reg & 0x7fff0000) >> 16; + *divs = (reg & 0x00007fff); + return 0; + } + } else + if (line == 9) { + u32 reg = nv_rd32(device, 0x0015f4); + if (reg & 0x80000000) { + *divs = nv_rd32(device, 0x0015f8); + *duty = (reg & 0x7fffffff); + return 0; + } + } else { + nv_error(device, "unknown pwm ctrl for gpio %d\n", line); + return -ENODEV; + } + + return -ENODEV; +} diff --git a/plugins/GPUSensors/GeforceSensors/nv40.h b/plugins/GPUSensors/GeforceSensors/nv40.h new file mode 100755 index 0000000..66b70aa --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nv40.h @@ -0,0 +1,19 @@ +// +// nv40.h +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +#ifndef HWSensors_nv40_h +#define HWSensors_nv40_h + +bool nv40_identify(struct nouveau_device *device); +void nv40_init(struct nouveau_device *device); +int nv40_clocks_get(struct nouveau_device *device, u8 source); +int nv40_sensor_setup(struct nouveau_device *device); +int nv40_temp_get(struct nouveau_device *device); +int nv40_fan_pwm_get(struct nouveau_device *device, int line, u32 *divs, u32 *duty); + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/nv50.cpp b/plugins/GPUSensors/GeforceSensors/nv50.cpp new file mode 100755 index 0000000..7bd1452 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nv50.cpp @@ -0,0 +1,558 @@ +// +// nv50.c +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nouveau.h" +#include "nv50.h" +#include "nva3.h" +#include "nv84.h" +#include "nouveau_therm.h" + +void nv50_sensor_setup(struct nouveau_device *device); + +bool nv50_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0x50: + device->cname = "G80"; + break; + case 0x84: + device->cname = "G84"; + break; + case 0x86: + device->cname = "G86"; + break; + case 0x92: + device->cname = "G92"; + break; + case 0x94: + device->cname = "G94"; + break; + case 0x96: + device->cname = "G96"; + break; + case 0x98: + device->cname = "G98"; + break; + case 0xa0: + device->cname = "G200"; + break; + case 0xaa: + device->cname = "MCP77/MCP78"; + break; + case 0xac: + device->cname = "MCP79/MCP7A"; + break; + case 0xa3: + device->cname = "GT215"; + break; + case 0xa5: + device->cname = "GT216"; + break; + case 0xa8: + device->cname = "GT218"; + break; + case 0xaf: + device->cname = "MCP89"; + break; + default: + nv_fatal(device, "unknown Tesla chipset\n"); + return false; + } + + return true; +} + +void nv50_init(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0x50: + nv50_sensor_setup(device); + device->temp_get = nv50_temp_get; + device->clocks_get = nv50_clocks_get; + device->fan_rpm_get = nouveau_therm_fan_rpm_get; + break; + case 0xa3: + case 0xa5: + case 0xa8: + case 0xaf: + nva3_therm_init(device); + device->clocks_get = nva3_clocks_get; + device->temp_get = nv84_temp_get; + device->fan_rpm_get = nva3_therm_fan_sense; + break; + default: + device->clocks_get = nv50_clocks_get; + device->temp_get = nv84_temp_get; + device->fan_rpm_get = nouveau_therm_fan_rpm_get; + break; + } + + device->gpio_sense = nv50_gpio_sense; + device->gpio_find = nouveau_gpio_find; + device->gpio_get = nouveau_gpio_get; + + device->pwm_get = nv50_fan_pwm_get; + device->fan_pwm_get = nouveau_therm_fan_pwm_get; +} + +enum clk_src { + clk_src_crystal, + clk_src_href, + clk_src_hclk, + clk_src_hclkm3, + clk_src_hclkm3d2, + clk_src_host, + clk_src_nvclk, + clk_src_sclk, + clk_src_mclk, + clk_src_vdec, + clk_src_dom6 +}; + +static u32 read_clk(struct nouveau_device *, enum clk_src); + +static u32 read_div(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0x50: /* it exists, but only has bit 31, not the dividers.. */ + case 0x84: + case 0x86: + case 0x98: + case 0xa0: + return nv_rd32(device, 0x004700); + case 0x92: + case 0x94: + case 0x96: + return nv_rd32(device, 0x004800); + default: + return 0x00000000; + } +} + +static u32 read_pll_src(struct nouveau_device *device, u32 base) +{ + u32 coef, ref = read_clk(device, clk_src_crystal); + u32 rsel = nv_rd32(device, 0x00e18c); + int P, N, M = 0, id = 0; + + switch (device->chipset) { + case 0x50: + case 0xa0: + switch (base) { + case 0x4020: + case 0x4028: id = !!(rsel & 0x00000004); break; + case 0x4008: id = !!(rsel & 0x00000008); break; + case 0x4030: id = 0; break; + default: + nv_error(device, "ref: bad pll 0x%06x\n", (unsigned int)base); + return 0; + } + + coef = nv_rd32(device, 0x00e81c + (id * 0x0c)); + ref *= (coef & 0x01000000) ? 2 : 4; + P = (coef & 0x00070000) >> 16; + N = ((coef & 0x0000ff00) >> 8) + 1; + M = ((coef & 0x000000ff) >> 0) + 1; + break; + case 0x84: + case 0x86: + case 0x92: + coef = nv_rd32(device, 0x00e81c); + P = (coef & 0x00070000) >> 16; + N = (coef & 0x0000ff00) >> 8; + M = (coef & 0x000000ff) >> 0; + break; + case 0x94: + case 0x96: + case 0x98: + rsel = nv_rd32(device, 0x00c050); + switch (base) { + case 0x4020: rsel = (rsel & 0x00000003) >> 0; break; + case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break; + case 0x4028: rsel = (rsel & 0x00001800) >> 11; break; + case 0x4030: rsel = 3; break; + default: + nv_error(device, "ref: bad pll 0x%06x\n", (unsigned int)base); + return 0; + } + + switch (rsel) { + case 0: id = 1; break; + case 1: return read_clk(device, clk_src_crystal); + case 2: return read_clk(device, clk_src_href); + case 3: id = 0; break; + } + + coef = nv_rd32(device, 0x00e81c + (id * 0x28)); + P = (nv_rd32(device, 0x00e824 + (id * 0x28)) >> 16) & 7; + P += (coef & 0x00070000) >> 16; + N = (coef & 0x0000ff00) >> 8; + M = (coef & 0x000000ff) >> 0; + break; + default: + //BUG_ON(1); + break; + } + + if (M) + return (ref * N / M) >> P; + return 0; +} + +static u32 read_pll_ref(struct nouveau_device *device, u32 base) +{ + u32 src, mast = nv_rd32(device, 0x00c040); + + switch (base) { + case 0x004028: + src = !!(mast & 0x00200000); + break; + case 0x004020: + src = !!(mast & 0x00400000); + break; + case 0x004008: + src = !!(mast & 0x00010000); + break; + case 0x004030: + src = !!(mast & 0x02000000); + break; + case 0x00e810: + return read_clk(device, clk_src_crystal); + default: + nv_error(device, "bad pll 0x%06x\n", (unsigned int)base); + return 0; + } + + if (src) + return read_clk(device, clk_src_href); + return read_pll_src(device, base); +} + +static u32 read_pll(struct nouveau_device *device, u32 base) +{ + u32 mast = nv_rd32(device, 0x00c040); + u32 ctrl = nv_rd32(device, base + 0); + u32 coef = nv_rd32(device, base + 4); + u32 ref = read_pll_ref(device, base); + u32 clk = 0; + int N1, N2, M1, M2; + + if (base == 0x004028 && (mast & 0x00100000)) { + /* wtf, appears to only disable post-divider on nva0 */ + if (device->chipset != 0xa0) + return read_clk(device, clk_src_dom6); + } + + N2 = (coef & 0xff000000) >> 24; + M2 = (coef & 0x00ff0000) >> 16; + N1 = (coef & 0x0000ff00) >> 8; + M1 = (coef & 0x000000ff); + if ((ctrl & 0x80000000) && M1) { + clk = ref * N1 / M1; + if ((ctrl & 0x40000100) == 0x40000000) { + if (M2) + clk = clk * N2 / M2; + else + clk = 0; + } + } + + return clk; +} + +static u32 read_clk(struct nouveau_device *device, enum clk_src src) +{ + u32 mast = nv_rd32(device, 0x00c040); + u32 P = 0; + + switch (src) { + case clk_src_crystal: + return device->crystal; + case clk_src_href: + return 100000; /* PCIE reference clock */ + case clk_src_hclk: + return read_clk(device, clk_src_href) * 27778 / 10000; + case clk_src_hclkm3: + return read_clk(device, clk_src_hclk) * 3; + case clk_src_hclkm3d2: + return read_clk(device, clk_src_hclk) * 3 / 2; + case clk_src_host: + switch (mast & 0x30000000) { + case 0x00000000: return read_clk(device, clk_src_href); + case 0x10000000: break; + case 0x20000000: /* !0x50 */ + case 0x30000000: return read_clk(device, clk_src_hclk); + } + break; + case clk_src_nvclk: + if (!(mast & 0x00100000)) + P = (nv_rd32(device, 0x004028) & 0x00070000) >> 16; + switch (mast & 0x00000003) { + case 0x00000000: return read_clk(device, clk_src_crystal) >> P; + case 0x00000001: return read_clk(device, clk_src_dom6); + case 0x00000002: return read_pll(device, 0x004020) >> P; + case 0x00000003: return read_pll(device, 0x004028) >> P; + } + break; + case clk_src_sclk: + P = (nv_rd32(device, 0x004020) & 0x00070000) >> 16; + switch (mast & 0x00000030) { + case 0x00000000: + if (mast & 0x00000080) + return read_clk(device, clk_src_host) >> P; + return read_clk(device, clk_src_crystal) >> P; + case 0x00000010: break; + case 0x00000020: return read_pll(device, 0x004028) >> P; + case 0x00000030: return read_pll(device, 0x004020) >> P; + } + break; + case clk_src_mclk: + P = (nv_rd32(device, 0x004008) & 0x00070000) >> 16; + if (nv_rd32(device, 0x004008) & 0x00000200) { + switch (mast & 0x0000c000) { + case 0x00000000: + return read_clk(device, clk_src_crystal) >> P; + case 0x00008000: + case 0x0000c000: + return read_clk(device, clk_src_href) >> P; + } + } else { + return read_pll(device, 0x004008) >> P; + } + break; + case clk_src_vdec: + P = (read_div(device) & 0x00000700) >> 8; + switch (device->chipset) { + case 0x84: + case 0x86: + case 0x92: + case 0x94: + case 0x96: + case 0xa0: + switch (mast & 0x00000c00) { + case 0x00000000: + if (device->chipset == 0xa0) /* wtf?? */ + return read_clk(device, clk_src_nvclk) >> P; + return read_clk(device, clk_src_crystal) >> P; + case 0x00000400: + return 0; + case 0x00000800: + if (mast & 0x01000000) + return read_pll(device, 0x004028) >> P; + return read_pll(device, 0x004030) >> P; + case 0x00000c00: + return read_clk(device, clk_src_nvclk) >> P; + } + break; + case 0x98: + switch (mast & 0x00000c00) { + case 0x00000000: + return read_clk(device, clk_src_nvclk) >> P; + case 0x00000400: + return 0; + case 0x00000800: + return read_clk(device, clk_src_hclkm3d2) >> P; + case 0x00000c00: + return read_clk(device, clk_src_mclk) >> P; + } + break; + } + break; + case clk_src_dom6: + switch (device->chipset) { + case 0x50: + case 0xa0: + return read_pll(device, 0x00e810) >> 2; + case 0x84: + case 0x86: + case 0x92: + case 0x94: + case 0x96: + case 0x98: + P = (read_div(device) & 0x00000007) >> 0; + switch (mast & 0x0c000000) { + case 0x00000000: return read_clk(device, clk_src_href); + case 0x04000000: break; + case 0x08000000: return read_clk(device, clk_src_hclk); + case 0x0c000000: + return read_clk(device, clk_src_hclkm3) >> P; + } + break; + default: + break; + } + default: + break; + } + + nv_debug(device, "unknown clock source %d 0x%08x\n", src, (unsigned int)mast); + return 0; +} + +int nv50_clocks_get(struct nouveau_device *device, u8 source) +{ + if (device->chipset == 0xaa) + return 0; + + switch (source) { + case nouveau_clock_core: + if (device->chipset == 0xac) { //from TimeWalker + u32 ref = 27000; + u32 ctrl = nv_rd32(device, 0x004028); + u32 coef = nv_rd32(device, 0x00402c); + u32 P = (ctrl >> 16) & 0x03; + int N1 = (coef >> 8) & 0xff; + int M1 = coef & 0xff; + return ref*N1*4/M1 >> P; + } + else { + return read_clk(device, clk_src_nvclk); + } + + case nouveau_clock_shader: + return read_clk(device, clk_src_sclk); + + case nouveau_clock_memory: + return read_clk(device, clk_src_mclk); + + default: + if (device->chipset != 0x50) { + switch (source) { + case nouveau_clock_vdec: + return read_clk(device, clk_src_vdec); + + case nouveau_clock_dom6: + return read_clk(device, clk_src_dom6); + + default: + return 0; + } + } + + return 0; + } + + return 0; +} + +static bool nv50_gpio_location(int line, u32 *reg, u32 *shift) +{ + const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; + + if (line >= 32) + return false; + + *reg = nv50_gpio_reg[line >> 3]; + *shift = (line & 7) << 2; + + return true; +} + +int nv50_gpio_sense(struct nouveau_device *device, int line) +{ + u32 reg, shift; + + if (!nv50_gpio_location(line, ®, &shift)) + return -EINVAL; + + return !!(nv_rd32(device, reg) & (4 << shift)); +} + +void nv50_sensor_setup(struct nouveau_device *device) +{ + nv_mask(device, 0x20010, 0x40000000, 0x0); + IOSleep(20); /* wait for the temperature to stabilize */ +} + +int nv50_temp_get(struct nouveau_device *device) +{ + struct nouveau_pm_temp_sensor_constants *sensor = &device->sensor_constants; + int core_temp; + + core_temp = nv_rd32(device, 0x20014) & 0x3fff; + + /* if the slope or the offset is unset, do no use the sensor */ + if (!sensor->slope_div || !sensor->slope_mult || + !sensor->offset_num || !sensor->offset_den) + return -ENODEV; + + core_temp = core_temp * sensor->slope_mult / sensor->slope_div; + core_temp = core_temp + sensor->offset_num / sensor->offset_den; + core_temp = core_temp + sensor->offset_constant - 8; + + /* reserve negative temperatures for errors */ + if (core_temp < 0) + core_temp = 0; + + return core_temp; +} + +static int pwm_info(struct nouveau_device *device, int *line, int *ctrl, int *indx) +{ + if (*line == 0x04) { + *ctrl = 0x00e100; + *line = 4; + *indx = 0; + } else + if (*line == 0x09) { + *ctrl = 0x00e100; + *line = 9; + *indx = 1; + } else + if (*line == 0x10) { + *ctrl = 0x00e28c; + *line = 0; + *indx = 0; + } else { + nv_error(device, "unknown pwm ctrl for gpio %d\n", *line); + return -ENODEV; + } + + return 0; +} + +int nv50_fan_pwm_get(struct nouveau_device *device, int line, u32 *divs, u32 *duty) +{ + int ctrl, id, ret = pwm_info(device, &line, &ctrl, &id); + if (ret) + return ret; + + if (nv_rd32(device, ctrl) & (1 << line)) { + *divs = nv_rd32(device, 0x00e114 + (id * 8)); + *duty = nv_rd32(device, 0x00e118 + (id * 8)); + return 0; + } + + return -ENODEV; +} + + diff --git a/plugins/GPUSensors/GeforceSensors/nv50.h b/plugins/GPUSensors/GeforceSensors/nv50.h new file mode 100755 index 0000000..74f800c --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nv50.h @@ -0,0 +1,22 @@ +// +// nv50.h +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +#ifndef HWSensors_nv50_h +#define HWSensors_nv50_h + +bool nv50_identify(struct nouveau_device *device); +void nv50_init(struct nouveau_device *device); + +int nv50_gpio_sense(struct nouveau_device *device, int line); + +int nv50_clocks_get(struct nouveau_device *device, u8 source); +void nv50_sensor_setup(struct nouveau_device *device); +int nv50_temp_get(struct nouveau_device *device); +int nv50_fan_pwm_get(struct nouveau_device *device, int line, u32 *divs, u32 *duty); + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/nv84.cpp b/plugins/GPUSensors/GeforceSensors/nv84.cpp new file mode 100644 index 0000000..ad398ee --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nv84.cpp @@ -0,0 +1,39 @@ +// +// nv84.cpp +// HWSensors +// +// Created by kozlek on 18.03.13. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nv84.h" +#include "nouveau.h" + +int nv84_temp_get(struct nouveau_device *device) +{ + return nv_rd32(device, 0x20400); +} \ No newline at end of file diff --git a/plugins/GPUSensors/GeforceSensors/nv84.h b/plugins/GPUSensors/GeforceSensors/nv84.h new file mode 100644 index 0000000..5d2739b --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nv84.h @@ -0,0 +1,14 @@ +// +// nv84.h +// HWSensors +// +// Created by kozlek on 18.03.13. +// +// + +#ifndef __HWSensors__nv84__ +#define __HWSensors__nv84__ + +int nv84_temp_get(struct nouveau_device *device); + +#endif /* defined(__HWSensors__nv84__) */ diff --git a/plugins/GPUSensors/GeforceSensors/nva3.cpp b/plugins/GPUSensors/GeforceSensors/nva3.cpp new file mode 100755 index 0000000..fab65f6 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nva3.cpp @@ -0,0 +1,156 @@ +// +// nva3.c +// HWSensors +// +// Created by Kozlek on 10.08.12. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nouveau.h" +#include "nva3.h" + +int nva3_therm_fan_sense(struct nouveau_device *device) +{ + u32 tach = nv_rd32(device, 0x00e728) & 0x0000ffff; + u32 ctrl = nv_rd32(device, 0x00e720); + if (ctrl & 0x00000001) { +// return tach * ((device->card_type == NV_C0 || device->card_type == NV_E0) ? 30 : 60); + return tach * ((device->card_type >= NV_C0) ? 30 : 60); + } + + return -ENODEV; +} + +int nva3_therm_init(struct nouveau_device *device) +{ + struct dcb_gpio_func *tach = &device->fan_tach; + + /* enable fan tach, count revolutions per-second */ + nv_mask(device, 0x00e720, 0x00000003, 0x00000002); + if (tach->func != DCB_GPIO_UNUSED) { + nv_wr32(device, 0x00e724, device->crystal * 1000); + nv_mask(device, 0x00e720, 0x001f0000, tach->line << 16); + nv_mask(device, 0x00e720, 0x00000001, 0x00000001); + } + nv_mask(device, 0x00e720, 0x00000002, 0x00000000); + + return 0; +} + +static u32 read_clk(struct nouveau_device *, int, bool); +static u32 read_pll(struct nouveau_device *, int, u32); + +static u32 read_vco(struct nouveau_device *device, int clk) +{ + u32 sctl = nv_rd32(device, 0x4120 + (clk * 4)); + if ((sctl & 0x00000030) != 0x00000030) + return read_pll(device, 0x41, 0x00e820); + return read_pll(device, 0x42, 0x00e8a0); +} + +static u32 read_clk(struct nouveau_device *device, int clk, bool ignore_en) +{ + u32 sctl, sdiv, sclk; + + /* refclk for the 0xe8xx plls is a fixed frequency */ + if (clk >= 0x40) { + if (device->chipset == 0xaf) { + /* no joke.. seriously.. sigh.. */ + return nv_rd32(device, 0x00471c) * 1000; + } + + return device->crystal; + } + + sctl = nv_rd32(device, 0x4120 + (clk * 4)); + if (!ignore_en && !(sctl & 0x00000100)) + return 0; + + switch (sctl & 0x00003000) { + case 0x00000000: + return device->crystal; + case 0x00002000: + if (sctl & 0x00000040) + return 108000; + return 100000; + case 0x00003000: + sclk = read_vco(device, clk); + sdiv = ((sctl & 0x003f0000) >> 16) + 2; + return (sclk * 2) / sdiv; + default: + return 0; + } +} + +static u32 read_pll(struct nouveau_device *device, int clk, u32 pll) +{ + u32 ctrl = nv_rd32(device, pll + 0); + u32 sclk = 0, P = 1, N = 1, M = 1; + + if (!(ctrl & 0x00000008)) { + if (ctrl & 0x00000001) { + u32 coef = nv_rd32(device, pll + 4); + M = (coef & 0x000000ff) >> 0; + N = (coef & 0x0000ff00) >> 8; + P = (coef & 0x003f0000) >> 16; + + /* no post-divider on these.. */ + if ((pll & 0x00ff00) == 0x00e800) + P = 1; + + sclk = read_clk(device, 0x00 + clk, false); + } + } else { + sclk = read_clk(device, 0x10 + clk, false); + } + + if (M * P) + return sclk * N / (M * P); + return 0; +} + +int nva3_clocks_get(struct nouveau_device *device, u8 source) +{ + switch (source) { + case nouveau_clock_core: + return read_pll(device, 0x00, 0x4200); + case nouveau_clock_shader: + return read_pll(device, 0x01, 0x4220); + case nouveau_clock_memory: + return read_pll(device, 0x02, 0x4000); + case nouveau_clock_unka0: + return read_clk(device, 0x20, false); + case nouveau_clock_vdec: + return read_clk(device, 0x21, false); + case nouveau_clock_daemon: + return read_clk(device, 0x25, false); + case nouveau_clock_copy: + return read_pll(device, 0x00, 0x4200); // core + default: + return 0; + } +} diff --git a/plugins/GPUSensors/GeforceSensors/nva3.h b/plugins/GPUSensors/GeforceSensors/nva3.h new file mode 100755 index 0000000..1c35146 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nva3.h @@ -0,0 +1,16 @@ +// +// nva3.h +// HWSensors +// +// Created by Kozlek on 10.08.12. +// +// + +#ifndef HWSensors_nva3_h +#define HWSensors_nva3_h + +int nva3_therm_fan_sense(struct nouveau_device *device); +int nva3_therm_init(struct nouveau_device *device); +int nva3_clocks_get(struct nouveau_device *device, u8 source); + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/nvc0.cpp b/plugins/GPUSensors/GeforceSensors/nvc0.cpp new file mode 100755 index 0000000..9e8fd5e --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nvc0.cpp @@ -0,0 +1,321 @@ +// +// nvc0.c +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nvc0.h" + +#include "nouveau.h" +#include "nv50.h" +#include "nv84.h" +#include "nva3.h" +#include "nvd0.h" +#include "nouveau_therm.h" + +bool nvc0_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0xc0: + device->cname = "GF100"; + break; + case 0xc4: + device->cname = "GF104"; + break; + case 0xc3: + device->cname = "GF106"; + break; + case 0xce: + device->cname = "GF114"; + break; + case 0xcf: + device->cname = "GF116"; + break; + case 0xc1: + device->cname = "GF108"; + break; + case 0xc8: + device->cname = "GF110"; + break; + case 0xd9: + device->cname = "GF119"; + break; + default: + nv_fatal(device, "unknown Fermi chipset\n"); + return false; + } + + return true; +} + +void nvc0_init(struct nouveau_device *device) +{ + switch (device->chipset) { + + case 0xd9: + device->gpio_sense = nvd0_gpio_sense; + device->fan_rpm_get = nouveau_therm_fan_rpm_get; + break; + default: + nva3_therm_init(device); + device->gpio_sense = nv50_gpio_sense; + device->fan_rpm_get = nva3_therm_fan_sense; + break; + } + + device->gpio_find = nouveau_gpio_find; + device->gpio_get = nouveau_gpio_get; + + device->temp_get = nv84_temp_get; + device->clocks_get = nvc0_clocks_get; + //device->voltage_get = nouveau_voltage_get; + device->pwm_get = nvd0_fan_pwm_get; + device->fan_pwm_get = nouveau_therm_fan_pwm_get; +} + +static u32 read_div(struct nouveau_device *, int, u32, u32); +static u32 read_pll(struct nouveau_device *, u32); + +static u32 read_vco(struct nouveau_device *device, u32 dsrc) +{ + u32 ssrc = nv_rd32(device, dsrc); //dsrc = 0x137160 + nv_debug(device, "read_vco ssrc=0x%x\n", ssrc); //read_vco ssrc=0x3 + if (!(ssrc & 0x00000100)) + return read_pll(device, 0x00e800); + return read_pll(device, 0x00e820); +} + +#if 0 +int +nvkm_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +{ + return clk->func->read(clk, src); +} +struct nvkm_clk { + const struct nvkm_clk_func *func; +//... +}; +static const struct nvkm_clk_func +gf100_clk = { + .read = gf100_clk_read, + .calc = gf100_clk_calc, + .prog = gf100_clk_prog, + .tidy = gf100_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_hubk06 , 0x00 }, + { nv_clk_src_hubk01 , 0x01 }, + { nv_clk_src_copy , 0x02 }, + { nv_clk_src_gpc , 0x03, NVKM_CLK_DOM_FLAG_VPSTATE, "core", 2000 }, + { nv_clk_src_rop , 0x04 }, + { nv_clk_src_mem , 0x05, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0x06 }, + { nv_clk_src_pmu , 0x0a }, + { nv_clk_src_hubk07 , 0x0b }, + { nv_clk_src_max } + } +}; +#endif + + +static u32 read_pll(struct nouveau_device *device, u32 pll) +{ + u32 ctrl = nv_rd32(device, pll + 0); + u32 coef = nv_rd32(device, pll + 4); + u32 P = (coef & 0x003f0000) >> 16; + u32 N = (coef & 0x0000ff00) >> 8; + u32 M = (coef & 0x000000ff) >> 0; + u32 sclk, doff; + u16 fN = 0xf000; + + nv_debug(device, "read pll=0x%x, ctrl=0x%x, coef=0x%x\n", pll, ctrl, coef); + //read pll=0xe820, ctrl=0x1030005, coef=0x5063c01 => P=6 N=60 M=1 + //=>sclk=0x18b820 = + //read pll=0xe800, ctrl=0x1030005, coef=0x5063c01 + if (!(ctrl & 0x00000001)) + return 0; + + if (P == 0) P = 1; + if (M == 0) M = 1; + + switch (pll) { + case 0x00e820: + sclk = device->crystal; + P = 1; + break; + case 0x00e800: + sclk = device->crystal; + P = 3; + break; + case 0x137000: + case 0x137020: + case 0x137040: + case 0x1370e0: + doff = (pll - 0x137000) / 0x20; + sclk = read_div(device, doff, 0x137120, 0x137140); + break; + case 0x132000: + sclk = read_pll(device, 0x132020); + P = (coef & 0x10000000) ? 2 : 1; + break; + case 0x132020: + sclk = read_div(device, 0, 0x137320, 0x137330); + fN = nv_rd32(device, pll + 0x10) >> 16; + break; + default: + return 0; + } + + sclk = (sclk * N) + (((u16)(fN + 4096) * sclk) >> 13); + return sclk / (M * P); +} + +static u32 read_div(struct nouveau_device *device, int doff, u32 dsrc, u32 dctl) +{ + u32 ssrc = nv_rd32(device, dsrc + (doff * 4)); + u32 sclk, sctl, sdiv = 2; + u32 ret = 0; + + //read_div(device, 0, 0x137160, 0x1371d0); //ssrc=0x3 + switch (ssrc & 0x00000003) { + case 0: + if ((ssrc & 0x00030000) != 0x00030000) { + ret = device->crystal; + break; + } + ret = 108000; + break; + case 2: + ret = 100000; + break; + case 3: + sclk = read_vco(device, dsrc + (doff * 4)); //read_vco ssrc=0x103 + //read pll=0xe820, ctrl=0x1030005, coef=0x5063c01 + //return sclk=0x41eb0 = 270000 + //return read_div=0xd2f0 + // + //read pll=0xe800, ctrl=0x1030005, coef=0x5063c01 + //return sclk=0x41eb0 + //return read_div=0x107ac + /* Memclk has doff of 0 despite its alt. location */ + if (doff <= 2) { + sctl = nv_rd32(device, dctl + (doff * 4)); + nv_debug(device, "sctl=0x%x\n", sctl); //sctl=0x81200606 + if (sctl & 0x80000000) { + if (ssrc & 0x100) + sctl >>= 8; + + sdiv = (sctl & 0x3f) + 2; + } + nv_debug(device, "sctl=0x%x sdiv=0x%x\n", sctl, sdiv); //sctl=0x81200606 sdiv=0x8 + } + + ret = (sclk * 2) / sdiv; + break; + default: + break; + } + nv_debug(device, "return read_div=0x%x\n", ret); //return read_div=0x107ac = 67500 + return ret; +} + +static u32 read_mem(struct nouveau_device *device) +{ + u32 base = 0; + u32 ssel = nv_rd32(device, 0x1373f0); + if (ssel & 0x00000002) + base = read_pll(device, 0x132000); + else + base = read_div(device, 0, 0x137300, 0x137310); //return read_div=0xd2f0 + nv_debug(device, "return read_mem=%d\n", base); //return read_mem=54000 + return base / 4.0f; +} + +static u32 read_clk(struct nouveau_device *device, int clk) +{ + u32 sctl = nv_rd32(device, 0x137250 + (clk * 4)); + u32 ssel = nv_rd32(device, 0x137100); + u32 sclk, sdiv; + + nv_debug(device, "read_clk sctl=0x%x ssel=0x%x\n", sctl, ssel); //read_clk sctl=0x81200000 ssel=0x0 + + if (ssel & (1 << clk)) { + if (clk < 7) + sclk = read_pll(device, 0x137000 + (clk * 0x20)); + else + sclk = read_pll(device, 0x1370e0); + sdiv = ((sctl & 0x00003f00) >> 8) + 2; + //read pll=0xe800, ctrl=0x1030005, coef=0x5063c01 + } else { + sclk = read_div(device, clk, 0x137160, 0x1371d0); //return read_div=0x107ac = 67500 + sdiv = ((sctl & 0x0000003f) >> 0) + 2; + } + nv_debug(device, "return read_clk=%d div=%d\n", sclk, sdiv/2); //return read_clk=67500 div=1 + + if (sctl & 0x80000000) + return (sclk * 2) / sdiv; + return sclk; +} +//gf100_clk_read(struct nvkm_clk *base, enum nv_clk_src src) +int nvc0_clocks_get(struct nouveau_device *device, u8 source) +{ + switch (source) { + case nouveau_clock_core: + return read_clk(device, 0x00) / 2; + case nouveau_clock_shader: + return read_clk(device, 0x00); + case nouveau_clock_memory: + return read_mem(device); + case nouveau_clock_rop: + return read_clk(device, 0x01); + case nouveau_clock_hub01: + return read_clk(device, 0x08); + case nouveau_clock_hub06: + return read_clk(device, 0x07); + case nouveau_clock_hub07: + return read_clk(device, 0x02); + case nouveau_clock_vdec: + return read_clk(device, 0x0e); + case nouveau_clock_daemon: + return read_clk(device, 0x0c); + case nouveau_clock_copy: + return read_clk(device, 0x09); + + case nouveau_clock_mpllref: + return read_div(device, 0, 0x137320, 0x137330); + case nouveau_clock_mpllsrc: + return read_pll(device, 0x132020); + case nouveau_clock_mpll: + return read_pll(device, 0x132000); + + default: + return 0; + } +} diff --git a/plugins/GPUSensors/GeforceSensors/nvc0.h b/plugins/GPUSensors/GeforceSensors/nvc0.h new file mode 100755 index 0000000..db4e805 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nvc0.h @@ -0,0 +1,20 @@ +// +// nvc0.h +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +#ifndef HWSensors_nvc0_h +#define HWSensors_nvc0_h + +#include "nouveau_definitions.h" + +bool nvc0_identify(struct nouveau_device *device); +void nvc0_init(struct nouveau_device *device); + +int nvc0_clocks_get(struct nouveau_device *device, u8 source); +int nve0_clocks_get(struct nouveau_device *device, u8 source); + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/nvclock_i2c.cpp b/plugins/GPUSensors/GeforceSensors/nvclock_i2c.cpp new file mode 100755 index 0000000..cc013a0 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nvclock_i2c.cpp @@ -0,0 +1,368 @@ +// +// i2c.c +// HWSensors +// +// Created by Kozlek on 31.07.12. +// +// + +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2006 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * I2C support needed for hardware monitoring, this code is partly based on code from nvtv + * and the opensource xfree86 nv driver. + */ + +/* NVTV TV common routines -- Dirk Thierbach + * + * This file is part of nvtv, a tool for tv-output on NVidia cards. + * + * nvtv is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * nvtv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: i2c.c,v 1.14 2007/04/24 08:10:47 thunderbird Exp $ + * + * Contents: + * + * Header: Common tv-related routines. + * + */ + +/***************************************************************************\ + |* *| + |* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| + |* *| + |* NOTICE TO USER: The source code is copyrighted under U.S. and *| + |* international laws. Users and possessors of this source code are *| + |* hereby granted a nonexclusive, royalty-free copyright license to *| + |* use this code in individual and commercial software. *| + |* *| + |* Any use of this source code must include, in the user documenta- *| + |* tion and internal comments to the code, notices to the end user *| + |* as follows: *| + |* *| + |* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| + |* *| + |* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| + |* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| + |* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| + |* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| + |* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| + |* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| + |* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| + |* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| + |* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| + |* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| + |* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| + |* *| + |* U.S. Government End Users. This source code is a "commercial *| + |* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| + |* consisting of "commercial computer software" and "commercial *| + |* computer software documentation," as such terms are used in *| + |* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| + |* ment only as a commercial end item. Consistent with 48 C.F.R. *| + |* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| + |* all U.S. Government End Users acquire the source code with only *| + |* those rights set forth herein. *| + |* *| + \***************************************************************************/ + +#include "nvclock_i2c.h" +#include "nouveau.h" + +void nvclock_i2c_lock_unlock(nouveau_device *device, int lock) +{ + unsigned char cr11; + volatile unsigned char *PCIO = (volatile unsigned char*)(device->mmio->getVirtualAddress() + 0x00601000); + + PCIO[0x3d4] = 0x1f; + PCIO[0x3d5] = lock ? 0x99 : 0x57; + + PCIO[0x3d4] = 0x11; + cr11 = PCIO[0x3d5]; + if(lock) cr11 |= 0x80; + else cr11 &= ~0x80; + PCIO[0x3d5] = cr11; +} + + +void nvclock_i2c_get_bits(I2CBusPtr b, int *clock, int *data) +{ + unsigned char val; + int DDCBase = (int)b->DriverPrivate.val; + volatile unsigned char *PCIO = (volatile unsigned char*)(b->card->mmio->getVirtualAddress() + 0x00601000); + + /* Get the result. */ + PCIO[0x3d4] = DDCBase; + val = PCIO[0x3d5]; + + *clock = (val & DDC_SCL_READ_MASK) != 0; + *data = (val & DDC_SDA_READ_MASK) != 0; +} + +void nvclock_i2c_put_bits(I2CBusPtr b, int clock, int data) +{ + unsigned char val; + int DDCBase = (int)b->DriverPrivate.val; + volatile unsigned char *PCIO = (volatile unsigned char*)(b->card->mmio->getVirtualAddress() + 0x00601000); + + PCIO[0x3d4] = DDCBase + 1; + val = PCIO[0x3d5] & 0xf0; + if (clock) + val |= DDC_SCL_WRITE_MASK; + else + val &= ~DDC_SCL_WRITE_MASK; + + if (data) + val |= DDC_SDA_WRITE_MASK; + else + val &= ~DDC_SDA_WRITE_MASK; + + PCIO[0x3d4] = DDCBase + 1; + PCIO[0x3d5] = val | 0x1; +} + +void nvclock_nv50_i2c_get_bits(I2CBusPtr bus, int *clock, int *data) +{ + const long offset = bus->DriverPrivate.val; + volatile unsigned int *PMC = (volatile unsigned int*)bus->card->mmio->getVirtualAddress(); + + unsigned char val = PMC[offset/4]; + + *clock = !!(val & 1); + *data = !!(val & 2); +} + +void nvclock_nv50_i2c_put_bits(I2CBusPtr bus, int clock, int data) +{ + const long offset = bus->DriverPrivate.val; + volatile unsigned int *PMC = (volatile unsigned int*)bus->card->mmio->getVirtualAddress(); + + PMC[offset/4] = 4 | clock | data << 1; +} + +I2CBusPtr nvclock_i2c_create_bus_ptr(nouveau_device *device, char *name, int bus) +{ + I2CBusPtr I2CPtr; + + I2CPtr = xf86CreateI2CBusRec(); + if(!I2CPtr) return NULL; + + I2CPtr->BusName = name; + I2CPtr->scrnIndex = device->card_index; /* We need to use unique indices or else it can lead to a segfault in multicard situations */ + I2CPtr->I2CAddress = I2CAddress; + + if (device->card_type < NV_50) { + I2CPtr->I2CPutBits = nvclock_i2c_put_bits; + I2CPtr->I2CGetBits = nvclock_i2c_get_bits; + I2CPtr->AcknTimeout = 5; + } + else { + I2CPtr->I2CPutBits = nvclock_nv50_i2c_put_bits; + I2CPtr->I2CGetBits = nvclock_nv50_i2c_get_bits; + I2CPtr->AcknTimeout = 40; + } + I2CPtr->DriverPrivate.val = bus; + I2CPtr->card = device; + + if (!xf86I2CBusInit(I2CPtr)) + return 0; + + return I2CPtr; +} + +I2CDevPtr nvclock_i2c_probe_device(I2CBusPtr bus, I2CSlaveAddr addr, const char *format, ...) +{ + char *s; + va_list ap; + + if(xf86I2CProbeAddress(bus, addr)) + { + I2CDevPtr dev = xf86CreateI2CDevRec(); + s = (char*)IOMalloc(8); + va_start (ap, format); + vsnprintf (s, 7, format, ap); + va_end (ap); + dev->DevName = s; + dev->SlaveAddr = addr; + dev->pI2CBus = bus; + + if (!xf86I2CDevInit(dev)) + { + IOFree(dev->DevName, 8); + xf86DestroyI2CDevRec(dev, TRUE); + + return NULL; + } + + return dev; + } + + return NULL; +} + +void nvclock_i2c_probe_all_devices(I2CBusPtr busses[], int nbus) +{ + I2CSlaveAddr addr; + int bus; + for (bus = 0; bus < nbus; bus++) + { + for (addr = 0x00; addr < 0x100; addr += 2) + { + nvclock_i2c_probe_device(busses[bus], addr, "%1i:%02X", bus, addr); + } + } +} + +I2CDevPtr nvclock_i2c_probe_devices(nouveau_device *device, I2CBusPtr busses[], int num_busses) +{ + int bus; + I2CDevPtr dev; + + nv_debug(device, "probing I2C busses...\n"); + + /* Unlock the extended CRTC registers to get i2c working */ + nvclock_i2c_lock_unlock(device, 0); + + /* On NV40 cards the i2c busses can be disabled */ + if(device->card_type == NV_40) + { + volatile unsigned char *PCIO = (volatile unsigned char*)(device->mmio->getVirtualAddress() + 0x00601000); + PCIO[0x3d4] = 0x49; + PCIO[0x3d5] |= 0x4; /* Unlock the i2c busses */ + } + + nvclock_i2c_probe_all_devices(busses, num_busses); + + for(bus = 0; bus < num_busses; bus++) + { + for(dev = busses[bus]->FirstDev; dev; dev = dev->NextDev) + { + nv_debug(dev->pI2CBus->card, "got response on bus:%s port:0x%x\n", busses[bus]->BusName, dev->SlaveAddr / 2); + + dev->arch = dev->pI2CBus->card->chipset; + + switch(dev->SlaveAddr / 2) + { + case 0x2d: + if(w83l785r_detect(dev)) + return dev; + if(w83781d_detect(dev)) + return dev; + break; + case 0x2e: + if(f75375_detect(dev)) + return dev; + if(adt7473_detect(dev)) + return dev; + break; + case 0x4c: + if(lm99_detect(dev)) + return dev; + break; + default: + /* Unknown device */ + break; + } + } + } + + nvclock_i2c_lock_unlock(device, 1); + + return NULL; +} + +bool nvclock_i2c_sensor_init(nouveau_device *device) +{ + int num_busses = 0; + I2CBusPtr busses[4]; + + struct nouveau_i2c_port *port = NULL; + + for (int i = 0; i <= 4; i++) { + if ((port = nouveau_i2c_find(&device->i2c, NV_I2C_DEFAULT(i)))) { + char name[16]; + + snprintf(name, 16, "NV_I2C_DEFAULT%X", i); + + busses[num_busses++] = nvclock_i2c_create_bus_ptr(device, STRDUP(name, sizeof(name)), port->drive); + } + } + + if (num_busses > 0) { + device->nvclock_i2c_sensor = nvclock_i2c_probe_devices(device, busses, num_busses); + + /* When a sensor is available, enable the correct function pointers */ + if(device->nvclock_i2c_sensor) { + nv_info(device, "found %s monitoring chip\n", device->nvclock_i2c_sensor->chip_name); + + switch(device->nvclock_i2c_sensor->chip_id) + { + case LM99: + case MAX6559: + device->board_temp_get = lm99_get_board_temp; + device->core_temp_get = lm99_get_gpu_temp; + break; + case F75375: + device->board_temp_get = f75375_get_board_temp; + device->core_temp_get = f75375_get_gpu_temp; + device->fan_rpm_get = f75375_get_fanspeed_rpm; + device->fan_pwm_get = f75375_get_fanspeed_pwm; + break; + case W83781D: + device->board_temp_get = w83781d_get_board_temp; + device->core_temp_get = w83781d_get_gpu_temp; + //nv_card->get_i2c_fanspeed_rpm = w83781d_get_fanspeed_rpm; + //nv_card->get_i2c_fanspeed_pwm = w83781d_get_fanspeed_pwm; + break; + case W83L785R: + device->board_temp_get = w83l785r_get_board_temp; + device->core_temp_get = w83l785r_get_gpu_temp; + device->fan_rpm_get = w83l785r_get_fanspeed_rpm; + device->fan_pwm_get = w83l785r_get_fanspeed_pwm; + break; + case ADT7473: + device->board_temp_get = adt7473_get_board_temp; + device->core_temp_get = adt7473_get_gpu_temp; + device->fan_rpm_get = adt7473_get_fanspeed_rpm; + device->fan_pwm_get = adt7473_get_fanspeed_pwm; + break; + default: + break; + } + } + + return true; + } + + return false; +} + diff --git a/plugins/GPUSensors/GeforceSensors/nvclock_i2c.h b/plugins/GPUSensors/GeforceSensors/nvclock_i2c.h new file mode 100755 index 0000000..f1ebdbc --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nvclock_i2c.h @@ -0,0 +1,97 @@ +// +// i2c.h +// HWSensors +// +// Created by Kozlek on 31.07.12. +// +// + +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2005 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef HWSensors_i2c_h +#define HWSensors_i2c_h + +#include "xf86i2c.h" + +#define LM99 0x1 +#define MAX6559 0x2 +#define F75375 0x4 +#define W83L785R 0x8 +#define W83781D 0x16 +#define ADT7473 0x32 + +struct nouveau_device; + +Bool I2CAddress(I2CDevPtr d, I2CSlaveAddr addr); + +void nvclock_i2c_lock_unlock(nouveau_device *device, int lock); +void nvclock_i2c_get_bits(I2CBusPtr b, int *clock, int *data); +void nvclock_i2c_put_bits(I2CBusPtr b, int clock, int data); +void nvclock_nv50_i2c_get_bits(I2CBusPtr bus, int *clock, int *data); +void nvclock_nv50_i2c_put_bits(I2CBusPtr bus, int clock, int data); +I2CBusPtr nvclock_i2c_create_bus_ptr(nouveau_device *device, char *name, int bus); +I2CDevPtr nvclock_i2c_probe_device (I2CBusPtr bus, I2CSlaveAddr addr, const char *format, ...); +void nvclock_i2c_probe_all_devices (I2CBusPtr busses[], int nbus); +I2CDevPtr nvclock_i2c_probe_devices(nouveau_device *device, I2CBusPtr busses[], int num_busses); +bool nvclock_i2c_sensor_init(nouveau_device *device); + +/* ADT7473 */ +int adt7473_detect(I2CDevPtr dev); +int adt7473_get_board_temp(nouveau_device *device); +int adt7473_get_gpu_temp(nouveau_device *device); +int adt7473_get_fanspeed_rpm(nouveau_device *device); +int adt7473_get_fanspeed_pwm(nouveau_device *device); +int adt7473_set_fanspeed_pwm(I2CDevPtr dev, float speed); +int adt7473_get_fanspeed_mode(I2CDevPtr dev); +void adt7473_set_fanspeed_mode(I2CDevPtr dev, int mode); + +/* LM99 */ +int lm99_detect(I2CDevPtr dev); +int lm99_get_board_temp(nouveau_device *device); +int lm99_get_gpu_temp(nouveau_device *device); + +/* Fintek F75375 */ +int f75375_detect(I2CDevPtr dev); +int f75375_get_gpu_temp(nouveau_device *device); +int f75375_get_board_temp(nouveau_device *device); +int f75375_get_fanspeed_rpm(nouveau_device *device); +int f75375_set_fanspeed_rpm(I2CDevPtr dev, int desired_rpm); +int f75375_get_fanspeed_pwm(nouveau_device *device); +int f75375_set_fanspeed_pwm(I2CDevPtr dev, float speed); + +/* Winbond W83781D */ +int w83781d_detect(I2CDevPtr dev); +int w83781d_get_board_temp(nouveau_device *device); +int w83781d_get_gpu_temp(nouveau_device *device); +int w83781d_get_fanspeed_rpm(nouveau_device *device); +//int w83781d_get_fanspeed_pwm(nouveau_device *device); +//int w83781d_set_fanspeed_pwm(I2CDevPtr dev, float speed); + +/* Winbond W83L785R */ +int w83l785r_detect(I2CDevPtr dev); +int w83l785r_get_board_temp(nouveau_device *device); +int w83l785r_get_gpu_temp(nouveau_device *device); +int w83l785r_get_fanspeed_rpm(nouveau_device *device); +int w83l785r_get_fanspeed_pwm(nouveau_device *device); +int w83l785r_set_fanspeed_pwm(I2CDevPtr dev, float speed); + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/nvd0.cpp b/plugins/GPUSensors/GeforceSensors/nvd0.cpp new file mode 100755 index 0000000..d6146f9 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nvd0.cpp @@ -0,0 +1,96 @@ +// +// nvd0.cpp +// HWSensors +// +// Created by Kozlek on 11.08.12. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nvd0.h" + +#include "nouveau_definitions.h" +#include "nouveau.h" + +void nvd0_therm_init(struct nouveau_device *device) +{ + /* enable fan tach, count revolutions per-second */ + nv_mask(device, 0x00e720, 0x00000003, 0x00000002); + if (device->fan_tach.func != DCB_GPIO_UNUSED) { + nv_mask(device, 0x00d79c, 0x000000ff, device->fan_tach.line); + nv_wr32(device, 0x00e724, device->crystal * 1000); + nv_mask(device, 0x00e720, 0x00000001, 0x00000001); + } + nv_mask(device, 0x00e720, 0x00000002, 0x00000000); +} + +int nvd0_gpio_sense(struct nouveau_device *device, int line) +{ + u32 gp_sens = nv_rd32(device, 0x00d610 + (line * 4)) & 0x00004000; + nv_debug(device, "nvd0_gpio_sense return 0x%x\n", gp_sens); + return !!gp_sens; +} + +static int pwm_info(struct nouveau_device *device, int line) +{ + u32 gpio = nv_rd32(device, 0x00d610 + (line * 0x04)); + switch (gpio & 0x000000c0) { + case 0x00000000: /* normal mode, possibly pwm forced off by us */ + case 0x00000040: /* nvio special */ + switch (gpio & 0x0000001f) { + case 0x00: return 2; + case 0x19: return 1; + case 0x1c: return 0; + default: + break; + } + default: + break; + } + + nv_error(device, "GPIO %d unknown PWM: 0x%08x\n", line, (unsigned int)gpio); + return -ENODEV; +} + +int nvd0_fan_pwm_get(struct nouveau_device *device, int line, u32 *divs, u32 *duty) +{ + int indx = pwm_info(device, line); + if (indx < 0) { + return indx; + } else if (indx < 2) { + if (nv_rd32(device, 0x00d610 + (line * 0x04)) & 0x00000040) { + *divs = nv_rd32(device, 0x00e114 + (indx * 8)); + *duty = nv_rd32(device, 0x00e118 + (indx * 8)); + return 0; + } + } else if (indx == 2) { + *divs = nv_rd32(device, 0x0200d8) & 0x1fff; + *duty = nv_rd32(device, 0x0200dc) & 0x1fff; + return 0; + } + + return -EINVAL; +} diff --git a/plugins/GPUSensors/GeforceSensors/nvd0.h b/plugins/GPUSensors/GeforceSensors/nvd0.h new file mode 100755 index 0000000..ff1171f --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nvd0.h @@ -0,0 +1,18 @@ +// +// nvd0.h +// HWSensors +// +// Created by Kozlek on 11.08.12. +// +// + +#ifndef __HWSensors__nvd0__ +#define __HWSensors__nvd0__ + +#include "linux_definitions.h" + +void nvd0_therm_init(struct nouveau_device *device); +int nvd0_fan_pwm_get(struct nouveau_device *device, int line, u32 *divs, u32 *duty); +int nvd0_gpio_sense(struct nouveau_device *device, int line); + +#endif /* defined(__HWSensors__nvd0__) */ diff --git a/plugins/GPUSensors/GeforceSensors/nve0.cpp b/plugins/GPUSensors/GeforceSensors/nve0.cpp new file mode 100755 index 0000000..d1ff15d --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nve0.cpp @@ -0,0 +1,244 @@ +// +// nve0.c +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nouveau.h" +#include "nv50.h" +#include "nva3.h" +#include "nv84.h" +#include "nvc0.h" +#include "nve0.h" +#include "nvd0.h" +#include "nouveau_therm.h" + +bool nve0_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0xe4: + device->cname = "GK104"; + break; + case 0xe6: + device->cname = "GK106"; + break; + case 0xe7: + device->cname = "GK107"; + break; + case 0xf0: + device->cname = "GK110"; + break; + case 0xf1: + device->cname = "GK110B"; + break; + case 0x106: + case 0x108: + device->cname = "GK208"; + break; + default: + nv_fatal(device, "unknown Kepler chipset 0x%x\n", (unsigned int)device->chipset); + return false; + } + + return true; +} + + + +void nve0_init(struct nouveau_device *device) +{ + nvd0_therm_init(device); + + device->gpio_sense = nvd0_gpio_sense; + device->gpio_find = nouveau_gpio_find; + device->gpio_get = nouveau_gpio_get; + // device->gpio_sense = nvd0_gpio_sense; + device->temp_get = nv84_temp_get; + device->clocks_get = nve0_clock_read; + // device->voltage_get = nouveau_voltage_get; + device->pwm_get = nvd0_fan_pwm_get; + device->fan_pwm_get = nouveau_therm_fan_pwm_get; + device->fan_rpm_get = nva3_therm_fan_sense; +} + +static u32 read_div(struct nouveau_device *, int, u32, u32); +static u32 read_pll(struct nouveau_device *, u32); + +static u32 read_vco(struct nouveau_device *device, u32 dsrc) +{ + u32 ssrc = nv_rd32(device, dsrc); + if (!(ssrc & 0x00000100)) + return read_pll(device, 0x00e800); + return read_pll(device, 0x00e820); +} + +static u32 read_pll(struct nouveau_device *device, u32 pll) +{ + u32 ctrl = nv_rd32(device, pll + 0x00); + u32 coef = nv_rd32(device, pll + 0x04); + u32 P = (coef & 0x003f0000) >> 16; + u32 N = (coef & 0x0000ff00) >> 8; + u32 M = (coef & 0x000000ff) >> 0; + u32 sclk; + u16 fN = 0xf000; + + if (!(ctrl & 0x00000001)) + return 0; + + switch (pll) { + case 0x00e800: + case 0x00e820: + sclk = device->crystal; + P = 1; + break; + case 0x132000: + sclk = read_pll(device, 0x132020); + P = (coef & 0x10000000) ? 2 : 1; + break; + case 0x132020: + sclk = read_div(device, 0, 0x137320, 0x137330); + fN = nv_rd32(device, pll + 0x10) >> 16; + break; + case 0x137000: + case 0x137020: + case 0x137040: + case 0x1370e0: + sclk = read_div(device, (pll & 0xff) / 0x20, 0x137120, 0x137140); + break; + default: + return 0; + } + + if (P == 0) + P = 1; + + sclk = (sclk * N) + (((u16)(fN + 4096) * sclk) >> 13); + return sclk / (M * P); +} + +static u32 read_div(struct nouveau_device *device, int doff, u32 dsrc, u32 dctl) +{ + u32 ssrc = nv_rd32(device, dsrc + (doff * 4)); + u32 sctl = nv_rd32(device, dctl + (doff * 4)); + + switch (ssrc & 0x00000003) { + case 0: + if ((ssrc & 0x00030000) != 0x00030000) + return device->crystal; + return 108000; + case 2: + return 100000; + case 3: + if (sctl & 0x80000000) { + u32 sclk = read_vco(device, dsrc + (doff * 4)); + u32 sdiv = (sctl & 0x0000003f) + 2; + return (sclk * 2) / sdiv; + } + + return read_vco(device, dsrc + (doff * 4)); + default: + return 0; + } +} + +static u32 read_mem(struct nouveau_device *device) +{ + switch (nv_rd32(device, 0x1373f4) & 0x0000000f) { + case 1: return read_pll(device, 0x132020); + case 2: return read_pll(device, 0x132000); + default: + return 0; + } +} + +static u32 read_clk(struct nouveau_device *device, int clk) +{ + u32 sctl = nv_rd32(device, 0x137250 + (clk * 4)); + u32 sclk, sdiv; + + if (clk < 7) { + u32 ssel = nv_rd32(device, 0x137100); + if (ssel & (1 << clk)) { + sclk = read_pll(device, 0x137000 + (clk * 0x20)); + sdiv = 1; + } else { + sclk = read_div(device, clk, 0x137160, 0x1371d0); + sdiv = 0; + } + } else { + u32 ssrc = nv_rd32(device, 0x137160 + (clk * 0x04)); + if ((ssrc & 0x00000003) == 0x00000003) { + sclk = read_div(device, clk, 0x137160, 0x1371d0); + if (ssrc & 0x00000100) { + if (ssrc & 0x40000000) + sclk = read_pll(device, 0x1370e0); + sdiv = 1; + } else { + sdiv = 0; + } + } else { + sclk = read_div(device, clk, 0x137160, 0x1371d0); + sdiv = 0; + } + } + + if (sctl & 0x80000000) { + if (sdiv) + sdiv = ((sctl & 0x00003f00) >> 8) + 2; + else + sdiv = ((sctl & 0x0000003f) >> 0) + 2; + return (sclk * 2) / sdiv; + } + + return sclk; +} + +int nve0_clock_read(struct nouveau_device *device, u8 source) +{ + switch (source) { + case nouveau_clock_memory: + return read_mem(device) * 2; + case nouveau_clock_core: + return read_clk(device, 0x00) / 2; + case nouveau_clock_rop: + return read_clk(device, 0x01) / 2; + // case nv_clk_src_hubk07: + // return read_clk(device, 0x02); + // case nv_clk_src_hubk06: + // return read_clk(device, 0x07); + // case nv_clk_src_hubk01: + // return read_clk(device, 0x08); + // case nv_clk_src_daemon: + // return read_clk(device, 0x0c); + // case nv_clk_src_vdec: + // return read_clk(device, 0x0e); + } + + return 0; +} diff --git a/plugins/GPUSensors/GeforceSensors/nve0.h b/plugins/GPUSensors/GeforceSensors/nve0.h new file mode 100755 index 0000000..923d80b --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/nve0.h @@ -0,0 +1,16 @@ +// +// nve0.h +// HWSensors +// +// Created by Kozlek on 07.08.12. +// +// + +#ifndef HWSensors_nve0_h +#define HWSensors_nve0_h + +bool nve0_identify(struct nouveau_device *device); +void nve0_init(struct nouveau_device *device); +int nve0_clock_read(struct nouveau_device *device, u8 source); + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/timer.h b/plugins/GPUSensors/GeforceSensors/timer.h new file mode 100755 index 0000000..48b860f --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/timer.h @@ -0,0 +1,30 @@ +// +// timer.h +// HWSensors +// +// Created by Kozlek on 28.09.12. +// +// + +#ifndef HWSensors_timer_h +#define HWSensors_timer_h + +#include + +static UInt64 ptimer_read() +{ + clock_sec_t secs; + clock_nsec_t nanosecs; + + clock_get_calendar_nanotime(&secs, &nanosecs); + + return (UInt64)secs * (UInt64)NSEC_PER_SEC + (UInt64)nanosecs; +// uint64_t uptime, nanoseconds; +// +// clock_get_uptime(&uptime); +// absolutetime_to_nanoseconds(uptime, &nanoseconds); +// +// return nanoseconds; +} + +#endif diff --git a/plugins/GPUSensors/GeforceSensors/vga.cpp b/plugins/GPUSensors/GeforceSensors/vga.cpp new file mode 100755 index 0000000..9ac74de --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/vga.cpp @@ -0,0 +1,225 @@ +// +// vga.cpp +// HWSensors +// +// Created by Kozlek on 13.08.12. +// +// + +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "vga.h" + +#include "nouveau.h" + +#define nv_device(obj) ((struct nouveau_device *)obj) + +u8 +nv_rdport(void *obj, int head, u16 port) +{ + struct nouveau_device *device = nv_device(obj); + + if (device->card_type >= NV_50) + return nv_rd08(device, 0x601000 + port); + + if (port == 0x03c0 || port == 0x03c1 || /* AR */ + port == 0x03c2 || port == 0x03da || /* INP0 */ + port == 0x03d4 || port == 0x03d5) /* CR */ + return nv_rd08(device, 0x601000 + (head * 0x2000) + port); + + if (port == 0x03c2 || port == 0x03cc || /* MISC */ + port == 0x03c4 || port == 0x03c5 || /* SR */ + port == 0x03ce || port == 0x03cf) { /* GR */ + if (device->card_type < NV_40) + head = 0; /* CR44 selects head */ + return nv_rd08(device, 0x0c0000 + (head * 0x2000) + port); + } + + nv_error(device, "unknown vga port 0x%04x\n", port); + return 0x00; +} + +void +nv_wrport(void *obj, int head, u16 port, u8 data) +{ + struct nouveau_device *device = nv_device(obj); + + if (device->card_type >= NV_50) + nv_wr08(device, 0x601000 + port, data); + else + if (port == 0x03c0 || port == 0x03c1 || /* AR */ + port == 0x03c2 || port == 0x03da || /* INP0 */ + port == 0x03d4 || port == 0x03d5) /* CR */ + nv_wr08(device, 0x601000 + (head * 0x2000) + port, data); + else + if (port == 0x03c2 || port == 0x03cc || /* MISC */ + port == 0x03c4 || port == 0x03c5 || /* SR */ + port == 0x03ce || port == 0x03cf) { /* GR */ + if (device->card_type < NV_40) + head = 0; /* CR44 selects head */ + nv_wr08(device, 0x0c0000 + (head * 0x2000) + port, data); + } else + nv_error(device, "unknown vga port 0x%04x\n", port); +} + +u8 +nv_rdvgas(void *obj, int head, u8 index) +{ + nv_wrport(obj, head, 0x03c4, index); + return nv_rdport(obj, head, 0x03c5); +} + +void +nv_wrvgas(void *obj, int head, u8 index, u8 value) +{ + nv_wrport(obj, head, 0x03c4, index); + nv_wrport(obj, head, 0x03c5, value); +} + +u8 +nv_rdvgag(void *obj, int head, u8 index) +{ + nv_wrport(obj, head, 0x03ce, index); + return nv_rdport(obj, head, 0x03cf); +} + +void +nv_wrvgag(void *obj, int head, u8 index, u8 value) +{ + nv_wrport(obj, head, 0x03ce, index); + nv_wrport(obj, head, 0x03cf, value); +} + +u8 +nv_rdvgac(void *obj, int head, u8 index) +{ + nv_wrport(obj, head, 0x03d4, index); + return nv_rdport(obj, head, 0x03d5); +} + +void +nv_wrvgac(void *obj, int head, u8 index, u8 value) +{ + nv_wrport(obj, head, 0x03d4, index); + nv_wrport(obj, head, 0x03d5, value); +} + +u8 +nv_rdvgai(void *obj, int head, u16 port, u8 index) +{ + if (port == 0x03c4) return nv_rdvgas(obj, head, index); + if (port == 0x03ce) return nv_rdvgag(obj, head, index); + if (port == 0x03d4) return nv_rdvgac(obj, head, index); + nv_error(nv_device(obj), "unknown indexed vga port 0x%04x\n", port); + return 0x00; +} + +void +nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value) +{ + if (port == 0x03c4) nv_wrvgas(obj, head, index, value); + else if (port == 0x03ce) nv_wrvgag(obj, head, index, value); + else if (port == 0x03d4) nv_wrvgac(obj, head, index, value); + else nv_error(nv_device(obj), "unknown indexed vga port 0x%04x\n", port); +} + +bool +nv_lockvgac(void *obj, bool lock) +{ + bool locked = !nv_rdvgac(obj, 0, 0x1f); + u8 data = lock ? 0x99 : 0x57; + nv_wrvgac(obj, 0, 0x1f, data); + if (nv_device(obj)->chipset == 0x11) { + if (!(nv_rd32(nv_device(obj), 0x001084) & 0x10000000)) + nv_wrvgac(obj, 1, 0x1f, data); + } + return locked; +} + +/* CR44 takes values 0 (head A), 3 (head B) and 4 (heads tied) + * it affects only the 8 bit vga io regs, which we access using mmio at + * 0xc{0,2}3c*, 0x60{1,3}3*, and 0x68{1,3}3d* + * in general, the set value of cr44 does not matter: reg access works as + * expected and values can be set for the appropriate head by using a 0x2000 + * offset as required + * however: + * a) pre nv40, the head B range of PRMVIO regs at 0xc23c* was not exposed and + * cr44 must be set to 0 or 3 for accessing values on the correct head + * through the common 0xc03c* addresses + * b) in tied mode (4) head B is programmed to the values set on head A, and + * access using the head B addresses can have strange results, ergo we leave + * tied mode in init once we know to what cr44 should be restored on exit + * + * the owner parameter is slightly abused: + * 0 and 1 are treated as head values and so the set value is (owner * 3) + * other values are treated as literal values to set + */ +u8 +nv_rdvgaowner(void *obj) +{ + if (nv_device(obj)->card_type < NV_50) { + if (nv_device(obj)->chipset == 0x11) { + u32 tied = nv_rd32((struct nouveau_device*)obj, 0x001084) & 0x10000000; + if (tied == 0) { + u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80; + u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01; + u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80; + u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01; + if (slA && !tvA) return 0x00; + if (slB && !tvB) return 0x03; + if (slA) return 0x00; + if (slB) return 0x03; + return 0x00; + } + return 0x04; + } + + return nv_rdvgac(obj, 0, 0x44); + } + + nv_error(nv_device(obj), "rdvgaowner after nv4x\n"); + return 0x00; +} + +void +nv_wrvgaowner(void *obj, u8 select) +{ + if (nv_device(obj)->card_type < NV_50) { + u8 owner = (select == 1) ? 3 : select; + if (nv_device(obj)->chipset == 0x11) { + /* workaround hw lockup bug */ + nv_rdvgac(obj, 0, 0x1f); + nv_rdvgac(obj, 1, 0x1f); + } + + nv_wrvgac(obj, 0, 0x44, owner); + + if (nv_device(obj)->chipset == 0x11) { + nv_wrvgac(obj, 0, 0x2e, owner); + nv_wrvgac(obj, 0, 0x2e, owner); + } + } else + nv_error(nv_device(obj), "wrvgaowner after nv4x\n"); +} diff --git a/plugins/GPUSensors/GeforceSensors/vga.h b/plugins/GPUSensors/GeforceSensors/vga.h new file mode 100755 index 0000000..6922f7d --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/vga.h @@ -0,0 +1,38 @@ +// +// vga.h +// HWSensors +// +// Created by Kozlek on 13.08.12. +// +// + +#ifndef __HWSensors__vga__ +#define __HWSensors__vga__ + +#include "nouveau_definitions.h" + +/* access to various legacy io ports */ +u8 nv_rdport(void *obj, int head, u16 port); +void nv_wrport(void *obj, int head, u16 port, u8 value); + +/* VGA Sequencer */ +u8 nv_rdvgas(void *obj, int head, u8 index); +void nv_wrvgas(void *obj, int head, u8 index, u8 value); + +/* VGA Graphics */ +u8 nv_rdvgag(void *obj, int head, u8 index); +void nv_wrvgag(void *obj, int head, u8 index, u8 value); + +/* VGA CRTC */ +u8 nv_rdvgac(void *obj, int head, u8 index); +void nv_wrvgac(void *obj, int head, u8 index, u8 value); + +/* VGA indexed port access dispatcher */ +u8 nv_rdvgai(void *obj, int head, u16 port, u8 index); +void nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value); + +bool nv_lockvgac(void *obj, bool lock); +u8 nv_rdvgaowner(void *obj); +void nv_wrvgaowner(void *obj, u8); + +#endif /* defined(__HWSensors__vga__) */ diff --git a/plugins/GPUSensors/GeforceSensors/w83781d.cpp b/plugins/GPUSensors/GeforceSensors/w83781d.cpp new file mode 100755 index 0000000..a30f997 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/w83781d.cpp @@ -0,0 +1,83 @@ +/* NVClock Winbond W83781D hardware monitoring + */ +//#include +#include +#include +#include "nvclock_i2c.h" +//#include "nvclock.h" + + +/* various defines for register offsets and such are needed */ + +#define W83781D_REG_LOCAL_TEMP 0x27 +#define W83781D_REG_REMOTE_TEMP 0x27 +#define W83781D_REG_FAN1_COUNT 0x28 +#define W83781D_REG_MAN_ID 0x4f +#define ASUS_MAN_ID 0x12 +#define W83781D_MAN_ID 0x5c +#define W83781D_REG_CHIP_ID 0x58 +#define W83781D_REG_FAN_DIVISOR 0x47 + +/* This function should return the chip type .. */ +int w83781d_detect(I2CDevPtr dev) +{ + I2CByte man_id, chip_id; + + xf86I2CReadByte (dev, W83781D_REG_MAN_ID, &man_id); + xf86I2CReadByte (dev, W83781D_REG_CHIP_ID, &chip_id); + + switch(man_id) + { + case ASUS_MAN_ID: + case W83781D_MAN_ID: + /* We still need a chip_id check (0x11 for w83781d) */ + dev->chip_id = W83781D; + dev->chip_name = (char*)STRDUP("Winbond W83781D", sizeof("Winbond W83781D")); + break; + default: + //IOLog("Uknown Winbond vendor: %x\n", man_id); + return 0; + } + return 1; +} + +int w83781d_get_board_temp(nouveau_device *device) +{ + I2CByte temp; + xf86I2CReadByte(device->nvclock_i2c_sensor, W83781D_REG_LOCAL_TEMP, &temp); + return temp; +} + +/* only one temperature exists ... */ +int w83781d_get_gpu_temp(nouveau_device *device) +{ + I2CByte temp; + xf86I2CReadByte(device->nvclock_i2c_sensor, W83781D_REG_REMOTE_TEMP, &temp); + return temp; +} + +int w83781d_get_fanspeed_rpm(nouveau_device *device) +{ + I2CByte count, divisor; + + xf86I2CReadByte(device->nvclock_i2c_sensor, W83781D_REG_FAN1_COUNT, &count); + xf86I2CReadByte(device->nvclock_i2c_sensor, W83781D_REG_FAN_DIVISOR, &divisor); + divisor = 1 << ((divisor >> 4) & 0x3); /* bit 5:4 are for fan1; a value of 0 means a divider of 1, while 2 means 2^3 = 8 */ + + /* A count of 0xff indicates that something is wrong i.e. no fan is connected */ + if(count == 0xff) + return 0; + + return 1350000/(count * divisor); +} + +//int w83781d_get_fanspeed_pwm(nouveau_device *device) +//{ +// return 0; +//} + +//int w83781d_set_fanspeed_pwm(I2CDevPtr dev, float speed) +//{ +// return 0; +//} + diff --git a/plugins/GPUSensors/GeforceSensors/w83l785r.cpp b/plugins/GPUSensors/GeforceSensors/w83l785r.cpp new file mode 100755 index 0000000..fbc2a36 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/w83l785r.cpp @@ -0,0 +1,123 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2005 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * W83L785R hardware monitoring + */ +#include +#include "nvclock_i2c.h" +//#include "nvclock.h" + + +/* various defines for register offsets and such are needed */ + +#define W83L785R_REG_LOCAL_TEMP 0x26 +#define W83L785R_REG_LOCAL_TEMP_OFFSET 0x85 +#define W83L785R_REG_REMOTE_TEMP 0x27 +#define W83L785R_REG_REMOTE_TEMP_OFFSET 0x86 + +#define W83L785R_REG_FAN1_COUNT 0x28 +#define W83L785R_REG_FAN2_COUNT 0x29 +#define W83L785R_REG_FAN_DIVISOR 0x47 /* bit 2-0 for fan1; bit 6-4 for fan2 */ + +#define W83L785R_REG_MAN_ID_L 0x4c +#define W83L785R_REG_MAN_ID_H 0x4d +#define W83L785R_REG_CHIP_ID 0x4e + +#define W83L785R_REG_FAN1_PWM 0x81 +#define W83L785R_REG_FAN2_PWM 0x83 + +/* This function should return the chip type .. */ +int w83l785r_detect(I2CDevPtr dev) +{ + I2CByte man_id_l, man_id_h, chip_id; + + xf86I2CReadByte(dev, W83L785R_REG_MAN_ID_L, &man_id_l); + xf86I2CReadByte(dev, W83L785R_REG_MAN_ID_H, &man_id_h); + xf86I2CReadByte(dev, W83L785R_REG_CHIP_ID, &chip_id); + + /* Winbond chip */ + if((man_id_l == 0xa3) && (man_id_h == 0x5c)) + { + if((chip_id & 0xfe) == 0x60) + { + dev->chip_id = W83L785R; + dev->chip_name = (char*)STRDUP("Winbond W83L785R", sizeof("Winbond W83L785R")); + return 1; + } + } + + return 0; +} + +int w83l785r_get_board_temp(nouveau_device *device) +{ + I2CByte temp, offset; + xf86I2CReadByte(device->nvclock_i2c_sensor, W83L785R_REG_LOCAL_TEMP, &temp); + xf86I2CReadByte(device->nvclock_i2c_sensor, W83L785R_REG_LOCAL_TEMP_OFFSET, &offset); + return temp + offset; +} + +int w83l785r_get_gpu_temp(nouveau_device *device) +{ + I2CByte temp, offset; + xf86I2CReadByte(device->nvclock_i2c_sensor, W83L785R_REG_REMOTE_TEMP, &temp); + xf86I2CReadByte(device->nvclock_i2c_sensor, W83L785R_REG_REMOTE_TEMP_OFFSET, &offset); + return temp + offset; +} + +int w83l785r_get_fanspeed_rpm(nouveau_device *device) +{ + I2CByte count, divisor; + + xf86I2CReadByte(device->nvclock_i2c_sensor, W83L785R_REG_FAN1_COUNT, &count); + xf86I2CReadByte(device->nvclock_i2c_sensor, W83L785R_REG_FAN_DIVISOR, &divisor); + divisor &= 0x7; + + /* By default count useally is 153, it seems that a value of 255 means that something is wrong. + / For example it retuns this value on boards on which the fan is replaced with a heatpipe and because + / of that the fan was removed. + */ + if(count == 0xff) + return 0; + + return 1350000/(count * (1<nvclock_i2c_sensor, W83L785R_REG_FAN1_PWM, &value); + return (float)(0xff-value)*100/256; +} + +int w83l785r_set_fanspeed_pwm(I2CDevPtr dev, float speed) +{ + /* We have 8 bits to adjust the duty cycle, to set a speed of 100% we need to write a value of 0 + / as the register is inverted. (0 means 100% and 0xff means 0) + / + / Below we scale the speed (in %) with 255/100 to turn '100%' into the max value 255. + */ + I2CByte value = (100 - (int)speed) * 255/100; + + xf86I2CWriteByte(dev, W83L785R_REG_FAN1_PWM, value); + xf86I2CReadByte(dev, W83L785R_REG_FAN1_PWM, &value); + return 1; +} diff --git a/plugins/GPUSensors/GeforceSensors/xf86i2c.cpp b/plugins/GPUSensors/GeforceSensors/xf86i2c.cpp new file mode 100755 index 0000000..ba6042d --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/xf86i2c.cpp @@ -0,0 +1,851 @@ +/* + * Copyright (C) 1998 Itai Nahshon, Michael Schimek + * + * The original code was derived from and inspired by + * the I2C driver from the Linux kernel. + * (c) 1998 Gerd Knorr + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/i2c/xf86i2c.c,v 1.6 1999/06/12 15:37:08 dawes Exp $ */ + +#include + +#include "xfree.h" +#include "xf86i2c.h" + +#include "nouveau_definitions.h" + +#define I2C_TIMEOUT(x, args...) /*(x)*/ /* Report timeouts */ +#define I2C_TRACE(x, args...) /*(x)*/ /* Report progress */ + +void xf86getsecs(long * secs, long * usecs) +{ + clock_sec_t sec; + clock_usec_t usec; + + clock_get_system_microtime(&sec, &usec); + + *secs = sec; + *usecs= usec; + + return; +} + +/* This is the default I2CUDelay function if not supplied by the driver. + * High level I2C interfaces implementing the bus protocol in hardware + * should supply this function too. + * + * Delay execution at least usec microseconds. + * All values 0 to 1e6 inclusive must be expected. + */ + +static void +I2CUDelay(I2CBusPtr b, int usec) +{ + long b_secs, b_usecs; + long a_secs, a_usecs; + + if (usec > 0) { + long d_secs, d_usecs; + long diff; + + xf86getsecs(&b_secs, &b_usecs); + do { + /* It would be nice to use {xf86}usleep, + * but usleep (1) takes >10000 usec ! + */ + IOPause(500); + + xf86getsecs(&a_secs, &a_usecs); + d_secs = (a_secs - b_secs); + d_usecs = (a_usecs - b_usecs); + diff = d_secs*1000000 + d_usecs; + } while (diff>0 && diff< (usec + 1)); + } + +} + +/* Most drivers will register just with GetBits/PutBits functions. + * The following functions implement a software I2C protocol + * by using the promitive functions given by the driver. + * ================================================================ + * + * It is assumed that there is just one master on the I2C bus, therefore + * there is no explicit test for conflits. + */ + +#define RISEFALLTIME 2 /* usec, actually 300 to 1000 ns according to the i2c specs */ + +/* Some devices will hold SCL low to slow down the bus or until + * ready for transmission. + * + * This condition will be noticed when the master tries to raise + * the SCL line. You can set the timeout to zero if the slave device + * does not support this clock synchronization. + */ + +static Bool +I2CRaiseSCL(I2CBusPtr b, int sda, int timeout) +{ + int i, scl; + + b->I2CPutBits(b, 1, sda); + b->I2CUDelay(b, b->RiseFallTime); + + for (i = timeout; i > 0; i -= b->RiseFallTime) { + b->I2CGetBits(b, &scl, &sda); + if (scl) break; + b->I2CUDelay(b, b->RiseFallTime); + } + + if (i <= 0) { + I2C_TIMEOUT(IOLog("[I2CRaiseSCL(<%s>, %d, %d) timeout]\n", b->BusName, sda, timeout)); + return FALSE; + } + + return TRUE; +} + +/* Send a start signal on the I2C bus. The start signal notifies + * devices that a new transaction is initiated by the bus master. + * + * The start signal is always followed by a slave address. + * Slave addresses are 8+ bits. The first 7 bits identify the + * device and the last bit signals if this is a read (1) or + * write (0) operation. + * + * There may be more than one start signal on one transaction. + * This happens for example on some devices that allow reading + * of registers. First send a start bit followed by the device + * address (with the last bit 0) and the register number. Then send + * a new start bit with the device address (with the last bit 1) + * and then read the value from the device. + * + * Note this is function does not implement a multiple master + * arbitration procedure. + */ + +static Bool +I2CStart(I2CBusPtr b, int timeout) +{ + int i, scl, sda; + b->I2CPutBits(b, 1, 1); + b->I2CUDelay(b, b->RiseFallTime); + + for (i = timeout; i > 0; i -= b->RiseFallTime) { + b->I2CGetBits(b, &scl, &sda); + if (scl) break; + b->I2CUDelay(b, b->RiseFallTime); + } + + if (i <= 0) { + I2C_TIMEOUT(IOLog("\ni2c: <[I2CStart(<%s>, %d) timeout]", b->BusName, timeout)); + return FALSE; + } + + b->I2CPutBits(b, 1, 0); + b->I2CUDelay(b, b->HoldTime); + b->I2CPutBits(b, 0, 0); + b->I2CUDelay(b, b->HoldTime); + + I2C_TRACE(b->device, "\ni2c: <"); + + return TRUE; +} + +/* This is the default I2CStop function if not supplied by the driver. + * + * Signal devices on the I2C bus that a transaction on the + * bus has finished. There may be more than one start signal + * on a transaction but only one stop signal. + */ + +static void +I2CStop(I2CDevPtr d) +{ + I2CBusPtr b = d->pI2CBus; + + b->I2CPutBits(b, 0, 0); + b->I2CUDelay(b, b->RiseFallTime); + + b->I2CPutBits(b, 1, 0); + b->I2CUDelay(b, b->HoldTime); + b->I2CPutBits(b, 1, 1); + b->I2CUDelay(b, b->HoldTime); + + I2C_TRACE(IOLog(">")); +} + +/* Write/Read a single bit to/from a device. + * Return FALSE if a timeout occurs. + */ + +static Bool +I2CWriteBit(I2CBusPtr b, int sda, int timeout) +{ + Bool r; + + b->I2CPutBits(b, 0, sda); + b->I2CUDelay(b, b->RiseFallTime); + + r = I2CRaiseSCL(b, sda, timeout); + b->I2CUDelay(b, b->HoldTime); + + b->I2CPutBits(b, 0, sda); + b->I2CUDelay(b, b->HoldTime); + + return r; +} + +static Bool +I2CReadBit(I2CBusPtr b, int *psda, int timeout) +{ + Bool r; + int scl; + + r = I2CRaiseSCL(b, 1, timeout); + b->I2CUDelay(b, b->HoldTime); + + b->I2CGetBits(b, &scl, psda); + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->HoldTime); + + return r; +} + +/* This is the default I2CPutByte function if not supplied by the driver. + * + * A single byte is sent to the device. + * The function returns FALSE if a timeout occurs, you should send + * a stop condition afterwards to reset the bus. + * + * A timeout occurs, + * if the slave pulls SCL to slow down the bus more than ByteTimeout usecs, + * or slows down the bus for more than BitTimeout usecs for each bit, + * or does not send an ACK bit (0) to acknowledge the transmission within + * AcknTimeout usecs, but a NACK (1) bit. + * + * AcknTimeout must be at least b->HoldTime, the other timeouts can be + * zero according to the comment on I2CRaiseSCL. + */ + +static Bool +I2CPutByte(I2CDevPtr d, I2CByte data) +{ + Bool r; + int i, scl, sda; + I2CBusPtr b = d->pI2CBus; + + if (!I2CWriteBit(b, (data >> 7) & 1, d->ByteTimeout)) + return FALSE; + + for (i = 6; i >= 0; i--) + if (!I2CWriteBit(b, (data >> i) & 1, d->BitTimeout)) + return FALSE; + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->RiseFallTime); + + r = I2CRaiseSCL(b, 1, b->HoldTime); + + if (r) { + for (i = d->AcknTimeout; i > 0; i -= b->HoldTime) { + b->I2CUDelay(b, b->HoldTime); + b->I2CGetBits(b, &scl, &sda); + if (sda == 0) break; + } + + if (i <= 0) { + I2C_TIMEOUT(IOLog("[I2CPutByte(<%s>, 0x%02x, %d, %d, %d) timeout]", + b->BusName, data, d->BitTimeout, + d->ByteTimeout, d->AcknTimeout)); + r = FALSE; + } + + I2C_TRACE(IOLog("W%02x%c ", (int) data, sda ? '-' : '+')); + } + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->HoldTime); + + return r; +} + +/* This is the default I2CGetByte function if not supplied by the driver. + * + * A single byte is read from the device. + * The function returns FALSE if a timeout occurs, you should send + * a stop condition afterwards to reset the bus. + * + * A timeout occurs, + * if the slave pulls SCL to slow down the bus more than ByteTimeout usecs, + * or slows down the bus for more than b->BitTimeout usecs for each bit. + * + * ByteTimeout must be at least b->HoldTime, the other timeouts can be + * zero according to the comment on I2CRaiseSCL. + * + * For the byte in a sequence the acknowledge bit NACK (1), + * otherwise ACK (0) will be sent. + */ + +static Bool +I2CGetByte(I2CDevPtr d, I2CByte *data, Bool last) +{ + int i, sda; + I2CBusPtr b = d->pI2CBus; + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->RiseFallTime); + + if (!I2CReadBit(b, &sda, d->ByteTimeout)) + return FALSE; + + *data = (sda > 0) << 7; + + for (i = 6; i >= 0; i--) + if (!I2CReadBit(b, &sda, d->BitTimeout)) + return FALSE; + else + *data |= (sda > 0) << i; + + if (!I2CWriteBit(b, last ? 1 : 0, d->BitTimeout)) + return FALSE; + + I2C_TRACE(IOLog("R%02x%c ", (int) *data, last ? '+' : '-')); + + return TRUE; +} + +/* This is the default I2CAddress function if not supplied by the driver. + * + * It creates the start condition, followed by the d->SlaveAddr. + * Higher level functions must call this routine rather than + * I2CStart/PutByte because a hardware I2C master may not be able + * to send a slave address without a start condition. + * + * The same timeouts apply as with I2CPutByte and additional a + * StartTimeout, similar to the ByteTimeout but for the start + * condition. + * + * In case of a timeout, the bus is left in a clean idle condition. + * I. e. you *must not* send a Stop. If this function succeeds, you *must*. + * + * The slave address format is 16 bit, with the legacy _8_bit_ slave address + * in the least significant byte. This is, the slave address must include the + * R/_W flag as least significant bit. + * + * The most significant byte of the address will be sent _after_ the LSB, + * but only if the LSB indicates: + * a) an 11 bit address, this is LSB = 1111 0xxx. + * b) a 'general call address', this is LSB = 0000 000x - see the I2C specs + * for more. + */ + +Bool I2CAddress(I2CDevPtr d, I2CSlaveAddr addr) +{ + if (I2CStart(d->pI2CBus, d->StartTimeout)) { + if (I2CPutByte(d, addr & 0xFF)) { + if ((addr & 0xF8) != 0xF0 && + (addr & 0xFE) != 0x00) + return TRUE; + + if (I2CPutByte(d, (addr >> 8) & 0xFF)) + return TRUE; + } + + I2CStop(d); + } + + return FALSE; +} + +/* These are the hardware independent I2C helper functions. + * ======================================================== + */ + +/* Function for probing. Just send the slave address + * and return true if the device responds. The slave address + * must have the lsb set to reflect a read (1) or write (0) access. + * Don't expect a read- or write-only device will respond otherwise. + */ + +Bool +xf86I2CProbeAddress(I2CBusPtr b, I2CSlaveAddr addr) +{ + int r; + I2CDevRec d; + + d.DevName = STRDUP("Probing", sizeof("Probing")); + d.BitTimeout = b->BitTimeout; + d.ByteTimeout = b->ByteTimeout; + d.AcknTimeout = b->AcknTimeout; + d.StartTimeout = b->StartTimeout; + d.SlaveAddr = addr; + d.pI2CBus = b; + d.NextDev = NULL; + + r = b->I2CAddress(&d, addr); + + if (r) b->I2CStop(&d); + + return r; +} + +/* All functions below are related to devices and take the + * slave address and timeout values from an I2CDevRec. They + * return FALSE in case of an error (presumably a timeout). + */ + +/* General purpose read and write function. + * + * 1st, if nWrite > 0 + * Send a start condition + * Send the slave address (1 or 2 bytes) with write flag + * Write n bytes from WriteBuffer + * 2nd, if nRead > 0 + * Send a start condition [again] + * Send the slave address (1 or 2 bytes) with read flag + * Read n bytes to ReadBuffer + * 3rd, if a Start condition has been successfully sent, + * Send a Stop condition. + * + * The functions exits immediately when an error occures, + * not proceeding any data left. However, step 3 will + * be executed anyway to leave the bus in clean idle state. + */ + +Bool +xf86I2CWriteRead(I2CDevPtr d, + I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead) +{ + Bool r = TRUE; + I2CBusPtr b = d->pI2CBus; + int s = 0; + + if (r && nWrite > 0) { + r = b->I2CAddress(d, d->SlaveAddr & ~1); + if (r) { + for (; nWrite > 0; WriteBuffer++, nWrite--) + if (!(r = b->I2CPutByte(d, *WriteBuffer))) + break; + s++; + } + } + + if (r && nRead > 0) { + r = b->I2CAddress(d, d->SlaveAddr | 1); + if (r) { + for (; nRead > 0; ReadBuffer++, nRead--) + if (!(r = b->I2CGetByte(d, ReadBuffer, nRead == 1))) + break; + s++; + } + } + + if (s) b->I2CStop(d); + + return r; +} + +/* Read a byte, the only readable register of a device. + */ + +Bool +xf86I2CReadStatus(I2CDevPtr d, I2CByte *pbyte) +{ + return xf86I2CWriteRead(d, NULL, 0, pbyte, 1); +} + +/* Read a byte from one of the registers determined by its sub-address. + */ + +Bool +xf86I2CReadByte(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte) +{ + return xf86I2CWriteRead(d, &subaddr, 1, pbyte, 1); +} + +/* Read bytes from subsequent registers determined by the + * sub-address of the first register. + */ + +Bool +xf86I2CReadBytes(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte, int n) +{ + return xf86I2CWriteRead(d, &subaddr, 1, pbyte, n); +} + +/* Read a word (high byte, then low byte) from one of the registers + * determined by its sub-address. + */ + +Bool +xf86I2CReadWord(I2CDevPtr d, I2CByte subaddr, unsigned short *pword) +{ + I2CByte rb[2]; + + if (!xf86I2CWriteRead(d, &subaddr, 1, rb, 2)) return FALSE; + + *pword = (rb[0] << 8) | rb[1]; + + return TRUE; +} + +/* Write a byte to one of the registers determined by its sub-address. + */ + +Bool +xf86I2CWriteByte(I2CDevPtr d, I2CByte subaddr, I2CByte byte) +{ + I2CByte wb[2]; + + wb[0] = subaddr; + wb[1] = byte; + + return xf86I2CWriteRead(d, wb, 2, NULL, 0); +} + +/* Write bytes to subsequent registers determined by the + * sub-address of the first register. + */ + +Bool +xf86I2CWriteBytes(I2CDevPtr d, I2CByte subaddr, + I2CByte *WriteBuffer, int nWrite) +{ + I2CBusPtr b = d->pI2CBus; + Bool r = TRUE; + + if (nWrite > 0) { + r = b->I2CAddress(d, d->SlaveAddr & ~1); + if (r){ + if ((r = b->I2CPutByte(d, subaddr))) + for (; nWrite > 0; WriteBuffer++, nWrite--) + if (!(r = b->I2CPutByte(d, *WriteBuffer))) + break; + + b->I2CStop(d); + } + } + + return r; +} + +/* Write a word (high byte, then low byte) to one of the registers + * determined by its sub-address. + */ + +Bool +xf86I2CWriteWord(I2CDevPtr d, I2CByte subaddr, unsigned short word) +{ + I2CByte wb[3]; + + wb[0] = subaddr; + wb[1] = word >> 8; + wb[2] = word & 0xFF; + + return xf86I2CWriteRead(d, wb, 3, NULL, 0); +} + +/* Write a vector of bytes to not adjacent registers. This vector is, + * 1st byte sub-address, 2nd byte value, 3rd byte sub-address asf. + * This function is intended to initialize devices. Note this function + * exits immediately when an error occurs, some registers may + * remain uninitialized. + */ + +Bool +xf86I2CWriteVec(I2CDevPtr d, I2CByte *vec, int nValues) +{ + I2CBusPtr b = d->pI2CBus; + Bool r = TRUE; + + if (nValues > 0) { + int s = 0; + for (; nValues > 0; nValues--, vec += 2) { + if (!(r = b->I2CAddress(d, d->SlaveAddr & ~1))) + break; + + s++; + + if (!(r = b->I2CPutByte(d, vec[0]))) + break; + + if (!(r = b->I2CPutByte(d, vec[1]))) + break; + } + + if (s > 0) b->I2CStop(d); + } + + return r; +} + +/* Administrative functions. + * ========================= + */ + +/* Allocates an I2CDevRec for you and initializes with propper defaults + * you may modify before calling xf86I2CDevInit. Your I2CDevRec must + * contain at least a SlaveAddr, and a pI2CBus pointer to the bus this + * device shall be linked to. + * + * See function I2CAddress for the slave address format. Always set + * the least significant bit, indicating a read or write access, to zero. + */ + +I2CDevPtr +xf86CreateI2CDevRec(void) +{ + I2CDevPtr d = (I2CDevPtr) new I2CDevRec; + + if (d != NULL) { + d->SlaveAddr = 0x2e; + d->pI2CBus = NULL; + } + + return d; +} + +/* Unlink an I2C device. If you got the I2CDevRec from xf86CreateI2CDevRec + * you should set to free it. + */ + +void +xf86DestroyI2CDevRec(I2CDevPtr d, Bool unalloc) +{ + if (d) { + I2CDevPtr *p; + + /* Remove this from the list of active I2C devices. */ + + for (p = &d->pI2CBus->FirstDev; *p != NULL; p = &(*p)->NextDev) + if (*p == d) { + *p = (*p)->NextDev; + break; + } + + if (d->pI2CBus->scrnIndex >= 0) + xf86DrvMsg(d->pI2CBus->scrnIndex, X_INFO, + "I2C device \"%s:%s\" removed.", + d->pI2CBus->BusName, d->DevName); + else + xf86Msg(X_INFO, "I2C device \"%s:%s\" removed.", + d->pI2CBus->BusName, d->DevName); + + if (unalloc) delete p; + } +} + +/* I2C transmissions are related to an I2CDevRec you must link to a + * previously registered bus (see xf86I2CBusInit) before attempting + * to read and write data. You may call xf86I2CProbeAddress first to + * see if the device in question is present on this bus. + * + * xf86I2CDevInit will not allocate an I2CBusRec for you, instead you + * may enter a pointer to a statically allocated I2CDevRec or the (modified) + * result of xf86CreateI2CDevRec. + * + * If you don't specify timeouts for the device (n <= 0), it will inherit + * the bus-wide defaults. The function returns TRUE on success. + */ + +Bool +xf86I2CDevInit(I2CDevPtr d) +{ + I2CBusPtr b; + + if (d == NULL || (b = d->pI2CBus) == NULL || (d->SlaveAddr & 1) || xf86I2CFindDev(b, d->SlaveAddr) != NULL) { + I2C_TRACE("xf86I2CDevInit = FALSE"); + return FALSE; + } + + if (d->BitTimeout <= 0) d->BitTimeout = b->BitTimeout; + if (d->ByteTimeout <= 0) d->ByteTimeout = b->ByteTimeout; + if (d->AcknTimeout <= 0) d->AcknTimeout = b->AcknTimeout; + if (d->StartTimeout <= 0) d->StartTimeout = b->StartTimeout; + + d->NextDev = b->FirstDev; + b->FirstDev = d; + + if(b->scrnIndex >= 0) + xf86DrvMsg(b->scrnIndex, X_INFO, "I2C device \"%s:%s\" registered.", + b->BusName, d->DevName); + else + xf86Msg(X_INFO, "I2C device \"%s:%s\" registered.", + b->BusName, d->DevName); + + return TRUE; +} + +I2CDevPtr +xf86I2CFindDev(I2CBusPtr b, I2CSlaveAddr addr) +{ + I2CDevPtr d; + + if (b) { + for (d = b->FirstDev; d != NULL; d = d->NextDev) + if (d->SlaveAddr == addr) { + I2C_TRACE("xf86I2CFindDev = %s", d ? "TRUE" : "FALSE"); + return d; + } + } + + return NULL; +} + +static I2CBusPtr I2CBusList; + +/* Allocates an I2CBusRec for you and initializes with propper defaults + * you may modify before calling xf86I2CBusInit. Your I2CBusRec must + * contain at least a BusName, a scrnIndex (or -1), and a complete set + * of either high or low level I2C function pointers. You may pass + * bus-wide timeouts, otherwise inplausible values will be replaced + * with safe defaults. + */ + +I2CBusPtr +xf86CreateI2CBusRec(void) +{ + I2CBusPtr b; + + b = (I2CBusPtr) new I2CBusRec; + + if (b != NULL) { + b->scrnIndex = -1; + b->HoldTime = 5; /* 100 kHz bus */ + b->BitTimeout = 5; + b->ByteTimeout = 5; + b->AcknTimeout = 5; + b->StartTimeout = 5; + b->RiseFallTime = RISEFALLTIME; + } + + return b; +} + +/* Unregister an I2C bus. If you got the I2CBusRec from xf86CreateI2CBusRec + * you should set to free it. If you set , the function + * xf86DestroyI2CDevRec will be called for all devices linked to the bus + * first, passing down the option. + */ + +void +xf86DestroyI2CBusRec(I2CBusPtr b, Bool unalloc, Bool devs_too) +{ + if (b) { + I2CBusPtr *p; + + /* Remove this from the list of active I2C busses. */ + + for (p = &I2CBusList; *p != NULL; p = &(*p)->NextBus) + if (*p == b) { + *p = (*p)->NextBus; + break; + } + + if (b->FirstDev != NULL) { + if (devs_too) { + I2CDevPtr d; + + while ((d = b->FirstDev) != NULL) + xf86DestroyI2CDevRec(d, unalloc); + } else { + if (unalloc) { + xf86Msg(X_ERROR, "i2c bug: Attempt to remove I2C bus \"%s\", " + "but device list is not empty.", + b->BusName); + return; + } + } + } + + if (b->scrnIndex >= 0) + xf86DrvMsg(b->scrnIndex, X_INFO, "I2C bus \"%s\" removed.", + b->BusName); + else + xf86Msg(X_INFO, "I2C bus \"%s\" removed.", b->BusName); + + if (unalloc) delete b; + } +} + +/* I2C masters have to register themselves using this function. + * It will not allocate an I2CBusRec for you, instead you may enter + * a pointer to a statically allocated I2CBusRec or the (modified) + * result of xf86CreateI2CBusRec. Returns TRUE on success. + * + * At this point there won't be any traffic on the I2C bus. + */ + +Bool +xf86I2CBusInit(I2CBusPtr b) +{ + /* I2C busses must be identified by a unique scrnIndex + * and name. If scrnIndex is unspecified (a negative value), + * then the name must be unique throughout the server. + */ + + if (b->BusName == NULL || + xf86I2CFindBus(b->scrnIndex, b->BusName) != NULL) + return FALSE; + + /* If the high level functions are not + * supplied, use the generic functions. + * In this case we need the low-level + * function. + */ + + if (b->I2CPutBits == NULL || + b->I2CGetBits == NULL) + { + if (b->I2CPutByte == NULL || + b->I2CGetByte == NULL || + b->I2CAddress == NULL || + b->I2CStop == NULL) + return FALSE; + } else { + b->I2CPutByte = I2CPutByte; + b->I2CGetByte = I2CGetByte; + b->I2CAddress = I2CAddress; + b->I2CStop = I2CStop; + } + + if (b->I2CUDelay == NULL) + b->I2CUDelay = I2CUDelay; + + if (b->HoldTime < 2) b->HoldTime = 5; + if (b->BitTimeout <= 0) b->BitTimeout = b->HoldTime; + if (b->ByteTimeout <= 0) b->ByteTimeout = b->HoldTime; + if (b->AcknTimeout <= 0) b->AcknTimeout = b->HoldTime; + if (b->StartTimeout <= 0) b->StartTimeout = b->HoldTime; + + /* Put new bus on list. */ + + b->NextBus = I2CBusList; + I2CBusList = b; + + if (b->scrnIndex >= 0) + xf86DrvMsg(b->scrnIndex, X_INFO, "I2C bus \"%s\" initialized.", + b->BusName); + else + xf86Msg(X_INFO, "I2C bus \"%s\" initialized.", b->BusName); + + return TRUE; +} + +I2CBusPtr +xf86I2CFindBus(int scrnIndex, char *name) +{ + I2CBusPtr p; + + if (name != NULL) + for (p = I2CBusList; p != NULL; p = p->NextBus) + if (scrnIndex < 0 || p->scrnIndex == scrnIndex) + if (!strcmp(p->BusName, name)) + return p; + + return NULL; +} diff --git a/plugins/GPUSensors/GeforceSensors/xf86i2c.h b/plugins/GPUSensors/GeforceSensors/xf86i2c.h new file mode 100755 index 0000000..b50fc32 --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/xf86i2c.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 1998 Itai Nahshon, Michael Schimek + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/i2c/xf86i2c.h,v 1.4 1999/04/11 13:11:01 dawes Exp $ */ +#ifndef _XF86I2C_H +#define _XF86I2C_H + +#include "xfree.h" +#include "nouveau.h" + +typedef unsigned char I2CByte; +typedef unsigned short I2CSlaveAddr; + +typedef struct _I2CBusRec *I2CBusPtr; +typedef struct _I2CDevRec *I2CDevPtr; + +/* I2C masters have to register themselves */ + +typedef struct _I2CBusRec { + char * BusName; + int scrnIndex; + + void (*I2CUDelay) (I2CBusPtr b, int usec); + + void (*I2CPutBits)(I2CBusPtr b, int scl, int sda); + void (*I2CGetBits)(I2CBusPtr b, int *scl, int *sda); + + /* Look at the generic routines to see how these functions should behave. */ + + Bool (*I2CAddress)(I2CDevPtr d, I2CSlaveAddr); + void (*I2CStop) (I2CDevPtr d); + Bool (*I2CPutByte)(I2CDevPtr d, I2CByte data); + Bool (*I2CGetByte)(I2CDevPtr d, I2CByte *data, Bool); + + nouveau_device *card; + + DevUnion DriverPrivate; + + int HoldTime; /* 1 / bus clock frequency, 5 or 2 usec */ + + int BitTimeout; /* usec */ + int ByteTimeout; /* usec */ + int AcknTimeout; /* usec */ + int StartTimeout; /* usec */ + int RiseFallTime; /* usec */ + + I2CDevPtr FirstDev; + I2CBusPtr NextBus; +} I2CBusRec; + +I2CBusPtr xf86CreateI2CBusRec(void); +void xf86DestroyI2CBusRec(I2CBusPtr pI2CBus, Bool unalloc, Bool devs_too); +Bool xf86I2CBusInit(I2CBusPtr pI2CBus); +I2CBusPtr xf86I2CFindBus(int scrnIndex, char *name); + +/* I2C slave devices */ + +typedef struct _I2CDevRec { + char * DevName; + + int BitTimeout; /* usec */ + int ByteTimeout; /* usec */ + int AcknTimeout; /* usec */ + int StartTimeout; /* usec */ + + short chip_id; /* type of i2c chip; required atleast by the lm99 to decide whether to add an offset or not */ + int arch; /* architecture to which the gpu belongs; the lm99 code needs this for adding offsets too */ + char *chip_name; + + I2CSlaveAddr SlaveAddr; + I2CBusPtr pI2CBus; + I2CDevPtr NextDev; +} I2CDevRec; + +I2CDevPtr xf86CreateI2CDevRec(void); +void xf86DestroyI2CDevRec(I2CDevPtr pI2CDev, Bool unalloc); +Bool xf86I2CDevInit(I2CDevPtr pI2CDev); +I2CDevPtr xf86I2CFindDev(I2CBusPtr, I2CSlaveAddr); + +Bool I2CAddress(I2CDevPtr d, I2CSlaveAddr addr); + +/* See descriptions of these functions in xf86i2c.c */ + +Bool xf86I2CProbeAddress(I2CBusPtr pI2CBus, I2CSlaveAddr); +Bool xf86I2CWriteRead(I2CDevPtr d, I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead); +#define xf86I2CRead(d, rb, nr) xf86I2CWriteRead(d, NULL, 0, rb, nr) +Bool xf86I2CReadStatus(I2CDevPtr d, I2CByte *pbyte); +Bool xf86I2CReadByte(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte); +Bool xf86I2CReadBytes(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte, int n); +Bool xf86I2CReadWord(I2CDevPtr d, I2CByte subaddr, unsigned short *pword); +#define xf86I2CWrite(d, wb, nw) xf86I2CWriteRead(d, wb, nw, NULL, 0) +Bool xf86I2CWriteByte(I2CDevPtr d, I2CByte subaddr, I2CByte byte); +Bool xf86I2CWriteBytes(I2CDevPtr d, I2CByte subaddr, I2CByte *WriteBuffer, int nWrite); +Bool xf86I2CWriteWord(I2CDevPtr d, I2CByte subaddr, unsigned short word); +Bool xf86I2CWriteVec(I2CDevPtr d, I2CByte *vec, int nValues); + +#endif /*_XF86I2C_H */ diff --git a/plugins/GPUSensors/GeforceSensors/xfree.h b/plugins/GPUSensors/GeforceSensors/xfree.h new file mode 100755 index 0000000..e7028ce --- /dev/null +++ b/plugins/GPUSensors/GeforceSensors/xfree.h @@ -0,0 +1,73 @@ +/* NVTV xfree -- Dirk Thierbach + * + * Header: All definitions from xfree that are needed. + * + */ + +#ifndef _XFREE_H +#define _XFREE_H 1 + +#define xf86Msg(type,format,args...) /*NouveauInfoLog(format,args)*/ +#define xf86DrvMsg(scrnIndex,type,format, args...) /*NouveauInfoLog(format,args)*/ + +#ifndef Bool +# ifndef _XTYPEDEF_BOOL +# define _XTYPEDEF_BOOL +typedef int Bool; +# endif +#endif + +#ifndef _XTYPEDEF_POINTER +# define _XTYPEDEF_POINTER +typedef void *pointer; +#endif + + +/* Flags for driver messages */ +typedef enum { + X_PROBED, /* Value was probed */ + X_CONFIG, /* Value was given in the config file */ + X_DEFAULT, /* Value is a default */ + X_CMDLINE, /* Value was given on the command line */ + X_NOTICE, /* Notice */ + X_ERROR, /* Error message */ + X_WARNING, /* Warning message */ + X_INFO, /* Informational message */ + X_NONE, /* No prefix */ + X_NOT_IMPLEMENTED /* Not implemented */ +} MessageType; + +typedef union _DevUnion { + pointer ptr; + long val; + unsigned long uval; + pointer (*fptr)(void); +} DevUnion; + + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +//void xf86usleep(unsigned long usec); +void xf86getsecs(long * secs, long * usecs); + +#define xcalloc(_num, _size) calloc(_num, _size) +#define xfree(_ptr) free(_ptr) + + +/* ---------------- nv driver files ---------------- */ + +/**** nv_dac.c */ + +#define DDC_SDA_READ_MASK (1 << 3) +#define DDC_SCL_READ_MASK (1 << 2) +#define DDC_SDA_WRITE_MASK (1 << 4) +#define DDC_SCL_WRITE_MASK (1 << 5) + + +#endif diff --git a/plugins/GPUSensors/IntelX3100/X3100-Info.plist b/plugins/GPUSensors/IntelX3100/X3100-Info.plist new file mode 100644 index 0000000..8e67790 --- /dev/null +++ b/plugins/GPUSensors/IntelX3100/X3100-Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + IOKitPersonalities + + Intel X3100 Cards Monitoring Plugin + + CFBundleIdentifier + org.slice.sensor.X3100 + IOClass + X3100monitor + IOMatchCategory + X3100monitor + IOProbeScore + 500 + IOProviderClass + IOResources + IOResourceMatch + IOKit + + + OSBundleLibraries + + com.apple.iokit.IOPCIFamily + 2.4 + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + + diff --git a/plugins/GPUSensors/IntelX3100/X3100-pre106-Info.plist b/plugins/GPUSensors/IntelX3100/X3100-pre106-Info.plist new file mode 100644 index 0000000..0fedf1f --- /dev/null +++ b/plugins/GPUSensors/IntelX3100/X3100-pre106-Info.plist @@ -0,0 +1,55 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.slice.sensor.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + IOKitPersonalities + + Intel X3100 Cards Monitoring Plugin + + CFBundleIdentifier + org.slice.sensor.X3100 + IOClass + X3100monitor + IOProbeScore + 500 + IOMatchCategory + X3100monitor + IOProviderClass + IOResources + IOResourceMatch + IOKit + + + OSBundleLibraries + + org.netkas.FakeSMC + 3.1.0 + com.apple.iokit.IOACPIFamily + 1.0.0d1 + com.apple.iokit.IOPCIFamily + 2.4 + com.apple.kernel.6.0 + 7.9.9 + com.apple.kernel.iokit + 7.9.9 + com.apple.kernel.libkern + 7.9.9 + + + diff --git a/plugins/GPUSensors/IntelX3100/X3100.cpp b/plugins/GPUSensors/IntelX3100/X3100.cpp new file mode 100644 index 0000000..56e5d8e --- /dev/null +++ b/plugins/GPUSensors/IntelX3100/X3100.cpp @@ -0,0 +1,242 @@ +/* + * X3100.cpp + * HWSensors + * + * Created by Sergey on 19.12.10. + * Copyright 2010 slice. All rights reserved. + * + */ + +#include "X3100.h" +#include "FakeSMC.h" + +#define kGenericPCIDevice "IOPCIDevice" +#define kTimeoutMSecs 1000 +#define fVendor "vendor-id" +#define fDevice "device-id" +#define kIOPCIConfigBaseAddress0 0x10 +#define kMCHBAR 0x48 +#define TSC1 0x1001 +#define TSS1 0x1004 +#define TR1 0x1006 +#define RTR1 0x1008 +#define TIC1 0x100B +#define TSC2 0x1041 +#define TSS2 0x1044 +#define TR2 0x1046 +#define RTR2 0x1048 +#define TIC2 0x104B + + +#define INVID8(offset) (mmio_base[offset]) +#define INVID16(offset) OSReadLittleInt16((mmio_base), offset) +#define INVID(offset) OSReadLittleInt32((mmio_base), offset) +#define OUTVID(offset,val) OSWriteLittleInt32((mmio_base), offset, val) + +#define Debug FALSE + +#define LogPrefix "X3100monitor: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +#define super IOService +OSDefineMetaClassAndStructors(X3100monitor, IOService) + +bool X3100monitor::addSensor(const char* key, const char* type, unsigned int size, int index) { + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)key, + (void *)type, + (void *)(long long)size, + (void *)this)) { + return sensors->setObject(key, OSNumber::withNumber(index, 32)); + } + return false; +} + +IOService* X3100monitor::probe(IOService *provider, SInt32 *score) { + if (super::probe(provider, score) != this) return 0; + UInt32 vendor_id = 0, device_id = 0; + VCard = NULL; + if (OSDictionary * dictionary = serviceMatching(kGenericPCIDevice)) { + if (OSIterator * iterator = getMatchingServices(dictionary)) { + IOPCIDevice* device = 0; + do { + device = OSDynamicCast(IOPCIDevice, iterator->getNextObject()); + if (!device) { + break; + } + OSData *data = OSDynamicCast(OSData, device->getProperty("vendor-id")); + if (data) { + vendor_id = *(UInt32*)data->getBytesNoCopy(); + } + + data = OSDynamicCast(OSData, device->getProperty("device-id")); + if (data) { + device_id = *(UInt32*)data->getBytesNoCopy(); + } + + if ((vendor_id==0x8086) && (device_id==0x2a00)) { + InfoLog("found %lx chip", (long unsigned int)device_id); + VCard = device; + break; + } + } while(TRUE); + } + } + + if (!VCard) { + WarningLog("no ICH8M found"); +// return NULL; // no return NULL here because on repeating attempts to probe + } + return this; +} + +bool X3100monitor::start(IOService * provider) { + if (!provider || !super::start(provider)) { return false; } + + if (!(fakeSMC = waitForService(serviceMatching(kFakeSMCDeviceService)))) { + WarningLog("Can't locate fake SMC device, kext will not load"); + return false; + } + + if (!VCard) { + return false; + } + + IOMemoryDescriptor * theDescriptor; + IOPhysicalAddress bar = (IOPhysicalAddress)((VCard->configRead32(kMCHBAR)) & ~0xf); + DebugLog("Fx3100: register space=%08lx\n", (long unsigned int)bar); + theDescriptor = IOMemoryDescriptor::withPhysicalAddress (bar, 0x2000, kIODirectionOutIn); // | kIOMapInhibitCache); + + if (theDescriptor != NULL) { + mmio = theDescriptor->map(); + if (mmio != NULL) { + mmio_base = (volatile UInt8 *)mmio->getVirtualAddress(); +#if DEBUG + DebugLog(" MCHBAR mapped\n"); + for (int i=0; i<0x2f; i +=16) { + DebugLog("%04lx: ", (long unsigned int)i+0x1000); + for (int j=0; j<16; j += 1) { + DebugLog("%02lx ", (long unsigned int)INVID8(i+j+0x1000)); + } + DebugLog("\n"); + } +#endif + } else { + InfoLog(" MCHBAR failed to map\n"); + return -1; + } + } + + char name[5]; + //try to find empty key + for (int i = 0; i < 0x10; i++) { + + snprintf(name, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, i); + + UInt8 length = 0; + void * data = 0; + + IOReturn result = fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, true, (void *)name, (void *)&length, (void *)&data, 0); + + if (kIOReturnSuccess == result) { + continue; + } + if (addSensor(name, TYPE_SP78, 2, i)) { + numCard = i; + break; + } + } + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)name, + (void *)TYPE_SP78, + (void *)2, + this)) { + WarningLog("Can't add key to fake SMC device, kext will not load"); + return false; + } + + return true; +} + +bool X3100monitor::init(OSDictionary *properties) { + if (!super::init(properties)) { + return false; + } + + if (!(sensors = OSDictionary::withCapacity(0))) { + return false; + } + + return true; +} + + +void X3100monitor::stop (IOService* provider) { + sensors->flushCollection(); + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCRemoveKeyHandler, + true, + this, + NULL, + NULL, + NULL)) { + WarningLog("Can't remove key handler"); + IOSleep(500); + } + + super::stop(provider); +} + +void X3100monitor::free () { + sensors->release(); + super::free(); +} + +IOReturn X3100monitor::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4) { + UInt16 t; + + if (functionName->isEqualTo(kFakeSMCGetValueCallback)) { + const char* name = (const char*)param1; + void* data = param2; + + if (name && data) { + if (OSNumber *number = OSDynamicCast(OSNumber, sensors->getObject(name))) { + UInt32 index = number->unsigned16BitValue(); + if (index != numCard) { + return kIOReturnBadArgument; + } + } + short value = 130; + if (mmio_base) { + OUTVID(TIC1, 3); + // if ((INVID16(TSC1) & (1<<15)) && !(INVID16(TSC1) & (1<<8)))//enabled and ready + for (int i=0; i<1000; i++) { //attempts to ready + if (INVID16(TSS1) & (1<<10)) //valid? + break; + IOSleep(10); + } + value = INVID8(TR1); + } + + t = 150 - value; + bcopy(&t, data, 2); + + return kIOReturnSuccess; + } + + //DebugLog("bad argument key name or data"); + + return kIOReturnBadArgument; + } + + return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); +} diff --git a/plugins/GPUSensors/IntelX3100/X3100.h b/plugins/GPUSensors/IntelX3100/X3100.h new file mode 100644 index 0000000..b5990c5 --- /dev/null +++ b/plugins/GPUSensors/IntelX3100/X3100.h @@ -0,0 +1,40 @@ +/* + * X3100.h + * HWSensors + * + * Created by Sergey on 19.12.10 with templates of Mozodojo. + * Copyright 2010 Slice. + * + */ + +#include +#include +#include + +class X3100monitor : public IOService +{ + OSDeclareDefaultStructors(X3100monitor) +private: + IOService* fakeSMC; + OSDictionary* sensors; + volatile UInt8* mmio_base; + int numCard; //numCard=0 if only one Video, but may be any other value + IOPCIDevice * VCard; + IOMemoryMap * mmio; + + bool addSensor(const char* key, const char* type, unsigned int size, int index); + +public: + virtual IOService* probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual bool init(OSDictionary *properties=0); + virtual void free(void); + virtual void stop(IOService *provider); + + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); +}; diff --git a/plugins/GPUSensors/NVClockX/NVClock/adt7473.cpp b/plugins/GPUSensors/NVClockX/NVClock/adt7473.cpp new file mode 100644 index 0000000..5d1c204 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/adt7473.cpp @@ -0,0 +1,193 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2005 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * ADT7473 hardware monitoring + */ +#include +#include "i2c.h" +#include "nvclock.h" + +/* various defines for register offsets and such are needed */ +#define ADT7473_REG_LOCAL_TEMP 0x26 +#define ADT7473_REG_LOCAL_TEMP_OFFSET 0x70 +#define ADT7473_REG_REMOTE_TEMP 0x25 +#define ADT7473_REG_REMOTE_TEMP_OFFSET 0x71 + +#define ADT7473_REG_PWM1_CFG 0x5c +#define ADT7473_REG_PWM1_DUTYCYCLE 0x30 +#define ADT7473_REG_PWM1_MAX_DUTYCYCLE 0x38 +#define ADT7473_REG_PWM1_MIN_DUTYCYCLE 0x64 + +#define ADT7473_REG_TACH1_LB 0x28 +#define ADT7473_REG_TACH1_HB 0x29 + +#define ADT7473_REG_CFG5 0x7c + +#define ADT7473_REG_MAN_ID 0x3e +#define AD_MAN_ID 0x41 +#define ADT7473_REG_CHIP_ID 0x3d +#define ADT7473_CHIP_ID 0x73 + +/* This function should return the chip type .. */ +int adt7473_detect(I2CDevPtr dev) +{ + I2CByte man_id, chip_id; + + xf86I2CReadByte(dev, ADT7473_REG_MAN_ID, &man_id); + xf86I2CReadByte(dev, ADT7473_REG_CHIP_ID, &chip_id); + + if((man_id == AD_MAN_ID) && (chip_id == ADT7473_CHIP_ID)) + { + dev->chip_id = ADT7473; + dev->chip_name = (char*)STRDUP("Analog Devices ADT7473", sizeof("Analog Devices ADT7473")); + return 1; + } + + return 0; +} + +int adt7473_get_board_temp(I2CDevPtr dev) +{ + I2CByte temp; + I2CByte cfg; + + xf86I2CReadByte(dev, ADT7473_REG_LOCAL_TEMP, &temp); + + /* Check if the sensor uses 2-complement or offset-64 mode */ + xf86I2CReadByte(dev, ADT7473_REG_CFG5, &cfg); + if(cfg & 0x1) + return (int)((char)temp); + else + return temp - 64; +} + +int adt7473_get_gpu_temp(I2CDevPtr dev) +{ + I2CByte temp; + I2CByte cfg; + int offset = 0; + + /* The temperature needs to be corrected using an offset which is stored in the bios. + / If no bios has been parsed we fall back to a default value. + */ + if(nv_card->bios) + { + offset = nv_card->bios->sensor_cfg.temp_correction; + } + else + { + /* We add a 10C offset to the temperature though this isn't conform + / the ADT7473 datasheet. The reason we add this is to show a temperature + / similar to the internal gpu sensor. Right now the board and gpu + / temperature as reported by the sensor are about the same (there's + / a difference between the two or 3-4C). Most likely the internal gpu + / temperature is a bit higher and assuming the temperature as reported + / by the internal sensor is correct adding a 10C offset is a good solution. + / Add an offset of 8C for 8*00/GTX2*0 cards but it doesn't seem 100% correct though. + / It could be that +7C is more correct for 8800GT cards. + */ + if(dev->arch & NV4X) + offset = 10; + else if(dev->arch & NV5X) + offset = 8; + } + + xf86I2CReadByte(dev, ADT7473_REG_REMOTE_TEMP, &temp); + + /* Check if the sensor uses 2-complement or offset-64 mode */ + + xf86I2CReadByte(dev, ADT7473_REG_CFG5, &cfg); + if(cfg & 0x1) + return (int)((char)temp + offset); + else + return temp - 64 + offset; +} + +int adt7473_get_fanspeed_rpm(I2CDevPtr dev) +{ + I2CByte count_lb, count_hb; + int count; + + xf86I2CReadByte(dev, ADT7473_REG_TACH1_LB, &count_lb); + xf86I2CReadByte(dev, ADT7473_REG_TACH1_HB, &count_hb); + count = (count_hb << 8) | count_lb; + + /* GT200 boards seem to use two phases instead of a single, the fan speed is twice as high */ + if(dev->arch & GT200) + count *= 2; + + /* GF100 boards seem to use four phases... */ + if(dev->arch & GF100) + count *= 4; + + /* RPM = 60*90k pulses / (number of counts that fit in a pulse) */ + return 90000*60/count; +} + +float adt7473_get_fanspeed_pwm(I2CDevPtr dev) +{ + I2CByte value; + + xf86I2CReadByte(dev, ADT7473_REG_PWM1_DUTYCYCLE, &value); + return (float)value*100/255; +} + +int adt7473_set_fanspeed_pwm(I2CDevPtr dev, float speed) +{ + I2CByte value = (int)speed * 255/100; + I2CByte cfg, max_dutycycle; + + xf86I2CReadByte(dev, ADT7473_REG_PWM1_CFG, &cfg); + cfg |= 0xe0; /* Put PWM1 in manual mode; this disables automatic control */ + xf86I2CWriteByte(dev, ADT7473_REG_PWM1_CFG, cfg); + + /* If the MAX dutycycle is lower than 0xff (100%), set it to 0xff */ + xf86I2CReadByte(dev, ADT7473_REG_PWM1_MAX_DUTYCYCLE, &max_dutycycle); + if(max_dutycycle < 0xff) + xf86I2CWriteByte(dev, ADT7473_REG_PWM1_MAX_DUTYCYCLE, 0xff); + + xf86I2CWriteByte(dev, ADT7473_REG_PWM1_DUTYCYCLE, value); + return 1; +} + +int adt7473_get_fanspeed_mode(I2CDevPtr dev) { + I2CByte cfg; + xf86I2CReadByte(dev, ADT7473_REG_PWM1_CFG, &cfg); + + if(cfg & (0x6 << 5)) return 0; /* auto */ + if(cfg & (0x7 << 5)) return 1; /* manual */ + + return -1; /* something went wrong */ +} + +void adt7473_set_fanspeed_mode(I2CDevPtr dev, int mode) { + I2CByte cfg; + xf86I2CReadByte(dev, ADT7473_REG_PWM1_CFG, &cfg); + + /* Clear the pwm1 config bits */ + cfg&=~(0xF << 5); + + if(mode==1) + cfg|=0x7 << 5; /* manual */ + else + cfg|=0x6 << 5; /* auto */ + + xf86I2CWriteByte(dev, ADT7473_REG_PWM1_CFG, cfg); +} diff --git a/plugins/GPUSensors/NVClockX/NVClock/backend.cpp b/plugins/GPUSensors/NVClockX/NVClock/backend.cpp new file mode 100644 index 0000000..136722f --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/backend.cpp @@ -0,0 +1,106 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * Copyright(C) 2001-2007 Roderick Colenbrander + * + * site: http://nvclock.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +//#include +//#include +#include + +//#include "config.h" +#ifdef HAVE_NVCONTROL +#include "nvcontrol.h" +#endif +#include "backend.h" + +/* Read a byte from the pci bus */ +unsigned char nv_read_pbus8(int offset) +{ + int shift = (offset % 4)*8; + return (nv_card->PBUS[offset/4] >> shift) & 0xff; +} + +/* Read an unsigned short from the pci bus */ +unsigned short nv_read_pbus16(int offset) +{ + int shift = (offset / 2)*16; + return (nv_card->PBUS[offset/4] >> shift) & 0xffff; +} + +/* Read an unsigned int from the pci bus */ +unsigned int nv_read_pbus(int offset) +{ + return nv_card->PBUS[offset/4]; +} + +/* Read an unsigned int from the PMC registers */ +unsigned int nv_read_pmc(int offset) +{ + return nv_card->PMC[offset/4]; +} + +/* This function is actually a basic version of set_card. + / It mainly copies the entries of the card list and maps + / the video registers. We need this function because we need + / access to the videocard from the config file creation code. + / At that stage we can't use the normal set_card because that + / function also sets function pointers and uses bios/config + / file info which we don't have yet. + */ +int set_card_info(int number) +{ + nv_card = &nvclock.card[number]; + + /*if(!nv_card->mem_mapped) + if(!map_mem(nv_card->dev_name)) + return 0; // map_mem already took care of the error + */ + + return 1; +} + +int32_t pciReadLong(unsigned short devbusfn, long offset){ + return -1; +} + +/* Set the card object to the requested card */ +int set_card(int number) +{ + if(!set_card_info(number)) + return 0; + + + info_init(); + + if(nv_card->arch & NV3X) + ;//nv30_init(); + else if(nv_card->arch & NV4X) + nv40_init(); + else if(nv_card->arch & NV5X) + nv50_init(); + else + nv_init(); + + return 1; +} + +/*void unset_card() + { + unmap_mem(); + }*/ diff --git a/plugins/GPUSensors/NVClockX/NVClock/backend.h b/plugins/GPUSensors/NVClockX/NVClock/backend.h new file mode 100644 index 0000000..7eb11ab --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/backend.h @@ -0,0 +1,88 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * Copyright(C) 2001-2005 Roderick Colenbrander + * + * site: http://nvclock.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +//#include "config.h" +#include "i2c.h" +#include "nvclock.h" +#include "nvreg.h" +#include + + +/* Thanks to Alexey Nicolaychuk (Unwinder), the author of Rivatuner, for providing + these macros to get nv30 clock detection working. +*/ +#define NV30_PLL_M1(PLL) ( ( PLL ) & 0x0f ) +#define NV30_PLL_M2(PLL) ( ( ( PLL ) >> 4 ) & 0x07 ) +#define NV30_PLL_N1(PLL) ( ( ( PLL ) >> 8 ) & 0xff ) +#define NV30_PLL_N2(PLL) ( ( ( ( PLL ) >> 19 ) & 0x07 ) | ( ( ( PLL ) >> 21 ) & 0x18 ) ) +#define NV30_PLL_P(PLL) ( ( ( PLL ) >> 16 ) & 0x07 ) + +#define PCI_GET_BUS(devbusfn) ((devbusfn >> 8) & 0xff) +#define PCI_GET_DEVICE(devbusfn) ((devbusfn & 0xff) >> 3) +#define PCI_GET_FUNCTION(devbusfn) (devbusfn & 0x7) +#define PCI_GET_DEVBUSFN(dev, bus, fn) ((bus << 8) | (dev << 3) | (fn & 0x7)) + +/* Set the card object to the requested card */ +int set_card(int number); + +/* Some internally needed functions */ +const char* get_card_name(int device_id, gpu_type *gpu); +int get_gpu_arch(int device_id); +int set_card_info(int number); /* Basic version of set_card */ +//int map_mem(const char* dev_name); +//void unmap_mem(); +int32_t pciReadLong(unsigned short devbusfn, long offset); + +/* Bios related stuff */ +void dump_bios(const char *filename); +struct nvbios* read_bios(const char *filename); + +/* NV-CONTROL overclocking functions */ +float nvcontrol_get_gpu_speed(); +float nvcontrol_get_memory_speed(); /* NV-CONTROL wrapper */ +void nvcontrol_set_gpu_speed(unsigned int nvclk); +void nvcontrol_set_memory_speed(unsigned int memclk); +void nvcontrol_reset_gpu_speed(); +void nvcontrol_reset_memory_speed(); + +/* PLL to clock conversion */ +float GetClock(int base_freq, unsigned int pll); +float GetClock_nv30(int base_freq, unsigned int pll, unsigned int pll2); +float GetClock_nv40(int base_freq, unsigned int pll, unsigned int pll2); +float GetClock_nv50(int base_freq, unsigned int pll, unsigned int pll2); + +void info_init(void); +void i2c_sensor_init(void); + +void nv_init(void); +void nv30_init(void); +void nv31_init(void); +void nv40_init(void); +void nv50_init(void); + +/* PCI bus reading */ +unsigned char nv_read_pbus8(int offset); +unsigned short nv_read_pbus16(int offset); +unsigned int nv_read_pbus(int offset); + +/* PMC reading */ +unsigned int nv_read_pmc(int offset); + diff --git a/plugins/GPUSensors/NVClockX/NVClock/bios.cpp b/plugins/GPUSensors/NVClockX/NVClock/bios.cpp new file mode 100644 index 0000000..db6b1e6 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/bios.cpp @@ -0,0 +1,1142 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * Copyright(C) 2001-2007 Roderick Colenbrander + * + * Copyright(C) 2005 Hans-Frieder Vogt + * NV40 bios parsing improvements (BIT parsing rewrite + performance table fixes) + * + * site: http://nvclock.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + TODO: + - support for parsing some other init/script tables + - support for pre-GeforceFX bioses + */ + +#include "backend.h" +#include "nvclock.h" +#include "nvreg.h" +//#include +#include +#include +//#include +//#include +#include +//#include +#include + +#define READ_BYTE(rom, offset) (rom[offset]&0xff) +#define READ_SHORT(rom, offset) ((rom[offset+1]&0xff) << 8 | (rom[offset]&0xff)) +#define READ_INT(rom, offset) ((rom[offset+3]&0xff) << 24 | (rom[offset+2]&0xff) << 16 | (rom[offset+1]&0xff) << 8 | (rom[offset]&0xff)) +#define READ_LONG(rom, offset) (READ_INT(rom, offset+4)<<32 | READ_INT(rom, offset)) + +//#define DEBUG true + +//static unsigned int locate(char *rom, char *str, int offset); +struct nvbios *read_bios(const char *file); +static struct nvbios *parse_bios(char *rom); +int load_bios_prom(char *data); +int verify_bios(char *rom); +int load_bios_pramin(char *data); + +typedef struct +{ + unsigned char version; + unsigned char start; + unsigned char entry_size; + unsigned char num_entries; +} BitTableHeader; + +typedef struct +{ + unsigned char version; + unsigned char start; + unsigned char num_active_entries; + unsigned char offset; + unsigned char entry_size; + unsigned char num_entries; +} BitPerformanceTableHeader; + +/* Read a string from a given offset */ +static char* nv_read(char *rom, unsigned short offset) +{ + /*char *res = STRDUP(&rom[offset], NV_PROM_SIZE-offset); + short len=0; + short i; + len = strlen(res); + + // + // Currently we only use this function for reading the signon message. + // The string ends with a '\n' which we don't want so remove it. + + for(i=0; i>24) & 0xff, (version>>16) & 0xff, (version>>8) & 0xff, version&0xff, '\0'); + return (char*)STRDUP(res,12); +} + + +/* Parse the GeforceFX performance table */ +static void parse_nv30_performance_table(struct nvbios *bios, char *rom, int offset) +{ + short i, num_entries; + unsigned char start; + unsigned char size; + //int tmp = 0; + + /* read how far away the start is */ + start = rom[offset]; + num_entries = rom[offset+2]; + size = rom[offset + 3]; + + bios->perf_entries=0; + offset += start + 1; + for(i=0; i < num_entries; i++) + { + bios->perf_lst[i].nvclk = (READ_INT(rom, offset))/100; + + /* The list can contain multiple distinct memory clocks. + / Later on the ramcfg register can tell which of the ones is the right one. + / But for now assume the first one is correct. It doesn't matter much if the + / clocks are a little lower/higher as we mainly use this to detect 3d clocks + / + / Further the clock stored here is the 'real' memory frequency, the effective one + / is twice as high. It doesn't seem to be the case for all bioses though. In some effective + / and real speed entries existed but this might be patched dumps. + */ + bios->perf_lst[i].memclk = (READ_INT(rom, offset+4))/50; + + /* Move behind the timing stuff to the fanspeed and voltage */ + bios->perf_lst[i].fanspeed = (float)(unsigned char)rom[offset + 54]; + bios->perf_lst[i].voltage = (float)(unsigned char)rom[offset + 55]/100; + /* In case the voltage is 0, assume the voltage is similar to the previous voltage */ + if(bios->perf_lst[i].voltage==0 && i>0) + bios->perf_lst[i].voltage = bios->perf_lst[i-1].voltage; + + bios->perf_entries++; + offset += size; + } +} + + +/* Convert the bios version which is stored in a numeric way to a string. + / On NV40 bioses it is stored in 5 numbers instead of 4 which was the + / case on old cards. The bios version on old cards could be bigger than + / 4 numbers too but that version was only stored in a string which was + / hard to locate. On NV40 cards the version is stored in a string too, + / for which the offset can be found at +3 in the 'S' table. + */ +static char *nv40_bios_version_to_str(char *rom, short offset) +{ + char res[16]; + int version = READ_INT(rom, offset); + unsigned char extra = rom[offset+4]; + + snprintf(res, 16,"%02X.%02x.%02x.%02x.%02x%c", (version>>24) & 0xff, (version>>16) & 0xff, (version>>8) & 0xff, version&0xff, extra, '\0'); + return (char*)STRDUP(res,16); +} + + +/* Init script tables contain dozens of entries containing commands to initialize + / the card. There are lots of different commands each having a different 'id' useally + / most entries also have a different size. The task of this function is to move to the + / next entry in the table. + */ +static int bit_init_script_table_get_next_entry(char *rom, int offset) +{ + unsigned char id = rom[offset]; + //int i=0; + + switch(id) + { + case '2': /* 0x32 */ + offset += 43; + break; + case '3': /* 0x33: INIT_REPEAT */ + offset += 2; + break; + case '6': /* 0x36: INIT_REPEAT_END */ + offset += 1; + break; + case '7': /* 0x37 */ + offset += 11; + break; + case '8': /* 0x38: INIT_NOT */ + offset += 1; + break; + case '9': /* 0x39 */ + offset += 2; + break; + case 'J': /* 0x4A */ + offset += 43; + break; + case 'K': /* 0x4B */ +#if DEBUG + /* +1 = PLL register, +5 = value */ + printf("'%c'\t%08x %08x\n", id, READ_INT(rom, offset+1), READ_INT(rom, offset+5)); +#endif + offset += 9; + break; + case 'M': /* 0x4D: INIT_ZM_I2C_BYTE */ +#if DEBUG + printf("'%c'\ti2c bytes: %x\n", id, rom[offset+3]); +#endif + offset += 4 + rom[offset+3]*2; + break; + case 'Q': /* 0x51 */ + offset += 5 + rom[offset+4]; + break; + case 'R': /* 0x52 */ + offset += 4; + break; + case 'S': /* 0x53: INIT_ZM_CR */ +#if DEBUG + /* +1 CRTC index (8-bit) + / +2 value (8-bit) + */ + printf("'%c'\tCRTC index: %x value: %x\n", id, rom[offset+1], rom[offset+2]); +#endif + offset += 3; + break; + case 'T': /* 0x54 */ + offset += 2 + rom[offset+1] * 2; + break; + case 'V': /* 0x56 */ + offset += 3; + break; + case 'X': /* 0x58 */ +#if DEBUG + { + /* +1 register base (32-bit) + / +5 number of values (8-bit) + / +6 value (32-bit) to regbase+4 + / .. */ + int base = READ_INT(rom, offset+1); + int number = (unsigned char)rom[offset+5]; + + printf("'%c'\tbase: %08x number: %d\n", id, base, number); + for(int i=0; ipipe_cfg = val; + break; + case 0x4000: + bios->nvpll = val; + break; + case 0x4020: + bios->mpll = val; + break; + } + } + } + +#if DEBUG /* Read all init tables and print some debug info */ + /* Table 1 */ + offset = READ_SHORT(rom, init_offset); + + for(int i=0; i<=len; i+=2) + { + /* Not all tables have to exist */ + if(!offset) + { + init_offset += 2; + offset = READ_SHORT(rom, init_offset); + continue; + } + + printf("Init script table %d\n", i/2+1); + id = rom[offset]; + + while(id != 'q') + { + /* Break out of the loop if we find an unknown entry id */ + if(!offset) + break; + + if(!(id == 'K' || id == 'n' || id == 'x' || id == 'y' || id == 'z')) + printf("'%c' (%x)\n", id, id); + offset = bit_init_script_table_get_next_entry(rom, offset); + id = rom[offset]; + } + + /* Pointer to next init table */ + init_offset += 2; + /* Get location of next table */ + offset = READ_SHORT(rom, init_offset); + } +#endif + +} + + +/* Parse the Geforce6/7/8 performance table */ +static void parse_bit_performance_table(struct nvbios *bios, char *rom, int offset) +{ + short i, entry; + unsigned char entry_size; + short nvclk_offset, memclk_offset, shader_offset, fanspeed_offset, voltage_offset; + BitPerformanceTableHeader *header = (BitPerformanceTableHeader*)&rom[offset]; + + /* The first byte contains a version number; based on this we set offsets to interesting entries */ + switch(header->version) + { + case 0x25: /* First seen on Geforce 8800GTS bioses */ + fanspeed_offset = 4; + voltage_offset = 5; + nvclk_offset = 8; + shader_offset = 10; + memclk_offset = 12; + break; + case 0x30: /* First seen on Geforce 8600GT bioses */ + fanspeed_offset = 6; + voltage_offset = 7; + nvclk_offset = 8; + shader_offset = 10; + memclk_offset = 12; + break; + case 0x35: /* First seen on Geforce 8800GT bioses; what else is different? */ + fanspeed_offset = 6; + voltage_offset = 7; + nvclk_offset = 8; + shader_offset = 10; + memclk_offset = 12; + break; + default: /* Default to this for all other bioses, I haven't seen issues yet for the entries we use */ + shader_offset = 0; + fanspeed_offset = 4; + voltage_offset = 5; + nvclk_offset = 6; + memclk_offset = 11; + } + + /* +5 contains the number of entries, +4 the size of one in bytes and +3 is some 'offset' */ + entry_size = header->offset + header->entry_size * header->num_entries; + + /* now read entries + / entries start with 0x20 for entry 0, 0x21 for entry 1, ... + */ + offset += header->start; + + for(entry=0, i=0; entrynum_active_entries; entry++) + { + /* On bios version 0x35, this 0x20, 0x21 .. pattern doesn't exist anymore; do the last 4 bits of the first byte tell if an entry is active on 0x35? */ + if ( (header->version != 0x35) && (rom[offset] & 0xf0) != 0x20) + { + break; + } + + bios->perf_lst[i].fanspeed = (unsigned char)rom[offset+fanspeed_offset]; + + bios->perf_lst[i].voltage = (float)(unsigned char)rom[offset+voltage_offset]/100; + /* In case the voltage is 0, assume the voltage is similar to the previous voltage */ + if(bios->perf_lst[i].voltage==0 && i>0) + bios->perf_lst[i].voltage = bios->perf_lst[i-1].voltage; + + /* HACK: My collection of bioses contains a (valid) 6600 bios with two 'bogus' entries at 0x21 (100MHz) and 0x22 (200MHz) + / these entries aren't the default ones for sure, so skip them until we have a better entry selection algorithm. + */ + if(READ_SHORT(rom, offset+nvclk_offset) > 200) + { + bios->perf_lst[i].nvclk = READ_SHORT(rom, offset+nvclk_offset); + + /* Support delta clock reading on some NV4X boards. The entries seem to be present on most Geforce7 boards but are as far as I know only used on 7800/7900 boards. + / On other boards the delta clocks are set to 0. Offset +8 contains the actual delta clock and offset +7 contains a divider for it. If the divider is 0 we don't read the delta clock. */ + if((get_gpu_arch(bios->device_id) & (NV47 | NV49)) && rom[offset+7]) + { + bios->perf_lst[i].delta = rom[offset+8]/rom[offset+7]; + bios->perf_lst[i].memclk = READ_SHORT(rom, offset+memclk_offset); + } + /* Geforce8 cards have a shader clock, further the memory clock is at a different offset as well */ + else if(get_gpu_arch(bios->device_id) & NV5X) + { + bios->perf_lst[i].shaderclk= READ_SHORT(rom, offset+shader_offset); + bios->perf_lst[i].memclk = READ_SHORT(rom, offset+memclk_offset); + } + else + bios->perf_lst[i].memclk = READ_SHORT(rom, offset+memclk_offset)*2; + + bios->perf_entries = i+1; + i++; + } + offset += entry_size; + } +} + +/* Parse the table containing pll programming limits */ +static void parse_bit_pll_table(struct nvbios *bios, char *rom, unsigned short offset) +{ + BitTableHeader *header = (BitTableHeader*)&rom[offset]; + int i; + + offset += header->start; + for(i=0; inum_entries; i++) + { + /* Each type of pll (corresponding to a certain register) has its own limits */ + bios->pll_lst[i].reg = READ_INT(rom, offset); + + /* Minimum/maximum frequency each VCO can generate */ + bios->pll_lst[i].VCO1.minFreq = READ_SHORT(rom, offset+4)*1000; + bios->pll_lst[i].VCO1.maxFreq = READ_SHORT(rom, offset+6)*1000; + bios->pll_lst[i].VCO2.minFreq = READ_SHORT(rom, offset+8)*1000; + bios->pll_lst[i].VCO2.maxFreq = READ_SHORT(rom, offset+0xa)*1000; + + /* Minimum/maximum input frequency for each VCO */ + bios->pll_lst[i].VCO1.minInputFreq = READ_SHORT(rom, offset+0xc)*1000; + bios->pll_lst[i].VCO1.maxInputFreq = READ_SHORT(rom, offset+0xe)*1000; + bios->pll_lst[i].VCO2.minInputFreq = READ_SHORT(rom, offset+0x10)*1000; + bios->pll_lst[i].VCO2.maxInputFreq = READ_SHORT(rom, offset+0x12)*1000; + + /* Low and high values for the dividers and multipliers */ + bios->pll_lst[i].VCO1.minN = READ_BYTE(rom, offset+0x14); + bios->pll_lst[i].VCO1.maxN = READ_BYTE(rom, offset+0x15); + bios->pll_lst[i].VCO1.minM = READ_BYTE(rom, offset+0x16); + bios->pll_lst[i].VCO1.maxM = READ_BYTE(rom, offset+0x17); + bios->pll_lst[i].VCO2.minN = READ_BYTE(rom, offset+0x18); + bios->pll_lst[i].VCO2.maxN = READ_BYTE(rom, offset+0x19); + bios->pll_lst[i].VCO2.minM = READ_BYTE(rom, offset+0x1a); + bios->pll_lst[i].VCO2.maxM = READ_BYTE(rom, offset+0x1b); + + bios->pll_lst[i].var1d = READ_BYTE(rom, offset+0x1d); + bios->pll_lst[i].var1e = READ_BYTE(rom, offset+0x1e); + +#if DEBUG + printf("register: %#08x\n", READ_INT(rom, offset)); + + /* Minimum/maximum frequency each VCO can generate */ + printf("minVCO_1: %d\n", READ_SHORT(rom, offset+4)); + printf("maxVCO_1: %d\n", READ_SHORT(rom, offset+6)); + printf("minVCO_2: %d\n", READ_SHORT(rom, offset+8)); + printf("maxVCO_2: %d\n", READ_SHORT(rom, offset+0xa)); + + /* Minimum/maximum input frequency for each VCO */ + printf("minVCO_1_in: %d\n", READ_SHORT(rom, offset+0xc)); + printf("minVCO_2_in: %d\n", READ_SHORT(rom, offset+0xe)); + printf("maxVCO_1_in: %d\n", READ_SHORT(rom, offset+0x10)); + printf("maxVCO_2_in: %d\n", READ_SHORT(rom, offset+0x12)); + + /* Low and high values for the dividers and multipliers */ + printf("N1_low: %d\n", READ_BYTE(rom, offset+0x14)); + printf("N1_high: %d\n", READ_BYTE(rom, offset+0x15)); + printf("M1_low: %d\n", READ_BYTE(rom, offset+0x16)); + printf("M1_high: %d\n", READ_BYTE(rom, offset+0x17)); + printf("N2_low: %d\n", READ_BYTE(rom, offset+0x18)); + printf("N2_high: %d\n", READ_BYTE(rom, offset+0x19)); + printf("M2_low: %d\n", READ_BYTE(rom, offset+0x1a)); + printf("M2_high: %d\n", READ_BYTE(rom, offset+0x1b)); + + /* What's the purpose of these? */ + printf("1c: %d\n", READ_BYTE(rom, offset+0x1c)); + printf("1d: %d\n", READ_BYTE(rom, offset+0x1d)); + printf("1e: %d\n", READ_BYTE(rom, offset+0x1e)); + printf("\n"); +#endif + + bios->pll_entries = i+1; + offset += header->entry_size; + } +} + +/* The internal gpu sensor most likely consists of a diode and a resistor. + / The voltage across this resistor is meassured using a ADC. Since the + / voltage-current relationship of a diode isn't linear the value needs some correction. + / The temperature can be calculated by scaling the output value of the ADC and adding an offset + / to it. + / + / This function reads the temperature table and reads the offset/scaling constants for the + / temperature calculation formula. Before I didn't know where and how these values were stored and + / used some hardcoded (wrong) values. I expected the values to be tored near the place where + / the temperature sensor enable/disable bit was but I didn't have the time to figure it all out. + / The code below is very similar to the code from the Rivatuner gpu diode by Alexey Nicolaychuk with a few adjustments. + / Rivatuner's code didn't contain constants for the latest Geforce7 (NV46/NV49/NV4B) cards so I had to add those myself. + */ +static void parse_bit_temperature_table(struct nvbios *bios, char *rom, int offset) +{ + short i; + BitTableHeader *header = (BitTableHeader*)&rom[offset]; + + switch(get_gpu_arch(bios->device_id)) + { + case NV43: + bios->sensor_cfg.diode_offset_mult = 32060; + bios->sensor_cfg.diode_offset_div = 1000; + bios->sensor_cfg.slope_mult = 792; + bios->sensor_cfg.slope_div = 1000; + break; + case NV44: + case NV47: + bios->sensor_cfg.diode_offset_mult = 27839; + bios->sensor_cfg.diode_offset_div = 1000; + bios->sensor_cfg.slope_mult = 780; + bios->sensor_cfg.slope_div = 1000; + break; + case NV46: /* are these really the default ones? they come from a 7300GS bios */ + bios->sensor_cfg.diode_offset_mult = -24775; + bios->sensor_cfg.diode_offset_div = 100; + bios->sensor_cfg.slope_mult = 467; + bios->sensor_cfg.slope_div = 10000; + break; + case NV49: /* are these really the default ones? they come from a 7900GT/GTX bioses */ + bios->sensor_cfg.diode_offset_mult = -25051; + bios->sensor_cfg.diode_offset_div = 100; + bios->sensor_cfg.slope_mult = 458; + bios->sensor_cfg.slope_div = 10000; + break; + case NV4B: /* are these really the default ones? they come from a 7600GT bios */ + bios->sensor_cfg.diode_offset_mult = -24088; + bios->sensor_cfg.diode_offset_div = 100; + bios->sensor_cfg.slope_mult = 442; + bios->sensor_cfg.slope_div = 10000; + break; + } + + offset += header->start; + for(i=0; inum_entries; i++) + { + unsigned char id = rom[offset]; + short value = READ_SHORT(rom, offset+1); + + switch(id) + { + /* The temperature section can store settings for more than just the builtin sensor. + / The value of 0x0 sets the channel for which the values below are meant. Right now + / we ignore this as we only use option 0x10-0x13 which are specific to the builtin sensor. + / Further what do 0x33/0x34 contain? Those appear on Geforce7300/7600/7900 cards. + */ + case 0x1: +#if DEBUG + printf("0x1: (%0x) %d 0x%0x\n", value, (value>>9) & 0x7f, value & 0x3ff); +#endif + if((value & 0x8f) == 0) + bios->sensor_cfg.temp_correction = (value>>9) & 0x7f; + break; + /* An id of 4 seems to correspond to a temperature threshold but 5, 6 and 8 have similar values, what are they? */ + case 0x4: + case 0x5: + case 0x6: + case 0x8: + /* printf("0x%x: 0x%x %d\n", id, value & 0xf, (value>>4) & 0x1ff); */ + break; + case 0x10: + bios->sensor_cfg.diode_offset_mult = value; + break; + case 0x11: + bios->sensor_cfg.diode_offset_div = value; + break; + case 0x12: + bios->sensor_cfg.slope_mult = value; + break; + case 0x13: + bios->sensor_cfg.slope_div = value; + break; +#if DEBUG + default: + printf("0x%x: %x\n", id, value); +#endif + } + offset += header->entry_size; + } +#if DEBUG + printf("temperature table version: %#x\n", header->version); + printf("correction: %d\n", bios->sensor_cfg.temp_correction); + printf("offset: %.3f\n", (float)bios->sensor_cfg.diode_offset_mult / (float)bios->sensor_cfg.diode_offset_div); + printf("slope: %.3f\n", (float)bios->sensor_cfg.slope_mult / (float)bios->sensor_cfg.slope_div); +#endif +} + +/* Read the voltage table for nv30/nv40/nv50 cards */ +static void parse_voltage_table(struct nvbios *bios, char *rom, int offset) +{ + unsigned char entry_size=0; + unsigned char start=0; + int i; + + /* In case of the first voltage table revision, there was no start pointer? */ + switch(rom[offset]) + { + case 0x10: + case 0x12: + start = 5; + entry_size = rom[offset+1]; + bios->volt_entries = rom[offset+2]; + bios->volt_mask = rom[offset+4]; + break; + default: + start = rom[offset+1]; + bios->volt_entries = rom[offset+2]; + entry_size = rom[offset+3]; + + /* The VID mask is stored right before the start of the first entry? */ + bios->volt_mask = rom[offset+start -1]; + } + + offset += start; + for(i=0; ivolt_entries; i++) + { + /* The voltage is stored in multiples of 10mV, scale it to V */ + bios->volt_lst[i].voltage = (float)(unsigned char)rom[offset] / 100; + bios->volt_lst[i].VID = rom[offset + 1]; + offset += entry_size; + } +} + + +static void nv5_parse(struct nvbios *bios, char *rom, unsigned short nv_offset) +{ + /* Go to the position containing the offset to the card name, it is 30 away from NV. */ + int offset = READ_SHORT(rom, nv_offset + 30); + bios->signon_msg = nv_read(rom, offset); +} + + +static void nv30_parse(struct nvbios *bios, char *rom, unsigned short nv_offset) +{ +// unsigned short init_offset = 0; + unsigned short perf_offset = 0; + unsigned short volt_offset = 0; + + int offset = READ_SHORT(rom, nv_offset + 30); + bios->signon_msg = nv_read(rom, offset); + +// init_offset = READ_SHORT(rom, nv_offset + 0x4d); + + volt_offset = READ_SHORT(rom, nv_offset + 0x98); + parse_voltage_table(bios, rom, volt_offset); + + perf_offset = READ_SHORT(rom, nv_offset + 0x94); + parse_nv30_performance_table(bios, rom, perf_offset); +} + + +static void parse_bit_structure(struct nvbios *bios, char *rom, unsigned int bit_offset) +{ + //IOLog("Parsing BIT structure\n"); + unsigned short init_offset=0; + unsigned short perf_offset=0; + unsigned short pll_offset=0; + unsigned short signon_offset=0; + unsigned short temp_offset=0; + unsigned short volt_offset=0; + unsigned short offset=0; + + struct bit_entry + { + unsigned char id[2]; /* first byte is ID, second byte sub-ID? */ + unsigned short len; /* size of data pointed to by offset */ + unsigned short offset; /* offset of data */ + } *entry; + + /* In older nvidia bioses there was some start position and at fixed positions from there offsets to various tables were stored. + / For Geforce6 bioses this is all different. There is still some start position (now called BIT) but offsets to tables aren't at fixed + / positions from the start. There's now some weird pattern which starts a few places from the start of the BIT section. + / This pattern seems to consist of a subset of the alphabet (all in uppercase). After each such token there is the length of the data + / referred to by the entry and an offset. The first entry "0x00 0x01" is probably somewhat different since the length/offset info + / seems to be a bit strange. The list ends with the entry "0x00 0x00" + */ + + /* skip 'B' 'I' 'T' '\0' */ + offset = bit_offset + 4; + + /* read the entries */ + while (1) + { + entry = (struct bit_entry *)&rom[offset]; + if ((entry->id[0] == 0) && (entry->id[1] == 0)) + break; + //IOLog("Got new entry: "); + + switch (entry->id[0]) + { + case 'B': /* BIOS related data */ + //IOLog("BIOS"); + bios->version = nv40_bios_version_to_str(rom, entry->offset); + break; + case 'C': /* Configuration table; it contains at least PLL parameters */ + //IOLog("Configuration"); + pll_offset = READ_SHORT(rom, entry->offset + 8); + parse_bit_pll_table(bios, rom, pll_offset); + break; + case 'I': /* Init table */ + //IOLog("Init"); + init_offset = READ_SHORT(rom, entry->offset); + parse_bit_init_script_table(bios, rom, init_offset, entry->len); + break; + case 'P': /* Performance related data */ + //IOLog("Performance"); + perf_offset = READ_SHORT(rom, entry->offset); + parse_bit_performance_table(bios, rom, perf_offset); + + temp_offset = READ_SHORT(rom, entry->offset + 0xc); + parse_bit_temperature_table(bios, rom, temp_offset); + + /* 0x10 behind perf_offset the voltage table offset is stored */ + volt_offset = READ_SHORT(rom, entry->offset + 0x10); + parse_voltage_table(bios, rom, volt_offset); + break; + case 'S': + //IOLog("String table"); + /* table with string references of signon-message, + BIOS version, BIOS copyright, OEM string, VESA vendor, + VESA Product Name, and VESA Product Rev. + table consists of offset, max-string-length pairs + for all strings */ + //IOLog("Or panic was here?"); + signon_offset = READ_SHORT(rom, entry->offset); + bios->signon_msg = nv_read(rom, signon_offset); + break; + } + //IOLog("\n"); + + offset += sizeof(struct bit_entry); + } + //IOLog("It has been parsed!!!\n"); +} + + +static unsigned int locate(char *rom, const char *str, int offset) +{ + unsigned int size = (unsigned int)strlen(str); + + /* We shouldn't assume this is allways 64kB */ + for(unsigned int i=offset; iarch) + return 0; + + /* On NV5x cards we need to let pramin point to the bios */ + if (nv_card->arch & NV5X) + { + uint32_t vbios_vram = (nv_card->PDISPLAY[0x9f04/4] & ~0xff) << 8; + + if (!vbios_vram) + vbios_vram = (nv_card->PMC[0x1700/4] << 16) + 0xf0000; + + old_bar0_pramin = nv_card->PMC[0x1700/4]; + nv_card->PMC[0x1700/4] = (vbios_vram >> 16); + } + + /* Copy bios data */ + bios = (char*)nv_card->PRAMIN; + memcpy(data, bios, NV_PROM_SIZE); + + if (nv_card->arch & NV5X) + nv_card->PMC[0x1700/4] = old_bar0_pramin; + + /* Make sure the bios is correct */ + if(verify_bios(data)) + return 1; + else + return 0; +} + +/* Load the video bios from the ROM. Note laptops might not have a ROM which can be accessed from the GPU */ +int load_bios_prom(char *data) +{ + int i; + + /* enable bios parsing; on some boards the display might turn off */ + nv_card->PMC[0x1850/4] = 0x0; + + for(i=0; iPROM[i]; + data[i] = nv_card->PROM[i]; + data[i] = nv_card->PROM[i]; + data[i] = nv_card->PROM[i]; + data[i] = nv_card->PROM[i]; + } + + /* disable the rom; if we don't do it the screens stays black on some cards */ + nv_card->PMC[0x1850/4] = 0x1; + + /* Make sure the bios is correct */ + if(verify_bios(data)) + return 1; + else + return 0; +} + +/* This function tries to read a copy of the bios from harddrive. If that doesn't + exist it will dump the bios and then read it. You might wonder why we don't read the bios from + card. The reason behind that is that some bioses are slow to read (can take seconds) and second on some + cards (atleast on my gf2mx) the screen becomes black if I enable reading of the rom. + */ +struct nvbios *read_bios(const char *file) +{ + struct nvbios *res; + char *rom = (char*)IOMalloc(NV_PROM_SIZE); + if(!rom) { + InfoLog("Memory allocation error"); + return NULL; + } + if(!load_bios_prom(rom)) + { + InfoLog("Error reading BIOS"); + IOFree(rom, NV_PROM_SIZE); + return NULL; + } + else { + InfoLog("BIOS successfully read"); + } + + + /* Do the actual bios parsing */ + res = parse_bios(rom); + //IOLog("Parsing BIOS complete\n"); + /* Cleanup the mess */ + IOFree(rom, NV_PROM_SIZE); + + return res; +} + + +struct nvbios *parse_bios(char *rom) +{ + //IOLog("Parsing BIOS...\n"); + unsigned short bit_offset = 0; + unsigned short nv_offset = 0; + unsigned short pcir_offset = 0; + unsigned short device_id = 0; + struct nvbios *bios; + //int i=0; + + //IOLog("Checking BIOS\n"); + /* All bioses start with this '0x55 0xAA' signature */ + if((rom[0] != 0x55) || (rom[1] != (char)0xAA)) + return NULL; + + //IOLog("Checking PCIR\n"); + /* Fail when the PCIR header can't be found; it is present on all PCI bioses */ + if(!(pcir_offset = locate(rom, "PCIR", 0))) + return NULL; + + //IOLog("Checking vendor\n"); + /* Fail if the bios is not from an Nvidia card */ + if(READ_SHORT(rom, pcir_offset + 4) != 0x10de) + return NULL; + + device_id = READ_SHORT(rom, pcir_offset + 6); + if(get_gpu_arch(device_id) & (NV4X | NV5X)) + { + //IOLog("It's new card\n"); + /* For NV40 card the BIT structure is used instead of the BMP structure (last one doesn't exist anymore on 6600/6800le cards). */ + //IOLog("Checking BIT\n"); + if(!(bit_offset = locate(rom, "BIT", 0))) + return NULL; + //IOLog("Allocating memory for BIOS structure\n"); + // bios = (nvbios*)IOMalloc(sizeof(nvbios)); + bios = new nvbios; + bios->device_id = device_id; + parse_bit_structure(bios, rom, bit_offset); + //IOLog("BIT structure parsed\n"); + } + /* We are dealing with a card that only contains the BMP structure */ + else + { + int version; + + /* The main offset starts with "0xff 0x7f NV" */ + if(!(nv_offset = locate(rom, "\xff\x7fNV", 0))) + return NULL; + + /* We don't support old bioses. Mainly some old tnt1 models */ + if(rom[nv_offset + 5] < 5) + return NULL; + + // bios = (nvbios*)IOMalloc(sizeof(nvbios)); + bios = new nvbios; + bios->device_id = device_id; + + bios->major = (char)rom[nv_offset + 5]; + bios->minor = (char)rom[nv_offset + 6]; + + /* Go to the bios version */ + /* Not perfect for bioses containing 5 numbers */ + version = READ_INT(rom, nv_offset + 10); + bios->version = bios_version_to_str(version); + + /* Use nv30_parse for all NV3X cards; for overclocking purposes the 5200 is considered + / a NV25 card but in this case it really is a NV3X board. + */ + if((get_gpu_arch(device_id) & NV3X) || ((device_id & 0xff0) == 0x320)) + nv30_parse(bios, rom, nv_offset); + else + nv5_parse(bios, rom, nv_offset); + } + +#if 0 + if(bios) + { + int i; + printf("-- VideoBios information --\n"); + printf("Version: %s\n", bios->version); + printf("Signon message: %s\n", bios->signon_msg); + + for(i=0; i< bios->perf_entries; i++) + { + if(bios->volt_entries) + { + if(bios->perf_lst[i].delta) + /* For now assume the first memory entry is the right one; should be fixed as some bioses contain various different entries */ + printf("Performance level %d: gpu %d(+%d)MHz/memory %dMHz/ %.2fV / %d%%\n", i, bios->perf_lst[i].nvclk, bios->perf_lst[i].delta, bios->perf_lst[i].memclk, bios->perf_lst[i].voltage, bios->perf_lst[i].fanspeed); + else if(bios->perf_lst[i].shaderclk) + printf("Performance level %d: gpu %d/shader %dMHz/memory %dMHz/ %.2fV / %d%%\n", i, bios->perf_lst[i].nvclk, bios->perf_lst[i].shaderclk, bios->perf_lst[i].memclk, bios->perf_lst[i].voltage, bios->perf_lst[i].fanspeed); + else + printf("Performance level %d: gpu %dMHz/memory %dMHz/ %.2fV / %d%%\n", i, bios->perf_lst[i].nvclk, bios->perf_lst[i].memclk, bios->perf_lst[i].voltage, bios->perf_lst[i].fanspeed); + } + else + printf("Performance level %d: %dMHz / %dMHz / %d%%\n", i, bios->perf_lst[i].nvclk, bios->perf_lst[i].memclk, bios->perf_lst[i].fanspeed); + } + + if(bios->volt_entries) + printf("VID mask: %x\n", bios->volt_mask); + + for(i=0; i< bios->volt_entries; i++) + { + /* For now assume the first memory entry is the right one; should be fixed as some bioses contain various different entries */ + /* Note that voltage entries in general don't correspond to performance levels!! */ + printf("Voltage level %d: %.2fV, VID: %x\n", i, bios->volt_lst[i].voltage, bios->volt_lst[i].VID); + } + printf("\n"); + } +#endif + //IOLog("Returning BIOS structure\n"); + return bios; +} diff --git a/plugins/GPUSensors/NVClockX/NVClock/error.cpp b/plugins/GPUSensors/NVClockX/NVClock/error.cpp new file mode 100644 index 0000000..fbe82b0 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/error.cpp @@ -0,0 +1,63 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2004 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +//#include +//#include +#include + +#include "nvclock.h" + +void set_error(int code) +{ + nvclock.nv_errno = code; +} + + +void set_error_str(const char *str) +{ + nvclock.nv_errno = NV_ERR_OTHER; + + /* hacky; we need to think about memory management .. */ + nvclock.nv_err_str = /*(char*)strdup(str)*/NULL; +} + + +char *get_error(char *buf, int size) +{ + switch(nvclock.nv_errno) + { + case NV_ERR_NO_DEVICES_FOUND: + buf=STRDUP("No nvidia cards found in your system!", sizeof("No nvidia cards found in your system!")); + break; + case NV_ERR_NO_DRIVERS_FOUND: + buf=STRDUP("You don't have enough permissions to run NVClock! Retry as root or install the Nvidia drivers.", sizeof("You don't have enough permissions to run NVClock! Retry as root or install the Nvidia drivers.")); + break; + case NV_ERR_NOT_ENOUGH_PERMISSIONS: + buf=STRDUP("You don't have enough permissions to run NVClock! Retry as root.", sizeof("You don't have enough permissions to run NVClock! Retry as root.")); + break; + case NV_ERR_OTHER: + buf=STRDUP(nvclock.nv_err_str, 80); + break; + } + + return buf; +} diff --git a/plugins/GPUSensors/NVClockX/NVClock/f75375.cpp b/plugins/GPUSensors/NVClockX/NVClock/f75375.cpp new file mode 100644 index 0000000..e71c1a1 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/f75375.cpp @@ -0,0 +1,164 @@ +/* Fintek F75375 sensor module + / Copyright(C) 2005, Matt Wright + */ + +#include +#include "i2c.h" +#include "f75375.h" + +int f75375_detect(I2CDevPtr dev) +{ + I2CByte nvl, nvh; + + xf86I2CReadByte(dev, FINTEK_VENDOR1, &nvl); + xf86I2CReadByte(dev, FINTEK_VENDOR2, &nvh); + + if (MERGE_BYTE(nvh, nvl) != 0x3419) + { + return 0; + } + + xf86I2CReadByte(dev, ASUS_NV40_CHIPID_H, &nvh); + xf86I2CReadByte(dev, ASUS_NV40_CHIPID_L, &nvl); + + if (MERGE_BYTE(nvh, nvl) == 0x0306) + { + dev->chip_id = F75375; + dev->chip_name = (char*)STRDUP("Fintek F75375S", sizeof("Fintek F75375S")); + return 1; + } + if (MERGE_BYTE(nvh, nvl) == 0x0204) + { + dev->chip_id = F75375; + dev->chip_name = (char*)STRDUP("Fintek F75373S", sizeof("Fintek F75375S")); + return 1; + } + return 0; +} + + +int f75375_get_gpu_temp(I2CDevPtr dev) +{ + I2CByte nvh; + + xf86I2CReadByte(dev, F75375S_TEMP_GPU, &nvh); + return (int)nvh; +} + + +int f75375_get_fanspeed_rpm(I2CDevPtr dev) +{ + I2CByte nvh, nvl; + int rpm; + + xf86I2CReadByte(dev, F75375S_FAN1_COUNT_H, &nvh); + xf86I2CReadByte(dev, F75375S_FAN1_COUNT_L, &nvl); + + rpm = FAN_TO_RPM(nvh, nvl); + + return rpm; +} + + +int f75375_get_board_temp(I2CDevPtr dev) +{ + I2CByte nvh; + + xf86I2CReadByte(dev, F75375S_TEMP_RAM, &nvh); + return (int)nvh; +} + + +int f75375_set_fanspeed_rpm(I2CDevPtr dev, int desired_rpm) +{ + I2CByte nvh, nvl; + int desired_count; + + desired_count = RPM_TO_FAN(desired_rpm); + + nvh = (desired_count>>8) & 0x00ff; + nvl = (desired_count) & 0x00ff; + + xf86I2CWriteByte(dev, F75375S_FAN1_EXPECT_H, nvh); + xf86I2CWriteByte(dev, F75375S_FAN1_EXPECT_L, nvl); + return 1; +} + + +int f75375_set_gpu_tempctl(I2CDevPtr dev, fan_vtemp speeds) +{ + for (int i=0; i<4; i++) + { + xf86I2CWriteByte(dev, F75375S_VT1_B1 + i, speeds.temp[i]); + } + + for (int i=0; i<5; i++) + { + I2CByte nvh, nvl; + + int temp_speed = RPM_TO_FAN(speeds.speed[i]); + + nvh = (temp_speed >> 8) & 0x00ff; + nvl = (temp_speed) & 0x00ff; + + xf86I2CWriteByte(dev, F75375S_VT1_S1_H + (i*2), nvh); + xf86I2CWriteByte(dev, F75375S_VT1_S1_L + (i*2), nvl); + } + + return 0; +} + + +int f75375_get_gpu_tempctl(I2CDevPtr dev, fan_vtemp *speeds) +{ + I2CByte nvh, nvl; + + for (int i=0; i<4; i++) + { + xf86I2CReadByte(dev, F75375S_VT1_B1 + i, &nvl); + speeds->temp[i] = (int)nvl; + } + + for (int i=0; i<5; i++) + { + xf86I2CReadByte(dev, F75375S_VT1_S1_H + (i*2), &nvh); + xf86I2CReadByte(dev, F75375S_VT1_S1_L + (i*2), &nvl); + speeds->speed[i] = FAN_TO_RPM(nvh, nvl); + } + + return 0; +} + + +int f75375_get_gpu_fanmode(I2CDevPtr dev) +{ + I2CByte mode; + + xf86I2CReadByte(dev, F75375S_FAN1_MODE, &mode); + return (int)mode; +} + + +int f75375_set_gpu_fanmode(I2CDevPtr dev, I2CByte mode) +{ + xf86I2CWriteByte(dev, F75375S_FAN1_MODE, (I2CByte)mode); + return 0; +} + + +float f75375_get_fanspeed_pwm(I2CDevPtr dev) +{ + I2CByte speed; + + xf86I2CReadByte(dev, F75375S_FAN1_PWM, &speed); + return (float)speed*100/256; +} + + +int f75375_set_fanspeed_pwm(I2CDevPtr dev, float speed) +{ + I2CByte value = (I2CByte)(speed * 255/100); + + xf86I2CWriteByte(dev, F75375S_FAN1_PWM, value); + return 0; +} diff --git a/plugins/GPUSensors/NVClockX/NVClock/f75375.h b/plugins/GPUSensors/NVClockX/NVClock/f75375.h new file mode 100644 index 0000000..f036fd4 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/f75375.h @@ -0,0 +1,71 @@ +/* Fintek F75375 sensor module +/ Copyright(C) 2005, Matt Wright +*/ +#include "nvclock.h" +#include "i2c.h" + +int debug; +typedef struct _fan_vtemp +{ + int temp[4]; + int speed[5]; +} fan_vtemp; + + +#define dbg_printf(x) if (debug==1) printf(x) + +#define MODE_SPEED 0x00 +#define MODE_TEMP 0x10 +#define MODE_PWM 0x20 + +int f75375_get_gpu_fanmode(I2CDevPtr dev); +int f75375_set_gpu_fanmode(I2CDevPtr dev, I2CByte mode); +int f75375_set_gpu_tempctl(I2CDevPtr dev, fan_vtemp speeds); +int f75375_get_gpu_tempctl(I2CDevPtr dev, fan_vtemp *speeds); + +#define FINTEK_VENDOR1 0x5d +#define FINTEK_VENDOR2 0x5e + +#define ASUS_NV40_CHIPID_H 0x5a +#define ASUS_NV40_CHIPID_L 0x5b + +#define F75375S_VRAM_VCC 0x10 +#define F75375S_VRAM_V1 0x11 +#define F75375S_VRAM_V2 0x12 +#define F75375S_VRAM_V3 0x13 +#define F75375S_VRAM_TEMP1 0x14 +#define F75375S_VRAM_TEMP2 0x15 +#define F75375S_VRAM_FAN1_MSB 0x16 +#define F75375S_VRAM_FAN1_LSB 0x17 +#define F75375S_VRAM_FAN2_MSB 0x18 +#define F75375S_VRAM_FAN2_LSB 0x19 + +#define F75375S_FAN1_PWM 0x76 +#define F75375S_FAN1_COUNT_H 0x16 +#define F75375S_FAN1_COUNT_L 0x17 +#define F75375S_FAN1_MODE 0x60 +#define F75375S_FAN1_EXPECT_H 0x74 +#define F75375S_FAN1_EXPECT_L 0x75 + +#define F75375S_TEMP_GPU 0x14 +#define F75375S_TEMP_RAM 0x15 + +#define F75375S_VT1_B1 0xa0 +#define F75375S_VT1_B2 0xa1 +#define F75375S_VT1_B3 0xa2 +#define F75375S_VT1_B4 0xa3 + +#define F75375S_VT1_S1_H 0xa4 +#define F75375S_VT1_S1_L 0xa5 +#define F75375S_VT1_S2_H 0xa6 +#define F75375S_VT1_S2_L 0xa7 +#define F75375S_VT1_S3_H 0xa8 +#define F75375S_VT1_S3_L 0xa9 +#define F75375S_VT1_S4_H 0xaa +#define F75375S_VT1_S4_L 0xab +#define F75375S_VT1_S5_H 0xac +#define F75375S_VT1_S5_L 0xad + +#define FAN_TO_RPM(msb, lsb) (1500000/((msb<<8)+lsb)) +#define RPM_TO_FAN(x) (1500000/x) +#define MERGE_BYTE(msb, lsb) ((msb<<8)+lsb) diff --git a/plugins/GPUSensors/NVClockX/NVClock/i2c.cpp b/plugins/GPUSensors/NVClockX/NVClock/i2c.cpp new file mode 100644 index 0000000..48af6de --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/i2c.cpp @@ -0,0 +1,344 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2006 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * I2C support needed for hardware monitoring, this code is partly based on code from nvtv + * and the opensource xfree86 nv driver. + */ + +/* NVTV TV common routines -- Dirk Thierbach + * + * This file is part of nvtv, a tool for tv-output on NVidia cards. + * + * nvtv is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * nvtv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: i2c.c,v 1.14 2007/04/24 08:10:47 thunderbird Exp $ + * + * Contents: + * + * Header: Common tv-related routines. + * + */ + +/***************************************************************************\ + |* *| + |* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| + |* *| + |* NOTICE TO USER: The source code is copyrighted under U.S. and *| + |* international laws. Users and possessors of this source code are *| + |* hereby granted a nonexclusive, royalty-free copyright license to *| + |* use this code in individual and commercial software. *| + |* *| + |* Any use of this source code must include, in the user documenta- *| + |* tion and internal comments to the code, notices to the end user *| + |* as follows: *| + |* *| + |* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| + |* *| + |* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| + |* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| + |* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| + |* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| + |* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| + |* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| + |* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| + |* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| + |* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| + |* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| + |* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| + |* *| + |* U.S. Government End Users. This source code is a "commercial *| + |* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| + |* consisting of "commercial computer software" and "commercial *| + |* computer software documentation," as such terms are used in *| + |* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| + |* ment only as a commercial end item. Consistent with 48 C.F.R. *| + |* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| + |* all U.S. Government End Users acquire the source code with only *| + |* those rights set forth herein. *| + |* *| + \***************************************************************************/ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_dac.c,v 1.43 2004/11/30 23:50:26 mvojkovi Exp $ */ + +//#include +#include +#include "xf86i2c.h" +#include "backend.h" + +/* + * DDC1 support only requires DDC_SDA_MASK, + * DDC2 support requires DDC_SDA_MASK and DDC_SCL_MASK + */ +#define DDC_SDA_READ_MASK (1 << 3) +#define DDC_SCL_READ_MASK (1 << 2) +#define DDC_SDA_WRITE_MASK (1 << 4) +#define DDC_SCL_WRITE_MASK (1 << 5) + +static void NVLockUnlock(int lock) +{ + unsigned char cr11; + + nv_card->PCIO[0x3d4] = 0x1f; + nv_card->PCIO[0x3d5] = lock ? 0x99 : 0x57; + + nv_card->PCIO[0x3d4] = 0x11; + cr11 = nv_card->PCIO[0x3d5]; + if(lock) cr11 |= 0x80; + else cr11 &= ~0x80; + nv_card->PCIO[0x3d5] = cr11; +} + + +static void NV_I2CGetBits(I2CBusPtr b, int *clock, int *data) +{ + unsigned char val; + int DDCBase = (int)b->DriverPrivate.val; + + /* Get the result. */ + nv_card->PCIO[0x3d4] = DDCBase; + val = nv_card->PCIO[0x3d5]; + + *clock = (val & DDC_SCL_READ_MASK) != 0; + *data = (val & DDC_SDA_READ_MASK) != 0; +} + + +static void NV_I2CPutBits(I2CBusPtr b, int clock, int data) +{ + unsigned char val; + int DDCBase = (int)b->DriverPrivate.val; + + nv_card->PCIO[0x3d4] = DDCBase + 1; + val = nv_card->PCIO[0x3d5] & 0xf0; + if (clock) + val |= DDC_SCL_WRITE_MASK; + else + val &= ~DDC_SCL_WRITE_MASK; + + if (data) + val |= DDC_SDA_WRITE_MASK; + else + val &= ~DDC_SDA_WRITE_MASK; + + nv_card->PCIO[0x3d4] = DDCBase + 1; + nv_card->PCIO[0x3d5] = val | 0x1; +} + + +I2CBusPtr NV_I2CCreateBusPtr(char *name, int bus) +{ + I2CBusPtr I2CPtr; + + I2CPtr = xf86CreateI2CBusRec(); + if(!I2CPtr) return NULL; + + I2CPtr->BusName = name; + I2CPtr->scrnIndex = nv_card->number; /* We need to use unique indices or else it can lead to a segfault in multicard situations */ + I2CPtr->I2CAddress = I2CAddress; + I2CPtr->I2CPutBits = NV_I2CPutBits; + I2CPtr->I2CGetBits = NV_I2CGetBits; + I2CPtr->AcknTimeout = 5; + I2CPtr->DriverPrivate.val = bus; + + if (!xf86I2CBusInit(I2CPtr)) + { + return 0; + } + return I2CPtr; +} + + +static void ProbeDevice (I2CBusPtr bus, I2CSlaveAddr addr, const char *format, ...) +{ + I2CDevPtr dev; + char *s; + va_list ap; + + if(xf86I2CProbeAddress(bus, addr)) + { + dev = xf86CreateI2CDevRec(); + s = new char[8]; + va_start (ap, format); + vsnprintf (s, 7, format, ap); + va_end (ap); + dev->DevName = s; + dev->SlaveAddr = addr; + dev->pI2CBus = bus; + + if (!xf86I2CDevInit(dev)) + { + delete[] dev->DevName; + xf86DestroyI2CDevRec(dev, TRUE); + } + } +} + + +static void I2CProbeAllDevices (I2CBusPtr busses[], int nbus) +{ + I2CSlaveAddr addr; + int bus; + for (bus = 0; bus < nbus; bus++) + { + for (addr = 0x00; addr < 0x100; addr += 2) + { + ProbeDevice (busses[bus], addr, "%1i:%02X", bus, addr); + } + } +} + + +static I2CDevPtr I2cProbeDevices(I2CBusPtr busses[], int num_busses) +{ + int bus; + I2CDevPtr dev; + + /* Unlock the extended CRTC registers to get i2c working */ + NVLockUnlock(0); + + /* On NV40 cards the i2c busses can be disabled */ + if(nv_card->arch & NV4X) + { + nv_card->PCIO[0x3d4] = 0x49; + nv_card->PCIO[0x3d5] |= 0x4; /* Unlock the i2c busses */ + } + I2CProbeAllDevices(busses, num_busses); + + if(nv_card->debug) + printf("Probing I2C busses\n"); + + for(bus = 0; bus < num_busses; bus++) + { + for(dev = busses[bus]->FirstDev; dev; dev = dev->NextDev) + { + if(nv_card->debug) + printf("bus: %x device: %x\n", bus, dev->SlaveAddr); + + dev->arch = nv_card->arch; + switch(dev->SlaveAddr) + { + /* LM99 */ + case 0x98: + if(lm99_detect(dev)) + return dev; + break; + case 0x5a: + if(w83l785r_detect(dev)) + return dev; + if(w83781d_detect(dev)) + return dev; + case 0x5c: + if(f75375_detect(dev)) + return dev; + if(adt7473_detect(dev)) + return dev; + case 0x6e: /* DDC/CI ? */ + /* The addresses below oftenly appear on most cards but what are these? */ + case 0x70: + case 0xa0: + case 0xa2: + case 0xa4: + case 0xa6: + case 0xa8: + case 0xaa: + case 0xac: + case 0xae: + break; + default: + /* Unknown device */ + break; + } + } + } + + NVLockUnlock(1); + return NULL; +} + +void i2c_sensor_init(void) +{ + nv_card->sensor = I2cProbeDevices(nv_card->busses, nv_card->num_busses); + + /* When a sensor is available, enable the correct function pointers */ + if(nv_card->sensor) + { + nv_card->sensor_name = nv_card->sensor->chip_name; + + switch(nv_card->sensor->chip_id) + { + case LM99: + case MAX6559: + nv_card->caps |= BOARD_TEMP_MONITORING | GPU_TEMP_MONITORING; + nv_card->get_board_temp = lm99_get_board_temp; + nv_card->get_gpu_temp = lm99_get_gpu_temp; + break; + case F75375: + nv_card->caps |= BOARD_TEMP_MONITORING | GPU_TEMP_MONITORING | I2C_FANSPEED_MONITORING; + nv_card->get_board_temp = f75375_get_board_temp; + nv_card->get_gpu_temp = f75375_get_gpu_temp; + nv_card->get_i2c_fanspeed_rpm = f75375_get_fanspeed_rpm; + nv_card->get_i2c_fanspeed_pwm = f75375_get_fanspeed_pwm; + nv_card->set_i2c_fanspeed_pwm = f75375_set_fanspeed_pwm; + break; + case W83781D: + nv_card->caps |= BOARD_TEMP_MONITORING | GPU_TEMP_MONITORING | I2C_FANSPEED_MONITORING; + nv_card->get_board_temp = w83781d_get_board_temp; + nv_card->get_gpu_temp = w83781d_get_gpu_temp; + nv_card->get_i2c_fanspeed_rpm = w83781d_get_fanspeed_rpm; + nv_card->get_i2c_fanspeed_pwm = w83781d_get_fanspeed_pwm; + nv_card->set_i2c_fanspeed_pwm = w83781d_set_fanspeed_pwm; + break; + case W83L785R: + nv_card->caps |= BOARD_TEMP_MONITORING | GPU_TEMP_MONITORING | I2C_FANSPEED_MONITORING; + nv_card->get_board_temp = w83l785r_get_board_temp; + nv_card->get_gpu_temp = w83l785r_get_gpu_temp; + nv_card->get_i2c_fanspeed_rpm = w83l785r_get_fanspeed_rpm; + nv_card->get_i2c_fanspeed_pwm = w83l785r_get_fanspeed_pwm; + nv_card->set_i2c_fanspeed_pwm = w83l785r_set_fanspeed_pwm; + break; + case ADT7473: + nv_card->caps |= BOARD_TEMP_MONITORING | GPU_TEMP_MONITORING | I2C_FANSPEED_MONITORING | I2C_AUTOMATIC_FANSPEED_CONTROL; + nv_card->get_board_temp = adt7473_get_board_temp; + nv_card->get_gpu_temp = adt7473_get_gpu_temp; + nv_card->get_i2c_fanspeed_mode = adt7473_get_fanspeed_mode; + nv_card->set_i2c_fanspeed_mode = adt7473_set_fanspeed_mode; + nv_card->get_i2c_fanspeed_rpm = adt7473_get_fanspeed_rpm; + nv_card->get_i2c_fanspeed_pwm = adt7473_get_fanspeed_pwm; + nv_card->set_i2c_fanspeed_pwm = adt7473_set_fanspeed_pwm; + } + } + else + { + nv_card->sensor = NULL; + } +} + diff --git a/plugins/GPUSensors/NVClockX/NVClock/i2c.h b/plugins/GPUSensors/NVClockX/NVClock/i2c.h new file mode 100644 index 0000000..5cc99c0 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/i2c.h @@ -0,0 +1,76 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2005 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef I2C_H +#define I2C_H + +#include "xf86i2c.h" + +#define LM99 0x1 +#define MAX6559 0x2 +#define F75375 0x4 +#define W83L785R 0x8 +#define W83781D 0x16 +#define ADT7473 0x32 + +Bool I2CAddress(I2CDevPtr d, I2CSlaveAddr addr); +I2CBusPtr NV_I2CCreateBusPtr(char *name, int bus); + +/* ADT7473 */ +int adt7473_detect(I2CDevPtr dev); +int adt7473_get_board_temp(I2CDevPtr dev); +int adt7473_get_gpu_temp(I2CDevPtr dev); +int adt7473_get_fanspeed_rpm(I2CDevPtr dev); +float adt7473_get_fanspeed_pwm(I2CDevPtr dev); +int adt7473_set_fanspeed_pwm(I2CDevPtr dev, float speed); +int adt7473_get_fanspeed_mode(I2CDevPtr dev); +void adt7473_set_fanspeed_mode(I2CDevPtr dev, int mode); + +/* LM99 */ +int lm99_detect(I2CDevPtr dev); +int lm99_get_board_temp(I2CDevPtr dev); +int lm99_get_gpu_temp(I2CDevPtr dev); + +/* Fintek F75375 */ +int f75375_detect(I2CDevPtr dev); +int f75375_get_gpu_temp(I2CDevPtr dev); +int f75375_get_board_temp(I2CDevPtr dev); +int f75375_get_fanspeed_rpm(I2CDevPtr dev); +int f75375_set_fanspeed_rpm(I2CDevPtr dev, int desired_rpm); +float f75375_get_fanspeed_pwm(I2CDevPtr dev); +int f75375_set_fanspeed_pwm(I2CDevPtr dev, float speed); + +/* Winbond W83781D */ +int w83781d_detect(I2CDevPtr dev); +int w83781d_get_board_temp(I2CDevPtr dev); +int w83781d_get_gpu_temp(I2CDevPtr dev); +int w83781d_get_fanspeed_rpm(I2CDevPtr dev); +float w83781d_get_fanspeed_pwm(I2CDevPtr dev); +int w83781d_set_fanspeed_pwm(I2CDevPtr dev, float speed); + +/* Winbond W83L785R */ +int w83l785r_detect(I2CDevPtr dev); +int w83l785r_get_board_temp(I2CDevPtr dev); +int w83l785r_get_gpu_temp(I2CDevPtr dev); +int w83l785r_get_fanspeed_rpm(I2CDevPtr dev); +float w83l785r_get_fanspeed_pwm(I2CDevPtr dev); +int w83l785r_set_fanspeed_pwm(I2CDevPtr dev, float speed); +#endif /* I2C_H */ diff --git a/plugins/GPUSensors/NVClockX/NVClock/info.cpp b/plugins/GPUSensors/NVClockX/NVClock/info.cpp new file mode 100644 index 0000000..3d0c658 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/info.cpp @@ -0,0 +1,1557 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2007 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +//#include +//#include +#include +#include "backend.h" +#include "nvclock.h" + +char* get_bus_type(void); +char* get_agp_fw_status(void); +char* get_agp_sba_status(void); +char* get_agp_status(void); +char* get_memory_type(void); + +/* This list isn't used much for the speed ranges anymore */ +/* Mainly mobile gpu speeds are missing */ +static const struct pci_ids ids[] = +{ + { 0x0020, "RIVA [NV4 TNT]", DESKTOP }, + { 0x0028, "NV5 [RIVA TNT2/TNT2 Pro]", DESKTOP }, + { 0x002a, "NV5 [Riva TNT2]", DESKTOP }, + { 0x002b, "NV5 [Riva TNT2]", DESKTOP }, + { 0x00a0, "NV5 [Aladdin TNT2]", DESKTOP }, + { 0x002c, "NV6 [Vanta/Vanta LT]", DESKTOP }, + { 0x002d, "NV5M64 [RIVA TNT2 Model 64/Model 64 Pro]", DESKTOP }, + { 0x002e, "NV6 [Vanta]", DESKTOP }, + { 0x002f, "NV6 [Vanta]", DESKTOP }, + { 0x0029, "NV5 [RIVA TNT2 Ultra]", DESKTOP }, + { 0x0100, "NV10 [GeForce 256 SDR]", DESKTOP }, + { 0x0101, "NV10DDR [GeForce 256 DDR]", DESKTOP }, + { 0x0103, "NV10GL [Quadro]", DESKTOP }, + { 0x0110, "NV11 [GeForce2 MX/MX 400]", DESKTOP }, + { 0x0111, "NV11DDR [GeForce2 MX200]", DESKTOP }, + { 0x0112, "NV11 [GeForce2 Go]", MOBILE }, + { 0x0113, "NV11GL [Quadro2 MXR/EX/Go]", MOBILE }, + { 0x01a0, "nVidia Geforce 2 MX integrated [?]", NFORCE }, + { 0x0150, "NV15 [GeForce2 GTS/Pro]", DESKTOP }, + { 0x0151, "NV15DDR [GeForce2 Ti]", DESKTOP }, + { 0x0152, "NV15BR [GeForce2 Ultra, Bladerunner]", DESKTOP }, + { 0x0153, "NV15GL [Quadro2 Pro]", DESKTOP }, + { 0x0170, "NV17 [GeForce4 MX 460]", DESKTOP }, + { 0x0171, "NV17 [GeForce4 MX 440]", DESKTOP }, + { 0x0172, "NV17 [GeForce4 MX 420]", DESKTOP }, + { 0x0173, "NV17 [GeForce4 MX 440-SE]", DESKTOP }, + { 0x0174, "NV17 [GeForce4 440 Go]", MOBILE }, + { 0x0175, "NV17 [GeForce4 420 Go]", MOBILE }, + { 0x0176, "NV17 [GeForce4 420 Go 32M]", MOBILE }, + { 0x0177, "NV17 [GeForce4 460 Go]", MOBILE }, + { 0x0178, "NV17GL [Quadro4 550 XGL]", DESKTOP }, + { 0x0179, "NV17 [GeForce4 440 Go 64M]", MOBILE }, + { 0x017a, "NV17GL [Quadro NVS]", DESKTOP }, + { 0x017b, "NV17GL [Quadro4 550 XGL]", DESKTOP }, + { 0x017c, "NV17GL [Quadro4 500 GoGL]", MOBILE }, + { 0x017d, "NV17 [GeForce4 410 Go 16M]", MOBILE }, + { 0x0180, "nVidia Geforce 4 MX440 8X [?]", DESKTOP }, + { 0x0181, "NV18 [GeForce4 MX 440 AGP 8x]", DESKTOP }, + { 0x0182, "NV18 [GeForce4 MX 440SE AGP 8x]", DESKTOP }, + { 0x0185, "NV18 [GeForce4 MX 4000]", DESKTOP }, + { 0x0183, "NV18 [GeForce4 MX 420 AGP 8x]", DESKTOP }, + { 0x0186, "NV18M [GeForce4 448 Go]", MOBILE }, + { 0x0187, "NV18M [GeForce4 488 Go]", MOBILE }, + { 0x0188, "NV18GL [Quadro4 580 XGL]", DESKTOP }, + { 0x018a, "NV18GL [Quadro NVS 280 SD]", DESKTOP }, + { 0x018b, "NV18GL [Quadro4 380 XGL]", DESKTOP }, + { 0x018c, "NV18GL [Quadro NVS 50 PCI]", DESKTOP }, + { 0x018d, "NV18M [GeForce4 448 Go]", MOBILE }, + { 0x01f0, "NV18 [GeForce4 MX - nForce GPU]", NFORCE }, + { 0x0200, "NV20 [GeForce3]", DESKTOP }, + { 0x0201, "NV20 [GeForce3 Ti 200]", DESKTOP }, + { 0x0202, "NV20 [GeForce3 Ti 500]", DESKTOP }, + { 0x0203, "NV20DCC [Quadro DCC]", DESKTOP }, + { 0x0250, "NV25 [GeForce4 Ti 4600]", DESKTOP }, + { 0x0251, "NV25 [GeForce4 Ti 4400]", DESKTOP }, + { 0x0253, "NV25 [GeForce4 Ti 4200]", DESKTOP }, + { 0x0258, "NV25GL [Quadro4 900 XGL]", DESKTOP }, + { 0x0259, "NV25GL [Quadro4 750 XGL]", DESKTOP }, + { 0x025a, "nVidia Quadro 4 600 XGL [?]", DESKTOP }, + { 0x025b, "NV25GL [Quadro4 700 XGL]", DESKTOP }, + { 0x0280, "NV28 [GeForce4 Ti 4800]", DESKTOP }, + { 0x0281, "NV28 [GeForce4 Ti 4200 AGP 8x]", DESKTOP }, + { 0x0282, "NV28 [GeForce4 Ti 4800 SE]", DESKTOP }, + { 0x0286, "NV28 [GeForce4 Ti 4200 Go AGP 8x]", MOBILE }, + { 0x0288, "NV28GL [Quadro4 980 XGL]", DESKTOP }, + { 0x0289, "NV28GL [Quadro4 780 XGL]", DESKTOP }, + { 0x028c, "NV28GLM [Quadro4 Go700]", MOBILE }, + { 0x0300, "NV30 [GeForce FX]", DESKTOP }, + { 0x0301, "NV30 [GeForce FX 5800 Ultra]", DESKTOP }, + { 0x0302, "NV30 [GeForce FX 5800]", DESKTOP }, + { 0x0308, "NV30GL [Quadro FX 2000]", DESKTOP }, + { 0x0309, "NV30GL [Quadro FX 1000]", DESKTOP }, + { 0x0311, "NV31 [GeForce FX 5600 Ultra]", DESKTOP }, + { 0x0312, "NV31 [GeForce FX 5600]", DESKTOP }, + { 0x0314, "NV31 [GeForce FX 5600XT]", DESKTOP }, + { 0x0316, "NV31M [?]", MOBILE }, + { 0x0317, "NV31M Pro [?]", MOBILE }, + { 0x0318, "nVidia NV31GL [?]", DESKTOP }, + { 0x0319, "nVidia NV31GL [?]", DESKTOP }, + { 0x031a, "NV31M [GeForce FX Go5600]", MOBILE }, + { 0x031b, "NV31M [GeForce FX Go5650]", MOBILE }, + { 0x031c, "NV31 [Quadro FX Go700]", MOBILE }, + { 0x031d, "NV31GLM [?]", MOBILE }, + { 0x031e, "NV31GLM Pro [?]", MOBILE }, + { 0x031f, "NV31GLM Pro [?]", MOBILE }, + { 0x0321, "NV34 [GeForce FX 5200 Ultra]", DESKTOP }, + { 0x0322, "NV34 [GeForce FX 5200]", DESKTOP }, + { 0x0323, "NV34 [GeForce FX 5200LE]", DESKTOP }, + { 0x0324, "NV34M [GeForce FX Go5200 64M]", MOBILE }, + { 0x0325, "NV34M [GeForce FX Go5250]", MOBILE }, + { 0x0326, "NV34 [GeForce FX 5500]", DESKTOP }, + { 0x0328, "NV34M [GeForce FX Go5200 32M/64M]", MOBILE }, + { 0x0329, "NV34M [GeForce FX Go5200]", MOBILE }, + { 0x032a, "NV34GL [Quadro NVS 280 PCI]", DESKTOP }, + { 0x032b, "NV34GL [Quadro FX 500/600 PCI]", DESKTOP }, + { 0x032c, "NV34GLM [GeForce FX Go 5300]", MOBILE }, + { 0x032d, "NV34 [GeForce FX Go5100]", MOBILE }, + { 0x032f, "NV34GL [?]", DESKTOP }, + { 0x0330, "NV35 [GeForce FX 5900 Ultra]", DESKTOP }, + { 0x0331, "NV35 [GeForce FX 5900]", DESKTOP }, + { 0x0332, "NV35 [GeForce FX 5900XT]", DESKTOP }, + { 0x0333, "NV38 [GeForce FX 5950 Ultra]", DESKTOP }, + { 0x0334, "NV35 [GeForce FX 5900ZT]", DESKTOP }, + { 0x0338, "NV35GL [Quadro FX 3000]", DESKTOP }, + { 0x033f, "NV35GL [Quadro FX 700]", DESKTOP }, + { 0x0341, "NV36.1 [GeForce FX 5700 Ultra]", DESKTOP }, + { 0x0342, "NV36.2 [GeForce FX 5700]", DESKTOP }, + { 0x0343, "NV36 [GeForce FX 5700LE]", DESKTOP }, + { 0x0344, "NV36.4 [GeForce FX 5700VE]", DESKTOP }, + { 0x0345, "NV36.5 [?]", DESKTOP }, + { 0x0347, "NV36 [GeForce FX Go5700]", MOBILE }, + { 0x0348, "NV36 [GeForce FX Go5700]", MOBILE }, + { 0x0349, "NV36M Pro [?]", MOBILE }, + { 0x034b, "NV36MAP [?]", MOBILE }, + { 0x034c, "NV36 [Quadro FX Go1000]", MOBILE }, + { 0x034e, "NV36GL [Quadro FX 1100]", DESKTOP }, + { 0x034f, "NV36GL [?]", DESKTOP }, + { 0x02a0, "NV2A [XGPU] Xbox Graphics Processing Unit (Integrated).", NFORCE }, + { 0x0040, "NV40 [GeForce 6800 Ultra]", DESKTOP }, + { 0x0041, "NV40 [GeForce 6800]", DESKTOP }, + { 0x0042, "NV40.2 [GeForce 6800 LE]", DESKTOP }, + { 0x0043, "NV40.3 [GeForce 6800 XE]", DESKTOP }, + { 0x0044, "NV40 [GeForce 6800 XT]", DESKTOP }, + { 0x0045, "NV40 [GeForce 6800 GT]", DESKTOP }, + { 0x0046, "NV45 [GeForce 6800 GT]", DESKTOP }, + { 0x0047, "NV40 [GeForce 6800 GS]", DESKTOP }, + { 0x0048, "NV40 [GeForce 6800 XT]", DESKTOP }, + { 0x0049, "NV40GL [?]", DESKTOP }, + { 0x004d, "NV40GL [Quadro FX 4000]", DESKTOP }, + { 0x004e, "NV40GL [Quadro FX 4000]", DESKTOP }, + { 0x00c0, "NV41 [GeForce 6800 GS]", DESKTOP }, + { 0x00c1, "NV41.1 [GeForce 6800]", DESKTOP }, + { 0x00c2, "NV41.2 [GeForce 6800 LE]", DESKTOP }, + { 0x00c3, "NV42 [GeForce 6800 XT]", DESKTOP }, + { 0x00c8, "NV41.8 [GeForce Go 6800]", MOBILE }, + { 0x00c9, "NV41.9 [GeForce Go 6800 Ultra]", MOBILE }, + { 0x00cc, "NV41 [Quadro FX Go1400]", MOBILE }, + { 0x00cd, "NV41 [Quadro FX 3450/4000 SDI]", DESKTOP }, + { 0x00ce, "NV41GL [Quadro FX 1400]", DESKTOP }, + { 0x00f0, "NV40 [GeForce 6800 Ultra]", DESKTOP }, + { 0x00f1, "NV43 [GeForce 6600 GT]", DESKTOP }, + { 0x00f2, "NV43 [GeForce 6600]", DESKTOP }, + { 0x00f3, "NV43 [GeForce 6200]", DESKTOP }, + { 0x00f4, "NV43 [GeForce 6600 LE]", DESKTOP }, + { 0x00f5, "G70 [GeForce 7800 GS]", DESKTOP }, + { 0x00f6, "NV43 [GeForce 6800 GS]", DESKTOP }, + { 0x00f8, "NV45GL [Quadro FX 3400/4400]", DESKTOP }, + { 0x00f9, "NV45 [GeForce 6800 GTO]", DESKTOP }, + { 0x00fa, "NV36 [GeForce PCX 5750]", DESKTOP }, + { 0x00fb, "NV35 [GeForce PCX 5900]", DESKTOP }, + { 0x00fc, "NV37GL [Quadro FX 330/GeForce PCX 5300]", DESKTOP }, + { 0x00fd, "NV37GL [Quadro PCI-E Series]", DESKTOP }, + { 0x00fe, "NV38GL [Quadro FX 1300]", DESKTOP }, + { 0x00ff, "NV18 [GeForce PCX 4300]", DESKTOP }, + { 0x0140, "NV43 [GeForce 6600 GT]", DESKTOP }, + { 0x0141, "NV43 [GeForce 6600]", DESKTOP }, + { 0x0142, "NV43 [GeForce 6600 LE]", DESKTOP }, + { 0x0143, "NV43 [GeForce 6600 VE]", DESKTOP }, + { 0x0144, "NV43 [GeForce Go 6600]", MOBILE }, + { 0x0145, "NV43 [GeForce 6610 XL]", DESKTOP }, + { 0x0146, "NV43 [Geforce Go 6600TE/6200TE]", MOBILE }, + { 0x0147, "NV43 [GeForce 6700 XL]", DESKTOP }, + { 0x0148, "NV43 [GeForce Go 6600]", MOBILE }, + { 0x0149, "NV43 [GeForce Go 6600 GT]", MOBILE }, + { 0x014a, "NV43 [Quadro NVS 440]", DESKTOP }, + { 0x014b, "NV43 [?]", DESKTOP }, + { 0x014c, "NV43 [Quadro FX 540 MXM]", DESKTOP }, + { 0x014d, "NV43GL [Quadro FX 550]", DESKTOP }, + { 0x014e, "NV43GL [Quadro FX 540]", DESKTOP }, + { 0x014f, "NV43 [GeForce 6200]", DESKTOP }, + { 0x0160, "NV44 [GeForce 6500]", DESKTOP }, + { 0x0161, "NV44 [GeForce 6200 TurboCache(TM)]", DESKTOP }, + { 0x0162, "NV44 [GeForce 6200SE TurboCache (TM)]", DESKTOP }, + { 0x0163, "NV44 [GeForce 6200 LE]", DESKTOP }, + { 0x0164, "NV44 [GeForce Go 6200]", MOBILE }, + { 0x0165, "NV44 [Quadro NVS 285]", DESKTOP }, + { 0x0166, "NV43 [GeForce Go 6400]", MOBILE }, + { 0x0167, "NV43 [GeForce Go 6200/6400]", MOBILE }, + { 0x0168, "NV43 [GeForce Go 6200/6400]", MOBILE }, + { 0x0169, "NV44 [GeForce 6250]", DESKTOP }, + { 0x016a, "NV44 [GeForce 7100 GS]", DESKTOP }, + { 0x016b, "NV44GLM [?]", DESKTOP }, + { 0x016c, "NV44GLM [?]", DESKTOP }, + { 0x016d, "NV44GLM [?]", DESKTOP }, + { 0x016e, "NV44GLM [?]", DESKTOP }, + { 0x0210, "NV48 [?]", DESKTOP }, + { 0x0211, "NV48 [GeForce 6800]", DESKTOP }, + { 0x0212, "NV48 [GeForce 6800 LE]", DESKTOP }, + { 0x0215, "NV48 [GeForce 6800 GT]", DESKTOP }, + { 0x0218, "NV48 [GeForce 6800 XT]", DESKTOP }, + { 0x0220, "NV44 [?]", DESKTOP }, + { 0x0221, "NV44A [GeForce 6200]", DESKTOP }, + { 0x0222, "NV44 [GeForce 6200 A-LE]", DESKTOP }, + { 0x0228, "NV44M [?]", MOBILE }, + { 0x0240, "C51PV [GeForce 6150]", NFORCE }, + { 0x0241, "C51 [GeForce 6150 LE]", NFORCE }, + { 0x0242, "C51G [GeForce 6100]", NFORCE }, + { 0x0244, "C51 [Geforce Go 6150]", NFORCE }, + { 0x0245, "C51 [Quadro NVS 210S/GeForce 6150LE]", NFORCE }, + { 0x0247, "C51 [GeForce Go 6100]", NFORCE }, + { 0x02dd, "NV4x [?]", DESKTOP }, + { 0x02de, "NV4x [?]", DESKTOP }, + { 0x0090, "G70 [GeForce 7800 GTX]", DESKTOP }, + { 0x0091, "G70 [GeForce 7800 GTX]", DESKTOP }, + { 0x0092, "G70 [GeForce 7800 GT]", DESKTOP }, + { 0x0093, "G70 [GeForce 7800 GS]", DESKTOP }, + { 0x0094, "G70 [?]", DESKTOP }, + { 0x0098, "G70 [GeForce Go 7800]", DESKTOP }, + { 0x0099, "G70 [GeForce Go 7800 GTX]", MOBILE }, + { 0x009c, "G70 [?]", DESKTOP }, + { 0x009d, "G70GL [Quadro FX 4500]", DESKTOP }, + { 0x009e, "G70GL [?]", DESKTOP }, + { 0x0290, "G71 [GeForce 7900 GTX]", DESKTOP }, + { 0x0291, "G71 [GeForce 7900 GT/GTO]", DESKTOP }, + { 0x0292, "G71 [GeForce 7900 GS]", DESKTOP }, + { 0x0293, "G71 [GeForce 7900 GX2]", DESKTOP }, + { 0x0294, "G71 [GeForce 7950 GX2]", DESKTOP }, + { 0x0295, "G71 [GeForce 7950 GT]", DESKTOP }, + { 0x0297, "G71 [GeForce Go 7950 GTX]", MOBILE }, + { 0x0298, "G71 [GeForce Go 7900 GS]", MOBILE }, + { 0x0299, "G71 [GeForce Go 7900 GTX]", MOBILE }, + { 0x029a, "G71 [Quadro FX 2500M]", MOBILE }, + { 0x029b, "G71 [Quadro FX 1500M]", MOBILE }, + { 0x029c, "G71 [Quadro FX 5500]", DESKTOP }, + { 0x029d, "G71GL [Quadro FX 3500]", DESKTOP }, + { 0x029e, "G71 [Quadro FX 1500]", DESKTOP }, + { 0x029f, "G70 [Quadro FX 4500 X2]", DESKTOP }, + { 0x0390, "G73 [GeForce 7650 GS]", DESKTOP }, + { 0x0391, "G73 [GeForce 7600 GT]", DESKTOP }, + { 0x0392, "G73 [GeForce 7600 GS]", DESKTOP }, + { 0x0393, "G73 [GeForce 7300 GT]", DESKTOP }, + { 0x0394, "G73 [GeForce 7600 LE]", DESKTOP }, + { 0x0395, "G73 [GeForce 7300 GT]", DESKTOP }, + { 0x0397, "G73 [GeForce Go 7700]", MOBILE }, + { 0x0398, "G73 [GeForce Go 7600]", MOBILE }, + { 0x0399, "G73 [GeForce Go 7600 GT]", MOBILE }, + { 0x039a, "G73M [Quadro NVS 300M]", MOBILE }, + { 0x039b, "G73 [GeForce Go 7900 SE]", MOBILE }, + { 0x039c, "G73 [Quadro FX 550M]", MOBILE }, + { 0x039e, "G73GL [Quadro FX 560]", DESKTOP }, + { 0x02e0, "G73 [GeForce 7600 GT]", DESKTOP }, + { 0x02e1, "G73 [GeForce 7600 GS]", DESKTOP }, + { 0x02e2, "G73 [GeForce 7300 GT]", DESKTOP }, + { 0x02e4, "G71 [GeForce 7950 GT]", DESKTOP }, + { 0x01d1, "G72 [GeForce 7300 LE]", DESKTOP }, + { 0x01d3, "G72 [GeForce 7300 SE/7200 GS]", DESKTOP }, + { 0x01d7, "G72M [Quadro NVS 110M/GeForce Go 7300]", MOBILE }, + { 0x01d8, "G72M [GeForce Go 7400]", MOBILE }, + { 0x01d9, "G72M [GeForce Go 7450]", MOBILE }, + { 0x01da, "G72M [Quadro NVS 110M]", MOBILE }, + { 0x01db, "G72M [Quadro NVS 120M]", MOBILE }, + { 0x01dc, "G72GL [Quadro FX 350M]", MOBILE }, + { 0x01dd, "G72 [GeForce 7500 LE]", MOBILE }, + { 0x01de, "G72GL [Quadro FX 350]", DESKTOP }, + { 0x01df, "G71 [GeForce 7300 GS]", DESKTOP }, + { 0x0190, "G80 [GeForce 8800]", DESKTOP }, + { 0x0191, "G80 [GeForce 8800 GTX]", DESKTOP }, + { 0x0192, "G80 [GeForce 8800]", DESKTOP }, + { 0x0193, "G80 [GeForce 8800 GTS]", DESKTOP }, + { 0x0194, "G80 [GeForce 8800 Ultra]", DESKTOP }, + { 0x0197, "G80 [Tesla C870]", DESKTOP }, + { 0x019a, "G80 [G80-875]", DESKTOP }, + { 0x019d, "G80 [Quadro FX 5600]", DESKTOP }, + { 0x019e, "G80 [Quadro FX 4600]", DESKTOP }, + { 0x0400, "G84 [GeForce 8600 GTS]", DESKTOP }, + { 0x0401, "G84 [GeForce 8600GT]", DESKTOP }, + { 0x0402, "G84 [GeForce 8600 GT]", DESKTOP }, + { 0x0403, "G84 [GeForce 8600 GS]", DESKTOP }, + { 0x0404, "G84 [GeForce 8400 GS]", DESKTOP }, + { 0x0405, "G84 [GeForce 9500M GS]", MOBILE }, + { 0x0406, "G84 [GeForce 8300 GS]", MOBILE }, + { 0x0407, "G84 [GeForce 8600M GT]", MOBILE }, + { 0x0408, "G84 [GeForce 9650M GS]", MOBILE }, + { 0x0409, "G84 [GeForce 8700M GT]", MOBILE }, + { 0x040a, "G84 [Quadro FX 370]", MOBILE }, + { 0x040b, "G84M [Quadro NVS 320M]", MOBILE }, + { 0x040c, "G84M [Quadro FX 570M]", MOBILE }, + { 0x040d, "G84 [Quadro FX 1600M]", MOBILE }, + { 0x040e, "G84 [Quadro FX 570]", DESKTOP }, + { 0x040f, "G84 [Quadro FX 1700]", DESKTOP }, + { 0x0420, "G86 [GeForce 8400 SE]", DESKTOP }, + { 0x0421, "G86 [GeForce 8500 GT]", DESKTOP }, + { 0x0422, "G86 [GeForce 8400 GS]", DESKTOP }, + { 0x0423, "G86 [GeForce 8300 GS]", DESKTOP }, + { 0x0424, "G86 [GeForce 8400 GS]", DESKTOP }, + { 0x0425, "G86 [GeForce 8600M GS]", MOBILE }, + { 0x0426, "G86 [GeForce 8400M GT]", MOBILE }, + { 0x0427, "G86 [GeForce 8400M GS]", MOBILE }, + { 0x0428, "G86 [GeForce 8400M G]", MOBILE }, + { 0x0429, "G84M [Quadro NVS 140M]", MOBILE }, + { 0x042a, "G86M [Quadro NVS 130M]", MOBILE }, + { 0x042b, "G86M [Quadro NVS 135M]", MOBILE }, + { 0x042d, "G86M [Quadro FX 360M]", MOBILE }, + { 0x042e, "G86 [GeForce 9300M G]", MOBILE }, + { 0x042f, "G86 [Quadro NVS 290]", DESKTOP }, + { 0x03d0, "C61 [GeForce 6150SE nForce 430]", NFORCE}, + { 0x03d1, "C61 [GeForce 6100 nForce 405]", NFORCE}, + { 0x03d2, "C61 [GeForce 6100 nForce 400]", NFORCE}, + { 0x03d5, "C61 [GeForce 6100 nForce 420]", NFORCE}, + { 0x053a, "C68 [GeForce 7050 PV / nForce 630a]", NFORCE}, + { 0x053b, "C68 [GeForce 7050 PV / nForce 630a]", NFORCE}, + { 0x053e, "C68 [GeForce 7025 / nForce 630a]", NFORCE}, + { 0x05e0, "GT200b [GeForce GTX 295]", DESKTOP }, + { 0x05e1, "GT200 [GeForce GTX 280]", DESKTOP }, + { 0x05e2, "GT200 [GeForce GTX 260]", DESKTOP }, + { 0x05e7, "GT200 [Tesla C1060]", DESKTOP }, + { 0x05ed, "GT200GL [Quadro Plex 2200 D2]", DESKTOP }, + { 0x05f8, "GT200GL [Quadro Plex 2200 S4]", DESKTOP }, + { 0x05f9, "GT200GL [Quadro CX]", DESKTOP }, + { 0x05fd, "GT200GL [Quadro FX 5800]", DESKTOP }, + { 0x05fe, "GT200GL [Quadro FX 4800]", DESKTOP }, + { 0x0600, "G92 [GeForce 8800 GTS 512]", DESKTOP }, + { 0x0602, "G92 [GeForce 8800 GT]", DESKTOP }, + { 0x0604, "G92 [GeForce 9800 GX2]", DESKTOP }, + { 0x0606, "G92 [GeForce 8800 GS]", DESKTOP }, + { 0x060d, "G92 [GeForce 8800 GS]", DESKTOP }, + { 0x0609, "G92 [GeForce 8800M GTS]", MOBILE }, + { 0x060c, "G92 [GeForce 8800M GTX]", MOBILE }, + { 0x0610, "G92 [GeForce 9600 GSO]", DESKTOP }, + { 0x0611, "G92 [GeForce 8800 GT]", DESKTOP }, + { 0x0612, "G92 [GeForce 9800 GTX]", DESKTOP }, + { 0x0614, "G92 [GeForce 9800 GT]", DESKTOP }, + { 0x061a, "G92 [Quadro FX 3700]", DESKTOP }, + { 0x061c, "G92M [Quadro FX 3600M]", MOBILE }, + { 0x0622, "G94 [GeForce 9600 GT]", DESKTOP }, + { 0x0623, "G94 [GeForce 9600 GS]", DESKTOP }, + { 0x0640, "G96 [GeForce 9500 GT]", DESKTOP }, + { 0x0643, "G96 [GeForce 9500 GT]", DESKTOP }, + { 0x0647, "G96 [GeForce 9600M GT]", MOBILE }, + { 0x0648, "G96 [GeForce 9600M GS]", MOBILE }, + { 0x0649, "G96 [GeForce 9600M GT]", MOBILE }, + { 0x064b, "G96 [GeForce 9500M G]", MOBILE }, + { 0x06e0, "G98 [GeForce 9300 GE]", DESKTOP }, + { 0x06e1, "G98 [GeForce 9300 GS]", DESKTOP }, + { 0x06e2, "G98 [GeForce 8400]", DESKTOP }, + { 0x06e3, "G98 [GeForce 8300 GS]", DESKTOP }, + { 0x06e4, "G98 [GeForce 8400 GS]", DESKTOP }, + { 0x06e5, "G98 [GeForce 9300M GS]", MOBILE }, + { 0x06e6, "G98 [GeForce G100]", DESKTOP }, + { 0x06e7, "G98 [GeForce 9300 SE]", DESKTOP }, + { 0x06e8, "G98 [GeForce 9200M GS]", MOBILE }, + { 0x06e9, "G98 [GeForce 9300M GS]", MOBILE }, + { 0x06ea, "G86M [Quadro NVS 150M]", MOBILE }, + { 0x06eb, "G98M [Quadro NVS 160M]", MOBILE }, + { 0x06ec, "G98M [GeForce G 105M]", MOBILE }, + { 0x06ed, "G98 [?]", DESKTOP }, + { 0x06ee, "G98 [?]", DESKTOP }, + { 0x06ef, "G98M [GeForce G 103M]", DESKTOP }, + { 0x06f0, "G98 [?]", DESKTOP }, + { 0x06f1, "G98 [GeForce G105M]", DESKTOP }, + { 0x06f2, "G98 [?]", DESKTOP }, + { 0x06f3, "G98 [?]", DESKTOP }, + { 0x06f4, "G98 [?]", DESKTOP }, + { 0x06f5, "G98 [?]", DESKTOP }, + { 0x06f6, "G98 [?]", DESKTOP }, + { 0x06f7, "G98 [?]", DESKTOP }, + { 0x06f8, "G98 [Quadro NVS 420]", DESKTOP }, + { 0x06f9, "G98 [Quadro FX 370 LP]", DESKTOP }, + { 0x06fa, "G98 [Quadro NVS 450]", DESKTOP }, + { 0x06fb, "G98 [Quadro FX 370M]", MOBILE }, + { 0x06fc, "G98 [?]", DESKTOP }, + { 0x06fd, "G98 [Quadro NVS 295]", DESKTOP }, + { 0x06fe, "G98 [?]", DESKTOP }, + { 0x06ff, "G98 [HICx16 + Graphics]", DESKTOP }, + { 0x0860, "C79 [GeForce 9300]", DESKTOP }, + { 0x0861, "C79 [GeForce 9400]", DESKTOP }, + { 0x0863, "C79 [GeForce 9400M]", MOBILE }, + { 0x0864, "C79 [GeForce 9300]", DESKTOP }, + { 0x0865, "C79 [GeForce 9300]", DESKTOP }, + + + /* New product-ids */ + { 0x0095, "G70 [GeForce 7800 SLI]", DESKTOP }, + { 0x0184, "NV18 [GeForce4 MX]", MOBILE }, + { 0x0189, "NV18 [GeForce4 MX with AGP8X (Mac)]", MOBILE }, + { 0x01d0, "G72 [GeForce 7350 LE]", DESKTOP }, + { 0x01d2, "G72 [GeForce 7550 LE]", DESKTOP }, + { 0x01d6, "G72M [GeForce Go 7200]", MOBILE }, + { 0x0243, "C51 PCI Express Bridge [?]", DESKTOP }, + { 0x0246, "C51 PCI Express Bridge [?]", DESKTOP }, + { 0x0248, "C51 PCI Express Bridge [?]", DESKTOP }, + { 0x0249, "C51 PCI Express Bridge [?]", DESKTOP }, + { 0x024a, "C51 PCI Express Bridge [?]", DESKTOP }, + { 0x024b, "C51 PCI Express Bridge [?]", DESKTOP }, + { 0x024c, "C51 PCI Express Bridge [?]", DESKTOP }, + { 0x024d, "C51 PCI Express Bridge [?]", DESKTOP }, + { 0x024e, "C51 PCI Express Bridge [?]", DESKTOP }, + { 0x024f, "C51 PCI Express Bridge [?]", DESKTOP }, + { 0x0252, "NV25 [GeForce4 Ti]", DESKTOP }, + { 0x02e3, "G71 [GeForce 7900 GS]", DESKTOP }, + { 0x0313, "NV31 [?]", DESKTOP }, + { 0x0320, "NV34 [GeForce FX 5200]", DESKTOP }, + { 0x0327, "NV34 [GeForce FX 5100]", DESKTOP }, + { 0x038b, "G73 [GeForce 7650 GS]", DESKTOP }, + { 0x03d6, "C61 [GeForce 7025 / nForce 630a]", DESKTOP }, + { 0x0410, "G92 [GeForce GT 330]", DESKTOP }, + { 0x042c, "G86 [GeForce 9400 GT]", DESKTOP }, + { 0x0531, "C67 [GeForce 7150M / nForce 630M]", MOBILE }, + { 0x0533, "C67 [GeForce 7000M / nForce 610M]", MOBILE }, + { 0x05e3, "GT200b [GeForce GTX 285]", DESKTOP }, + { 0x05e6, "GT200b [GeForce GTX 275]", DESKTOP }, + { 0x05ea, "GT200 [GeForce GTX 260]", DESKTOP }, + { 0x05eb, "GT200 [GeForce GTX 295]", DESKTOP }, + { 0x05ff, "GT200GL [NVIDIA Quadro FX 3800]", DESKTOP }, + //Slice - replace G92 -> G84 for 0x60x and 0x61x + { 0x0601, "G84 [GeForce 9800 GT]", DESKTOP }, + { 0x0603, "G84 [GeForce GT 230]", DESKTOP }, + { 0x0605, "G84 [GeForce 9800 GT]", DESKTOP }, + { 0x0607, "G84 [GeForce GTS 240]", DESKTOP }, + { 0x0608, "G84M [GeForce 9800M GTX]", MOBILE }, + { 0x060a, "GT200 [GeForce GTX 280M]", MOBILE }, + { 0x060b, "G84 [GeForce 9800M GT]", MOBILE }, + { 0x060e, "G84 [GeForce 9850 E]", DESKTOP }, + { 0x060f, "G84M [GeForce GTX 285M]", MOBILE }, + { 0x0613, "G84 [GeForce 9800 GTX+]", DESKTOP }, + { 0x0615, "G84 [GeForce GTS 250]", DESKTOP }, + { 0x0617, "G84M [GeForce 9800M GTX]", MOBILE }, + { 0x0618, "G84M [GeForce GTX 260M]", MOBILE }, + { 0x0619, "G92GL [Quadro FX 4700 X2]", DESKTOP }, + { 0x061b, "G92GL [Quadro VX 200]", DESKTOP }, + { 0x061d, "G92 [Quadro FX 2800M]", MOBILE }, + { 0x061e, "G92 [Quadro FX 3700M]", MOBILE }, + { 0x061f, "G92 [Quadro FX 3800M]", MOBILE }, + { 0x0621, "G94 [GeForce GT 230]", DESKTOP }, + { 0x0625, "G94 [GeForce 9600 GSO 512]", DESKTOP }, + { 0x0626, "G94 [GeForce GT 130]", DESKTOP }, + { 0x0627, "G94 [GeForce GT 140]", DESKTOP }, + { 0x0628, "G94 [GeForce 9800M GTS]", MOBILE }, + { 0x062a, "G94 [GeForce 9700M GTS]", MOBILE }, + { 0x062b, "G94 [GeForce 9800M GS]", MOBILE }, + { 0x062c, "G94 [GeForce 9800M GTS]", MOBILE }, + { 0x062d, "G94 [GeForce 9600 GT]", DESKTOP }, + { 0x062e, "G94 [GeForce 9600 GT]", DESKTOP }, + { 0x062f, "G94 [GeForce 9800 S]", DESKTOP }, + { 0x0630, "G94 [GeForce 9700 S]", DESKTOP }, + { 0x0631, "G94M [GeForce GTS 160M]", MOBILE }, + { 0x0632, "G94M [GeForce GTS 150M]", MOBILE }, + { 0x0633, "G94 [GeForce GT 220]", DESKTOP }, + { 0x0635, "G94 [GeForce 9600 GSO]", DESKTOP }, + { 0x0637, "G94 [GeForce 9600 GT]", DESKTOP }, + { 0x0638, "G94 [Quadro FX 1800]", DESKTOP }, + { 0x063a, "G94M [Quadro FX 2700M]", MOBILE }, + { 0x0641, "G96 [GeForce 9400 GT]", DESKTOP }, + { 0x0642, "G96 [GeForce 8400 GS]", DESKTOP }, + { 0x0644, "G96 [GeForce 9500 GS]", DESKTOP }, + { 0x0645, "G96 [GeForce 9500 GS]", DESKTOP }, + { 0x0646, "G96 [GeForce GT 120]", DESKTOP }, + { 0x064a, "G96 [GeForce 9700M GT]", MOBILE }, + { 0x064c, "G96 [GeForce 9650M GT]", MOBILE }, + { 0x064f, "G96 [GeForce 9600 S]", DESKTOP }, + { 0x0650, "G96 [?]", DESKTOP }, + { 0x0651, "G96 [GeForce G 110M]", MOBILE }, + { 0x0652, "G96 [GeForce GT 130M]", MOBILE }, + { 0x0653, "G96M [GeForce GT 120M]", MOBILE }, + { 0x0654, "G96 [GeForce GT 220M]", MOBILE }, + { 0x0655, "G96 [GeForce 9500 GS]", DESKTOP }, + { 0x0656, "G96 [GeForce 9650 S]", DESKTOP }, + { 0x0658, "G96 [Quadro FX 380]", DESKTOP }, + { 0x0659, "G96 [Quadro FX 580]", DESKTOP }, + { 0x065a, "G96 [Quadro FX 1700M]", MOBILE }, + { 0x065b, "G96 [GeForce 9400 GT]", DESKTOP }, + { 0x065c, "G96M [Quadro FX 770M]", MOBILE }, + { 0x065f, "G96 [GeForce GT 210]", DESKTOP }, + { 0x06a0, "GT214 [?]", DESKTOP }, + { 0x06b0, "GT214 [?]", DESKTOP }, + { 0x07e0, "C73 [GeForce 7150 / nForce 630i]", DESKTOP }, + { 0x07e1, "C73 [GeForce 7100 / nForce 630i]", DESKTOP }, + { 0x07e2, "C73 [GeForce 7050 / nForce 630i]", DESKTOP }, + { 0x07e3, "C73 [GeForce 7050 / nForce 610i]", DESKTOP }, + { 0x07e5, "C73 [GeForce 7100 / nForce 620i]", DESKTOP }, + { 0x0844, "C77 [GeForce 9100M G]", MOBILE }, + { 0x0845, "C77 [GeForce 8200M G]", MOBILE }, + { 0x0846, "C77 [GeForce 9200]", DESKTOP }, + { 0x0847, "C78 [GeForce 9100]", DESKTOP }, + { 0x0848, "C77 [GeForce 8300]", DESKTOP }, + { 0x0849, "C77 [GeForce 8200]", DESKTOP }, + { 0x084a, "C77 [nForce 730a]", DESKTOP }, + { 0x084b, "C77 [GeForce 8200]", DESKTOP }, + { 0x084c, "C77 [nForce 780a SLI]", DESKTOP }, + { 0x084d, "C77 [nForce 750a SLI]", DESKTOP }, + { 0x084f, "C77 [GeForce 8100 / nForce 720a]", DESKTOP }, + { 0x0862, "C79 [GeForce 9400M G]", MOBILE }, + { 0x0866, "C79 [GeForce 9400M G]", MOBILE }, + { 0x0867, "C79 [GeForce 9400]", DESKTOP }, + { 0x0868, "C79 [nForce 760i SLI]", DESKTOP }, + { 0x086a, "C79 [GeForce 9400]", DESKTOP }, + { 0x086c, "C79 [GeForce 9300 / nForce 730i]", DESKTOP }, + { 0x086d, "C79 [GeForce 9200]", DESKTOP }, + { 0x086e, "C79 [GeForce 9100M G]", MOBILE }, + { 0x086f, "C79 [GeForce 9200M G]", MOBILE }, + { 0x0870, "C79 [GeForce 9400M]", MOBILE }, + { 0x0871, "C79 [GeForce 9200]", DESKTOP }, + { 0x0872, "C79 [GeForce G102M]", MOBILE }, + { 0x0873, "C79 [GeForce G102M]", MOBILE }, + { 0x0874, "C79 [ION 9300M]", DESKTOP }, + { 0x0876, "C79 [GeForce 9400M]", MOBILE }, + { 0x087a, "C79 [GeForce 9400]", DESKTOP }, + { 0x087d, "C79 [ION 9400M]", DESKTOP }, + { 0x087e, "C79 [?]", DESKTOP }, + { 0x087f, "C79 [?]", DESKTOP }, + { 0x0a20, "GT216 [GeForce GT 220]", DESKTOP }, + { 0x0a23, "GT218 [GeForce 210]", DESKTOP }, + { 0x0a28, "GT216 [GeForce GT 230M]", MOBILE }, + { 0x0a29, "GT216 [GeForce GT 330M]", MOBILE }, + { 0x0a2a, "GT216 [GeForce GT 230M]", MOBILE }, + { 0x0a2b, "GT216 [GeForce GT 330M]", MOBILE }, + { 0x0a2c, "GT216 [NVS 5100M]", MOBILE }, + { 0x0a2d, "GT216 [GeForce GT 320M]", MOBILE }, + { 0x0a34, "GT216 [GeForce GT 240M]", MOBILE }, + { 0x0a35, "GT216 [GeForce GT 325M]", MOBILE }, + { 0x0a3c, "GT216 [Quadro FX 880M]", MOBILE }, + { 0x0a60, "GT218 [GeForce G210]", DESKTOP }, + { 0x0a62, "GT218 [GeForce 205]", DESKTOP }, + { 0x0a63, "GT218 [GeForce 310]", DESKTOP }, + { 0x0a64, "GT218 [?]", DESKTOP }, + { 0x0a65, "GT218 [GeForce 210]", DESKTOP }, + { 0x0a66, "GT218 [GeForce 310]", DESKTOP }, + { 0x0a68, "G98M [GeForce G105M]", MOBILE }, + { 0x0a69, "G98M [GeForce G105M]", MOBILE }, + { 0x0a6a, "GT218 [NVS 2100M]", MOBILE }, + { 0x0a6c, "GT218 [NVS 3100M]", MOBILE }, + { 0x0a6e, "GT218 [GeForce 305M]", MOBILE }, + { 0x0a6f, "GT218 [?]", DESKTOP }, + { 0x0a70, "GT218 [GeForce 310M]", MOBILE }, + { 0x0a71, "GT218 [GeForce 305M]", MOBILE }, + { 0x0a72, "GT218 [GeForce 310M]", MOBILE }, + { 0x0a73, "GT218 [GeForce 305M]", MOBILE }, + { 0x0a74, "GT218 [GeForce G210M]", MOBILE }, + { 0x0a75, "GT218 [GeForce 310M]", MOBILE }, + { 0x0a78, "GT218GL [Quadro FX 380 LP]", DESKTOP }, + { 0x0a7c, "GT218 [Quadro FX 380M]", MOBILE }, + { 0x0ca0, "GT215 [GeForce GT 330]", DESKTOP }, + { 0x0ca2, "GT215 [GeForce GT 320]", DESKTOP }, + { 0x0ca3, "GT215 [GeForce GT 240]", DESKTOP }, + { 0x0ca4, "GT215 [GeForce GT 340]", DESKTOP }, + { 0x0ca5, "GT215 [?]", DESKTOP }, + { 0x0ca7, "GT215 [GeForce GT 330]", DESKTOP }, + { 0x0ca8, "GT215 [GeForce GTS 260M]", MOBILE }, + { 0x0ca9, "GT215 [GeForce GTS 250M]", MOBILE }, + { 0x0cad, "GT215 [?]", DESKTOP }, + { 0x0caf, "GT215 [GeForce GT 335M]", MOBILE }, + { 0x0cb0, "GT215 [GeForce GTS 350M]", MOBILE }, + { 0x0cb1, "GT215 [GeForce GTS 360M]", MOBILE }, + { 0x0cbc, "GT215 [Quadro FX 1800M]", MOBILE }, + + /*************** GF1xx *************/ + // 06C0 - 06DF + { 0x06C0, "GF100 [GeForce GTX 480]", DESKTOP }, + { 0x06C3, "GF100 [GeForce GTX D12U]", DESKTOP }, + { 0x06C4, "GF100 [GeForce GTX 465]", DESKTOP }, + { 0x06CA, "GF100 [GeForce GTX 480M]", DESKTOP }, + { 0x06CD, "GF100 [GeForce GTX 470]", DESKTOP }, + { 0x06D1, "GF100 [Tesla C2050]", DESKTOP }, + { 0x06D1, "GF100 [Tesla C2070]", DESKTOP }, + { 0x06D2, "GF100 [Tesla M2070]", DESKTOP }, + { 0x06D8, "GF100 [Quadro 6000]", DESKTOP }, + { 0x06D9, "GF100 [Quadro 5000]", DESKTOP }, + { 0x06DA, "GF100 [Quadro 5000M]", MOBILE }, + { 0x06DC, "GF100 [Quadro 6000]", DESKTOP }, + { 0x06DD, "GF100 [Quadro 4000]", DESKTOP }, + { 0x06DE, "GF100 [Tesla M2050]", DESKTOP }, + { 0x06DE, "GF100 [Tesla M2070]", DESKTOP }, + { 0x06DF, "GF100 [Tesla M2070-Q]", DESKTOP }, + + // 0DC0 - 0DFF + { 0x0DC0, "GF100 [GeForce GT 440]", DESKTOP }, + { 0x0DC1, "GF100 [D12-P1-35]", DESKTOP }, + { 0x0DC2, "GF100 [D12-P1-35]", DESKTOP }, + { 0x0DC4, "GF100 [GeForce GTS 450]", DESKTOP }, + { 0x0DC5, "GF100 [GeForce GTS 450]", DESKTOP }, + { 0x0DC6, "GF100 [GeForce GTS 450]", DESKTOP }, + { 0x0DCA, "GF100 [GF10x]", DESKTOP }, + { 0x0DCD, "GF100 [GeForce GT 555M]", MOBILE }, + { 0x0DCE, "GF100 [GeForce GT 555M]", MOBILE }, + { 0x0DD1, "GF100 [GeForce GTX 460M]", MOBILE }, + { 0x0DD2, "GF100 [GeForce GT 445M]", MOBILE }, + { 0x0DD3, "GF100 [GeForce GT 435M]", MOBILE }, + { 0x0DD6, "GF100 [GeForce GT 550M]", MOBILE }, + { 0x0DD8, "GF100 [Quadro 2000]", DESKTOP }, + { 0x0DDA, "GF100 [Quadro 2000M]", MOBILE }, + { 0x0DDE, "GF100 [GF106-ES]", DESKTOP }, + { 0x0DDF, "GF100 [GF106-INT]", DESKTOP }, + { 0x0DE0, "GF100 [GeForce GT 440]", DESKTOP }, + { 0x0DE1, "GF100 [GeForce GT 430]", DESKTOP }, + { 0x0DE2, "GF100 [GeForce GT 420]", DESKTOP }, + { 0x0DE5, "GF100 [GeForce GT 530]", DESKTOP }, + { 0x0DEB, "GF100 [GeForce GT 555M]", MOBILE }, + { 0x0DEC, "GF100 [GeForce GT 525M]", MOBILE }, + { 0x0DED, "GF100 [GeForce GT 520M]", MOBILE }, + { 0x0DEE, "GF100 [GeForce GT 415M]", MOBILE }, + { 0x0DF0, "GF100 [GeForce GT 425M]", MOBILE }, + { 0x0DF1, "GF100 [GeForce GT 420M]", MOBILE }, + { 0x0DF2, "GF100 [GeForce GT 435M]", MOBILE }, + { 0x0DF3, "GF100 [GeForce GT 420M]", MOBILE }, + { 0x0DF4, "GF100 [GeForce GT 540M]", MOBILE }, + { 0x0DF5, "GF100 [GeForce GT 525M]", MOBILE }, + { 0x0DF6, "GF100 [GeForce GT 550M]", MOBILE }, + { 0x0DF7, "GF100 [GeForce GT 520M]", MOBILE }, + { 0x0DF8, "GF100 [Quadro 600]", DESKTOP }, + { 0x0DFA, "GF100 [Quadro 1000M]", MOBILE }, + { 0x0DFE, "GF100 [GF108 ES]", DESKTOP }, + { 0x0DFF, "GF100 [GF108 INT]", DESKTOP }, + + // 0E20 - 0E3F + { 0x0E21, "GF100 [D12U-25]", DESKTOP }, + { 0x0E22, "GF100 [GeForce GTX 460]", DESKTOP }, + { 0x0E23, "GF100 [GeForce GTX 460 SE]", DESKTOP }, + { 0x0E24, "GF100 [GeForce GTX 460]", DESKTOP }, + { 0x0E25, "GF100 [D12U-50]", DESKTOP }, + { 0x0E30, "GF100 [GeForce GTX 470M]", MOBILE }, + { 0x0E31, "GF100 [GeForce GTX 485M]", MOBILE }, + { 0x0E38, "GF100 [GF104GL]", DESKTOP }, + { 0x0E3A, "GF100 [Quadro 3000M]", MOBILE }, + { 0x0E3B, "GF100 [Quadro 4000M]", MOBILE }, + { 0x0E3E, "GF100 [GF104-ES]", DESKTOP }, + { 0x0E3F, "GF100 [GF104-INT]", DESKTOP }, + + // 0EE0 - 0EFF: none yet + // 0F00 - 0F3F: none yet + { 0x0F00, "GF100 [GeForce GT630]", DESKTOP }, + + // 1040 - 107F + { 0x1040, "GF100 [GeForce GT 520]", DESKTOP }, + { 0x104A, "GF100 [GeForce GT 610]", DESKTOP }, + { 0x1050, "GF100 [GeForce GT 520M]", MOBILE }, + { 0x1051, "GF100 [GeForce GT 520MX]", MOBILE }, + { 0x1054, "GF100 [GeForce GT 410M]", MOBILE }, + { 0x1055, "GF100 [GeForce GT 410M]", MOBILE }, + { 0x1056, "GF100 [NVS 4200M]", MOBILE }, + { 0x1057, "GF100 [NVS 4200M]", MOBILE }, + { 0x107F, "GF100 [NVIDIA GF119-ES]", DESKTOP }, + + // 1080 - 109F + { 0x1080, "GF100 [GeForce GTX 580]", DESKTOP }, + { 0x1081, "GF100 [GeForce GTX 570]", DESKTOP }, + { 0x1082, "GF100 [GeForce GTX 560 Ti]", DESKTOP }, + { 0x1083, "GF100 [GeForce GTX 590]", DESKTOP }, + { 0x1086, "GF100 [GeForce GTX 570]", DESKTOP }, + { 0x1088, "GF100 [GeForce GTX 590]", DESKTOP }, + { 0x1098, "GF100 [D13U]", DESKTOP }, + { 0x109A, "GF100 [Quadro 5010M]", MOBILE }, + + // 1200 - 127F + { 0x1200, "GF100 [GeForce GTX 560 Ti]", DESKTOP }, + { 0x1201, "GF100 [GeForce GTX 560]", DESKTOP }, + { 0x1244, "GF100 [GeForce GTX 550 Ti]", DESKTOP }, + { 0x1245, "GF100 [GeForce GTS 450]", DESKTOP }, + { 0x1251, "GF100 [N12E-GS-A1]", DESKTOP }, + + + { 0, NULL, UNKNOWN } +}; + +const char *get_card_name(int device_id, gpu_type *gpu) +{ + struct pci_ids *nv_ids = (struct pci_ids*)ids; + + while(nv_ids->id != 0) + { + if(nv_ids->id == device_id) + { + *gpu = nv_ids->gpu; + return nv_ids->name; + } + + nv_ids++; + } + + /* if !found */ + *gpu = UNKNOWN; + return "Unknown Nvidia card"; +} + +/* Internal gpu architecture function which sets + / a device to a specific architecture. This architecture + / doesn't have to be the real architecture. It is mainly + / used to choose codepaths inside nvclock. + */ +int get_gpu_arch(int device_id) +{ + int arch = UNKNOWN; + + switch(device_id & 0xfff0) + { + case 0x20: + arch = NV5; + break; + case 0x100: + case 0x110: + case 0x150: + case 0x1a0: + arch = NV10; + break; + case 0x170: + case 0x180: + case 0x1f0: + arch = NV17; + break; + case 0x200: + arch = NV20; + break; + case 0x250: + case 0x280: + case 0x320: /* We don't treat the FX5200/FX5500 as FX cards */ + arch = NV25; + break; + case 0x300: + arch = NV30; + break; + case 0x330: + arch = NV35; /* Similar to NV30 but fanspeed stuff works differently */ + break; + /* Give a seperate arch to FX5600/FX5700 cards as they need different code than other FX cards */ + case 0x310: + case 0x340: + arch = NV31; + break; + case 0x40: + case 0x120: + case 0x130: + case 0x210: + case 0x230: + arch = NV40; + break; + case 0xc0: + arch = NV41; + break; + case 0x140: + arch = NV43; /* Similar to NV40 but with different fanspeed code */ + break; + case 0x160: + case 0x220: + arch = NV44; + break; + case 0x1d0: + arch = NV46; + break; + case 0x90: + arch = NV47; + break; + case 0x290: + arch = NV49; /* 7900 */ + break; + case 0x390: + arch = NV4B; /* 7600 */ + break; + case 0x190: + // case 0x606: + arch = NV50; /* 8800 'NV50 / G80' */ + break; + // case 0xa30: /* GT240 */ + case 0x400: /* 8600 'G84' */ + arch = G84; + break; + case 0x420: /* 8500 'G86' */ + arch = G86; + break; + case 0x5e0: /* GT2x0 */ + case 0x5f0: /* GT2x0 */ + case 0xa60: /* GT2x0 */ + case 0xa20: + case 0xa30: /* GT240 */ + case 0xa70: + case 0xca0: + case 0xcb0: + arch = GT200; + break; + case 0x6e0: /* G98 */ + case 0x6f0: /* G98 */ + case 0x860: /* C79 */ + case 0x870: /* C79 */ + arch = G86; + break; + case 0x600: /* G92 */ + case 0x610: /* G92 */ + if (device_id == 0x606) { + arch = NV50; + } else { + arch = G84; + } + break; + case 0x620: /* 9600GT 'G94' */ + arch = G94; + break; + case 0x640: /* 9500GT */ + arch = G96; + break; + case 0x240: + case 0x3d0: /* not sure if this is a C51 too */ + case 0x530: /* not sure if the 70xx is C51 too */ + arch = C51; + break; + case 0x06C0 ... 0x06DF: + case 0x0DC0 ... 0x0DFF: + case 0x0E20 ... 0x0E3F: + case 0x0EE0 ... 0x0EFF: + case 0x0F00 ... 0x0F3F: + case 0x1040 ... 0x107F: + case 0x1080 ... 0x109F: + case 0x1200 ... 0x127F: + arch = GF100; + break; + case 0x2e0: + case 0xf0: + /* The code above doesn't work for pci-express cards as multiple architectures share one id-range */ + switch(device_id) + { + case 0xf0: /* 6800 */ + case 0xf9: /* 6800Ultra */ + arch = NV40; + break; + case 0xf6: /* 6800GS/XT */ + arch = NV41; + break; + case 0xf1: /* 6600/6600GT */ + case 0xf2: /* 6600GT */ + case 0xf3: /* 6200 */ + case 0xf4: /* 6600LE */ + arch = NV43; + break; + case 0xf5: /* 7800GS */ + arch = NV47; + break; + case 0xfa: /* PCX5700 */ + arch = NV31; + break; + case 0xf8: /* QuadroFX 3400 */ + case 0xfb: /* PCX5900 */ + arch = NV35; + break; + case 0xfc: /* PCX5300 */ + case 0xfd: /* Quadro NVS280/FX330, FX5200 based? */ + case 0xff: /* PCX4300 */ + arch = NV25; + break; + case 0xfe: /* Quadro 1300, has the same id as a FX3000 */ + arch = NV35; + break; + case 0x2e0: /* Geforce 7600GT AGP (at least Leadtek uses this id) */ + case 0x2e1: /* Geforce 7600GS AGP (at least BFG uses this id) */ + case 0x2e2: /* Geforce 7300GT AGP (at least a Galaxy 7300GT uses this id) */ + arch = NV4B; + break; + case 0x2e4: /* Geforce 7950 GT AGP */ + arch = NV49; + break; + } + break; + default: + printf("Unknown GPU %s\n", nv_card->card_name); + arch = UNKNOWN; + } + return arch; +} + +/* Receive the real gpu architecture */ +static short get_gpu_architecture() +{ + return (nv_read_pmc(NV_PMC_BOOT_0) >> 20) & 0xff; +} + +/* Receive the gpu revision */ +static short get_gpu_revision() +{ + return nv_read_pmc(NV_PMC_BOOT_0) & NV_PMC_BOOT_0_REVISION_MASK; +} + +/* Retrieve the 'real' PCI id from the card */ +static short get_gpu_pci_id() +{ + return nv_read_pbus16(PCI_DEVICE_ID); +} + +/* Retrieve the pci subvendor id */ +static short get_pci_subvendor_id() +{ + return nv_read_pbus16(PCI_SUBSYSTEM_VENDOR_ID); +} + +static int set_gpu_pci_id(short id) +{ + if(nv_card->arch & (NV10 | NV20)) + { + /* The first two bits of the pci id can be changed. They are stored in bit 13-12 of PEXTDEV_BOOT0 */ + int pextdev_boot0 = nv_card->PEXTDEV[0x0/4] & ~(0x3 << 12); + /* Only the first 2 bits can be changed on these GPUs */ + if(id > 3) + return 0; + + nv_card->PEXTDEV[0x0/4] = pextdev_boot0 | ((id & 0x3) << 12); + nv_card->device_id = get_gpu_pci_id(); + nv_card->card_name = (char*)get_card_name(nv_card->device_id, &nv_card->gpu); + return 1; + } + /* Don't allow modding on cards using bridges (0xf*)! */ + else if((nv_card->arch & (NV17 | NV25 | NV3X | NV4X)) && ((nv_card->device_id & 0xfff0) != 0xf0)) + { + /* The first four bits of the pci id can be changed. The first two bits are stored in bit 13-12 of PEXTDEV_BOOT0, bit 3 and 4 are stored in bit 21-20 */ + int pextdev_boot0 = nv_card->PEXTDEV[0x0/4] & ~((0x3 << 20) | (0x3 << 12)); + /* The first 4 bits can be changed */ + if(id > 16) + return 0; + + /* On various NV4x cards the quadro capability bit in PBUS_DEBUG1 is locked. It can be unlocked by setting the first bit in 0xc020/0xc028 */ + nv_card->PMC[0xc020/4] = 1; + nv_card->PMC[0xc028/4] = 1; + + nv_card->PEXTDEV[0x0/4] = pextdev_boot0 | (((id>>2) & 0x3) << 20) | ((id & 0x3) << 12); + nv_card->device_id = get_gpu_pci_id(); + nv_card->card_name = (char*)get_card_name(nv_card->device_id, &nv_card->gpu); + return 1; + } + return 0; +} + +/* Function to read a single byte from pci configuration space */ +#if NOTUSED +static void read_byte(int offset, unsigned char *data) +{ + /* The original plan was to read the PCI configuration directly from registers 0x1800 and upwards + / from the card itself. Although this is a fully correct way, it doesn't work for some cards using + / a PCI-Express -> AGP bridge. If I would read the registers from the card they would include PCI-Express + / as one of the capabilities. Reading using the "normal" way results in AGP as one of the capabilities. + / To correctly show that a card uses AGP we need to read the modded config space. + */ + *data = pciReadLong(nv_card->devbusfn,offset) & 0xff; +} +#endif + +/* Check the videocard for a certain PCI capability like AGP/PCI-Express/PowerManagement. + / If a certain capability is supported return the position of the cap pointer. + */ +/* + static int pci_find_capability(unsigned char cap) + { + unsigned char pos, id; + + read_byte(PCI_CAPABILITY_LIST, &pos); + + while(pos >= 0x40) + { + pos &= ~3; + read_byte(pos + PCI_CAP_LIST_ID, &id); + if(id == 0xff) + break; + if(id == cap) + return pos; // Return the position of the cap pointer + + read_byte(pos + PCI_CAP_LIST_NEXT, &pos); + } + return 0; + } + */ +/* Check the videocard for a certain PCI capability like AGP/PCI-Express/PowerManagement. + / If a certain capability is supported return the position of the cap pointer. + */ +static int nv_pci_find_capability(unsigned char cap) +{ + unsigned char pos, id; + + pos = nv_read_pbus8(PCI_CAPABILITY_LIST); + + while(pos >= 0x40) + { + pos &= ~3; + id = nv_read_pbus8(pos + PCI_CAP_LIST_ID); + if(id == 0xff) + break; + if(id == cap) + return pos; /* Return the position of the cap pointer */ + + pos = nv_read_pbus8(pos + PCI_CAP_LIST_NEXT); + } + return 0; +} + +char* get_bus_type() +{ + /* The pci header contains lots of information about a device like + / what type of device it is, who the vendor is and so on. It also + / contains a list of capabilities. Things like AGP, power management, + / PCI-X and PCI-Express are considered capabilities. We could check + / these capabilities to find out if the card is AGP or PCI-Express. + / + / Reading the bus type from the pci header would be a nice way but + / unfortunately there are some issues. One way to do the reading + / is to read the information directly from the card (from PMC). + / This doesn't work as some PCI-Express boards (6600GT) actually use + / PCI-Express GPUs connected to some bridge chip on AGP boards (same device id!). + / If you read directly from the card it will advertise PCI-Express instead of AGP. + / There is also another way to read the pci header for instance on Linux + / using from files in /proc/bus/pci but non-root users can only read + / a small part of the file. Most of the time the info we need isn't in + / the readable part. Further there are also some early PCI-Express boards (GeforcePCX) + / that contain bridge chips to turn AGP GPUs into PCI-Express ones. + / + / Currently we will return PCI-Express on GeforcePCX board under the valid + / assumption that there are no AGP boards with the same device id. Further + / it seems that 'low' device ids are for PCI-Express->AGP while the higher ones + / are for AGP->PCI-Express, so for the lower ones (6200/6600/6800) we will return AGP + / and for the higher ones PCI-Express. A nicer way would be to read all this stuff from + / the pci header but as explained that can't be done at the moment. + */ + switch(nv_card->device_id) + { + case 0xf0: /* 6800 */ + case 0xf1: /* 6600GT */ + case 0xf2: /* 6600 */ + case 0xf3: /* 6200 */ + case 0xf5: /* 6800GS/XT */ + case 0xf6: /* 7800GS */ + case 0x2e0: /* 7600GT */ + case 0x2e1: /* 7600GS */ + case 0x2e2: /* 7300GT */ + return STRDUP("AGP (BR02)", sizeof("AGP (BR02)")); /* We return something different from AGP for now as we don't want to show the AGP tab */ + case 0xf8: /* Quadro FX3400 */ + case 0xf9: /* Geforce 6800 series */ + case 0xfa: /* PCX5500 */ + case 0xfb: /* PCX5900 */ + case 0xfc: /* Quadro FX330*/ + case 0xfd: /* PCX5500 */ + case 0xfe: /* Quadro 1300 */ + case 0xff: /* PCX4300 */ + return STRDUP("PCI-Express (BR02)", sizeof("PCI-Express (BR02)")); + } + + if(nv_pci_find_capability(PCI_CAP_ID_EXP)) + return STRDUP("PCI-Express", sizeof("PCI-Express")); + else if(nv_pci_find_capability(PCI_CAP_ID_AGP)) + return STRDUP("AGP", sizeof("AGP")); + else + return STRDUP("PCI", sizeof("PCI")); +} + +/* Needs better bus checks .. return a string ?*/ +static short get_agp_bus_rate() +{ + int agp_capptr, agp_rate, agp_status; + + agp_capptr = nv_pci_find_capability(PCI_CAP_ID_AGP); + agp_status = nv_read_pbus(agp_capptr + PCI_AGP_STATUS); + agp_rate = nv_read_pbus(agp_capptr + PCI_AGP_COMMAND) & PCI_AGP_STATUS_RATE_MASK; + + /* If true, the user has AGP8x support */ + if(agp_status & PCI_AGP_STATUS_RATE_8X_SUPPORT) + { + agp_rate <<= PCI_AGP_STATUS_RATE_8X_SHIFT; + } + return agp_rate; +} + +char* get_agp_fw_status() +{ + int agp_capptr = nv_pci_find_capability(PCI_CAP_ID_AGP); + unsigned int agp_status = nv_read_pbus(agp_capptr + PCI_AGP_STATUS); + unsigned int agp_command = nv_read_pbus(agp_capptr + PCI_AGP_COMMAND); + + /* Check if Fast Writes is supported by the hostbridge */ + if(agp_status & PCI_AGP_STATUS_FW) + return (agp_command & PCI_AGP_COMMAND_FW) ? STRDUP("Enabled", sizeof("Enabled")) : STRDUP("Disabled", sizeof("Disabled")); + else + return STRDUP("Unsupported", sizeof("Unsupported")); +} + +char* get_agp_sba_status() +{ + int agp_capptr = nv_pci_find_capability(PCI_CAP_ID_AGP); + unsigned int agp_status = nv_read_pbus(agp_capptr + PCI_AGP_STATUS); + unsigned int agp_command = nv_read_pbus(agp_capptr + PCI_AGP_COMMAND); + + /* Check if Sideband Addressing is supported by the hostbridge */ + if(agp_status & PCI_AGP_STATUS_SBA) + return (agp_command & PCI_AGP_COMMAND_SBA) ? STRDUP("Enabled", sizeof("Enabled")) : STRDUP("Disabled", sizeof("Disabled")); + else + return STRDUP("Unsupported", sizeof("Unsupported")); +} + +char* get_agp_status() +{ + int agp_capptr = nv_pci_find_capability(PCI_CAP_ID_AGP); + unsigned int agp_command = nv_read_pbus(agp_capptr + PCI_AGP_COMMAND); + return (agp_command & PCI_AGP_COMMAND_AGP) ? STRDUP("Enabled", sizeof("Enabled")) : STRDUP("Disabled", sizeof("Disabled")); +} + +static char* get_agp_supported_rates() +{ + int agp_capptr, agp_rates, agp_status, i; + static char *rate; + + agp_capptr = nv_pci_find_capability(PCI_CAP_ID_AGP); + agp_status = nv_read_pbus(agp_capptr + PCI_AGP_STATUS); + agp_rates = agp_status & PCI_AGP_STATUS_RATE_MASK; + + /* If true, the user has AGP8x support */ + if(agp_status & PCI_AGP_STATUS_RATE_8X_SUPPORT) + { + agp_rates <<= PCI_AGP_STATUS_RATE_8X_SHIFT; + } + + rate = new char[1]; + + for(i=1; i <= 8; i*=2) + { + if(agp_rates & i) + { + char *temp = new char[4]; + snprintf(temp, 4, "%dX ", i); + char* newrate=new char[strlen(rate)+4]; + strncpy(newrate, rate, strlen(rate)+4); + delete[] rate; + rate=newrate; + rate = strncat(rate, temp, strlen(rate)); + delete[] temp; + } + } + + return rate; +} + +static short get_pcie_bus_rate() +{ + int pcie_rate, pcie_status_reg; + + pcie_status_reg = nv_pci_find_capability(PCI_CAP_ID_EXP); + if(pcie_status_reg != 0 ) + { + pcie_rate = (nv_read_pbus16(pcie_status_reg + PCIE_LINKSTATUS) & PCIE_LINK_SPEED_MASK) >> PCIE_LINK_SPEED_SHIFT; + return pcie_rate; + } + return 0; +} + +static short get_pcie_max_bus_rate() +{ + int pcie_rate, pcie_status_reg; + + pcie_status_reg = nv_pci_find_capability(PCI_CAP_ID_EXP); + if(pcie_status_reg != 0 ) + { + pcie_rate = (nv_read_pbus16(pcie_status_reg + PCIE_LINKCAP) & PCIE_LINK_SPEED_MASK) >> PCIE_LINK_SPEED_SHIFT; + + return pcie_rate; + } + return 0; +} + +static short get_memory_width() +{ + /* Nforce / Nforce2 */ + if((nv_card->device_id == 0x1a0) || (nv_card->device_id == 0x1f0)) + return 64; + /* GeforceFX cards (except for FX5200) need a different check */ + /* What to do with NV40 cards ? */ + else if(nv_card->arch & NV3X) + { + /* I got this info from the rivatuner forum. On the forum + * is a thread containing register dumps from lots of cards. + * It might not be 100% correct but it is better than a pci id check */ + switch(nv_card->PFB[0x200/4] & 0x7) + { + /* 64bit FX5600 */ + case 0x1: + return 64; + /* 128bit FX5800 */ + case 0x3: + return 128; + /* 128bit FX5600, FX5700 */ + case 0x5: + return 128; + /* 256bit FX5900 */ + case 0x7: + return 256; + } + } + else if(nv_card->arch == NV44) + { + return 64; /* For now return 64; (Turbocache cards) */ + } + else if(nv_card->arch & NV4X) + { + /* Memory bandwith detection for nv40 but not sure if it is correct, it is atleast better than nothing */ + switch(nv_card->PFB[0x200/4] & 0x7) + { + /* 128bit 6600GT */ + case 0x1: + return 128; + /* 256bit 6800 */ + case 0x3: + return 256; + default: + return 128; + } + } + else if(nv_card->arch & NV5X) + { + /* On Geforce 8800GTS/GTX and 8600GT/GTS cards the memory bandwith is proportional to the number of ROPs * 16. + * In case of the 8500 this isn't the case, there the size is just 128 where there are 4 ROPs. + * So for now use the number of ROPs as a meassure for the bus width. + */ + char rmask, rmask_default; + switch(nv_card->get_rop_units(&rmask, &rmask_default)) + { + case 48: /* Geforce GTX 480 */ + return 384; + case 40: /* Geforce GTX 470 */ + return 320; + case 32: /* Geforce GTX280 */ + return 512; + case 28: /* Geforce GTX260 */ + return 448; + case 24: /* 8800GTX */ + return 384; + case 20: /* 8800GTS */ + return 320; + case 16: /* 8800GT */ + return 256; + case 12: /* 8800GS */ + return 192; + case 8: /* 8600GT/GTS */ + case 4: /* 8500GT; 8400GS boards use the same core and offer 64-bit, how to handle this? */ + return 128; + case 2: /* 8300GS */ + return 64; + default: + if(nv_card->arch == GF100) { + return nv_card->get_rop_units(&rmask, &rmask_default) * 8; + } + break; + } + } + /* Generic algorithm for cards up to the Geforce4 */ + return (nv_card->PEXTDEV[0x0/4] & 0x17) ? 128 : 64; +} + +char* get_memory_type() +{ + /* Nforce / Nforce2 */ + if((nv_card->device_id == 0x1a0) || (nv_card->device_id == 0x1f0)) + return ((pciReadLong(0x1, 0x7c) >> 12) & 0x1) ? STRDUP("DDR", sizeof("DDR")) : STRDUP("SDR", sizeof("SDR")); + else if(nv_card->arch & (NV2X | NV3X)) + { + /* Based on statistics found on the rivatuner forum, the first two bytes of + * register 0x1218 of NV2X/NV3X boards, contains "0x0001 or 0x0101" in case of DDR memory and "0x0301" for DDR2. + */ + return (((nv_card->PMC[0x1218/4] >> 8) & 0x3) == 0x3) ? STRDUP("DDR2", sizeof("DDR2")) : STRDUP("DDR", sizeof("DDR")); + } + else if(nv_card->arch & (NV4X)) + { + /* On Geforce6/7 cards 0x100474 (PFB 0x474) can be used to distinguish between DDR and DDR3. + * Note these values are based on the bios and it was noted that for instance bits in this register differ. + * In case of DDR3 the first byte contains 0x4 while in case of DDR it contains 0x1. + */ + return (nv_card->PFB[0x474/4] & 0x4) ? STRDUP("DDR3", sizeof("DDR3")) : STRDUP("DDR", sizeof("DDR")); + } + else if(nv_card->arch & (NV5X)) + { + /* For now use 0x100218 (PFB 0x218) to distinguish between DDR2 and DDR3. The contents of this + * register differs between a 8500GT (DDR2) and 8600GTS/8800GTS (DDR3) according to the bios. + * FIXME: use a better register + */ + return (nv_card->PFB[0x218/4] & 0x1000000) ? STRDUP("DDR3", sizeof("DDR3")) : STRDUP("DDR2", sizeof("DDR2")); + } + else + /* TNT, Geforce1/2/4MX */ + return (nv_card->PFB[0x200/4] & 0x01) ? STRDUP("DDR", sizeof("DDR")) : STRDUP("SDR", sizeof("SDR")); +} + +static short get_memory_size() +{ + short memory_size; + + /* If the card is something TNT based the calculation of the memory is different. */ + if(nv_card->arch == NV5) + { + if(nv_card->PFB[0x0/4] & 0x100) + memory_size = ((nv_card->PFB[0x0/4] >> 12) & 0xf)*2+2; + else + { + switch(nv_card->PFB[0x0/4] & 0x3) + { + case 0: + memory_size = 32; + break; + case 1: + memory_size = 4; + break; + case 2: + memory_size = 8; + break; + case 3: + memory_size = 16; + break; + default: + memory_size = 16; + break; + } + } + } + /* Nforce 1 */ + else if(nv_card->device_id == 0x1a0) + { + int32_t temp = pciReadLong(0x1, 0x7c); + memory_size = ((temp >> 6) & 0x31) + 1; + } + /* Nforce2 */ + else if(nv_card->device_id == 0x1f0) + { + int32_t temp = pciReadLong(0x1, 0x84); + memory_size = ((temp >> 4) & 0x127) + 1; + } + /* Memory calculation for geforce cards or better.*/ + else + { + /* The code below is needed to show more than 256MB of memory + / but I'm not sure if 0xfff is safe for pre-geforcefx cards. + / There's no clean way right now to use 0xff for those old cards + / as currently the FX5200/FX5500 (which support 256MB) use the + / pre-geforcefx backend. + */ + memory_size = (nv_card->PFB[0x20c/4] >> 20) & 0xfff; + } + + return memory_size; +} + +/* Print various GPU registers for debugging purposes */ +static void get_debug_info() +{ + printf("--- %s GPU registers ---\n", nv_card->card_name); + printf("NV_PMC_BOOT_0 (0x0): %08x\n", nv_card->PMC[0]); + printf("NV_PBUS_DEBUG_0 (0x1080): %08x\n", nv_card->PMC[0x1080/4]); + printf("NV_PBUS_DEBUG_1 (0x1084): %08x\n", nv_card->PMC[0x1084/4]); + printf("NV_PBUS_DEBUG_2 (0x1088): %08x\n", nv_card->PMC[0x1088/4]); + printf("NV_PBUS_DEBUG_3 (0x108c): %08x\n", nv_card->PMC[0x108c/4]); + printf("NV_10F0 (0x10f0): %08x\n", nv_card->PMC[0x10f0/4]); + printf("NV_1540 (0x1540): %08x\n", nv_card->PMC[0x1540/4]); + printf("NV_15B0 (0x15b0): %08x\n", nv_card->PMC[0x15b0/4]); + printf("NV_15B4 (0x15b4): %08x\n", nv_card->PMC[0x15b4/4]); + printf("NV_15B8 (0x15b8): %08x\n", nv_card->PMC[0x15b8/4]); + printf("NV_15F0 (0x15f0): %08x\n", nv_card->PMC[0x15f0/4]); + printf("NV_15F4 (0x15f4): %08x\n", nv_card->PMC[0x15f4/4]); + printf("NV_15F8 (0x15f8): %08x\n", nv_card->PMC[0x15f8/4]); + printf("NV_PBUS_PCI_0 (0x1800): %08x\n", nv_read_pbus(PCI_VENDOR_ID)); + printf("NV_PBUS_PCI_0 (0x182c): %08x\n", nv_read_pbus(PCI_SUBSYSTEM_VENDOR_ID)); + + if(nv_card->arch & (NV4X | NV5X)) + { + printf("NV_C010 (0xc010): %08x\n", nv_card->PMC[0xc010/4]); + printf("NV_C014 (0xc014): %08x\n", nv_card->PMC[0xc014/4]); + printf("NV_C018 (0xc018): %08x\n", nv_card->PMC[0xc018/4]); + printf("NV_C01C (0xc01c): %08x\n", nv_card->PMC[0xc01c/4]); + printf("NV_C020 (0xc020): %08x\n", nv_card->PMC[0xc020/4]); + printf("NV_C024 (0xc024): %08x\n", nv_card->PMC[0xc024/4]); + printf("NV_C028 (0xc028): %08x\n", nv_card->PMC[0xc028/4]); + printf("NV_C02C (0xc02c): %08x\n", nv_card->PMC[0xc02c/4]); + printf("NV_C040 (0xc040): %08x\n", nv_card->PMC[0xc040/4]); + printf("NV_4000 (0x4000): %08x\n", nv_card->PMC[0x4000/4]); + printf("NV_4004 (0x4004): %08x\n", nv_card->PMC[0x4004/4]); + printf("NV_4008 (0x4008): %08x\n", nv_card->PMC[0x4008/4]); + printf("NV_400C (0x400c): %08x\n", nv_card->PMC[0x400c/4]); + printf("NV_4010 (0x4010): %08x\n", nv_card->PMC[0x4010/4]); + printf("NV_4014 (0x4014): %08x\n", nv_card->PMC[0x4014/4]); + printf("NV_4018 (0x4018): %08x\n", nv_card->PMC[0x4018/4]); + printf("NV_401C (0x401c): %08x\n", nv_card->PMC[0x401c/4]); + printf("NV_4020 (0x4020): %08x\n", nv_card->PMC[0x4020/4]); + printf("NV_4024 (0x4024): %08x\n", nv_card->PMC[0x4024/4]); + printf("NV_4028 (0x4028): %08x\n", nv_card->PMC[0x4028/4]); + printf("NV_402C (0x402c): %08x\n", nv_card->PMC[0x402c/4]); + printf("NV_4030 (0x4030): %08x\n", nv_card->PMC[0x4030/4]); + printf("NV_4034 (0x4034): %08x\n", nv_card->PMC[0x4034/4]); + printf("NV_4038 (0x4038): %08x\n", nv_card->PMC[0x4038/4]); + printf("NV_403C (0x403c): %08x\n", nv_card->PMC[0x403c/4]); + printf("NV_4040 (0x4040): %08x\n", nv_card->PMC[0x4040/4]); + printf("NV_4044 (0x4044): %08x\n", nv_card->PMC[0x4044/4]); + printf("NV_4048 (0x4048): %08x\n", nv_card->PMC[0x4048/4]); + printf("NV_404C (0x404c): %08x\n", nv_card->PMC[0x404c/4]); + printf("NV_4050 (0x4050): %08x\n", nv_card->PMC[0x4050/4]); + printf("NV_4054 (0x4054): %08x\n", nv_card->PMC[0x4054/4]); + printf("NV_4058 (0x4058): %08x\n", nv_card->PMC[0x4058/4]); + printf("NV_405C (0x405c): %08x\n", nv_card->PMC[0x405c/4]); + printf("NV_4060 (0x4060): %08x\n", nv_card->PMC[0x4060/4]); + } + if(nv_card->arch & NV5X) + { + printf("NV_E100 (0xe100): %08x\n", nv_card->PMC[0xe100/4]); + printf("NV_E114 (0xe114): %08x\n", nv_card->PMC[0xe114/4]); + printf("NV_E118 (0xe118): %08x\n", nv_card->PMC[0xe118/4]); + printf("NV_E11C (0xe11c): %08x\n", nv_card->PMC[0xe11c/4]); + printf("NV_E120 (0xe120): %08x\n", nv_card->PMC[0xe120/4]); + printf("NV_E300 (0xe300): %08x\n", nv_card->PMC[0xe300/4]); + printf("NV_20008 (0x20008): %08x\n", nv_card->PMC[0x20008/4]); + printf("NV_20400 (0x20400): %08x\n", nv_card->PMC[0x20400/4]); + printf("NV_PDISPLAY_SOR0_REGS_BRIGHTNESS(%x): %08x\n", NV_PDISPLAY_SOR0_REGS_BRIGHTNESS, nv_card->PDISPLAY[NV_PDISPLAY_SOR0_REGS_BRIGHTNESS/4]); + } + + printf("NV_PFB_CFG0 (0x100200): %08x\n", nv_card->PFB[0x200/4]); + printf("NV_PFB_CFG0 (0x100204): %08x\n", nv_card->PFB[0x204/4]); + printf("NV_PFB_CFG0 (0x100208): %08x\n", nv_card->PFB[0x208/4]); + printf("NV_PFB_CFG0 (0x10020c): %08x\n", nv_card->PFB[0x20c/4]); + printf("NV_PFB_218 (0x100218): %08x\n", nv_card->PFB[0x218/4]); + printf("NV_PFB_TIMING0 (0x100220): %08x\n", nv_card->PFB[0x220/4]); + printf("NV_PFB_TIMING1 (0x100224): %08x\n", nv_card->PFB[0x224/4]); + printf("NV_PFB_TIMING2 (0x100228): %08x\n", nv_card->PFB[0x228/4]); + printf("NV_PFB_474 (0x100474): %08x\n", nv_card->PFB[0x474/4]); + printf("NV_PEXTDEV_BOOT_0 (0x101000): %08x\n", nv_card->PEXTDEV[0x0/4]); + printf("NV_NVPLL_COEFF_A (0x680500): %08x\n", nv_card->PRAMDAC[0x500/4]); + printf("NV_MPLL_COEFF_A (0x680504): %08x\n", nv_card->PRAMDAC[0x504/4]); + printf("NV_VPLL_COEFF (0x680508): %08x\n", nv_card->PRAMDAC[0x508/4]); + printf("NV_PLL_COEFF_SELECT (0x68050c): %08x\n", nv_card->PRAMDAC[0x50c/4]); + printf("NV_NVPLL_COEFF_B (0x680570: %08x\n", nv_card->PRAMDAC[0x570/4]); + printf("NV_MPLL_COEFF_B (0x680574: %08x\n", nv_card->PRAMDAC[0x574/4]); + + /* The builtin tvout encoder is available on Geforce4MX/TI and all other GPUs upto NV3x/NV4x. + * The registers are somewhere else on Geforce8 cards. There is a difference between the encoders + * on the difference cards but I'm not sure which apart from more features like the addition of + * component on the Geforce6 */ + if(nv_card->arch & (NV17 | NV25 | NV3X | NV4X)) + { + int index=0; + printf("--- TVOut regs ---\n"); + printf("0xd200: 0x%08x\n", nv_card->PMC[0xd200/4]); /* bit27-24 flickering (?) */ + printf("0xd204: 0x%08x\n", nv_card->PMC[0xd204/4]); + printf("0xd208: 0x%08x\n", nv_card->PMC[0xd208/4]); /* Overscan */ + printf("0xd20c: 0x%08x\n", nv_card->PMC[0xd20c/4]); + printf("0xd210: 0x%08x\n", nv_card->PMC[0xd210/4]); /* bit 23-8 contain the horizontal resolution */ + printf("0xd214: 0x%08x\n", nv_card->PMC[0xd214/4]); /* bit 23-8 contain the vertical resolution */ + printf("0xd218: 0x%08x\n", nv_card->PMC[0xd218/4]); /* bit31 = sign bit; bit16 and up can be used for horizontal positioning */ + + printf("0xd21c: 0x%08x\n", nv_card->PMC[0xd21c/4]); /* bit31 = sign bit; bit16 and up can be used for vertical positioning */ + + printf("0xd228: 0x%08x\n", nv_card->PMC[0xd228/4]); /* is this some clock signal?? */ + printf("0xd22c: 0x%08x\n", nv_card->PMC[0xd22c/4]); + + printf("0xd230: 0x%08x\n", nv_card->PMC[0xd230/4]); + printf("0xd304: 0x%08x\n", nv_card->PMC[0xd304/4]); /* bit 25-16 hscaler (PAL 720, NTSC 720) */ + printf("0xd508: 0x%08x\n", nv_card->PMC[0xd508/4]); /* bit 25-26 vscalar (PAL 288, NTSC 240) */ + printf("0xd600: 0x%08x\n", nv_card->PMC[0xd600/4]); + printf("0xd604: 0x%08x\n", nv_card->PMC[0xd604/4]); + printf("0xd608: 0x%08x\n", nv_card->PMC[0xd608/4]); + + /* Register 0xd220/0xd224 form a index/data register pair + * - 0x7 = bit4:0 connector type; bit2 s-video, bit2-0 empty: composite? + * - 0xe = bit7:0 tv system; ntscm (japan) 0x2; palb/d/g 0x4; palm/n/ntsc 0xc; is this correct? + * - 0x22 = tv saturation + * - 0x25 = tv hue + * how many indices exist ? + */ + for(index=0; index < 0x80; index++) + { + nv_card->PMC[0xd220/4] = index; + printf("index 0x%x: %02x\n", index, nv_card->PMC[0xd224/4]); + } + } +} + + +void info_init(void) +{ + nv_card->get_bus_type = get_bus_type; + + /* Set the pci id again as the detected id might not be accurate in case of pci id modding. The OS doesn't allways update the id while it really changed! Only do it for cards without bridges (device_id != 0xf* and 0x2e* + * Don't use this for NV50 as the location of the pci config header has changed to an unknown position. + */ + if(((nv_card->device_id & 0xfff0) != 0xf0) && ((nv_card->device_id & 0xfff0) != 0x2e0) && !(nv_card->arch & NV5X)) + { + nv_card->device_id = get_gpu_pci_id(); + nv_card->card_name = (char*)get_card_name(nv_card->device_id, &nv_card->gpu); + } + + /* Set the pci subvendor id */ + nv_card->subvendor_id = get_pci_subvendor_id(); + + /* gpu arch/revision */ + nv_card->get_gpu_architecture = get_gpu_architecture; + nv_card->get_gpu_revision = get_gpu_revision; + + /* Allow modding on all Geforce cards except for ones using bridges */ + if((nv_card->arch & (NV1X | NV2X | NV3X | NV4X)) && ((nv_card->device_id & 0xfff0) != 0xf0)) + { + nv_card->caps |= GPU_ID_MODDING; + nv_card->set_gpu_pci_id = set_gpu_pci_id; + } + else + nv_card->set_gpu_pci_id = NULL; + + /* Check if card is a native AGP one and not using a bridge chip else we can't use the code below */ + if(strcmp(nv_card->get_bus_type(), "AGP") == 0) + { + nv_card->get_bus_rate = get_agp_bus_rate; + nv_card->get_agp_status = get_agp_status; + nv_card->get_agp_fw_status = get_agp_fw_status; + nv_card->get_agp_sba_status = get_agp_sba_status; + nv_card->get_agp_supported_rates = get_agp_supported_rates; + } + /* Check if card is a native PCI-Express one and not using a bridge chip else we can't use the code below */ + else if(strcmp(nv_card->get_bus_type(), "PCI-Express") == 0) + { + nv_card->get_bus_rate = get_pcie_bus_rate; + nv_card->get_pcie_max_bus_rate = get_pcie_max_bus_rate; + nv_card->get_agp_status = NULL; + nv_card->get_agp_fw_status = NULL; + nv_card->get_agp_sba_status = NULL; + nv_card->get_agp_supported_rates = NULL; + } + else + { + nv_card->get_bus_rate = NULL; + nv_card->get_agp_status = NULL; + nv_card->get_agp_fw_status = NULL; + nv_card->get_agp_sba_status = NULL; + nv_card->get_agp_supported_rates = NULL; + } + + nv_card->get_memory_size = get_memory_size; + nv_card->get_memory_type = get_memory_type; + nv_card->get_memory_width = get_memory_width; + + /* Debugging stuff */ + nv_card->get_debug_info = get_debug_info; +} diff --git a/plugins/GPUSensors/NVClockX/NVClock/libc_wrapper.cpp b/plugins/GPUSensors/NVClockX/NVClock/libc_wrapper.cpp new file mode 100644 index 0000000..e3b678b --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/libc_wrapper.cpp @@ -0,0 +1,65 @@ +/* Excerpt from: */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/libc_wrapper.c,v 1.70 2000/09/26 15:57:20 tsi Exp $ */ +/* + * Copyright 1997 by The XFree86 Project, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the names of Orest Zborowski and David Wexelblat + * not be used in advertising or publicity pertaining to distribution of + * the software without specific, written prior permission. Orest Zborowski + * and David Wexelblat make no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * THE XFREE86 PROJECT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID WEXELBLAT BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +//#include +#include "nvclock.h" +#include "xfree.h" + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include + +/* Misc functions. Some are ANSI C, some are not. */ + +/* FIXME might use nanosleep (POSIX) here. */ +/* resolution of 1/HZ s (i.e, 10 ms on Linux/i386 and 1 ms on Linux/Alpha). */ +/* If the process is scheduled under a real-time policy like + SCHED_FIFO or SCHED_RR, then pauses of up to 2 ms will be + performed as busy waits with microsecond precision. +*/ + +/*void +xf86usleep(unsigned long usec) + //unsigned long usec; +{ + IOSleep(usec); +} +*/ + +void xf86getsecs(long * secs, long * usecs) +{ + /*struct timeval tv; + + microtime(&tv); + *secs = tv.tv_sec; + *usecs= tv.tv_usec; +*/ + return; +} + diff --git a/plugins/GPUSensors/NVClockX/NVClock/lm99.cpp b/plugins/GPUSensors/NVClockX/NVClock/lm99.cpp new file mode 100644 index 0000000..4dd687f --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/lm99.cpp @@ -0,0 +1,104 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2005 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * LM99 hardware monitoring + */ +#include +#include "i2c.h" +#include "nvclock.h" + + +/* various defines for register offsets and such are needed */ + +#define LM99_REG_LOCAL_TEMP 0x0 +#define LM99_REG_REMOTE_TEMP 0x1 +#define LM99_REG_MAN_ID 0xfe + #define NATSEM_MAN_ID 0x1 + #define MAXIM_MAN_ID 0x4d +#define LM99_REG_CHIP_ID 0xff + +/* This function should return the chip type .. */ +int lm99_detect(I2CDevPtr dev) +{ + I2CByte man_id, chip_id; + + xf86I2CReadByte (dev, LM99_REG_MAN_ID, &man_id); + xf86I2CReadByte (dev, LM99_REG_CHIP_ID, &chip_id); + + switch(man_id) + { + /* National Semiconductor LM99; needs offset? */ + case NATSEM_MAN_ID: + dev->chip_id = LM99; + dev->chip_name = (char*)STRDUP("National Semiconductor LM99", sizeof("National Semiconductor LM99")); + break; + /* Unknown vendor; this chip was used in a FX5700Go laptop and looks similar to the MAx6659 */ + case 0x47: + /* Maxim; likely a 655x model */ + case MAXIM_MAN_ID: + dev->chip_id = MAX6559; + dev->chip_name = (char*)STRDUP("Maxim MAX6659", sizeof("Maxim MAX6659")); + break; + default: + return 0; + } + + return 1; +} + +int lm99_get_board_temp(I2CDevPtr dev) +{ + I2CByte temp; + xf86I2CReadByte(dev, LM99_REG_LOCAL_TEMP, &temp); + return temp; +} + +int lm99_get_gpu_temp(I2CDevPtr dev) +{ + I2CByte temp; + + xf86I2CReadByte(dev, LM99_REG_REMOTE_TEMP, &temp); + + /* Cards with lm99 chips need an offset of 16C according to the datasheets. */ + if(dev->chip_id == LM99) + { + temp += 16; + } + + /* The temperature needs to be corrected using an offset which is stored in the bios. + / If no bios has been parsed we fall back to a default value. + */ + if(nv_card->bios) + { + temp += nv_card->bios->sensor_cfg.temp_correction; + } + else + { + /* An extra offset of 10C seems to be needed on Geforce6800 cards to match nvidia-settings. + / Last but not least Geforce6600GT boards containing an LM99 sensor seem to need a +5C offset. + */ + if(dev->arch == NV43) + temp += 5; + else if(dev->arch & NV4X) + temp += 10; + } + + return temp; +} diff --git a/plugins/GPUSensors/NVClockX/NVClock/nv40.cpp b/plugins/GPUSensors/NVClockX/NVClock/nv40.cpp new file mode 100644 index 0000000..15d1f83 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/nv40.cpp @@ -0,0 +1,1100 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2008 Roderick Colenbrander + * + * Thanks to Erik Waling for doing Smartdimmer coding/testing. (his code isn't the one in NVClock) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* This source file uses some clock calculation code from nvidia's xfree86 driver. + To keep Nvidia happy I have added their copyright. The way they interpret it (see linux kernel riva_hw.h) + is that you need to add the disclaimer and copyright and when that's done + you can basicly do what you want. +*/ + +/***************************************************************************\ +|* *| +|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| +\***************************************************************************/ + +//#include +#include +#include "backend.h" + +/* +/ The original NV40 gpu was used as the base for 6800LE/6800NU/6800GT/6800Ultra +/ GPUs. The difference between all these models lie in the amount of enabled +/ pixel/vertex pipelines and clockspeeds. For instance the 6800LE ships with 8 +/ pixel pipelines while the 6800GT ships with 16 of those. Right after production +/ all GPUs are tested, if all pipelines work and they run at high clocks they +/ are called Ultra or if pipes are broken they are called 6800NU(12p) or 6800LE(8p). +/ Further in some cases 'good' GPUs can be rebranded too if there's a shortage of +/ 6800NU/6800LE GPUs. The key to this rebranding is register 0x1540 which contains +/ the enabled pixel/vertex pipelines. Depending on the GPU architecture a bit can +/ correspond to a single vertex shader or to a block containing two or four +/ pixel pipelines. +/ +/ We now define some words coming from Rivatuner as people are familiar with those. +/ A 'good' GPU for which pipelines are disabled just to get enough lowend models +/ is said to contain 'Software masked units'. In this case the videobios initializes +/ 0x1540 with a value that locks out some units. +/ GPUs which didn't pass the hardware quality testing contain 'Hardware masked units'. +/ In this case the bios initializes 0x1540 with a value that enables all pipelines. +/ A certain (read-only) register (0xc010) contains a mask of units to disable by default. +/ The bios loads this value into another register (0xc020) at startup. The value from +/ 0xc020 is then used by the drivers to disable units in 0x1540. For example by clearing this +/ register before the drivers are loaded, you can prevent masks from being disabled. + +/ 1540 units_cfg (rw) second byte contains vertex configuration and first byte pipeline +/ c010 default_mask (r) pixel pipelines start at +22, while vertex start at +16 (is this correct for all cards?) +/ c020 active_mask (rw) +/ c024/c028/c02c are being set to 0, why? (they correspond to c014/c018/c01c) +/ +/ Below are supported pipeline configurations on various types of cards. Not sure +/ if everything is fully correct though: +/ - NV40 0x3f0f 6800 cards +/ - NV41 0x1f07 6800 pci-e (is this correct?) +/ - NV43 0x0703 6200/6600 cards +/ - NV44 0x0703 6200(Go)/Turbocache cards +/ - NV46 0x0703 7300 (is this correct?) +/ - NV47/NV49 0xff3f 7800/7900 cards +/ - NV4B 0x1f0f 7600 +*/ +unsigned int abs0 (int number); +unsigned int abs0 (int number) +{ + if (number<0) + number=-number; + return number; +} + + +static int nv40_get_default_mask(char *pmask, char *vmask) +{ + int mask = 0; + switch(nv_card->arch) + { + case NV40: + mask = 0x3f0f; + break; + case NV41: + mask = 0x1f07; + break; + case NV43: + case NV44: + case NV46: + case C51: + mask = 0x703; + break; + case NV47: + case NV49: + mask = 0xff3f; + break; + case NV4B: + mask = 0x1f0b; + break; + } + + if(pmask) + *pmask = mask & 0xff; + if(vmask) + *vmask = (mask >> 8) & 0xff; + + return mask; +} + +/* Try to locate hardware maskes units. On success we return 1 and pmask/vmask +/ contain the masked units. When no hw masked units are found we return 0. +*/ +static int nv40_get_hw_masked_units(char *pmask, char *vmask) +{ + unsigned int mask = nv_card->PMC[0xc010/4]; /* Or should we show the currently locked pipes? */ + unsigned int masked_units; + + /* On 6200 cards for some reason 0xc010 can be empty while there are locked pipes, 0xc020 is then used instead. + / For now we use 0xc020 if that's the case. Note that during unlocking 0xc020 is cleared and that we then lose this locking info. + */ + if(mask == 0) + mask = nv_card->PMC[0xc020/4]; + /* For now we show units that are hw masked by default, not the currently masked units; the cli code wants to have this info + / Unfortunately bios dumping isn't possible on various mobile 6200go cards, so as a fallback use the currently masked pipes + / in favor of a segfault ;) + */ + /* What to do with NV47 which has 8 vertex units? */ + masked_units = (((mask & 0x3f0000) >> 8) | (mask >> 22)) & nv40_get_default_mask(0, 0); + + if(masked_units != 0) + { + *pmask = masked_units & 0xff; /* pixel */ + *vmask = (masked_units >> 8) & 0xff; /* vertex */ + return 1; + } + + return 0; +} + +/* Try to locate software maskes units. On success we return 1 and pmask/vmask +/ contain the masked units. When no sw masked units are found we return 0. +*/ +static int nv40_get_sw_masked_units(char *pmask, char *vmask) +{ + unsigned int mask = nv40_get_default_mask(0, 0); + unsigned int pipe_cfg; + + pipe_cfg = nv_card->PMC[0x1540/4] & nv40_get_default_mask(0, 0); + + if(!pipe_cfg) + return 0; + + /* Check if the card contains sw masked units by comparing + / the default pipe_cfg register value with the most optimal + / register value for the type of card. If they differ we have + / sw masked units. The check below first does a AND-mask to filter + / out bits which aren't needed. + */ + if((pipe_cfg & 0xffff) != mask) + { + /* First note the bits that are different + / E.g. pipe_cfg = 0x701, while mask = 0x703 + / 0x701 ^ 0x703 = 0x002 + */ + pipe_cfg = (pipe_cfg ^ mask) & mask; + *pmask = pipe_cfg & 0xff; + *vmask = (pipe_cfg >> 8) & 0xff; + return 1; + } + return 0; +} + +/* Receive the number of enabled pixel pipelines and also +/ store a mask with active pipelines. Further store the total +/ number of pixel units per pipeline in total. +*/ +static int nv40_get_pixel_pipelines(char *mask, int *total) +{ + unsigned char pipe_cfg = nv_card->PMC[0x1540/4] & 0xff; + int i, pipelines=0; + + /* The number of enabled pixel pipelines is stored in the first 4 (or more?) bits. + / In case of 6800 hardware a single bit corresponds to 4 pipelines and on NV44/NV46 + / hardware a bit corresponds to 2 pipelines + */ + for(i=0; i<8; i++) + if((pipe_cfg >> i) & 0x1) + pipelines++; + + *mask = pipe_cfg; + + /* NV44/NV46 use 2 pixel units per pipeline */ + if(nv_card->arch & (NV44 | NV46)) + *total = 2; + else + *total = 4; + + return pipelines; +} + +/* Receive the number of enabled vertex pipelines and also +/ store a mask with active pipelines. +*/ +static int nv40_get_vertex_pipelines(char *mask) +{ + unsigned char pipe_cfg = (nv_card->PMC[0x1540/4] >> 8) & 0xff; + int i, pipelines=0; + + /* The number of enabled vertex pipelines is stored in the second byte. + / A a single bit corresponds to 1 vertex pipeline. + */ + for(i=0; i<8; i++) + if((pipe_cfg >> i) & 0x1) + pipelines++; + + *mask = pipe_cfg; + + return pipelines; +} + +static void nv40_set_pixel_pipelines(unsigned char mask) +{ + int pipe_cfg = nv_card->PMC[0x1540/4]; + + /* Why do 0xc024/0xc028/0xc02c need to be reset? What do they contain? */ + nv_card->PMC[0xc020/4] = nv_card->PMC[0xc024/4] = nv_card->PMC[0xc028/4] = nv_card->PMC[0xc02c/4] = 0; + + nv_card->PMC[0x1540/4] = ~(~pipe_cfg | 0xff) | mask; +} + +static void nv40_set_vertex_pipelines(unsigned char mask) +{ + int pipe_cfg = nv_card->PMC[0x1540/4]; + + /* Why do 0xc024/0xc028/0xc02c need to be reset? What do they contain? */ + nv_card->PMC[0xc020/4] = nv_card->PMC[0xc024/4] = nv_card->PMC[0xc028/4] = nv_card->PMC[0xc02c/4] = 0; + + nv_card->PMC[0x1540/4] = ~(~pipe_cfg | 0xff00) | (mask<<8); +} + +/* Fanspeed code for Geforce6800 hardware */ +static float nv40_get_fanspeed() +{ + /* Bit 30-16 of register 0x10f0 control the voltage for the pwm signal generator + / which is connected to the fan. By changing the value in the register the duty cycle can be controlled + / so that the fan turns slower or faster. Bit 14-0 of 0x10f0 contain the pwm division + / ratio which decides the smallest fanspeed adjustment step. + / The value stored in the registers needs to be inverted, so a value of 10% means 90% and so on. + */ + int pwm_divider = nv_card->PMC[0x10f0/4] & 0x7fff; + float fanspeed = (float)(pwm_divider - ((nv_card->PMC[0x10f0/4] >> 16) & 0x7fff)) * 100.0/(float)pwm_divider; + return fanspeed; +} + +static void nv40_set_fanspeed(float speed) +{ + int value; + int pwm_divider = nv_card->PMC[0x10f0/4] & 0x7fff; + + /* For safety reasons we should never disable the fan by not putting it below 10%; further negative values don't exist ;) */ + if(speed < 0 || speed > 100) + return; + + value = 0x80000000 + ((((int)(100 - speed) * pwm_divider/100) & 0x7fff)<<16) + pwm_divider; + nv_card->PMC[0x10f0/4] = value; +} + +/* Fanspeed code for Geforce6600 hardware (does this work for 6200 cards too??)*/ +static float nv43_get_fanspeed() +{ + /* The first 12 or more bits of register 0x15f4 control the voltage for the pwm signal generator in case + / of Geforce 6200/6600(GT)/7600/7800GS hardware. By changing the value in the register the duty cycle of the pwm signal + / can be controlled so that the fan turns slower or faster. The first part of register 0x15f8 contains the pwm division ratio. + / The value stored in the registers needs to be inverted, so a value of 10% means 90% and so on. (pwm_divider means off, 0 means on) + */ + int pwm_divider = nv_card->PMC[0x15f8/4] & 0x3fff; + float fanspeed = (pwm_divider - (nv_card->PMC[0x15f4/4] & 0x3fff)) * 100.0/(float)pwm_divider; + return fanspeed; +} + +static void nv43_set_fanspeed(float speed) +{ + int value; + int pwm_divider = nv_card->PMC[0x15f8/4] & 0x3fff; + + /* For safety reasons we should never disable the fan by not putting it below 10%; further negative values don't exist ;) */ + if(speed < 0 || speed > 100) + return; + + value = 0x80000000 + (int)((100 - speed) * pwm_divider/100); + nv_card->PMC[0x15f4/4] = value; +} + +/* There's an internal temperature sensor on NV43 hardware and higher +/ Note that the sensor variable which is passed to this function is bogus +/ it is only there to share nv_card->get_gpu_temp between I2C and low-level. +*/ +static int nv43_get_gpu_temp(void *sensor) +{ + int temp; + int correction=0; + float offset = 0; + float slope = 1.0f; + + /* For now duplicate the temperature offset code here. It is needed for Mobile users in most cases the bios can't be read on those GPUs. */ + if(!nv_card->bios) + { + switch(nv_card->arch) + { + case NV43: + offset = 32060.0/1000.0; + slope = 792.0/1000.0; + break; + case NV44: + case NV47: + offset = 27839.0/1000.0; + slope = 700.0/1000.0; + break; + case NV46: /* are these really the default ones? they come from a 7300GS bios */ + offset = -24775.0/100.0; + slope = 467.0/10000.0; + break; + case NV49: /* are these really the default ones? they come from a 7900GT/GTX bioses */ + offset = -25051.0/100.0; + slope = 458.0/10000.0; + break; + case NV4B: /* are these really the default ones? they come from a 7600GT bios */ + offset = -24088.0/100.0; + slope = 442.0/10000.0; + break; + } + } + else + { + /* The output value of the sensor needs to be 'calibrated' in order to get the correct temperature. These + / values are stored in the video bios and are different for each type of gpu. The value needs to be multiplied + / with a certain 'slope' and further the sensor has an offset and another correction constant. + */ + offset = (float)nv_card->bios->sensor_cfg.diode_offset_mult / (float)nv_card->bios->sensor_cfg.diode_offset_div; + slope = (float)nv_card->bios->sensor_cfg.slope_mult / (float)nv_card->bios->sensor_cfg.slope_div; + correction = nv_card->bios->sensor_cfg.temp_correction; + } + + /* Assume that the sensor is disabled when the temperature part (without offset) is 0 */ + if((nv_card->PMC[0x15b4/4] & 0xfff) == 0) + { + /* Initialize the sensor, for now program a threshold value of 120C. + */ + int max_temp = (int)(((float)120 - offset - correction) / slope); + + /* 7300/7600/7900 cards need bit31 to be set while older cards need a different bit */ + if(nv_card->arch & (NV46 | NV49 | NV4B)) + nv_card->PMC[0x15b0/4] = 0x80000000 | max_temp; + else + nv_card->PMC[0x15b0/4] = 0x10000000 | max_temp; + IOSleep(500); + } + + /* In case of Geforce 7300/7600/7900 cards more than one byte is used for the temperature */ + if(nv_card->arch & (NV46 | NV49 | NV4B)) + temp = nv_card->PMC[0x15b4/4] & 0x1fff; + else + temp = nv_card->PMC[0x15b4/4] & 0xff; + + if(nv_card->debug) + { + printf("NV_15B4 (0x15B4): %08x\n", nv_card->PMC[0x15b4/4]); + printf("slope=%f, offset=%f, correction=%d\n", slope, offset, correction); + } + + return (int)(temp * slope + offset) + correction; +} + +/* Get current backpanel brightness level on laptops */ +static int nv44_mobile_get_smartdimmer() +{ + /* Convert level to a value between 1 and 100 */ + return 5*(((nv_card->PMC[0x15f0/4] >> 16) & 0x1f) - 1); +} + +/* Adjust backpanel brightness on laptops */ +static void nv44_mobile_set_smartdimmer(int level) +{ + if(level < 15 || level > 100) + return; + + /* Convert the level to correct Smartdimmer values; on Windows a value between 4 and 21 works fine although 0-31 should work. + / The code below creates a value between 4 and 21; + */ + level = level/5 + 1; + + /* Modify the smartdimmer part but keep the rest of the register the same */ + nv_card->PMC[0x15f0/4] = (level << 16) | (nv_card->PMC[0x15f0/4] & 0xffe0ffff); +} + +static int CalcSpeed_nv40(int base_freq, int m1, int m2, int n1, int n2, int p) +{ + return (int)((float)(n1*n2)/(m1*m2) * base_freq) >> p; +} + +float GetClock_nv40(int base_freq, unsigned int pll, unsigned int pll2) +{ + int m1, m2, n1, n2, p; + + /* mpll at 0x4020 and 0x4024; nvpll at 0x4000 and 0x4004 */ + p = (pll >> 16) & 0x03; + m1 = pll2 & 0xFF; + n1 = (pll2 >> 8) & 0xFF; + + /* Bit 8 of the first pll register can be used to disable the second set of dividers/multipliers. */ + if(pll & 0x100) + { + m2 = 1; + n2 = 1; + } + /* NV46/NV49/NV4B cards seem to use a different calculation; I'm not sure how it works yet, so for now check the architecture. Further it looks like bit 15 can be used to identify it but I'm not sure yet. + */ + else if(pll & 0x1000) + { + m2 = 1; + n2 = 1; + } + else + { + m2 = (pll2 >> 16) & 0xFF; + n2 = (pll2 >> 24) & 0xFF; + } + + if(nv_card->debug) + printf("m1=%d m2=%d n1=%d n2=%d p=%d\n", m1, m2, n1, n2, p); + + return (float)CalcSpeed_nv40(base_freq, m1, m2, n1, n2, p)/1000; +} + +const unsigned int pll_entries=2; +/* TODO: add proper architecture specific defaults */ +const struct pll pll_lst[2] = { + {0x0000, 7, 0, {3000, 25000, 100000, 405000, 1, 255, 1, 255}, {35000, 100000, 400000, 1000000, 1, 31, 1, 31}}, + {0x4020, 7, 0, {3000, 25000, 100000, 405000, 1, 255, 1, 255}, {35000, 100000, 600000, 1400000, 1, 31, 1, 31}}, +}; + +static const struct pll* GetPllLimits(unsigned int reg) +{ + int i; + if(nv_card->bios && nv_card->bios->pll_entries) + { + for(i=0; ibios->pll_entries; i++) + { + if(nv_card->bios->pll_lst[i].reg == reg) + return &nv_card->bios->pll_lst[i]; + } + /* Return the default limits */ + return &nv_card->bios->pll_lst[0]; + } + else + { + for(i=0; iVCO1.minInputFreq; + minVCOFreq = pll_limits->VCO1.minFreq; + maxVCOFreq = pll_limits->VCO1.maxFreq; + minM = pll_limits->VCO1.minM; + maxM = pll_limits->VCO1.maxM; + minN = pll_limits->VCO1.minN; + maxN = pll_limits->VCO1.maxN; + maxP = 6; + + /* The optimal frequency for the PLL to work at is somewhere in the center of its range. + / Choose a post divider in such a way to achieve this. + / The G8x nv driver does something similar but they they derive a minP and maxP. That + / doesn't seem required as you get so many matching clocks that you don't enter a second + / iteration for P. (The minP / maxP values in the nv driver only differ at most 1, so it is for + / some rare corner cases. + */ + for(P=0, VCOFreq=maxVCOFreq/2; clockIn<=VCOFreq && P <= maxP; P++) + { + VCOFreq /= 2; + } + + /* Calculate the m and n values. There are a lot of values which give the same speed; + / We choose the speed for which the difference with the request speed is as small as possible. + */ + for(M=minM; M<=maxM; M++) + { + /* The VCO has a minimum input frequency */ + if((refClk/M) < minVCOInputFreq) + break; + + for(N=minN; N<=maxN; N++) + { + /* Calculate the frequency generated by VCO1 */ + clock = (int)(refClk * N / (float)M); + + /* Verify if the clock lies within the output limits of VCO1 */ + if(clock < minVCOFreq) + continue; + else if (clock > maxVCOFreq) /* It is no use to continue as the clock will only become higher */ + break; + + clock >>= P; + delta = abs0((int)(clockIn - clock)); + /* When the difference is 0 or less than .5% accept the speed */ + if(((delta == 0) || ((float)delta/(float)clockIn <= 0.005))) + { + *bestM = M; + *bestN = N; + *bestP = P; + return; + } + + /* When the new difference is smaller than the old one, use this one */ + if(delta < bestDelta) + { + bestDelta = delta; + *bestM = M; + *bestN = N; + *bestP = P; + } + } + } +} + +static void ClockSelectDoubleVCO_nv40(int clockIn, const struct pll *pll_limits, int *bestM, int *bestM2, int *bestN, int *bestN2, int *bestP) +{ + int clock1, clock2, M, M2, N, N2, P; + int delta, bestDelta, minM, minM2, maxM, maxM2, minN, minN2, maxN, maxN2, maxP; + int minVCOInputFreq, minVCO2InputFreq, maxVCO2InputFreq, minVCOFreq, minVCO2Freq, maxVCOFreq, maxVCO2Freq; + int maxClock, VCO2Freq; + int refClk = 27000; + bestDelta = clockIn; + *bestM=*bestM2=*bestN=*bestN2=*bestP=0; + + minVCOInputFreq = pll_limits->VCO1.minInputFreq; + minVCOFreq = pll_limits->VCO1.minFreq; + maxVCOFreq = pll_limits->VCO1.maxFreq; + minM = pll_limits->VCO1.minM; + maxM = pll_limits->VCO1.maxM; + minN = pll_limits->VCO1.minN; + maxN = pll_limits->VCO1.maxN; + + minVCO2InputFreq = pll_limits->VCO2.minInputFreq; + maxVCO2InputFreq = pll_limits->VCO2.maxInputFreq; + minVCO2Freq = pll_limits->VCO2.minFreq; + maxVCO2Freq = pll_limits->VCO2.maxFreq; + minM2 = pll_limits->VCO2.minM; + maxM2 = pll_limits->VCO2.maxM; + minN2 = pll_limits->VCO2.minN; + maxN2 = pll_limits->VCO2.maxN; + maxP = 6; /* This should be somewhere in the bios too */ + + maxClock = maxVCO2Freq; + /* If the requested clock is behind the bios limits, try it anyway */ + if(clockIn > maxVCO2Freq) + maxClock = clockIn + clockIn/200; /* Add a .5% margin */ + + /* The optimal frequency for the PLL to work at is somewhere in the center of its range. + / Choose a post divider in such a way to achieve this. + / The G8x nv driver does something similar but they they derive a minP and maxP. That + / doesn't seem required as you get so many matching clocks that you don't enter a second + / iteration for P. (The minP / maxP values in the nv driver only differ at most 1, so it is for + / some rare corner cases. + */ + for(P=0, VCO2Freq=maxClock/2; clockIn<=VCO2Freq && P <= maxP; P++) + { + VCO2Freq /= 2; + } + + /* The PLLs on Geforce6/7 hardware can operate in a single stage made with only 1 VCO + / and a cascade mode of two VCOs. This second mode is in general used for relatively high + / frequencies. The loop below calculates the divider and multiplier ratios for the cascade + / mode. The code takes into account limits defined in the video bios. + */ + for(M=minM; M<=maxM; M++) + { + /* The VCO has a minimum input frequency */ + if((refClk/M) < minVCOInputFreq) + break; + + for(N=minN; N<=maxN; N++) + { + /* Calculate the frequency generated by VCO1 */ + clock1 = (int)(refClk * N / (float)M); + /* Verify if the clock lies within the output limits of VCO1 */ + if( (clock1 < minVCOFreq) ) + continue; + else if(clock1 > maxVCOFreq) /* For future N, the clock will only increase so stop; xorg nv continues but that is useless */ + break; + + for(M2=minM2; M2<=maxM2; M2++) + { + /* The clock fed to the second VCO needs to lie within a certain input range */ + if(clock1 / M2 < minVCO2InputFreq) + break; + else if(clock1 / M2 > maxVCO2InputFreq) + continue; + + N2 = (int)((float)((clockIn << P) * M * M2) / (float)(refClk * N)+.5); + if( (N2 < minN2) || (N2 > maxN2) ) + continue; + + /* The clock before being fed to the post-divider needs to lie within a certain range. + / Further there are some limits on N2/M2. + */ + clock2 = (int)((float)(N*N2)/(M*M2) * refClk); + if( (clock2 < minVCO2Freq) || (clock2 > maxClock))// || ((N2 / M2) < 4) || ((N2 / M2) > 10) ) + continue; + + /* The post-divider delays the 'high' clock to create a low clock if requested. + / This post-divider exists because the VCOs can only generate frequencies within + / a limited frequency range. This range has been tuned to lie around half of its max + / input frequency. It tries to calculate all clocks (including lower ones) around this + / 'center' frequency. + */ + clock2 >>= P; + delta = abs0((int)(clockIn - clock2)); + + /* When the difference is 0 or less than .5% accept the speed */ + if(((delta == 0) || ((float)delta/(float)clockIn <= 0.005))) + { + *bestM = M; + *bestM2 = M2; + *bestN = N; + *bestN2 = N2; + *bestP = P; + return; + } + + /* When the new difference is smaller than the old one, use this one */ + if(delta < bestDelta) + { + bestDelta = delta; + *bestM = M; + *bestM2 = M2; + *bestN = N; + *bestN2 = N2; + *bestP = P; + } + } + } + } +} + +static void ClockSelect_nv40(int clockIn, unsigned int reg, unsigned int *pllOut, unsigned int *pllBOut) +{ + int PLL=0, PLL2=0; + int bestM=0, bestM2=1, bestN=0, bestN2=1, bestP=0; + const struct pll *pll_limits = GetPllLimits(reg); + //int pllIn = nv_card->PMC[reg/4]; + + printf("Warning using experimental NV4x lowlevel clock adjustment, if you encounter strange issues, issue a bugreport.\n"); + + /* Use a single VCO if the clock isn't high enough to require a second. + / This is what apparently the Nvidia drivers are doing. For instance on my 7600GS + / the max frequency for the first VCO in case of the GPU clock is 300MHz. Indeed below + / 300MHz it moves to a single VCO. + / We could likely also check if the limits of the second divider and multiplier are 1. */ + if(clockIn < pll_limits->VCO1.maxFreq) + { + ClockSelectSingleVCO_nv40(clockIn, pll_limits, &bestM, &bestN, &bestP); + + /* Bit31 enables the first VCO */ + PLL = 0x80000000; + + /* Select only a single VCO; bit12 is apparently used when there is a single VCO (G7x) + / while bit8 is used when there are two VCOs, so it is apparently some disable bit. + / + / On some cards at least on G7x ones, a single VCO is used for the memory + / In this case the min and max reference dividers (M) are equal. + */ + if(pll_limits->VCO2.minM == pll_limits->VCO2.maxM) + PLL |= 0x1000; + else + PLL |= 0x100; + + /* Set the reference divider (M) and the feedback divider (N) */ + PLL2 = (bestN<<8) | bestM; + } + else + { + ClockSelectDoubleVCO_nv40(clockIn, pll_limits, &bestM, &bestM2, &bestN, &bestN2, &bestP); + + /* Bit31 enables the first VCO, bit30 the second */ + PLL = 0xc0000000; + /* Set the reference dividers (M, M2) and the feedback dividers (N, N2) */ + PLL2 = (bestN2<<24) | (bestM2<<16) | (bestN<<8) | bestM; + } + + /* Set the post divider */ + PLL |= (bestP<<16); + + if(reg == 0x4020) /* MPLL */ + { + unsigned int default_pll = nv_card->bios ? nv_card->bios->mpll : 0; + + /* This data comes from the init script tables of bios of the respective cards */ + if(!default_pll) + { + switch(nv_card->arch) + { + case NV40: + case NV41: /* I'm not sure if this is correct */ + case NV43: + case NV44: + default_pll = 0x2000001c; + break; + case NV46: + default_pll = 0x20000000; + break; + case NV47: + default_pll = 0x2400001c; + break; + case NV49: + case NV4B: + default_pll = 0x24800000; + break; + default: + printf("Unknown default pll for %#x\n", nv_card->arch); + } + } + + /* According to a vbtracetool log, this is done. Why a second post divider for the MPLL? */ + PLL |= (bestP + pll_limits->var1e) << 20; + /* Or with the 'empty' PLL but make sure that it doesn't adjust the post dividers or the enable bits */ + PLL |= (default_pll & 0x3f88ffff); + } + else /* NVPLL */ + { + unsigned int default_pll = nv_card->bios ? nv_card->bios->nvpll : 0; + if(!default_pll) + { + switch(nv_card->arch) + { + case NV40: + case NV41: /* I'm not sure if this is correct */ + case NV43: + default_pll = 0x0000001c; + break; + case NV44: + default_pll = 0xc000001c; + break; + case NV46: + default_pll = 0xc0000000; + break; + case NV47: + default_pll = 0x0001001f; + break; + case NV49: + case NV4B: + default_pll = 0x00010000; + break; + case C51: + default: + printf("Unknown default pll for %#x\n", nv_card->arch); + default_pll = 0xc0000000; /* this should only get reached for C51 */ + } + } + + /* Or with the 'empty' PLL but make sure that it doesn't adjust the post dividers or the enable bits */ + PLL |= (default_pll & 0x3f88ffff); + } + + /* TODO: at some stage we should perhaps also play nice with 0xc040. + / Before programming a PLL, we should disable it in there. Then + / we should put the PLL in program mode (?) by setting bit28. After that + / we should program the PLLs (first the dividers/multipliers and then the config), + / then re-enable the PLL in 0xc040 and then unset bit28 of the pll config register. + / At least this is what happens in a vbtracetool log. + */ + *pllOut = PLL; + *pllBOut = PLL2; + + if(nv_card->debug) + { + printf("register=%#x, clockIn=%d, calculated=%d\n", reg, clockIn, CalcSpeed_nv40(27000, bestM, bestM2, bestN, bestN2, bestP)); + printf("PLL=%#08x, PLL2=%08x\n", *pllOut, *pllBOut); + } +} + +static float nv40_get_gpu_speed() +{ + int pll = nv_card->PMC[0x4000/4]; + int pll2 = nv_card->PMC[0x4004/4]; + if(nv_card->debug == 1) + { + printf("NVPLL_COEFF=%08x\n", pll); + printf("NVPLL2_COEFF=%08x\n", pll2); + } + + return (float)GetClock_nv40(nv_card->base_freq, pll, pll2); +} + +static void nv40_set_gpu_speed(unsigned int nvclk) +{ + unsigned int PLL=0, PLL2=0; + nvclk *= 1000; + + ClockSelect_nv40(nvclk, 0x4000, &PLL, &PLL2); + + /* When no speed is found, don't change the PLL */ + /* The algorithm doesn't allow too low speeds */ + if(PLL) + { + if(nv_card->debug) + { + printf("NVPLL_COEFF: %08x\n", PLL); + printf("NVPLL2_COEFF: %08x\n", PLL2); + } + + nv_card->PMC[0x4000/4] = PLL; + nv_card->PMC[0x4004/4] = PLL2; + } +} + +static float nv40_get_memory_speed() +{ + int pll = nv_card->PMC[0x4020/4]; + int pll2 = nv_card->PMC[0x4024/4]; + if(nv_card->debug == 1) + { + printf("MPLL_COEFF=%08x\n", pll); + printf("MPLL2_COEFF=%08x\n", pll2); + } + + return (float)GetClock_nv40(nv_card->base_freq, pll, pll2); +} + +static void nv40_set_memory_speed(unsigned int memclk) +{ + unsigned int PLL=0, PLL2=0; + memclk *= 1000; + + ClockSelect_nv40(memclk, 0x4020, &PLL, &PLL2); + + /* When no speed is found, don't change the PLL */ + /* The algorithm doesn't allow too low speeds */ + if(PLL) + { + if(nv_card->debug) + { + printf("MPLL_COEFF: %08x\n", PLL); + printf("MPLL2_COEFF: %08x\n", PLL2); + } + + /* It seems that different NV4X GPUs contain multiple memory clocks. + / A 6800 card has 4 of them, a 6600GT 2 of them and a NV44 (6200) 1. + / Very likely this is related to the width of the memory bus, which + / is 256bit on the 6800, 128bit on the 6600GT (NV43) and 64bit on the NV44. + / + / The code below handles the setting of the extra clockspeeds. + */ + switch(nv_card->arch) + { + case NV40: + case NV41: + case NV47: + nv_card->PMC[0x402c/4] = PLL; + nv_card->PMC[0x4030/4] = PLL2; + nv_card->PMC[0x4044/4] = PLL; + nv_card->PMC[0x4048/4] = PLL2; + case NV43: + case NV49: + case NV4B: + nv_card->PMC[0x4038/4] = PLL; + nv_card->PMC[0x403c/4] = PLL2; + case NV44: + case NV46: + nv_card->PMC[0x4020/4] = PLL; + nv_card->PMC[0x4024/4] = PLL2; + } + } +} + +static void nv40_reset_gpu_speed() +{ + /* Set the gpu speed */ + nv_card->PMC[0x4000/4] = nv_card->nvpll; + nv_card->PMC[0x4004/4] = nv_card->nvpll2; +} + +static void nv40_reset_memory_speed() +{ + /* Set the memory speed */ + nv_card->PMC[0x4024/4] = nv_card->mpll2; + + switch(nv_card->arch) + { + case NV40: + case NV41: + case NV47: + nv_card->PMC[0x402c/4] = nv_card->mpll; + nv_card->PMC[0x4030/4] = nv_card->mpll2; + nv_card->PMC[0x4044/4] = nv_card->mpll; + nv_card->PMC[0x4048/4] = nv_card->mpll2; + case NV43: + case NV49: + case NV4B: + nv_card->PMC[0x4038/4] = nv_card->mpll; + nv_card->PMC[0x403c/4] = nv_card->mpll2; + case NV44: + case NV46: + nv_card->PMC[0x4020/4] = nv_card->mpll; + nv_card->PMC[0x4024/4] = nv_card->mpll2; + } +} + +static void nv40_set_state(int state) +{ + { + nv_card->state = STATE_LOWLEVEL; + nv_card->get_gpu_speed = nv40_get_gpu_speed; + nv_card->get_memory_speed = nv40_get_memory_speed; + nv_card->set_memory_speed = nv40_set_memory_speed; + nv_card->set_gpu_speed = nv40_set_gpu_speed; + nv_card->reset_gpu_speed = nv40_reset_gpu_speed; + nv_card->reset_memory_speed = nv40_reset_memory_speed; + } +} + +void nv40_init(void) +{ + nv_card->base_freq = 27000; + + nv_card->set_state = nv40_set_state; + nv_card->set_state(STATE_LOWLEVEL); /* Set the clock function pointers */ + + nv_card->get_default_mask = nv40_get_default_mask; + nv_card->get_hw_masked_units = nv40_get_hw_masked_units; + nv_card->get_sw_masked_units = nv40_get_sw_masked_units; + nv_card->get_pixel_pipelines = nv40_get_pixel_pipelines; + nv_card->get_vertex_pipelines = nv40_get_vertex_pipelines; + + /* Register I2C busses for hardware monitoring purposes */ + if(nv_card->busses[0] == NULL) + { + nv_card->num_busses = 3; + nv_card->busses[0] = NV_I2CCreateBusPtr(STRDUP("BUS0", sizeof("BUS0")), 0x3e); /* available on riva128 and higher */ + nv_card->busses[1] = NV_I2CCreateBusPtr(STRDUP("BUS1", sizeof("BUS1")), 0x36); /* available on rivatnt hardware and higher */ + nv_card->busses[2] = NV_I2CCreateBusPtr(STRDUP("BUS2", sizeof("BUS2")), 0x50); /* available on geforce4mx/4ti/fx/6/7 */ + + i2c_sensor_init(); + } + + /* For now enable modding on NV40 cards and NV43 revisions prior to A4; other cards are locked */ + if((nv_card->arch & NV40) || ((nv_card->arch & NV43) && (nv_card->get_gpu_revision() < 0xA4))) + { + nv_card->caps |= PIPELINE_MODDING; + nv_card->set_pixel_pipelines = nv40_set_pixel_pipelines; + nv_card->set_vertex_pipelines = nv40_set_vertex_pipelines; + } + + /* If the smartdimmer register contains a value (default 21) then smartdimmer is supported on the laptop; This should work on various 6200Go/7600Go cards */ + if((nv_card->PMC[0x15f0/4] & 0xff) && nv_card->gpu == MOBILE) + { + nv_card->caps |= SMARTDIMMER; + nv_card->get_smartdimmer = nv44_mobile_get_smartdimmer; + nv_card->set_smartdimmer = nv44_mobile_set_smartdimmer; + } + + /* Temperature monitoring; all cards after the NV40 feature an internal temperature sensor. + / Only it is disabled on most 6200/6600(GT) cards but we can re-enable it ;) + */ + if((nv_card->arch & (NV43 | NV44 | NV46 | NV47 | NV49 | NV4B)) && !(nv_card->caps & GPU_TEMP_MONITORING)) + { + nv_card->caps |= GPU_TEMP_MONITORING; + nv_card->sensor_name = (char*)STRDUP("GPU Internal Sensor", sizeof("GPU Internal Sensor")); + nv_card->get_gpu_temp = (int(*)(I2CDevPtr))nv43_get_gpu_temp; + } + + /* Fanspeed monitoring; bit 31 is an indication if fanspeed monitoring is available + / Note this bit isn't very reliable as it is set on cards with advanced sensors too. + / Should the NV44 use the NV43 codepath? + */ + if(((nv_card->arch & (NV40 | NV49)) && (nv_card->PMC[0x10f0/4] & 0x80000000)) && !(nv_card->caps & I2C_FANSPEED_MONITORING)) + { + nv_card->caps |= GPU_FANSPEED_MONITORING; + nv_card->get_fanspeed = nv40_get_fanspeed; + nv_card->set_fanspeed = nv40_set_fanspeed; + } + else if(((nv_card->arch & (NV41 | NV43 | NV44 | NV47 | NV4B)) && (nv_card->PMC[0x15f4/4] & 0x80000000)) && !(nv_card->caps & I2C_FANSPEED_MONITORING)) + { + nv_card->caps |= GPU_FANSPEED_MONITORING; + nv_card->get_fanspeed = nv43_get_fanspeed; + nv_card->set_fanspeed = nv43_set_fanspeed; + } + + /* Mobile GPU check; we don't want to overclock those unless the user wants it */ + if(nv_card->gpu == MOBILE) + { + nv_card->caps = ~(~nv_card->caps | GPU_OVERCLOCKING | MEM_OVERCLOCKING); + } + else + nv_card->caps |= (GPU_OVERCLOCKING | MEM_OVERCLOCKING); + + /* Set the speed range */ + if(nv_card->bios) + { + /* Most Geforce6 bioses just have one active entry but some Geforce6 6800(Ultra) bioses have 2 entries + / in that case the first one contains the highest clocks (3d?). Further there are 6600GT cards with + / also two entries for which the second entry contains the 3d clock. + */ + if((nv_card->bios->perf_entries == 1) || (nv_card->bios->perf_lst[0].nvclk > nv_card->bios->perf_lst[1].nvclk)) + { + nv_card->memclk_3d = (short)nv_card->bios->perf_lst[0].memclk; + nv_card->nvclk_3d = (short)nv_card->bios->perf_lst[0].nvclk; + } + else + { + /* 6600GT cards have 2d/3d clocks again; the second entries are the 3d ones. + / We use the 2d entries for the minimum clocks and the 3d ones for the maximum ones. + */ + nv_card->memclk_3d = (short)nv_card->bios->perf_lst[1].memclk; + nv_card->nvclk_3d = (short)nv_card->bios->perf_lst[1].nvclk; + } + nv_card->memclk_min = (short)(nv_card->bios->perf_lst[0].memclk * .75); + nv_card->memclk_max = nv_card->memclk_3d * 1.25; + nv_card->nvclk_min = (short)(nv_card->bios->perf_lst[0].nvclk * .75); + nv_card->nvclk_max = nv_card->nvclk_3d * 1.25; + + /* FIXME: Divide the memory clocks by two on Geforc7600/7900 cards because we program the 'real' clocks for those instead of the effective DDR ones which are twice as high */ + if(nv_card->arch & (NV46 | NV49 | NV4B)) + { + nv_card->memclk_min /= 2; + nv_card->memclk_max /= 2; + } + } + else + { + float memclk = GetClock_nv40(nv_card->base_freq, nv_card->mpll, nv_card->mpll2); + float nvclk = GetClock_nv40(nv_card->base_freq, nv_card->nvpll, nv_card->nvpll2); + + /* Not great but better than nothing .. */ + nv_card->memclk_min = (short)(memclk * .75); + nv_card->memclk_max = (short)(memclk * 1.5); + nv_card->nvclk_min = (short)(nvclk * .75); + nv_card->nvclk_max = (short)(nvclk * 1.5); + } +} diff --git a/plugins/GPUSensors/NVClockX/NVClock/nv50.cpp b/plugins/GPUSensors/NVClockX/NVClock/nv50.cpp new file mode 100644 index 0000000..d16afb8 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/nv50.cpp @@ -0,0 +1,493 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2007 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +//#include +//#include +#include "backend.h" +#include "nouveau_therm.h" + + +static void nv50_i2c_get_bits(I2CBusPtr bus, int *clock, int *data) +{ + long offset = bus->DriverPrivate.val; + unsigned char val; + + val = nv_card->PMC[(0x0000E138 + offset)/4]; + *clock = !!(val & 1); + *data = !!(val & 2); +} + +static void nv50_i2c_put_bits(I2CBusPtr bus, int clock, int data) +{ + long offset = bus->DriverPrivate.val; + nv_card->PMC[(0x0000E138 + offset)/4] = 4 | clock | data << 1; +} + +static I2CBusPtr nv50_i2c_create_bus_ptr(char *name, int bus) +{ + I2CBusPtr I2CPtr; + + I2CPtr = xf86CreateI2CBusRec(); + if(!I2CPtr) return NULL; + + I2CPtr->BusName = name; + I2CPtr->scrnIndex = nv_card->number; /* We need to use unique indices or else it can lead to a segfault in multicard situations */ + I2CPtr->I2CAddress = I2CAddress; + I2CPtr->I2CPutBits = nv50_i2c_put_bits; + I2CPtr->I2CGetBits = nv50_i2c_get_bits; + I2CPtr->AcknTimeout = 40; + I2CPtr->DriverPrivate.val = bus; + + if (!xf86I2CBusInit(I2CPtr)) + { + return 0; + } + return I2CPtr; +} + +static int nv50_get_default_mask(char *smask, char *rmask) +{ + int mask = 0; + switch(nv_card->arch) + { + case NV50: + mask = 0x3f00ff; + break; + case G84: + mask = 0x030003; + break; + case G86: + mask = 0x010001; + break; + case G92: + mask = 0x0f00ff; + break; + case G94: + mask = 0x0f000f; + break; + case GT200: + case GF100: + mask = 0xff03ff; + break; + } + + if(smask) + *smask = mask & 0x3ff; + if(rmask) + *rmask = (mask >> 16) & 0xff; + + return mask; +} + +/* Receive the number of enabled stream processors and also +/ store a mask with active pipelines. +*/ +static int nv50_get_stream_units(char *mask, char *default_mask) +{ + int i, stream_units=0; + int32_t stream_units_cfg = nv_card->PMC[0x1540/4] & 0x3ff; + /* The number of shaders is again stored in 0x1540 + bit9-0: number of unified pixel shaders in blocks of 16 + bit23-16: number of ROP units in blocks of 4 + bit31-24: what's in here? + */ + + for(i=0; i<10; i++) + if((stream_units_cfg >> i) & 0x1) + stream_units++; + + nv50_get_default_mask(default_mask, 0); + + *mask = stream_units_cfg; + + if(nv_card->arch == GT200) { + return (stream_units * 24); /* GT200 stores stream units in blocks of 24 */ + } + else if(nv_card->arch == GF100) { + if((nv_card->device_id & 0xffe0) == 0x06C0 || + (nv_card->device_id & 0xffe0) == 0x1080) { + return (stream_units * 32); // blocks of 32 on GF100 and GF110 + } + else return (stream_units * 48); // blocks of 48 on all others + } + + return (stream_units << 4); /* stream units are stored in blocks of 16 */ +} + +/* Receive the number of enabled ROP units and also +/ store a mask with active units. +*/ +static int nv50_get_rop_units(char *mask, char *default_mask) +{ + int i, rop_units=0; + unsigned char rop_units_cfg = (nv_card->PMC[0x1540/4] >> 16) & 0xff; + + for(i=0; i<8; i++) + if((rop_units_cfg >> i) & 0x1) + rop_units++; + + nv50_get_default_mask(0, default_mask); + + *mask = rop_units_cfg; + return (rop_units << 2); /* rop units are stored in blocks of 4 */ +} + +static float g84_get_fanspeed() +{ + int pwm_divider = nv_card->PMC[0xe11c/4] & 0x7fff; + + /* On most Geforce8/9 cards I have seen the fanspeed register is 'inverted', so + / a low value corresponds with fullspeed (to be exact the register defines the low + / period of a pwm pulse. Though some boards aren't inverted like a 8500GT (G86). I'm + / not sure what we should do about this. If it is possible to whitelist some generations + / or so we should perhaps do that or perhaps there is some setting in the bios? So right + / now 100% would show 0% on a 8500GT. + / + / Further some boards use 0xe114 / 0xe118 instead of 0xe11c / 0xe1220. At least the 9800GTX + / seems to do that. When I have a more clear picture of the situation those should receive support too. + */ + float fanspeed = (float)(pwm_divider - (nv_card->PMC[0xe120/4] & 0x7fff)) * 100.0/(float)pwm_divider; + return fanspeed; +} + +static void g84_set_fanspeed(float speed) +{ + int value; + int pwm_divider = nv_card->PMC[0xe11c/4] & 0x7fff; + + /* For safety reasons we should never disable the fan by not putting it below 10%; further negative values don't exist ;) */ + if(speed < 0 || speed > 100) + return; + + /* Bit31 must be set else the hardware doesn't seem to do anything with the changes + / Bit30-16 contain some magical bits on 9500GT and other cards which we should preserve. + / On a 9500gt the contents of 0xe120 could be e.g. 0x0300010e with a pwm_divider of 0x21d. + / + / Note Oxe300 is also related to the fanspeed. By default it seems to contain 0x100 on + / 9600GT and other cards. Setting this value to 0x300 seems to set the fanspeed to a fixed + / value. Apparently 0xe300 acts like a multiplexer? + */ + value = 0x80000000 | (nv_card->PMC[0xe120/4] & 0x7fff0000) | (((int)(100 - speed) * pwm_divider/100) & 0x7fff); + nv_card->PMC[0xe120/4] = value; +} + +/* Reading of the internal gpu sensor, it not entirely correct yet */ +static int nv50_get_gpu_temp(void *sensor) +{ + int temp; + int correction=0; + float offset; + float slope; + + /* For now use a hardcoded offset and gain. This isn't correct but I don't know how the new temperture table works yet; this at least gives something */ + offset = -227.0; + slope = 430.0/10000.0; + + if(nv_card->debug) + { + printf("NV_20008 (0x20008): %08x\n", nv_card->PMC[0x20008/4]); + printf("slope=%f, offset=%f, correction=%d\n", slope, offset, correction); + } + + temp = nv_card->PMC[0x20008/4] & 0x1fff; + return (int)(temp * slope + offset) + correction; +} + +static int g84_get_gpu_temp(void *sensor) +{ + if(nv_card->debug) + { + /* A calibrated value of the temperature is stored in 0x20400, raw in 0x20008 it would require bios info to calibrate it */ + printf("NV_20008 (0x20008): %08x\n", nv_card->PMC[0x20008/4]); + printf("NV_20400 (0x20400): %08x\n", nv_card->PMC[0x20400/4]); + } + + /* A calibrated value of the temperature is stored in 0x20400 */ + return nv_card->PMC[0x20400/4]; +} + +static int g92_get_gpu_temp(void *sensor) +{ + int temp; + float offset; + float divider; + + /* According to a formula on the rivatuner forum Asus uses the following formula: (-13115 + raw_temp)/18.7 + 1. */ + offset = -13115 + 18.7; + divider = 18.7; + + if(nv_card->debug) + { + printf("NV_20008 (0x20008): %08x\n", nv_card->PMC[0x20008/4]); + printf("divider=%f, offset=%f\n", divider, offset); + } + + temp = nv_card->PMC[0x20008/4] & 0x1fff; + return (int)(temp + offset)/divider; +} + + +/* Get current backpanel brightness level on laptops */ +static int nv50_mobile_get_smartdimmer() +{ + int val = nv_card->PDISPLAY[NV_PDISPLAY_SOR0_REGS_BRIGHTNESS/4]; + /* Convert level to a value between 1 and 100 */ + /* For now assume the maximum value is 1024 */ + return ((val / 1024.0 * 100) + 0.5); +} + +/* Adjust backpanel brightness on laptops */ +static void nv50_mobile_set_smartdimmer(int level) +{ + int val; + if(level < 15 || level > 100) + return; + val = (level * 1024 / 100) | NV_PDIPSLAY_SOR0_REGS_BRIGHTNESS_CONTROL_ENABLED; + nv_card->PDISPLAY[NV_PDISPLAY_SOR0_REGS_BRIGHTNESS/4] = val; +} + +static int CalcSpeed_nv50(int base_freq, int m1, int m2, int n1, int n2, int p) +{ + return (int)((float)(n1*n2)/(m1*m2) * base_freq) >> p; +} + +float GetClock_nv50(int base_freq, unsigned int pll, unsigned int pll2) +{ + int m1, m2, n1, n2, p; + + p = (pll >> 16) & 0x03; + m1 = pll2 & 0xFF; + n1 = (pll2 >> 8) & 0xFF; + + /* This is always 1 for NV5x? */ + m2 = 1; + n2 = 1; + + if(nv_card->debug) + printf("m1=%d m2=%d n1=%d n2=%d p=%d\n", m1, m2, n1, n2, p); + + /* The clocks need to be multiplied by 4 for some reason. Is this 4 stored in 0x4000/0x4004? */ + return (float)4*CalcSpeed_nv50(base_freq, m1, m2, n1, n2, p)/1000; +} + +static float nv50_get_gpu_speed() +{ + int pll = nv_card->PMC[0x4028/4]; + int pll2 = nv_card->PMC[0x402c/4]; + if(nv_card->debug == 1) + { + printf("NVPLL_COEFF=%08x\n", pll); + printf("NVPLL2_COEFF=%08x\n", pll2); + } + + return (float)GetClock_nv50(nv_card->base_freq, pll, pll2); +} + +static void nv50_set_gpu_speed(unsigned int nvclk) +{ +} + +static float nv50_get_memory_speed() +{ + /* The memory clock appears to be in 0x4008/0x400c, 0x4010/0x4014 and 0x4018/0x401c but the second and third set aren't always set to the same values as 0x4008/0x400c */ + int pll = nv_card->PMC[0x4008/4]; + int pll2 = nv_card->PMC[0x400c/4]; + if(nv_card->debug == 1) + { + printf("MPLL_COEFF=%08x\n", pll); + printf("MPLL2_COEFF=%08x\n", pll2); + } + + return (float)GetClock_nv50(nv_card->base_freq, pll, pll2); +} + +static void nv50_set_memory_speed(unsigned int memclk) +{ +} + +static float nv50_get_shader_speed() +{ + int pll = nv_card->PMC[0x4020/4]; + int pll2 = nv_card->PMC[0x4024/4]; + if(nv_card->debug == 1) + { + printf("SPLL_COEFF=%08x\n", pll); + printf("SPLL2_COEFF=%08x\n", pll2); + } + + return (float)GetClock_nv50(nv_card->base_freq, pll, pll2); +} + +static void nv50_set_shader_speed(unsigned int clk) +{ +} + +static void nv50_reset_gpu_speed() +{ +} + +static void nv50_reset_memory_speed() +{ +} + +static void nv50_reset_shader_speed() +{ +} + +static void nv50_set_state(int state) +{ +#ifdef HAVE_NVCONTROL + if(state & (STATE_2D | STATE_3D)) + { + nv_card->state = state; + nv_card->get_gpu_speed = nvcontrol_get_gpu_speed; + nv_card->get_memory_speed = nvcontrol_get_memory_speed; + nv_card->set_gpu_speed = nvcontrol_set_gpu_speed; + nv_card->set_memory_speed = nvcontrol_set_memory_speed; + nv_card->reset_gpu_speed = nvcontrol_reset_gpu_speed; + nv_card->reset_memory_speed = nvcontrol_reset_memory_speed; + } + else +#endif + { + nv_card->state = STATE_LOWLEVEL; + nv_card->get_gpu_speed = nv50_get_gpu_speed; + nv_card->get_memory_speed = nv50_get_memory_speed; + nv_card->set_memory_speed = nv50_set_memory_speed; + nv_card->set_gpu_speed = nv50_set_gpu_speed; + nv_card->reset_gpu_speed = nv50_reset_gpu_speed; + nv_card->reset_memory_speed = nv50_reset_memory_speed; + } + nv_card->get_shader_speed = nv50_get_shader_speed; + nv_card->set_shader_speed = nv50_set_shader_speed; + nv_card->reset_shader_speed = nv50_reset_shader_speed; +} + +void nv50_init(void) +{ + nv_card->base_freq = 27000; + + nv_card->set_state = nv50_set_state; + nv_card->set_state(STATE_LOWLEVEL); /* Set the clock function pointers */ + + nv_card->get_stream_units = nv50_get_stream_units; + nv_card->get_rop_units = nv50_get_rop_units; + + /* Initialize the NV50 I2C busses; compared to older hardware they are located at different register addresses */ + if(nv_card->busses[0] == NULL) + { + nv_card->num_busses = 4; + nv_card->busses[0] = nv50_i2c_create_bus_ptr(STRDUP("BUS0", sizeof("BUS0")), 0x0); + nv_card->busses[1] = nv50_i2c_create_bus_ptr(STRDUP("BUS1", sizeof("BUS1")), 0x18); + nv_card->busses[2] = nv50_i2c_create_bus_ptr(STRDUP("BUS2", sizeof("BUS2")), 0x30); + nv_card->busses[3] = nv50_i2c_create_bus_ptr(STRDUP("BUS3", sizeof("BUS3")), 0x48); + + i2c_sensor_init(); + } + + /* For now unlock laptops of HP, Samsung (Sanyo), Sony and Zepto. Later on we whould find a better way if there is any. + / Most likely there is some info in the bios which can help us figuring out what smartdimmer method is used. + / The code has been reported to work on the following models: + / - Apple Macbook5,1 (Aluminium), Geforce 9400M, dev=0x863, subvendor=0x106b + / - HP Compaq 8510W, QuadroFX 570M, dev=0x40c, subvendor=0x103c + / - HP Compaq 8710P, QuadroFX 320M, dev=0x40b, subvendor=0x103c + / - Samsung Q210 / Q310 / R510, Geforce 9200M, dev=0x6e8, subvendor=0x144d + / - Sony Vaio models using 8400/8600 GPUs: + / VGN SZ650N, SZ61MN/B, SZ730E, SZ750N, SZ71MN/B, SZ71E, VGN FZ38M, FZ31M, FZ11Z, NR31, AR41E, FZ11S, FZ290, FZ250AE, + / FZ21E, FZ21M, FZ470E, FZ340E, FZ190N, FZ18M, FZ31E, FZ18E, FZ31Z, FZ21Z, FZ31S, AR51SU, AR71S + / - Zepto (unknown model), Geforce 9600M, dev=0x649, subvendor=0x1a46, + */ + if((nv_card->gpu == MOBILE) && + ((nv_card->subvendor_id == PCI_VENDOR_ID_APPLE) || + (nv_card->subvendor_id == PCI_VENDOR_ID_HP) || + (nv_card->subvendor_id == PCI_VENDOR_ID_SANYO) || + (nv_card->subvendor_id == PCI_VENDOR_ID_SONY) || + (nv_card->subvendor_id == PCI_VENDOR_ID_ZEPTO))) + { + nv_card->caps |= SMARTDIMMER; + nv_card->get_smartdimmer = nv50_mobile_get_smartdimmer; + nv_card->set_smartdimmer = nv50_mobile_set_smartdimmer; + } + + /* Temperature monitoring; all NV50 cards feature an internal temperature sensor + / but only use it when there is no I2C sensor around. + */ + if((nv_card->arch & NV50) && !(nv_card->caps & GPU_TEMP_MONITORING)) + { + nv_card->caps |= GPU_TEMP_MONITORING; + nv_card->sensor_name = (char*)STRDUP("GPU Internal Sensor", sizeof("GPU Internal Sensor")); + nv_card->get_gpu_temp = (int(*)(I2CDevPtr))nv50_get_gpu_temp; + } + else if((nv_card->arch & (G84 | G86 | G94 | G96 | GT200 | GF100)) && !(nv_card->caps & GPU_TEMP_MONITORING)) + { + nv_card->caps |= GPU_TEMP_MONITORING; + nv_card->sensor_name = (char*)STRDUP("GPU Internal Sensor", sizeof("GPU Internal Sensor")); + nv_card->get_gpu_temp = (int(*)(I2CDevPtr))g84_get_gpu_temp; + } + else if((nv_card->arch & G92) && !(nv_card->caps & GPU_TEMP_MONITORING)) + { + /* Nearly all G92 boards use a ADT7473 except some Asus models. They don't use the bios data properly, so give it its own function */ + nv_card->caps |= GPU_TEMP_MONITORING; + nv_card->sensor_name = (char*)STRDUP("GPU Internal Sensor", sizeof("GPU Internal Sensor")); + nv_card->get_gpu_temp = (int(*)(I2CDevPtr))g92_get_gpu_temp; + } + + + /* Fanspeed adjustment support for several 8600GT 'G84', 9600GT 'G94' and 9600GSO 'G92' boards + / For now only support fanspeed adjustment using pwm registers 0xe11c/0xe120. Assume they are + / active when 0xe11c (pwm divider) is higher than 1. We need a proper method to distinguish between + / the use of 0xe114/0xe118 and 0xe11c/0xe120 and to detect whether the pwm signal needs to be inverted + / or not. Likely there is info in the bios for this. + */ + if((nv_card->arch & (G84 | G86 | G92 | G94 | G96 | GT200 | GF100)) && !(nv_card->caps & I2C_FANSPEED_MONITORING) && (nv_card->PMC[0xe11c/4] > 1)) + { + nv_card->caps |= GPU_FANSPEED_MONITORING; + nv_card->get_fanspeed = g84_get_fanspeed; + nv_card->set_fanspeed = g84_set_fanspeed; + } + + /* Mobile GPU check; we don't want to overclock those unless the user wants it */ + if(nv_card->gpu == MOBILE) + { + nv_card->caps = ~(~nv_card->caps | GPU_OVERCLOCKING | MEM_OVERCLOCKING); + } + else + nv_card->caps |= (GPU_OVERCLOCKING | MEM_OVERCLOCKING); + +#if 0 + /* Set the speed range */ + if(nv_card->bios) + { + + } + else +#endif + { + float memclk = GetClock_nv50(nv_card->base_freq, nv_card->mpll, nv_card->mpll2); + float nvclk = GetClock_nv50(nv_card->base_freq, nv_card->nvpll, nv_card->nvpll2); + + /* Not great but better than nothing .. */ + nv_card->memclk_min = (short)(memclk * .75); + nv_card->memclk_max = (short)(memclk * 1.5); + nv_card->nvclk_min = (short)(nvclk * .75); + nv_card->nvclk_max = (short)(nvclk * 1.5); + } +} diff --git a/plugins/GPUSensors/NVClockX/NVClock/nvclock.h b/plugins/GPUSensors/NVClockX/NVClock/nvclock.h new file mode 100644 index 0000000..8ae67d9 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/nvclock.h @@ -0,0 +1,354 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2007 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef NVCLOCK_H +#define NVCLOCK_H + +#include + +#define Debug FALSE + +#define LogPrefix "NVClockX: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +#define MAX_CARDS 4 + +#define NV5 (1<<0) +#define NV10 (1<<1) +#define NV17 (1<<2) +#define NV1X (NV10 | NV17) +#define NV20 (1<<3) +#define NV25 (1<<4) +#define NV2X (NV20 | NV25) +#define NV30 (1<<5) +#define NV31 (1<<6) +#define NV35 (1<<7) +#define NV3X (NV30 | NV31 | NV35) +#define NV40 (1<<8) +#define NV41 (1<<9) +#define NV43 (1<<10) +#define NV44 (1<<11) +#define NV46 (1<<12) +#define NV47 (1<<13) +#define NV49 (1<<14) +#define NV4B (1<<15) +#define C51 (1<<16) +#define NV4X (NV40 | NV41 | NV43 | NV44 | NV46 | NV47 | NV49 | NV4B | C51) +#define NV50 (1<<17) +#define G84 (1<<18) +#define G86 (1<<19) +#define G92 (1<<20) +#define G94 (1<<21) +#define G96 (1<<22) +#define GT200 (1<<23) +#define GF100 (1<<24) +#define NV5X (NV50 | G84 | G86 | G92 | G94 | G96 | GT200 | GF100) + +#define NV_ERR_NO_DEVICES_FOUND 1 +#define NV_ERR_NO_DRIVERS_FOUND 2 +#define NV_ERR_NOT_ENOUGH_PERMISSIONS 3 +#define NV_ERR_OTHER 4 + +#define GPU_OVERCLOCKING (1<<0) +#define MEM_OVERCLOCKING (1<<1) +#define COOLBITS_OVERCLOCKING (1<<2) +#define PIPELINE_MODDING (1<<3) +#define GPU_FANSPEED_MONITORING (1<<4) /* Fanspeed monitoring based on fan voltage */ +#define BOARD_TEMP_MONITORING (1<<5) /* Board temperature; not available using NVSensor */ +#define GPU_TEMP_MONITORING (1<<6) /* Internal GPU temperature */ +#define I2C_FANSPEED_MONITORING (1<<7) /* Fanspeed monitoring using a i2c sensor chip */ +#define I2C_AUTOMATIC_FANSPEED_CONTROL (1<<8) /* The sensor supports automatic fanspeed control */ +#define SMARTDIMMER (1<<9) /* Smartdimmer support for mobile GPUs */ +#define GPU_ID_MODDING (1<<10) /* PCI id modding is supported on this board */ + +#define STATE_LOWLEVEL (1<<0) +#define STATE_2D (1<<1) +#define STATE_3D (1<<2) +#define STATE_BOTH (STATE_2D | STATE_3D) + +/* Define some i2c types, so that we don't depend on additional headers when using NVClock as a library */ +#ifndef _XF86I2C_H +#include "xf86i2c.h" +/*typedef void* I2CBusPtr; +typedef void* I2CDevPtr;*/ +#endif + +typedef struct +{ + void *next; + char *section; + char *name; + unsigned int value; +} cfg_entry; + +typedef enum +{ + SDR, + DDR +} mem_type; + +typedef enum +{ + UNKNOWN, + DESKTOP, + NFORCE, + MOBILE +} gpu_type; + +struct pci_ids { + short id; + const char *name; + gpu_type gpu; +}; + +struct voltage +{ + unsigned char VID; + float voltage; +}; + +struct performance +{ + int nvclk; + int delta; + int memclk; + int shaderclk; + int fanspeed; + float voltage; +}; + +struct vco +{ + unsigned int minInputFreq, maxInputFreq; + unsigned int minFreq, maxFreq; + unsigned char minN, maxN; + unsigned char minM, maxM; +}; + +struct pll +{ + unsigned int reg; + unsigned char var1d; + unsigned char var1e; + struct vco VCO1; + struct vco VCO2; +}; + +struct sensor +{ + int slope_div; + int slope_mult; + int diode_offset_div; + int diode_offset_mult; + int temp_correction; +}; + +struct nvbios +{ + char *signon_msg; + char *vendor_name; + unsigned short device_id; + char* version; + unsigned char major; + unsigned char minor; + + short volt_entries; + short volt_mask; + struct voltage volt_lst[4]; + + short perf_entries; + struct performance perf_lst[4]; + + short pll_entries; + struct pll pll_lst[16]; + + struct sensor sensor_cfg; + + /* Cache the 'empty' PLLs, this is needed for PLL calculation */ + unsigned int mpll; + unsigned int nvpll; + unsigned int spll; + + unsigned int pipe_cfg; /* Used to cache the NV4x pipe_cfg register */ +}; + +typedef struct { + char *card_name; /* Name of the card */ + short number; /* internal card number; used by the gtk client and set_card to see if we really need to switch cards */ + short caps; /* A bitmask that contains what card features are supported; A normal gpu can do gpu/memory overclocking but a nforce can do only gpu. */ + short device_id; + short subvendor_id; + int arch; /* Architecture NV10, NV15, NV20 ..; for internal use only as we don't list all architectures */ +#if __LP64__ + mach_vm_address_t reg_address; +#else + vm_address_t reg_address; +#endif + //unsigned int reg_address; + char *dev_name; /* /dev/mem or /dev/nvidiaX */ + unsigned short devbusfn; + int irq; /* We might need the IRQ to sync NV-CONTROL info with nvclock */ + short base_freq; + gpu_type gpu; /* Tells what type of gpu is used: mobile, nforce .. */ + short debug; /* Enable/Disable debug information */ + + struct nvbios *bios; /* pointer to bios information */ + int have_coolbits; /* Tells if Coolbits (NV-CONTROL) is enabled */ + int state; /* Tells which clocks to change for NV-CONTROL: 2D, 3D or BOTH */ + + /* card registers */ + int mem_mapped; /* Check for set_card to see if the memory has been mapped or not. */ + volatile unsigned int *PFB; + volatile unsigned int *PBUS; + volatile unsigned int *PDISPLAY; /* NV50 display registers */ + volatile unsigned int *PMC; + volatile unsigned int *PRAMDAC; + volatile unsigned int *PRAMIN; + volatile unsigned int *PEXTDEV; + volatile unsigned char *PROM; /* Nvidia bios */ + volatile unsigned char *PCIO; + + /* Overclock range of speeds */ + short nvclk_min; + short nvclk_max; + short memclk_min; + short memclk_max; + + /* Various GeforceFX/Geforce6 boards use different clocks in 3d. We need to store those clocks */ + short nvclk_3d; + short memclk_3d; + + /* Card info */ + short (*get_gpu_architecture)(); + short (*get_gpu_revision)(); + int (*set_gpu_pci_id)(short id); /* Changes the least significant 2 or 4 bits of the pci id */ + + /* Memory info */ + int mem_type; /* needs to replace memory_type ?? */ + char* (*get_memory_type)(); /* Memory type: SDR/DDR */ + short (*get_memory_width)(); /* Memory width 64bit or 128bit */ + short (*get_memory_size)(); /* Amount of memory between 4 and 128 MB */ + + /* BUS info: PCI/PCI-Express/AGP */ + char* (*get_bus_type)(); /* Bus type: AGP/PCI/PCI-Express */ + short (*get_bus_rate)(); /* Current AGP rate: 1, 2, 4 or 8; PCI-Express: 1-32X*/ + + /* AGP */ + char* (*get_agp_status)(); /* Current AGP status: Enabled/Disabled */ + char* (*get_agp_fw_status)(); /* Current FW status: Enabled/Disabled */ + char* (*get_agp_sba_status)(); /* Current SBA status: Enabled/Disabled */ + char* (*get_agp_supported_rates)(); /* Supported AGP rates */ + + /* PCI-Express */ + short (*get_pcie_max_bus_rate)(); /* Get the maximum PCI-E busrate */ + + /* Hardware monitoring */ + short num_busses; /* Number of available i2c busses */ + I2CBusPtr busses[4]; /* I2C busses on the videocard; this bus is needed for communication with sensor chips */ + I2CDevPtr sensor; /* When a sensor chip is available, this device pointer can be used to access it */ + char *sensor_name; /* Name of the sensor; although sensor contains the name too, we add sensor_name because of the builtin temperature sensor used on various NV4x cards */ + int (*get_board_temp)(I2CDevPtr dev); /* Temperature of the sensor chip or for example the ram chips */ + int (*get_gpu_temp)(I2CDevPtr dev); /* Internal gpu temperature */ + float (*get_fanspeed)(); /* Get the speed in % from the pwm register in %*/ + void (*set_fanspeed)(float speed); /* Set the speed of the fan using the pwm register of the gpu */ + int (*get_i2c_fanspeed_mode)(I2CDevPtr dev); /* Advanced sensors like the ADT7473 support manual and automatic fanspeed adjustments */ + void (*set_i2c_fanspeed_mode)(I2CDevPtr dev, int mode); /* Set the fanspeed mode to manual or automatic; Note that a pwm fanspeed change already causes a switch to implicit switch to manual, so this function should only be used to deactivate manual mode */ + int (*get_i2c_fanspeed_rpm)(I2CDevPtr dev); /* Speed of the fan in rpm */ + float (*get_i2c_fanspeed_pwm)(I2CDevPtr dev); /* Duty cycle of the pwm signal that controls the fan */ + int (*set_i2c_fanspeed_pwm)(I2CDevPtr dev, float speed); /* By adjusting the duty cycle of the pwm signal, the fanspeed can be adjusted. */ + + /* Pipeline stuff for NV4x; On various Geforce6 boards disabled pixel/vertex pipelines can be re-enabled. */ + int (*get_default_mask)(char *pmask, char *vmask); + int (*get_hw_masked_units)(char *pmask, char *vmask); + int (*get_sw_masked_units)(char *pmask, char *vmask); + int (*get_pixel_pipelines)(char *mask, int *total); + void (*set_pixel_pipelines)(unsigned char mask); + int (*get_vertex_pipelines)(char *mask); + void (*set_vertex_pipelines)(unsigned char mask); + + /* NV5x (Geforce8) shader stuff */ + float (*get_shader_speed)(); /* NV5X-only */ + void (*set_shader_speed)(unsigned int clk); /* NV5X-only */ + void (*reset_shader_speed)(); + int (*get_stream_units)(char *mask, char *default_mask); + int (*get_rop_units)(char *mask, char *default_mask); + + /* Smartdimmer (adjustment of the brigthenss of the backlight on Laptops) */ + int (*get_smartdimmer)(); + void (*set_smartdimmer)(int level); + + /* Overclocking */ + volatile unsigned int mpll; /* default memory speed */ + volatile unsigned int mpll2; + volatile unsigned int nvpll; /* default gpu speed */ + volatile unsigned int nvpll2; + + void (*set_state)(int state); + float (*get_gpu_speed)(); + void (*set_gpu_speed)(unsigned int nvclk); + float (*get_memory_speed)(); + void (*set_memory_speed)(unsigned int memclk); + void (*reset_gpu_speed)(); + void (*reset_memory_speed)(); + + /* Debug */ + void (*get_debug_info)(); +} NVCard, *NVCardPtr; + +typedef struct +{ + int num_cards; + NVCard card[MAX_CARDS]; + cfg_entry *cfg; + void *dpy; /* X display needed for the NV-CONTROL backend */ + char *path; /* path to home directory */ + int nv_errno; + char *nv_err_str; +} NVClock; + +extern NVClock nvclock; +extern NVCard* nv_card; + +#ifdef __cplusplus +extern "C" { +#endif + +int init_nvclock(); +int set_card(int number); +void unset_card(); + + +/* error handling */ +char *get_error(char *buf, int size); +void set_error(int code); +void set_error_str(const char *err); + +/* utility functions */ +int convert_gpu_architecture(short arch, char *buf); +void convert_unit_mask_to_binary(char mask, char hw_default, char *buf); + +#ifdef __cplusplus +}; +#endif + +#endif /* NVCLOCK_H */ diff --git a/plugins/GPUSensors/NVClockX/NVClock/nvreg.h b/plugins/GPUSensors/NVClockX/NVClock/nvreg.h new file mode 100644 index 0000000..a62a624 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/nvreg.h @@ -0,0 +1,102 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * Copyright(C) 2001-2007 Roderick Colenbrander + * + * site: http://nvclock.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* PCI stuff */ +#define PCI_VENDOR_ID 0x0 /* 16-bit */ +# define PCI_VENDOR_ID_APPLE 0x106b +# define PCI_VENDOR_ID_HP 0x103c +# define PCI_VENDOR_ID_SANYO 0x144d /* Samsung laptops use the Sanyo vendor id */ +# define PCI_VENDOR_ID_SONY 0x104d +# define PCI_VENDOR_ID_ZEPTO 0x1a46 +#define PCI_DEVICE_ID 0x2 /* 16-bit */ +#define PCI_SUBSYSTEM_VENDOR_ID 0x2c /* 16-bit */ +#define PCI_SUBSYSTEM_ID 0x2e /* 16-bit */ +#define PCI_CAPABILITY_LIST 0x34 +#define PCI_CAP_LIST_ID 0x0 +#define PCI_CAP_LIST_NEXT 0x1 +#define PCI_CAP_ID_AGP 0x2 /* AGP */ +#define PCI_AGP_STATUS 0x4 +# define PCI_AGP_STATUS_SBA 0x200 /* Sideband Addressing */ +# define PCI_AGP_STATUS_64BIT 0x20 +# define PCI_AGP_STATUS_FW 0x10 /* Fast Writes */ +# define PCI_AGP_STATUS_RATE_8X_SUPPORT 0x8 /* If set AGP1x/AGP2x need to be interpreted as AGP4x/AGP8x */ +# define PCI_AGP_STATUS_RATE_8X_SHIFT 0x2 /* Needs to be used when 8x support is enabled to translate 1x/ -> 4x/8x*/ +# define PCI_AGP_STATUS_RATE_4X 0x4 +# define PCI_AGP_STATUS_RATE_2X 0x2 +# define PCI_AGP_STATUS_RATE_1X 0x1 +# define PCI_AGP_STATUS_RATE_MASK 0x7 /* AGP4X | AGP2X | AGP1X */ +#define PCI_AGP_COMMAND 0x8 +# define PCI_AGP_COMMAND_SBA 0x200 /* Sideband Addressing */ +# define PCI_AGP_COMMAND_AGP 0x100 /* Tells if AGP is enabled */ +# define PCI_AGP_COMMAND_64BIT 0x20 +# define PCI_AGP_COMMAND_FW 0x10 /* Fast Writes */ +# define PCI_AGP_COMMAND_RATE_4X 0x4 +# define PCI_AGP_COMMAND_RATE_2X 0x2 +# define PCI_AGP_COMMAND_RATE_1X 0x1 +# define PCI_AGP_COMMAND_RATE_MASK 0x7 /* AGP4X | AGP2X | AGP1X */ +#define PCI_CAP_ID_EXP 0x10 /* PCI-Express */ +#define PCIE_LINKCAP 0xc +#define PCIE_LINKCONTROL 0x10 +#define PCIE_LINKSTATUS 0x12 +# define PCIE_LINK_SPEED_MASK 0x3f0 +# define PCIE_LINK_SPEED_SHIFT 4 + +/* PMC */ +#define NV_PMC_BOOT_0 0x0 +# define NV_PMC_BOOT_0_REVISION_MINOR 0xf +# define NV_PMC_BOOT_0_REVISION_MAJOR 0xf0 /* in general A or B, on pre-NV10 it was different */ +# define NV_PMC_BOOT_0_REVISION_MASK 0xff + +/* PDISPLAY */ +#define NV_PDISPLAY_OFFSET 0x610000 +#define NV_PDISPLAY_SIZE 0x10000 +#define NV_PDISPLAY_SOR0_REGS_BRIGHTNESS 0xc084 +# define NV_PDIPSLAY_SOR0_REGS_BRIGHTNESS_CONTROL_ENABLED 0x80000000 + +/* PRAMIN */ +#define NV_PRAMIN_OFFSET 0x00700000 +#define NV_PRAMIN_SIZE 0x00100000 + +/* PROM */ +#define NV_PROM_OFFSET 0x300000 +#define NV_PROM_SIZE 0xffff /* size in bytes */ + +/* NV4X registers +* +* 0xc040: used to enble/disable parts of the GPU? +* bit1:0, enable/disable PLL 0x4000/0x4004; perhaps one bit is enable and the other a PLL layout switch? +* bit3:2, ?? +* bit5:4, seems similar to bit1:0, perhaps for a VPLL? but in various cases it is equal to bit1:0 +* bit7:6, ?? +* bit9:8, seems similar to bit1:0, perhaps for a VPLL? but in various cases it is equal to bit1:0 +* bit11:10, seems related to 0x4030/0x4034 (??) +* bit12:13, ?? +* bit15:14, seems related to 0x4020/0x4024; perhaps it is for all MPLL ones? (what about bit11:10 then?) +* bit17:16, seems related to 0x680508/0x680578 (primary VPLL) +* bit29:28, seems to be off when dumping bios +*/ + +/* NV5x registers +* +* The following register is around again but much more bits are used, so start a new description +* 0xc040: used to enable/disable parts of the GPU +* bit21:20, used to enable/disable PLL 0x4008/0x400c (gpu clock) +*/ diff --git a/plugins/GPUSensors/NVClockX/NVClock/overclock.cpp b/plugins/GPUSensors/NVClockX/NVClock/overclock.cpp new file mode 100644 index 0000000..a435794 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/overclock.cpp @@ -0,0 +1,344 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2005 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +//#include +//#include +#include "backend.h" + +unsigned int abs (int number); +unsigned int abs (int number) +{ + if (number<0) + number=-number; + return number; +} + + +static int CalcSpeed(int base_freq, int m, int n, int p) +{ + return (int)((float)n/(float)m * base_freq) >> p; +} + +/* Generic clock algorithm for all cards upto the Geforce4 */ +float GetClock(int base_freq, unsigned int pll) +{ + int m, n, p; + + m = pll & 0xff; + n = (pll >> 8) & 0xff; + p = (pll >> 16) & 0x0f; + + if(nv_card->debug) + printf("m=%d n=%d p=%d\n", m, n, p); + + return (float)CalcSpeed(base_freq, m, n, p)/1000; +} + +/* Calculate the requested speed. */ +static void ClockSelect(int base_freq, int clockIn, int *PLL) +{ + int m, n, p, bestm, bestn, bestp; + int diff, diffOld, mlow, mhigh, nlow, nhigh, plow, phigh; + diffOld = clockIn; + + if(base_freq == 14318) + { + mlow = 7; + mhigh = 14; + nlow = 14; + nhigh = 255; + } + else + { + mlow = 6; + mhigh = 13; + nlow = 14; + nhigh = 255; + } + + if(clockIn > 250000) + { + mlow = 1; + mhigh = 6; + nlow = 14; + nhigh = 93; + } + if(clockIn > 340000) + { + /* When DDR memory is used we should perhaps force mhigh to 1, since + * on some cards the framebuffer needs to be reinitialized and image corruption + * can occur. + */ + mlow = 1; + mhigh = 2; + nlow = 14; + nhigh = 93; + } + + /* postdivider locking to improve stability. + * in the near future we will provide some tuning options for the + * overclocking algorithm which will extend this. + */ + plow = (*PLL >> 16) & 0x0f; + phigh = (*PLL >> 16) & 0x0f; + + /* + Calculate the m and n values. There are a lot of values which give the same speed; + We choose the speed for which the difference with the request speed is as small as possible. + */ + for(p = plow; p <= phigh; p++) + { + for(m = mlow; m <= mhigh; m++) + { + for(n = nlow; n <= nhigh; n++) + { + diff = abs((int)(clockIn - CalcSpeed(base_freq, m, n, p))); + + /* When the new difference is smaller than the old one, use this one */ + if(diff < diffOld) + { + diffOld = diff; + bestm = m; + bestn = n; + bestp = p; + +#if 0 + /* When the difference is 0 or less than .5% accept the speed */ + if(((diff == 0) || ((float)diff/(float)clockIn <= 0.005))) + { + *PLL = ((int)bestp << 16) + ((int)bestn << 8) + bestm; + return; + } +#endif + } + } + } + } + + + *PLL = ((int)bestp << 16) + ((int)bestn << 8) + bestm; + return; +} + +static void set_gpu_speed(unsigned int clk) +{ + int PLL; + + /* MHz -> KHz */ + clk *= 1000; + + PLL = nv_card->PRAMDAC[0x500/4]; + + /* HERE the new clocks are selected (in KHz). */ + ClockSelect(nv_card->base_freq, clk, &PLL); + + /* Unlock the programmable NVPLL/MPLL */ + nv_card->PRAMDAC[0x50c/4] |= 0x500; + + /* Overclock */ + nv_card->PRAMDAC[0x500/4] = PLL; +} + +static void set_memory_speed(unsigned int clk) +{ + int PLL = nv_card->PRAMDAC[0x504/4]; + + /* MHz -> KHz */ + clk *= 1000; + /* This is a workaround meant for some Geforce2 MX/Geforce4 MX cards + * using SDR memory. Gf2MX/Gf4MX cards use 4x16 SDR memory report + * twice as high clockspeeds. I call that "fake ddr". + * By detecting the memory type, pci id and clockspeed we check + * if this occurs. It is a workaround. + */ + if(nv_card->mem_type == SDR && ( nv_card->device_id == 0x110 || nv_card->device_id == 0x111 + || nv_card->device_id == 0x172 || nv_card->device_id == 0x17a)) + { + if(GetClock(nv_card->base_freq, PLL) > 280) clk *= 2; + } + + /* Here the clocks are selected in kHz */ + ClockSelect(nv_card->base_freq, clk, &PLL); + + /* Unlock the programmable NVPLL/MPLL */ + nv_card->PRAMDAC[0x50c/4] |= 0x500; + + /* Overclock */ + nv_card->PRAMDAC[0x504/4] = PLL; +} + +static float get_gpu_speed() +{ + int pll = nv_card->PRAMDAC[0x500/4]; + + /* Unlock the programmable NVPLL/MPLL */ + nv_card->PRAMDAC[0x50c/4] |= 0x500; + + if(nv_card->debug == 1) + { + printf("NVPLL_COEFF=%08x\n", pll); + } + return (float)GetClock(nv_card->base_freq, pll); +} + +static float get_memory_speed() +{ + int factor = 1; + int pll = nv_card->PRAMDAC[0x504/4]; + + /* Unlock the programmable NVPLL/MPLL */ + nv_card->PRAMDAC[0x50c/4] |= 0x500; + + /* This is a workaround meant for some Geforce2 MX/Geforce4 MX cards + * using SDR memory. Gf2MX/Gf4MX cards use 4x16 SDR memory report + * twice as high clockspeeds. I call that "fake ddr". + * By detecting the memory type, pci id and clockspeed we check + * if this occurs. It is a workaround. We divide the memclk later by 2. + */ + if(nv_card->mem_type == SDR && ( nv_card->device_id == 0x110 || nv_card->device_id == 0x111 || + nv_card->device_id == 0x172 || nv_card->device_id == 0x17a || nv_card->device_id == 0x182 \ + || nv_card->device_id == 0x183)) + { + if(GetClock(nv_card->base_freq, pll) > 280) + { + factor = 2; + } + } + + if(nv_card->debug == 1) + { + printf("MPLL_COEFF=%08x\n", nv_card->PRAMDAC[0x504/4]); + } + + return ((float)GetClock(nv_card->base_freq, pll)) / factor; +} + +static float nforce_get_memory_speed() +{ + unsigned short p = (pciReadLong(0x3, 0x6c) >> 8) & 0xf; + if(!p) p = 4; + return 400.0 / (float)p; +} + +static void reset_gpu_speed() +{ + /* Unlock the programmable NVPLL/MPLL */ + nv_card->PRAMDAC[0x50c/4] |= 0x500; + + /* Set the gpu speed */ + nv_card->PRAMDAC[0x500/4] = nv_card->nvpll; +} + +static void reset_memory_speed() +{ + /* Unlock the programmable NVPLL/MPLL */ + nv_card->PRAMDAC[0x50c/4] |= 0x500; + + /* Don't overclock the memory of integrated GPUs */ + if(nv_card->gpu == NFORCE) + return; + + /* Set the memory speed */ + nv_card->PRAMDAC[0x504/4] = nv_card->mpll; +} + +static void nv_set_state(int state) +{ +} + +void nv_init(void) +{ + float memclk, nvclk; + + /* Get the base frequency */ + nv_card->base_freq = (nv_card->PEXTDEV[0x0000/4] & 0x40) ? 14318 : 13500; + if(nv_card->arch & (NV17 | NV25)) + { + if (nv_card->PEXTDEV[0x0000/4] & (1<<22)) + nv_card->base_freq = 27000; + } + + nv_card->set_state = nv_set_state; + nv_card->get_gpu_speed = get_gpu_speed; + nv_card->set_gpu_speed = set_gpu_speed; + nv_card->get_memory_speed = get_memory_speed; + nv_card->set_memory_speed = set_memory_speed; + nv_card->reset_gpu_speed = reset_gpu_speed; + nv_card->reset_memory_speed = reset_memory_speed; + + /* Register I2C busses for hardware monitoring purposes */ + if(nv_card->busses[0] == NULL) + { + nv_card->num_busses = 2; + nv_card->busses[0] = NV_I2CCreateBusPtr(STRDUP("BUS0", sizeof("BUS0")), 0x3e); /* available on riva128 and higher */ + nv_card->busses[1] = NV_I2CCreateBusPtr(STRDUP("BUS1", sizeof("BUS1")), 0x36); /* available on rivatnt hardware and higher */ + + /* There's an extra bus available on geforce4mx/ti, geforcefx and geforce6 cards. + / The check below looks for geforce4mx/geforcefx/geforce6 architecture. + */ + if(nv_card->arch & (NV17 | NV25 | NV3X | NV4X)) + { + nv_card->num_busses = 3; + nv_card->busses[2] = NV_I2CCreateBusPtr(STRDUP("BUS2", sizeof("BUS2")), 0x50); + } + } + + /* Mobile GPU check; we don't want to overclock those unless the user wants it */ + if(nv_card->gpu == MOBILE) + { + nv_card->caps = ~(~nv_card->caps | GPU_OVERCLOCKING | MEM_OVERCLOCKING); + } + else if(nv_card->gpu == NFORCE) + { + /* Only support gpu overclocking because the memory is normal system memory of which we can't adjust the clocks */ + nv_card->caps |= GPU_OVERCLOCKING; + nv_card->get_memory_speed = nforce_get_memory_speed; + nv_card->set_memory_speed = NULL; + nv_card->reset_memory_speed = NULL; + } + else + nv_card->caps |= (GPU_OVERCLOCKING | MEM_OVERCLOCKING); + + /* Set the speed range */ + memclk = GetClock(nv_card->base_freq, nv_card->mpll); + nvclk = GetClock(nv_card->base_freq, nv_card->nvpll); + nv_card->memclk_min = (short)(memclk * .75); + nv_card->memclk_max = (short)(memclk * 1.5); + nv_card->nvclk_min = (short)(nvclk * .75); + nv_card->nvclk_max = (short)(nvclk * 1.5); + + /* Find out what memory is being used */ + nv_card->mem_type = (nv_card->PFB[0x200/4] & 0x01) ? DDR : SDR; + + /* Hack. + * Nvidia was so nice to ship support both DDR and SDR memory on some gf2mx and gf4mx cards :( + * Because of this the speed ranges of the memory speed can be different. + * Check if the card is a gf2mx/gf4mx using SDR and if the speed is "too" high. + * Then adjust the speed range. + */ + if((nv_card->device_id == 0x110 || nv_card->device_id == 0x111 \ + || nv_card->device_id == 0x172 || nv_card->device_id == 0x182 \ + || nv_card->device_id == 0x183) && ((nv_card->PFB[0x200/4] & 0x1) == SDR) && memclk > 280) + { + nv_card->memclk_min /= 2; + nv_card->memclk_max /= 2; + } +} diff --git a/plugins/GPUSensors/NVClockX/NVClock/utils.cpp b/plugins/GPUSensors/NVClockX/NVClock/utils.cpp new file mode 100644 index 0000000..ca56204 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/utils.cpp @@ -0,0 +1,86 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2007 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +int convert_gpu_architecture(short arch, char *buf); +void convert_unit_mask_to_binary(char mask, char hw_default, char *buf); + +/* Convert the gpu architecture to a string using NVxx/Gxx naming */ +int convert_gpu_architecture(short arch, char *buf) +{ + if(!buf) + return 0; + + switch(arch) + { + case 0x46: + snprintf(buf, sizeof("NV46/G72"), "NV46/G72"); /* 7300 */ + break; + case 0x47: + snprintf(buf, sizeof("NV47/G70"), "NV47/G70"); /* 7800 */ + break; + case 0x49: + snprintf(buf, sizeof("NV49/G71"), "NV49/G71"); /* 7900 */ + break; + case 0x4b: + snprintf(buf, sizeof("NV4B/G73"), "NV4B/G73"); /* 7600 */ + break; + case 0x4c: /* is this correct also a C51? */ + case 0x4e: + snprintf(buf, sizeof("C51"), "C51"); /* Geforce 6x00 nForce */ + break; + // sprintf(buf, "C68"); /* Geforce 70xx nForce */ + case 0x50: + snprintf(buf, sizeof("NV50/G80"), "NV50/G80"); /* 8800 */ + break; + case 0xa0: + snprintf(buf, sizeof("GT200"), "GT200"); /* Geforce GTX260/280 */ + break; + case 0xc0 ... 0xcf: + snprintf(buf, sizeof("GF100"), "GF100"); /* GF100 */ + break; + default: + if(arch <= 0x44) /* The NV44/6200TC is the last card with only an NV name */ + snprintf(buf, sizeof("NV??"), "NV%X", arch); + else /* Use Gxx for anything else */ + snprintf(buf, sizeof("G??"), "G%X", arch); + } + return 1; +} + +/* Convert a mask containing enabled/disabled pipelines for nv4x cards +/ to a binary string. +*/ +void convert_unit_mask_to_binary(char mask, char hw_default, char *buf) +{ + int i, len; + + /* Count the number of pipelines on the card */ + for(i=0, len=0; i<8; i++) + len += (hw_default & (1< +#include +#include +#include "i2c.h" +#include "nvclock.h" + + +/* various defines for register offsets and such are needed */ + +#define W83781D_REG_LOCAL_TEMP 0x27 +#define W83781D_REG_REMOTE_TEMP 0x27 +#define W83781D_REG_FAN1_COUNT 0x28 +#define W83781D_REG_MAN_ID 0x4f +#define ASUS_MAN_ID 0x12 +#define W83781D_MAN_ID 0x5c +#define W83781D_REG_CHIP_ID 0x58 +#define W83781D_REG_FAN_DIVISOR 0x47 + +/* This function should return the chip type .. */ +int w83781d_detect(I2CDevPtr dev) +{ + I2CByte man_id, chip_id; + + xf86I2CReadByte (dev, W83781D_REG_MAN_ID, &man_id); + xf86I2CReadByte (dev, W83781D_REG_CHIP_ID, &chip_id); + + switch(man_id) + { + case ASUS_MAN_ID: + case W83781D_MAN_ID: + /* We still need a chip_id check (0x11 for w83781d) */ + dev->chip_id = W83781D; + dev->chip_name = (char*)STRDUP("Winbond W83781D", sizeof("Winbond W83781D")); + break; + default: + printf("Uknown Winbond vendor: %x\n", man_id); + return 0; + } + return 1; +} + +int w83781d_get_board_temp(I2CDevPtr dev) +{ + I2CByte temp; + xf86I2CReadByte(dev, W83781D_REG_LOCAL_TEMP, &temp); + return temp; +} + +/* only one temperature exists ... */ +int w83781d_get_gpu_temp(I2CDevPtr dev) +{ + I2CByte temp; + xf86I2CReadByte(dev, W83781D_REG_REMOTE_TEMP, &temp); + return temp; +} + +int w83781d_get_fanspeed_rpm(I2CDevPtr dev) +{ + I2CByte count, divisor; + + xf86I2CReadByte(dev, W83781D_REG_FAN1_COUNT, &count); + xf86I2CReadByte(dev, W83781D_REG_FAN_DIVISOR, &divisor); + divisor = 1 << ((divisor >> 4) & 0x3); /* bit 5:4 are for fan1; a value of 0 means a divider of 1, while 2 means 2^3 = 8 */ + + /* A count of 0xff indicates that something is wrong i.e. no fan is connected */ + if(count == 0xff) + return 0; + + return 1350000/(count * divisor); +} + +float w83781d_get_fanspeed_pwm(I2CDevPtr dev) +{ + return 0; +} + +int w83781d_set_fanspeed_pwm(I2CDevPtr dev, float speed) +{ + return 0; +} + diff --git a/plugins/GPUSensors/NVClockX/NVClock/w83l785r.cpp b/plugins/GPUSensors/NVClockX/NVClock/w83l785r.cpp new file mode 100644 index 0000000..f47ec34 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/w83l785r.cpp @@ -0,0 +1,123 @@ +/* NVClock 0.8 - Linux overclocker for NVIDIA cards + * + * site: http://nvclock.sourceforge.net + * + * Copyright(C) 2001-2005 Roderick Colenbrander + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * W83L785R hardware monitoring + */ +#include +#include "i2c.h" +#include "nvclock.h" + + +/* various defines for register offsets and such are needed */ + +#define W83L785R_REG_LOCAL_TEMP 0x26 +#define W83L785R_REG_LOCAL_TEMP_OFFSET 0x85 +#define W83L785R_REG_REMOTE_TEMP 0x27 +#define W83L785R_REG_REMOTE_TEMP_OFFSET 0x86 + +#define W83L785R_REG_FAN1_COUNT 0x28 +#define W83L785R_REG_FAN2_COUNT 0x29 +#define W83L785R_REG_FAN_DIVISOR 0x47 /* bit 2-0 for fan1; bit 6-4 for fan2 */ + +#define W83L785R_REG_MAN_ID_L 0x4c +#define W83L785R_REG_MAN_ID_H 0x4d +#define W83L785R_REG_CHIP_ID 0x4e + +#define W83L785R_REG_FAN1_PWM 0x81 +#define W83L785R_REG_FAN2_PWM 0x83 + +/* This function should return the chip type .. */ +int w83l785r_detect(I2CDevPtr dev) +{ + I2CByte man_id_l, man_id_h, chip_id; + + xf86I2CReadByte(dev, W83L785R_REG_MAN_ID_L, &man_id_l); + xf86I2CReadByte(dev, W83L785R_REG_MAN_ID_H, &man_id_h); + xf86I2CReadByte(dev, W83L785R_REG_CHIP_ID, &chip_id); + + /* Winbond chip */ + if((man_id_l == 0xa3) && (man_id_h == 0x5c)) + { + if((chip_id & 0xfe) == 0x60) + { + dev->chip_id = W83L785R; + dev->chip_name = (char*)STRDUP("Winbond W83L785R", sizeof("Winbond W83L785R")); + return 1; + } + } + + return 0; +} + +int w83l785r_get_board_temp(I2CDevPtr dev) +{ + I2CByte temp, offset; + xf86I2CReadByte(dev, W83L785R_REG_LOCAL_TEMP, &temp); + xf86I2CReadByte(dev, W83L785R_REG_LOCAL_TEMP_OFFSET, &offset); + return temp + offset; +} + +int w83l785r_get_gpu_temp(I2CDevPtr dev) +{ + I2CByte temp, offset; + xf86I2CReadByte(dev, W83L785R_REG_REMOTE_TEMP, &temp); + xf86I2CReadByte(dev, W83L785R_REG_REMOTE_TEMP_OFFSET, &offset); + return temp + offset; +} + +int w83l785r_get_fanspeed_rpm(I2CDevPtr dev) +{ + I2CByte count, divisor; + + xf86I2CReadByte(dev, W83L785R_REG_FAN1_COUNT, &count); + xf86I2CReadByte(dev, W83L785R_REG_FAN_DIVISOR, &divisor); + divisor &= 0x7; + + /* By default count useally is 153, it seems that a value of 255 means that something is wrong. + / For example it retuns this value on boards on which the fan is replaced with a heatpipe and because + / of that the fan was removed. + */ + if(count == 0xff) + return 0; + + return 1350000/(count * (1< + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/i2c/xf86i2c.c,v 1.6 1999/06/12 15:37:08 dawes Exp $ */ + +#include "xfree.h" +#include + +#if 0 +#define NULL ((void *)0) + +#include "misc.h" +#include "xf86.h" +#include "xf86_ansic.h" +#include "xf86_OSproc.h" + +#include "X.h" +#include "Xproto.h" +#include "scrnintstr.h" +#include "regionstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "validate.h" +#include "resource.h" +#include "gcstruct.h" +#include "dixstruct.h" +/* #else */ +typedef int Bool; +typedef void *Pointer; +#define TRUE 1 +#define FALSE 0 +#endif + +#include + +#include "xf86i2c.h" + +#define I2C_TIMEOUT(x) /*(x)*/ /* Report timeouts */ +#define I2C_TRACE(x) /*(x)*/ /* Report progress */ + +/* Set which OSs have bad gettimeofday resolution. */ +#if defined(SVR4) && !defined(sun) +#define BAD_GETTIMEOFDAY_RESOLUTION +#endif + + +/* This is the default I2CUDelay function if not supplied by the driver. + * High level I2C interfaces implementing the bus protocol in hardware + * should supply this function too. + * + * Delay execution at least usec microseconds. + * All values 0 to 1e6 inclusive must be expected. + */ + +#ifdef BAD_GETTIMEOFDAY_RESOLUTION +/* + * This is temporary until a better, portable + * way is found. Adjust bogo_usec to match CPU speed. + */ +static int bogo_usec = 500; + +static void +I2CUDelay(I2CBusPtr b, int usec) +{ + volatile long i; + + if (usec > 0) + for (i = usec * bogo_usec; i > 0; i--) + /* (perhaps hw delay action) */; +} +#else +static void +I2CUDelay(I2CBusPtr b, int usec) +{ + IODelay(usec); + /*long b_secs, b_usecs; + long a_secs, a_usecs; + long d_secs, d_usecs; + long diff; + + if (usec > 0) { + xf86getsecs(&b_secs, &b_usecs); + do { + // It would be nice to use {xf86}usleep, + // but usleep (1) takes >10000 usec ! + // + xf86getsecs(&a_secs, &a_usecs); + d_secs = (a_secs - b_secs); + d_usecs = (a_usecs - b_usecs); + diff = d_secs*1000000 + d_usecs; + } while (diff>0 && diff< (usec + 1)); + }*/ +} +#endif + +/* Most drivers will register just with GetBits/PutBits functions. + * The following functions implement a software I2C protocol + * by using the promitive functions given by the driver. + * ================================================================ + * + * It is assumed that there is just one master on the I2C bus, therefore + * there is no explicit test for conflits. + */ + +#define RISEFALLTIME 2 /* usec, actually 300 to 1000 ns according to the i2c specs */ + +/* Some devices will hold SCL low to slow down the bus or until + * ready for transmission. + * + * This condition will be noticed when the master tries to raise + * the SCL line. You can set the timeout to zero if the slave device + * does not support this clock synchronization. + */ + +Bool I2CAddress(I2CDevPtr d, I2CSlaveAddr addr); + +static Bool +I2CRaiseSCL(I2CBusPtr b, int sda, int timeout) +{ + int i, scl; + + b->I2CPutBits(b, 1, sda); + b->I2CUDelay(b, b->RiseFallTime); + + for (i = timeout; i > 0; i -= b->RiseFallTime) { + b->I2CGetBits(b, &scl, &sda); + if (scl) break; + b->I2CUDelay(b, b->RiseFallTime); + } + + if (i <= 0) { + I2C_TIMEOUT(ErrorF("[I2CRaiseSCL(<%s>, %d, %d) timeout]", b->BusName, sda, timeout)); + return FALSE; + } + + return TRUE; +} + +/* Send a start signal on the I2C bus. The start signal notifies + * devices that a new transaction is initiated by the bus master. + * + * The start signal is always followed by a slave address. + * Slave addresses are 8+ bits. The first 7 bits identify the + * device and the last bit signals if this is a read (1) or + * write (0) operation. + * + * There may be more than one start signal on one transaction. + * This happens for example on some devices that allow reading + * of registers. First send a start bit followed by the device + * address (with the last bit 0) and the register number. Then send + * a new start bit with the device address (with the last bit 1) + * and then read the value from the device. + * + * Note this is function does not implement a multiple master + * arbitration procedure. + */ + +static Bool +I2CStart(I2CBusPtr b, int timeout) +{ + int i, scl, sda; + b->I2CPutBits(b, 1, 1); + b->I2CUDelay(b, b->RiseFallTime); + + for (i = timeout; i > 0; i -= b->RiseFallTime) { + b->I2CGetBits(b, &scl, &sda); + if (scl) break; + b->I2CUDelay(b, b->RiseFallTime); + } + + if (i <= 0) { + I2C_TIMEOUT(ErrorF("\ni2c: <[I2CStart(<%s>, %d) timeout]", b->BusName, timeout)); + return FALSE; + } + + b->I2CPutBits(b, 1, 0); + b->I2CUDelay(b, b->HoldTime); + b->I2CPutBits(b, 0, 0); + b->I2CUDelay(b, b->HoldTime); + + I2C_TRACE(ErrorF("\ni2c: <")); + + return TRUE; +} + +/* This is the default I2CStop function if not supplied by the driver. + * + * Signal devices on the I2C bus that a transaction on the + * bus has finished. There may be more than one start signal + * on a transaction but only one stop signal. + */ + +static void +I2CStop(I2CDevPtr d) +{ + I2CBusPtr b = d->pI2CBus; + + b->I2CPutBits(b, 0, 0); + b->I2CUDelay(b, b->RiseFallTime); + + b->I2CPutBits(b, 1, 0); + b->I2CUDelay(b, b->HoldTime); + b->I2CPutBits(b, 1, 1); + b->I2CUDelay(b, b->HoldTime); + + I2C_TRACE(ErrorF(">\n")); +} + +/* Write/Read a single bit to/from a device. + * Return FALSE if a timeout occurs. + */ + +static Bool +I2CWriteBit(I2CBusPtr b, int sda, int timeout) +{ + Bool r; + + b->I2CPutBits(b, 0, sda); + b->I2CUDelay(b, b->RiseFallTime); + + r = I2CRaiseSCL(b, sda, timeout); + b->I2CUDelay(b, b->HoldTime); + + b->I2CPutBits(b, 0, sda); + b->I2CUDelay(b, b->HoldTime); + + return r; +} + +static Bool +I2CReadBit(I2CBusPtr b, int *psda, int timeout) +{ + Bool r; + int scl; + + r = I2CRaiseSCL(b, 1, timeout); + b->I2CUDelay(b, b->HoldTime); + + b->I2CGetBits(b, &scl, psda); + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->HoldTime); + + return r; +} + +/* This is the default I2CPutByte function if not supplied by the driver. + * + * A single byte is sent to the device. + * The function returns FALSE if a timeout occurs, you should send + * a stop condition afterwards to reset the bus. + * + * A timeout occurs, + * if the slave pulls SCL to slow down the bus more than ByteTimeout usecs, + * or slows down the bus for more than BitTimeout usecs for each bit, + * or does not send an ACK bit (0) to acknowledge the transmission within + * AcknTimeout usecs, but a NACK (1) bit. + * + * AcknTimeout must be at least b->HoldTime, the other timeouts can be + * zero according to the comment on I2CRaiseSCL. + */ + +static Bool +I2CPutByte(I2CDevPtr d, I2CByte data) +{ + Bool r; + int i, scl, sda; + I2CBusPtr b = d->pI2CBus; + + if (!I2CWriteBit(b, (data >> 7) & 1, d->ByteTimeout)) + return FALSE; + + for (i = 6; i >= 0; i--) + if (!I2CWriteBit(b, (data >> i) & 1, d->BitTimeout)) + return FALSE; + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->RiseFallTime); + + r = I2CRaiseSCL(b, 1, b->HoldTime); + + if (r) { + for (i = d->AcknTimeout; i > 0; i -= b->HoldTime) { + b->I2CUDelay(b, b->HoldTime); + b->I2CGetBits(b, &scl, &sda); + if (sda == 0) break; + } + + if (i <= 0) { + I2C_TIMEOUT(ErrorF("[I2CPutByte(<%s>, 0x%02x, %d, %d, %d) timeout]", + b->BusName, data, d->BitTimeout, + d->ByteTimeout, d->AcknTimeout)); + r = FALSE; + } + + I2C_TRACE(ErrorF("W%02x%c ", (int) data, sda ? '-' : '+')); + } + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->HoldTime); + + return r; +} + +/* This is the default I2CGetByte function if not supplied by the driver. + * + * A single byte is read from the device. + * The function returns FALSE if a timeout occurs, you should send + * a stop condition afterwards to reset the bus. + * + * A timeout occurs, + * if the slave pulls SCL to slow down the bus more than ByteTimeout usecs, + * or slows down the bus for more than b->BitTimeout usecs for each bit. + * + * ByteTimeout must be at least b->HoldTime, the other timeouts can be + * zero according to the comment on I2CRaiseSCL. + * + * For the byte in a sequence the acknowledge bit NACK (1), + * otherwise ACK (0) will be sent. + */ + +static Bool +I2CGetByte(I2CDevPtr d, I2CByte *data, Bool last) +{ + int i, sda; + I2CBusPtr b = d->pI2CBus; + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->RiseFallTime); + + if (!I2CReadBit(b, &sda, d->ByteTimeout)) + return FALSE; + + *data = (sda > 0) << 7; + + for (i = 6; i >= 0; i--) + if (!I2CReadBit(b, &sda, d->BitTimeout)) + return FALSE; + else + *data |= (sda > 0) << i; + + if (!I2CWriteBit(b, last ? 1 : 0, d->BitTimeout)) + return FALSE; + + I2C_TRACE(ErrorF("R%02x%c ", (int) *data, last ? '+' : '-')); + + return TRUE; +} + +/* This is the default I2CAddress function if not supplied by the driver. + * + * It creates the start condition, followed by the d->SlaveAddr. + * Higher level functions must call this routine rather than + * I2CStart/PutByte because a hardware I2C master may not be able + * to send a slave address without a start condition. + * + * The same timeouts apply as with I2CPutByte and additional a + * StartTimeout, similar to the ByteTimeout but for the start + * condition. + * + * In case of a timeout, the bus is left in a clean idle condition. + * I. e. you *must not* send a Stop. If this function succeeds, you *must*. + * + * The slave address format is 16 bit, with the legacy _8_bit_ slave address + * in the least significant byte. This is, the slave address must include the + * R/_W flag as least significant bit. + * + * The most significant byte of the address will be sent _after_ the LSB, + * but only if the LSB indicates: + * a) an 11 bit address, this is LSB = 1111 0xxx. + * b) a 'general call address', this is LSB = 0000 000x - see the I2C specs + * for more. + */ + +Bool I2CAddress(I2CDevPtr d, I2CSlaveAddr addr) +{ + if (I2CStart(d->pI2CBus, d->StartTimeout)) { + if (I2CPutByte(d, addr & 0xFF)) { + if ((addr & 0xF8) != 0xF0 && + (addr & 0xFE) != 0x00) + return TRUE; + + if (I2CPutByte(d, (addr >> 8) & 0xFF)) + return TRUE; + } + + I2CStop(d); + } + + return FALSE; +} + +/* These are the hardware independent I2C helper functions. + * ======================================================== + */ + +/* Function for probing. Just send the slave address + * and return true if the device responds. The slave address + * must have the lsb set to reflect a read (1) or write (0) access. + * Don't expect a read- or write-only device will respond otherwise. + */ + +Bool +xf86I2CProbeAddress(I2CBusPtr b, I2CSlaveAddr addr) +{ + int r; + I2CDevRec d; + + d.DevName = STRDUP("Probing", sizeof("Probing")); + d.BitTimeout = b->BitTimeout; + d.ByteTimeout = b->ByteTimeout; + d.AcknTimeout = b->AcknTimeout; + d.StartTimeout = b->StartTimeout; + d.SlaveAddr = addr; + d.pI2CBus = b; + d.NextDev = NULL; + + r = b->I2CAddress(&d, addr); + + if (r) b->I2CStop(&d); + + return r; +} + +/* All functions below are related to devices and take the + * slave address and timeout values from an I2CDevRec. They + * return FALSE in case of an error (presumably a timeout). + */ + +/* General purpose read and write function. + * + * 1st, if nWrite > 0 + * Send a start condition + * Send the slave address (1 or 2 bytes) with write flag + * Write n bytes from WriteBuffer + * 2nd, if nRead > 0 + * Send a start condition [again] + * Send the slave address (1 or 2 bytes) with read flag + * Read n bytes to ReadBuffer + * 3rd, if a Start condition has been successfully sent, + * Send a Stop condition. + * + * The functions exits immediately when an error occures, + * not proceeding any data left. However, step 3 will + * be executed anyway to leave the bus in clean idle state. + */ + +Bool +xf86I2CWriteRead(I2CDevPtr d, + I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead) +{ + Bool r = TRUE; + I2CBusPtr b = d->pI2CBus; + int s = 0; + + if (r && nWrite > 0) { + r = b->I2CAddress(d, d->SlaveAddr & ~1); + if (r) { + for (; nWrite > 0; WriteBuffer++, nWrite--) + if (!(r = b->I2CPutByte(d, *WriteBuffer))) + break; + s++; + } + } + + if (r && nRead > 0) { + r = b->I2CAddress(d, d->SlaveAddr | 1); + if (r) { + for (; nRead > 0; ReadBuffer++, nRead--) + if (!(r = b->I2CGetByte(d, ReadBuffer, nRead == 1))) + break; + s++; + } + } + + if (s) b->I2CStop(d); + + return r; +} + +/* Read a byte, the only readable register of a device. + */ + +Bool +xf86I2CReadStatus(I2CDevPtr d, I2CByte *pbyte) +{ + return xf86I2CWriteRead(d, NULL, 0, pbyte, 1); +} + +/* Read a byte from one of the registers determined by its sub-address. + */ + +Bool +xf86I2CReadByte(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte) +{ + return xf86I2CWriteRead(d, &subaddr, 1, pbyte, 1); +} + +/* Read bytes from subsequent registers determined by the + * sub-address of the first register. + */ + +Bool +xf86I2CReadBytes(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte, int n) +{ + return xf86I2CWriteRead(d, &subaddr, 1, pbyte, n); +} + +/* Read a word (high byte, then low byte) from one of the registers + * determined by its sub-address. + */ + +Bool +xf86I2CReadWord(I2CDevPtr d, I2CByte subaddr, unsigned short *pword) +{ + I2CByte rb[2]; + + if (!xf86I2CWriteRead(d, &subaddr, 1, rb, 2)) return FALSE; + + *pword = (rb[0] << 8) | rb[1]; + + return TRUE; +} + +/* Write a byte to one of the registers determined by its sub-address. + */ + +Bool +xf86I2CWriteByte(I2CDevPtr d, I2CByte subaddr, I2CByte byte) +{ + I2CByte wb[2]; + + wb[0] = subaddr; + wb[1] = byte; + + return xf86I2CWriteRead(d, wb, 2, NULL, 0); +} + +/* Write bytes to subsequent registers determined by the + * sub-address of the first register. + */ + +Bool +xf86I2CWriteBytes(I2CDevPtr d, I2CByte subaddr, + I2CByte *WriteBuffer, int nWrite) +{ + I2CBusPtr b = d->pI2CBus; + Bool r = TRUE; + + if (nWrite > 0) { + r = b->I2CAddress(d, d->SlaveAddr & ~1); + if (r){ + if ((r = b->I2CPutByte(d, subaddr))) + for (; nWrite > 0; WriteBuffer++, nWrite--) + if (!(r = b->I2CPutByte(d, *WriteBuffer))) + break; + + b->I2CStop(d); + } + } + + return r; +} + +/* Write a word (high byte, then low byte) to one of the registers + * determined by its sub-address. + */ + +Bool +xf86I2CWriteWord(I2CDevPtr d, I2CByte subaddr, unsigned short word) +{ + I2CByte wb[3]; + + wb[0] = subaddr; + wb[1] = word >> 8; + wb[2] = word & 0xFF; + + return xf86I2CWriteRead(d, wb, 3, NULL, 0); +} + +/* Write a vector of bytes to not adjacent registers. This vector is, + * 1st byte sub-address, 2nd byte value, 3rd byte sub-address asf. + * This function is intended to initialize devices. Note this function + * exits immediately when an error occurs, some registers may + * remain uninitialized. + */ + +Bool +xf86I2CWriteVec(I2CDevPtr d, I2CByte *vec, int nValues) +{ + I2CBusPtr b = d->pI2CBus; + Bool r = TRUE; + int s = 0; + + if (nValues > 0) { + for (; nValues > 0; nValues--, vec += 2) { + if (!(r = b->I2CAddress(d, d->SlaveAddr & ~1))) + break; + + s++; + + if (!(r = b->I2CPutByte(d, vec[0]))) + break; + + if (!(r = b->I2CPutByte(d, vec[1]))) + break; + } + + if (s > 0) b->I2CStop(d); + } + + return r; +} + +/* Administrative functions. + * ========================= + */ + +/* Allocates an I2CDevRec for you and initializes with propper defaults + * you may modify before calling xf86I2CDevInit. Your I2CDevRec must + * contain at least a SlaveAddr, and a pI2CBus pointer to the bus this + * device shall be linked to. + * + * See function I2CAddress for the slave address format. Always set + * the least significant bit, indicating a read or write access, to zero. + */ + +I2CDevPtr +xf86CreateI2CDevRec(void) +{ + return new I2CDevRec; +} + +/* Unlink an I2C device. If you got the I2CDevRec from xf86CreateI2CDevRec + * you should set to free it. + */ + +void +xf86DestroyI2CDevRec(I2CDevPtr d, Bool unalloc) +{ + if (d) { + I2CDevPtr *p; + + /* Remove this from the list of active I2C devices. */ + + for (p = &d->pI2CBus->FirstDev; *p != NULL; p = &(*p)->NextDev) + if (*p == d) { + *p = (*p)->NextDev; + break; + } + + if (d->pI2CBus->scrnIndex >= 0) + xf86DrvMsg(d->pI2CBus->scrnIndex, X_INFO, + "I2C device \"%s:%s\" removed.\n", + d->pI2CBus->BusName, d->DevName); + else + xf86Msg(X_INFO, "I2C device \"%s:%s\" removed.\n", + d->pI2CBus->BusName, d->DevName); + + if (unalloc) delete p; + } +} + +/* I2C transmissions are related to an I2CDevRec you must link to a + * previously registered bus (see xf86I2CBusInit) before attempting + * to read and write data. You may call xf86I2CProbeAddress first to + * see if the device in question is present on this bus. + * + * xf86I2CDevInit will not allocate an I2CBusRec for you, instead you + * may enter a pointer to a statically allocated I2CDevRec or the (modified) + * result of xf86CreateI2CDevRec. + * + * If you don't specify timeouts for the device (n <= 0), it will inherit + * the bus-wide defaults. The function returns TRUE on success. + */ + +Bool +xf86I2CDevInit(I2CDevPtr d) +{ + I2CBusPtr b; + + if (d == NULL || + (b = d->pI2CBus) == NULL || + (d->SlaveAddr & 1) || + xf86I2CFindDev(b, d->SlaveAddr) != NULL) + return FALSE; + + if (d->BitTimeout <= 0) d->BitTimeout = b->BitTimeout; + if (d->ByteTimeout <= 0) d->ByteTimeout = b->ByteTimeout; + if (d->AcknTimeout <= 0) d->AcknTimeout = b->AcknTimeout; + if (d->StartTimeout <= 0) d->StartTimeout = b->StartTimeout; + + d->NextDev = b->FirstDev; + b->FirstDev = d; + + if(b->scrnIndex >= 0) + xf86DrvMsg(b->scrnIndex, X_INFO, "I2C device \"%s:%s\" registered.\n", + b->BusName, d->DevName); + else + xf86Msg(X_INFO, "I2C device \"%s:%s\" registered.\n", + b->BusName, d->DevName); + + return TRUE; +} + +I2CDevPtr +xf86I2CFindDev(I2CBusPtr b, I2CSlaveAddr addr) +{ + I2CDevPtr d; + + if (b) { + for (d = b->FirstDev; d != NULL; d = d->NextDev) + if (d->SlaveAddr == addr) + return d; + } + + return NULL; +} + +static I2CBusPtr I2CBusList; + +/* Allocates an I2CBusRec for you and initializes with propper defaults + * you may modify before calling xf86I2CBusInit. Your I2CBusRec must + * contain at least a BusName, a scrnIndex (or -1), and a complete set + * of either high or low level I2C function pointers. You may pass + * bus-wide timeouts, otherwise inplausible values will be replaced + * with safe defaults. + */ + +I2CBusPtr +xf86CreateI2CBusRec(void) +{ + I2CBusPtr b; + + b = (I2CBusPtr) new I2CBusRec; + + if (b != NULL) { + b->scrnIndex = -1; + b->HoldTime = 5; /* 100 kHz bus */ + b->BitTimeout = 5; + b->ByteTimeout = 5; + b->AcknTimeout = 5; + b->StartTimeout = 5; + b->RiseFallTime = RISEFALLTIME; + } + + return b; +} + +/* Unregister an I2C bus. If you got the I2CBusRec from xf86CreateI2CBusRec + * you should set to free it. If you set , the function + * xf86DestroyI2CDevRec will be called for all devices linked to the bus + * first, passing down the option. + */ + +void +xf86DestroyI2CBusRec(I2CBusPtr b, Bool unalloc, Bool devs_too) +{ + if (b) { + I2CBusPtr *p; + + /* Remove this from the list of active I2C busses. */ + + for (p = &I2CBusList; *p != NULL; p = &(*p)->NextBus) + if (*p == b) { + *p = (*p)->NextBus; + break; + } + + if (b->FirstDev != NULL) { + if (devs_too) { + I2CDevPtr d; + + while ((d = b->FirstDev) != NULL) + xf86DestroyI2CDevRec(d, unalloc); + } else { + if (unalloc) { + xf86Msg(X_ERROR, "i2c bug: Attempt to remove I2C bus \"%s\", " + "but device list is not empty.\n", + b->BusName); + return; + } + } + } + + if (b->scrnIndex >= 0) + xf86DrvMsg(b->scrnIndex, X_INFO, "I2C bus \"%s\" removed.\n", + b->BusName); + else + xf86Msg(X_INFO, "I2C bus \"%s\" removed.\n", b->BusName); + + if (unalloc) delete b; + } +} + +/* I2C masters have to register themselves using this function. + * It will not allocate an I2CBusRec for you, instead you may enter + * a pointer to a statically allocated I2CBusRec or the (modified) + * result of xf86CreateI2CBusRec. Returns TRUE on success. + * + * At this point there won't be any traffic on the I2C bus. + */ + +Bool +xf86I2CBusInit(I2CBusPtr b) +{ + /* I2C busses must be identified by a unique scrnIndex + * and name. If scrnIndex is unspecified (a negative value), + * then the name must be unique throughout the server. + */ + + if (b->BusName == NULL || + xf86I2CFindBus(b->scrnIndex, b->BusName) != NULL) + return FALSE; + + /* If the high level functions are not + * supplied, use the generic functions. + * In this case we need the low-level + * function. + */ + + if (b->I2CPutBits == NULL || + b->I2CGetBits == NULL) + { + if (b->I2CPutByte == NULL || + b->I2CGetByte == NULL || + b->I2CAddress == NULL || + b->I2CStop == NULL) + return FALSE; + } else { + b->I2CPutByte = I2CPutByte; + b->I2CGetByte = I2CGetByte; + b->I2CAddress = I2CAddress; + b->I2CStop = I2CStop; + } + + if (b->I2CUDelay == NULL) + b->I2CUDelay = I2CUDelay; + + if (b->HoldTime < 2) b->HoldTime = 5; + if (b->BitTimeout <= 0) b->BitTimeout = b->HoldTime; + if (b->ByteTimeout <= 0) b->ByteTimeout = b->HoldTime; + if (b->AcknTimeout <= 0) b->AcknTimeout = b->HoldTime; + if (b->StartTimeout <= 0) b->StartTimeout = b->HoldTime; + + /* Put new bus on list. */ + + b->NextBus = I2CBusList; + I2CBusList = b; + + if (b->scrnIndex >= 0) + xf86DrvMsg(b->scrnIndex, X_INFO, "I2C bus \"%s\" initialized.\n", + b->BusName); + else + xf86Msg(X_INFO, "I2C bus \"%s\" initialized.\n", b->BusName); + + return TRUE; +} + +I2CBusPtr +xf86I2CFindBus(int scrnIndex, char *name) +{ + I2CBusPtr p; + + if (name != NULL) + for (p = I2CBusList; p != NULL; p = p->NextBus) + if (scrnIndex < 0 || p->scrnIndex == scrnIndex) + if (!strcmp(p->BusName, name)) + return p; + + return NULL; +} diff --git a/plugins/GPUSensors/NVClockX/NVClock/xf86i2c.h b/plugins/GPUSensors/NVClockX/NVClock/xf86i2c.h new file mode 100644 index 0000000..8d2eaa6 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/xf86i2c.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 1998 Itai Nahshon, Michael Schimek + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/i2c/xf86i2c.h,v 1.4 1999/04/11 13:11:01 dawes Exp $ */ +#ifndef _XF86I2C_H +#define _XF86I2C_H + +#include "xfree.h" + +typedef unsigned char I2CByte; +typedef unsigned short I2CSlaveAddr; + +typedef struct _I2CBusRec *I2CBusPtr; +typedef struct _I2CDevRec *I2CDevPtr; + +/* I2C masters have to register themselves */ + +typedef struct _I2CBusRec { + char * BusName; + int scrnIndex; + + void (*I2CUDelay) (I2CBusPtr b, int usec); + + void (*I2CPutBits)(I2CBusPtr b, int scl, int sda); + void (*I2CGetBits)(I2CBusPtr b, int *scl, int *sda); + + /* Look at the generic routines to see how these functions should behave. */ + + Bool (*I2CAddress)(I2CDevPtr d, I2CSlaveAddr); + void (*I2CStop) (I2CDevPtr d); + Bool (*I2CPutByte)(I2CDevPtr d, I2CByte data); + Bool (*I2CGetByte)(I2CDevPtr d, I2CByte *data, Bool); + + DevUnion DriverPrivate; + + int HoldTime; /* 1 / bus clock frequency, 5 or 2 usec */ + + int BitTimeout; /* usec */ + int ByteTimeout; /* usec */ + int AcknTimeout; /* usec */ + int StartTimeout; /* usec */ + int RiseFallTime; /* usec */ + + I2CDevPtr FirstDev; + I2CBusPtr NextBus; +} I2CBusRec; + +I2CBusPtr xf86CreateI2CBusRec(void); +void xf86DestroyI2CBusRec(I2CBusPtr pI2CBus, Bool unalloc, Bool devs_too); +Bool xf86I2CBusInit(I2CBusPtr pI2CBus); +I2CBusPtr xf86I2CFindBus(int scrnIndex, char *name); + +/* I2C slave devices */ + +typedef struct _I2CDevRec { + char * DevName; + + int BitTimeout; /* usec */ + int ByteTimeout; /* usec */ + int AcknTimeout; /* usec */ + int StartTimeout; /* usec */ + + short chip_id; /* type of i2c chip; required atleast by the lm99 to decide whether to add an offset or not */ + int arch; /* architecture to which the gpu belongs; the lm99 code needs this for adding offsets too */ + char *chip_name; + + I2CSlaveAddr SlaveAddr; + I2CBusPtr pI2CBus; + I2CDevPtr NextDev; +} I2CDevRec; + +I2CDevPtr xf86CreateI2CDevRec(void); +void xf86DestroyI2CDevRec(I2CDevPtr pI2CDev, Bool unalloc); +Bool xf86I2CDevInit(I2CDevPtr pI2CDev); +I2CDevPtr xf86I2CFindDev(I2CBusPtr, I2CSlaveAddr); + +/* See descriptions of these functions in xf86i2c.c */ + +Bool xf86I2CProbeAddress(I2CBusPtr pI2CBus, I2CSlaveAddr); +Bool xf86I2CWriteRead(I2CDevPtr d, I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead); +#define xf86I2CRead(d, rb, nr) xf86I2CWriteRead(d, NULL, 0, rb, nr) +Bool xf86I2CReadStatus(I2CDevPtr d, I2CByte *pbyte); +Bool xf86I2CReadByte(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte); +Bool xf86I2CReadBytes(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte, int n); +Bool xf86I2CReadWord(I2CDevPtr d, I2CByte subaddr, unsigned short *pword); +#define xf86I2CWrite(d, wb, nw) xf86I2CWriteRead(d, wb, nw, NULL, 0) +Bool xf86I2CWriteByte(I2CDevPtr d, I2CByte subaddr, I2CByte byte); +Bool xf86I2CWriteBytes(I2CDevPtr d, I2CByte subaddr, I2CByte *WriteBuffer, int nWrite); +Bool xf86I2CWriteWord(I2CDevPtr d, I2CByte subaddr, unsigned short word); +Bool xf86I2CWriteVec(I2CDevPtr d, I2CByte *vec, int nValues); + +#endif /*_XF86I2C_H */ diff --git a/plugins/GPUSensors/NVClockX/NVClock/xfree.h b/plugins/GPUSensors/NVClockX/NVClock/xfree.h new file mode 100644 index 0000000..5483da8 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClock/xfree.h @@ -0,0 +1,76 @@ +/* NVTV xfree -- Dirk Thierbach + * + * Header: All definitions from xfree that are needed. + * + */ + +#ifndef _XFREE_H +#define _XFREE_H 1 + +//#include +//#include + +#define xf86Msg(type,format,args...) /* */ +#define xf86DrvMsg(scrnIndex,type,format, args...) /* */ + +#ifndef Bool +# ifndef _XTYPEDEF_BOOL +# define _XTYPEDEF_BOOL +typedef int Bool; +# endif +#endif + +#ifndef _XTYPEDEF_POINTER +# define _XTYPEDEF_POINTER +typedef void *pointer; +#endif + + +/* Flags for driver messages */ +typedef enum { + X_PROBED, /* Value was probed */ + X_CONFIG, /* Value was given in the config file */ + X_DEFAULT, /* Value is a default */ + X_CMDLINE, /* Value was given on the command line */ + X_NOTICE, /* Notice */ + X_ERROR, /* Error message */ + X_WARNING, /* Warning message */ + X_INFO, /* Informational message */ + X_NONE, /* No prefix */ + X_NOT_IMPLEMENTED /* Not implemented */ +} MessageType; + +typedef union _DevUnion { + pointer ptr; + long val; + unsigned long uval; + pointer (*fptr)(void); +} DevUnion; + + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +//void xf86usleep(unsigned long usec); +void xf86getsecs(long * secs, long * usecs); + +#define xcalloc(_num, _size) calloc(_num, _size) +#define xfree(_ptr) free(_ptr) + + +/* ---------------- nv driver files ---------------- */ + +/**** nv_dac.c */ + +#define DDC_SDA_READ_MASK (1 << 3) +#define DDC_SCL_READ_MASK (1 << 2) +#define DDC_SDA_WRITE_MASK (1 << 4) +#define DDC_SCL_WRITE_MASK (1 << 5) + + +#endif diff --git a/plugins/GPUSensors/NVClockX/NVClockX-Info.plist b/plugins/GPUSensors/NVClockX/NVClockX-Info.plist new file mode 100644 index 0000000..06311d8 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClockX-Info.plist @@ -0,0 +1,57 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + IOKitPersonalities + + NVClockX nVidia Cards Monitoring Plugin + + CFBundleIdentifier + org.usrsse2.${PRODUCT_NAME} + IOClass + NVClockX + IOMatchCategory + ${PRODUCT_NAME} + IOProbeScore + 2000 + IOProviderClass + IOResources + IOResourceMatch + IOKit + + + OSBundleLibraries + + com.apple.iokit.IOPCIFamily + 2.4 + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.mach + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + OSBundleRequired + Root + + diff --git a/plugins/GPUSensors/NVClockX/NVClockX-pre106-info.plist b/plugins/GPUSensors/NVClockX/NVClockX-pre106-info.plist new file mode 100644 index 0000000..aa64aeb --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClockX-pre106-info.plist @@ -0,0 +1,55 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.usrsse2.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + 1.0.1 + CFBundleSignature + ???? + CFBundleVersion + 1.0.1d1 + IOKitPersonalities + + NVClockX nVidia Cards Monitoring Plugin + + CFBundleIdentifier + org.usrsse2.${PRODUCT_NAME} + IOClass + NVClockX + IOMatchCategory + ${PRODUCT_NAME} + IOProviderClass + IOResources + IOResourceMatch + IOKit + + + OSBundleLibraries + + org.netkas.FakeSMC + 3.1.0 + com.apple.iokit.IOPCIFamily + 2.4 + com.apple.iokit.IOACPIFamily + 1.0.0d1 + com.apple.kernel.6.0 + 7.9.9 + com.apple.kernel.iokit + 7.9.9 + com.apple.kernel.libkern + 7.9.9 + + OSBundleRequired + Root + + diff --git a/plugins/GPUSensors/NVClockX/NVClockX.cpp b/plugins/GPUSensors/NVClockX/NVClockX.cpp new file mode 100644 index 0000000..cf59853 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClockX.cpp @@ -0,0 +1,420 @@ +/* + * NVClockX.cpp + * HWSensors + * + * Based on NVClock Darwin port by alphamerik (C) 2010 + * + * + * Created by mozo on 15/10/10. + * Copyright 2010 usr-sse2. All rights reserved. + * + */ + +#include "NVClockX.h" +#include "FakeSMC.h" +#include "utils.h" + +#include +#include +#include "backend.h" + +#define Debug FALSE + +/*#define LogPrefix "NVClockX: " + #define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) + #define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) + #define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0)*/ + +#define super IOService +OSDefineMetaClassAndStructors(NVClockX, IOService) + +NVClock nvclock; +NVCard* nv_card; + +bool is_digit(char c); + +bool is_digit(char c) { + if (((c>='0')&&(c<='9'))||((c>='a')&&(c<='f'))||((c>='A')&&(c<='F'))) { + return true; + } + + return false; +} + +int NVClockX::probeDevices() { + nvclock.num_cards=0; + + if (OSDictionary * dictionary = serviceMatching(kGenericPCIDevice)) { + if (OSIterator * iterator = getMatchingServices(dictionary)) { + IOPCIDevice* device = 0; + do { + device = OSDynamicCast(IOPCIDevice, iterator->getNextObject()); + if (!device) { + break; + } + UInt16 vendor_id=0; + +#if __LP64__ + mach_vm_address_t addr; + //mach_vm_size_t size; +#else + vm_address_t addr; + //vm_size_t size; +#endif + + OSString *string = OSDynamicCast(OSString, device->getProperty("IOName")); + OSData *data = OSDynamicCast(OSData, device->getProperty("vendor-id")); + + if (data) { + vendor_id = *(UInt32*)data->getBytesNoCopy(); + } + + if (string && string->isEqualTo("display") && vendor_id==0x10de) { + device->setMemoryEnable(true); + nvio = device->mapDeviceMemoryWithIndex(0); +#if __LP64__ + addr = (mach_vm_address_t)nvio->getVirtualAddress(); +#else + addr = (vm_address_t)nvio->getVirtualAddress(); +#endif + data = OSDynamicCast(OSData, device->getProperty("device-id")); + if (data) { + nvclock.card[nvclock.num_cards].device_id=*(UInt32*)data->getBytesNoCopy(); + nvclock.card[nvclock.num_cards].arch = get_gpu_arch(nvclock.card[nvclock.num_cards].device_id); + nvclock.card[nvclock.num_cards].number = nvclock.num_cards; + nvclock.card[nvclock.num_cards].card_name = (char*)get_card_name(nvclock.card[nvclock.num_cards].device_id, &nvclock.card[nvclock.num_cards].gpu); + nvclock.card[nvclock.num_cards].state = 0; + nvclock.card[nvclock.num_cards].reg_address = addr; + + //map_mem_card(&nvclock.card[nvclock.num_cards], addr); + // Map the registers of the nVidia chip + // normally pmc is till 0x2000 but extended it for nv40 + nvclock.card[nvclock.num_cards].PEXTDEV = (volatile unsigned int*)addr + 0x101000; + nvclock.card[nvclock.num_cards].PFB = (volatile unsigned int*)addr + 0x100000; + nvclock.card[nvclock.num_cards].PMC = (volatile unsigned int*)addr + 0x000000; + nvclock.card[nvclock.num_cards].PCIO = (volatile unsigned char*)addr + 0x601000; + nvclock.card[nvclock.num_cards].PDISPLAY = (volatile unsigned int*)addr + NV_PDISPLAY_OFFSET; + nvclock.card[nvclock.num_cards].PRAMDAC = (volatile unsigned int*)addr + 0x680000; + nvclock.card[nvclock.num_cards].PRAMIN = (volatile unsigned int*)addr + NV_PRAMIN_OFFSET; + nvclock.card[nvclock.num_cards].PROM = (volatile unsigned char*)addr + 0x300000; + + // On Geforce 8xxx cards it appears that the pci config header has been moved + if (nvclock.card[nvclock.num_cards].arch & NV5X) { + nvclock.card[nvclock.num_cards].PBUS = (volatile unsigned int*)addr + 0x88000; + } else { + nvclock.card[nvclock.num_cards].PBUS = nvclock.card[nvclock.num_cards].PMC + 0x1800/4; + } + + nvclock.card[nvclock.num_cards].mem_mapped = 1; + + InfoLog("Card: %d, Vendor ID: %x, Device ID: %x, Architecture: %x, %s", + nvclock.num_cards, + vendor_id, + nvclock.card[nvclock.num_cards].device_id, + nvclock.card[nvclock.num_cards].arch, + nvclock.card[nvclock.num_cards].card_name); + + nvclock.num_cards++; + } + } + } while(TRUE); + } + } + + if (nvclock.num_cards == 0) { + WarningLog("no nVidia graphics adapters found"); + } + + return nvclock.num_cards; +} + +bool NVClockX::addSensor(const char* key, const char* type, unsigned int size, int index) { + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)key, + (void *)type, + (void *)(long long)size, + (void *)this)) { + if (sensors->setObject(key, OSNumber::withNumber(index, 32))) { + return true; + } else { + WarningLog("%s key sensor not set", key); + return 0; + } + } + + WarningLog("%s key sensor not added", key); + + return 0; +} + +int NVClockX::addTachometer(int index) { + UInt8 length = 0; + void * data = 0; + + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, + true, + (void *)KEY_FAN_NUMBER, + (void *)&length, + (void *)&data, + 0)) { + length = 0; + + bcopy(data, &length, 1); + + char name[5]; + + snprintf(name, 5, KEY_FORMAT_FAN_SPEED, length); + + if (addSensor(name, TYPE_FPE2, 2, index)) { + + length++; + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCSetKeyValue, + true, + (void *)KEY_FAN_NUMBER, + (void *)1, + (void *)&length, + 0)) { + WarningLog("error updating FNum value"); + } + + return length-1; + } + } else { + WarningLog("error reading FNum value"); + } + + return -1; +} + +bool NVClockX::init(OSDictionary *properties) { + DebugLog("Initialising..."); + + if (!super::init(properties)) { return false; } + + if (!(sensors = OSDictionary::withCapacity(0))) { + return false; + } + + return true; +} + +IOService* NVClockX::probe(IOService *provider, SInt32 *score) { + DebugLog("Probing..."); + + if (super::probe(provider, score) != this) { return 0; } + + InfoLog("NVClock Darwin port by alphamerik (C) 2010"); + InfoLog("usr-sse2 (C) 2010"); + + return this; +} + +bool NVClockX::start(IOService * provider) { + DebugLog("Starting..."); + + if (!super::start(provider)) { return false; } + + if (!(fakeSMC = waitForService(serviceMatching(kFakeSMCDeviceService)))) { + WarningLog("Can't locate fake SMC device, kext will not load"); + return false; + } + + char key[7]; + + nvclock.dpy = NULL; + + if (!probeDevices()) { + char buf[80]; + WarningLog("%s", get_error(buf, 80)); + return false; + } + + for (int index = 0; index < nvclock.num_cards; index++) { + /* set the card object to the requested card */ + if (!set_card(index)){ + char buf[80]; + WarningLog("%s", get_error(buf, 80)); + return 0; + } + + nvbios* bios=read_bios(""); + nvclock.card[index].bios=bios; + + /* Check if the card is supported, if not print a message. */ + if (nvclock.card[index].gpu == UNKNOWN){ + WarningLog("it seems your card isn't officialy supported in FakeSMCnVclockPort yet"); + WarningLog("please tell the author the pci_id of the card for further investigation"); + WarningLog("continuing anyway"); + } + + if (nv_card->caps & (GPU_TEMP_MONITORING)) { + snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, index); + addSensor(key, TYPE_SP78, 2, index); + + if (nv_card->caps & BOARD_TEMP_MONITORING) { + snprintf(key, 5, KEY_FORMAT_GPU_BOARD_TEMPERATURE, index); + addSensor(key, TYPE_SP78, 2, index); + } + } + + if (nv_card->caps & (I2C_FANSPEED_MONITORING | GPU_FANSPEED_MONITORING)) { + int fanIndex = addTachometer(index); + + if (fanIndex > -1) { + char name[6]; + + snprintf(key, 5, KEY_FORMAT_FAN_ID, fanIndex); + snprintf (name, 6, "GPU %X", index); + + // fakeSMC->callPlatformFunction(kFakeSMCAddKeyValue, false, (void *)key, (void *)TYPE_CH8, (void *)strlen(name), (void *)name); + + FanTypeDescStruct fds; + fds.type = FAN_PWM_TACH; + fds.ui8Zone = 1; + fds.location = LEFT_LOWER_FRONT; + strncpy(fds.strFunction, name, DIAG_FUNCTION_STR_LEN); + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyValue, + false, + (void *)key, + (void *)TYPE_FDESC, + (void *)((UInt64)sizeof(fds)), + (void *)&fds)) { + + WarningLog("error adding tachometer id value"); + } + + } + } + + snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_FREQUENCY, index); + addSensor(key, TYPE_FREQ, 2, index); + + + OSNumber* fanKey = OSDynamicCast(OSNumber, getProperty("FanSpeedPercentage")); + + if ((fanKey!=NULL)&(nv_card->set_fanspeed!=NULL)) { + nv_card->set_fanspeed(fanKey->unsigned8BitValue()); + } + + OSNumber* speedKey=OSDynamicCast(OSNumber, getProperty("GPUSpeed")); + + if ((speedKey!=NULL)&(nv_card->caps&GPU_OVERCLOCKING)) { + InfoLog("Default speed %d", (UInt16)nv_card->get_gpu_speed()); + //InfoLog("%d", speedKey->unsigned16BitValue()); + nv_card->set_gpu_speed(speedKey->unsigned16BitValue()); + InfoLog("Overclocked to %d", (UInt16)nv_card->get_gpu_speed()); + } + + //snprintf(key, 5, "FGC%d", index); + //gpuFreqSensor[index] = new FrequencySensor(key, "freq", 2); + } + + return true; +} + +void NVClockX::stop (IOService* provider) { + DebugLog("Stoping..."); + + sensors->flushCollection(); + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCRemoveKeyHandler, + true, + this, + NULL, + NULL, + NULL)) { + WarningLog("Can't remove key handler"); + IOSleep(500); + } + + super::stop(provider); +} + +void NVClockX::free () { + DebugLog("Freeing..."); + + sensors->release(); + super::free(); +} + +IOReturn NVClockX::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4) { + if (functionName->isEqualTo(kFakeSMCGetValueCallback)) { + const char* key = (const char*)param1; + char * data = (char*)param2; + //UInt32 size = (UInt64)param3; + + if (key && data) { + if (OSNumber *number = OSDynamicCast(OSNumber, sensors->getObject(key))) { + + UInt32 index = number->unsigned16BitValue(); + + if (index < nvclock.num_cards) { + if (!set_card(index)){ + char buf[80]; + WarningLog("%s", get_error(buf, 80)); + return kIOReturnSuccess; + } + + UInt16 value = 0; + + switch (key[0]) { + case 'T': + switch (key[3]) { + case 'D': + if (nv_card->caps & GPU_TEMP_MONITORING) { + value = nv_card->get_gpu_temp(nv_card->sensor); + } + break; + case 'H': + if (nv_card->caps & BOARD_TEMP_MONITORING) { + value = nv_card->get_board_temp(nv_card->sensor); + } + break; + } + + //bcopy(&value, data, 2); + memcpy(data, &value, 2); + break; + case 'F': + switch (key[2]) { + case 'A': + if (nv_card->caps & I2C_FANSPEED_MONITORING) { + value = encode_fp2e(nv_card->get_i2c_fanspeed_rpm(nv_card->sensor)); + } else if (nv_card->caps & GPU_FANSPEED_MONITORING) { + value = encode_fp2e((UInt16)nv_card->get_fanspeed()); + } else { + value = 0; + } + + //bcopy(&value, data, 2); + memcpy(data, &value, 2); + + break; + case 'C': + value=(UInt16)nv_card->get_gpu_speed(); + + //bcopy(&value, data, 2); + memcpy(data, &value, 2); + + break; + } + } + return kIOReturnSuccess; + } + } + + return kIOReturnBadArgument; + } + + return kIOReturnBadArgument; + } + + return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); +} diff --git a/plugins/GPUSensors/NVClockX/NVClockX.h b/plugins/GPUSensors/NVClockX/NVClockX.h new file mode 100644 index 0000000..afdfc2b --- /dev/null +++ b/plugins/GPUSensors/NVClockX/NVClockX.h @@ -0,0 +1,46 @@ +/* + * NVClockX.h + * HWSensors + * + * Created by mozo on 15/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +#include +#include "NVClock/nvclock.h" + +#define kGenericPCIDevice "IOPCIDevice" +#define kNVGraphicsDevice "IONDRVDevice" + +//NVClock nvclock; +//NVCard* nv_card; + +class NVClockX : public IOService { + OSDeclareDefaultStructors(NVClockX) + +private: + IOService * fakeSMC; + OSDictionary * sensors; + + IOMemoryMap * nvio; + + int probeDevices(); + bool addSensor(const char* key, const char* type, unsigned int size, int index); + int addTachometer(int index); + +public: + virtual bool init(OSDictionary *properties=0); + virtual IOService* probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual void stop(IOService *provider); + virtual void free(void); + + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); + +}; diff --git a/plugins/GPUSensors/NVClockX/gpl.txt b/plugins/GPUSensors/NVClockX/gpl.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/plugins/GPUSensors/NVClockX/gpl.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/plugins/GPUSensors/RadeonMonitor/ATICard.cpp b/plugins/GPUSensors/RadeonMonitor/ATICard.cpp new file mode 100644 index 0000000..67a1573 --- /dev/null +++ b/plugins/GPUSensors/RadeonMonitor/ATICard.cpp @@ -0,0 +1,473 @@ +/* + * ATICard.cpp + * FakeSMCRadeon + * + * Created by Slice on 24.07.10. + * Copyright 2010 Applelife.ru. All rights reserved. + * + */ + +#include "ATICard.h" +#include "radeon_chipinfo_gen.h" +//#include "Sensor.h" +OSDefineMetaClassAndStructors(ATICard, OSObject) + +bool ATICard::initialize() { + IOMemoryMap * mmio5 = NULL; + rinfo = (RADEONCardInfo*)IOMalloc(sizeof(RADEONCardInfo)); + VCard->setMemoryEnable(true); + IOMemoryDescriptor * theDescriptor; + IOPhysicalAddress bar = (IOPhysicalAddress)((VCard->configRead32(kIOPCIConfigBaseAddress5)) & ~0x3f); + InfoLog("register space5=%08lx\n", (long unsigned int)bar); + theDescriptor = IOMemoryDescriptor::withPhysicalAddress (bar, 0x80000, kIODirectionOutIn); // | kIOMapInhibitCache); + + if(theDescriptor != NULL) { + mmio5 = theDescriptor->map(); + } + + /* + // PCI dump + for (int i=0; i<0xff; i +=16) { + IOLog("%02lx: ", (long unsigned int)i); + for (int j=0; j<16; j += 4) { + IOLog("%08lx ", (long unsigned int)VCard->configRead32(i+j)); + } + IOLog("\n"); + } + */ + //Test for ElCapitan problem +/* long unsigned int j = VCard->configRead32(0xAC); + IOLog("PMIR value: %08lx\n", j); + VCard->configWrite32(0xAC, (j & (~0x1)) | 0x2); + */ + // + /* + for (UInt32 i = 0; (mmio = VCard->mapDeviceMemoryWithIndex(i)); i++) { + long unsigned int mmio_base_phys = mmio->getPhysicalAddress(); + // Make sure we select MMIO registers + if (((mmio->getLength()) <= 0x00080000) && (mmio_base_phys != 0)) + break; + } + */ + mmio = VCard->mapDeviceMemoryWithIndex(1); + if (mmio) { + mmio_base = (volatile UInt8 *)mmio->getVirtualAddress(); + InfoLog("mmio_base=0x%llx\n", mmio->getPhysicalAddress()); + } else { + InfoLog(" have no mmio\n "); + return false; + } + + if(!getRadeonInfo()) { return false; } + + if (!mmio_base || rinfo->ChipFamily >= CHIP_FAMILY_HAWAII) { +// IOMemoryMap * mmio5; +// mmio5 = VCard->mapDeviceMemoryWithIndex(4); + if (mmio5 && mmio5->getPhysicalAddress() != 0) { + mmio = mmio5; + mmio_base = (volatile UInt8 *)mmio->getVirtualAddress(); + } + InfoLog(" use mmio5 at 0x%llx\n", (unsigned long long)mmio_base); + } + + switch (rinfo->ChipFamily) { + case CHIP_FAMILY_R600: + case CHIP_FAMILY_RV610: + case CHIP_FAMILY_RV630: + case CHIP_FAMILY_RV670: + //setup_R6xx(); + tempFamily = R6xx; + break; + case CHIP_FAMILY_R700: + case CHIP_FAMILY_R710: + case CHIP_FAMILY_R730: + case CHIP_FAMILY_RV740: + case CHIP_FAMILY_RV770: + case CHIP_FAMILY_RV790: + //setup_R7xx(); + tempFamily = R7xx; + break; + case CHIP_FAMILY_Evergreen: + //setup_Evergreen(); + tempFamily = R8xx; + break; + case CHIP_FAMILY_PITCAIRN: + case CHIP_FAMILY_TAHITI: + case CHIP_FAMILY_VERDE: + tempFamily = R9xx; + break; + case CHIP_FAMILY_HAWAII: + case CHIP_FAMILY_OLAND: + case CHIP_FAMILY_BONAIRE: + case CHIP_FAMILY_HAINAN: + case CHIP_FAMILY_TONGA: + tempFamily = RCIx; + break; + case CHIP_FAMILY_POLARIS: + tempFamily = RAIx; + break; + case CHIP_FAMILY_VEGA: + tempFamily = RVEx; + break; + + default: + InfoLog("sorry, but your card %04lx is not supported!\n", (long unsigned int)(rinfo->device_id)); + return false; + } + + return true; +} + +bool ATICard::getRadeonInfo() { + UInt16 devID = chipID & 0xffff; + + RADEONCardInfo *devices = radeon_device_list; + //rinfo = new RADEONCardInfo; + //old devices + while (devices->device_id != NULL) { + //IOLog("check %d/n", devices->device_id ); //Debug + if ((devices->device_id & 0xffff) == devID ) { + // rinfo->device_id = devID; + rinfo->device_id = devices->device_id; + rinfo->ChipFamily = devices->ChipFamily; + family = devices->ChipFamily; + rinfo->igp = devices->igp; + rinfo->is_mobility = devices->is_mobility; + IOLog(" Found ATI Radeon %04lx\n", (long unsigned int)devID); + return true; + } + devices++; + } + + //Vega + if (((devID >= 0x6860) && (devID <= 0x687F))) { //Vega + rinfo->device_id = devID; + rinfo->ChipFamily = CHIP_FAMILY_VEGA; + family = CHIP_FAMILY_VEGA; + rinfo->igp = 0; + rinfo->is_mobility = false; + InfoLog(" Common ATI Radeon VEGA DID=%04lx\n", (long unsigned int)devID); + return true; + + //Polaris + } else if (((devID >= 0x67C0) && (devID <= 0x67FF)) || //Polaris 10,11 + ((devID >= 0x6980) && (devID <= 0x699F)) //Polaris 12, RX550 + ) { + rinfo->device_id = devID; + rinfo->ChipFamily = CHIP_FAMILY_POLARIS; + family = CHIP_FAMILY_POLARIS; + rinfo->igp = 0; + rinfo->is_mobility = false; + InfoLog(" Common ATI Radeon Polaris DID=%04lx\n", (long unsigned int)devID); + return true; + + //SeaIsland R7-2xx, 3xx, 4xx, 5xx, + } else if (((devID >= 0x67A0) && (devID <= 0x67BF)) || //Hawaii + ((devID >= 0x6900) && (devID <= 0x693F)) || //Volcanic Island, Tonga + ((devID >= 0x6600) && (devID <= 0x663F)) || //Oland + ((devID >= 0x6640) && (devID <= 0x666F))) { //Bonair & Hainan + rinfo->device_id = devID; + rinfo->ChipFamily = CHIP_FAMILY_HAWAII; + family = CHIP_FAMILY_HAWAII; + rinfo->igp = 0; + rinfo->is_mobility = false; + InfoLog(" Common ATI Radeon SeaIsland DID=%04lx\n", (long unsigned int)devID); + return true; + //SouthernIsland HD7xxx + } else if (((devID >= 0x6780) && (devID <= 0x679F)) || //Tahiti + ((devID >= 0x6800) && (devID <= 0x683F))) { //Pitcairn, Verde + + rinfo->device_id = devID; + rinfo->ChipFamily = CHIP_FAMILY_PITCAIRN; + family = CHIP_FAMILY_PITCAIRN; + rinfo->igp = 0; + rinfo->is_mobility = false; + InfoLog(" Common ATI Radeon SouthernIsland DID=%04lx\n", (long unsigned int)devID); + return true; + //Evergreen HD5xxx and NothenIsland HD6xxx + } else if (((devID & 0xFF00) == 0x6700) || ((devID & 0xFF00) == 0x6800)) { + rinfo->device_id = devID; + rinfo->ChipFamily = CHIP_FAMILY_Evergreen; + family = CHIP_FAMILY_Evergreen; + rinfo->igp = 0; + rinfo->is_mobility = false; + InfoLog(" Common ATI Radeon Evergreen/NothenIsland DID=%04lx\n", (long unsigned int)devID); + // IOLog("sorry, not supported yet, please report DeviceID=0x%x\n", devID); + return true; + } + + InfoLog("Unknown DeviceID!\n"); + return false; +} +/* +void ATICard::setup_R6xx() { + char key[5]; + int id = GetNextUnusedKey(KEY_FORMAT_GPU_DIODE_TEMPERATURE, key); + if (id == -1) { + InfoLog("No new GPU SMC key!\n"); + return; + } + card_number = id; + tempSensor = new R6xxTemperatureSensor(this, id, key, TYPE_SP78, 2); + Caps = GPU_TEMP_MONITORING; +} + +void ATICard::setup_R7xx() { + char key[5]; + int id = GetNextUnusedKey(KEY_FORMAT_GPU_DIODE_TEMPERATURE, key); + if (id == -1) { + InfoLog("No new GPU SMC key!\n"); + return; + } + card_number = id; + tempSensor = new R7xxTemperatureSensor(this, id, key, TYPE_SP78, 2); + Caps = GPU_TEMP_MONITORING; +} + +void ATICard::setup_Evergreen() { + char key[5]; + int id = GetNextUnusedKey(KEY_FORMAT_GPU_DIODE_TEMPERATURE, key); + if (id == -1) { + InfoLog("No new GPU SMC key!\n"); + return; + } + card_number = id; + tempSensor = new EverTemperatureSensor(this, id, key, TYPE_SP78, 2); + Caps = GPU_TEMP_MONITORING; +} +*/ +UInt32 ATICard::read32(UInt32 reg) { + return INVID(reg); +} + +void ATICard::write32(UInt32 reg, UInt32 val) { + return OUTVID(reg, val); +} + +//read_ind_pcie -> +/* +WREG32(mmPCIE_INDEX, reg); +(void)RREG32(mmPCIE_INDEX); +r = RREG32(mmPCIE_DATA); +*/ + +//GetClock +/* +PPSMC_Result amdgpu_ci_send_msg_to_smc(struct amdgpu_device *adev, PPSMC_Msg msg) { + u32 tmp; + int i; + + if (!amdgpu_ci_is_smc_running(adev)) { + return PPSMC_Result_Failed; + } + + WREG32(mmSMC_MESSAGE_0, msg); + + for (i = 0; i < adev->usec_timeout; i++) { + tmp = RREG32(mmSMC_RESP_0); + if (tmp != 0) { + break; + } + udelay(1); + } + tmp = RREG32(mmSMC_RESP_0); + + return (PPSMC_Result)tmp; +} + +amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_API_GetSclkFrequency); //SCLK +amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_API_GetMclkFrequency); //MCLK +clock = RREG32(mmSMC_MSG_ARG_0); units=100MHz + +//get FAN +#define CG_THERMAL_STATUS 0xC0300008 +#define FDO_PWM_DUTY(x) ((x) << 9) +#define FDO_PWM_DUTY_MASK (0xff << 9) +#define FDO_PWM_DUTY_SHIFT 9 +#define CG_FDO_CTRL1 0xC0300068 +#define FMAX_DUTY100(x) ((x) << 0) +#define FMAX_DUTY100_MASK 0x000000FF +#define FMAX_DUTY100_SHIFT 0 +RREG32_SMC based on 0x200 +cik -> mmSMC_IND_INDEX_0 0x200 +si -> SMC_IND_INDEX_0 0x200 +vi -> mmSMC_IND_INDEX_11 0x1AC => 0x6b0 +ni -> TN_SMC_IND_INDEX_0 0x200 +cz -> +#define mmMP0PUB_IND_INDEX 0x180 => 0x600 +#define mmMP0PUB_IND_DATA 0x181 + + +int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev, u32 *speed) { + u32 duty, duty100; + u64 tmp64; + + if (rdev->pm.no_fan) + return -ENOENT; + + duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT; + duty = (RREG32_SMC(CG_THERMAL_STATUS) & FDO_PWM_DUTY_MASK) >> FDO_PWM_DUTY_SHIFT; + + if (duty100 == 0) + return -EINVAL; + + tmp64 = (u64)duty * 100; + do_div(tmp64, duty100); + *speed = (u32)tmp64; + + if (*speed > 100) { + *speed = 100; + } + + return 0; +} +*/ + +UInt32 ATICard::read_smc(UInt32 reg) { + UInt32 r; + OUTVID(SMC_IND_INDEX_0, (reg)); + r = INVID(SMC_IND_DATA_0); + return r; +} + + +UInt32 ATICard::read_ind(UInt32 reg) { + //unsigned long flags; + UInt32 r; + //spin_lock_irqsave(&rdev->smc_idx_lock, flags); + OUTVID(mmSMC_IND_INDEX_11, (reg)); + r = INVID(mmSMC_IND_DATA_11); + //spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); + return r; +} + +IOReturn ATICard::R6xxTemperatureSensor(UInt16* data) { + UInt32 temp, actual_temp = 0; + for (int i=0; i<1000; i++) { //attempts to ready + temp = (read32(CG_THERMAL_STATUS) & ASIC_T_MASK) >> ASIC_T_SHIFT; + if ((temp >> 7) & 1) { + actual_temp = 0; + } else { + actual_temp = temp & 0xff; //(temp >> 1) + break; + } + IOSleep(10); + } + *data = (UInt16)(actual_temp & 0x1ff); + //data[1] = 0; + return kIOReturnSuccess; +} + +IOReturn ATICard::R7xxTemperatureSensor(UInt16* data) { + UInt32 temp, actual_temp = 0; + for (int i=0; i<1000; i++) { //attempts to ready + temp = (read32(CG_MULT_THERMAL_STATUS) & ASIC_TM_MASK) >> ASIC_TM_SHIFT; + if ((temp >> 9) & 1) { + actual_temp = 0; + } else { + actual_temp = (temp >> 1) & 0xff; + break; + } + IOSleep(10); + } + + *data = (UInt16)(actual_temp & 0x1ff); + //data[1] = 0; + return kIOReturnSuccess; +} + +IOReturn ATICard::EverTemperatureSensor(UInt16* data) { + UInt32 temp, actual_temp = 0; + for (int i=0; i<1000; i++) { //attempts to ready + temp = (read32(CG_MULT_THERMAL_STATUS) & ASIC_TM_MASK) >> ASIC_TM_SHIFT; + if ((temp >> 10) & 1) { + actual_temp = 0; + } else if ((temp >> 9) & 1) { + actual_temp = 255; + } else { + actual_temp = (temp >> 1) & 0xff; + break; + } + IOSleep(10); + } + + *data = (UInt16)(actual_temp & 0x1ff); + //data[1] = 0; + return kIOReturnSuccess; +} + +IOReturn ATICard::TahitiTemperatureSensor(UInt16* data) { + UInt32 temp, actual_temp = 0; + for (int i=0; i<1000; i++) { //attempts to ready + temp = (read32(CG_SI_THERMAL_STATUS) & CTF_TEMP_MASK) >> CTF_TEMP_SHIFT; + if ((temp >> 10) & 1) { + actual_temp = 0; + } else if ((temp >> 9) & 1){ + actual_temp = 255; + } else { + actual_temp = temp; //(temp >> 1) & 0xff; + break; + } + IOSleep(10); + } + + *data = (UInt16)(actual_temp & 0x1ff); + //data[1] = 0; + return kIOReturnSuccess; +} + +IOReturn ATICard::HawaiiTemperatureSensor(UInt16* data) { + UInt32 temp, actual_temp = 0; + for (int i=0; i<1000; i++) { //attempts to ready + temp = (read_smc(CG_CI_MULT_THERMAL_STATUS) & CI_CTF_TEMP_MASK) >> CI_CTF_TEMP_SHIFT; + if ((temp >> 10) & 1) { + actual_temp = 0; + } else if ((temp >> 9) & 1) { + actual_temp = 255; + } else { + actual_temp = temp & 0x1ff; //(temp >> 1) & 0xff; + break; + } + IOSleep(10); + } + + *data = (UInt16)(actual_temp & 0x1ff); + //data[1] = 0; + return kIOReturnSuccess; +} + +IOReturn ATICard::ArcticTemperatureSensor(UInt16* data) { + UInt32 temp, actual_temp = 0; + for (int i=0; i<1000; i++) { //attempts to ready + temp = (read_ind(CG_CI_MULT_THERMAL_STATUS) & CI_CTF_TEMP_MASK) >> CI_CTF_TEMP_SHIFT; + if ((temp >> 10) & 1) { + actual_temp = 0; + } else if ((temp >> 9) & 1) { + actual_temp = 255; + } else { + actual_temp = temp & 0x1ff; //(temp >> 1) & 0xff; + break; + } + IOSleep(10); + } + + *data = (UInt16)(actual_temp & 0x1ff); + //data[1] = 0; + return kIOReturnSuccess; +} + +//#define mmTHM_TCON_CUR_TMP 0x59800 +//#define THM_TCON_CUR_TMP__CUR_TEMP__SHIFT 24 + +IOReturn ATICard::VegaTemperatureSensor(UInt16* data) { + UInt32 temp, actual_temp = 0; + + temp = read32(mmTHM_TCON_CUR_TMP) >> THM_TCON_CUR_TMP__CUR_TEMP__SHIFT; + actual_temp = temp & 0x1ff; + *data = (UInt16)actual_temp; + + return kIOReturnSuccess; +} + + + diff --git a/plugins/GPUSensors/RadeonMonitor/ATICard.h b/plugins/GPUSensors/RadeonMonitor/ATICard.h new file mode 100644 index 0000000..fb6565b --- /dev/null +++ b/plugins/GPUSensors/RadeonMonitor/ATICard.h @@ -0,0 +1,96 @@ +/* + * ATICard.h + * FakeSMCRadeon + * + * Created by Slice on 24.07.10. + * Copyright 2010 Applelife.ru. All rights reserved. + * + */ + +#ifndef _ATICARD_H +#define _ATICARD_H + +#include +#include +#include "FakeSMC.h" +#include "radeon_chipsets.h" + +#define GPU_OVERCLOCKING (1<<0) +#define MEM_OVERCLOCKING (1<<1) +#define COOLBITS_OVERCLOCKING (1<<2) +#define PIPELINE_MODDING (1<<3) +#define GPU_FANSPEED_MONITORING (1<<4) /* Fanspeed monitoring based on fan voltage */ +#define BOARD_TEMP_MONITORING (1<<5) /* Board temperature */ +#define GPU_TEMP_MONITORING (1<<6) /* Internal GPU temperature */ +#define I2C_FANSPEED_MONITORING (1<<7) /* Fanspeed monitoring using a i2c sensor chip */ +#define I2C_AUTOMATIC_FANSPEED_CONTROL (1<<8) /* The sensor supports automatic fanspeed control */ +#define SMARTDIMMER (1<<9) /* Smartdimmer support for mobile GPUs */ +#define GPU_ID_MODDING (1<<10) /* PCI id modding is supported on this board */ + + +#define INVID8(offset) (mmio_base[offset]) +#define INVID16(offset) OSReadLittleInt16((mmio_base), offset) +#define INVID(offset) OSReadLittleInt32((mmio_base), offset) +#define OUTVID(offset,val) OSWriteLittleInt32((mmio_base), offset, val) + +#define Debug FALSE + +#define LogPrefix "RadeonMonitor: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +enum TempFamilies { + R5xx, + R6xx, + R7xx, + R8xx, + R9xx, + RCIx, + RAIx, + RVEx, +}; + +class ATICard : public OSObject { + OSDeclareDefaultStructors(ATICard) + +public: + UInt32 chipID; + UInt16 family; + IOPCIDevice * VCard; + RADEONCardInfo* rinfo; + int tempFamily; + +private: + volatile UInt8* mmio_base; + IOMemoryMap * mmio; + UInt32 Caps; + UInt32 tReg; + int card_number; + + + bool getRadeonInfo (); + +protected: +// IOService* m_Service; //??? +public: + // Binding* tempSensor; + // Binding* boardSensor; + // Binding* fanSensor; + UInt32 read32(UInt32 reg); + void write32(UInt32 reg, UInt32 val); + UInt32 read_ind(UInt32 reg); + UInt32 read_smc(UInt32 reg); + + bool initialize(void); + IOReturn R6xxTemperatureSensor(UInt16* data); + IOReturn R7xxTemperatureSensor(UInt16* data); + IOReturn EverTemperatureSensor(UInt16* data); + IOReturn TahitiTemperatureSensor(UInt16* data); + IOReturn HawaiiTemperatureSensor(UInt16* data); + IOReturn ArcticTemperatureSensor(UInt16* data); + IOReturn VegaTemperatureSensor(UInt16* data); +}; + + +#endif diff --git a/plugins/GPUSensors/RadeonMonitor/ATI_Device_ID_List_Jun_2010.txt b/plugins/GPUSensors/RadeonMonitor/ATI_Device_ID_List_Jun_2010.txt new file mode 100644 index 0000000..a49f0d7 --- /dev/null +++ b/plugins/GPUSensors/RadeonMonitor/ATI_Device_ID_List_Jun_2010.txt @@ -0,0 +1,111 @@ +// { ATI Vendor ID: 0x1002 } + +// Retail name, ASIC, Device ID + +VENDOR ID 1002 +Product ASIC Table + +{ ATI All-in-Wonder HD" , RV630, 9598} +{ ATI Radeon HD 2350" , RV610, 94C7} +{ ATI Radeon HD 2350 Series" , RV610, 94C3} +{ ATI Radeon HD 2400 Series" , RV610, 94C3} +{ ATI Radeon HD 2400 Series " , RV610, 94C1} +{ ATI Radeon HD 2400 Series " , RV610, 94CC} +{ ATI Radeon HD 2400 LE " , RV610, 94C3} +{ ATI Radeon HD 2400 PRO " , RV610, 94C3} +{ ATI Radeon HD 2400 XT " , RV610, 94C1} +{ ATI Radeon HD 2600 PRO" , RV630, 9589} +{ ATI Radeon HD 2600 X2 Series" , RV630, 958A} +{ ATI Radeon HD 2600 XT" , RV630, 9588} +{ ATI Radeon HD 2900 GT" , R600, 9405} +{ ATI Radeon HD 2900 XT " , R600, 9400} +{ ATI Radeon HD 2900 PRO" , R600, 9400} +{ ATI Radeon HD 2900 XT" , R600, 9400} +{ ATI Radeon 3100 Graphics" , RS780, 9611} +{ ATI Radeon HD 3200 Graphics" , RS780, 9610} +{ ATI Radeon HD 3300 Graphics" , RS780D, 9614} +{ ATI Radeon HD 3400 Series" , RV610, 95C0} +{ ATI Radeon HD 3400 Series " , RV610, 95C5} +{ ATI Radeon HD 3410" , RV610, 94C3} +{ ATI Radeon HD 3450" , RV610, 95C5} +{ ATI Radeon HD 3550 " , RV610, 95C0} +{ ATI Radeon HD 3550 " , RV610, 95C5} +{ ATI Radeon HD 3570" , RV610, 95C0} +{ ATI Radeon HD 3600 Series " , RV630, 9598} +{ ATI Radeon HD 3600 Series" , RV630, 9589} +{ ATI Radeon HD 3610" , RV630, 9589} +{ ATI Radeon HD 3690 " , RV630, 9501} +{ ATI Radeon HD 3690 " , RV630, 9505} +{ ATI Radeon HD 3730" , RV630, 9598} +{ ATI Radeon HD3750" , RV630, 9598} +{ ATI Radeon HD 3800 Series" , RV630, 9501} +{ ATI Radeon HD 3800 Series " , RV630, 9505} +{ ATI Radeon HD 3830" , RV630, 9507} +{ ATI Radeon HD 3850 " , RV630, 9505} +{ ATI Radeon HD 3850 X2" , RV630, 9513} +{ ATI Radeon HD 3870" , RV630, 9501} +{ ATI Radeon HD 3870 X2" , RV630, 950F} +{ ATI Radeon HD 4200" , RS880, 9710} +{ ATI Radeon HD 4230" , RV610, 95C5} +{ ATI Radeon HD 4250 " , RV610, 95C5} +{ ATI Radeon HD 4250 " , RS880, 9715} +{ ATI Radeon HD 4290" , RS880, 9714} +{ ATI Radeon HD 4300/4500 Series" , R710, 954F} +{ ATI Radeon HD 4520" , R710, 954F} +{ ATI Radeon HD 4550 " , R710, 9540} +{ ATI Radeon HD 4450" , R710, 954F} +{ ATI Radeon HD 4570 " , RV630, 9598} +{ ATI Radeon HD 4580 " , RV630, 9598} +{ ATI Radeon HD 4590 " , R730, 9540} +{ ATI Radeon HD 4600 Series " , R730, 9490} +{ ATI Radeon HD 4600 Series" , R730, 9498} +{ ATI Radeon HD 4610 " , RV630, 9598} +{ ATI Radeon HD 4650" , R730, 9498} +{ ATI Radeon HD 4670" , R730, 9498} +{ ATI Radeon HD 4700 Series " , RV770, 944E} +{ ATI Radeon HD 4700 Series " , RV740, 94B4} +{ ATI Radeon HD 4700" , R730, 9498} +{ ATI Radeon HD 4710" , R730, 9490} +{ ATI Radeon HD 4720" , R730, 9498} +{ ATI Radeon HD 4730 Series" , RV770, 944E} +{ ATI Radeon HD 4730" , RV630, 9505} +{ ATI Radeon HD 4750 " , RV630, 9501} +{ ATI Radeon HD 4750 " , RV630, 9505} +{ ATI Radeon HD 4770" , RV740, 94B3} +{ ATI Radeon HD 4770 " , RV740, 94B5} +{ ATI Radeon HD 4800 Series " , RV770, 9440} +{ ATI Radeon HD 4800 Series " , RV770, 9442} +{ ATI Radeon HD 4800 Series " , RV770, 944C} +{ ATI Radeon HD 4800 Series " , RV790, 9460} +{ ATI Radeon HD 4800 Series " , RV790, 9462} +{ ATI Radeon HD 4800 Series " , M98, 944A} +{ ATI Radeon HD 4810 Series " , RV770, 944E} +{ ATI Radeon HD 4820" , RV770, 944E} +{ ATI Radeon HD 4830" , RV770, 944C} +{ ATI Radeon HD 4850 X2" , RV700, 9443} +{ ATI Radeon HD 4850" , RV770, 9442} +{ ATI Radeon HD 4870" , RV770, 9440} +{ ATI Radeon HD 4870 X2 " , RV700, 9441} +{ ATI Radeon HD 5400 Series" , EvergreenC, 68F9} +{ ATI Radeon HD 5470" , EvergreenC, 68F9} +{ ATI Radeon HD 5490 " , EvergreenC, 68F9} +{ ATI Radeon HD 5500 Series" , Evergreen, 68D9} +{ ATI Radeon HD 5500 Series " , Evergreen, 68DA} +{ ATI Radeon HD 5530" , EvergreenC, 68F9} +{ ATI Radeon HD 5600 Series" , Evergreen, 68D8} +{ ATI Radeon HD 5600 Series " , Evergreen, 68B9} +{ ATI Radeon HD 5630 " , Evergreen, 68D9} +{ ATI Radeon HD 5630 " , Evergreen, 68DA} +{ ATI Radeon HD 5690" , Evergreen, 68D8} +{ ATI Radeon HD 5730" , Evergreen, 68D8} +{ ATI Radeon HD 5700 Series" , Evergreen, 68B8} +{ ATI Radeon HD 5700 Series " , Evergreen, 68BE} +{ ATI Radeon HD 5800 Series" , Evergreen, 6898} +{ ATI Radeon HD 5800 Series " , Evergreen, 6899} +{ ATI Radeon HD 5800 Series " , Evergreen, 689E} +{ ATI Radeon HD 5900 Series" , EvergreenH, 689C} +{"AMD 760G" , RS780, 9616} +{"AMD FireStream 9170" , RV630, 9519} +{"AMD FireStream 9250" , RV770, 9452} +{"AMD FireStream 9270" , RV770, 9450} + diff --git a/plugins/GPUSensors/RadeonMonitor/Radeon.cpp b/plugins/GPUSensors/RadeonMonitor/Radeon.cpp new file mode 100644 index 0000000..4a07098 --- /dev/null +++ b/plugins/GPUSensors/RadeonMonitor/Radeon.cpp @@ -0,0 +1,310 @@ +/* + * Radeon.cpp + * HWSensors + * + * Created by Sergey on 20.12.10. + * Copyright 2010 Slice. All rights reserved. + * + */ + +#include "Radeon.h" + + +#define kGenericPCIDevice "IOPCIDevice" +#define kTimeoutMSecs 1000 +#define fVendor "vendor-id" +#define fATYVendor "ATY,VendorID" +#define fDevice "device-id" +#define fClass "class-code" +#define kIOPCIConfigBaseAddress0 0x10 + +#define INVID8(offset) (mmio_base[offset]) +#define INVID16(offset) OSReadLittleInt16((mmio_base), offset) +#define INVID(offset) OSReadLittleInt32((mmio_base), offset) +#define OUTVID(offset,val) OSWriteLittleInt32((mmio_base), offset, val) + +//TODO +/* +CARD32 +_RHDReadPLL(int scrnIndex, CARD16 offset) +{ + _RHDRegWrite(scrnIndex, CLOCK_CNTL_INDEX, (offset & PLL_ADDR)); + return _RHDRegRead(scrnIndex, CLOCK_CNTL_DATA); +} +*/ + +#define super IOService +OSDefineMetaClassAndStructors(RadeonMonitor, IOService) + +bool RadeonMonitor::addSensor(const char* key, const char* type, unsigned int size, int index) { + void *tmp = (void *)(long long)size; + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)key, + (void *)type, + tmp, + (void *)this)) { + return sensors->setObject(key, OSNumber::withNumber(index, 32)); + } + return false; +} + +IOService* RadeonMonitor::probe(IOService *provider, SInt32 *score) { + if (super::probe(provider, score) != this) { return 0; } + bool ret = 0; + if (OSDictionary * dictionary = serviceMatching(kGenericPCIDevice)) { + if (OSIterator * iterator = getMatchingServices(dictionary)) { + IOPCIDevice* device = 0; + do { + device = OSDynamicCast(IOPCIDevice, iterator->getNextObject()); + if (!device) { + break; + } + vendor_id = 0; + OSData *data = OSDynamicCast(OSData, device->getProperty(fVendor)); + if (data) { + vendor_id = *(UInt32*)data->getBytesNoCopy(); + } else { + data = OSDynamicCast(OSData, device->getProperty(fATYVendor)); + if (data) { + vendor_id = *(UInt32*)data->getBytesNoCopy(); + } + } + + device_id = 0; + data = OSDynamicCast(OSData, device->getProperty(fDevice)); + if (data) { + device_id = *(UInt32*)data->getBytesNoCopy(); + } + + class_id = 0; + data = OSDynamicCast(OSData, device->getProperty(fClass)); + if (data) { + class_id = *(UInt32*)data->getBytesNoCopy(); + } + + if ((vendor_id==0x1002) && (class_id == 0x030000)) { + InfoLog("found Radeon chip id=%x ", (unsigned int)device_id); + VCard = device; + ret = 1; //TODO - count a number of cards + break; + } + /*else { + WarningLog("ATI Radeon not found!"); + }*/ + } while (device); + } + } + + if(ret) { + return this; + } + + return 0; +} + +bool RadeonMonitor::start(IOService * provider) { + if (!provider || !super::start(provider)) { return false; } + + if (!(fakeSMC = waitForService(serviceMatching(kFakeSMCDeviceService)))) { + WarningLog("Can't locate fake SMC device, kext will not load"); + return false; + } + + Card = new ATICard(); + Card->VCard = VCard; + Card->chipID = device_id; + if(Card->initialize()) { + char name[5]; + //try to find empty key + for (int i = 0; i < 0x10; i++) { + snprintf(name, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, i); + + UInt8 length = 0; + void * data = 0; + + IOReturn result = fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, + true, + (void *)name, + (void *)&length, + (void *)&data, + 0); + + if (kIOReturnSuccess == result) { + continue; + } + + if (addSensor(name, TYPE_SP78, 2, i)) { + numCard = i; + break; + } + } + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)name, + (void *)TYPE_SP78, + (void *)2, this)) { + WarningLog("Can't add key to fake SMC device, kext will not load"); + return false; + } + + return true; + } else { + return false; + } +} + + +bool RadeonMonitor::init(OSDictionary *properties) { + if (!super::init(properties)) { return false; } + + if (!(sensors = OSDictionary::withCapacity(0))) { + return false; + } + + return true; +} + +void RadeonMonitor::stop (IOService* provider) { + sensors->flushCollection(); + Card->release(); //? + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCRemoveKeyHandler, + true, + this, + NULL, + NULL, + NULL)) { + WarningLog("Can't remove key handler"); + IOSleep(500); + } + + super::stop(provider); +} + +void RadeonMonitor::free() { + sensors->release(); + //Card->release(); + super::free(); +} + +IOReturn RadeonMonitor::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4) { + UInt16 t; + + if (functionName->isEqualTo(kFakeSMCGetValueCallback)) { + const char* name = (const char*)param1; + void* data = param2; + + if (name && data) { + if (OSNumber *number = OSDynamicCast(OSNumber, sensors->getObject(name))) { + UInt32 index = number->unsigned16BitValue(); + if (index != numCard) { //TODO - multiple card support + return kIOReturnBadArgument; + } + } + + switch (Card->tempFamily) { + case R6xx: + Card->R6xxTemperatureSensor(&t); + break; + case R7xx: + Card->R7xxTemperatureSensor(&t); + break; + case R8xx: + Card->EverTemperatureSensor(&t); + break; + case R9xx: + Card->TahitiTemperatureSensor(&t); + break; + case RCIx: + Card->HawaiiTemperatureSensor(&t); + break; + case RAIx: + Card->ArcticTemperatureSensor(&t); + break; + case RVEx: + Card->VegaTemperatureSensor(&t); + break; + default: + break; + } + //t = Card->tempSensor->readTemp(index); + bcopy(&t, data, 2); + + return kIOReturnSuccess; + } + + //DebugLog("bad argument key name or data"); + + return kIOReturnBadArgument; + } + + return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); +} + +//what about sleep/wake? +/* +#pragma mark - +#pragma mark ••• Power Management ••• +#pragma mark - + +//--------------------------------------------------------------------------- + +enum { + kPowerStateOff = 0, + kPowerStateDoze, + kPowerStateOn, + kPowerStateCount +}; + +IOReturn RadeonMonitor::registerWithPolicyMaker( IOService * policyMaker ) { + static IOPMPowerState powerStateArray[ kPowerStateCount ] = { + { 1,0,0,0,0,0,0,0,0,0,0,0 }, + { 1,0,kIOPMDoze,kIOPMDoze,0,0,0,0,0,0,0,0 }, + { 1,kIOPMDeviceUsable,kIOPMPowerOn,kIOPMPowerOn,0,0,0,0,0,0,0,0 } + }; + + fCurrentPowerState = kPowerStateOn; + + return policyMaker->registerPowerDriver( this, powerStateArray, + kPowerStateCount ); +} + +//--------------------------------------------------------------------------- + +IOReturn RadeonMonitor::setPowerState( unsigned long powerStateOrdinal, + IOService * policyMaker) { + if (!pciNub || (powerStateOrdinal == fCurrentPowerState)) + return IOPMAckImplied; + + switch (powerStateOrdinal) { + case kPowerStateOff: + // Now that the driver knows if Magic Packet support was enabled, + // tell PCI Family whether PME_EN should be set or not. + + //hwSetMagicPacketEnable( fMagicPacketEnabled ); + + pciNub->hasPCIPowerManagement( fMagicPacketEnabled ? + kPCIPMCPMESupportFromD3Cold : kPCIPMCD3Support ); + break; + + case kPowerStateDoze: + break; + + case kPowerStateOn: + if (fCurrentPowerState == kPowerStateOff) { + initPCIConfigSpace(pciNub); + } + break; + } + + fCurrentPowerState = powerStateOrdinal; + + return IOPMAckImplied; +} +*/ diff --git a/plugins/GPUSensors/RadeonMonitor/Radeon.h b/plugins/GPUSensors/RadeonMonitor/Radeon.h new file mode 100644 index 0000000..60a4ac4 --- /dev/null +++ b/plugins/GPUSensors/RadeonMonitor/Radeon.h @@ -0,0 +1,47 @@ +/* + * Radeon.h + * HWSensors + * + * Created by Sergey on 20.12.10. + * Copyright 2010 Slice. All rights reserved. + * + */ + +#include +#include +#include +#include "ATICard.h" + +class RadeonMonitor : public IOService +{ + OSDeclareDefaultStructors(RadeonMonitor) + +private: + IOService* fakeSMC; + OSDictionary* sensors; + volatile UInt8* mmio_base; + int numCard; //numCard=0 if only one Video, but may be any other value + IOPCIDevice * VCard; + IOMemoryMap * mmio; + UInt32 vendor_id; + UInt32 device_id; + UInt32 class_id; + + bool addSensor(const char* key, const char* type, unsigned int size, int index); +protected: + ATICard* Card; + +public: + virtual IOService* probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual bool init(OSDictionary *properties=0); + virtual void free(void); + virtual void stop(IOService *provider); + + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); +}; diff --git a/plugins/GPUSensors/RadeonMonitor/RadeonMonitor-Info.plist b/plugins/GPUSensors/RadeonMonitor/RadeonMonitor-Info.plist new file mode 100644 index 0000000..f4b1d24 --- /dev/null +++ b/plugins/GPUSensors/RadeonMonitor/RadeonMonitor-Info.plist @@ -0,0 +1,53 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + IOKitPersonalities + + Radeon Cards Monitoring Plugin + + CFBundleIdentifier + org.slice.RadeonMonitor + IOClass + RadeonMonitor + IOMatchCategory + RadeonMonitor + IOProbeScore + 500 + IOProviderClass + IOResources + IOResourceMatch + IOKit + + + OSBundleLibraries + + com.apple.iokit.IOPCIFamily + 2.4 + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + + diff --git a/plugins/GPUSensors/RadeonMonitor/RadeonMonitor-pre106-Info.plist b/plugins/GPUSensors/RadeonMonitor/RadeonMonitor-pre106-Info.plist new file mode 100644 index 0000000..415b9c4 --- /dev/null +++ b/plugins/GPUSensors/RadeonMonitor/RadeonMonitor-pre106-Info.plist @@ -0,0 +1,53 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.slice.RadeonMonitor + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + IOKitPersonalities + + Radeon Cards Monitoring Plugin + + CFBundleIdentifier + org.slice.RadeonMonitor + IOClass + RadeonMonitor + IOProbeScore + 500 + IOMatchCategory + RadeonMonitor + IOProviderClass + IOResources + IOResourceMatch + IOKit + + + OSBundleLibraries + + org.netkas.FakeSMC + 3.1.0 + com.apple.iokit.IOACPIFamily + 1.0.0d1 + com.apple.iokit.IOPCIFamily + 2.4 + com.apple.kernel.6.0 + 7.9.9 + com.apple.kernel.iokit + 7.9.9 + com.apple.kernel.libkern + 7.9.9 + + + diff --git a/plugins/GPUSensors/RadeonMonitor/atombios.h b/plugins/GPUSensors/RadeonMonitor/atombios.h new file mode 100644 index 0000000..73a0f54 --- /dev/null +++ b/plugins/GPUSensors/RadeonMonitor/atombios.h @@ -0,0 +1,6141 @@ +/* + * Copyright 2006-2007 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/****************************************************************************/ +/*Portion I: Definitions shared between VBIOS and Driver */ +/****************************************************************************/ + + +#ifndef _ATOMBIOS_H +#define _ATOMBIOS_H + +#define ATOM_VERSION_MAJOR 0x00020000 +#define ATOM_VERSION_MINOR 0x00000002 + +#define ATOM_HEADER_VERSION (ATOM_VERSION_MAJOR | ATOM_VERSION_MINOR) + +#define ATOM_BIG_ENDIAN 0 +#define USHORT UInt16 +#define UCHAR UInt8 +#define ULONG UInt32 +/* Endianness should be specified before inclusion, + * default to little endian + */ +#ifndef ATOM_BIG_ENDIAN +#error Endian not specified +#endif + +#ifdef _H2INC + #ifndef ULONG + typedef unsigned long ULONG; + #endif + + #ifndef UCHAR + typedef unsigned char UCHAR; + #endif + + #ifndef USHORT + typedef unsigned short USHORT; + #endif +#endif + +#define ATOM_DAC_A 0 +#define ATOM_DAC_B 1 +#define ATOM_EXT_DAC 2 + +#define ATOM_CRTC1 0 +#define ATOM_CRTC2 1 +#define ATOM_CRTC3 2 +#define ATOM_CRTC4 3 +#define ATOM_CRTC5 4 +#define ATOM_CRTC6 5 +#define ATOM_CRTC_INVALID 0xFF + +#define ATOM_DIGA 0 +#define ATOM_DIGB 1 + +#define ATOM_PPLL1 0 +#define ATOM_PPLL2 1 +#define ATOM_DCPLL 2 +#define ATOM_PPLL_INVALID 0xFF + +#define ATOM_SCALER1 0 +#define ATOM_SCALER2 1 + +#define ATOM_SCALER_DISABLE 0 +#define ATOM_SCALER_CENTER 1 +#define ATOM_SCALER_EXPANSION 2 +#define ATOM_SCALER_MULTI_EX 3 + +#define ATOM_DISABLE 0 +#define ATOM_ENABLE 1 +#define ATOM_LCD_BLOFF (ATOM_DISABLE+2) +#define ATOM_LCD_BLON (ATOM_ENABLE+2) +#define ATOM_LCD_BL_BRIGHTNESS_CONTROL (ATOM_ENABLE+3) +#define ATOM_LCD_SELFTEST_START (ATOM_DISABLE+5) +#define ATOM_LCD_SELFTEST_STOP (ATOM_ENABLE+5) +#define ATOM_ENCODER_INIT (ATOM_DISABLE+7) +#define ATOM_GET_STATUS (ATOM_DISABLE+8) + +#define ATOM_BLANKING 1 +#define ATOM_BLANKING_OFF 0 + +#define ATOM_CURSOR1 0 +#define ATOM_CURSOR2 1 + +#define ATOM_ICON1 0 +#define ATOM_ICON2 1 + +#define ATOM_CRT1 0 +#define ATOM_CRT2 1 + +#define ATOM_TV_NTSC 1 +#define ATOM_TV_NTSCJ 2 +#define ATOM_TV_PAL 3 +#define ATOM_TV_PALM 4 +#define ATOM_TV_PALCN 5 +#define ATOM_TV_PALN 6 +#define ATOM_TV_PAL60 7 +#define ATOM_TV_SECAM 8 +#define ATOM_TV_CV 16 + +#define ATOM_DAC1_PS2 1 +#define ATOM_DAC1_CV 2 +#define ATOM_DAC1_NTSC 3 +#define ATOM_DAC1_PAL 4 + +#define ATOM_DAC2_PS2 ATOM_DAC1_PS2 +#define ATOM_DAC2_CV ATOM_DAC1_CV +#define ATOM_DAC2_NTSC ATOM_DAC1_NTSC +#define ATOM_DAC2_PAL ATOM_DAC1_PAL + +#define ATOM_PM_ON 0 +#define ATOM_PM_STANDBY 1 +#define ATOM_PM_SUSPEND 2 +#define ATOM_PM_OFF 3 + +/* Bit0:{=0:single, =1:dual}, + Bit1 {=0:666RGB, =1:888RGB}, + Bit2:3:{Grey level} + Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888}*/ + +#define ATOM_PANEL_MISC_DUAL 0x00000001 +#define ATOM_PANEL_MISC_888RGB 0x00000002 +#define ATOM_PANEL_MISC_GREY_LEVEL 0x0000000C +#define ATOM_PANEL_MISC_FPDI 0x00000010 +#define ATOM_PANEL_MISC_GREY_LEVEL_SHIFT 2 +#define ATOM_PANEL_MISC_SPATIAL 0x00000020 +#define ATOM_PANEL_MISC_TEMPORAL 0x00000040 +#define ATOM_PANEL_MISC_API_ENABLED 0x00000080 + + +#define MEMTYPE_DDR1 "DDR1" +#define MEMTYPE_DDR2 "DDR2" +#define MEMTYPE_DDR3 "DDR3" +#define MEMTYPE_DDR4 "DDR4" + +#define ASIC_BUS_TYPE_PCI "PCI" +#define ASIC_BUS_TYPE_AGP "AGP" +#define ASIC_BUS_TYPE_PCIE "PCI_EXPRESS" + +/* Maximum size of that FireGL flag string */ + +#define ATOM_FIREGL_FLAG_STRING "FGL" //Flag used to enable FireGL Support +#define ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING 3 //sizeof( ATOM_FIREGL_FLAG_STRING ) + +#define ATOM_FAKE_DESKTOP_STRING "DSK" //Flag used to enable mobile ASIC on Desktop +#define ATOM_MAX_SIZE_OF_FAKE_DESKTOP_STRING ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING + +#define ATOM_M54T_FLAG_STRING "M54T" //Flag used to enable M54T Support +#define ATOM_MAX_SIZE_OF_M54T_FLAG_STRING 4 //sizeof( ATOM_M54T_FLAG_STRING ) + +#define HW_ASSISTED_I2C_STATUS_FAILURE 2 +#define HW_ASSISTED_I2C_STATUS_SUCCESS 1 + +#pragma pack(1) /* BIOS data must use byte aligment */ + +/* Define offset to location of ROM header. */ + +#define OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER 0x00000048L +#define OFFSET_TO_ATOM_ROM_IMAGE_SIZE 0x00000002L + +#define OFFSET_TO_ATOMBIOS_ASIC_BUS_MEM_TYPE 0x94 +#define MAXSIZE_OF_ATOMBIOS_ASIC_BUS_MEM_TYPE 20 /* including the terminator 0x0! */ +#define OFFSET_TO_GET_ATOMBIOS_STRINGS_NUMBER 0x002f +#define OFFSET_TO_GET_ATOMBIOS_STRINGS_START 0x006e + +/* Common header for all ROM Data tables. + Every table pointed _ATOM_MASTER_DATA_TABLE has this common header. + And the pointer actually points to this header. */ + +typedef struct _ATOM_COMMON_TABLE_HEADER +{ + USHORT usStructureSize; + UCHAR ucTableFormatRevision; /*Change it when the Parser is not backward compatible */ + UCHAR ucTableContentRevision; /*Change it only when the table needs to change but the firmware */ + /*Image can't be updated, while Driver needs to carry the new table! */ +}ATOM_COMMON_TABLE_HEADER; + +typedef struct _ATOM_ROM_HEADER +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR uaFirmWareSignature[4]; /*Signature to distinguish between Atombios and non-atombios, + atombios should init it as "ATOM", don't change the position */ + USHORT usBiosRuntimeSegmentAddress; + USHORT usProtectedModeInfoOffset; + USHORT usConfigFilenameOffset; + USHORT usCRC_BlockOffset; + USHORT usBIOS_BootupMessageOffset; + USHORT usInt10Offset; + USHORT usPciBusDevInitCode; + USHORT usIoBaseAddress; + USHORT usSubsystemVendorID; + USHORT usSubsystemID; + USHORT usPCI_InfoOffset; + USHORT usMasterCommandTableOffset; /*Offset for SW to get all command table offsets, Don't change the position */ + USHORT usMasterDataTableOffset; /*Offset for SW to get all data table offsets, Don't change the position */ + UCHAR ucExtendedFunctionCode; + UCHAR ucReserved; +}ATOM_ROM_HEADER; + +/*==============================Command Table Portion==================================== */ + +#ifdef UEFI_BUILD + #define UTEMP USHORT + #define USHORT void* +#endif + +typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{ + USHORT ASIC_Init; //Function Table, used by various SW components,latest version 1.1 + USHORT GetDisplaySurfaceSize; //Atomic Table, Used by Bios when enabling HW ICON + USHORT ASIC_RegistersInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init + USHORT VRAM_BlockVenderDetection; //Atomic Table, used only by Bios + USHORT DIGxEncoderControl; //Only used by Bios + USHORT MemoryControllerInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init + USHORT EnableCRTCMemReq; //Function Table,directly used by various SW components,latest version 2.1 + USHORT MemoryParamAdjust; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock if needed + USHORT DVOEncoderControl; //Function Table,directly used by various SW components,latest version 1.2 + USHORT GPIOPinControl; //Atomic Table, only used by Bios + USHORT SetEngineClock; //Function Table,directly used by various SW components,latest version 1.1 + USHORT SetMemoryClock; //Function Table,directly used by various SW components,latest version 1.1 + USHORT SetPixelClock; //Function Table,directly used by various SW components,latest version 1.2 + USHORT DynamicClockGating; //Atomic Table, indirectly used by various SW components,called from ASIC_Init + USHORT ResetMemoryDLL; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT ResetMemoryDevice; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT MemoryPLLInit; + USHORT AdjustDisplayPll; //only used by Bios + USHORT AdjustMemoryController; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT EnableASIC_StaticPwrMgt; //Atomic Table, only used by Bios + USHORT ASIC_StaticPwrMgtStatusChange; //Obsolete , only used by Bios + USHORT DAC_LoadDetection; //Atomic Table, directly used by various SW components,latest version 1.2 + USHORT LVTMAEncoderControl; //Atomic Table,directly used by various SW components,latest version 1.3 + USHORT LCD1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT DAC1EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT DAC2EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT DVOOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT CV1OutputControl; //Atomic Table, Atomic Table, Obsolete from Ry6xx, use DAC2 Output instead + USHORT GetConditionalGoldenSetting; //only used by Bios + USHORT TVEncoderControl; //Function Table,directly used by various SW components,latest version 1.1 + USHORT TMDSAEncoderControl; //Atomic Table, directly used by various SW components,latest version 1.3 + USHORT LVDSEncoderControl; //Atomic Table, directly used by various SW components,latest version 1.3 + USHORT TV1OutputControl; //Atomic Table, Obsolete from Ry6xx, use DAC2 Output instead + USHORT EnableScaler; //Atomic Table, used only by Bios + USHORT BlankCRTC; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT EnableCRTC; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT GetPixelClock; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT EnableVGA_Render; //Function Table,directly used by various SW components,latest version 1.1 + USHORT GetSCLKOverMCLKRatio; //Atomic Table, only used by Bios + USHORT SetCRTC_Timing; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT SetCRTC_OverScan; //Atomic Table, used by various SW components,latest version 1.1 + USHORT SetCRTC_Replication; //Atomic Table, used only by Bios + USHORT SelectCRTC_Source; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT EnableGraphSurfaces; //Atomic Table, used only by Bios + USHORT UpdateCRTC_DoubleBufferRegisters; + USHORT LUT_AutoFill; //Atomic Table, only used by Bios + USHORT EnableHW_IconCursor; //Atomic Table, only used by Bios + USHORT GetMemoryClock; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT GetEngineClock; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT SetCRTC_UsingDTDTiming; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT ExternalEncoderControl; //Atomic Table, directly used by various SW components,latest version 2.1 + USHORT LVTMAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT VRAM_BlockDetectionByStrap; //Atomic Table, used only by Bios + USHORT MemoryCleanUp; //Atomic Table, only used by Bios + USHORT ProcessI2cChannelTransaction; //Function Table,only used by Bios + USHORT WriteOneByteToHWAssistedI2C; //Function Table,indirectly used by various SW components + USHORT ReadHWAssistedI2CStatus; //Atomic Table, indirectly used by various SW components + USHORT SpeedFanControl; //Function Table,indirectly used by various SW components,called from ASIC_Init + USHORT PowerConnectorDetection; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT MC_Synchronization; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT ComputeMemoryEnginePLL; //Atomic Table, indirectly used by various SW components,called from SetMemory/EngineClock + USHORT MemoryRefreshConversion; //Atomic Table, indirectly used by various SW components,called from SetMemory or SetEngineClock + USHORT VRAM_GetCurrentInfoBlock; //Atomic Table, used only by Bios + USHORT DynamicMemorySettings; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT MemoryTraining; //Atomic Table, used only by Bios + USHORT EnableSpreadSpectrumOnPPLL; //Atomic Table, directly used by various SW components,latest version 1.2 + USHORT TMDSAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT SetVoltage; //Function Table,directly and/or indirectly used by various SW components,latest version 1.1 + USHORT DAC1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT DAC2OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT SetupHWAssistedI2CStatus; //Function Table,only used by Bios, obsolete soon.Switch to use "ReadEDIDFromHWAssistedI2C" + USHORT ClockSource; //Atomic Table, indirectly used by various SW components,called from ASIC_Init + USHORT MemoryDeviceInit; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT EnableYUV; //Atomic Table, indirectly used by various SW components,called from EnableVGARender + USHORT DIG1EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1 + USHORT DIG2EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1 + USHORT DIG1TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1 + USHORT DIG2TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1 + USHORT ProcessAuxChannelTransaction; //Function Table,only used by Bios + USHORT DPEncoderService; //Function Table,only used by Bios +}ATOM_MASTER_LIST_OF_COMMAND_TABLES; + +// For backward compatible +#define ReadEDIDFromHWAssistedI2C ProcessI2cChannelTransaction +#define UNIPHYTransmitterControl DIG1TransmitterControl +#define LVTMATransmitterControl DIG2TransmitterControl +#define SetCRTC_DPM_State GetConditionalGoldenSetting +#define SetUniphyInstance ASIC_StaticPwrMgtStatusChange +#define HPDInterruptService ReadHWAssistedI2CStatus +#define EnableVGA_Access GetSCLKOverMCLKRatio + +typedef struct _ATOM_MASTER_COMMAND_TABLE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_MASTER_LIST_OF_COMMAND_TABLES ListOfCommandTables; +}ATOM_MASTER_COMMAND_TABLE; + +/****************************************************************************/ +// Structures used in every command table +/****************************************************************************/ +typedef struct _ATOM_TABLE_ATTRIBUTE +{ +#if ATOM_BIG_ENDIAN + USHORT UpdatedByUtility:1; //[15]=Table updated by utility flag + USHORT PS_SizeInBytes:7; //[14:8]=Size of parameter space in Bytes (multiple of a dword), + USHORT WS_SizeInBytes:8; //[7:0]=Size of workspace in Bytes (in multiple of a dword), +#else + USHORT WS_SizeInBytes:8; //[7:0]=Size of workspace in Bytes (in multiple of a dword), + USHORT PS_SizeInBytes:7; //[14:8]=Size of parameter space in Bytes (multiple of a dword), + USHORT UpdatedByUtility:1; //[15]=Table updated by utility flag +#endif +}ATOM_TABLE_ATTRIBUTE; + +typedef union _ATOM_TABLE_ATTRIBUTE_ACCESS +{ + ATOM_TABLE_ATTRIBUTE sbfAccess; + USHORT susAccess; +}ATOM_TABLE_ATTRIBUTE_ACCESS; + +/****************************************************************************/ +// Common header for all command tables. +// Every table pointed by _ATOM_MASTER_COMMAND_TABLE has this common header. +// And the pointer actually points to this header. +/****************************************************************************/ +typedef struct _ATOM_COMMON_ROM_COMMAND_TABLE_HEADER +{ + ATOM_COMMON_TABLE_HEADER CommonHeader; + ATOM_TABLE_ATTRIBUTE TableAttribute; +}ATOM_COMMON_ROM_COMMAND_TABLE_HEADER; + +/****************************************************************************/ +// Structures used by ComputeMemoryEnginePLLTable +/****************************************************************************/ +#define COMPUTE_MEMORY_PLL_PARAM 1 +#define COMPUTE_ENGINE_PLL_PARAM 2 + +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS +{ + ULONG ulClock; //When returen, it's the re-calculated clock based on given Fb_div Post_Div and ref_div + UCHAR ucAction; //0:reserved //1:Memory //2:Engine + UCHAR ucReserved; //may expand to return larger Fbdiv later + UCHAR ucFbDiv; //return value + UCHAR ucPostDiv; //return value +}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS; + +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 +{ + ULONG ulClock; //When return, [23:0] return real clock + UCHAR ucAction; //0:reserved;COMPUTE_MEMORY_PLL_PARAM:Memory;COMPUTE_ENGINE_PLL_PARAM:Engine. it return ref_div to be written to register + USHORT usFbDiv; //return Feedback value to be written to register + UCHAR ucPostDiv; //return post div to be written to register +}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2; +#define COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS + + +#define SET_CLOCK_FREQ_MASK 0x00FFFFFF //Clock change tables only take bit [23:0] as the requested clock value +#define USE_NON_BUS_CLOCK_MASK 0x01000000 //Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa) +#define USE_MEMORY_SELF_REFRESH_MASK 0x02000000 //Only applicable to memory clock change, when set, using memory self refresh during clock transition +#define SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04000000 //Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change +#define FIRST_TIME_CHANGE_CLOCK 0x08000000 //Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup +#define SKIP_SW_PROGRAM_PLL 0x10000000 //Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL +#define USE_SS_ENABLED_PIXEL_CLOCK USE_NON_BUS_CLOCK_MASK + +#define b3USE_NON_BUS_CLOCK_MASK 0x01 //Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa) +#define b3USE_MEMORY_SELF_REFRESH 0x02 //Only applicable to memory clock change, when set, using memory self refresh during clock transition +#define b3SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04 //Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change +#define b3FIRST_TIME_CHANGE_CLOCK 0x08 //Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup +#define b3SKIP_SW_PROGRAM_PLL 0x10 //Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL + +typedef struct _ATOM_COMPUTE_CLOCK_FREQ +{ +#if ATOM_BIG_ENDIAN + ULONG ulComputeClockFlag:8; // =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM + ULONG ulClockFreq:24; // in unit of 10kHz +#else + ULONG ulClockFreq:24; // in unit of 10kHz + ULONG ulComputeClockFlag:8; // =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM +#endif +}ATOM_COMPUTE_CLOCK_FREQ; + +typedef struct _ATOM_S_MPLL_FB_DIVIDER +{ + USHORT usFbDivFrac; + USHORT usFbDiv; +}ATOM_S_MPLL_FB_DIVIDER; + +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 +{ + union + { + ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter + ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter + }; + UCHAR ucRefDiv; //Output Parameter + UCHAR ucPostDiv; //Output Parameter + UCHAR ucCntlFlag; //Output Parameter + UCHAR ucReserved; +}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3; + +// ucCntlFlag +#define ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN 1 +#define ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE 2 +#define ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE 4 +#define ATOM_PLL_CNTL_FLAG_SPLL_ISPARE_9 8 + + +// V4 are only used for APU which PLL outside GPU +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 +{ +#if ATOM_BIG_ENDIAN + ULONG ucPostDiv; //return parameter: post divider which is used to program to register directly + ULONG ulClock:24; //Input= target clock, output = actual clock +#else + ULONG ulClock:24; //Input= target clock, output = actual clock + ULONG ucPostDiv; //return parameter: post divider which is used to program to register directly +#endif +}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4; + +typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER +{ + ATOM_COMPUTE_CLOCK_FREQ ulClock; + ULONG ulReserved[2]; +}DYNAMICE_MEMORY_SETTINGS_PARAMETER; + +typedef struct _DYNAMICE_ENGINE_SETTINGS_PARAMETER +{ + ATOM_COMPUTE_CLOCK_FREQ ulClock; + ULONG ulMemoryClock; + ULONG ulReserved; +}DYNAMICE_ENGINE_SETTINGS_PARAMETER; + +/****************************************************************************/ +// Structures used by SetEngineClockTable +/****************************************************************************/ +typedef struct _SET_ENGINE_CLOCK_PARAMETERS +{ + ULONG ulTargetEngineClock; //In 10Khz unit +}SET_ENGINE_CLOCK_PARAMETERS; + +typedef struct _SET_ENGINE_CLOCK_PS_ALLOCATION +{ + ULONG ulTargetEngineClock; //In 10Khz unit + COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved; +}SET_ENGINE_CLOCK_PS_ALLOCATION; + +/****************************************************************************/ +// Structures used by SetMemoryClockTable +/****************************************************************************/ +typedef struct _SET_MEMORY_CLOCK_PARAMETERS +{ + ULONG ulTargetMemoryClock; //In 10Khz unit +}SET_MEMORY_CLOCK_PARAMETERS; + +typedef struct _SET_MEMORY_CLOCK_PS_ALLOCATION +{ + ULONG ulTargetMemoryClock; //In 10Khz unit + COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved; +}SET_MEMORY_CLOCK_PS_ALLOCATION; + +/****************************************************************************/ +// Structures used by ASIC_Init.ctb +/****************************************************************************/ +typedef struct _ASIC_INIT_PARAMETERS +{ + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit +}ASIC_INIT_PARAMETERS; + +typedef struct _ASIC_INIT_PS_ALLOCATION +{ + ASIC_INIT_PARAMETERS sASICInitClocks; + SET_ENGINE_CLOCK_PS_ALLOCATION sReserved; //Caller doesn't need to init this structure +}ASIC_INIT_PS_ALLOCATION; + +/****************************************************************************/ +// Structure used by DynamicClockGatingTable.ctb +/****************************************************************************/ +typedef struct _DYNAMIC_CLOCK_GATING_PARAMETERS +{ + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[3]; +}DYNAMIC_CLOCK_GATING_PARAMETERS; +#define DYNAMIC_CLOCK_GATING_PS_ALLOCATION DYNAMIC_CLOCK_GATING_PARAMETERS + +/****************************************************************************/ +// Structure used by EnableASIC_StaticPwrMgtTable.ctb +/****************************************************************************/ +typedef struct _ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS +{ + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[3]; +}ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS; +#define ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS + +/****************************************************************************/ +// Structures used by DAC_LoadDetectionTable.ctb +/****************************************************************************/ +typedef struct _DAC_LOAD_DETECTION_PARAMETERS +{ + USHORT usDeviceID; //{ATOM_DEVICE_CRTx_SUPPORT,ATOM_DEVICE_TVx_SUPPORT,ATOM_DEVICE_CVx_SUPPORT} + UCHAR ucDacType; //{ATOM_DAC_A,ATOM_DAC_B, ATOM_EXT_DAC} + UCHAR ucMisc; //Valid only when table revision =1.3 and above +}DAC_LOAD_DETECTION_PARAMETERS; + +// DAC_LOAD_DETECTION_PARAMETERS.ucMisc +#define DAC_LOAD_MISC_YPrPb 0x01 + +typedef struct _DAC_LOAD_DETECTION_PS_ALLOCATION +{ + DAC_LOAD_DETECTION_PARAMETERS sDacload; + ULONG Reserved[2];// Don't set this one, allocation for EXT DAC +}DAC_LOAD_DETECTION_PS_ALLOCATION; + +/****************************************************************************/ +// Structures used by DAC1EncoderControlTable.ctb and DAC2EncoderControlTable.ctb +/****************************************************************************/ +typedef struct _DAC_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucDacStandard; // See definition of ATOM_DACx_xxx, For DEC3.0, bit 7 used as internal flag to indicate DAC2 (==1) or DAC1 (==0) + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder + // 7: ATOM_ENCODER_INIT Initialize DAC +}DAC_ENCODER_CONTROL_PARAMETERS; + +#define DAC_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PARAMETERS + +/****************************************************************************/ +// Structures used by DIG1EncoderControlTable +// DIG2EncoderControlTable +// ExternalEncoderControlTable +/****************************************************************************/ +typedef struct _DIG_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucConfig; + // [2] Link Select: + // =0: PHY linkA if bfLane<3 + // =1: PHY linkB if bfLanes<3 + // =0: PHY linkA+B if bfLanes=3 + // [3] Transmitter Sel + // =0: UNIPHY or PCIEPHY + // =1: LVTMA + UCHAR ucAction; // =0: turn off encoder + // =1: turn on encoder + UCHAR ucEncoderMode; + // =0: DP encoder + // =1: LVDS encoder + // =2: DVI encoder + // =3: HDMI encoder + // =4: SDVO encoder + UCHAR ucLaneNum; // how many lanes to enable + UCHAR ucReserved[2]; +}DIG_ENCODER_CONTROL_PARAMETERS; +#define DIG_ENCODER_CONTROL_PS_ALLOCATION DIG_ENCODER_CONTROL_PARAMETERS +#define EXTERNAL_ENCODER_CONTROL_PARAMETER DIG_ENCODER_CONTROL_PARAMETERS + +//ucConfig +#define ATOM_ENCODER_CONFIG_DPLINKRATE_MASK 0x01 +#define ATOM_ENCODER_CONFIG_DPLINKRATE_1_62GHZ 0x00 +#define ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ 0x01 +#define ATOM_ENCODER_CONFIG_LINK_SEL_MASK 0x04 +#define ATOM_ENCODER_CONFIG_LINKA 0x00 +#define ATOM_ENCODER_CONFIG_LINKB 0x04 +#define ATOM_ENCODER_CONFIG_LINKA_B ATOM_TRANSMITTER_CONFIG_LINKA +#define ATOM_ENCODER_CONFIG_LINKB_A ATOM_ENCODER_CONFIG_LINKB +#define ATOM_ENCODER_CONFIG_TRANSMITTER_SEL_MASK 0x08 +#define ATOM_ENCODER_CONFIG_UNIPHY 0x00 +#define ATOM_ENCODER_CONFIG_LVTMA 0x08 +#define ATOM_ENCODER_CONFIG_TRANSMITTER1 0x00 +#define ATOM_ENCODER_CONFIG_TRANSMITTER2 0x08 +#define ATOM_ENCODER_CONFIG_DIGB 0x80 // VBIOS Internal use, outside SW should set this bit=0 +// ucAction +// ATOM_ENABLE: Enable Encoder +// ATOM_DISABLE: Disable Encoder + +//ucEncoderMode +#define ATOM_ENCODER_MODE_DP 0 +#define ATOM_ENCODER_MODE_LVDS 1 +#define ATOM_ENCODER_MODE_DVI 2 +#define ATOM_ENCODER_MODE_HDMI 3 +#define ATOM_ENCODER_MODE_SDVO 4 +#define ATOM_ENCODER_MODE_DP_AUDIO 5 +#define ATOM_ENCODER_MODE_TV 13 +#define ATOM_ENCODER_MODE_CV 14 +#define ATOM_ENCODER_MODE_CRT 15 + +typedef struct _ATOM_DIG_ENCODER_CONFIG_V2 +{ +#if ATOM_BIG_ENDIAN + UCHAR ucReserved1:2; + UCHAR ucTransmitterSel:2; // =0: UniphyAB, =1: UniphyCD =2: UniphyEF + UCHAR ucLinkSel:1; // =0: linkA/C/E =1: linkB/D/F + UCHAR ucReserved:1; + UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz +#else + UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz + UCHAR ucReserved:1; + UCHAR ucLinkSel:1; // =0: linkA/C/E =1: linkB/D/F + UCHAR ucTransmitterSel:2; // =0: UniphyAB, =1: UniphyCD =2: UniphyEF + UCHAR ucReserved1:2; +#endif +}ATOM_DIG_ENCODER_CONFIG_V2; + + +typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2 +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + ATOM_DIG_ENCODER_CONFIG_V2 acConfig; + UCHAR ucAction; + UCHAR ucEncoderMode; + // =0: DP encoder + // =1: LVDS encoder + // =2: DVI encoder + // =3: HDMI encoder + // =4: SDVO encoder + UCHAR ucLaneNum; // how many lanes to enable + UCHAR ucStatus; // = DP_LINK_TRAINING_COMPLETE or DP_LINK_TRAINING_INCOMPLETE, only used by VBIOS with command ATOM_ENCODER_CMD_QUERY_DP_LINK_TRAINING_STATUS + UCHAR ucReserved; +}DIG_ENCODER_CONTROL_PARAMETERS_V2; + +//ucConfig +#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_MASK 0x01 +#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_1_62GHZ 0x00 +#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_2_70GHZ 0x01 +#define ATOM_ENCODER_CONFIG_V2_LINK_SEL_MASK 0x04 +#define ATOM_ENCODER_CONFIG_V2_LINKA 0x00 +#define ATOM_ENCODER_CONFIG_V2_LINKB 0x04 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER_SEL_MASK 0x18 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER1 0x00 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER2 0x08 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER3 0x10 + +// ucAction: +// ATOM_DISABLE +// ATOM_ENABLE +#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_START 0x08 +#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1 0x09 +#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2 0x0a +#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE 0x0b +#define ATOM_ENCODER_CMD_DP_VIDEO_OFF 0x0c +#define ATOM_ENCODER_CMD_DP_VIDEO_ON 0x0d +#define ATOM_ENCODER_CMD_QUERY_DP_LINK_TRAINING_STATUS 0x0e +#define ATOM_ENCODER_CMD_SETUP 0x0f + +// ucStatus +#define ATOM_ENCODER_STATUS_LINK_TRAINING_COMPLETE 0x10 +#define ATOM_ENCODER_STATUS_LINK_TRAINING_INCOMPLETE 0x00 + +// Following function ENABLE sub-function will be used by driver when TMDS/HDMI/LVDS is used, disable function will be used by driver +typedef struct _ATOM_DIG_ENCODER_CONFIG_V3 +{ +#if ATOM_BIG_ENDIAN + UCHAR ucReserved1:1; + UCHAR ucDigSel:3; // =0: DIGA/B/C/D/E/F + UCHAR ucReserved:3; + UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz +#else + UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz + UCHAR ucReserved:3; + UCHAR ucDigSel:3; // =0: DIGA/B/C/D/E/F + UCHAR ucReserved1:1; +#endif +}ATOM_DIG_ENCODER_CONFIG_V3; + +#define ATOM_ENCODER_CONFIG_V3_ENCODER_SEL 0x70 + + +typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V3 +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + ATOM_DIG_ENCODER_CONFIG_V3 acConfig; + UCHAR ucAction; + UCHAR ucEncoderMode; + // =0: DP encoder + // =1: LVDS encoder + // =2: DVI encoder + // =3: HDMI encoder + // =4: SDVO encoder + // =5: DP audio + UCHAR ucLaneNum; // how many lanes to enable + UCHAR ucBitPerColor; // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP + UCHAR ucReserved; +}DIG_ENCODER_CONTROL_PARAMETERS_V3; + + +// define ucBitPerColor: +#define PANEL_BPC_UNDEFINE 0x00 +#define PANEL_6BIT_PER_COLOR 0x01 +#define PANEL_8BIT_PER_COLOR 0x02 +#define PANEL_10BIT_PER_COLOR 0x03 +#define PANEL_12BIT_PER_COLOR 0x04 +#define PANEL_16BIT_PER_COLOR 0x05 + +/****************************************************************************/ +// Structures used by UNIPHYTransmitterControlTable +// LVTMATransmitterControlTable +// DVOOutputControlTable +/****************************************************************************/ +typedef struct _ATOM_DP_VS_MODE +{ + UCHAR ucLaneSel; + UCHAR ucLaneSet; +}ATOM_DP_VS_MODE; + +typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS +{ + union + { + USHORT usPixelClock; // in 10KHz; for bios convenient + USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h + ATOM_DP_VS_MODE asMode; // DP Voltage swing mode + }; + UCHAR ucConfig; + // [0]=0: 4 lane Link, + // =1: 8 lane Link ( Dual Links TMDS ) + // [1]=0: InCoherent mode + // =1: Coherent Mode + // [2] Link Select: + // =0: PHY linkA if bfLane<3 + // =1: PHY linkB if bfLanes<3 + // =0: PHY linkA+B if bfLanes=3 + // [5:4]PCIE lane Sel + // =0: lane 0~3 or 0~7 + // =1: lane 4~7 + // =2: lane 8~11 or 8~15 + // =3: lane 12~15 + UCHAR ucAction; // =0: turn off encoder + // =1: turn on encoder + UCHAR ucReserved[4]; +}DIG_TRANSMITTER_CONTROL_PARAMETERS; + +#define DIG_TRANSMITTER_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PARAMETERS + +//ucInitInfo +#define ATOM_TRAMITTER_INITINFO_CONNECTOR_MASK 0x00ff + +//ucConfig +#define ATOM_TRANSMITTER_CONFIG_8LANE_LINK 0x01 +#define ATOM_TRANSMITTER_CONFIG_COHERENT 0x02 +#define ATOM_TRANSMITTER_CONFIG_LINK_SEL_MASK 0x04 +#define ATOM_TRANSMITTER_CONFIG_LINKA 0x00 +#define ATOM_TRANSMITTER_CONFIG_LINKB 0x04 +#define ATOM_TRANSMITTER_CONFIG_LINKA_B 0x00 +#define ATOM_TRANSMITTER_CONFIG_LINKB_A 0x04 + +#define ATOM_TRANSMITTER_CONFIG_ENCODER_SEL_MASK 0x08 // only used when ATOM_TRANSMITTER_ACTION_ENABLE +#define ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER 0x00 // only used when ATOM_TRANSMITTER_ACTION_ENABLE +#define ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER 0x08 // only used when ATOM_TRANSMITTER_ACTION_ENABLE + +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_MASK 0x30 +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL 0x00 +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PCIE 0x20 +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_XTALIN 0x30 +#define ATOM_TRANSMITTER_CONFIG_LANE_SEL_MASK 0xc0 +#define ATOM_TRANSMITTER_CONFIG_LANE_0_3 0x00 +#define ATOM_TRANSMITTER_CONFIG_LANE_0_7 0x00 +#define ATOM_TRANSMITTER_CONFIG_LANE_4_7 0x40 +#define ATOM_TRANSMITTER_CONFIG_LANE_8_11 0x80 +#define ATOM_TRANSMITTER_CONFIG_LANE_8_15 0x80 +#define ATOM_TRANSMITTER_CONFIG_LANE_12_15 0xc0 + +//ucAction +#define ATOM_TRANSMITTER_ACTION_DISABLE 0 +#define ATOM_TRANSMITTER_ACTION_ENABLE 1 +#define ATOM_TRANSMITTER_ACTION_LCD_BLOFF 2 +#define ATOM_TRANSMITTER_ACTION_LCD_BLON 3 +#define ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL 4 +#define ATOM_TRANSMITTER_ACTION_LCD_SELFTEST_START 5 +#define ATOM_TRANSMITTER_ACTION_LCD_SELFTEST_STOP 6 +#define ATOM_TRANSMITTER_ACTION_INIT 7 +#define ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT 8 +#define ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT 9 +#define ATOM_TRANSMITTER_ACTION_SETUP 10 +#define ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH 11 +#define ATOM_TRANSMITTER_ACTION_POWER_ON 12 +#define ATOM_TRANSMITTER_ACTION_POWER_OFF 13 + +// Following are used for DigTransmitterControlTable ver1.2 +typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V2 +{ +#if ATOM_BIG_ENDIAN + UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) + // =1 Dig Transmitter 2 ( Uniphy CD ) + // =2 Dig Transmitter 3 ( Uniphy EF ) + UCHAR ucReserved:1; + UCHAR fDPConnector:1; //bit4=0: DP connector =1: None DP connector + UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 ) + UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E + // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F + + UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode ) + UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector +#else + UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector + UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode ) + UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E + // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F + UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 ) + UCHAR fDPConnector:1; //bit4=0: DP connector =1: None DP connector + UCHAR ucReserved:1; + UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) + // =1 Dig Transmitter 2 ( Uniphy CD ) + // =2 Dig Transmitter 3 ( Uniphy EF ) +#endif +}ATOM_DIG_TRANSMITTER_CONFIG_V2; + +//ucConfig +//Bit0 +#define ATOM_TRANSMITTER_CONFIG_V2_DUAL_LINK_CONNECTOR 0x01 + +//Bit1 +#define ATOM_TRANSMITTER_CONFIG_V2_COHERENT 0x02 + +//Bit2 +#define ATOM_TRANSMITTER_CONFIG_V2_LINK_SEL_MASK 0x04 +#define ATOM_TRANSMITTER_CONFIG_V2_LINKA 0x00 +#define ATOM_TRANSMITTER_CONFIG_V2_LINKB 0x04 + +// Bit3 +#define ATOM_TRANSMITTER_CONFIG_V2_ENCODER_SEL_MASK 0x08 +#define ATOM_TRANSMITTER_CONFIG_V2_DIG1_ENCODER 0x00 // only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP +#define ATOM_TRANSMITTER_CONFIG_V2_DIG2_ENCODER 0x08 // only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP + +// Bit4 +#define ATOM_TRASMITTER_CONFIG_V2_DP_CONNECTOR 0x10 + +// Bit7:6 +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER_SEL_MASK 0xC0 +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER1 0x00 //AB +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER2 0x40 //CD +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER3 0x80 //EF + +typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 +{ + union + { + USHORT usPixelClock; // in 10KHz; for bios convenient + USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h + ATOM_DP_VS_MODE asMode; // DP Voltage swing mode + }; + ATOM_DIG_TRANSMITTER_CONFIG_V2 acConfig; + UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_XXX + UCHAR ucReserved[4]; +}DIG_TRANSMITTER_CONTROL_PARAMETERS_V2; + +typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V3 +{ +#if ATOM_BIG_ENDIAN + UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) + // =1 Dig Transmitter 2 ( Uniphy CD ) + // =2 Dig Transmitter 3 ( Uniphy EF ) + UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, EXT_CLK=2 + UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F + UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E + // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F + UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode ) + UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector +#else + UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector + UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode ) + UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E + // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F + UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F + UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, EXT_CLK=2 + UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) + // =1 Dig Transmitter 2 ( Uniphy CD ) + // =2 Dig Transmitter 3 ( Uniphy EF ) +#endif +}ATOM_DIG_TRANSMITTER_CONFIG_V3; + +typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 +{ + union + { + USHORT usPixelClock; // in 10KHz; for bios convenient + USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h + ATOM_DP_VS_MODE asMode; // DP Voltage swing mode + }; + ATOM_DIG_TRANSMITTER_CONFIG_V3 acConfig; + UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_XXX + UCHAR ucLaneNum; + UCHAR ucReserved[3]; +}DIG_TRANSMITTER_CONTROL_PARAMETERS_V3; + +//ucConfig +//Bit0 +#define ATOM_TRANSMITTER_CONFIG_V3_DUAL_LINK_CONNECTOR 0x01 + +//Bit1 +#define ATOM_TRANSMITTER_CONFIG_V3_COHERENT 0x02 + +//Bit2 +#define ATOM_TRANSMITTER_CONFIG_V3_LINK_SEL_MASK 0x04 +#define ATOM_TRANSMITTER_CONFIG_V3_LINKA 0x00 +#define ATOM_TRANSMITTER_CONFIG_V3_LINKB 0x04 + +// Bit3 +#define ATOM_TRANSMITTER_CONFIG_V3_ENCODER_SEL_MASK 0x08 +#define ATOM_TRANSMITTER_CONFIG_V3_DIG1_ENCODER 0x00 +#define ATOM_TRANSMITTER_CONFIG_V3_DIG2_ENCODER 0x08 + +// Bit5:4 +#define ATOM_TRASMITTER_CONFIG_V3_REFCLK_SEL_MASK 0x30 +#define ATOM_TRASMITTER_CONFIG_V3_P1PLL 0x00 +#define ATOM_TRASMITTER_CONFIG_V3_P2PLL 0x10 +#define ATOM_TRASMITTER_CONFIG_V3_REFCLK_SRC_EXT 0x20 + +// Bit7:6 +#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER_SEL_MASK 0xC0 +#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER1 0x00 //AB +#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER2 0x40 //CD +#define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER3 0x80 //EF + +/****************************************************************************/ +// Structures used by DAC1OuputControlTable +// DAC2OuputControlTable +// LVTMAOutputControlTable (Before DEC30) +// TMDSAOutputControlTable (Before DEC30) +/****************************************************************************/ +typedef struct _DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +{ + UCHAR ucAction; // Possible input:ATOM_ENABLE||ATOMDISABLE + // When the display is LCD, in addition to above: + // ATOM_LCD_BLOFF|| ATOM_LCD_BLON ||ATOM_LCD_BL_BRIGHTNESS_CONTROL||ATOM_LCD_SELFTEST_START|| + // ATOM_LCD_SELFTEST_STOP + + UCHAR aucPadding[3]; // padding to DWORD aligned +}DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS; + +#define DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS + + +#define CRT1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define CRT1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define CRT2_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define CRT2_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define CV1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define CV1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define TV1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define TV1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define DFP1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define DFP1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define DFP2_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define DFP2_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define LCD1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define LCD1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define DVO_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define DVO_OUTPUT_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PS_ALLOCATION +#define DVO_OUTPUT_CONTROL_PARAMETERS_V3 DIG_TRANSMITTER_CONTROL_PARAMETERS + +/****************************************************************************/ +// Structures used by BlankCRTCTable +/****************************************************************************/ +typedef struct _BLANK_CRTC_PARAMETERS +{ + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucBlanking; // ATOM_BLANKING or ATOM_BLANKINGOFF + USHORT usBlackColorRCr; + USHORT usBlackColorGY; + USHORT usBlackColorBCb; +}BLANK_CRTC_PARAMETERS; +#define BLANK_CRTC_PS_ALLOCATION BLANK_CRTC_PARAMETERS + +/****************************************************************************/ +// Structures used by EnableCRTCTable +// EnableCRTCMemReqTable +// UpdateCRTC_DoubleBufferRegistersTable +/****************************************************************************/ +typedef struct _ENABLE_CRTC_PARAMETERS +{ + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[2]; +}ENABLE_CRTC_PARAMETERS; +#define ENABLE_CRTC_PS_ALLOCATION ENABLE_CRTC_PARAMETERS + +/****************************************************************************/ +// Structures used by SetCRTC_OverScanTable +/****************************************************************************/ +typedef struct _SET_CRTC_OVERSCAN_PARAMETERS +{ + USHORT usOverscanRight; // right + USHORT usOverscanLeft; // left + USHORT usOverscanBottom; // bottom + USHORT usOverscanTop; // top + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucPadding[3]; +}SET_CRTC_OVERSCAN_PARAMETERS; +#define SET_CRTC_OVERSCAN_PS_ALLOCATION SET_CRTC_OVERSCAN_PARAMETERS + +/****************************************************************************/ +// Structures used by SetCRTC_ReplicationTable +/****************************************************************************/ +typedef struct _SET_CRTC_REPLICATION_PARAMETERS +{ + UCHAR ucH_Replication; // horizontal replication + UCHAR ucV_Replication; // vertical replication + UCHAR usCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucPadding; +}SET_CRTC_REPLICATION_PARAMETERS; +#define SET_CRTC_REPLICATION_PS_ALLOCATION SET_CRTC_REPLICATION_PARAMETERS + +/****************************************************************************/ +// Structures used by SelectCRTC_SourceTable +/****************************************************************************/ +typedef struct _SELECT_CRTC_SOURCE_PARAMETERS +{ + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucDevice; // ATOM_DEVICE_CRT1|ATOM_DEVICE_CRT2|.... + UCHAR ucPadding[2]; +}SELECT_CRTC_SOURCE_PARAMETERS; +#define SELECT_CRTC_SOURCE_PS_ALLOCATION SELECT_CRTC_SOURCE_PARAMETERS + +typedef struct _SELECT_CRTC_SOURCE_PARAMETERS_V2 +{ + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucEncoderID; // DAC1/DAC2/TVOUT/DIG1/DIG2/DVO + UCHAR ucEncodeMode; // Encoding mode, only valid when using DIG1/DIG2/DVO + UCHAR ucPadding; +}SELECT_CRTC_SOURCE_PARAMETERS_V2; + +//ucEncoderID +//#define ASIC_INT_DAC1_ENCODER_ID 0x00 +//#define ASIC_INT_TV_ENCODER_ID 0x02 +//#define ASIC_INT_DIG1_ENCODER_ID 0x03 +//#define ASIC_INT_DAC2_ENCODER_ID 0x04 +//#define ASIC_EXT_TV_ENCODER_ID 0x06 +//#define ASIC_INT_DVO_ENCODER_ID 0x07 +//#define ASIC_INT_DIG2_ENCODER_ID 0x09 +//#define ASIC_EXT_DIG_ENCODER_ID 0x05 + +//ucEncodeMode +//#define ATOM_ENCODER_MODE_DP 0 +//#define ATOM_ENCODER_MODE_LVDS 1 +//#define ATOM_ENCODER_MODE_DVI 2 +//#define ATOM_ENCODER_MODE_HDMI 3 +//#define ATOM_ENCODER_MODE_SDVO 4 +//#define ATOM_ENCODER_MODE_TV 13 +//#define ATOM_ENCODER_MODE_CV 14 +//#define ATOM_ENCODER_MODE_CRT 15 + +/****************************************************************************/ +// Structures used by SetPixelClockTable +// GetPixelClockTable +/****************************************************************************/ +//Major revision=1., Minor revision=1 +typedef struct _PIXEL_CLOCK_PARAMETERS +{ + USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) + // 0 means disable PPLL + USHORT usRefDiv; // Reference divider + USHORT usFbDiv; // feedback divider + UCHAR ucPostDiv; // post divider + UCHAR ucFracFbDiv; // fractional feedback divider + UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2 + UCHAR ucRefDivSrc; // ATOM_PJITTER or ATO_NONPJITTER + UCHAR ucCRTC; // Which CRTC uses this Ppll + UCHAR ucPadding; +}PIXEL_CLOCK_PARAMETERS; + +//Major revision=1., Minor revision=2, add ucMiscIfno +//ucMiscInfo: +#define MISC_FORCE_REPROG_PIXEL_CLOCK 0x1 +#define MISC_DEVICE_INDEX_MASK 0xF0 +#define MISC_DEVICE_INDEX_SHIFT 4 + +typedef struct _PIXEL_CLOCK_PARAMETERS_V2 +{ + USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) + // 0 means disable PPLL + USHORT usRefDiv; // Reference divider + USHORT usFbDiv; // feedback divider + UCHAR ucPostDiv; // post divider + UCHAR ucFracFbDiv; // fractional feedback divider + UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2 + UCHAR ucRefDivSrc; // ATOM_PJITTER or ATO_NONPJITTER + UCHAR ucCRTC; // Which CRTC uses this Ppll + UCHAR ucMiscInfo; // Different bits for different purpose, bit [7:4] as device index, bit[0]=Force prog +}PIXEL_CLOCK_PARAMETERS_V2; + +//Major revision=1., Minor revision=3, structure/definition change +//ucEncoderMode: +//ATOM_ENCODER_MODE_DP +//ATOM_ENOCDER_MODE_LVDS +//ATOM_ENOCDER_MODE_DVI +//ATOM_ENOCDER_MODE_HDMI +//ATOM_ENOCDER_MODE_SDVO +//ATOM_ENCODER_MODE_TV 13 +//ATOM_ENCODER_MODE_CV 14 +//ATOM_ENCODER_MODE_CRT 15 + +//ucDVOConfig +//#define DVO_ENCODER_CONFIG_RATE_SEL 0x01 +//#define DVO_ENCODER_CONFIG_DDR_SPEED 0x00 +//#define DVO_ENCODER_CONFIG_SDR_SPEED 0x01 +//#define DVO_ENCODER_CONFIG_OUTPUT_SEL 0x0c +//#define DVO_ENCODER_CONFIG_LOW12BIT 0x00 +//#define DVO_ENCODER_CONFIG_UPPER12BIT 0x04 +//#define DVO_ENCODER_CONFIG_24BIT 0x08 + +//ucMiscInfo: also changed, see below +#define PIXEL_CLOCK_MISC_FORCE_PROG_PPLL 0x01 +#define PIXEL_CLOCK_MISC_VGA_MODE 0x02 +#define PIXEL_CLOCK_MISC_CRTC_SEL_MASK 0x04 +#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1 0x00 +#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2 0x04 +#define PIXEL_CLOCK_MISC_USE_ENGINE_FOR_DISPCLK 0x08 +#define PIXEL_CLOCK_MISC_REF_DIV_SRC 0x10 +// V1.4 for RoadRunner +#define PIXEL_CLOCK_V4_MISC_SS_ENABLE 0x10 +#define PIXEL_CLOCK_V4_MISC_COHERENT_MODE 0x20 + +typedef struct _PIXEL_CLOCK_PARAMETERS_V3 +{ + USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) + // 0 means disable PPLL. For VGA PPLL,make sure this value is not 0. + USHORT usRefDiv; // Reference divider + USHORT usFbDiv; // feedback divider + UCHAR ucPostDiv; // post divider + UCHAR ucFracFbDiv; // fractional feedback divider + UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2 + UCHAR ucTransmitterId; // graphic encoder id defined in objectId.h + union + { + UCHAR ucEncoderMode; // encoder type defined as ATOM_ENCODER_MODE_DP/DVI/HDMI/ + UCHAR ucDVOConfig; // when use DVO, need to know SDR/DDR, 12bit or 24bit + }; + UCHAR ucMiscInfo; // bit[0]=Force program, bit[1]= set pclk for VGA, b[2]= CRTC sel + // bit[3]=0:use PPLL for dispclk source, =1: use engine clock for dispclock source + // bit[4]=0:use XTALIN as the source of reference divider,=1 use the pre-defined clock as the source of reference divider +}PIXEL_CLOCK_PARAMETERS_V3; + +#define PIXEL_CLOCK_PARAMETERS_LAST PIXEL_CLOCK_PARAMETERS_V2 +#define GET_PIXEL_CLOCK_PS_ALLOCATION PIXEL_CLOCK_PARAMETERS_LAST + +typedef struct _PIXEL_CLOCK_PARAMETERS_V5 +{ + UCHAR ucCRTC; // ATOM_CRTC1~6, indicate the CRTC controller to + // drive the pixel clock. not used for DCPLL case. + union{ + UCHAR ucReserved; + UCHAR ucFracFbDiv; // [gphan] temporary to prevent build problem. remove it after driver code is changed. + }; + USHORT usPixelClock; // target the pixel clock to drive the CRTC timing + // 0 means disable PPLL/DCPLL. + USHORT usFbDiv; // feedback divider integer part. + UCHAR ucPostDiv; // post divider. + UCHAR ucRefDiv; // Reference divider + UCHAR ucPpll; // ATOM_PPLL1/ATOM_PPLL2/ATOM_DCPLL + UCHAR ucTransmitterID; // ASIC encoder id defined in objectId.h, + // indicate which graphic encoder will be used. + UCHAR ucEncoderMode; // Encoder mode: + UCHAR ucMiscInfo; // bit[0]= Force program PPLL + // bit[1]= when VGA timing is used. + // bit[3:2]= HDMI panel bit depth: =0: 24bpp =1:30bpp, =2:32bpp + // bit[4]= RefClock source for PPLL. + // =0: XTLAIN( default mode ) + // =1: other external clock source, which is pre-defined + // by VBIOS depend on the feature required. + // bit[7:5]: reserved. + ULONG ulFbDivDecFrac; // 20 bit feedback divider decimal fraction part, range from 1~999999 ( 0.000001 to 0.999999 ) + +}PIXEL_CLOCK_PARAMETERS_V5; + +#define PIXEL_CLOCK_V5_MISC_FORCE_PROG_PPLL 0x01 +#define PIXEL_CLOCK_V5_MISC_VGA_MODE 0x02 +#define PIXEL_CLOCK_V5_MISC_HDMI_BPP_MASK 0x0c +#define PIXEL_CLOCK_V5_MISC_HDMI_24BPP 0x00 +#define PIXEL_CLOCK_V5_MISC_HDMI_30BPP 0x04 +#define PIXEL_CLOCK_V5_MISC_HDMI_32BPP 0x08 +#define PIXEL_CLOCK_V5_MISC_REF_DIV_SRC 0x10 + +typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2 +{ + PIXEL_CLOCK_PARAMETERS_V3 sDispClkInput; +}GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2; + +typedef struct _GET_DISP_PLL_STATUS_OUTPUT_PARAMETERS_V2 +{ + UCHAR ucStatus; + UCHAR ucRefDivSrc; // =1: reference clock source from XTALIN, =0: source from PCIE ref clock + UCHAR ucReserved[2]; +}GET_DISP_PLL_STATUS_OUTPUT_PARAMETERS_V2; + +typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V3 +{ + PIXEL_CLOCK_PARAMETERS_V5 sDispClkInput; +}GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V3; + +/****************************************************************************/ +// Structures used by AdjustDisplayPllTable +/****************************************************************************/ +typedef struct _ADJUST_DISPLAY_PLL_PARAMETERS +{ + USHORT usPixelClock; + UCHAR ucTransmitterID; + UCHAR ucEncodeMode; + union + { + UCHAR ucDVOConfig; //if DVO, need passing link rate and output 12bitlow or 24bit + UCHAR ucConfig; //if none DVO, not defined yet + }; + UCHAR ucReserved[3]; +}ADJUST_DISPLAY_PLL_PARAMETERS; + +#define ADJUST_DISPLAY_CONFIG_SS_ENABLE 0x10 +#define ADJUST_DISPLAY_PLL_PS_ALLOCATION ADJUST_DISPLAY_PLL_PARAMETERS + +typedef struct _ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3 +{ + USHORT usPixelClock; // target pixel clock + UCHAR ucTransmitterID; // transmitter id defined in objectid.h + UCHAR ucEncodeMode; // encoder mode: CRT, LVDS, DP, TMDS or HDMI + UCHAR ucDispPllConfig; // display pll configure parameter defined as following DISPPLL_CONFIG_XXXX + UCHAR ucReserved[3]; +}ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3; + +// usDispPllConfig v1.2 for RoadRunner +#define DISPPLL_CONFIG_DVO_RATE_SEL 0x0001 // need only when ucTransmitterID = DVO +#define DISPPLL_CONFIG_DVO_DDR_SPEED 0x0000 // need only when ucTransmitterID = DVO +#define DISPPLL_CONFIG_DVO_SDR_SPEED 0x0001 // need only when ucTransmitterID = DVO +#define DISPPLL_CONFIG_DVO_OUTPUT_SEL 0x000c // need only when ucTransmitterID = DVO +#define DISPPLL_CONFIG_DVO_LOW12BIT 0x0000 // need only when ucTransmitterID = DVO +#define DISPPLL_CONFIG_DVO_UPPER12BIT 0x0004 // need only when ucTransmitterID = DVO +#define DISPPLL_CONFIG_DVO_24BIT 0x0008 // need only when ucTransmitterID = DVO +#define DISPPLL_CONFIG_SS_ENABLE 0x0010 // Only used when ucEncoderMode = DP or LVDS +#define DISPPLL_CONFIG_COHERENT_MODE 0x0020 // Only used when ucEncoderMode = TMDS or HDMI +#define DISPPLL_CONFIG_DUAL_LINK 0x0040 // Only used when ucEncoderMode = TMDS or LVDS + + +typedef struct _ADJUST_DISPLAY_PLL_OUTPUT_PARAMETERS_V3 +{ + ULONG ulDispPllFreq; // return display PPLL freq which is used to generate the pixclock, and related idclk, symclk etc + UCHAR ucRefDiv; // if it is none-zero, it is used to be calculated the other ppll parameter fb_divider and post_div ( if it is not given ) + UCHAR ucPostDiv; // if it is none-zero, it is used to be calculated the other ppll parameter fb_divider + UCHAR ucReserved[2]; +}ADJUST_DISPLAY_PLL_OUTPUT_PARAMETERS_V3; + +typedef struct _ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 +{ + union + { + ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3 sInput; + ADJUST_DISPLAY_PLL_OUTPUT_PARAMETERS_V3 sOutput; + }; +} ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3; + +/****************************************************************************/ +// Structures used by EnableYUVTable +/****************************************************************************/ +typedef struct _ENABLE_YUV_PARAMETERS +{ + UCHAR ucEnable; // ATOM_ENABLE:Enable YUV or ATOM_DISABLE:Disable YUV (RGB) + UCHAR ucCRTC; // Which CRTC needs this YUV or RGB format + UCHAR ucPadding[2]; +}ENABLE_YUV_PARAMETERS; +#define ENABLE_YUV_PS_ALLOCATION ENABLE_YUV_PARAMETERS + +/****************************************************************************/ +// Structures used by GetMemoryClockTable +/****************************************************************************/ +typedef struct _GET_MEMORY_CLOCK_PARAMETERS +{ + ULONG ulReturnMemoryClock; // current memory speed in 10KHz unit +} GET_MEMORY_CLOCK_PARAMETERS; +#define GET_MEMORY_CLOCK_PS_ALLOCATION GET_MEMORY_CLOCK_PARAMETERS + +/****************************************************************************/ +// Structures used by GetEngineClockTable +/****************************************************************************/ +typedef struct _GET_ENGINE_CLOCK_PARAMETERS +{ + ULONG ulReturnEngineClock; // current engine speed in 10KHz unit +} GET_ENGINE_CLOCK_PARAMETERS; +#define GET_ENGINE_CLOCK_PS_ALLOCATION GET_ENGINE_CLOCK_PARAMETERS + +/****************************************************************************/ +// Following Structures and constant may be obsolete +/****************************************************************************/ +//Maxium 8 bytes,the data read in will be placed in the parameter space. +//Read operaion successeful when the paramter space is non-zero, otherwise read operation failed +typedef struct _READ_EDID_FROM_HW_I2C_DATA_PARAMETERS +{ + USHORT usPrescale; //Ratio between Engine clock and I2C clock + USHORT usVRAMAddress; //Adress in Frame Buffer where to pace raw EDID + USHORT usStatus; //When use output: lower byte EDID checksum, high byte hardware status + //WHen use input: lower byte as 'byte to read':currently limited to 128byte or 1byte + UCHAR ucSlaveAddr; //Read from which slave + UCHAR ucLineNumber; //Read from which HW assisted line +}READ_EDID_FROM_HW_I2C_DATA_PARAMETERS; +#define READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION READ_EDID_FROM_HW_I2C_DATA_PARAMETERS + + +#define ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSDATABYTE 0 +#define ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSTWODATABYTES 1 +#define ATOM_WRITE_I2C_FORMAT_PSCOUNTER_PSOFFSET_IDDATABLOCK 2 +#define ATOM_WRITE_I2C_FORMAT_PSCOUNTER_IDOFFSET_PLUS_IDDATABLOCK 3 +#define ATOM_WRITE_I2C_FORMAT_IDCOUNTER_IDOFFSET_IDDATABLOCK 4 + +typedef struct _WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS +{ + USHORT usPrescale; //Ratio between Engine clock and I2C clock + USHORT usByteOffset; //Write to which byte + //Upper portion of usByteOffset is Format of data + //1bytePS+offsetPS + //2bytesPS+offsetPS + //blockID+offsetPS + //blockID+offsetID + //blockID+counterID+offsetID + UCHAR ucData; //PS data1 + UCHAR ucStatus; //Status byte 1=success, 2=failure, Also is used as PS data2 + UCHAR ucSlaveAddr; //Write to which slave + UCHAR ucLineNumber; //Write from which HW assisted line +}WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS; + +#define WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +typedef struct _SET_UP_HW_I2C_DATA_PARAMETERS +{ + USHORT usPrescale; //Ratio between Engine clock and I2C clock + UCHAR ucSlaveAddr; //Write to which slave + UCHAR ucLineNumber; //Write from which HW assisted line +}SET_UP_HW_I2C_DATA_PARAMETERS; + + +/**************************************************************************/ +#define SPEED_FAN_CONTROL_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +/****************************************************************************/ +// Structures used by PowerConnectorDetectionTable +/****************************************************************************/ +typedef struct _POWER_CONNECTOR_DETECTION_PARAMETERS +{ + UCHAR ucPowerConnectorStatus; //Used for return value 0: detected, 1:not detected + UCHAR ucPwrBehaviorId; + USHORT usPwrBudget; //how much power currently boot to in unit of watt +}POWER_CONNECTOR_DETECTION_PARAMETERS; + +typedef struct POWER_CONNECTOR_DETECTION_PS_ALLOCATION +{ + UCHAR ucPowerConnectorStatus; //Used for return value 0: detected, 1:not detected + UCHAR ucReserved; + USHORT usPwrBudget; //how much power currently boot to in unit of watt + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; +}POWER_CONNECTOR_DETECTION_PS_ALLOCATION; + +/****************************LVDS SS Command Table Definitions**********************/ + +/****************************************************************************/ +// Structures used by EnableSpreadSpectrumOnPPLLTable +/****************************************************************************/ +typedef struct _ENABLE_LVDS_SS_PARAMETERS +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD + UCHAR ucSpreadSpectrumStepSize_Delay; //bits3:2 SS_STEP_SIZE; bit 6:4 SS_DELAY + UCHAR ucEnable; //ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[3]; +}ENABLE_LVDS_SS_PARAMETERS; + +//ucTableFormatRevision=1,ucTableContentRevision=2 +typedef struct _ENABLE_LVDS_SS_PARAMETERS_V2 +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD + UCHAR ucSpreadSpectrumStep; // + UCHAR ucEnable; //ATOM_ENABLE or ATOM_DISABLE + UCHAR ucSpreadSpectrumDelay; + UCHAR ucSpreadSpectrumRange; + UCHAR ucPadding; +}ENABLE_LVDS_SS_PARAMETERS_V2; + +//This new structure is based on ENABLE_LVDS_SS_PARAMETERS but expands to SS on PPLL, so other devices can use SS. +typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; // Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD + UCHAR ucSpreadSpectrumStep; // + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucSpreadSpectrumDelay; + UCHAR ucSpreadSpectrumRange; + UCHAR ucPpll; // ATOM_PPLL1/ATOM_PPLL2 +}ENABLE_SPREAD_SPECTRUM_ON_PPLL; + +typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; // Bit[0]: 0-Down Spread,1-Center Spread. + // Bit[1]: 1-Ext. 0-Int. + // Bit[3:2]: =0 P1PLL =1 P2PLL =2 DCPLL + // Bits[7:4] reserved + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + USHORT usSpreadSpectrumAmount; // Includes SS_AMOUNT_FBDIV[7:0] and SS_AMOUNT_NFRAC_SLIP[11:8] + USHORT usSpreadSpectrumStep; // SS_STEP_SIZE_DSFRAC +}ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2; + +#define ATOM_PPLL_SS_TYPE_V2_DOWN_SPREAD 0x00 +#define ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD 0x01 +#define ATOM_PPLL_SS_TYPE_V2_EXT_SPREAD 0x02 +#define ATOM_PPLL_SS_TYPE_V2_PPLL_SEL_MASK 0x0c +#define ATOM_PPLL_SS_TYPE_V2_P1PLL 0x00 +#define ATOM_PPLL_SS_TYPE_V2_P2PLL 0x04 +#define ATOM_PPLL_SS_TYPE_V2_DCPLL 0x08 +#define ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK 0x00FF +#define ATOM_PPLL_SS_AMOUNT_V2_FBDIV_SHIFT 0 +#define ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK 0x0F00 +#define ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT 8 + +#define ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION ENABLE_SPREAD_SPECTRUM_ON_PPLL + +/**************************************************************************/ + +typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION +{ + PIXEL_CLOCK_PARAMETERS sPCLKInput; + ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved;//Caller doesn't need to init this portion +}SET_PIXEL_CLOCK_PS_ALLOCATION; + +#define ENABLE_VGA_RENDER_PS_ALLOCATION SET_PIXEL_CLOCK_PS_ALLOCATION + +/****************************************************************************/ +// Structures used by ### +/****************************************************************************/ +typedef struct _MEMORY_TRAINING_PARAMETERS +{ + ULONG ulTargetMemoryClock; //In 10Khz unit +}MEMORY_TRAINING_PARAMETERS; +#define MEMORY_TRAINING_PS_ALLOCATION MEMORY_TRAINING_PARAMETERS + + +/****************************LVDS and other encoder command table definitions **********************/ + + +/****************************************************************************/ +// Structures used by LVDSEncoderControlTable (Before DCE30) +// LVTMAEncoderControlTable (Before DCE30) +// TMDSAEncoderControlTable (Before DCE30) +/****************************************************************************/ +typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucMisc; // bit0=0: Enable single link + // =1: Enable dual link + // Bit1=0: 666RGB + // =1: 888RGB + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder +}LVDS_ENCODER_CONTROL_PARAMETERS; + +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION LVDS_ENCODER_CONTROL_PARAMETERS + +#define TMDS1_ENCODER_CONTROL_PARAMETERS LVDS_ENCODER_CONTROL_PARAMETERS +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION TMDS1_ENCODER_CONTROL_PARAMETERS + +#define TMDS2_ENCODER_CONTROL_PARAMETERS TMDS1_ENCODER_CONTROL_PARAMETERS +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION TMDS2_ENCODER_CONTROL_PARAMETERS + + +//ucTableFormatRevision=1,ucTableContentRevision=2 +typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS_V2 +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucMisc; // see PANEL_ENCODER_MISC_xx defintions below + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder + UCHAR ucTruncate; // bit0=0: Disable truncate + // =1: Enable truncate + // bit4=0: 666RGB + // =1: 888RGB + UCHAR ucSpatial; // bit0=0: Disable spatial dithering + // =1: Enable spatial dithering + // bit4=0: 666RGB + // =1: 888RGB + UCHAR ucTemporal; // bit0=0: Disable temporal dithering + // =1: Enable temporal dithering + // bit4=0: 666RGB + // =1: 888RGB + // bit5=0: Gray level 2 + // =1: Gray level 4 + UCHAR ucFRC; // bit4=0: 25FRC_SEL pattern E + // =1: 25FRC_SEL pattern F + // bit6:5=0: 50FRC_SEL pattern A + // =1: 50FRC_SEL pattern B + // =2: 50FRC_SEL pattern C + // =3: 50FRC_SEL pattern D + // bit7=0: 75FRC_SEL pattern E + // =1: 75FRC_SEL pattern F +}LVDS_ENCODER_CONTROL_PARAMETERS_V2; + +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2 + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS2_ENCODER_CONTROL_PARAMETERS_V2 + +#define LVDS_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V2 +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS1_ENCODER_CONTROL_PARAMETERS_V3 + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS2_ENCODER_CONTROL_PARAMETERS_V3 + +/****************************************************************************/ +// Structures used by ### +/****************************************************************************/ +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS +{ + UCHAR ucEnable; // Enable or Disable External TMDS encoder + UCHAR ucMisc; // Bit0=0:Enable Single link;=1:Enable Dual link;Bit1 {=0:666RGB, =1:888RGB} + UCHAR ucPadding[2]; +}ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS; + +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION +{ + ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS sXTmdsEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion +}ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION; + +#define ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 + +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2 +{ + ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 sXTmdsEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion +}ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2; + +typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION +{ + DIG_ENCODER_CONTROL_PARAMETERS sDigEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; +}EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION; + +/****************************************************************************/ +// Structures used by DVOEncoderControlTable +/****************************************************************************/ +//ucTableFormatRevision=1,ucTableContentRevision=3 + +//ucDVOConfig: +#define DVO_ENCODER_CONFIG_RATE_SEL 0x01 +#define DVO_ENCODER_CONFIG_DDR_SPEED 0x00 +#define DVO_ENCODER_CONFIG_SDR_SPEED 0x01 +#define DVO_ENCODER_CONFIG_OUTPUT_SEL 0x0c +#define DVO_ENCODER_CONFIG_LOW12BIT 0x00 +#define DVO_ENCODER_CONFIG_UPPER12BIT 0x04 +#define DVO_ENCODER_CONFIG_24BIT 0x08 + +typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3 +{ + USHORT usPixelClock; + UCHAR ucDVOConfig; + UCHAR ucAction; //ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT + UCHAR ucReseved[4]; +}DVO_ENCODER_CONTROL_PARAMETERS_V3; +#define DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 DVO_ENCODER_CONTROL_PARAMETERS_V3 + +//ucTableFormatRevision=1 +//ucTableContentRevision=3 structure is not changed but usMisc add bit 1 as another input for +// bit1=0: non-coherent mode +// =1: coherent mode + +//========================================================================================== +//Only change is here next time when changing encoder parameter definitions again! +#define LVDS_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_LAST LVDS_ENCODER_CONTROL_PARAMETERS_LAST + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_LAST TMDS1_ENCODER_CONTROL_PARAMETERS_LAST + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_LAST TMDS2_ENCODER_CONTROL_PARAMETERS_LAST + +#define DVO_ENCODER_CONTROL_PARAMETERS_LAST DVO_ENCODER_CONTROL_PARAMETERS +#define DVO_ENCODER_CONTROL_PS_ALLOCATION_LAST DVO_ENCODER_CONTROL_PS_ALLOCATION + +//========================================================================================== +#define PANEL_ENCODER_MISC_DUAL 0x01 +#define PANEL_ENCODER_MISC_COHERENT 0x02 +#define PANEL_ENCODER_MISC_TMDS_LINKB 0x04 +#define PANEL_ENCODER_MISC_HDMI_TYPE 0x08 + +#define PANEL_ENCODER_ACTION_DISABLE ATOM_DISABLE +#define PANEL_ENCODER_ACTION_ENABLE ATOM_ENABLE +#define PANEL_ENCODER_ACTION_COHERENTSEQ (ATOM_ENABLE+1) + +#define PANEL_ENCODER_TRUNCATE_EN 0x01 +#define PANEL_ENCODER_TRUNCATE_DEPTH 0x10 +#define PANEL_ENCODER_SPATIAL_DITHER_EN 0x01 +#define PANEL_ENCODER_SPATIAL_DITHER_DEPTH 0x10 +#define PANEL_ENCODER_TEMPORAL_DITHER_EN 0x01 +#define PANEL_ENCODER_TEMPORAL_DITHER_DEPTH 0x10 +#define PANEL_ENCODER_TEMPORAL_LEVEL_4 0x20 +#define PANEL_ENCODER_25FRC_MASK 0x10 +#define PANEL_ENCODER_25FRC_E 0x00 +#define PANEL_ENCODER_25FRC_F 0x10 +#define PANEL_ENCODER_50FRC_MASK 0x60 +#define PANEL_ENCODER_50FRC_A 0x00 +#define PANEL_ENCODER_50FRC_B 0x20 +#define PANEL_ENCODER_50FRC_C 0x40 +#define PANEL_ENCODER_50FRC_D 0x60 +#define PANEL_ENCODER_75FRC_MASK 0x80 +#define PANEL_ENCODER_75FRC_E 0x00 +#define PANEL_ENCODER_75FRC_F 0x80 + +/****************************************************************************/ +// Structures used by SetVoltageTable +/****************************************************************************/ +#define SET_VOLTAGE_TYPE_ASIC_VDDC 1 +#define SET_VOLTAGE_TYPE_ASIC_MVDDC 2 +#define SET_VOLTAGE_TYPE_ASIC_MVDDQ 3 +#define SET_VOLTAGE_TYPE_ASIC_VDDCI 4 +#define SET_VOLTAGE_INIT_MODE 5 +#define SET_VOLTAGE_GET_MAX_VOLTAGE 6 //Gets the Max. voltage for the soldered Asic + +#define SET_ASIC_VOLTAGE_MODE_ALL_SOURCE 0x1 +#define SET_ASIC_VOLTAGE_MODE_SOURCE_A 0x2 +#define SET_ASIC_VOLTAGE_MODE_SOURCE_B 0x4 + +#define SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE 0x0 +#define SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL 0x1 +#define SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK 0x2 + +typedef struct _SET_VOLTAGE_PARAMETERS +{ + UCHAR ucVoltageType; // To tell which voltage to set up, VDDC/MVDDC/MVDDQ + UCHAR ucVoltageMode; // To set all, to set source A or source B or ... + UCHAR ucVoltageIndex; // An index to tell which voltage level + UCHAR ucReserved; +}SET_VOLTAGE_PARAMETERS; + +typedef struct _SET_VOLTAGE_PARAMETERS_V2 +{ + UCHAR ucVoltageType; // To tell which voltage to set up, VDDC/MVDDC/MVDDQ + UCHAR ucVoltageMode; // Not used, maybe use for state machine for differen power mode + USHORT usVoltageLevel; // real voltage level +}SET_VOLTAGE_PARAMETERS_V2; + +typedef struct _SET_VOLTAGE_PS_ALLOCATION +{ + SET_VOLTAGE_PARAMETERS sASICSetVoltage; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; +}SET_VOLTAGE_PS_ALLOCATION; + +/****************************************************************************/ +// Structures used by TVEncoderControlTable +/****************************************************************************/ +typedef struct _TV_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucTvStandard; // See definition "ATOM_TV_NTSC ..." + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder +}TV_ENCODER_CONTROL_PARAMETERS; + +typedef struct _TV_ENCODER_CONTROL_PS_ALLOCATION +{ + TV_ENCODER_CONTROL_PARAMETERS sTVEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; // Don't set this one +}TV_ENCODER_CONTROL_PS_ALLOCATION; + +//==============================Data Table Portion==================================== + +/****************************************************************************/ +// Structure used in Data.mtb +/****************************************************************************/ +typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES +{ + USHORT UtilityPipeLine; // Offest for the utility to get parser info,Don't change this position! + USHORT MultimediaCapabilityInfo; // Only used by MM Lib,latest version 1.1, not configuable from Bios, need to include the table to build Bios + USHORT MultimediaConfigInfo; // Only used by MM Lib,latest version 2.1, not configuable from Bios, need to include the table to build Bios + USHORT StandardVESA_Timing; // Only used by Bios + USHORT FirmwareInfo; // Shared by various SW components,latest version 1.4 + USHORT DAC_Info; // Will be obsolete from R600 + USHORT LVDS_Info; // Shared by various SW components,latest version 1.1 + USHORT TMDS_Info; // Will be obsolete from R600 + USHORT AnalogTV_Info; // Shared by various SW components,latest version 1.1 + USHORT SupportedDevicesInfo; // Will be obsolete from R600 + USHORT GPIO_I2C_Info; // Shared by various SW components,latest version 1.2 will be used from R600 + USHORT VRAM_UsageByFirmware; // Shared by various SW components,latest version 1.3 will be used from R600 + USHORT GPIO_Pin_LUT; // Shared by various SW components,latest version 1.1 + USHORT VESA_ToInternalModeLUT; // Only used by Bios + USHORT ComponentVideoInfo; // Shared by various SW components,latest version 2.1 will be used from R600 + USHORT PowerPlayInfo; // Shared by various SW components,latest version 2.1,new design from R600 + USHORT CompassionateData; // Will be obsolete from R600 + USHORT SaveRestoreInfo; // Only used by Bios + USHORT PPLL_SS_Info; // Shared by various SW components,latest version 1.2, used to call SS_Info, change to new name because of int ASIC SS info + USHORT OemInfo; // Defined and used by external SW, should be obsolete soon + USHORT XTMDS_Info; // Will be obsolete from R600 + USHORT MclkSS_Info; // Shared by various SW components,latest version 1.1, only enabled when ext SS chip is used + USHORT Object_Header; // Shared by various SW components,latest version 1.1 + USHORT IndirectIOAccess; // Only used by Bios,this table position can't change at all!! + USHORT MC_InitParameter; // Only used by command table + USHORT ASIC_VDDC_Info; // Will be obsolete from R600 + USHORT ASIC_InternalSS_Info; // New tabel name from R600, used to be called "ASIC_MVDDC_Info" + USHORT TV_VideoMode; // Only used by command table + USHORT VRAM_Info; // Only used by command table, latest version 1.3 + USHORT MemoryTrainingInfo; // Used for VBIOS and Diag utility for memory training purpose since R600. the new table rev start from 2.1 + USHORT IntegratedSystemInfo; // Shared by various SW components + USHORT ASIC_ProfilingInfo; // New table name from R600, used to be called "ASIC_VDDCI_Info" for pre-R600 + USHORT VoltageObjectInfo; // Shared by various SW components, latest version 1.1 + USHORT PowerSourceInfo; // Shared by various SW components, latest versoin 1.1 +}ATOM_MASTER_LIST_OF_DATA_TABLES; + +typedef struct _ATOM_MASTER_DATA_TABLE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_MASTER_LIST_OF_DATA_TABLES ListOfDataTables; +}ATOM_MASTER_DATA_TABLE; + +/****************************************************************************/ +// Structure used in MultimediaCapabilityInfoTable +/****************************************************************************/ +typedef struct _ATOM_MULTIMEDIA_CAPABILITY_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulSignature; // HW info table signature string "$ATI" + UCHAR ucI2C_Type; // I2C type (normal GP_IO, ImpactTV GP_IO, Dedicated I2C pin, etc) + UCHAR ucTV_OutInfo; // Type of TV out supported (3:0) and video out crystal frequency (6:4) and TV data port (7) + UCHAR ucVideoPortInfo; // Provides the video port capabilities + UCHAR ucHostPortInfo; // Provides host port configuration information +}ATOM_MULTIMEDIA_CAPABILITY_INFO; + +/****************************************************************************/ +// Structure used in MultimediaConfigInfoTable +/****************************************************************************/ +typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulSignature; // MM info table signature sting "$MMT" + UCHAR ucTunerInfo; // Type of tuner installed on the adapter (4:0) and video input for tuner (7:5) + UCHAR ucAudioChipInfo; // List the audio chip type (3:0) product type (4) and OEM revision (7:5) + UCHAR ucProductID; // Defines as OEM ID or ATI board ID dependent on product type setting + UCHAR ucMiscInfo1; // Tuner voltage (1:0) HW teletext support (3:2) FM audio decoder (5:4) reserved (6) audio scrambling (7) + UCHAR ucMiscInfo2; // I2S input config (0) I2S output config (1) I2S Audio Chip (4:2) SPDIF Output Config (5) reserved (7:6) + UCHAR ucMiscInfo3; // Video Decoder Type (3:0) Video In Standard/Crystal (7:4) + UCHAR ucMiscInfo4; // Video Decoder Host Config (2:0) reserved (7:3) + UCHAR ucVideoInput0Info;// Video Input 0 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) + UCHAR ucVideoInput1Info;// Video Input 1 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) + UCHAR ucVideoInput2Info;// Video Input 2 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) + UCHAR ucVideoInput3Info;// Video Input 3 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) + UCHAR ucVideoInput4Info;// Video Input 4 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) +}ATOM_MULTIMEDIA_CONFIG_INFO; + +/****************************************************************************/ +// Structures used in FirmwareInfoTable +/****************************************************************************/ + +// usBIOSCapability Defintion: +// Bit 0 = 0: Bios image is not Posted, =1:Bios image is Posted; +// Bit 1 = 0: Dual CRTC is not supported, =1: Dual CRTC is supported; +// Bit 2 = 0: Extended Desktop is not supported, =1: Extended Desktop is supported; +// Others: Reserved +#define ATOM_BIOS_INFO_ATOM_FIRMWARE_POSTED 0x0001 +#define ATOM_BIOS_INFO_DUAL_CRTC_SUPPORT 0x0002 +#define ATOM_BIOS_INFO_EXTENDED_DESKTOP_SUPPORT 0x0004 +#define ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT 0x0008 // (valid from v1.1 ~v1.4):=1: memclk SS enable, =0 memclk SS disable. +#define ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT 0x0010 // (valid from v1.1 ~v1.4):=1: engclk SS enable, =0 engclk SS disable. +#define ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU 0x0020 +#define ATOM_BIOS_INFO_WMI_SUPPORT 0x0040 +#define ATOM_BIOS_INFO_PPMODE_ASSIGNGED_BY_SYSTEM 0x0080 +#define ATOM_BIOS_INFO_HYPERMEMORY_SUPPORT 0x0100 +#define ATOM_BIOS_INFO_HYPERMEMORY_SIZE_MASK 0x1E00 +#define ATOM_BIOS_INFO_VPOST_WITHOUT_FIRST_MODE_SET 0x2000 +#define ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE 0x4000 +#define ATOM_BIOS_INFO_MEMORY_CLOCK_EXT_SS_SUPPORT 0x0008 // (valid from v2.1 ): =1: memclk ss enable with external ss chip +#define ATOM_BIOS_INFO_ENGINE_CLOCK_EXT_SS_SUPPORT 0x0010 // (valid from v2.1 ): =1: engclk ss enable with external ss chip + +#ifndef _H2INC + +//Please don't add or expand this bitfield structure below, this one will retire soon.! +typedef struct _ATOM_FIRMWARE_CAPABILITY +{ +#if ATOM_BIG_ENDIAN + USHORT Reserved:3; + USHORT HyperMemory_Size:4; + USHORT HyperMemory_Support:1; + USHORT PPMode_Assigned:1; + USHORT WMI_SUPPORT:1; + USHORT GPUControlsBL:1; + USHORT EngineClockSS_Support:1; + USHORT MemoryClockSS_Support:1; + USHORT ExtendedDesktopSupport:1; + USHORT DualCRTC_Support:1; + USHORT FirmwarePosted:1; +#else + USHORT FirmwarePosted:1; + USHORT DualCRTC_Support:1; + USHORT ExtendedDesktopSupport:1; + USHORT MemoryClockSS_Support:1; + USHORT EngineClockSS_Support:1; + USHORT GPUControlsBL:1; + USHORT WMI_SUPPORT:1; + USHORT PPMode_Assigned:1; + USHORT HyperMemory_Support:1; + USHORT HyperMemory_Size:4; + USHORT Reserved:3; +#endif +}ATOM_FIRMWARE_CAPABILITY; + +typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS +{ + ATOM_FIRMWARE_CAPABILITY sbfAccess; + USHORT susAccess; +}ATOM_FIRMWARE_CAPABILITY_ACCESS; + +#else + +typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS +{ + USHORT susAccess; +}ATOM_FIRMWARE_CAPABILITY_ACCESS; + +#endif + +typedef struct _ATOM_FIRMWARE_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulDriverTargetEngineClock; //In 10Khz unit + ULONG ulDriverTargetMemoryClock; //In 10Khz unit + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulASICMaxEngineClock; //In 10Khz unit + ULONG ulASICMaxMemoryClock; //In 10Khz unit + UCHAR ucASICMaxTemperature; + UCHAR ucPadding[3]; //Don't use them + ULONG aulReservedForBIOS[3]; //Don't use them + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit, the definitions above can't change!!! + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; //In 10Khz unit + USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit + UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit + UCHAR ucDesign_ID; //Indicate what is the board design + UCHAR ucMemoryModule_ID; //Indicate what is the board design +}ATOM_FIRMWARE_INFO; + +typedef struct _ATOM_FIRMWARE_INFO_V1_2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulDriverTargetEngineClock; //In 10Khz unit + ULONG ulDriverTargetMemoryClock; //In 10Khz unit + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulASICMaxEngineClock; //In 10Khz unit + ULONG ulASICMaxMemoryClock; //In 10Khz unit + UCHAR ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + UCHAR ucPadding[2]; //Don't use them + ULONG aulReservedForBIOS[2]; //Don't use them + ULONG ulMinPixelClockPLL_Output; //In 10Khz unit + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; //In 10Khz unit + USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit + UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit + UCHAR ucDesign_ID; //Indicate what is the board design + UCHAR ucMemoryModule_ID; //Indicate what is the board design +}ATOM_FIRMWARE_INFO_V1_2; + +typedef struct _ATOM_FIRMWARE_INFO_V1_3 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulDriverTargetEngineClock; //In 10Khz unit + ULONG ulDriverTargetMemoryClock; //In 10Khz unit + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulASICMaxEngineClock; //In 10Khz unit + ULONG ulASICMaxMemoryClock; //In 10Khz unit + UCHAR ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + UCHAR ucPadding[2]; //Don't use them + ULONG aulReservedForBIOS; //Don't use them + ULONG ul3DAccelerationEngineClock;//In 10Khz unit + ULONG ulMinPixelClockPLL_Output; //In 10Khz unit + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; //In 10Khz unit + USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit + UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit + UCHAR ucDesign_ID; //Indicate what is the board design + UCHAR ucMemoryModule_ID; //Indicate what is the board design +}ATOM_FIRMWARE_INFO_V1_3; + +typedef struct _ATOM_FIRMWARE_INFO_V1_4 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulDriverTargetEngineClock; //In 10Khz unit + ULONG ulDriverTargetMemoryClock; //In 10Khz unit + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulASICMaxEngineClock; //In 10Khz unit + ULONG ulASICMaxMemoryClock; //In 10Khz unit + UCHAR ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + USHORT usBootUpVDDCVoltage; //In MV unit + USHORT usLcdMinPixelClockPLL_Output; // In MHz unit + USHORT usLcdMaxPixelClockPLL_Output; // In MHz unit + ULONG ul3DAccelerationEngineClock;//In 10Khz unit + ULONG ulMinPixelClockPLL_Output; //In 10Khz unit + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; //In 10Khz unit + USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit + UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit + UCHAR ucDesign_ID; //Indicate what is the board design + UCHAR ucMemoryModule_ID; //Indicate what is the board design +}ATOM_FIRMWARE_INFO_V1_4; + +//the structure below to be used from Cypress +typedef struct _ATOM_FIRMWARE_INFO_V2_1 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulReserved1; + ULONG ulReserved2; + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulBinaryAlteredInfo; //Was ulASICMaxEngineClock + ULONG ulDefaultDispEngineClkFreq; //In 10Khz unit + UCHAR ucReserved1; //Was ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + USHORT usBootUpVDDCVoltage; //In MV unit + USHORT usLcdMinPixelClockPLL_Output; // In MHz unit + USHORT usLcdMaxPixelClockPLL_Output; // In MHz unit + ULONG ulReserved4; //Was ulAsicMaximumVoltage + ULONG ulMinPixelClockPLL_Output; //In 10Khz unit + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usCoreReferenceClock; //In 10Khz unit + USHORT usMemoryReferenceClock; //In 10Khz unit + USHORT usUniphyDPModeExtClkFreq; //In 10Khz unit, if it is 0, In DP Mode Uniphy Input clock from internal PPLL, otherwise Input clock from external Spread clock + UCHAR ucMemoryModule_ID; //Indicate what is the board design + UCHAR ucReserved4[3]; +}ATOM_FIRMWARE_INFO_V2_1; + + +#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V2_1 + +/****************************************************************************/ +// Structures used in IntegratedSystemInfoTable +/****************************************************************************/ +#define IGP_CAP_FLAG_DYNAMIC_CLOCK_EN 0x2 +#define IGP_CAP_FLAG_AC_CARD 0x4 +#define IGP_CAP_FLAG_SDVO_CARD 0x8 +#define IGP_CAP_FLAG_POSTDIV_BY_2_MODE 0x10 + +typedef struct _ATOM_INTEGRATED_SYSTEM_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulBootUpEngineClock; //in 10kHz unit + ULONG ulBootUpMemoryClock; //in 10kHz unit + ULONG ulMaxSystemMemoryClock; //in 10kHz unit + ULONG ulMinSystemMemoryClock; //in 10kHz unit + UCHAR ucNumberOfCyclesInPeriodHi; + UCHAR ucLCDTimingSel; //=0:not valid.!=0 sel this timing descriptor from LCD EDID. + USHORT usReserved1; + USHORT usInterNBVoltageLow; //An intermidiate PMW value to set the voltage + USHORT usInterNBVoltageHigh; //Another intermidiate PMW value to set the voltage + ULONG ulReserved[2]; + + USHORT usFSBClock; //In MHz unit + USHORT usCapabilityFlag; //Bit0=1 indicates the fake HDMI support,Bit1=0/1 for Dynamic clocking dis/enable + //Bit[3:2]== 0:No PCIE card, 1:AC card, 2:SDVO card + //Bit[4]==1: P/2 mode, ==0: P/1 mode + USHORT usPCIENBCfgReg7; //bit[7:0]=MUX_Sel, bit[9:8]=MUX_SEL_LEVEL2, bit[10]=Lane_Reversal + USHORT usK8MemoryClock; //in MHz unit + USHORT usK8SyncStartDelay; //in 0.01 us unit + USHORT usK8DataReturnTime; //in 0.01 us unit + UCHAR ucMaxNBVoltage; + UCHAR ucMinNBVoltage; + UCHAR ucMemoryType; //[7:4]=1:DDR1;=2:DDR2;=3:DDR3.[3:0] is reserved + UCHAR ucNumberOfCyclesInPeriod; //CG.FVTHROT_PWM_CTRL_REG0.NumberOfCyclesInPeriod + UCHAR ucStartingPWM_HighTime; //CG.FVTHROT_PWM_CTRL_REG0.StartingPWM_HighTime + UCHAR ucHTLinkWidth; //16 bit vs. 8 bit + UCHAR ucMaxNBVoltageHigh; + UCHAR ucMinNBVoltageHigh; +}ATOM_INTEGRATED_SYSTEM_INFO; + +/* Explanation on entries in ATOM_INTEGRATED_SYSTEM_INFO +ulBootUpMemoryClock: For Intel IGP,it's the UMA system memory clock + For AMD IGP,it's 0 if no SidePort memory installed or it's the boot-up SidePort memory clock +ulMaxSystemMemoryClock: For Intel IGP,it's the Max freq from memory SPD if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0 + For AMD IGP,for now this can be 0 +ulMinSystemMemoryClock: For Intel IGP,it's 133MHz if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0 + For AMD IGP,for now this can be 0 + +usFSBClock: For Intel IGP,it's FSB Freq + For AMD IGP,it's HT Link Speed + +usK8MemoryClock: For AMD IGP only. For RevF CPU, set it to 200 +usK8SyncStartDelay: For AMD IGP only. Memory access latency in K8, required for watermark calculation +usK8DataReturnTime: For AMD IGP only. Memory access latency in K8, required for watermark calculation + +VC:Voltage Control +ucMaxNBVoltage: Voltage regulator dependent PWM value. Low 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all. +ucMinNBVoltage: Voltage regulator dependent PWM value. Low 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all. + +ucNumberOfCyclesInPeriod: Indicate how many cycles when PWM duty is 100%. low 8 bits of the value. +ucNumberOfCyclesInPeriodHi: Indicate how many cycles when PWM duty is 100%. high 8 bits of the value.If the PWM has an inverter,set bit [7]==1,otherwise set it 0 + +ucMaxNBVoltageHigh: Voltage regulator dependent PWM value. High 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all. +ucMinNBVoltageHigh: Voltage regulator dependent PWM value. High 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all. + + +usInterNBVoltageLow: Voltage regulator dependent PWM value. The value makes the the voltage >=Min NB voltage but <=InterNBVoltageHigh. Set this to 0x0000 if VC without PWM or no VC at all. +usInterNBVoltageHigh: Voltage regulator dependent PWM value. The value makes the the voltage >=InterNBVoltageLow but <=Max NB voltage.Set this to 0x0000 if VC without PWM or no VC at all. +*/ + + +/* +The following IGP table is introduced from RS780, which is supposed to be put by SBIOS in FB before IGP VBIOS starts VPOST; +Then VBIOS will copy the whole structure to its image so all GPU SW components can access this data structure to get whatever they need. +The enough reservation should allow us to never change table revisions. Whenever needed, a GPU SW component can use reserved portion for new data entries. + +SW components can access the IGP system infor structure in the same way as before +*/ + + +typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulBootUpEngineClock; //in 10kHz unit + ULONG ulReserved1[2]; //must be 0x0 for the reserved + ULONG ulBootUpUMAClock; //in 10kHz unit + ULONG ulBootUpSidePortClock; //in 10kHz unit + ULONG ulMinSidePortClock; //in 10kHz unit + ULONG ulReserved2[6]; //must be 0x0 for the reserved + ULONG ulSystemConfig; //see explanation below + ULONG ulBootUpReqDisplayVector; + ULONG ulOtherDisplayMisc; + ULONG ulDDISlot1Config; + ULONG ulDDISlot2Config; + UCHAR ucMemoryType; //[3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved + UCHAR ucUMAChannelNumber; + UCHAR ucDockingPinBit; + UCHAR ucDockingPinPolarity; + ULONG ulDockingPinCFGInfo; + ULONG ulCPUCapInfo; + USHORT usNumberOfCyclesInPeriod; + USHORT usMaxNBVoltage; + USHORT usMinNBVoltage; + USHORT usBootUpNBVoltage; + ULONG ulHTLinkFreq; //in 10Khz + USHORT usMinHTLinkWidth; + USHORT usMaxHTLinkWidth; + USHORT usUMASyncStartDelay; + USHORT usUMADataReturnTime; + USHORT usLinkStatusZeroTime; + USHORT usDACEfuse; //for storing badgap value (for RS880 only) + ULONG ulHighVoltageHTLinkFreq; // in 10Khz + ULONG ulLowVoltageHTLinkFreq; // in 10Khz + USHORT usMaxUpStreamHTLinkWidth; + USHORT usMaxDownStreamHTLinkWidth; + USHORT usMinUpStreamHTLinkWidth; + USHORT usMinDownStreamHTLinkWidth; + USHORT usFirmwareVersion; //0 means FW is not supported. Otherwise it's the FW version loaded by SBIOS and driver should enable FW. + USHORT usFullT0Time; // Input to calculate minimum HT link change time required by NB P-State. Unit is 0.01us. + ULONG ulReserved3[96]; //must be 0x0 +}ATOM_INTEGRATED_SYSTEM_INFO_V2; + +/* +ulBootUpEngineClock: Boot-up Engine Clock in 10Khz; +ulBootUpUMAClock: Boot-up UMA Clock in 10Khz; it must be 0x0 when UMA is not present +ulBootUpSidePortClock: Boot-up SidePort Clock in 10Khz; it must be 0x0 when SidePort Memory is not present,this could be equal to or less than maximum supported Sideport memory clock + +ulSystemConfig: +Bit[0]=1: PowerExpress mode =0 Non-PowerExpress mode; +Bit[1]=1: system boots up at AMD overdrived state or user customized mode. In this case, driver will just stick to this boot-up mode. No other PowerPlay state + =0: system boots up at driver control state. Power state depends on PowerPlay table. +Bit[2]=1: PWM method is used on NB voltage control. =0: GPIO method is used. +Bit[3]=1: Only one power state(Performance) will be supported. + =0: Multiple power states supported from PowerPlay table. +Bit[4]=1: CLMC is supported and enabled on current system. + =0: CLMC is not supported or enabled on current system. SBIOS need to support HT link/freq change through ATIF interface. +Bit[5]=1: Enable CDLW for all driver control power states. Max HT width is from SBIOS, while Min HT width is determined by display requirement. + =0: CDLW is disabled. If CLMC is enabled case, Min HT width will be set equal to Max HT width. If CLMC disabled case, Max HT width will be applied. +Bit[6]=1: High Voltage requested for all power states. In this case, voltage will be forced at 1.1v and powerplay table voltage drop/throttling request will be ignored. + =0: Voltage settings is determined by powerplay table. +Bit[7]=1: Enable CLMC as hybrid Mode. CDLD and CILR will be disabled in this case and we're using legacy C1E. This is workaround for CPU(Griffin) performance issue. + =0: Enable CLMC as regular mode, CDLD and CILR will be enabled. +Bit[8]=1: CDLF is supported and enabled on current system. + =0: CDLF is not supported or enabled on current system. +Bit[9]=1: DLL Shut Down feature is enabled on current system. + =0: DLL Shut Down feature is not enabled or supported on current system. + +ulBootUpReqDisplayVector: This dword is a bit vector indicates what display devices are requested during boot-up. Refer to ATOM_DEVICE_xxx_SUPPORT for the bit vector definitions. + +ulOtherDisplayMisc: [15:8]- Bootup LCD Expansion selection; 0-center, 1-full panel size expansion; + [7:0] - BootupTV standard selection; This is a bit vector to indicate what TV standards are supported by the system. Refer to ucTVSupportedStd definition; + +ulDDISlot1Config: Describes the PCIE lane configuration on this DDI PCIE slot (ADD2 card) or connector (Mobile design). + [3:0] - Bit vector to indicate PCIE lane config of the DDI slot/connector on chassis (bit 0=1 lane 3:0; bit 1=1 lane 7:4; bit 2=1 lane 11:8; bit 3=1 lane 15:12) + [7:4] - Bit vector to indicate PCIE lane config of the same DDI slot/connector on docking station (bit 4=1 lane 3:0; bit 5=1 lane 7:4; bit 6=1 lane 11:8; bit 7=1 lane 15:12) + When a DDI connector is not "paired" (meaming two connections mutualexclusive on chassis or docking, only one of them can be connected at one time. + in both chassis and docking, SBIOS has to duplicate the same PCIE lane info from chassis to docking or vice versa. For example: + one DDI connector is only populated in docking with PCIE lane 8-11, but there is no paired connection on chassis, SBIOS has to copy bit 6 to bit 2. + + [15:8] - Lane configuration attribute; + [23:16]- Connector type, possible value: + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D + CONNECTOR_OBJECT_ID_HDMI_TYPE_A + CONNECTOR_OBJECT_ID_DISPLAYPORT + CONNECTOR_OBJECT_ID_eDP + [31:24]- Reserved + +ulDDISlot2Config: Same as Slot1. +ucMemoryType: SidePort memory type, set it to 0x0 when Sideport memory is not installed. Driver needs this info to change sideport memory clock. Not for display in CCC. +For IGP, Hypermemory is the only memory type showed in CCC. + +ucUMAChannelNumber: how many channels for the UMA; + +ulDockingPinCFGInfo: [15:0]-Bus/Device/Function # to CFG to read this Docking Pin; [31:16]-reg offset in CFG to read this pin +ucDockingPinBit: which bit in this register to read the pin status; +ucDockingPinPolarity:Polarity of the pin when docked; + +ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, other bits reserved for now and must be 0x0 + +usNumberOfCyclesInPeriod:Indicate how many cycles when PWM duty is 100%. + +usMaxNBVoltage:Max. voltage control value in either PWM or GPIO mode. +usMinNBVoltage:Min. voltage control value in either PWM or GPIO mode. + GPIO mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=0 + PWM mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=1 + GPU SW don't control mode: usMaxNBVoltage & usMinNBVoltage=0 and no care about ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE + +usBootUpNBVoltage:Boot-up voltage regulator dependent PWM value. + +ulHTLinkFreq: Bootup HT link Frequency in 10Khz. +usMinHTLinkWidth: Bootup minimum HT link width. If CDLW disabled, this is equal to usMaxHTLinkWidth. + If CDLW enabled, both upstream and downstream width should be the same during bootup. +usMaxHTLinkWidth: Bootup maximum HT link width. If CDLW disabled, this is equal to usMinHTLinkWidth. + If CDLW enabled, both upstream and downstream width should be the same during bootup. + +usUMASyncStartDelay: Memory access latency, required for watermark calculation +usUMADataReturnTime: Memory access latency, required for watermark calculation +usLinkStatusZeroTime:Memory access latency required for watermark calculation, set this to 0x0 for K8 CPU, set a proper value in 0.01 the unit of us +for Griffin or Greyhound. SBIOS needs to convert to actual time by: + if T0Ttime [5:4]=00b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.1us (0.0 to 1.5us) + if T0Ttime [5:4]=01b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.5us (0.0 to 7.5us) + if T0Ttime [5:4]=10b, then usLinkStatusZeroTime=T0Ttime [3:0]*2.0us (0.0 to 30us) + if T0Ttime [5:4]=11b, and T0Ttime [3:0]=0x0 to 0xa, then usLinkStatusZeroTime=T0Ttime [3:0]*20us (0.0 to 200us) + +ulHighVoltageHTLinkFreq: HT link frequency for power state with low voltage. If boot up runs in HT1, this must be 0. + This must be less than or equal to ulHTLinkFreq(bootup frequency). +ulLowVoltageHTLinkFreq: HT link frequency for power state with low voltage or voltage scaling 1.0v~1.1v. If boot up runs in HT1, this must be 0. + This must be less than or equal to ulHighVoltageHTLinkFreq. + +usMaxUpStreamHTLinkWidth: Asymmetric link width support in the future, to replace usMaxHTLinkWidth. Not used for now. +usMaxDownStreamHTLinkWidth: same as above. +usMinUpStreamHTLinkWidth: Asymmetric link width support in the future, to replace usMinHTLinkWidth. Not used for now. +usMinDownStreamHTLinkWidth: same as above. +*/ + + +#define SYSTEM_CONFIG_POWEREXPRESS_ENABLE 0x00000001 +#define SYSTEM_CONFIG_RUN_AT_OVERDRIVE_ENGINE 0x00000002 +#define SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE 0x00000004 +#define SYSTEM_CONFIG_PERFORMANCE_POWERSTATE_ONLY 0x00000008 +#define SYSTEM_CONFIG_CLMC_ENABLED 0x00000010 +#define SYSTEM_CONFIG_CDLW_ENABLED 0x00000020 +#define SYSTEM_CONFIG_HIGH_VOLTAGE_REQUESTED 0x00000040 +#define SYSTEM_CONFIG_CLMC_HYBRID_MODE_ENABLED 0x00000080 +#define SYSTEM_CONFIG_CDLF_ENABLED 0x00000100 +#define SYSTEM_CONFIG_DLL_SHUTDOWN_ENABLED 0x00000200 + +#define IGP_DDI_SLOT_LANE_CONFIG_MASK 0x000000FF + +#define b0IGP_DDI_SLOT_LANE_MAP_MASK 0x0F +#define b0IGP_DDI_SLOT_DOCKING_LANE_MAP_MASK 0xF0 +#define b0IGP_DDI_SLOT_CONFIG_LANE_0_3 0x01 +#define b0IGP_DDI_SLOT_CONFIG_LANE_4_7 0x02 +#define b0IGP_DDI_SLOT_CONFIG_LANE_8_11 0x04 +#define b0IGP_DDI_SLOT_CONFIG_LANE_12_15 0x08 + +#define IGP_DDI_SLOT_ATTRIBUTE_MASK 0x0000FF00 +#define IGP_DDI_SLOT_CONFIG_REVERSED 0x00000100 +#define b1IGP_DDI_SLOT_CONFIG_REVERSED 0x01 + +#define IGP_DDI_SLOT_CONNECTOR_TYPE_MASK 0x00FF0000 + +// IntegratedSystemInfoTable new Rev is V5 after V2, because of the real rev of V2 is v1.4. This rev is used for RR +typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulBootUpEngineClock; //in 10kHz unit + ULONG ulDentistVCOFreq; //Dentist VCO clock in 10kHz unit, the source of GPU SCLK, LCLK, UCLK and VCLK. + ULONG ulLClockFreq; //GPU Lclk freq in 10kHz unit, have relationship with NCLK in NorthBridge + ULONG ulBootUpUMAClock; //in 10kHz unit + ULONG ulReserved1[8]; //must be 0x0 for the reserved + ULONG ulBootUpReqDisplayVector; + ULONG ulOtherDisplayMisc; + ULONG ulReserved2[4]; //must be 0x0 for the reserved + ULONG ulSystemConfig; //TBD + ULONG ulCPUCapInfo; //TBD + USHORT usMaxNBVoltage; //high NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse; + USHORT usMinNBVoltage; //low NB voltage, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse; + USHORT usBootUpNBVoltage; //boot up NB voltage + UCHAR ucHtcTmpLmt; //bit [22:16] of D24F3x64 Hardware Thermal Control (HTC) Register, may not be needed, TBD + UCHAR ucTjOffset; //bit [28:22] of D24F3xE4 Thermtrip Status Register,may not be needed, TBD + ULONG ulReserved3[4]; //must be 0x0 for the reserved + ULONG ulDDISlot1Config; //see above ulDDISlot1Config definition + ULONG ulDDISlot2Config; + ULONG ulDDISlot3Config; + ULONG ulDDISlot4Config; + ULONG ulReserved4[4]; //must be 0x0 for the reserved + UCHAR ucMemoryType; //[3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved + UCHAR ucUMAChannelNumber; + USHORT usReserved; + ULONG ulReserved5[4]; //must be 0x0 for the reserved + ULONG ulCSR_M3_ARB_CNTL_DEFAULT[10];//arrays with values for CSR M3 arbiter for default + ULONG ulCSR_M3_ARB_CNTL_UVD[10]; //arrays with values for CSR M3 arbiter for UVD playback + ULONG ulCSR_M3_ARB_CNTL_FS3D[10];//arrays with values for CSR M3 arbiter for Full Screen 3D applications + ULONG ulReserved6[61]; //must be 0x0 +}ATOM_INTEGRATED_SYSTEM_INFO_V5; + +#define ATOM_CRT_INT_ENCODER1_INDEX 0x00000000 +#define ATOM_LCD_INT_ENCODER1_INDEX 0x00000001 +#define ATOM_TV_INT_ENCODER1_INDEX 0x00000002 +#define ATOM_DFP_INT_ENCODER1_INDEX 0x00000003 +#define ATOM_CRT_INT_ENCODER2_INDEX 0x00000004 +#define ATOM_LCD_EXT_ENCODER1_INDEX 0x00000005 +#define ATOM_TV_EXT_ENCODER1_INDEX 0x00000006 +#define ATOM_DFP_EXT_ENCODER1_INDEX 0x00000007 +#define ATOM_CV_INT_ENCODER1_INDEX 0x00000008 +#define ATOM_DFP_INT_ENCODER2_INDEX 0x00000009 +#define ATOM_CRT_EXT_ENCODER1_INDEX 0x0000000A +#define ATOM_CV_EXT_ENCODER1_INDEX 0x0000000B +#define ATOM_DFP_INT_ENCODER3_INDEX 0x0000000C +#define ATOM_DFP_INT_ENCODER4_INDEX 0x0000000D + +// define ASIC internal encoder id ( bit vector ), used for CRTC_SourceSelTable +#define ASIC_INT_DAC1_ENCODER_ID 0x00 +#define ASIC_INT_TV_ENCODER_ID 0x02 +#define ASIC_INT_DIG1_ENCODER_ID 0x03 +#define ASIC_INT_DAC2_ENCODER_ID 0x04 +#define ASIC_EXT_TV_ENCODER_ID 0x06 +#define ASIC_INT_DVO_ENCODER_ID 0x07 +#define ASIC_INT_DIG2_ENCODER_ID 0x09 +#define ASIC_EXT_DIG_ENCODER_ID 0x05 +#define ASIC_EXT_DIG2_ENCODER_ID 0x08 +#define ASIC_INT_DIG3_ENCODER_ID 0x0a +#define ASIC_INT_DIG4_ENCODER_ID 0x0b +#define ASIC_INT_DIG5_ENCODER_ID 0x0c +#define ASIC_INT_DIG6_ENCODER_ID 0x0d + +//define Encoder attribute +#define ATOM_ANALOG_ENCODER 0 +#define ATOM_DIGITAL_ENCODER 1 +#define ATOM_DP_ENCODER 2 + +#define ATOM_ENCODER_ENUM_MASK 0x70 +#define ATOM_ENCODER_ENUM_ID1 0x00 +#define ATOM_ENCODER_ENUM_ID2 0x10 +#define ATOM_ENCODER_ENUM_ID3 0x20 +#define ATOM_ENCODER_ENUM_ID4 0x30 +#define ATOM_ENCODER_ENUM_ID5 0x40 +#define ATOM_ENCODER_ENUM_ID6 0x50 + +#define ATOM_DEVICE_CRT1_INDEX 0x00000000 +#define ATOM_DEVICE_LCD1_INDEX 0x00000001 +#define ATOM_DEVICE_TV1_INDEX 0x00000002 +#define ATOM_DEVICE_DFP1_INDEX 0x00000003 +#define ATOM_DEVICE_CRT2_INDEX 0x00000004 +#define ATOM_DEVICE_LCD2_INDEX 0x00000005 +#define ATOM_DEVICE_DFP6_INDEX 0x00000006 +#define ATOM_DEVICE_DFP2_INDEX 0x00000007 +#define ATOM_DEVICE_CV_INDEX 0x00000008 +#define ATOM_DEVICE_DFP3_INDEX 0x00000009 +#define ATOM_DEVICE_DFP4_INDEX 0x0000000A +#define ATOM_DEVICE_DFP5_INDEX 0x0000000B + +#define ATOM_DEVICE_RESERVEDC_INDEX 0x0000000C +#define ATOM_DEVICE_RESERVEDD_INDEX 0x0000000D +#define ATOM_DEVICE_RESERVEDE_INDEX 0x0000000E +#define ATOM_DEVICE_RESERVEDF_INDEX 0x0000000F +#define ATOM_MAX_SUPPORTED_DEVICE_INFO (ATOM_DEVICE_DFP3_INDEX+1) +#define ATOM_MAX_SUPPORTED_DEVICE_INFO_2 ATOM_MAX_SUPPORTED_DEVICE_INFO +#define ATOM_MAX_SUPPORTED_DEVICE_INFO_3 (ATOM_DEVICE_DFP5_INDEX + 1 ) + +#define ATOM_MAX_SUPPORTED_DEVICE (ATOM_DEVICE_RESERVEDF_INDEX+1) + +#define ATOM_DEVICE_CRT1_SUPPORT (0x1L << ATOM_DEVICE_CRT1_INDEX ) +#define ATOM_DEVICE_LCD1_SUPPORT (0x1L << ATOM_DEVICE_LCD1_INDEX ) +#define ATOM_DEVICE_TV1_SUPPORT (0x1L << ATOM_DEVICE_TV1_INDEX ) +#define ATOM_DEVICE_DFP1_SUPPORT (0x1L << ATOM_DEVICE_DFP1_INDEX ) +#define ATOM_DEVICE_CRT2_SUPPORT (0x1L << ATOM_DEVICE_CRT2_INDEX ) +#define ATOM_DEVICE_LCD2_SUPPORT (0x1L << ATOM_DEVICE_LCD2_INDEX ) +#define ATOM_DEVICE_DFP6_SUPPORT (0x1L << ATOM_DEVICE_DFP6_INDEX ) +#define ATOM_DEVICE_DFP2_SUPPORT (0x1L << ATOM_DEVICE_DFP2_INDEX ) +#define ATOM_DEVICE_CV_SUPPORT (0x1L << ATOM_DEVICE_CV_INDEX ) +#define ATOM_DEVICE_DFP3_SUPPORT (0x1L << ATOM_DEVICE_DFP3_INDEX ) +#define ATOM_DEVICE_DFP4_SUPPORT (0x1L << ATOM_DEVICE_DFP4_INDEX ) +#define ATOM_DEVICE_DFP5_SUPPORT (0x1L << ATOM_DEVICE_DFP5_INDEX ) + +#define ATOM_DEVICE_CRT_SUPPORT (ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_CRT2_SUPPORT) +#define ATOM_DEVICE_DFP_SUPPORT (ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | ATOM_DEVICE_DFP3_SUPPORT | ATOM_DEVICE_DFP4_SUPPORT | ATOM_DEVICE_DFP5_SUPPORT | ATOM_DEVICE_DFP6_SUPPORT) +#define ATOM_DEVICE_TV_SUPPORT (ATOM_DEVICE_TV1_SUPPORT) +#define ATOM_DEVICE_LCD_SUPPORT (ATOM_DEVICE_LCD1_SUPPORT | ATOM_DEVICE_LCD2_SUPPORT) + +#define ATOM_DEVICE_CONNECTOR_TYPE_MASK 0x000000F0 +#define ATOM_DEVICE_CONNECTOR_TYPE_SHIFT 0x00000004 +#define ATOM_DEVICE_CONNECTOR_VGA 0x00000001 +#define ATOM_DEVICE_CONNECTOR_DVI_I 0x00000002 +#define ATOM_DEVICE_CONNECTOR_DVI_D 0x00000003 +#define ATOM_DEVICE_CONNECTOR_DVI_A 0x00000004 +#define ATOM_DEVICE_CONNECTOR_SVIDEO 0x00000005 +#define ATOM_DEVICE_CONNECTOR_COMPOSITE 0x00000006 +#define ATOM_DEVICE_CONNECTOR_LVDS 0x00000007 +#define ATOM_DEVICE_CONNECTOR_DIGI_LINK 0x00000008 +#define ATOM_DEVICE_CONNECTOR_SCART 0x00000009 +#define ATOM_DEVICE_CONNECTOR_HDMI_TYPE_A 0x0000000A +#define ATOM_DEVICE_CONNECTOR_HDMI_TYPE_B 0x0000000B +#define ATOM_DEVICE_CONNECTOR_CASE_1 0x0000000E +#define ATOM_DEVICE_CONNECTOR_DISPLAYPORT 0x0000000F + + +#define ATOM_DEVICE_DAC_INFO_MASK 0x0000000F +#define ATOM_DEVICE_DAC_INFO_SHIFT 0x00000000 +#define ATOM_DEVICE_DAC_INFO_NODAC 0x00000000 +#define ATOM_DEVICE_DAC_INFO_DACA 0x00000001 +#define ATOM_DEVICE_DAC_INFO_DACB 0x00000002 +#define ATOM_DEVICE_DAC_INFO_EXDAC 0x00000003 + +#define ATOM_DEVICE_I2C_ID_NOI2C 0x00000000 + +#define ATOM_DEVICE_I2C_LINEMUX_MASK 0x0000000F +#define ATOM_DEVICE_I2C_LINEMUX_SHIFT 0x00000000 + +#define ATOM_DEVICE_I2C_ID_MASK 0x00000070 +#define ATOM_DEVICE_I2C_ID_SHIFT 0x00000004 +#define ATOM_DEVICE_I2C_ID_IS_FOR_NON_MM_USE 0x00000001 +#define ATOM_DEVICE_I2C_ID_IS_FOR_MM_USE 0x00000002 +#define ATOM_DEVICE_I2C_ID_IS_FOR_SDVO_USE 0x00000003 //For IGP RS600 +#define ATOM_DEVICE_I2C_ID_IS_FOR_DAC_SCL 0x00000004 //For IGP RS690 + +#define ATOM_DEVICE_I2C_HARDWARE_CAP_MASK 0x00000080 +#define ATOM_DEVICE_I2C_HARDWARE_CAP_SHIFT 0x00000007 +#define ATOM_DEVICE_USES_SOFTWARE_ASSISTED_I2C 0x00000000 +#define ATOM_DEVICE_USES_HARDWARE_ASSISTED_I2C 0x00000001 + +// usDeviceSupport: +// Bits0 = 0 - no CRT1 support= 1- CRT1 is supported +// Bit 1 = 0 - no LCD1 support= 1- LCD1 is supported +// Bit 2 = 0 - no TV1 support= 1- TV1 is supported +// Bit 3 = 0 - no DFP1 support= 1- DFP1 is supported +// Bit 4 = 0 - no CRT2 support= 1- CRT2 is supported +// Bit 5 = 0 - no LCD2 support= 1- LCD2 is supported +// Bit 6 = 0 - no DFP6 support= 1- DFP6 is supported +// Bit 7 = 0 - no DFP2 support= 1- DFP2 is supported +// Bit 8 = 0 - no CV support= 1- CV is supported +// Bit 9 = 0 - no DFP3 support= 1- DFP3 is supported +// Bit 10 = 0 - no DFP4 support= 1- DFP4 is supported +// Bit 11 = 0 - no DFP5 support= 1- DFP5 is supported +// +// + +/****************************************************************************/ +/* Structure used in MclkSS_InfoTable */ +/****************************************************************************/ +// ucI2C_ConfigID +// [7:0] - I2C LINE Associate ID +// = 0 - no I2C +// [7] - HW_Cap = 1, [6:0]=HW assisted I2C ID(HW line selection) +// = 0, [6:0]=SW assisted I2C ID +// [6-4] - HW_ENGINE_ID = 1, HW engine for NON multimedia use +// = 2, HW engine for Multimedia use +// = 3-7 Reserved for future I2C engines +// [3-0] - I2C_LINE_MUX = A Mux number when it's HW assisted I2C or GPIO ID when it's SW I2C + +typedef struct _ATOM_I2C_ID_CONFIG +{ +#if ATOM_BIG_ENDIAN + UCHAR bfHW_Capable:1; + UCHAR bfHW_EngineID:3; + UCHAR bfI2C_LineMux:4; +#else + UCHAR bfI2C_LineMux:4; + UCHAR bfHW_EngineID:3; + UCHAR bfHW_Capable:1; +#endif +}ATOM_I2C_ID_CONFIG; + +typedef union _ATOM_I2C_ID_CONFIG_ACCESS +{ + ATOM_I2C_ID_CONFIG sbfAccess; + UCHAR ucAccess; +}ATOM_I2C_ID_CONFIG_ACCESS; + + +/****************************************************************************/ +// Structure used in GPIO_I2C_InfoTable +/****************************************************************************/ +typedef struct _ATOM_GPIO_I2C_ASSIGMENT +{ + USHORT usClkMaskRegisterIndex; + USHORT usClkEnRegisterIndex; + USHORT usClkY_RegisterIndex; + USHORT usClkA_RegisterIndex; + USHORT usDataMaskRegisterIndex; + USHORT usDataEnRegisterIndex; + USHORT usDataY_RegisterIndex; + USHORT usDataA_RegisterIndex; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; + UCHAR ucClkMaskShift; + UCHAR ucClkEnShift; + UCHAR ucClkY_Shift; + UCHAR ucClkA_Shift; + UCHAR ucDataMaskShift; + UCHAR ucDataEnShift; + UCHAR ucDataY_Shift; + UCHAR ucDataA_Shift; + UCHAR ucReserved1; + UCHAR ucReserved2; +}ATOM_GPIO_I2C_ASSIGMENT; + +typedef struct _ATOM_GPIO_I2C_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_GPIO_I2C_ASSIGMENT asGPIO_Info[ATOM_MAX_SUPPORTED_DEVICE]; +}ATOM_GPIO_I2C_INFO; + +/****************************************************************************/ +// Common Structure used in other structures +/****************************************************************************/ + +#ifndef _H2INC + +//Please don't add or expand this bitfield structure below, this one will retire soon.! +typedef struct _ATOM_MODE_MISC_INFO +{ +#if ATOM_BIG_ENDIAN + USHORT Reserved:6; + USHORT RGB888:1; + USHORT DoubleClock:1; + USHORT Interlace:1; + USHORT CompositeSync:1; + USHORT V_ReplicationBy2:1; + USHORT H_ReplicationBy2:1; + USHORT VerticalCutOff:1; + USHORT VSyncPolarity:1; //0=Active High, 1=Active Low + USHORT HSyncPolarity:1; //0=Active High, 1=Active Low + USHORT HorizontalCutOff:1; +#else + USHORT HorizontalCutOff:1; + USHORT HSyncPolarity:1; //0=Active High, 1=Active Low + USHORT VSyncPolarity:1; //0=Active High, 1=Active Low + USHORT VerticalCutOff:1; + USHORT H_ReplicationBy2:1; + USHORT V_ReplicationBy2:1; + USHORT CompositeSync:1; + USHORT Interlace:1; + USHORT DoubleClock:1; + USHORT RGB888:1; + USHORT Reserved:6; +#endif +}ATOM_MODE_MISC_INFO; + +typedef union _ATOM_MODE_MISC_INFO_ACCESS +{ + ATOM_MODE_MISC_INFO sbfAccess; + USHORT usAccess; +}ATOM_MODE_MISC_INFO_ACCESS; + +#else + +typedef union _ATOM_MODE_MISC_INFO_ACCESS +{ + USHORT usAccess; +}ATOM_MODE_MISC_INFO_ACCESS; + +#endif + +// usModeMiscInfo- +#define ATOM_H_CUTOFF 0x01 +#define ATOM_HSYNC_POLARITY 0x02 //0=Active High, 1=Active Low +#define ATOM_VSYNC_POLARITY 0x04 //0=Active High, 1=Active Low +#define ATOM_V_CUTOFF 0x08 +#define ATOM_H_REPLICATIONBY2 0x10 +#define ATOM_V_REPLICATIONBY2 0x20 +#define ATOM_COMPOSITESYNC 0x40 +#define ATOM_INTERLACE 0x80 +#define ATOM_DOUBLE_CLOCK_MODE 0x100 +#define ATOM_RGB888_MODE 0x200 + +//usRefreshRate- +#define ATOM_REFRESH_43 43 +#define ATOM_REFRESH_47 47 +#define ATOM_REFRESH_56 56 +#define ATOM_REFRESH_60 60 +#define ATOM_REFRESH_65 65 +#define ATOM_REFRESH_70 70 +#define ATOM_REFRESH_72 72 +#define ATOM_REFRESH_75 75 +#define ATOM_REFRESH_85 85 + +// ATOM_MODE_TIMING data are exactly the same as VESA timing data. +// Translation from EDID to ATOM_MODE_TIMING, use the following formula. +// +// VESA_HTOTAL = VESA_ACTIVE + 2* VESA_BORDER + VESA_BLANK +// = EDID_HA + EDID_HBL +// VESA_HDISP = VESA_ACTIVE = EDID_HA +// VESA_HSYNC_START = VESA_ACTIVE + VESA_BORDER + VESA_FRONT_PORCH +// = EDID_HA + EDID_HSO +// VESA_HSYNC_WIDTH = VESA_HSYNC_TIME = EDID_HSPW +// VESA_BORDER = EDID_BORDER + +/****************************************************************************/ +// Structure used in SetCRTC_UsingDTDTimingTable +/****************************************************************************/ +typedef struct _SET_CRTC_USING_DTD_TIMING_PARAMETERS +{ + USHORT usH_Size; + USHORT usH_Blanking_Time; + USHORT usV_Size; + USHORT usV_Blanking_Time; + USHORT usH_SyncOffset; + USHORT usH_SyncWidth; + USHORT usV_SyncOffset; + USHORT usV_SyncWidth; + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + UCHAR ucH_Border; // From DFP EDID + UCHAR ucV_Border; + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucPadding[3]; +}SET_CRTC_USING_DTD_TIMING_PARAMETERS; + +/****************************************************************************/ +// Structure used in SetCRTC_TimingTable +/****************************************************************************/ +typedef struct _SET_CRTC_TIMING_PARAMETERS +{ + USHORT usH_Total; // horizontal total + USHORT usH_Disp; // horizontal display + USHORT usH_SyncStart; // horozontal Sync start + USHORT usH_SyncWidth; // horizontal Sync width + USHORT usV_Total; // vertical total + USHORT usV_Disp; // vertical display + USHORT usV_SyncStart; // vertical Sync start + USHORT usV_SyncWidth; // vertical Sync width + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucOverscanRight; // right + UCHAR ucOverscanLeft; // left + UCHAR ucOverscanBottom; // bottom + UCHAR ucOverscanTop; // top + UCHAR ucReserved; +}SET_CRTC_TIMING_PARAMETERS; +#define SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION SET_CRTC_TIMING_PARAMETERS + +/****************************************************************************/ +// Structure used in StandardVESA_TimingTable +// AnalogTV_InfoTable +// ComponentVideoInfoTable +/****************************************************************************/ +typedef struct _ATOM_MODE_TIMING +{ + USHORT usCRTC_H_Total; + USHORT usCRTC_H_Disp; + USHORT usCRTC_H_SyncStart; + USHORT usCRTC_H_SyncWidth; + USHORT usCRTC_V_Total; + USHORT usCRTC_V_Disp; + USHORT usCRTC_V_SyncStart; + USHORT usCRTC_V_SyncWidth; + USHORT usPixelClock; //in 10Khz unit + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + USHORT usCRTC_OverscanRight; + USHORT usCRTC_OverscanLeft; + USHORT usCRTC_OverscanBottom; + USHORT usCRTC_OverscanTop; + USHORT usReserve; + UCHAR ucInternalModeNumber; + UCHAR ucRefreshRate; +}ATOM_MODE_TIMING; + +typedef struct _ATOM_DTD_FORMAT +{ + USHORT usPixClk; + USHORT usHActive; + USHORT usHBlanking_Time; + USHORT usVActive; + USHORT usVBlanking_Time; + USHORT usHSyncOffset; + USHORT usHSyncWidth; + USHORT usVSyncOffset; + USHORT usVSyncWidth; + USHORT usImageHSize; + USHORT usImageVSize; + UCHAR ucHBorder; + UCHAR ucVBorder; + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + UCHAR ucInternalModeNumber; + UCHAR ucRefreshRate; +}ATOM_DTD_FORMAT; + +/****************************************************************************/ +// Structure used in LVDS_InfoTable +// * Need a document to describe this table +/****************************************************************************/ +#define SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004 +#define SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008 +#define SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010 +#define SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020 + +//ucTableFormatRevision=1 +//ucTableContentRevision=1 +typedef struct _ATOM_LVDS_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_DTD_FORMAT sLCDTiming; + USHORT usModePatchTableOffset; + USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec. + USHORT usOffDelayInMs; + UCHAR ucPowerSequenceDigOntoDEin10Ms; + UCHAR ucPowerSequenceDEtoBLOnin10Ms; + UCHAR ucLVDS_Misc; // Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level} + // Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888} + // Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled} + // Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled} + UCHAR ucPanelDefaultRefreshRate; + UCHAR ucPanelIdentification; + UCHAR ucSS_Id; +}ATOM_LVDS_INFO; + +//ucTableFormatRevision=1 +//ucTableContentRevision=2 +typedef struct _ATOM_LVDS_INFO_V12 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_DTD_FORMAT sLCDTiming; + USHORT usExtInfoTableOffset; + USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec. + USHORT usOffDelayInMs; + UCHAR ucPowerSequenceDigOntoDEin10Ms; + UCHAR ucPowerSequenceDEtoBLOnin10Ms; + UCHAR ucLVDS_Misc; // Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level} + // Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888} + // Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled} + // Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled} + UCHAR ucPanelDefaultRefreshRate; + UCHAR ucPanelIdentification; + UCHAR ucSS_Id; + USHORT usLCDVenderID; + USHORT usLCDProductID; + UCHAR ucLCDPanel_SpecialHandlingCap; + UCHAR ucPanelInfoSize; // start from ATOM_DTD_FORMAT to end of panel info, include ExtInfoTable + UCHAR ucReserved[2]; +}ATOM_LVDS_INFO_V12; + +//Definitions for ucLCDPanel_SpecialHandlingCap: + +//Once DAL sees this CAP is set, it will read EDID from LCD on its own instead of using sLCDTiming in ATOM_LVDS_INFO_V12. +//Other entries in ATOM_LVDS_INFO_V12 are still valid/useful to DAL +#define LCDPANEL_CAP_READ_EDID 0x1 + +//If a design supports DRR (dynamic refresh rate) on internal panels (LVDS or EDP), this cap is set in ucLCDPanel_SpecialHandlingCap together +//with multiple supported refresh rates@usSupportedRefreshRate. This cap should not be set when only slow refresh rate is supported (static +//refresh rate switch by SW. This is only valid from ATOM_LVDS_INFO_V12 +#define LCDPANEL_CAP_DRR_SUPPORTED 0x2 + +//Use this cap bit for a quick reference whether an embadded panel (LCD1 ) is LVDS or eDP. +#define LCDPANEL_CAP_eDP 0x4 + + +//Color Bit Depth definition in EDID V1.4 @BYTE 14h +//Bit 6 5 4 + // 0 0 0 - Color bit depth is undefined + // 0 0 1 - 6 Bits per Primary Color + // 0 1 0 - 8 Bits per Primary Color + // 0 1 1 - 10 Bits per Primary Color + // 1 0 0 - 12 Bits per Primary Color + // 1 0 1 - 14 Bits per Primary Color + // 1 1 0 - 16 Bits per Primary Color + // 1 1 1 - Reserved + +#define PANEL_COLOR_BIT_DEPTH_MASK 0x70 + +// Bit7:{=0:Random Dithering disabled;1 Random Dithering enabled} +#define PANEL_RANDOM_DITHER 0x80 +#define PANEL_RANDOM_DITHER_MASK 0x80 + + +#define ATOM_LVDS_INFO_LAST ATOM_LVDS_INFO_V12 + +typedef struct _ATOM_PATCH_RECORD_MODE +{ + UCHAR ucRecordType; + USHORT usHDisp; + USHORT usVDisp; +}ATOM_PATCH_RECORD_MODE; + +typedef struct _ATOM_LCD_RTS_RECORD +{ + UCHAR ucRecordType; + UCHAR ucRTSValue; +}ATOM_LCD_RTS_RECORD; + +//!! If the record below exits, it shoud always be the first record for easy use in command table!!! +// The record below is only used when LVDS_Info is present. From ATOM_LVDS_INFO_V12, use ucLCDPanel_SpecialHandlingCap instead. +typedef struct _ATOM_LCD_MODE_CONTROL_CAP +{ + UCHAR ucRecordType; + USHORT usLCDCap; +}ATOM_LCD_MODE_CONTROL_CAP; + +#define LCD_MODE_CAP_BL_OFF 1 +#define LCD_MODE_CAP_CRTC_OFF 2 +#define LCD_MODE_CAP_PANEL_OFF 4 + +typedef struct _ATOM_FAKE_EDID_PATCH_RECORD +{ + UCHAR ucRecordType; + UCHAR ucFakeEDIDLength; + UCHAR ucFakeEDIDString[1]; // This actually has ucFakeEdidLength elements. +} ATOM_FAKE_EDID_PATCH_RECORD; + +typedef struct _ATOM_PANEL_RESOLUTION_PATCH_RECORD +{ + UCHAR ucRecordType; + USHORT usHSize; + USHORT usVSize; +}ATOM_PANEL_RESOLUTION_PATCH_RECORD; + +#define LCD_MODE_PATCH_RECORD_MODE_TYPE 1 +#define LCD_RTS_RECORD_TYPE 2 +#define LCD_CAP_RECORD_TYPE 3 +#define LCD_FAKE_EDID_PATCH_RECORD_TYPE 4 +#define LCD_PANEL_RESOLUTION_RECORD_TYPE 5 +#define ATOM_RECORD_END_TYPE 0xFF + +/****************************Spread Spectrum Info Table Definitions **********************/ + +//ucTableFormatRevision=1 +//ucTableContentRevision=2 +typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Bit2=1: PCIE REFCLK SS =0 iternal PPLL SS Others:TBD + UCHAR ucSS_Step; + UCHAR ucSS_Delay; + UCHAR ucSS_Id; + UCHAR ucRecommendedRef_Div; + UCHAR ucSS_Range; //it was reserved for V11 +}ATOM_SPREAD_SPECTRUM_ASSIGNMENT; + +#define ATOM_MAX_SS_ENTRY 16 +#define ATOM_DP_SS_ID1 0x0f1 // SS ID for internal DP stream at 2.7Ghz. if ATOM_DP_SS_ID2 does not exist in SS_InfoTable, it is used for internal DP stream at 1.62Ghz as well. +#define ATOM_DP_SS_ID2 0x0f2 // SS ID for internal DP stream at 1.62Ghz, if it exists in SS_InfoTable. +#define ATOM_LVLINK_2700MHz_SS_ID 0x0f3 // SS ID for LV link translator chip at 2.7Ghz +#define ATOM_LVLINK_1620MHz_SS_ID 0x0f4 // SS ID for LV link translator chip at 1.62Ghz + + +#define ATOM_SS_DOWN_SPREAD_MODE_MASK 0x00000000 +#define ATOM_SS_DOWN_SPREAD_MODE 0x00000000 +#define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001 +#define ATOM_SS_CENTRE_SPREAD_MODE 0x00000001 +#define ATOM_INTERNAL_SS_MASK 0x00000000 +#define ATOM_EXTERNAL_SS_MASK 0x00000002 +#define EXEC_SS_STEP_SIZE_SHIFT 2 +#define EXEC_SS_DELAY_SHIFT 4 +#define ACTIVEDATA_TO_BLON_DELAY_SHIFT 4 + +typedef struct _ATOM_SPREAD_SPECTRUM_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_SPREAD_SPECTRUM_ASSIGNMENT asSS_Info[ATOM_MAX_SS_ENTRY]; +}ATOM_SPREAD_SPECTRUM_INFO; + +/****************************************************************************/ +// Structure used in AnalogTV_InfoTable (Top level) +/****************************************************************************/ +//ucTVBootUpDefaultStd definiton: + +//ATOM_TV_NTSC 1 +//ATOM_TV_NTSCJ 2 +//ATOM_TV_PAL 3 +//ATOM_TV_PALM 4 +//ATOM_TV_PALCN 5 +//ATOM_TV_PALN 6 +//ATOM_TV_PAL60 7 +//ATOM_TV_SECAM 8 + +//ucTVSupportedStd definition: +#define NTSC_SUPPORT 0x1 +#define NTSCJ_SUPPORT 0x2 + +#define PAL_SUPPORT 0x4 +#define PALM_SUPPORT 0x8 +#define PALCN_SUPPORT 0x10 +#define PALN_SUPPORT 0x20 +#define PAL60_SUPPORT 0x40 +#define SECAM_SUPPORT 0x80 + +#define MAX_SUPPORTED_TV_TIMING 2 + +typedef struct _ATOM_ANALOG_TV_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucTV_SupportedStandard; + UCHAR ucTV_BootUpDefaultStandard; + UCHAR ucExt_TV_ASIC_ID; + UCHAR ucExt_TV_ASIC_SlaveAddr; + /*ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_TV_TIMING];*/ + ATOM_MODE_TIMING aModeTimings[MAX_SUPPORTED_TV_TIMING]; +}ATOM_ANALOG_TV_INFO; + +#define MAX_SUPPORTED_TV_TIMING_V1_2 3 + +typedef struct _ATOM_ANALOG_TV_INFO_V1_2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucTV_SupportedStandard; + UCHAR ucTV_BootUpDefaultStandard; + UCHAR ucExt_TV_ASIC_ID; + UCHAR ucExt_TV_ASIC_SlaveAddr; + ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_TV_TIMING_V1_2]; +}ATOM_ANALOG_TV_INFO_V1_2; + +typedef struct _ATOM_DPCD_INFO +{ + UCHAR ucRevisionNumber; //10h : Revision 1.0; 11h : Revision 1.1 + UCHAR ucMaxLinkRate; //06h : 1.62Gbps per lane; 0Ah = 2.7Gbps per lane + UCHAR ucMaxLane; //Bits 4:0 = MAX_LANE_COUNT (1/2/4). Bit 7 = ENHANCED_FRAME_CAP + UCHAR ucMaxDownSpread; //Bit0 = 0: No Down spread; Bit0 = 1: 0.5% (Subject to change according to DP spec) +}ATOM_DPCD_INFO; + +#define ATOM_DPCD_MAX_LANE_MASK 0x1F + +/**************************************************************************/ +// VRAM usage and their defintions + +// One chunk of VRAM used by Bios are for HWICON surfaces,EDID data. +// Current Mode timing and Dail Timing and/or STD timing data EACH device. They can be broken down as below. +// All the addresses below are the offsets from the frame buffer start.They all MUST be Dword aligned! +// To driver: The physical address of this memory portion=mmFB_START(4K aligned)+ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR +// To Bios: ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR->MM_INDEX + +#ifndef VESA_MEMORY_IN_64K_BLOCK +#define VESA_MEMORY_IN_64K_BLOCK 0x100 //256*64K=16Mb (Max. VESA memory is 16Mb!) +#endif + +#define ATOM_EDID_RAW_DATASIZE 256 //In Bytes +#define ATOM_HWICON_SURFACE_SIZE 4096 //In Bytes +#define ATOM_HWICON_INFOTABLE_SIZE 32 +#define MAX_DTD_MODE_IN_VRAM 6 +#define ATOM_DTD_MODE_SUPPORT_TBL_SIZE (MAX_DTD_MODE_IN_VRAM*28) //28= (SIZEOF ATOM_DTD_FORMAT) +#define ATOM_STD_MODE_SUPPORT_TBL_SIZE 32*8 //32 is a predefined number,8= (SIZEOF ATOM_STD_FORMAT) +#define DFP_ENCODER_TYPE_OFFSET 0x80 +#define DP_ENCODER_LANE_NUM_OFFSET 0x84 +#define DP_ENCODER_LINK_RATE_OFFSET 0x88 + +#define ATOM_HWICON1_SURFACE_ADDR 0 +#define ATOM_HWICON2_SURFACE_ADDR (ATOM_HWICON1_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE) +#define ATOM_HWICON_INFOTABLE_ADDR (ATOM_HWICON2_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE) +#define ATOM_CRT1_EDID_ADDR (ATOM_HWICON_INFOTABLE_ADDR + ATOM_HWICON_INFOTABLE_SIZE) +#define ATOM_CRT1_DTD_MODE_TBL_ADDR (ATOM_CRT1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_CRT1_STD_MODE_TBL_ADDR (ATOM_CRT1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_LCD1_EDID_ADDR (ATOM_CRT1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_LCD1_DTD_MODE_TBL_ADDR (ATOM_LCD1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_LCD1_STD_MODE_TBL_ADDR (ATOM_LCD1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_TV1_DTD_MODE_TBL_ADDR (ATOM_LCD1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP1_EDID_ADDR (ATOM_TV1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP1_DTD_MODE_TBL_ADDR (ATOM_DFP1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP1_STD_MODE_TBL_ADDR (ATOM_DFP1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_CRT2_EDID_ADDR (ATOM_DFP1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_CRT2_DTD_MODE_TBL_ADDR (ATOM_CRT2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_CRT2_STD_MODE_TBL_ADDR (ATOM_CRT2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_LCD2_EDID_ADDR (ATOM_CRT2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_LCD2_DTD_MODE_TBL_ADDR (ATOM_LCD2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_LCD2_STD_MODE_TBL_ADDR (ATOM_LCD2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP6_EDID_ADDR (ATOM_LCD2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP6_DTD_MODE_TBL_ADDR (ATOM_DFP6_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP6_STD_MODE_TBL_ADDR (ATOM_DFP6_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP2_EDID_ADDR (ATOM_DFP6_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP2_DTD_MODE_TBL_ADDR (ATOM_DFP2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP2_STD_MODE_TBL_ADDR (ATOM_DFP2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_CV_EDID_ADDR (ATOM_DFP2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_CV_DTD_MODE_TBL_ADDR (ATOM_CV_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_CV_STD_MODE_TBL_ADDR (ATOM_CV_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP3_EDID_ADDR (ATOM_CV_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP3_DTD_MODE_TBL_ADDR (ATOM_DFP3_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP3_STD_MODE_TBL_ADDR (ATOM_DFP3_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP4_EDID_ADDR (ATOM_DFP3_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP4_DTD_MODE_TBL_ADDR (ATOM_DFP4_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP4_STD_MODE_TBL_ADDR (ATOM_DFP4_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP5_EDID_ADDR (ATOM_DFP4_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP5_DTD_MODE_TBL_ADDR (ATOM_DFP5_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP5_STD_MODE_TBL_ADDR (ATOM_DFP5_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR+ATOM_STD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR+256) +#define ATOM_STACK_STORAGE_END ATOM_STACK_STORAGE_START+512 + +//The size below is in Kb! +#define ATOM_VRAM_RESERVE_SIZE ((((ATOM_STACK_STORAGE_END - ATOM_HWICON1_SURFACE_ADDR)>>10)+4)&0xFFFC) + +#define ATOM_VRAM_OPERATION_FLAGS_MASK 0xC0000000L +#define ATOM_VRAM_OPERATION_FLAGS_SHIFT 30 +#define ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION 0x1 +#define ATOM_VRAM_BLOCK_NEEDS_RESERVATION 0x0 + +/***********************************************************************************/ +// Structure used in VRAM_UsageByFirmwareTable +// Note1: This table is filled by SetBiosReservationStartInFB in CoreCommSubs.asm +// at running time. +// note2: From RV770, the memory is more than 32bit addressable, so we will change +// ucTableFormatRevision=1,ucTableContentRevision=4, the strcuture remains +// exactly same as 1.1 and 1.2 (1.3 is never in use), but ulStartAddrUsedByFirmware +// (in offset to start of memory address) is KB aligned instead of byte aligend. +/***********************************************************************************/ +// Note3: +/* If we change usReserved to "usFBUsedbyDrvInKB", then to VBIOS this usFBUsedbyDrvInKB is a predefined, unchanged constant across VGA or non VGA adapter, +for CAIL, The size of FB access area is known, only thing missing is the Offset of FB Access area, so we can have: + +If (ulStartAddrUsedByFirmware!=0) +FBAccessAreaOffset= ulStartAddrUsedByFirmware - usFBUsedbyDrvInKB; +Reserved area has been claimed by VBIOS including this FB access area; CAIL doesn't need to reserve any extra area for this purpose +else //Non VGA case + if (FB_Size<=2Gb) + FBAccessAreaOffset= FB_Size - usFBUsedbyDrvInKB; + else + FBAccessAreaOffset= Aper_Size - usFBUsedbyDrvInKB + +CAIL needs to claim an reserved area defined by FBAccessAreaOffset and usFBUsedbyDrvInKB in non VGA case.*/ + +#define ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO 1 + +typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO +{ + ULONG ulStartAddrUsedByFirmware; + USHORT usFirmwareUseInKb; + USHORT usReserved; +}ATOM_FIRMWARE_VRAM_RESERVE_INFO; + +typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_FIRMWARE_VRAM_RESERVE_INFO asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO]; +}ATOM_VRAM_USAGE_BY_FIRMWARE; + +// change verion to 1.5, when allow driver to allocate the vram area for command table access. +typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO_V1_5 +{ + ULONG ulStartAddrUsedByFirmware; + USHORT usFirmwareUseInKb; + USHORT usFBUsedByDrvInKb; +}ATOM_FIRMWARE_VRAM_RESERVE_INFO_V1_5; + +typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE_V1_5 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_FIRMWARE_VRAM_RESERVE_INFO_V1_5 asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO]; +}ATOM_VRAM_USAGE_BY_FIRMWARE_V1_5; + +/****************************************************************************/ +// Structure used in GPIO_Pin_LUTTable +/****************************************************************************/ +typedef struct _ATOM_GPIO_PIN_ASSIGNMENT +{ + USHORT usGpioPin_AIndex; + UCHAR ucGpioPinBitShift; + UCHAR ucGPIO_ID; +}ATOM_GPIO_PIN_ASSIGNMENT; + +typedef struct _ATOM_GPIO_PIN_LUT +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_GPIO_PIN_ASSIGNMENT asGPIO_Pin[1]; +}ATOM_GPIO_PIN_LUT; + +/****************************************************************************/ +// Structure used in ComponentVideoInfoTable +/****************************************************************************/ +#define GPIO_PIN_ACTIVE_HIGH 0x1 + +#define MAX_SUPPORTED_CV_STANDARDS 5 + +// definitions for ATOM_D_INFO.ucSettings +#define ATOM_GPIO_SETTINGS_BITSHIFT_MASK 0x1F // [4:0] +#define ATOM_GPIO_SETTINGS_RESERVED_MASK 0x60 // [6:5] = must be zeroed out +#define ATOM_GPIO_SETTINGS_ACTIVE_MASK 0x80 // [7] + +typedef struct _ATOM_GPIO_INFO +{ + USHORT usAOffset; + UCHAR ucSettings; + UCHAR ucReserved; +}ATOM_GPIO_INFO; + +// definitions for ATOM_COMPONENT_VIDEO_INFO.ucMiscInfo (bit vector) +#define ATOM_CV_RESTRICT_FORMAT_SELECTION 0x2 + +// definitions for ATOM_COMPONENT_VIDEO_INFO.uc480i/uc480p/uc720p/uc1080i +#define ATOM_GPIO_DEFAULT_MODE_EN 0x80 //[7]; +#define ATOM_GPIO_SETTING_PERMODE_MASK 0x7F //[6:0] + +// definitions for ATOM_COMPONENT_VIDEO_INFO.ucLetterBoxMode +//Line 3 out put 5V. +#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_A 0x01 //represent gpio 3 state for 16:9 +#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_B 0x02 //represent gpio 4 state for 16:9 +#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_SHIFT 0x0 + +//Line 3 out put 2.2V +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_A 0x04 //represent gpio 3 state for 4:3 Letter box +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_B 0x08 //represent gpio 4 state for 4:3 Letter box +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_SHIFT 0x2 + +//Line 3 out put 0V +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_A 0x10 //represent gpio 3 state for 4:3 +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_B 0x20 //represent gpio 4 state for 4:3 +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_SHIFT 0x4 + +#define ATOM_CV_LINE3_ASPECTRATIO_MASK 0x3F // bit [5:0] + +#define ATOM_CV_LINE3_ASPECTRATIO_EXIST 0x80 //bit 7 + +//GPIO bit index in gpio setting per mode value, also represend the block no. in gpio blocks. +#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_A 3 //bit 3 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode. +#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_B 4 //bit 4 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode. + + +typedef struct _ATOM_COMPONENT_VIDEO_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMask_PinRegisterIndex; + USHORT usEN_PinRegisterIndex; + USHORT usY_PinRegisterIndex; + USHORT usA_PinRegisterIndex; + UCHAR ucBitShift; + UCHAR ucPinActiveState; //ucPinActiveState: Bit0=1 active high, =0 active low + ATOM_DTD_FORMAT sReserved; // must be zeroed out + UCHAR ucMiscInfo; + UCHAR uc480i; + UCHAR uc480p; + UCHAR uc720p; + UCHAR uc1080i; + UCHAR ucLetterBoxMode; + UCHAR ucReserved[3]; + UCHAR ucNumOfWbGpioBlocks; //For Component video D-Connector support. If zere, NTSC type connector + ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS]; + ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS]; +}ATOM_COMPONENT_VIDEO_INFO; + +//ucTableFormatRevision=2 +//ucTableContentRevision=1 +typedef struct _ATOM_COMPONENT_VIDEO_INFO_V21 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucMiscInfo; + UCHAR uc480i; + UCHAR uc480p; + UCHAR uc720p; + UCHAR uc1080i; + UCHAR ucReserved; + UCHAR ucLetterBoxMode; + UCHAR ucNumOfWbGpioBlocks; //For Component video D-Connector support. If zere, NTSC type connector + ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS]; + ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS]; +}ATOM_COMPONENT_VIDEO_INFO_V21; + +#define ATOM_COMPONENT_VIDEO_INFO_LAST ATOM_COMPONENT_VIDEO_INFO_V21 + +/****************************************************************************/ +// Structure used in object_InfoTable +/****************************************************************************/ +typedef struct _ATOM_OBJECT_HEADER +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + USHORT usConnectorObjectTableOffset; + USHORT usRouterObjectTableOffset; + USHORT usEncoderObjectTableOffset; + USHORT usProtectionObjectTableOffset; //only available when Protection block is independent. + USHORT usDisplayPathTableOffset; +}ATOM_OBJECT_HEADER; + +typedef struct _ATOM_OBJECT_HEADER_V3 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + USHORT usConnectorObjectTableOffset; + USHORT usRouterObjectTableOffset; + USHORT usEncoderObjectTableOffset; + USHORT usProtectionObjectTableOffset; //only available when Protection block is independent. + USHORT usDisplayPathTableOffset; + USHORT usMiscObjectTableOffset; +}ATOM_OBJECT_HEADER_V3; + +typedef struct _ATOM_DISPLAY_OBJECT_PATH +{ + USHORT usDeviceTag; //supported device + USHORT usSize; //the size of ATOM_DISPLAY_OBJECT_PATH + USHORT usConnObjectId; //Connector Object ID + USHORT usGPUObjectId; //GPU ID + USHORT usGraphicObjIds[1]; //1st Encoder Obj source from GPU to last Graphic Obj destinate to connector. +}ATOM_DISPLAY_OBJECT_PATH; + +typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE +{ + UCHAR ucNumOfDispPath; + UCHAR ucVersion; + UCHAR ucPadding[2]; + ATOM_DISPLAY_OBJECT_PATH asDispPath[1]; +}ATOM_DISPLAY_OBJECT_PATH_TABLE; + + +typedef struct _ATOM_OBJECT //each object has this structure +{ + USHORT usObjectID; + USHORT usSrcDstTableOffset; + USHORT usRecordOffset; //this pointing to a bunch of records defined below + USHORT usReserved; +}ATOM_OBJECT; + +typedef struct _ATOM_OBJECT_TABLE //Above 4 object table offset pointing to a bunch of objects all have this structure +{ + UCHAR ucNumberOfObjects; + UCHAR ucPadding[3]; + ATOM_OBJECT asObjects[1]; +}ATOM_OBJECT_TABLE; + +typedef struct _ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT //usSrcDstTableOffset pointing to this structure +{ + UCHAR ucNumberOfSrc; + USHORT usSrcObjectID[1]; + UCHAR ucNumberOfDst; + USHORT usDstObjectID[1]; +}ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT; + + +//Two definitions below are for OPM on MXM module designs + +#define EXT_HPDPIN_LUTINDEX_0 0 +#define EXT_HPDPIN_LUTINDEX_1 1 +#define EXT_HPDPIN_LUTINDEX_2 2 +#define EXT_HPDPIN_LUTINDEX_3 3 +#define EXT_HPDPIN_LUTINDEX_4 4 +#define EXT_HPDPIN_LUTINDEX_5 5 +#define EXT_HPDPIN_LUTINDEX_6 6 +#define EXT_HPDPIN_LUTINDEX_7 7 +#define MAX_NUMBER_OF_EXT_HPDPIN_LUT_ENTRIES (EXT_HPDPIN_LUTINDEX_7+1) + +#define EXT_AUXDDC_LUTINDEX_0 0 +#define EXT_AUXDDC_LUTINDEX_1 1 +#define EXT_AUXDDC_LUTINDEX_2 2 +#define EXT_AUXDDC_LUTINDEX_3 3 +#define EXT_AUXDDC_LUTINDEX_4 4 +#define EXT_AUXDDC_LUTINDEX_5 5 +#define EXT_AUXDDC_LUTINDEX_6 6 +#define EXT_AUXDDC_LUTINDEX_7 7 +#define MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES (EXT_AUXDDC_LUTINDEX_7+1) + +typedef struct _EXT_DISPLAY_PATH +{ + USHORT usDeviceTag; //A bit vector to show what devices are supported + USHORT usDeviceACPIEnum; //16bit device ACPI id. + USHORT usDeviceConnector; //A physical connector for displays to plug in, using object connector definitions + UCHAR ucExtAUXDDCLutIndex; //An index into external AUX/DDC channel LUT + UCHAR ucExtHPDPINLutIndex; //An index into external HPD pin LUT + USHORT usExtEncoderObjId; //external encoder object id + USHORT usReserved[3]; +}EXT_DISPLAY_PATH; + +#define NUMBER_OF_UCHAR_FOR_GUID 16 +#define MAX_NUMBER_OF_EXT_DISPLAY_PATH 7 + +typedef struct _ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucGuid [NUMBER_OF_UCHAR_FOR_GUID]; // a GUID is a 16 byte long string + EXT_DISPLAY_PATH sPath[MAX_NUMBER_OF_EXT_DISPLAY_PATH]; // total of fixed 7 entries. + UCHAR ucChecksum; // a simple Checksum of the sum of whole structure equal to 0x0. + UCHAR Reserved [7]; // for potential expansion +}ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO; + +//Related definitions, all records are differnt but they have a commond header +typedef struct _ATOM_COMMON_RECORD_HEADER +{ + UCHAR ucRecordType; //An emun to indicate the record type + UCHAR ucRecordSize; //The size of the whole record in byte +}ATOM_COMMON_RECORD_HEADER; + + +#define ATOM_I2C_RECORD_TYPE 1 +#define ATOM_HPD_INT_RECORD_TYPE 2 +#define ATOM_OUTPUT_PROTECTION_RECORD_TYPE 3 +#define ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE 4 +#define ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD_TYPE 5 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE +#define ATOM_ENCODER_FPGA_CONTROL_RECORD_TYPE 6 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE +#define ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD_TYPE 7 +#define ATOM_JTAG_RECORD_TYPE 8 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE +#define ATOM_OBJECT_GPIO_CNTL_RECORD_TYPE 9 +#define ATOM_ENCODER_DVO_CF_RECORD_TYPE 10 +#define ATOM_CONNECTOR_CF_RECORD_TYPE 11 +#define ATOM_CONNECTOR_HARDCODE_DTD_RECORD_TYPE 12 +#define ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE 13 +#define ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE 14 +#define ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE 15 +#define ATOM_CONNECTOR_HPDPIN_LUT_RECORD_TYPE 16 //This is for the case when connectors are not known to object table +#define ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE 17 //This is for the case when connectors are not known to object table +#define ATOM_OBJECT_LINK_RECORD_TYPE 18 //Once this record is present under one object, it indicats the oobject is linked to another obj described by the record +#define ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE 19 + + +//Must be updated when new record type is added,equal to that record definition! +#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE + +typedef struct _ATOM_I2C_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + ATOM_I2C_ID_CONFIG sucI2cId; + UCHAR ucI2CAddr; //The slave address, it's 0 when the record is attached to connector for DDC +}ATOM_I2C_RECORD; + +typedef struct _ATOM_HPD_INT_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucHPDIntGPIOID; //Corresponding block in GPIO_PIN_INFO table gives the pin info + UCHAR ucPlugged_PinState; +}ATOM_HPD_INT_RECORD; + + +typedef struct _ATOM_OUTPUT_PROTECTION_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucProtectionFlag; + UCHAR ucReserved; +}ATOM_OUTPUT_PROTECTION_RECORD; + +typedef struct _ATOM_CONNECTOR_DEVICE_TAG +{ + ULONG ulACPIDeviceEnum; //Reserved for now + USHORT usDeviceID; //This Id is same as "ATOM_DEVICE_XXX_SUPPORT" + USHORT usPadding; +}ATOM_CONNECTOR_DEVICE_TAG; + +typedef struct _ATOM_CONNECTOR_DEVICE_TAG_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucNumberOfDevice; + UCHAR ucReserved; + ATOM_CONNECTOR_DEVICE_TAG asDeviceTag[1]; //This Id is same as "ATOM_DEVICE_XXX_SUPPORT", 1 is only for allocation +}ATOM_CONNECTOR_DEVICE_TAG_RECORD; + + +typedef struct _ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucConfigGPIOID; + UCHAR ucConfigGPIOState; //Set to 1 when it's active high to enable external flow in + UCHAR ucFlowinGPIPID; + UCHAR ucExtInGPIPID; +}ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD; + +typedef struct _ATOM_ENCODER_FPGA_CONTROL_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucCTL1GPIO_ID; + UCHAR ucCTL1GPIOState; //Set to 1 when it's active high + UCHAR ucCTL2GPIO_ID; + UCHAR ucCTL2GPIOState; //Set to 1 when it's active high + UCHAR ucCTL3GPIO_ID; + UCHAR ucCTL3GPIOState; //Set to 1 when it's active high + UCHAR ucCTLFPGA_IN_ID; + UCHAR ucPadding[3]; +}ATOM_ENCODER_FPGA_CONTROL_RECORD; + +typedef struct _ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucGPIOID; //Corresponding block in GPIO_PIN_INFO table gives the pin info + UCHAR ucTVActiveState; //Indicating when the pin==0 or 1 when TV is connected +}ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD; + +typedef struct _ATOM_JTAG_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucTMSGPIO_ID; + UCHAR ucTMSGPIOState; //Set to 1 when it's active high + UCHAR ucTCKGPIO_ID; + UCHAR ucTCKGPIOState; //Set to 1 when it's active high + UCHAR ucTDOGPIO_ID; + UCHAR ucTDOGPIOState; //Set to 1 when it's active high + UCHAR ucTDIGPIO_ID; + UCHAR ucTDIGPIOState; //Set to 1 when it's active high + UCHAR ucPadding[2]; +}ATOM_JTAG_RECORD; + + +//The following generic object gpio pin control record type will replace JTAG_RECORD/FPGA_CONTROL_RECORD/DVI_EXT_INPUT_RECORD above gradually +typedef struct _ATOM_GPIO_PIN_CONTROL_PAIR +{ + UCHAR ucGPIOID; // GPIO_ID, find the corresponding ID in GPIO_LUT table + UCHAR ucGPIO_PinState; // Pin state showing how to set-up the pin +}ATOM_GPIO_PIN_CONTROL_PAIR; + +typedef struct _ATOM_OBJECT_GPIO_CNTL_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucFlags; // Future expnadibility + UCHAR ucNumberOfPins; // Number of GPIO pins used to control the object + ATOM_GPIO_PIN_CONTROL_PAIR asGpio[1]; // the real gpio pin pair determined by number of pins ucNumberOfPins +}ATOM_OBJECT_GPIO_CNTL_RECORD; + +//Definitions for GPIO pin state +#define GPIO_PIN_TYPE_INPUT 0x00 +#define GPIO_PIN_TYPE_OUTPUT 0x10 +#define GPIO_PIN_TYPE_HW_CONTROL 0x20 + +//For GPIO_PIN_TYPE_OUTPUT the following is defined +#define GPIO_PIN_OUTPUT_STATE_MASK 0x01 +#define GPIO_PIN_OUTPUT_STATE_SHIFT 0 +#define GPIO_PIN_STATE_ACTIVE_LOW 0x0 +#define GPIO_PIN_STATE_ACTIVE_HIGH 0x1 + +// Indexes to GPIO array in GLSync record +#define ATOM_GPIO_INDEX_GLSYNC_REFCLK 0 +#define ATOM_GPIO_INDEX_GLSYNC_HSYNC 1 +#define ATOM_GPIO_INDEX_GLSYNC_VSYNC 2 +#define ATOM_GPIO_INDEX_GLSYNC_SWAP_REQ 3 +#define ATOM_GPIO_INDEX_GLSYNC_SWAP_GNT 4 +#define ATOM_GPIO_INDEX_GLSYNC_INTERRUPT 5 +#define ATOM_GPIO_INDEX_GLSYNC_V_RESET 6 +#define ATOM_GPIO_INDEX_GLSYNC_MAX 7 + +typedef struct _ATOM_ENCODER_DVO_CF_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + ULONG ulStrengthControl; // DVOA strength control for CF + UCHAR ucPadding[2]; +}ATOM_ENCODER_DVO_CF_RECORD; + +// value for ATOM_CONNECTOR_CF_RECORD.ucConnectedDvoBundle +#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_UPPER12BITBUNDLEA 1 +#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_LOWER12BITBUNDLEB 2 + +typedef struct _ATOM_CONNECTOR_CF_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + USHORT usMaxPixClk; + UCHAR ucFlowCntlGpioId; + UCHAR ucSwapCntlGpioId; + UCHAR ucConnectedDvoBundle; + UCHAR ucPadding; +}ATOM_CONNECTOR_CF_RECORD; + +typedef struct _ATOM_CONNECTOR_HARDCODE_DTD_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + ATOM_DTD_FORMAT asTiming; +}ATOM_CONNECTOR_HARDCODE_DTD_RECORD; + +typedef struct _ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; //ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE + UCHAR ucSubConnectorType; //CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D|X_ID_DUAL_LINK_DVI_D|HDMI_TYPE_A + UCHAR ucReserved; +}ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD; + + +typedef struct _ATOM_ROUTER_DDC_PATH_SELECT_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucMuxType; //decide the number of ucMuxState, =0, no pin state, =1: single state with complement, >1: multiple state + UCHAR ucMuxControlPin; + UCHAR ucMuxState[2]; //for alligment purpose +}ATOM_ROUTER_DDC_PATH_SELECT_RECORD; + +typedef struct _ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucMuxType; + UCHAR ucMuxControlPin; + UCHAR ucMuxState[2]; //for alligment purpose +}ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD; + +// define ucMuxType +#define ATOM_ROUTER_MUX_PIN_STATE_MASK 0x0f +#define ATOM_ROUTER_MUX_PIN_SINGLE_STATE_COMPLEMENT 0x01 + +typedef struct _ATOM_CONNECTOR_HPDPIN_LUT_RECORD //record for ATOM_CONNECTOR_HPDPIN_LUT_RECORD_TYPE +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucHPDPINMap[MAX_NUMBER_OF_EXT_HPDPIN_LUT_ENTRIES]; //An fixed size array which maps external pins to internal GPIO_PIN_INFO table +}ATOM_CONNECTOR_HPDPIN_LUT_RECORD; + +typedef struct _ATOM_CONNECTOR_AUXDDC_LUT_RECORD //record for ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE +{ + ATOM_COMMON_RECORD_HEADER sheader; + ATOM_I2C_ID_CONFIG ucAUXDDCMap[MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES]; //An fixed size array which maps external pins to internal DDC ID +}ATOM_CONNECTOR_AUXDDC_LUT_RECORD; + +typedef struct _ATOM_OBJECT_LINK_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + USHORT usObjectID; //could be connector, encorder or other object in object.h +}ATOM_OBJECT_LINK_RECORD; + +typedef struct _ATOM_CONNECTOR_REMOTE_CAP_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + USHORT usReserved; +}ATOM_CONNECTOR_REMOTE_CAP_RECORD; + +/****************************************************************************/ +// ASIC voltage data table +/****************************************************************************/ +typedef struct _ATOM_VOLTAGE_INFO_HEADER +{ + USHORT usVDDCBaseLevel; //In number of 50mv unit + USHORT usReserved; //For possible extension table offset + UCHAR ucNumOfVoltageEntries; + UCHAR ucBytesPerVoltageEntry; + UCHAR ucVoltageStep; //Indicating in how many mv increament is one step, 0.5mv unit + UCHAR ucDefaultVoltageEntry; + UCHAR ucVoltageControlI2cLine; + UCHAR ucVoltageControlAddress; + UCHAR ucVoltageControlOffset; +}ATOM_VOLTAGE_INFO_HEADER; + +typedef struct _ATOM_VOLTAGE_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VOLTAGE_INFO_HEADER viHeader; + UCHAR ucVoltageEntries[64]; //64 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries*ucBytesPerVoltageEntry +}ATOM_VOLTAGE_INFO; + + +typedef struct _ATOM_VOLTAGE_FORMULA +{ + USHORT usVoltageBaseLevel; // In number of 1mv unit + USHORT usVoltageStep; // Indicating in how many mv increament is one step, 1mv unit + UCHAR ucNumOfVoltageEntries; // Number of Voltage Entry, which indicate max Voltage + UCHAR ucFlag; // bit0=0 :step is 1mv =1 0.5mv + UCHAR ucBaseVID; // if there is no lookup table, VID= BaseVID + ( Vol - BaseLevle ) /VoltageStep + UCHAR ucReserved; + UCHAR ucVIDAdjustEntries[32]; // 32 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries +}ATOM_VOLTAGE_FORMULA; + +typedef struct _VOLTAGE_LUT_ENTRY +{ + USHORT usVoltageCode; // The Voltage ID, either GPIO or I2C code + USHORT usVoltageValue; // The corresponding Voltage Value, in mV +}VOLTAGE_LUT_ENTRY; + +typedef struct _ATOM_VOLTAGE_FORMULA_V2 +{ + UCHAR ucNumOfVoltageEntries; // Number of Voltage Entry, which indicate max Voltage + UCHAR ucReserved[3]; + VOLTAGE_LUT_ENTRY asVIDAdjustEntries[32];// 32 is for allocation, the actual number of entries is in ucNumOfVoltageEntries +}ATOM_VOLTAGE_FORMULA_V2; + +typedef struct _ATOM_VOLTAGE_CONTROL +{ + UCHAR ucVoltageControlId; //Indicate it is controlled by I2C or GPIO or HW state machine + UCHAR ucVoltageControlI2cLine; + UCHAR ucVoltageControlAddress; + UCHAR ucVoltageControlOffset; + USHORT usGpioPin_AIndex; //GPIO_PAD register index + UCHAR ucGpioPinBitShift[9]; //at most 8 pin support 255 VIDs, termintate with 0xff + UCHAR ucReserved; +}ATOM_VOLTAGE_CONTROL; + +// Define ucVoltageControlId +#define VOLTAGE_CONTROLLED_BY_HW 0x00 +#define VOLTAGE_CONTROLLED_BY_I2C_MASK 0x7F +#define VOLTAGE_CONTROLLED_BY_GPIO 0x80 +#define VOLTAGE_CONTROL_ID_LM64 0x01 //I2C control, used for R5xx Core Voltage +#define VOLTAGE_CONTROL_ID_DAC 0x02 //I2C control, used for R5xx/R6xx MVDDC,MVDDQ or VDDCI +#define VOLTAGE_CONTROL_ID_VT116xM 0x03 //I2C control, used for R6xx Core Voltage +#define VOLTAGE_CONTROL_ID_DS4402 0x04 + +typedef struct _ATOM_VOLTAGE_OBJECT +{ + UCHAR ucVoltageType; //Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI + UCHAR ucSize; //Size of Object + ATOM_VOLTAGE_CONTROL asControl; //describ how to control + ATOM_VOLTAGE_FORMULA asFormula; //Indicate How to convert real Voltage to VID +}ATOM_VOLTAGE_OBJECT; + +typedef struct _ATOM_VOLTAGE_OBJECT_V2 +{ + UCHAR ucVoltageType; //Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI + UCHAR ucSize; //Size of Object + ATOM_VOLTAGE_CONTROL asControl; //describ how to control + ATOM_VOLTAGE_FORMULA_V2 asFormula; //Indicate How to convert real Voltage to VID +}ATOM_VOLTAGE_OBJECT_V2; + +typedef struct _ATOM_VOLTAGE_OBJECT_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VOLTAGE_OBJECT asVoltageObj[3]; //Info for Voltage control +}ATOM_VOLTAGE_OBJECT_INFO; + +typedef struct _ATOM_VOLTAGE_OBJECT_INFO_V2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VOLTAGE_OBJECT_V2 asVoltageObj[3]; //Info for Voltage control +}ATOM_VOLTAGE_OBJECT_INFO_V2; + +typedef struct _ATOM_LEAKID_VOLTAGE +{ + UCHAR ucLeakageId; + UCHAR ucReserved; + USHORT usVoltage; +}ATOM_LEAKID_VOLTAGE; + +typedef struct _ATOM_ASIC_PROFILE_VOLTAGE +{ + UCHAR ucProfileId; + UCHAR ucReserved; + USHORT usSize; + USHORT usEfuseSpareStartAddr; + USHORT usFuseIndex[8]; //from LSB to MSB, Max 8bit,end of 0xffff if less than 8 efuse id, + ATOM_LEAKID_VOLTAGE asLeakVol[2]; //Leakid and relatd voltage +}ATOM_ASIC_PROFILE_VOLTAGE; + +//ucProfileId +#define ATOM_ASIC_PROFILE_ID_EFUSE_VOLTAGE 1 +#define ATOM_ASIC_PROFILE_ID_EFUSE_PERFORMANCE_VOLTAGE 1 +#define ATOM_ASIC_PROFILE_ID_EFUSE_THERMAL_VOLTAGE 2 + +typedef struct _ATOM_ASIC_PROFILING_INFO +{ + ATOM_COMMON_TABLE_HEADER asHeader; + ATOM_ASIC_PROFILE_VOLTAGE asVoltage; +}ATOM_ASIC_PROFILING_INFO; + +typedef struct _ATOM_POWER_SOURCE_OBJECT +{ + UCHAR ucPwrSrcId; // Power source + UCHAR ucPwrSensorType; // GPIO, I2C or none + UCHAR ucPwrSensId; // if GPIO detect, it is GPIO id, if I2C detect, it is I2C id + UCHAR ucPwrSensSlaveAddr; // Slave address if I2C detect + UCHAR ucPwrSensRegIndex; // I2C register Index if I2C detect + UCHAR ucPwrSensRegBitMask; // detect which bit is used if I2C detect + UCHAR ucPwrSensActiveState; // high active or low active + UCHAR ucReserve[3]; // reserve + USHORT usSensPwr; // in unit of watt +}ATOM_POWER_SOURCE_OBJECT; + +typedef struct _ATOM_POWER_SOURCE_INFO +{ + ATOM_COMMON_TABLE_HEADER asHeader; + UCHAR asPwrbehave[16]; + ATOM_POWER_SOURCE_OBJECT asPwrObj[1]; +}ATOM_POWER_SOURCE_INFO; + + +//Define ucPwrSrcId +#define POWERSOURCE_PCIE_ID1 0x00 +#define POWERSOURCE_6PIN_CONNECTOR_ID1 0x01 +#define POWERSOURCE_8PIN_CONNECTOR_ID1 0x02 +#define POWERSOURCE_6PIN_CONNECTOR_ID2 0x04 +#define POWERSOURCE_8PIN_CONNECTOR_ID2 0x08 + +//define ucPwrSensorId +#define POWER_SENSOR_ALWAYS 0x00 +#define POWER_SENSOR_GPIO 0x01 +#define POWER_SENSOR_I2C 0x02 + +typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulBootUpEngineClock; + ULONG ulDentistVCOFreq; + ULONG ulBootUpUMAClock; + ULONG ulReserved1[8]; + ULONG ulBootUpReqDisplayVector; + ULONG ulOtherDisplayMisc; + ULONG ulGPUCapInfo; + ULONG ulReserved2[3]; + ULONG ulSystemConfig; + ULONG ulCPUCapInfo; + USHORT usMaxNBVoltage; + USHORT usMinNBVoltage; + USHORT usBootUpNBVoltage; + USHORT usExtDispConnInfoOffset; + UCHAR ucHtcTmpLmt; + UCHAR ucTjOffset; + UCHAR ucMemoryType; + UCHAR ucUMAChannelNumber; + ULONG ulCSR_M3_ARB_CNTL_DEFAULT[10]; + ULONG ulCSR_M3_ARB_CNTL_UVD[10]; + ULONG ulCSR_M3_ARB_CNTL_FS3D[10]; + ULONG ulReserved3[42]; + ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo; +}ATOM_INTEGRATED_SYSTEM_INFO_V6; + +/********************************************************************************************************************** +// ATOM_INTEGRATED_SYSTEM_INFO_V6 Description +//ulBootUpEngineClock: VBIOS bootup Engine clock frequency, in 10kHz unit. +//ulDentistVCOFreq: Dentist VCO clock in 10kHz unit. +//ulBootUpUMAClock: System memory boot up clock frequency in 10Khz unit. +//ulReserved1[8] Reserved by now, must be 0x0. +//ulBootUpReqDisplayVector VBIOS boot up display IDs +// ATOM_DEVICE_CRT1_SUPPORT 0x0001 +// ATOM_DEVICE_CRT2_SUPPORT 0x0010 +// ATOM_DEVICE_DFP1_SUPPORT 0x0008 +// ATOM_DEVICE_DFP6_SUPPORT 0x0040 +// ATOM_DEVICE_DFP2_SUPPORT 0x0080 +// ATOM_DEVICE_DFP3_SUPPORT 0x0200 +// ATOM_DEVICE_DFP4_SUPPORT 0x0400 +// ATOM_DEVICE_DFP5_SUPPORT 0x0800 +// ATOM_DEVICE_LCD1_SUPPORT 0x0002 +//ulOtherDisplayMisc Other display related flags, not defined yet. +//ulGPUCapInfo TBD +//ulReserved2[3] must be 0x0 for the reserved. +//ulSystemConfig TBD +//ulCPUCapInfo TBD +//usMaxNBVoltage High NB voltage in unit of mv, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse. +//usMinNBVoltage Low NB voltage in unit of mv, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse. +//usBootUpNBVoltage Boot up NB voltage in unit of mv. +//ucHtcTmpLmt Bit [22:16] of D24F3x64 Thermal Control (HTC) Register. +//ucTjOffset Bit [28:22] of D24F3xE4 Thermtrip Status Register,may not be needed. +//ucMemoryType [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved. +//ucUMAChannelNumber System memory channel numbers. +//usExtDispConnectionInfoOffset ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO offset relative to beginning of this table. +//ulCSR_M3_ARB_CNTL_DEFAULT[10] Arrays with values for CSR M3 arbiter for default +//ulCSR_M3_ARB_CNTL_UVD[10] Arrays with values for CSR M3 arbiter for UVD playback. +//ulCSR_M3_ARB_CNTL_FS3D[10] Arrays with values for CSR M3 arbiter for Full Screen 3D applications. +**********************************************************************************************************************/ + +/**************************************************************************/ +// This portion is only used when ext thermal chip or engine/memory clock SS chip is populated on a design +//Memory SS Info Table +//Define Memory Clock SS chip ID +#define ICS91719 1 +#define ICS91720 2 + +//Define one structure to inform SW a "block of data" writing to external SS chip via I2C protocol +typedef struct _ATOM_I2C_DATA_RECORD +{ + UCHAR ucNunberOfBytes; //Indicates how many bytes SW needs to write to the external ASIC for one block, besides to "Start" and "Stop" + UCHAR ucI2CData[1]; //I2C data in bytes, should be less than 16 bytes usually +}ATOM_I2C_DATA_RECORD; + + +//Define one structure to inform SW how many blocks of data writing to external SS chip via I2C protocol, in addition to other information +typedef struct _ATOM_I2C_DEVICE_SETUP_INFO +{ + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; //I2C line and HW/SW assisted cap. + UCHAR ucSSChipID; //SS chip being used + UCHAR ucSSChipSlaveAddr; //Slave Address to set up this SS chip + UCHAR ucNumOfI2CDataRecords; //number of data block + ATOM_I2C_DATA_RECORD asI2CData[1]; +}ATOM_I2C_DEVICE_SETUP_INFO; + +//========================================================================================== +typedef struct _ATOM_ASIC_MVDD_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_I2C_DEVICE_SETUP_INFO asI2CSetup[1]; +}ATOM_ASIC_MVDD_INFO; + +//========================================================================================== +#define ATOM_MCLK_SS_INFO ATOM_ASIC_MVDD_INFO + +//========================================================================================== +/**************************************************************************/ + +typedef struct _ATOM_ASIC_SS_ASSIGNMENT +{ + ULONG ulTargetClockRange; //Clock Out frequence (VCO ), in unit of 10Khz + USHORT usSpreadSpectrumPercentage; //in unit of 0.01% + USHORT usSpreadRateInKhz; //in unit of kHz, modulation freq + UCHAR ucClockIndication; //Indicate which clock source needs SS + UCHAR ucSpreadSpectrumMode; //Bit1=0 Down Spread,=1 Center Spread. + UCHAR ucReserved[2]; +}ATOM_ASIC_SS_ASSIGNMENT; + +//Define ucClockIndication, SW uses the IDs below to search if the SS is required/enabled on a clock branch/signal type. +//SS is not required or enabled if a match is not found. +#define ASIC_INTERNAL_MEMORY_SS 1 +#define ASIC_INTERNAL_ENGINE_SS 2 +#define ASIC_INTERNAL_UVD_SS 3 +#define ASIC_INTERNAL_SS_ON_TMDS 4 +#define ASIC_INTERNAL_SS_ON_HDMI 5 +#define ASIC_INTERNAL_SS_ON_LVDS 6 +#define ASIC_INTERNAL_SS_ON_DP 7 +#define ASIC_INTERNAL_SS_ON_DCPLL 8 + +typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V2 +{ + ULONG ulTargetClockRange; //For mem/engine/uvd, Clock Out frequence (VCO ), in unit of 10Khz + //For TMDS/HDMI/LVDS, it is pixel clock , for DP, it is link clock ( 27000 or 16200 ) + USHORT usSpreadSpectrumPercentage; //in unit of 0.01% + USHORT usSpreadRateIn10Hz; //in unit of 10Hz, modulation freq + UCHAR ucClockIndication; //Indicate which clock source needs SS + UCHAR ucSpreadSpectrumMode; //Bit0=0 Down Spread,=1 Center Spread, bit1=0: internal SS bit1=1: external SS + UCHAR ucReserved[2]; +}ATOM_ASIC_SS_ASSIGNMENT_V2; + +//ucSpreadSpectrumMode +//#define ATOM_SS_DOWN_SPREAD_MODE_MASK 0x00000000 +//#define ATOM_SS_DOWN_SPREAD_MODE 0x00000000 +//#define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001 +//#define ATOM_SS_CENTRE_SPREAD_MODE 0x00000001 +//#define ATOM_INTERNAL_SS_MASK 0x00000000 +//#define ATOM_EXTERNAL_SS_MASK 0x00000002 + +typedef struct _ATOM_ASIC_INTERNAL_SS_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_ASIC_SS_ASSIGNMENT asSpreadSpectrum[4]; +}ATOM_ASIC_INTERNAL_SS_INFO; + +typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_ASIC_SS_ASSIGNMENT_V2 asSpreadSpectrum[1]; //this is point only. +}ATOM_ASIC_INTERNAL_SS_INFO_V2; + +typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V3 +{ + ULONG ulTargetClockRange; //For mem/engine/uvd, Clock Out frequence (VCO ), in unit of 10Khz + //For TMDS/HDMI/LVDS, it is pixel clock , for DP, it is link clock ( 27000 or 16200 ) + USHORT usSpreadSpectrumPercentage; //in unit of 0.01% + USHORT usSpreadRateIn10Hz; //in unit of 10Hz, modulation freq + UCHAR ucClockIndication; //Indicate which clock source needs SS + UCHAR ucSpreadSpectrumMode; //Bit0=0 Down Spread,=1 Center Spread, bit1=0: internal SS bit1=1: external SS + UCHAR ucReserved[2]; +}ATOM_ASIC_SS_ASSIGNMENT_V3; + +typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_ASIC_SS_ASSIGNMENT_V3 asSpreadSpectrum[1]; //this is pointer only. +}ATOM_ASIC_INTERNAL_SS_INFO_V3; + + +//==============================Scratch Pad Definition Portion=============================== +#define ATOM_DEVICE_CONNECT_INFO_DEF 0 +#define ATOM_ROM_LOCATION_DEF 1 +#define ATOM_TV_STANDARD_DEF 2 +#define ATOM_ACTIVE_INFO_DEF 3 +#define ATOM_LCD_INFO_DEF 4 +#define ATOM_DOS_REQ_INFO_DEF 5 +#define ATOM_ACC_CHANGE_INFO_DEF 6 +#define ATOM_DOS_MODE_INFO_DEF 7 +#define ATOM_I2C_CHANNEL_STATUS_DEF 8 +#define ATOM_I2C_CHANNEL_STATUS1_DEF 9 + + +// BIOS_0_SCRATCH Definition +#define ATOM_S0_CRT1_MONO 0x00000001L +#define ATOM_S0_CRT1_COLOR 0x00000002L +#define ATOM_S0_CRT1_MASK (ATOM_S0_CRT1_MONO+ATOM_S0_CRT1_COLOR) + +#define ATOM_S0_TV1_COMPOSITE_A 0x00000004L +#define ATOM_S0_TV1_SVIDEO_A 0x00000008L +#define ATOM_S0_TV1_MASK_A (ATOM_S0_TV1_COMPOSITE_A+ATOM_S0_TV1_SVIDEO_A) + +#define ATOM_S0_CV_A 0x00000010L +#define ATOM_S0_CV_DIN_A 0x00000020L +#define ATOM_S0_CV_MASK_A (ATOM_S0_CV_A+ATOM_S0_CV_DIN_A) + + +#define ATOM_S0_CRT2_MONO 0x00000100L +#define ATOM_S0_CRT2_COLOR 0x00000200L +#define ATOM_S0_CRT2_MASK (ATOM_S0_CRT2_MONO+ATOM_S0_CRT2_COLOR) + +#define ATOM_S0_TV1_COMPOSITE 0x00000400L +#define ATOM_S0_TV1_SVIDEO 0x00000800L +#define ATOM_S0_TV1_SCART 0x00004000L +#define ATOM_S0_TV1_MASK (ATOM_S0_TV1_COMPOSITE+ATOM_S0_TV1_SVIDEO+ATOM_S0_TV1_SCART) + +#define ATOM_S0_CV 0x00001000L +#define ATOM_S0_CV_DIN 0x00002000L +#define ATOM_S0_CV_MASK (ATOM_S0_CV+ATOM_S0_CV_DIN) + +#define ATOM_S0_DFP1 0x00010000L +#define ATOM_S0_DFP2 0x00020000L +#define ATOM_S0_LCD1 0x00040000L +#define ATOM_S0_LCD2 0x00080000L +#define ATOM_S0_DFP6 0x00100000L +#define ATOM_S0_DFP3 0x00200000L +#define ATOM_S0_DFP4 0x00400000L +#define ATOM_S0_DFP5 0x00800000L + +#define ATOM_S0_DFP_MASK ATOM_S0_DFP1 | ATOM_S0_DFP2 | ATOM_S0_DFP3 | ATOM_S0_DFP4 | ATOM_S0_DFP5 | ATOM_S0_DFP6 + +#define ATOM_S0_FAD_REGISTER_BUG 0x02000000L // If set, indicates we are running a PCIE asic with + // the FAD/HDP reg access bug. Bit is read by DAL, this is obsolete from RV5xx + +#define ATOM_S0_THERMAL_STATE_MASK 0x1C000000L +#define ATOM_S0_THERMAL_STATE_SHIFT 26 + +#define ATOM_S0_SYSTEM_POWER_STATE_MASK 0xE0000000L +#define ATOM_S0_SYSTEM_POWER_STATE_SHIFT 29 + +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_AC 1 +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_DC 2 +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LITEAC 3 + +//Byte aligned defintion for BIOS usage +#define ATOM_S0_CRT1_MONOb0 0x01 +#define ATOM_S0_CRT1_COLORb0 0x02 +#define ATOM_S0_CRT1_MASKb0 (ATOM_S0_CRT1_MONOb0+ATOM_S0_CRT1_COLORb0) + +#define ATOM_S0_TV1_COMPOSITEb0 0x04 +#define ATOM_S0_TV1_SVIDEOb0 0x08 +#define ATOM_S0_TV1_MASKb0 (ATOM_S0_TV1_COMPOSITEb0+ATOM_S0_TV1_SVIDEOb0) + +#define ATOM_S0_CVb0 0x10 +#define ATOM_S0_CV_DINb0 0x20 +#define ATOM_S0_CV_MASKb0 (ATOM_S0_CVb0+ATOM_S0_CV_DINb0) + +#define ATOM_S0_CRT2_MONOb1 0x01 +#define ATOM_S0_CRT2_COLORb1 0x02 +#define ATOM_S0_CRT2_MASKb1 (ATOM_S0_CRT2_MONOb1+ATOM_S0_CRT2_COLORb1) + +#define ATOM_S0_TV1_COMPOSITEb1 0x04 +#define ATOM_S0_TV1_SVIDEOb1 0x08 +#define ATOM_S0_TV1_SCARTb1 0x40 +#define ATOM_S0_TV1_MASKb1 (ATOM_S0_TV1_COMPOSITEb1+ATOM_S0_TV1_SVIDEOb1+ATOM_S0_TV1_SCARTb1) + +#define ATOM_S0_CVb1 0x10 +#define ATOM_S0_CV_DINb1 0x20 +#define ATOM_S0_CV_MASKb1 (ATOM_S0_CVb1+ATOM_S0_CV_DINb1) + +#define ATOM_S0_DFP1b2 0x01 +#define ATOM_S0_DFP2b2 0x02 +#define ATOM_S0_LCD1b2 0x04 +#define ATOM_S0_LCD2b2 0x08 +#define ATOM_S0_DFP6b2 0x10 +#define ATOM_S0_DFP3b2 0x20 +#define ATOM_S0_DFP4b2 0x40 +#define ATOM_S0_DFP5b2 0x80 + + +#define ATOM_S0_THERMAL_STATE_MASKb3 0x1C +#define ATOM_S0_THERMAL_STATE_SHIFTb3 2 + +#define ATOM_S0_SYSTEM_POWER_STATE_MASKb3 0xE0 +#define ATOM_S0_LCD1_SHIFT 18 + +// BIOS_1_SCRATCH Definition +#define ATOM_S1_ROM_LOCATION_MASK 0x0000FFFFL +#define ATOM_S1_PCI_BUS_DEV_MASK 0xFFFF0000L + +// BIOS_2_SCRATCH Definition +#define ATOM_S2_TV1_STANDARD_MASK 0x0000000FL +#define ATOM_S2_CURRENT_BL_LEVEL_MASK 0x0000FF00L +#define ATOM_S2_CURRENT_BL_LEVEL_SHIFT 8 + +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK 0x0C000000L +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK_SHIFT 26 +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGE 0x10000000L + +#define ATOM_S2_DEVICE_DPMS_STATE 0x00010000L +#define ATOM_S2_VRI_BRIGHT_ENABLE 0x20000000L + +#define ATOM_S2_DISPLAY_ROTATION_0_DEGREE 0x0 +#define ATOM_S2_DISPLAY_ROTATION_90_DEGREE 0x1 +#define ATOM_S2_DISPLAY_ROTATION_180_DEGREE 0x2 +#define ATOM_S2_DISPLAY_ROTATION_270_DEGREE 0x3 +#define ATOM_S2_DISPLAY_ROTATION_DEGREE_SHIFT 30 +#define ATOM_S2_DISPLAY_ROTATION_ANGLE_MASK 0xC0000000L + + +//Byte aligned defintion for BIOS usage +#define ATOM_S2_TV1_STANDARD_MASKb0 0x0F +#define ATOM_S2_CURRENT_BL_LEVEL_MASKb1 0xFF +#define ATOM_S2_DEVICE_DPMS_STATEb2 0x01 + +#define ATOM_S2_DEVICE_DPMS_MASKw1 0x3FF +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASKb3 0x0C +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGEb3 0x10 +#define ATOM_S2_VRI_BRIGHT_ENABLEb3 0x20 +#define ATOM_S2_ROTATION_STATE_MASKb3 0xC0 + + +// BIOS_3_SCRATCH Definition +#define ATOM_S3_CRT1_ACTIVE 0x00000001L +#define ATOM_S3_LCD1_ACTIVE 0x00000002L +#define ATOM_S3_TV1_ACTIVE 0x00000004L +#define ATOM_S3_DFP1_ACTIVE 0x00000008L +#define ATOM_S3_CRT2_ACTIVE 0x00000010L +#define ATOM_S3_LCD2_ACTIVE 0x00000020L +#define ATOM_S3_DFP6_ACTIVE 0x00000040L +#define ATOM_S3_DFP2_ACTIVE 0x00000080L +#define ATOM_S3_CV_ACTIVE 0x00000100L +#define ATOM_S3_DFP3_ACTIVE 0x00000200L +#define ATOM_S3_DFP4_ACTIVE 0x00000400L +#define ATOM_S3_DFP5_ACTIVE 0x00000800L + +#define ATOM_S3_DEVICE_ACTIVE_MASK 0x00000FFFL + +#define ATOM_S3_LCD_FULLEXPANSION_ACTIVE 0x00001000L +#define ATOM_S3_LCD_EXPANSION_ASPEC_RATIO_ACTIVE 0x00002000L + +#define ATOM_S3_CRT1_CRTC_ACTIVE 0x00010000L +#define ATOM_S3_LCD1_CRTC_ACTIVE 0x00020000L +#define ATOM_S3_TV1_CRTC_ACTIVE 0x00040000L +#define ATOM_S3_DFP1_CRTC_ACTIVE 0x00080000L +#define ATOM_S3_CRT2_CRTC_ACTIVE 0x00100000L +#define ATOM_S3_LCD2_CRTC_ACTIVE 0x00200000L +#define ATOM_S3_DFP6_CRTC_ACTIVE 0x00400000L +#define ATOM_S3_DFP2_CRTC_ACTIVE 0x00800000L +#define ATOM_S3_CV_CRTC_ACTIVE 0x01000000L +#define ATOM_S3_DFP3_CRTC_ACTIVE 0x02000000L +#define ATOM_S3_DFP4_CRTC_ACTIVE 0x04000000L +#define ATOM_S3_DFP5_CRTC_ACTIVE 0x08000000L + +#define ATOM_S3_DEVICE_CRTC_ACTIVE_MASK 0x0FFF0000L +#define ATOM_S3_ASIC_GUI_ENGINE_HUNG 0x20000000L +//Below two definitions are not supported in pplib, but in the old powerplay in DAL +#define ATOM_S3_ALLOW_FAST_PWR_SWITCH 0x40000000L +#define ATOM_S3_RQST_GPU_USE_MIN_PWR 0x80000000L + +//Byte aligned defintion for BIOS usage +#define ATOM_S3_CRT1_ACTIVEb0 0x01 +#define ATOM_S3_LCD1_ACTIVEb0 0x02 +#define ATOM_S3_TV1_ACTIVEb0 0x04 +#define ATOM_S3_DFP1_ACTIVEb0 0x08 +#define ATOM_S3_CRT2_ACTIVEb0 0x10 +#define ATOM_S3_LCD2_ACTIVEb0 0x20 +#define ATOM_S3_DFP6_ACTIVEb0 0x40 +#define ATOM_S3_DFP2_ACTIVEb0 0x80 +#define ATOM_S3_CV_ACTIVEb1 0x01 +#define ATOM_S3_DFP3_ACTIVEb1 0x02 +#define ATOM_S3_DFP4_ACTIVEb1 0x04 +#define ATOM_S3_DFP5_ACTIVEb1 0x08 + +#define ATOM_S3_ACTIVE_CRTC1w0 0xFFF + +#define ATOM_S3_CRT1_CRTC_ACTIVEb2 0x01 +#define ATOM_S3_LCD1_CRTC_ACTIVEb2 0x02 +#define ATOM_S3_TV1_CRTC_ACTIVEb2 0x04 +#define ATOM_S3_DFP1_CRTC_ACTIVEb2 0x08 +#define ATOM_S3_CRT2_CRTC_ACTIVEb2 0x10 +#define ATOM_S3_LCD2_CRTC_ACTIVEb2 0x20 +#define ATOM_S3_DFP6_CRTC_ACTIVEb2 0x40 +#define ATOM_S3_DFP2_CRTC_ACTIVEb2 0x80 +#define ATOM_S3_CV_CRTC_ACTIVEb3 0x01 +#define ATOM_S3_DFP3_CRTC_ACTIVEb3 0x02 +#define ATOM_S3_DFP4_CRTC_ACTIVEb3 0x04 +#define ATOM_S3_DFP5_CRTC_ACTIVEb3 0x08 + +#define ATOM_S3_ACTIVE_CRTC2w1 0xFFF + +// BIOS_4_SCRATCH Definition +#define ATOM_S4_LCD1_PANEL_ID_MASK 0x000000FFL +#define ATOM_S4_LCD1_REFRESH_MASK 0x0000FF00L +#define ATOM_S4_LCD1_REFRESH_SHIFT 8 + +//Byte aligned defintion for BIOS usage +#define ATOM_S4_LCD1_PANEL_ID_MASKb0 0x0FF +#define ATOM_S4_LCD1_REFRESH_MASKb1 ATOM_S4_LCD1_PANEL_ID_MASKb0 +#define ATOM_S4_VRAM_INFO_MASKb2 ATOM_S4_LCD1_PANEL_ID_MASKb0 + +// BIOS_5_SCRATCH Definition, BIOS_5_SCRATCH is used by Firmware only !!!! +#define ATOM_S5_DOS_REQ_CRT1b0 0x01 +#define ATOM_S5_DOS_REQ_LCD1b0 0x02 +#define ATOM_S5_DOS_REQ_TV1b0 0x04 +#define ATOM_S5_DOS_REQ_DFP1b0 0x08 +#define ATOM_S5_DOS_REQ_CRT2b0 0x10 +#define ATOM_S5_DOS_REQ_LCD2b0 0x20 +#define ATOM_S5_DOS_REQ_DFP6b0 0x40 +#define ATOM_S5_DOS_REQ_DFP2b0 0x80 +#define ATOM_S5_DOS_REQ_CVb1 0x01 +#define ATOM_S5_DOS_REQ_DFP3b1 0x02 +#define ATOM_S5_DOS_REQ_DFP4b1 0x04 +#define ATOM_S5_DOS_REQ_DFP5b1 0x08 + +#define ATOM_S5_DOS_REQ_DEVICEw0 0x0FFF + +#define ATOM_S5_DOS_REQ_CRT1 0x0001 +#define ATOM_S5_DOS_REQ_LCD1 0x0002 +#define ATOM_S5_DOS_REQ_TV1 0x0004 +#define ATOM_S5_DOS_REQ_DFP1 0x0008 +#define ATOM_S5_DOS_REQ_CRT2 0x0010 +#define ATOM_S5_DOS_REQ_LCD2 0x0020 +#define ATOM_S5_DOS_REQ_DFP6 0x0040 +#define ATOM_S5_DOS_REQ_DFP2 0x0080 +#define ATOM_S5_DOS_REQ_CV 0x0100 +#define ATOM_S5_DOS_REQ_DFP3 0x0200 +#define ATOM_S5_DOS_REQ_DFP4 0x0400 +#define ATOM_S5_DOS_REQ_DFP5 0x0800 + +#define ATOM_S5_DOS_FORCE_CRT1b2 ATOM_S5_DOS_REQ_CRT1b0 +#define ATOM_S5_DOS_FORCE_TV1b2 ATOM_S5_DOS_REQ_TV1b0 +#define ATOM_S5_DOS_FORCE_CRT2b2 ATOM_S5_DOS_REQ_CRT2b0 +#define ATOM_S5_DOS_FORCE_CVb3 ATOM_S5_DOS_REQ_CVb1 +#define ATOM_S5_DOS_FORCE_DEVICEw1 (ATOM_S5_DOS_FORCE_CRT1b2+ATOM_S5_DOS_FORCE_TV1b2+ATOM_S5_DOS_FORCE_CRT2b2+\ + (ATOM_S5_DOS_FORCE_CVb3<<8)) + +// BIOS_6_SCRATCH Definition +#define ATOM_S6_DEVICE_CHANGE 0x00000001L +#define ATOM_S6_SCALER_CHANGE 0x00000002L +#define ATOM_S6_LID_CHANGE 0x00000004L +#define ATOM_S6_DOCKING_CHANGE 0x00000008L +#define ATOM_S6_ACC_MODE 0x00000010L +#define ATOM_S6_EXT_DESKTOP_MODE 0x00000020L +#define ATOM_S6_LID_STATE 0x00000040L +#define ATOM_S6_DOCK_STATE 0x00000080L +#define ATOM_S6_CRITICAL_STATE 0x00000100L +#define ATOM_S6_HW_I2C_BUSY_STATE 0x00000200L +#define ATOM_S6_THERMAL_STATE_CHANGE 0x00000400L +#define ATOM_S6_INTERRUPT_SET_BY_BIOS 0x00000800L +#define ATOM_S6_REQ_LCD_EXPANSION_FULL 0x00001000L //Normal expansion Request bit for LCD +#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO 0x00002000L //Aspect ratio expansion Request bit for LCD + +#define ATOM_S6_DISPLAY_STATE_CHANGE 0x00004000L //This bit is recycled when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_H_expansion +#define ATOM_S6_I2C_STATE_CHANGE 0x00008000L //This bit is recycled,when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_V_expansion + +#define ATOM_S6_ACC_REQ_CRT1 0x00010000L +#define ATOM_S6_ACC_REQ_LCD1 0x00020000L +#define ATOM_S6_ACC_REQ_TV1 0x00040000L +#define ATOM_S6_ACC_REQ_DFP1 0x00080000L +#define ATOM_S6_ACC_REQ_CRT2 0x00100000L +#define ATOM_S6_ACC_REQ_LCD2 0x00200000L +#define ATOM_S6_ACC_REQ_DFP6 0x00400000L +#define ATOM_S6_ACC_REQ_DFP2 0x00800000L +#define ATOM_S6_ACC_REQ_CV 0x01000000L +#define ATOM_S6_ACC_REQ_DFP3 0x02000000L +#define ATOM_S6_ACC_REQ_DFP4 0x04000000L +#define ATOM_S6_ACC_REQ_DFP5 0x08000000L + +#define ATOM_S6_ACC_REQ_MASK 0x0FFF0000L +#define ATOM_S6_SYSTEM_POWER_MODE_CHANGE 0x10000000L +#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH 0x20000000L +#define ATOM_S6_VRI_BRIGHTNESS_CHANGE 0x40000000L +#define ATOM_S6_CONFIG_DISPLAY_CHANGE_MASK 0x80000000L + +//Byte aligned defintion for BIOS usage +#define ATOM_S6_DEVICE_CHANGEb0 0x01 +#define ATOM_S6_SCALER_CHANGEb0 0x02 +#define ATOM_S6_LID_CHANGEb0 0x04 +#define ATOM_S6_DOCKING_CHANGEb0 0x08 +#define ATOM_S6_ACC_MODEb0 0x10 +#define ATOM_S6_EXT_DESKTOP_MODEb0 0x20 +#define ATOM_S6_LID_STATEb0 0x40 +#define ATOM_S6_DOCK_STATEb0 0x80 +#define ATOM_S6_CRITICAL_STATEb1 0x01 +#define ATOM_S6_HW_I2C_BUSY_STATEb1 0x02 +#define ATOM_S6_THERMAL_STATE_CHANGEb1 0x04 +#define ATOM_S6_INTERRUPT_SET_BY_BIOSb1 0x08 +#define ATOM_S6_REQ_LCD_EXPANSION_FULLb1 0x10 +#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIOb1 0x20 + +#define ATOM_S6_ACC_REQ_CRT1b2 0x01 +#define ATOM_S6_ACC_REQ_LCD1b2 0x02 +#define ATOM_S6_ACC_REQ_TV1b2 0x04 +#define ATOM_S6_ACC_REQ_DFP1b2 0x08 +#define ATOM_S6_ACC_REQ_CRT2b2 0x10 +#define ATOM_S6_ACC_REQ_LCD2b2 0x20 +#define ATOM_S6_ACC_REQ_DFP6b2 0x40 +#define ATOM_S6_ACC_REQ_DFP2b2 0x80 +#define ATOM_S6_ACC_REQ_CVb3 0x01 +#define ATOM_S6_ACC_REQ_DFP3b3 0x02 +#define ATOM_S6_ACC_REQ_DFP4b3 0x04 +#define ATOM_S6_ACC_REQ_DFP5b3 0x08 + +#define ATOM_S6_ACC_REQ_DEVICEw1 ATOM_S5_DOS_REQ_DEVICEw0 +#define ATOM_S6_SYSTEM_POWER_MODE_CHANGEb3 0x10 +#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCHb3 0x20 +#define ATOM_S6_VRI_BRIGHTNESS_CHANGEb3 0x40 +#define ATOM_S6_CONFIG_DISPLAY_CHANGEb3 0x80 + +#define ATOM_S6_DEVICE_CHANGE_SHIFT 0 +#define ATOM_S6_SCALER_CHANGE_SHIFT 1 +#define ATOM_S6_LID_CHANGE_SHIFT 2 +#define ATOM_S6_DOCKING_CHANGE_SHIFT 3 +#define ATOM_S6_ACC_MODE_SHIFT 4 +#define ATOM_S6_EXT_DESKTOP_MODE_SHIFT 5 +#define ATOM_S6_LID_STATE_SHIFT 6 +#define ATOM_S6_DOCK_STATE_SHIFT 7 +#define ATOM_S6_CRITICAL_STATE_SHIFT 8 +#define ATOM_S6_HW_I2C_BUSY_STATE_SHIFT 9 +#define ATOM_S6_THERMAL_STATE_CHANGE_SHIFT 10 +#define ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT 11 +#define ATOM_S6_REQ_SCALER_SHIFT 12 +#define ATOM_S6_REQ_SCALER_ARATIO_SHIFT 13 +#define ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT 14 +#define ATOM_S6_I2C_STATE_CHANGE_SHIFT 15 +#define ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT 28 +#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH_SHIFT 29 +#define ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT 30 +#define ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT 31 + +// BIOS_7_SCRATCH Definition, BIOS_7_SCRATCH is used by Firmware only !!!! +#define ATOM_S7_DOS_MODE_TYPEb0 0x03 +#define ATOM_S7_DOS_MODE_VGAb0 0x00 +#define ATOM_S7_DOS_MODE_VESAb0 0x01 +#define ATOM_S7_DOS_MODE_EXTb0 0x02 +#define ATOM_S7_DOS_MODE_PIXEL_DEPTHb0 0x0C +#define ATOM_S7_DOS_MODE_PIXEL_FORMATb0 0xF0 +#define ATOM_S7_DOS_8BIT_DAC_ENb1 0x01 +#define ATOM_S7_DOS_MODE_NUMBERw1 0x0FFFF + +#define ATOM_S7_DOS_8BIT_DAC_EN_SHIFT 8 + +// BIOS_8_SCRATCH Definition +#define ATOM_S8_I2C_CHANNEL_BUSY_MASK 0x00000FFFF +#define ATOM_S8_I2C_HW_ENGINE_BUSY_MASK 0x0FFFF0000 + +#define ATOM_S8_I2C_CHANNEL_BUSY_SHIFT 0 +#define ATOM_S8_I2C_ENGINE_BUSY_SHIFT 16 + +// BIOS_9_SCRATCH Definition +#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_MASK +#define ATOM_S9_I2C_CHANNEL_COMPLETED_MASK 0x0000FFFF +#endif +#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_MASK +#define ATOM_S9_I2C_CHANNEL_ABORTED_MASK 0xFFFF0000 +#endif +#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT +#define ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT 0 +#endif +#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT +#define ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT 16 +#endif + + +#define ATOM_FLAG_SET 0x20 +#define ATOM_FLAG_CLEAR 0 +#define CLEAR_ATOM_S6_ACC_MODE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_ACC_MODE_SHIFT | ATOM_FLAG_CLEAR) +#define SET_ATOM_S6_DEVICE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DEVICE_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_VRI_BRIGHTNESS_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_SCALER_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_SCALER_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_LID_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_CHANGE_SHIFT | ATOM_FLAG_SET) + +#define SET_ATOM_S6_LID_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_LID_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_CLEAR) + +#define SET_ATOM_S6_DOCK_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCKING_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_DOCK_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_DOCK_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_CLEAR) + +#define SET_ATOM_S6_THERMAL_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_THERMAL_STATE_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_SYSTEM_POWER_MODE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_INTERRUPT_SET_BY_BIOS ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT | ATOM_FLAG_SET) + +#define SET_ATOM_S6_CRITICAL_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_CRITICAL_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_CLEAR) + +#define SET_ATOM_S6_REQ_SCALER ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_REQ_SCALER ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_CLEAR ) + +#define SET_ATOM_S6_REQ_SCALER_ARATIO ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_SET ) +#define CLEAR_ATOM_S6_REQ_SCALER_ARATIO ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_CLEAR ) + +#define SET_ATOM_S6_I2C_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_I2C_STATE_CHANGE_SHIFT | ATOM_FLAG_SET ) + +#define SET_ATOM_S6_DISPLAY_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT | ATOM_FLAG_SET ) + +#define SET_ATOM_S6_DEVICE_RECONFIG ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S0_LCD1 ((ATOM_DEVICE_CONNECT_INFO_DEF << 8 )| ATOM_S0_LCD1_SHIFT | ATOM_FLAG_CLEAR ) +#define SET_ATOM_S7_DOS_8BIT_DAC_EN ((ATOM_DOS_MODE_INFO_DEF << 8 )|ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_SET ) +#define CLEAR_ATOM_S7_DOS_8BIT_DAC_EN ((ATOM_DOS_MODE_INFO_DEF << 8 )|ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_CLEAR ) + +/****************************************************************************/ +//Portion II: Definitinos only used in Driver +/****************************************************************************/ + +// Macros used by driver +#ifdef __cplusplus +#define GetIndexIntoMasterTable(MasterOrData, FieldName) ((reinterpret_cast(&(static_cast(0))->FieldName)-static_cast(0))/sizeof(USHORT)) + +#define GET_COMMAND_TABLE_COMMANDSET_REVISION(TABLE_HEADER_OFFSET) (((static_cast(TABLE_HEADER_OFFSET))->ucTableFormatRevision )&0x3F) +#define GET_COMMAND_TABLE_PARAMETER_REVISION(TABLE_HEADER_OFFSET) (((static_cast(TABLE_HEADER_OFFSET))->ucTableContentRevision)&0x3F) +#else // not __cplusplus +#define GetIndexIntoMasterTable(MasterOrData, FieldName) (((char*)(&((ATOM_MASTER_LIST_OF_##MasterOrData##_TABLES*)0)->FieldName)-(char*)0)/sizeof(USHORT)) + +#define GET_COMMAND_TABLE_COMMANDSET_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableFormatRevision)&0x3F) +#define GET_COMMAND_TABLE_PARAMETER_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableContentRevision)&0x3F) +#endif // __cplusplus + +#define GET_DATA_TABLE_MAJOR_REVISION GET_COMMAND_TABLE_COMMANDSET_REVISION +#define GET_DATA_TABLE_MINOR_REVISION GET_COMMAND_TABLE_PARAMETER_REVISION + +/****************************************************************************/ +//Portion III: Definitinos only used in VBIOS +/****************************************************************************/ +#define ATOM_DAC_SRC 0x80 +#define ATOM_SRC_DAC1 0 +#define ATOM_SRC_DAC2 0x80 + +typedef struct _MEMORY_PLLINIT_PARAMETERS +{ + ULONG ulTargetMemoryClock; //In 10Khz unit + UCHAR ucAction; //not define yet + UCHAR ucFbDiv_Hi; //Fbdiv Hi byte + UCHAR ucFbDiv; //FB value + UCHAR ucPostDiv; //Post div +}MEMORY_PLLINIT_PARAMETERS; + +#define MEMORY_PLLINIT_PS_ALLOCATION MEMORY_PLLINIT_PARAMETERS + + +#define GPIO_PIN_WRITE 0x01 +#define GPIO_PIN_READ 0x00 + +typedef struct _GPIO_PIN_CONTROL_PARAMETERS +{ + UCHAR ucGPIO_ID; //return value, read from GPIO pins + UCHAR ucGPIOBitShift; //define which bit in uGPIOBitVal need to be update + UCHAR ucGPIOBitVal; //Set/Reset corresponding bit defined in ucGPIOBitMask + UCHAR ucAction; //=GPIO_PIN_WRITE: Read; =GPIO_PIN_READ: Write +}GPIO_PIN_CONTROL_PARAMETERS; + +typedef struct _ENABLE_SCALER_PARAMETERS +{ + UCHAR ucScaler; // ATOM_SCALER1, ATOM_SCALER2 + UCHAR ucEnable; // ATOM_SCALER_DISABLE or ATOM_SCALER_CENTER or ATOM_SCALER_EXPANSION + UCHAR ucTVStandard; // + UCHAR ucPadding[1]; +}ENABLE_SCALER_PARAMETERS; +#define ENABLE_SCALER_PS_ALLOCATION ENABLE_SCALER_PARAMETERS + +//ucEnable: +#define SCALER_BYPASS_AUTO_CENTER_NO_REPLICATION 0 +#define SCALER_BYPASS_AUTO_CENTER_AUTO_REPLICATION 1 +#define SCALER_ENABLE_2TAP_ALPHA_MODE 2 +#define SCALER_ENABLE_MULTITAP_MODE 3 + +typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS +{ + ULONG usHWIconHorzVertPosn; // Hardware Icon Vertical position + UCHAR ucHWIconVertOffset; // Hardware Icon Vertical offset + UCHAR ucHWIconHorzOffset; // Hardware Icon Horizontal offset + UCHAR ucSelection; // ATOM_CURSOR1 or ATOM_ICON1 or ATOM_CURSOR2 or ATOM_ICON2 + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE +}ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS; + +typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION +{ + ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS sEnableIcon; + ENABLE_CRTC_PARAMETERS sReserved; +}ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION; + +typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS +{ + USHORT usHight; // Image Hight + USHORT usWidth; // Image Width + UCHAR ucSurface; // Surface 1 or 2 + UCHAR ucPadding[3]; +}ENABLE_GRAPH_SURFACE_PARAMETERS; + +typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2 +{ + USHORT usHight; // Image Hight + USHORT usWidth; // Image Width + UCHAR ucSurface; // Surface 1 or 2 + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[2]; +}ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2; + +typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_3 +{ + USHORT usHight; // Image Hight + USHORT usWidth; // Image Width + UCHAR ucSurface; // Surface 1 or 2 + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + USHORT usDeviceId; // Active Device Id for this surface. If no device, set to 0. +}ENABLE_GRAPH_SURFACE_PARAMETERS_V1_3; + +typedef struct _ENABLE_GRAPH_SURFACE_PS_ALLOCATION +{ + ENABLE_GRAPH_SURFACE_PARAMETERS sSetSurface; + ENABLE_YUV_PS_ALLOCATION sReserved; // Don't set this one +}ENABLE_GRAPH_SURFACE_PS_ALLOCATION; + +typedef struct _MEMORY_CLEAN_UP_PARAMETERS +{ + USHORT usMemoryStart; //in 8Kb boundry, offset from memory base address + USHORT usMemorySize; //8Kb blocks aligned +}MEMORY_CLEAN_UP_PARAMETERS; +#define MEMORY_CLEAN_UP_PS_ALLOCATION MEMORY_CLEAN_UP_PARAMETERS + +typedef struct _GET_DISPLAY_SURFACE_SIZE_PARAMETERS +{ + USHORT usX_Size; //When use as input parameter, usX_Size indicates which CRTC + USHORT usY_Size; +}GET_DISPLAY_SURFACE_SIZE_PARAMETERS; + +typedef struct _INDIRECT_IO_ACCESS +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR IOAccessSequence[256]; +} INDIRECT_IO_ACCESS; + +#define INDIRECT_READ 0x00 +#define INDIRECT_WRITE 0x80 + +#define INDIRECT_IO_MM 0 +#define INDIRECT_IO_PLL 1 +#define INDIRECT_IO_MC 2 +#define INDIRECT_IO_PCIE 3 +#define INDIRECT_IO_PCIEP 4 +#define INDIRECT_IO_NBMISC 5 + +#define INDIRECT_IO_PLL_READ INDIRECT_IO_PLL | INDIRECT_READ +#define INDIRECT_IO_PLL_WRITE INDIRECT_IO_PLL | INDIRECT_WRITE +#define INDIRECT_IO_MC_READ INDIRECT_IO_MC | INDIRECT_READ +#define INDIRECT_IO_MC_WRITE INDIRECT_IO_MC | INDIRECT_WRITE +#define INDIRECT_IO_PCIE_READ INDIRECT_IO_PCIE | INDIRECT_READ +#define INDIRECT_IO_PCIE_WRITE INDIRECT_IO_PCIE | INDIRECT_WRITE +#define INDIRECT_IO_PCIEP_READ INDIRECT_IO_PCIEP | INDIRECT_READ +#define INDIRECT_IO_PCIEP_WRITE INDIRECT_IO_PCIEP | INDIRECT_WRITE +#define INDIRECT_IO_NBMISC_READ INDIRECT_IO_NBMISC | INDIRECT_READ +#define INDIRECT_IO_NBMISC_WRITE INDIRECT_IO_NBMISC | INDIRECT_WRITE + +typedef struct _ATOM_OEM_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; +}ATOM_OEM_INFO; + +typedef struct _ATOM_TV_MODE +{ + UCHAR ucVMode_Num; //Video mode number + UCHAR ucTV_Mode_Num; //Internal TV mode number +}ATOM_TV_MODE; + +typedef struct _ATOM_BIOS_INT_TVSTD_MODE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usTV_Mode_LUT_Offset; // Pointer to standard to internal number conversion table + USHORT usTV_FIFO_Offset; // Pointer to FIFO entry table + USHORT usNTSC_Tbl_Offset; // Pointer to SDTV_Mode_NTSC table + USHORT usPAL_Tbl_Offset; // Pointer to SDTV_Mode_PAL table + USHORT usCV_Tbl_Offset; // Pointer to SDTV_Mode_PAL table +}ATOM_BIOS_INT_TVSTD_MODE; + + +typedef struct _ATOM_TV_MODE_SCALER_PTR +{ + USHORT ucFilter0_Offset; //Pointer to filter format 0 coefficients + USHORT usFilter1_Offset; //Pointer to filter format 0 coefficients + UCHAR ucTV_Mode_Num; +}ATOM_TV_MODE_SCALER_PTR; + +typedef struct _ATOM_STANDARD_VESA_TIMING +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_DTD_FORMAT aModeTimings[16]; // 16 is not the real array number, just for initial allocation +}ATOM_STANDARD_VESA_TIMING; + + +typedef struct _ATOM_STD_FORMAT +{ + USHORT usSTD_HDisp; + USHORT usSTD_VDisp; + USHORT usSTD_RefreshRate; + USHORT usReserved; +}ATOM_STD_FORMAT; + +typedef struct _ATOM_VESA_TO_EXTENDED_MODE +{ + USHORT usVESA_ModeNumber; + USHORT usExtendedModeNumber; +}ATOM_VESA_TO_EXTENDED_MODE; + +typedef struct _ATOM_VESA_TO_INTENAL_MODE_LUT +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VESA_TO_EXTENDED_MODE asVESA_ToExtendedModeInfo[76]; +}ATOM_VESA_TO_INTENAL_MODE_LUT; + +/*************** ATOM Memory Related Data Structure ***********************/ +typedef struct _ATOM_MEMORY_VENDOR_BLOCK{ + UCHAR ucMemoryType; + UCHAR ucMemoryVendor; + UCHAR ucAdjMCId; + UCHAR ucDynClkId; + ULONG ulDllResetClkRange; +}ATOM_MEMORY_VENDOR_BLOCK; + + +typedef struct _ATOM_MEMORY_SETTING_ID_CONFIG{ +#if ATOM_BIG_ENDIAN + ULONG ucMemBlkId:8; + ULONG ulMemClockRange:24; +#else + ULONG ulMemClockRange:24; + ULONG ucMemBlkId:8; +#endif +}ATOM_MEMORY_SETTING_ID_CONFIG; + +typedef union _ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS +{ + ATOM_MEMORY_SETTING_ID_CONFIG slAccess; + ULONG ulAccess; +}ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS; + + +typedef struct _ATOM_MEMORY_SETTING_DATA_BLOCK{ + ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS ulMemoryID; + ULONG aulMemData[1]; +}ATOM_MEMORY_SETTING_DATA_BLOCK; + + +typedef struct _ATOM_INIT_REG_INDEX_FORMAT{ + USHORT usRegIndex; // MC register index + UCHAR ucPreRegDataLength; // offset in ATOM_INIT_REG_DATA_BLOCK.saRegDataBuf +}ATOM_INIT_REG_INDEX_FORMAT; + + +typedef struct _ATOM_INIT_REG_BLOCK{ + USHORT usRegIndexTblSize; //size of asRegIndexBuf + USHORT usRegDataBlkSize; //size of ATOM_MEMORY_SETTING_DATA_BLOCK + ATOM_INIT_REG_INDEX_FORMAT asRegIndexBuf[1]; + ATOM_MEMORY_SETTING_DATA_BLOCK asRegDataBuf[1]; +}ATOM_INIT_REG_BLOCK; + +#define END_OF_REG_INDEX_BLOCK 0x0ffff +#define END_OF_REG_DATA_BLOCK 0x00000000 +#define ATOM_INIT_REG_MASK_FLAG 0x80 +#define CLOCK_RANGE_HIGHEST 0x00ffffff + +#define VALUE_DWORD SIZEOF ULONG +#define VALUE_SAME_AS_ABOVE 0 +#define VALUE_MASK_DWORD 0x84 + +#define INDEX_ACCESS_RANGE_BEGIN (VALUE_DWORD + 1) +#define INDEX_ACCESS_RANGE_END (INDEX_ACCESS_RANGE_BEGIN + 1) +#define VALUE_INDEX_ACCESS_SINGLE (INDEX_ACCESS_RANGE_END + 1) + + +typedef struct _ATOM_MC_INIT_PARAM_TABLE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usAdjustARB_SEQDataOffset; + USHORT usMCInitMemTypeTblOffset; + USHORT usMCInitCommonTblOffset; + USHORT usMCInitPowerDownTblOffset; + ULONG ulARB_SEQDataBuf[32]; + ATOM_INIT_REG_BLOCK asMCInitMemType; + ATOM_INIT_REG_BLOCK asMCInitCommon; +}ATOM_MC_INIT_PARAM_TABLE; + + +#define _4Mx16 0x2 +#define _4Mx32 0x3 +#define _8Mx16 0x12 +#define _8Mx32 0x13 +#define _16Mx16 0x22 +#define _16Mx32 0x23 +#define _32Mx16 0x32 +#define _32Mx32 0x33 +#define _64Mx8 0x41 +#define _64Mx16 0x42 + +#define SAMSUNG 0x1 +#define INFINEON 0x2 +#define ELPIDA 0x3 +#define ETRON 0x4 +#define NANYA 0x5 +#define HYNIX 0x6 +#define MOSEL 0x7 +#define WINBOND 0x8 +#define ESMT 0x9 +#define MICRON 0xF + +#define QIMONDA INFINEON +#define PROMOS MOSEL +#define KRETON INFINEON + +/////////////Support for GDDR5 MC uCode to reside in upper 64K of ROM///////////// + +#define UCODE_ROM_START_ADDRESS 0x1c000 +#define UCODE_SIGNATURE 0x4375434d // 'MCuC' - MC uCode + +//uCode block header for reference + +typedef struct _MCuCodeHeader +{ + ULONG ulSignature; + UCHAR ucRevision; + UCHAR ucChecksum; + UCHAR ucReserved1; + UCHAR ucReserved2; + USHORT usParametersLength; + USHORT usUCodeLength; + USHORT usReserved1; + USHORT usReserved2; +} MCuCodeHeader; + +////////////////////////////////////////////////////////////////////////////////// + +#define ATOM_MAX_NUMBER_OF_VRAM_MODULE 16 + +#define ATOM_VRAM_MODULE_MEMORY_VENDOR_ID_MASK 0xF +typedef struct _ATOM_VRAM_MODULE_V1 +{ + ULONG ulReserved; + USHORT usEMRSValue; + USHORT usMRSValue; + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] reserved; + UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender + UCHAR ucMemoryDeviceCfg; // [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32... + UCHAR ucRow; // Number of Row,in power of 2; + UCHAR ucColumn; // Number of Column,in power of 2; + UCHAR ucBank; // Nunber of Bank; + UCHAR ucRank; // Number of Rank, in power of 2 + UCHAR ucChannelNum; // Number of channel; + UCHAR ucChannelConfig; // [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2 + UCHAR ucDefaultMVDDQ_ID; // Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data; + UCHAR ucDefaultMVDDC_ID; // Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data; + UCHAR ucReserved[2]; +}ATOM_VRAM_MODULE_V1; + + +typedef struct _ATOM_VRAM_MODULE_V2 +{ + ULONG ulReserved; + ULONG ulFlags; // To enable/disable functionalities based on memory type + ULONG ulEngineClock; // Override of default engine clock for particular memory type + ULONG ulMemoryClock; // Override of default memory clock for particular memory type + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + USHORT usEMRSValue; + USHORT usMRSValue; + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; + UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed + UCHAR ucMemoryDeviceCfg; // [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32... + UCHAR ucRow; // Number of Row,in power of 2; + UCHAR ucColumn; // Number of Column,in power of 2; + UCHAR ucBank; // Nunber of Bank; + UCHAR ucRank; // Number of Rank, in power of 2 + UCHAR ucChannelNum; // Number of channel; + UCHAR ucChannelConfig; // [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2 + UCHAR ucDefaultMVDDQ_ID; // Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data; + UCHAR ucDefaultMVDDC_ID; // Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data; + UCHAR ucRefreshRateFactor; + UCHAR ucReserved[3]; +}ATOM_VRAM_MODULE_V2; + + +typedef struct _ATOM_MEMORY_TIMING_FORMAT +{ + ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing + union{ + USHORT usMRS; // mode register + USHORT usDDR3_MR0; + }; + union{ + USHORT usEMRS; // extended mode register + USHORT usDDR3_MR1; + }; + UCHAR ucCL; // CAS latency + UCHAR ucWL; // WRITE Latency + UCHAR uctRAS; // tRAS + UCHAR uctRC; // tRC + UCHAR uctRFC; // tRFC + UCHAR uctRCDR; // tRCDR + UCHAR uctRCDW; // tRCDW + UCHAR uctRP; // tRP + UCHAR uctRRD; // tRRD + UCHAR uctWR; // tWR + UCHAR uctWTR; // tWTR + UCHAR uctPDIX; // tPDIX + UCHAR uctFAW; // tFAW + UCHAR uctAOND; // tAOND + union + { + struct { + UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon + UCHAR ucReserved; + }; + USHORT usDDR3_MR2; + }; +}ATOM_MEMORY_TIMING_FORMAT; + + +typedef struct _ATOM_MEMORY_TIMING_FORMAT_V1 +{ + ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing + USHORT usMRS; // mode register + USHORT usEMRS; // extended mode register + UCHAR ucCL; // CAS latency + UCHAR ucWL; // WRITE Latency + UCHAR uctRAS; // tRAS + UCHAR uctRC; // tRC + UCHAR uctRFC; // tRFC + UCHAR uctRCDR; // tRCDR + UCHAR uctRCDW; // tRCDW + UCHAR uctRP; // tRP + UCHAR uctRRD; // tRRD + UCHAR uctWR; // tWR + UCHAR uctWTR; // tWTR + UCHAR uctPDIX; // tPDIX + UCHAR uctFAW; // tFAW + UCHAR uctAOND; // tAOND + UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon +////////////////////////////////////GDDR parameters/////////////////////////////////// + UCHAR uctCCDL; // + UCHAR uctCRCRL; // + UCHAR uctCRCWL; // + UCHAR uctCKE; // + UCHAR uctCKRSE; // + UCHAR uctCKRSX; // + UCHAR uctFAW32; // + UCHAR ucMR5lo; // + UCHAR ucMR5hi; // + UCHAR ucTerminator; +}ATOM_MEMORY_TIMING_FORMAT_V1; + +typedef struct _ATOM_MEMORY_TIMING_FORMAT_V2 +{ + ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing + USHORT usMRS; // mode register + USHORT usEMRS; // extended mode register + UCHAR ucCL; // CAS latency + UCHAR ucWL; // WRITE Latency + UCHAR uctRAS; // tRAS + UCHAR uctRC; // tRC + UCHAR uctRFC; // tRFC + UCHAR uctRCDR; // tRCDR + UCHAR uctRCDW; // tRCDW + UCHAR uctRP; // tRP + UCHAR uctRRD; // tRRD + UCHAR uctWR; // tWR + UCHAR uctWTR; // tWTR + UCHAR uctPDIX; // tPDIX + UCHAR uctFAW; // tFAW + UCHAR uctAOND; // tAOND + UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon +////////////////////////////////////GDDR parameters/////////////////////////////////// + UCHAR uctCCDL; // + UCHAR uctCRCRL; // + UCHAR uctCRCWL; // + UCHAR uctCKE; // + UCHAR uctCKRSE; // + UCHAR uctCKRSX; // + UCHAR uctFAW32; // + UCHAR ucMR4lo; // + UCHAR ucMR4hi; // + UCHAR ucMR5lo; // + UCHAR ucMR5hi; // + UCHAR ucTerminator; + UCHAR ucReserved; +}ATOM_MEMORY_TIMING_FORMAT_V2; + +typedef struct _ATOM_MEMORY_FORMAT +{ + ULONG ulDllDisClock; // memory DLL will be disable when target memory clock is below this clock + union{ + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usDDR3_Reserved; // Not used for DDR3 memory + }; + union{ + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + USHORT usDDR3_MR3; // Used for DDR3 memory + }; + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; + UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed + UCHAR ucRow; // Number of Row,in power of 2; + UCHAR ucColumn; // Number of Column,in power of 2; + UCHAR ucBank; // Nunber of Bank; + UCHAR ucRank; // Number of Rank, in power of 2 + UCHAR ucBurstSize; // burst size, 0= burst size=4 1= burst size=8 + UCHAR ucDllDisBit; // position of DLL Enable/Disable bit in EMRS ( Extended Mode Register ) + UCHAR ucRefreshRateFactor; // memory refresh rate in unit of ms + UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16 + UCHAR ucPreamble; //[7:4] Write Preamble, [3:0] Read Preamble + UCHAR ucMemAttrib; // Memory Device Addribute, like RDBI/WDBI etc + ATOM_MEMORY_TIMING_FORMAT asMemTiming[5]; //Memory Timing block sort from lower clock to higher clock +}ATOM_MEMORY_FORMAT; + + +typedef struct _ATOM_VRAM_MODULE_V3 +{ + ULONG ulChannelMapCfg; // board dependent paramenter:Channel combination + USHORT usSize; // size of ATOM_VRAM_MODULE_V3 + USHORT usDefaultMVDDQ; // board dependent parameter:Default Memory Core Voltage + USHORT usDefaultMVDDC; // board dependent parameter:Default Memory IO Voltage + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucChannelNum; // board dependent parameter:Number of channel; + UCHAR ucChannelSize; // board dependent parameter:32bit or 64bit + UCHAR ucVREFI; // board dependnt parameter: EXT or INT +160mv to -140mv + UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters + UCHAR ucFlag; // To enable/disable functionalities based on memory type + ATOM_MEMORY_FORMAT asMemory; // describ all of video memory parameters from memory spec +}ATOM_VRAM_MODULE_V3; + + +//ATOM_VRAM_MODULE_V3.ucNPL_RT +#define NPL_RT_MASK 0x0f +#define BATTERY_ODT_MASK 0xc0 + +#define ATOM_VRAM_MODULE ATOM_VRAM_MODULE_V3 + +typedef struct _ATOM_VRAM_MODULE_V4 +{ + ULONG ulChannelMapCfg; // board dependent parameter: Channel combination + USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE + USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; + UCHAR ucChannelNum; // Number of channels present in this module config + UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits + UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16 + UCHAR ucFlag; // To enable/disable functionalities based on memory type + UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8 + UCHAR ucVREFI; // board dependent parameter + UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters + UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble + UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros + UCHAR ucReserved[3]; + +//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level + union{ + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usDDR3_Reserved; + }; + union{ + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + USHORT usDDR3_MR3; // Used for DDR3 memory + }; + UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed + UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) + UCHAR ucReserved2[2]; + ATOM_MEMORY_TIMING_FORMAT asMemTiming[5];//Memory Timing block sort from lower clock to higher clock +}ATOM_VRAM_MODULE_V4; + +#define VRAM_MODULE_V4_MISC_RANK_MASK 0x3 +#define VRAM_MODULE_V4_MISC_DUAL_RANK 0x1 +#define VRAM_MODULE_V4_MISC_BL_MASK 0x4 +#define VRAM_MODULE_V4_MISC_BL8 0x4 +#define VRAM_MODULE_V4_MISC_DUAL_CS 0x10 + +typedef struct _ATOM_VRAM_MODULE_V5 +{ + ULONG ulChannelMapCfg; // board dependent parameter: Channel combination + USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE + USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; + UCHAR ucChannelNum; // Number of channels present in this module config + UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits + UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16 + UCHAR ucFlag; // To enable/disable functionalities based on memory type + UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8 + UCHAR ucVREFI; // board dependent parameter + UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters + UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble + UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros + UCHAR ucReserved[3]; + +//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed + UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) + UCHAR ucFIFODepth; // FIFO depth supposes to be detected during vendor detection, but if we dont do vendor detection we have to hardcode FIFO Depth + UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth + ATOM_MEMORY_TIMING_FORMAT_V1 asMemTiming[5];//Memory Timing block sort from lower clock to higher clock +}ATOM_VRAM_MODULE_V5; + +typedef struct _ATOM_VRAM_MODULE_V6 +{ + ULONG ulChannelMapCfg; // board dependent parameter: Channel combination + USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE + USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; + UCHAR ucChannelNum; // Number of channels present in this module config + UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits + UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16 + UCHAR ucFlag; // To enable/disable functionalities based on memory type + UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8 + UCHAR ucVREFI; // board dependent parameter + UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters + UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble + UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros + UCHAR ucReserved[3]; + +//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed + UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) + UCHAR ucFIFODepth; // FIFO depth supposes to be detected during vendor detection, but if we dont do vendor detection we have to hardcode FIFO Depth + UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth + ATOM_MEMORY_TIMING_FORMAT_V2 asMemTiming[5];//Memory Timing block sort from lower clock to higher clock +}ATOM_VRAM_MODULE_V6; + + + +typedef struct _ATOM_VRAM_INFO_V2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucNumOfVRAMModule; + ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule; +}ATOM_VRAM_INFO_V2; + +typedef struct _ATOM_VRAM_INFO_V3 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting + USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting + USHORT usRerseved; + UCHAR aVID_PinsShift[9]; // 8 bit strap maximum+terminator + UCHAR ucNumOfVRAMModule; + ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule; + ATOM_INIT_REG_BLOCK asMemPatch; // for allocation + // ATOM_INIT_REG_BLOCK aMemAdjust; +}ATOM_VRAM_INFO_V3; + +#define ATOM_VRAM_INFO_LAST ATOM_VRAM_INFO_V3 + +typedef struct _ATOM_VRAM_INFO_V4 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting + USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting + USHORT usRerseved; + UCHAR ucMemDQ7_0ByteRemap; // DQ line byte remap, =0: Memory Data line BYTE0, =1: BYTE1, =2: BYTE2, =3: BYTE3 + ULONG ulMemDQ7_0BitRemap; // each DQ line ( 7~0) use 3bits, like: DQ0=Bit[2:0], DQ1:[5:3], ... DQ7:[23:21] + UCHAR ucReservde[4]; + UCHAR ucNumOfVRAMModule; + ATOM_VRAM_MODULE_V4 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule; + ATOM_INIT_REG_BLOCK asMemPatch; // for allocation + // ATOM_INIT_REG_BLOCK aMemAdjust; +}ATOM_VRAM_INFO_V4; + +typedef struct _ATOM_VRAM_GPIO_DETECTION_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR aVID_PinsShift[9]; //8 bit strap maximum+terminator +}ATOM_VRAM_GPIO_DETECTION_INFO; + + +typedef struct _ATOM_MEMORY_TRAINING_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucTrainingLoop; + UCHAR ucReserved[3]; + ATOM_INIT_REG_BLOCK asMemTrainingSetting; +}ATOM_MEMORY_TRAINING_INFO; + + +typedef struct SW_I2C_CNTL_DATA_PARAMETERS +{ + UCHAR ucControl; + UCHAR ucData; + UCHAR ucSatus; + UCHAR ucTemp; +} SW_I2C_CNTL_DATA_PARAMETERS; + +#define SW_I2C_CNTL_DATA_PS_ALLOCATION SW_I2C_CNTL_DATA_PARAMETERS + +typedef struct _SW_I2C_IO_DATA_PARAMETERS +{ + USHORT GPIO_Info; + UCHAR ucAct; + UCHAR ucData; + } SW_I2C_IO_DATA_PARAMETERS; + +#define SW_I2C_IO_DATA_PS_ALLOCATION SW_I2C_IO_DATA_PARAMETERS + +/****************************SW I2C CNTL DEFINITIONS**********************/ +#define SW_I2C_IO_RESET 0 +#define SW_I2C_IO_GET 1 +#define SW_I2C_IO_DRIVE 2 +#define SW_I2C_IO_SET 3 +#define SW_I2C_IO_START 4 + +#define SW_I2C_IO_CLOCK 0 +#define SW_I2C_IO_DATA 0x80 + +#define SW_I2C_IO_ZERO 0 +#define SW_I2C_IO_ONE 0x100 + +#define SW_I2C_CNTL_READ 0 +#define SW_I2C_CNTL_WRITE 1 +#define SW_I2C_CNTL_START 2 +#define SW_I2C_CNTL_STOP 3 +#define SW_I2C_CNTL_OPEN 4 +#define SW_I2C_CNTL_CLOSE 5 +#define SW_I2C_CNTL_WRITE1BIT 6 + +//==============================VESA definition Portion=============================== +#define VESA_OEM_PRODUCT_REV '01.00' +#define VESA_MODE_ATTRIBUTE_MODE_SUPPORT 0xBB //refer to VBE spec p.32, no TTY support +#define VESA_MODE_WIN_ATTRIBUTE 7 +#define VESA_WIN_SIZE 64 + +typedef struct _PTR_32_BIT_STRUCTURE +{ + USHORT Offset16; + USHORT Segment16; +} PTR_32_BIT_STRUCTURE; + +typedef union _PTR_32_BIT_UNION +{ + PTR_32_BIT_STRUCTURE SegmentOffset; + ULONG Ptr32_Bit; +} PTR_32_BIT_UNION; + +typedef struct _VBE_1_2_INFO_BLOCK_UPDATABLE +{ + UCHAR VbeSignature[4]; + USHORT VbeVersion; + PTR_32_BIT_UNION OemStringPtr; + UCHAR Capabilities[4]; + PTR_32_BIT_UNION VideoModePtr; + USHORT TotalMemory; +} VBE_1_2_INFO_BLOCK_UPDATABLE; + + +typedef struct _VBE_2_0_INFO_BLOCK_UPDATABLE +{ + VBE_1_2_INFO_BLOCK_UPDATABLE CommonBlock; + USHORT OemSoftRev; + PTR_32_BIT_UNION OemVendorNamePtr; + PTR_32_BIT_UNION OemProductNamePtr; + PTR_32_BIT_UNION OemProductRevPtr; +} VBE_2_0_INFO_BLOCK_UPDATABLE; + +typedef union _VBE_VERSION_UNION +{ + VBE_2_0_INFO_BLOCK_UPDATABLE VBE_2_0_InfoBlock; + VBE_1_2_INFO_BLOCK_UPDATABLE VBE_1_2_InfoBlock; +} VBE_VERSION_UNION; + +typedef struct _VBE_INFO_BLOCK +{ + VBE_VERSION_UNION UpdatableVBE_Info; + UCHAR Reserved[222]; + UCHAR OemData[256]; +} VBE_INFO_BLOCK; + +typedef struct _VBE_FP_INFO +{ + USHORT HSize; + USHORT VSize; + USHORT FPType; + UCHAR RedBPP; + UCHAR GreenBPP; + UCHAR BlueBPP; + UCHAR ReservedBPP; + ULONG RsvdOffScrnMemSize; + ULONG RsvdOffScrnMEmPtr; + UCHAR Reserved[14]; +} VBE_FP_INFO; + +typedef struct _VESA_MODE_INFO_BLOCK +{ +// Mandatory information for all VBE revisions + USHORT ModeAttributes; // dw ? ; mode attributes + UCHAR WinAAttributes; // db ? ; window A attributes + UCHAR WinBAttributes; // db ? ; window B attributes + USHORT WinGranularity; // dw ? ; window granularity + USHORT WinSize; // dw ? ; window size + USHORT WinASegment; // dw ? ; window A start segment + USHORT WinBSegment; // dw ? ; window B start segment + ULONG WinFuncPtr; // dd ? ; real mode pointer to window function + USHORT BytesPerScanLine;// dw ? ; bytes per scan line + +//; Mandatory information for VBE 1.2 and above + USHORT XResolution; // dw ? ; horizontal resolution in pixels or characters + USHORT YResolution; // dw ? ; vertical resolution in pixels or characters + UCHAR XCharSize; // db ? ; character cell width in pixels + UCHAR YCharSize; // db ? ; character cell height in pixels + UCHAR NumberOfPlanes; // db ? ; number of memory planes + UCHAR BitsPerPixel; // db ? ; bits per pixel + UCHAR NumberOfBanks; // db ? ; number of banks + UCHAR MemoryModel; // db ? ; memory model type + UCHAR BankSize; // db ? ; bank size in KB + UCHAR NumberOfImagePages;// db ? ; number of images + UCHAR ReservedForPageFunction;//db 1 ; reserved for page function + +//; Direct Color fields(required for direct/6 and YUV/7 memory models) + UCHAR RedMaskSize; // db ? ; size of direct color red mask in bits + UCHAR RedFieldPosition; // db ? ; bit position of lsb of red mask + UCHAR GreenMaskSize; // db ? ; size of direct color green mask in bits + UCHAR GreenFieldPosition; // db ? ; bit position of lsb of green mask + UCHAR BlueMaskSize; // db ? ; size of direct color blue mask in bits + UCHAR BlueFieldPosition; // db ? ; bit position of lsb of blue mask + UCHAR RsvdMaskSize; // db ? ; size of direct color reserved mask in bits + UCHAR RsvdFieldPosition; // db ? ; bit position of lsb of reserved mask + UCHAR DirectColorModeInfo;// db ? ; direct color mode attributes + +//; Mandatory information for VBE 2.0 and above + ULONG PhysBasePtr; // dd ? ; physical address for flat memory frame buffer + ULONG Reserved_1; // dd 0 ; reserved - always set to 0 + USHORT Reserved_2; // dw 0 ; reserved - always set to 0 + +//; Mandatory information for VBE 3.0 and above + USHORT LinBytesPerScanLine; // dw ? ; bytes per scan line for linear modes + UCHAR BnkNumberOfImagePages;// db ? ; number of images for banked modes + UCHAR LinNumberOfImagPages; // db ? ; number of images for linear modes + UCHAR LinRedMaskSize; // db ? ; size of direct color red mask(linear modes) + UCHAR LinRedFieldPosition; // db ? ; bit position of lsb of red mask(linear modes) + UCHAR LinGreenMaskSize; // db ? ; size of direct color green mask(linear modes) + UCHAR LinGreenFieldPosition;// db ? ; bit position of lsb of green mask(linear modes) + UCHAR LinBlueMaskSize; // db ? ; size of direct color blue mask(linear modes) + UCHAR LinBlueFieldPosition; // db ? ; bit position of lsb of blue mask(linear modes) + UCHAR LinRsvdMaskSize; // db ? ; size of direct color reserved mask(linear modes) + UCHAR LinRsvdFieldPosition; // db ? ; bit position of lsb of reserved mask(linear modes) + ULONG MaxPixelClock; // dd ? ; maximum pixel clock(in Hz) for graphics mode + UCHAR Reserved; // db 190 dup (0) +} VESA_MODE_INFO_BLOCK; + +// BIOS function CALLS +#define ATOM_BIOS_EXTENDED_FUNCTION_CODE 0xA0 // ATI Extended Function code +#define ATOM_BIOS_FUNCTION_COP_MODE 0x00 +#define ATOM_BIOS_FUNCTION_SHORT_QUERY1 0x04 +#define ATOM_BIOS_FUNCTION_SHORT_QUERY2 0x05 +#define ATOM_BIOS_FUNCTION_SHORT_QUERY3 0x06 +#define ATOM_BIOS_FUNCTION_GET_DDC 0x0B +#define ATOM_BIOS_FUNCTION_ASIC_DSTATE 0x0E +#define ATOM_BIOS_FUNCTION_DEBUG_PLAY 0x0F +#define ATOM_BIOS_FUNCTION_STV_STD 0x16 +#define ATOM_BIOS_FUNCTION_DEVICE_DET 0x17 +#define ATOM_BIOS_FUNCTION_DEVICE_SWITCH 0x18 + +#define ATOM_BIOS_FUNCTION_PANEL_CONTROL 0x82 +#define ATOM_BIOS_FUNCTION_OLD_DEVICE_DET 0x83 +#define ATOM_BIOS_FUNCTION_OLD_DEVICE_SWITCH 0x84 +#define ATOM_BIOS_FUNCTION_HW_ICON 0x8A +#define ATOM_BIOS_FUNCTION_SET_CMOS 0x8B +#define SUB_FUNCTION_UPDATE_DISPLAY_INFO 0x8000 // Sub function 80 +#define SUB_FUNCTION_UPDATE_EXPANSION_INFO 0x8100 // Sub function 80 + +#define ATOM_BIOS_FUNCTION_DISPLAY_INFO 0x8D +#define ATOM_BIOS_FUNCTION_DEVICE_ON_OFF 0x8E +#define ATOM_BIOS_FUNCTION_VIDEO_STATE 0x8F +#define ATOM_SUB_FUNCTION_GET_CRITICAL_STATE 0x0300 // Sub function 03 +#define ATOM_SUB_FUNCTION_GET_LIDSTATE 0x0700 // Sub function 7 +#define ATOM_SUB_FUNCTION_THERMAL_STATE_NOTICE 0x1400 // Notify caller the current thermal state +#define ATOM_SUB_FUNCTION_CRITICAL_STATE_NOTICE 0x8300 // Notify caller the current critical state +#define ATOM_SUB_FUNCTION_SET_LIDSTATE 0x8500 // Sub function 85 +#define ATOM_SUB_FUNCTION_GET_REQ_DISPLAY_FROM_SBIOS_MODE 0x8900// Sub function 89 +#define ATOM_SUB_FUNCTION_INFORM_ADC_SUPPORT 0x9400 // Notify caller that ADC is supported + + +#define ATOM_BIOS_FUNCTION_VESA_DPMS 0x4F10 // Set DPMS +#define ATOM_SUB_FUNCTION_SET_DPMS 0x0001 // BL: Sub function 01 +#define ATOM_SUB_FUNCTION_GET_DPMS 0x0002 // BL: Sub function 02 +#define ATOM_PARAMETER_VESA_DPMS_ON 0x0000 // BH Parameter for DPMS ON. +#define ATOM_PARAMETER_VESA_DPMS_STANDBY 0x0100 // BH Parameter for DPMS STANDBY +#define ATOM_PARAMETER_VESA_DPMS_SUSPEND 0x0200 // BH Parameter for DPMS SUSPEND +#define ATOM_PARAMETER_VESA_DPMS_OFF 0x0400 // BH Parameter for DPMS OFF +#define ATOM_PARAMETER_VESA_DPMS_REDUCE_ON 0x0800 // BH Parameter for DPMS REDUCE ON (NOT SUPPORTED) + +#define ATOM_BIOS_RETURN_CODE_MASK 0x0000FF00L +#define ATOM_BIOS_REG_HIGH_MASK 0x0000FF00L +#define ATOM_BIOS_REG_LOW_MASK 0x000000FFL + +// structure used for VBIOS only + +//DispOutInfoTable +typedef struct _ASIC_TRANSMITTER_INFO +{ + USHORT usTransmitterObjId; + USHORT usSupportDevice; + UCHAR ucTransmitterCmdTblId; + UCHAR ucConfig; + UCHAR ucEncoderID; //available 1st encoder ( default ) + UCHAR ucOptionEncoderID; //available 2nd encoder ( optional ) + UCHAR uc2ndEncoderID; + UCHAR ucReserved; +}ASIC_TRANSMITTER_INFO; + +typedef struct _ASIC_ENCODER_INFO +{ + UCHAR ucEncoderID; + UCHAR ucEncoderConfig; + USHORT usEncoderCmdTblId; +}ASIC_ENCODER_INFO; + +typedef struct _ATOM_DISP_OUT_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT ptrTransmitterInfo; + USHORT ptrEncoderInfo; + ASIC_TRANSMITTER_INFO asTransmitterInfo[1]; + ASIC_ENCODER_INFO asEncoderInfo[1]; +}ATOM_DISP_OUT_INFO; + +typedef struct _ATOM_DISP_OUT_INFO_V2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT ptrTransmitterInfo; + USHORT ptrEncoderInfo; + USHORT ptrMainCallParserFar; // direct address of main parser call in VBIOS binary. + ASIC_TRANSMITTER_INFO asTransmitterInfo[1]; + ASIC_ENCODER_INFO asEncoderInfo[1]; +}ATOM_DISP_OUT_INFO_V2; + +// DispDevicePriorityInfo +typedef struct _ATOM_DISPLAY_DEVICE_PRIORITY_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT asDevicePriority[16]; +}ATOM_DISPLAY_DEVICE_PRIORITY_INFO; + +//ProcessAuxChannelTransactionTable +typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS +{ + USHORT lpAuxRequest; + USHORT lpDataOut; + UCHAR ucChannelID; + union + { + UCHAR ucReplyStatus; + UCHAR ucDelay; + }; + UCHAR ucDataOutLen; + UCHAR ucReserved; +}PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS; + +//ProcessAuxChannelTransactionTable +typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 +{ + USHORT lpAuxRequest; + USHORT lpDataOut; + UCHAR ucChannelID; + union + { + UCHAR ucReplyStatus; + UCHAR ucDelay; + }; + UCHAR ucDataOutLen; + UCHAR ucHPD_ID; //=0: HPD1, =1: HPD2, =2: HPD3, =3: HPD4, =4: HPD5, =5: HPD6 +}PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2; + +#define PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS + +//GetSinkType + +typedef struct _DP_ENCODER_SERVICE_PARAMETERS +{ + USHORT ucLinkClock; + union + { + UCHAR ucConfig; // for DP training command + UCHAR ucI2cId; // use for GET_SINK_TYPE command + }; + UCHAR ucAction; + UCHAR ucStatus; + UCHAR ucLaneNum; + UCHAR ucReserved[2]; +}DP_ENCODER_SERVICE_PARAMETERS; + +// ucAction +#define ATOM_DP_ACTION_GET_SINK_TYPE 0x01 +/* obselete */ +#define ATOM_DP_ACTION_TRAINING_START 0x02 +#define ATOM_DP_ACTION_TRAINING_COMPLETE 0x03 +#define ATOM_DP_ACTION_TRAINING_PATTERN_SEL 0x04 +#define ATOM_DP_ACTION_SET_VSWING_PREEMP 0x05 +#define ATOM_DP_ACTION_GET_VSWING_PREEMP 0x06 +#define ATOM_DP_ACTION_BLANKING 0x07 + +// ucConfig +#define ATOM_DP_CONFIG_ENCODER_SEL_MASK 0x03 +#define ATOM_DP_CONFIG_DIG1_ENCODER 0x00 +#define ATOM_DP_CONFIG_DIG2_ENCODER 0x01 +#define ATOM_DP_CONFIG_EXTERNAL_ENCODER 0x02 +#define ATOM_DP_CONFIG_LINK_SEL_MASK 0x04 +#define ATOM_DP_CONFIG_LINK_A 0x00 +#define ATOM_DP_CONFIG_LINK_B 0x04 +/* /obselete */ +#define DP_ENCODER_SERVICE_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +// DP_TRAINING_TABLE +#define DPCD_SET_LINKRATE_LANENUM_PATTERN1_TBL_ADDR ATOM_DP_TRAINING_TBL_ADDR +#define DPCD_SET_SS_CNTL_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 8 ) +#define DPCD_SET_LANE_VSWING_PREEMP_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 16 ) +#define DPCD_SET_TRAINING_PATTERN0_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 24 ) +#define DPCD_SET_TRAINING_PATTERN2_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 32) +#define DPCD_GET_LINKRATE_LANENUM_SS_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 40) +#define DPCD_GET_LANE_STATUS_ADJUST_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 48) +#define DP_I2C_AUX_DDC_WRITE_START_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 60) +#define DP_I2C_AUX_DDC_WRITE_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 64) +#define DP_I2C_AUX_DDC_READ_START_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 72) +#define DP_I2C_AUX_DDC_READ_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 76) +#define DP_I2C_AUX_DDC_WRITE_END_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 80) +#define DP_I2C_AUX_DDC_READ_END_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 84) + +typedef struct _PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS +{ + UCHAR ucI2CSpeed; + union + { + UCHAR ucRegIndex; + UCHAR ucStatus; + }; + USHORT lpI2CDataOut; + UCHAR ucFlag; + UCHAR ucTransBytes; + UCHAR ucSlaveAddr; + UCHAR ucLineNumber; +}PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS; + +#define PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS + +//ucFlag +#define HW_I2C_WRITE 1 +#define HW_I2C_READ 0 +#define I2C_2BYTE_ADDR 0x02 + +typedef struct _SET_HWBLOCK_INSTANCE_PARAMETER_V2 +{ + UCHAR ucHWBlkInst; // HW block instance, 0, 1, 2, ... + UCHAR ucReserved[3]; +}SET_HWBLOCK_INSTANCE_PARAMETER_V2; + +#define HWBLKINST_INSTANCE_MASK 0x07 +#define HWBLKINST_HWBLK_MASK 0xF0 +#define HWBLKINST_HWBLK_SHIFT 0x04 + +//ucHWBlock +#define SELECT_DISP_ENGINE 0 +#define SELECT_DISP_PLL 1 +#define SELECT_DCIO_UNIPHY_LINK0 2 +#define SELECT_DCIO_UNIPHY_LINK1 3 +#define SELECT_DCIO_IMPCAL 4 +#define SELECT_DCIO_DIG 6 +#define SELECT_CRTC_PIXEL_RATE 7 + +/****************************************************************************/ +//Portion VI: Definitinos for vbios MC scratch registers that driver used +/****************************************************************************/ + +#define MC_MISC0__MEMORY_TYPE_MASK 0xF0000000 +#define MC_MISC0__MEMORY_TYPE__GDDR1 0x10000000 +#define MC_MISC0__MEMORY_TYPE__DDR2 0x20000000 +#define MC_MISC0__MEMORY_TYPE__GDDR3 0x30000000 +#define MC_MISC0__MEMORY_TYPE__GDDR4 0x40000000 +#define MC_MISC0__MEMORY_TYPE__GDDR5 0x50000000 +#define MC_MISC0__MEMORY_TYPE__DDR3 0xB0000000 + +/****************************************************************************/ +//Portion VI: Definitinos being oboselete +/****************************************************************************/ + +//========================================================================================== +//Remove the definitions below when driver is ready! +typedef struct _ATOM_DAC_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMaxFrequency; // in 10kHz unit + USHORT usReserved; +}ATOM_DAC_INFO; + + +typedef struct _COMPASSIONATE_DATA +{ + ATOM_COMMON_TABLE_HEADER sHeader; + + //============================== DAC1 portion + UCHAR ucDAC1_BG_Adjustment; + UCHAR ucDAC1_DAC_Adjustment; + USHORT usDAC1_FORCE_Data; + //============================== DAC2 portion + UCHAR ucDAC2_CRT2_BG_Adjustment; + UCHAR ucDAC2_CRT2_DAC_Adjustment; + USHORT usDAC2_CRT2_FORCE_Data; + USHORT usDAC2_CRT2_MUX_RegisterIndex; + UCHAR ucDAC2_CRT2_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low + UCHAR ucDAC2_NTSC_BG_Adjustment; + UCHAR ucDAC2_NTSC_DAC_Adjustment; + USHORT usDAC2_TV1_FORCE_Data; + USHORT usDAC2_TV1_MUX_RegisterIndex; + UCHAR ucDAC2_TV1_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low + UCHAR ucDAC2_CV_BG_Adjustment; + UCHAR ucDAC2_CV_DAC_Adjustment; + USHORT usDAC2_CV_FORCE_Data; + USHORT usDAC2_CV_MUX_RegisterIndex; + UCHAR ucDAC2_CV_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low + UCHAR ucDAC2_PAL_BG_Adjustment; + UCHAR ucDAC2_PAL_DAC_Adjustment; + USHORT usDAC2_TV2_FORCE_Data; +}COMPASSIONATE_DATA; + +/****************************Supported Device Info Table Definitions**********************/ +// ucConnectInfo: +// [7:4] - connector type +// = 1 - VGA connector +// = 2 - DVI-I +// = 3 - DVI-D +// = 4 - DVI-A +// = 5 - SVIDEO +// = 6 - COMPOSITE +// = 7 - LVDS +// = 8 - DIGITAL LINK +// = 9 - SCART +// = 0xA - HDMI_type A +// = 0xB - HDMI_type B +// = 0xE - Special case1 (DVI+DIN) +// Others=TBD +// [3:0] - DAC Associated +// = 0 - no DAC +// = 1 - DACA +// = 2 - DACB +// = 3 - External DAC +// Others=TBD +// + +typedef struct _ATOM_CONNECTOR_INFO +{ +#if ATOM_BIG_ENDIAN + UCHAR bfConnectorType:4; + UCHAR bfAssociatedDAC:4; +#else + UCHAR bfAssociatedDAC:4; + UCHAR bfConnectorType:4; +#endif +}ATOM_CONNECTOR_INFO; + +typedef union _ATOM_CONNECTOR_INFO_ACCESS +{ + ATOM_CONNECTOR_INFO sbfAccess; + UCHAR ucAccess; +}ATOM_CONNECTOR_INFO_ACCESS; + +typedef struct _ATOM_CONNECTOR_INFO_I2C +{ + ATOM_CONNECTOR_INFO_ACCESS sucConnectorInfo; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; +}ATOM_CONNECTOR_INFO_I2C; + + +typedef struct _ATOM_SUPPORTED_DEVICES_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO]; +}ATOM_SUPPORTED_DEVICES_INFO; + +#define NO_INT_SRC_MAPPED 0xFF + +typedef struct _ATOM_CONNECTOR_INC_SRC_BITMAP +{ + UCHAR ucIntSrcBitmap; +}ATOM_CONNECTOR_INC_SRC_BITMAP; + +typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2]; + ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2]; +}ATOM_SUPPORTED_DEVICES_INFO_2; + +typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE]; + ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE]; +}ATOM_SUPPORTED_DEVICES_INFO_2d1; + +#define ATOM_SUPPORTED_DEVICES_INFO_LAST ATOM_SUPPORTED_DEVICES_INFO_2d1 + + + +typedef struct _ATOM_MISC_CONTROL_INFO +{ + USHORT usFrequency; + UCHAR ucPLL_ChargePump; // PLL charge-pump gain control + UCHAR ucPLL_DutyCycle; // PLL duty cycle control + UCHAR ucPLL_VCO_Gain; // PLL VCO gain control + UCHAR ucPLL_VoltageSwing; // PLL driver voltage swing control +}ATOM_MISC_CONTROL_INFO; + + +#define ATOM_MAX_MISC_INFO 4 + +typedef struct _ATOM_TMDS_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMaxFrequency; // in 10Khz + ATOM_MISC_CONTROL_INFO asMiscInfo[ATOM_MAX_MISC_INFO]; +}ATOM_TMDS_INFO; + + +typedef struct _ATOM_ENCODER_ANALOG_ATTRIBUTE +{ + UCHAR ucTVStandard; //Same as TV standards defined above, + UCHAR ucPadding[1]; +}ATOM_ENCODER_ANALOG_ATTRIBUTE; + +typedef struct _ATOM_ENCODER_DIGITAL_ATTRIBUTE +{ + UCHAR ucAttribute; //Same as other digital encoder attributes defined above + UCHAR ucPadding[1]; +}ATOM_ENCODER_DIGITAL_ATTRIBUTE; + +typedef union _ATOM_ENCODER_ATTRIBUTE +{ + ATOM_ENCODER_ANALOG_ATTRIBUTE sAlgAttrib; + ATOM_ENCODER_DIGITAL_ATTRIBUTE sDigAttrib; +}ATOM_ENCODER_ATTRIBUTE; + + +typedef struct _DVO_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; + USHORT usEncoderID; + UCHAR ucDeviceType; //Use ATOM_DEVICE_xxx1_Index to indicate device type only. + UCHAR ucAction; //ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT + ATOM_ENCODER_ATTRIBUTE usDevAttr; +}DVO_ENCODER_CONTROL_PARAMETERS; + +typedef struct _DVO_ENCODER_CONTROL_PS_ALLOCATION +{ + DVO_ENCODER_CONTROL_PARAMETERS sDVOEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion +}DVO_ENCODER_CONTROL_PS_ALLOCATION; + + +#define ATOM_XTMDS_ASIC_SI164_ID 1 +#define ATOM_XTMDS_ASIC_SI178_ID 2 +#define ATOM_XTMDS_ASIC_TFP513_ID 3 +#define ATOM_XTMDS_SUPPORTED_SINGLELINK 0x00000001 +#define ATOM_XTMDS_SUPPORTED_DUALLINK 0x00000002 +#define ATOM_XTMDS_MVPU_FPGA 0x00000004 + + +typedef struct _ATOM_XTMDS_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usSingleLinkMaxFrequency; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; //Point the ID on which I2C is used to control external chip + UCHAR ucXtransimitterID; + UCHAR ucSupportedLink; // Bit field, bit0=1, single link supported;bit1=1,dual link supported + UCHAR ucSequnceAlterID; // Even with the same external TMDS asic, it's possible that the program seqence alters + // due to design. This ID is used to alert driver that the sequence is not "standard"! + UCHAR ucMasterAddress; // Address to control Master xTMDS Chip + UCHAR ucSlaveAddress; // Address to control Slave xTMDS Chip +}ATOM_XTMDS_INFO; + +typedef struct _DFP_DPMS_STATUS_CHANGE_PARAMETERS +{ + UCHAR ucEnable; // ATOM_ENABLE=On or ATOM_DISABLE=Off + UCHAR ucDevice; // ATOM_DEVICE_DFP1_INDEX.... + UCHAR ucPadding[2]; +}DFP_DPMS_STATUS_CHANGE_PARAMETERS; + +/****************************Legacy Power Play Table Definitions **********************/ + +//Definitions for ulPowerPlayMiscInfo +#define ATOM_PM_MISCINFO_SPLIT_CLOCK 0x00000000L +#define ATOM_PM_MISCINFO_USING_MCLK_SRC 0x00000001L +#define ATOM_PM_MISCINFO_USING_SCLK_SRC 0x00000002L + +#define ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT 0x00000004L +#define ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH 0x00000008L + +#define ATOM_PM_MISCINFO_LOAD_PERFORMANCE_EN 0x00000010L + +#define ATOM_PM_MISCINFO_ENGINE_CLOCK_CONTRL_EN 0x00000020L +#define ATOM_PM_MISCINFO_MEMORY_CLOCK_CONTRL_EN 0x00000040L +#define ATOM_PM_MISCINFO_PROGRAM_VOLTAGE 0x00000080L //When this bit set, ucVoltageDropIndex is not an index for GPIO pin, but a voltage ID that SW needs program + +#define ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN 0x00000100L +#define ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN 0x00000200L +#define ATOM_PM_MISCINFO_ASIC_SLEEP_MODE_EN 0x00000400L +#define ATOM_PM_MISCINFO_LOAD_BALANCE_EN 0x00000800L +#define ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE 0x00001000L +#define ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE 0x00002000L +#define ATOM_PM_MISCINFO_LOW_LCD_REFRESH_RATE 0x00004000L + +#define ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE 0x00008000L +#define ATOM_PM_MISCINFO_OVER_CLOCK_MODE 0x00010000L +#define ATOM_PM_MISCINFO_OVER_DRIVE_MODE 0x00020000L +#define ATOM_PM_MISCINFO_POWER_SAVING_MODE 0x00040000L +#define ATOM_PM_MISCINFO_THERMAL_DIODE_MODE 0x00080000L + +#define ATOM_PM_MISCINFO_FRAME_MODULATION_MASK 0x00300000L //0-FM Disable, 1-2 level FM, 2-4 level FM, 3-Reserved +#define ATOM_PM_MISCINFO_FRAME_MODULATION_SHIFT 20 + +#define ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE 0x00400000L +#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2 0x00800000L +#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4 0x01000000L +#define ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN 0x02000000L //When set, Dynamic +#define ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN 0x04000000L //When set, Dynamic +#define ATOM_PM_MISCINFO_3D_ACCELERATION_EN 0x08000000L //When set, This mode is for acceleated 3D mode + +#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_MASK 0x70000000L //1-Optimal Battery Life Group, 2-High Battery, 3-Balanced, 4-High Performance, 5- Optimal Performance (Default state with Default clocks) +#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_SHIFT 28 +#define ATOM_PM_MISCINFO_ENABLE_BACK_BIAS 0x80000000L + +#define ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE 0x00000001L +#define ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT 0x00000002L +#define ATOM_PM_MISCINFO2_DYNAMIC_BACK_BIAS_EN 0x00000004L +#define ATOM_PM_MISCINFO2_FS3D_OVERDRIVE_INFO 0x00000008L +#define ATOM_PM_MISCINFO2_FORCEDLOWPWR_MODE 0x00000010L +#define ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN 0x00000020L +#define ATOM_PM_MISCINFO2_VIDEO_PLAYBACK_CAPABLE 0x00000040L //If this bit is set in multi-pp mode, then driver will pack up one with the minior power consumption. + //If it's not set in any pp mode, driver will use its default logic to pick a pp mode in video playback +#define ATOM_PM_MISCINFO2_NOT_VALID_ON_DC 0x00000080L +#define ATOM_PM_MISCINFO2_STUTTER_MODE_EN 0x00000100L +#define ATOM_PM_MISCINFO2_UVD_SUPPORT_MODE 0x00000200L + +//ucTableFormatRevision=1 +//ucTableContentRevision=1 +typedef struct _ATOM_POWERMODE_INFO +{ + ULONG ulMiscInfo; //The power level should be arranged in ascending order + ULONG ulReserved1; // must set to 0 + ULONG ulReserved2; // must set to 0 + USHORT usEngineClock; + USHORT usMemoryClock; + UCHAR ucVoltageDropIndex; // index to GPIO table + UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucNumPciELanes; // number of PCIE lanes +}ATOM_POWERMODE_INFO; + +//ucTableFormatRevision=2 +//ucTableContentRevision=1 +typedef struct _ATOM_POWERMODE_INFO_V2 +{ + ULONG ulMiscInfo; //The power level should be arranged in ascending order + ULONG ulMiscInfo2; + ULONG ulEngineClock; + ULONG ulMemoryClock; + UCHAR ucVoltageDropIndex; // index to GPIO table + UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucNumPciELanes; // number of PCIE lanes +}ATOM_POWERMODE_INFO_V2; + +//ucTableFormatRevision=2 +//ucTableContentRevision=2 +typedef struct _ATOM_POWERMODE_INFO_V3 +{ + ULONG ulMiscInfo; //The power level should be arranged in ascending order + ULONG ulMiscInfo2; + ULONG ulEngineClock; + ULONG ulMemoryClock; + UCHAR ucVoltageDropIndex; // index to Core (VDDC) votage table + UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucNumPciELanes; // number of PCIE lanes + UCHAR ucVDDCI_VoltageDropIndex; // index to VDDCI votage table +}ATOM_POWERMODE_INFO_V3; + + +#define ATOM_MAX_NUMBEROF_POWER_BLOCK 8 + +#define ATOM_PP_OVERDRIVE_INTBITMAP_AUXWIN 0x01 +#define ATOM_PP_OVERDRIVE_INTBITMAP_OVERDRIVE 0x02 + +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM63 0x01 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ADM1032 0x02 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ADM1030 0x03 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_MUA6649 0x04 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM64 0x05 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_F75375 0x06 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ASC7512 0x07 // Andigilog + + +typedef struct _ATOM_POWERPLAY_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucOverdriveThermalController; + UCHAR ucOverdriveI2cLine; + UCHAR ucOverdriveIntBitmap; + UCHAR ucOverdriveControllerAddress; + UCHAR ucSizeOfPowerModeEntry; + UCHAR ucNumOfPowerModeEntries; + ATOM_POWERMODE_INFO asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; +}ATOM_POWERPLAY_INFO; + +typedef struct _ATOM_POWERPLAY_INFO_V2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucOverdriveThermalController; + UCHAR ucOverdriveI2cLine; + UCHAR ucOverdriveIntBitmap; + UCHAR ucOverdriveControllerAddress; + UCHAR ucSizeOfPowerModeEntry; + UCHAR ucNumOfPowerModeEntries; + ATOM_POWERMODE_INFO_V2 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; +}ATOM_POWERPLAY_INFO_V2; + +typedef struct _ATOM_POWERPLAY_INFO_V3 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucOverdriveThermalController; + UCHAR ucOverdriveI2cLine; + UCHAR ucOverdriveIntBitmap; + UCHAR ucOverdriveControllerAddress; + UCHAR ucSizeOfPowerModeEntry; + UCHAR ucNumOfPowerModeEntries; + ATOM_POWERMODE_INFO_V3 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; +}ATOM_POWERPLAY_INFO_V3; + +/* New PPlib */ +/**************************************************************************/ +typedef struct _ATOM_PPLIB_THERMALCONTROLLER + +{ + UCHAR ucType; // one of ATOM_PP_THERMALCONTROLLER_* + UCHAR ucI2cLine; // as interpreted by DAL I2C + UCHAR ucI2cAddress; + UCHAR ucFanParameters; // Fan Control Parameters. + UCHAR ucFanMinRPM; // Fan Minimum RPM (hundreds) -- for display purposes only. + UCHAR ucFanMaxRPM; // Fan Maximum RPM (hundreds) -- for display purposes only. + UCHAR ucReserved; // ---- + UCHAR ucFlags; // to be defined +} ATOM_PPLIB_THERMALCONTROLLER; + +#define ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK 0x0f +#define ATOM_PP_FANPARAMETERS_NOFAN 0x80 // No fan is connected to this controller. + +#define ATOM_PP_THERMALCONTROLLER_NONE 0 +#define ATOM_PP_THERMALCONTROLLER_LM63 1 // Not used by PPLib +#define ATOM_PP_THERMALCONTROLLER_ADM1032 2 // Not used by PPLib +#define ATOM_PP_THERMALCONTROLLER_ADM1030 3 // Not used by PPLib +#define ATOM_PP_THERMALCONTROLLER_MUA6649 4 // Not used by PPLib +#define ATOM_PP_THERMALCONTROLLER_LM64 5 +#define ATOM_PP_THERMALCONTROLLER_F75375 6 // Not used by PPLib +#define ATOM_PP_THERMALCONTROLLER_RV6xx 7 +#define ATOM_PP_THERMALCONTROLLER_RV770 8 +#define ATOM_PP_THERMALCONTROLLER_ADT7473 9 +#define ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO 11 +#define ATOM_PP_THERMALCONTROLLER_EVERGREEN 12 +#define ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL 0x89 // ADT7473 Fan Control + Internal Thermal Controller + +typedef struct _ATOM_PPLIB_STATE +{ + UCHAR ucNonClockStateIndex; + UCHAR ucClockStateIndices[1]; // variable-sized +} ATOM_PPLIB_STATE; + +typedef struct _ATOM_PPLIB_FANTABLE +{ + UCHAR ucFanTableFormat; // Change this if the table format changes or version changes so that the other fields are not the same. + UCHAR ucTHyst; // Temperature hysteresis. Integer. + USHORT usTMin; // The temperature, in 0.01 centigrades, below which we just run at a minimal PWM. + USHORT usTMed; // The middle temperature where we change slopes. + USHORT usTHigh; // The high point above TMed for adjusting the second slope. + USHORT usPWMMin; // The minimum PWM value in percent (0.01% increments). + USHORT usPWMMed; // The PWM value (in percent) at TMed. + USHORT usPWMHigh; // The PWM value at THigh. +} ATOM_PPLIB_FANTABLE; + +typedef struct _ATOM_PPLIB_EXTENDEDHEADER +{ + USHORT usSize; + ULONG ulMaxEngineClock; // For Overdrive. + ULONG ulMaxMemoryClock; // For Overdrive. + // Add extra system parameters here, always adjust size to include all fields. +} ATOM_PPLIB_EXTENDEDHEADER; + +//// ATOM_PPLIB_POWERPLAYTABLE::ulPlatformCaps +#define ATOM_PP_PLATFORM_CAP_BACKBIAS 1 +#define ATOM_PP_PLATFORM_CAP_POWERPLAY 2 +#define ATOM_PP_PLATFORM_CAP_SBIOSPOWERSOURCE 4 +#define ATOM_PP_PLATFORM_CAP_ASPM_L0s 8 +#define ATOM_PP_PLATFORM_CAP_ASPM_L1 16 +#define ATOM_PP_PLATFORM_CAP_HARDWAREDC 32 +#define ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY 64 +#define ATOM_PP_PLATFORM_CAP_STEPVDDC 128 +#define ATOM_PP_PLATFORM_CAP_VOLTAGECONTROL 256 +#define ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL 512 +#define ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 1024 +#define ATOM_PP_PLATFORM_CAP_HTLINKCONTROL 2048 +#define ATOM_PP_PLATFORM_CAP_MVDDCONTROL 4096 +#define ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT 0x2000 // Go to boot state on alerts, e.g. on an AC->DC transition. +#define ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT 0x4000 // Do NOT wait for VBLANK during an alert (e.g. AC->DC transition). +#define ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL 0x8000 // Does the driver control VDDCI independently from VDDC. +#define ATOM_PP_PLATFORM_CAP_REGULATOR_HOT 0x00010000 // Enable the 'regulator hot' feature. +#define ATOM_PP_PLATFORM_CAP_BACO 0x00020000 // Does the driver supports BACO state. + +typedef struct _ATOM_PPLIB_POWERPLAYTABLE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + + UCHAR ucDataRevision; + + UCHAR ucNumStates; + UCHAR ucStateEntrySize; + UCHAR ucClockInfoSize; + UCHAR ucNonClockSize; + + // offset from start of this table to array of ucNumStates ATOM_PPLIB_STATE structures + USHORT usStateArrayOffset; + + // offset from start of this table to array of ASIC-specific structures, + // currently ATOM_PPLIB_CLOCK_INFO. + USHORT usClockInfoArrayOffset; + + // offset from start of this table to array of ATOM_PPLIB_NONCLOCK_INFO + USHORT usNonClockInfoArrayOffset; + + USHORT usBackbiasTime; // in microseconds + USHORT usVoltageTime; // in microseconds + USHORT usTableSize; //the size of this structure, or the extended structure + + ULONG ulPlatformCaps; // See ATOM_PPLIB_CAPS_* + + ATOM_PPLIB_THERMALCONTROLLER sThermalController; + + USHORT usBootClockInfoOffset; + USHORT usBootNonClockInfoOffset; + +} ATOM_PPLIB_POWERPLAYTABLE; + +typedef struct _ATOM_PPLIB_POWERPLAYTABLE2 +{ + ATOM_PPLIB_POWERPLAYTABLE basicTable; + UCHAR ucNumCustomThermalPolicy; + USHORT usCustomThermalPolicyArrayOffset; +}ATOM_PPLIB_POWERPLAYTABLE2, *LPATOM_PPLIB_POWERPLAYTABLE2; + +typedef struct _ATOM_PPLIB_POWERPLAYTABLE3 +{ + ATOM_PPLIB_POWERPLAYTABLE2 basicTable2; + USHORT usFormatID; // To be used ONLY by PPGen. + USHORT usFanTableOffset; + USHORT usExtendendedHeaderOffset; +} ATOM_PPLIB_POWERPLAYTABLE3, *LPATOM_PPLIB_POWERPLAYTABLE3; + +//// ATOM_PPLIB_NONCLOCK_INFO::usClassification +#define ATOM_PPLIB_CLASSIFICATION_UI_MASK 0x0007 +#define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT 0 +#define ATOM_PPLIB_CLASSIFICATION_UI_NONE 0 +#define ATOM_PPLIB_CLASSIFICATION_UI_BATTERY 1 +#define ATOM_PPLIB_CLASSIFICATION_UI_BALANCED 3 +#define ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE 5 +// 2, 4, 6, 7 are reserved + +#define ATOM_PPLIB_CLASSIFICATION_BOOT 0x0008 +#define ATOM_PPLIB_CLASSIFICATION_THERMAL 0x0010 +#define ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE 0x0020 +#define ATOM_PPLIB_CLASSIFICATION_REST 0x0040 +#define ATOM_PPLIB_CLASSIFICATION_FORCED 0x0080 +#define ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE 0x0100 +#define ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE 0x0200 +#define ATOM_PPLIB_CLASSIFICATION_UVDSTATE 0x0400 +#define ATOM_PPLIB_CLASSIFICATION_3DLOW 0x0800 +#define ATOM_PPLIB_CLASSIFICATION_ACPI 0x1000 +#define ATOM_PPLIB_CLASSIFICATION_HD2STATE 0x2000 +#define ATOM_PPLIB_CLASSIFICATION_HDSTATE 0x4000 +#define ATOM_PPLIB_CLASSIFICATION_SDSTATE 0x8000 + +//// ATOM_PPLIB_NONCLOCK_INFO::ulCapsAndSettings +#define ATOM_PPLIB_SINGLE_DISPLAY_ONLY 0x00000001 +#define ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK 0x00000002 + +// 0 is 2.5Gb/s, 1 is 5Gb/s +#define ATOM_PPLIB_PCIE_LINK_SPEED_MASK 0x00000004 +#define ATOM_PPLIB_PCIE_LINK_SPEED_SHIFT 2 + +// lanes - 1: 1, 2, 4, 8, 12, 16 permitted by PCIE spec +#define ATOM_PPLIB_PCIE_LINK_WIDTH_MASK 0x000000F8 +#define ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT 3 + +// lookup into reduced refresh-rate table +#define ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK 0x00000F00 +#define ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT 8 + +#define ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED 0 +#define ATOM_PPLIB_LIMITED_REFRESHRATE_50HZ 1 +// 2-15 TBD as needed. + +#define ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING 0x00001000 +#define ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS 0x00002000 +#define ATOM_PPLIB_DISALLOW_ON_DC 0x00004000 +#define ATOM_PPLIB_ENABLE_VARIBRIGHT 0x00008000 + +//memory related flags +#define ATOM_PPLIB_SWSTATE_MEMORY_DLL_OFF 0x000010000 + +//M3 Arb //2bits, current 3 sets of parameters in total +#define ATOM_PPLIB_M3ARB_MASK 0x00060000 +#define ATOM_PPLIB_M3ARB_SHIFT 17 + +// Contained in an array starting at the offset +// in ATOM_PPLIB_POWERPLAYTABLE::usNonClockInfoArrayOffset. +// referenced from ATOM_PPLIB_STATE_INFO::ucNonClockStateIndex +typedef struct _ATOM_PPLIB_NONCLOCK_INFO +{ + USHORT usClassification; + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + ULONG ulCapsAndSettings; + UCHAR ucRequiredPower; + UCHAR ucUnused1[3]; +} ATOM_PPLIB_NONCLOCK_INFO; + +// Contained in an array starting at the offset +// in ATOM_PPLIB_POWERPLAYTABLE::usClockInfoArrayOffset. +// referenced from ATOM_PPLIB_STATE::ucClockStateIndices +#define ATOM_PPLIB_NONCLOCKINFO_VER1 12 +#define ATOM_PPLIB_NONCLOCKINFO_VER2 24 + +typedef struct _ATOM_PPLIB_R600_CLOCK_INFO +{ + USHORT usEngineClockLow; + UCHAR ucEngineClockHigh; + + USHORT usMemoryClockLow; + UCHAR ucMemoryClockHigh; + + USHORT usVDDC; + USHORT usUnused1; + USHORT usUnused2; + + ULONG ulFlags; // ATOM_PPLIB_R600_FLAGS_* + +} ATOM_PPLIB_R600_CLOCK_INFO; + +// ulFlags in ATOM_PPLIB_R600_CLOCK_INFO +#define ATOM_PPLIB_R600_FLAGS_PCIEGEN2 1 +#define ATOM_PPLIB_R600_FLAGS_UVDSAFE 2 +#define ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE 4 +#define ATOM_PPLIB_R600_FLAGS_MEMORY_ODT_OFF 8 +#define ATOM_PPLIB_R600_FLAGS_MEMORY_DLL_OFF 16 +#define ATOM_PPLIB_R600_FLAGS_LOWPOWER 32 // On the RV770 use 'low power' setting (sequencer S0). + +typedef struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO +{ + USHORT usEngineClockLow; + UCHAR ucEngineClockHigh; + + USHORT usMemoryClockLow; + UCHAR ucMemoryClockHigh; + + USHORT usVDDC; + USHORT usVDDCI; + USHORT usUnused; + + ULONG ulFlags; // ATOM_PPLIB_R600_FLAGS_* + +} ATOM_PPLIB_EVERGREEN_CLOCK_INFO; + +typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO + +{ + USHORT usLowEngineClockLow; // Low Engine clock in MHz (the same way as on the R600). + UCHAR ucLowEngineClockHigh; + USHORT usHighEngineClockLow; // High Engine clock in MHz. + UCHAR ucHighEngineClockHigh; + USHORT usMemoryClockLow; // For now one of the ATOM_PPLIB_RS780_SPMCLK_XXXX constants. + UCHAR ucMemoryClockHigh; // Currentyl unused. + UCHAR ucPadding; // For proper alignment and size. + USHORT usVDDC; // For the 780, use: None, Low, High, Variable + UCHAR ucMaxHTLinkWidth; // From SBIOS - {2, 4, 8, 16} + UCHAR ucMinHTLinkWidth; // From SBIOS - {2, 4, 8, 16}. Effective only if CDLW enabled. Minimum down stream width could be bigger as display BW requirement. + USHORT usHTLinkFreq; // See definition ATOM_PPLIB_RS780_HTLINKFREQ_xxx or in MHz(>=200). + ULONG ulFlags; +} ATOM_PPLIB_RS780_CLOCK_INFO; + +#define ATOM_PPLIB_RS780_VOLTAGE_NONE 0 +#define ATOM_PPLIB_RS780_VOLTAGE_LOW 1 +#define ATOM_PPLIB_RS780_VOLTAGE_HIGH 2 +#define ATOM_PPLIB_RS780_VOLTAGE_VARIABLE 3 + +#define ATOM_PPLIB_RS780_SPMCLK_NONE 0 // We cannot change the side port memory clock, leave it as it is. +#define ATOM_PPLIB_RS780_SPMCLK_LOW 1 +#define ATOM_PPLIB_RS780_SPMCLK_HIGH 2 + +#define ATOM_PPLIB_RS780_HTLINKFREQ_NONE 0 +#define ATOM_PPLIB_RS780_HTLINKFREQ_LOW 1 +#define ATOM_PPLIB_RS780_HTLINKFREQ_HIGH 2 + +/**************************************************************************/ + + +// Following definitions are for compatiblity issue in different SW components. +#define ATOM_MASTER_DATA_TABLE_REVISION 0x01 +#define Object_Info Object_Header +#define AdjustARB_SEQ MC_InitParameter +#define VRAM_GPIO_DetectionInfo VoltageObjectInfo +#define ASIC_VDDCI_Info ASIC_ProfilingInfo +#define ASIC_MVDDQ_Info MemoryTrainingInfo +#define SS_Info PPLL_SS_Info +#define ASIC_MVDDC_Info ASIC_InternalSS_Info +#define DispDevicePriorityInfo SaveRestoreInfo +#define DispOutInfo TV_VideoMode + + +#define ATOM_ENCODER_OBJECT_TABLE ATOM_OBJECT_TABLE +#define ATOM_CONNECTOR_OBJECT_TABLE ATOM_OBJECT_TABLE + +//New device naming, remove them when both DAL/VBIOS is ready +#define DFP2I_OUTPUT_CONTROL_PARAMETERS CRT1_OUTPUT_CONTROL_PARAMETERS +#define DFP2I_OUTPUT_CONTROL_PS_ALLOCATION DFP2I_OUTPUT_CONTROL_PARAMETERS + +#define DFP1X_OUTPUT_CONTROL_PARAMETERS CRT1_OUTPUT_CONTROL_PARAMETERS +#define DFP1X_OUTPUT_CONTROL_PS_ALLOCATION DFP1X_OUTPUT_CONTROL_PARAMETERS + +#define DFP1I_OUTPUT_CONTROL_PARAMETERS DFP1_OUTPUT_CONTROL_PARAMETERS +#define DFP1I_OUTPUT_CONTROL_PS_ALLOCATION DFP1_OUTPUT_CONTROL_PS_ALLOCATION + +#define ATOM_DEVICE_DFP1I_SUPPORT ATOM_DEVICE_DFP1_SUPPORT +#define ATOM_DEVICE_DFP1X_SUPPORT ATOM_DEVICE_DFP2_SUPPORT + +#define ATOM_DEVICE_DFP1I_INDEX ATOM_DEVICE_DFP1_INDEX +#define ATOM_DEVICE_DFP1X_INDEX ATOM_DEVICE_DFP2_INDEX + +#define ATOM_DEVICE_DFP2I_INDEX 0x00000009 +#define ATOM_DEVICE_DFP2I_SUPPORT (0x1L << ATOM_DEVICE_DFP2I_INDEX) + +#define ATOM_S0_DFP1I ATOM_S0_DFP1 +#define ATOM_S0_DFP1X ATOM_S0_DFP2 + +#define ATOM_S0_DFP2I 0x00200000L +#define ATOM_S0_DFP2Ib2 0x20 + +#define ATOM_S2_DFP1I_DPMS_STATE ATOM_S2_DFP1_DPMS_STATE +#define ATOM_S2_DFP1X_DPMS_STATE ATOM_S2_DFP2_DPMS_STATE + +#define ATOM_S2_DFP2I_DPMS_STATE 0x02000000L +#define ATOM_S2_DFP2I_DPMS_STATEb3 0x02 + +#define ATOM_S3_DFP2I_ACTIVEb1 0x02 + +#define ATOM_S3_DFP1I_ACTIVE ATOM_S3_DFP1_ACTIVE +#define ATOM_S3_DFP1X_ACTIVE ATOM_S3_DFP2_ACTIVE + +#define ATOM_S3_DFP2I_ACTIVE 0x00000200L + +#define ATOM_S3_DFP1I_CRTC_ACTIVE ATOM_S3_DFP1_CRTC_ACTIVE +#define ATOM_S3_DFP1X_CRTC_ACTIVE ATOM_S3_DFP2_CRTC_ACTIVE +#define ATOM_S3_DFP2I_CRTC_ACTIVE 0x02000000L + +#define ATOM_S3_DFP2I_CRTC_ACTIVEb3 0x02 +#define ATOM_S5_DOS_REQ_DFP2Ib1 0x02 + +#define ATOM_S5_DOS_REQ_DFP2I 0x0200 +#define ATOM_S6_ACC_REQ_DFP1I ATOM_S6_ACC_REQ_DFP1 +#define ATOM_S6_ACC_REQ_DFP1X ATOM_S6_ACC_REQ_DFP2 + +#define ATOM_S6_ACC_REQ_DFP2Ib3 0x02 +#define ATOM_S6_ACC_REQ_DFP2I 0x02000000L + +#define TMDS1XEncoderControl DVOEncoderControl +#define DFP1XOutputControl DVOOutputControl + +#define ExternalDFPOutputControl DFP1XOutputControl +#define EnableExternalTMDS_Encoder TMDS1XEncoderControl + +#define DFP1IOutputControl TMDSAOutputControl +#define DFP2IOutputControl LVTMAOutputControl + +#define DAC1_ENCODER_CONTROL_PARAMETERS DAC_ENCODER_CONTROL_PARAMETERS +#define DAC1_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION + +#define DAC2_ENCODER_CONTROL_PARAMETERS DAC_ENCODER_CONTROL_PARAMETERS +#define DAC2_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION + +#define ucDac1Standard ucDacStandard +#define ucDac2Standard ucDacStandard + +#define TMDS1EncoderControl TMDSAEncoderControl +#define TMDS2EncoderControl LVTMAEncoderControl + +#define DFP1OutputControl TMDSAOutputControl +#define DFP2OutputControl LVTMAOutputControl +#define CRT1OutputControl DAC1OutputControl +#define CRT2OutputControl DAC2OutputControl + +//These two lines will be removed for sure in a few days, will follow up with Michael V. +#define EnableLVDS_SS EnableSpreadSpectrumOnPPLL +#define ENABLE_LVDS_SS_PARAMETERS_V3 ENABLE_SPREAD_SPECTRUM_ON_PPLL + +//#define ATOM_S2_CRT1_DPMS_STATE 0x00010000L +//#define ATOM_S2_LCD1_DPMS_STATE ATOM_S2_CRT1_DPMS_STATE +//#define ATOM_S2_TV1_DPMS_STATE ATOM_S2_CRT1_DPMS_STATE +//#define ATOM_S2_DFP1_DPMS_STATE ATOM_S2_CRT1_DPMS_STATE +//#define ATOM_S2_CRT2_DPMS_STATE ATOM_S2_CRT1_DPMS_STATE + +#define ATOM_S6_ACC_REQ_TV2 0x00400000L +#define ATOM_DEVICE_TV2_INDEX 0x00000006 +#define ATOM_DEVICE_TV2_SUPPORT (0x1L << ATOM_DEVICE_TV2_INDEX) +#define ATOM_S0_TV2 0x00100000L +#define ATOM_S3_TV2_ACTIVE ATOM_S3_DFP6_ACTIVE +#define ATOM_S3_TV2_CRTC_ACTIVE ATOM_S3_DFP6_CRTC_ACTIVE + +// +#define ATOM_S2_CRT1_DPMS_STATE 0x00010000L +#define ATOM_S2_LCD1_DPMS_STATE 0x00020000L +#define ATOM_S2_TV1_DPMS_STATE 0x00040000L +#define ATOM_S2_DFP1_DPMS_STATE 0x00080000L +#define ATOM_S2_CRT2_DPMS_STATE 0x00100000L +#define ATOM_S2_LCD2_DPMS_STATE 0x00200000L +#define ATOM_S2_TV2_DPMS_STATE 0x00400000L +#define ATOM_S2_DFP2_DPMS_STATE 0x00800000L +#define ATOM_S2_CV_DPMS_STATE 0x01000000L +#define ATOM_S2_DFP3_DPMS_STATE 0x02000000L +#define ATOM_S2_DFP4_DPMS_STATE 0x04000000L +#define ATOM_S2_DFP5_DPMS_STATE 0x08000000L + +#define ATOM_S2_CRT1_DPMS_STATEb2 0x01 +#define ATOM_S2_LCD1_DPMS_STATEb2 0x02 +#define ATOM_S2_TV1_DPMS_STATEb2 0x04 +#define ATOM_S2_DFP1_DPMS_STATEb2 0x08 +#define ATOM_S2_CRT2_DPMS_STATEb2 0x10 +#define ATOM_S2_LCD2_DPMS_STATEb2 0x20 +#define ATOM_S2_TV2_DPMS_STATEb2 0x40 +#define ATOM_S2_DFP2_DPMS_STATEb2 0x80 +#define ATOM_S2_CV_DPMS_STATEb3 0x01 +#define ATOM_S2_DFP3_DPMS_STATEb3 0x02 +#define ATOM_S2_DFP4_DPMS_STATEb3 0x04 +#define ATOM_S2_DFP5_DPMS_STATEb3 0x08 + +#define ATOM_S3_ASIC_GUI_ENGINE_HUNGb3 0x20 +#define ATOM_S3_ALLOW_FAST_PWR_SWITCHb3 0x40 +#define ATOM_S3_RQST_GPU_USE_MIN_PWRb3 0x80 + +/*********************************************************************************/ + +#pragma pack() // BIOS data must use byte aligment + +#endif /* _ATOMBIOS_H */ diff --git a/plugins/GPUSensors/RadeonMonitor/radeon_chipinfo_gen.h b/plugins/GPUSensors/RadeonMonitor/radeon_chipinfo_gen.h new file mode 100755 index 0000000..962148f --- /dev/null +++ b/plugins/GPUSensors/RadeonMonitor/radeon_chipinfo_gen.h @@ -0,0 +1,539 @@ +// dong remove radeon_device_list all elsewhere to avoid redefinition +#include "radeon_chipsets.h" + +static +RADEONCardInfo radeon_device_list[] = { + { 0x3150, CHIP_FAMILY_RV380, 1, 0, 0, 0, 0 }, + { 0x3152, CHIP_FAMILY_RV380, 1, 0, 0, 0, 0 }, + { 0x3154, CHIP_FAMILY_RV380, 1, 0, 0, 0, 0 }, + { 0x3E50, CHIP_FAMILY_RV380, 0, 0, 0, 0, 0 }, + { 0x3E54, CHIP_FAMILY_RV380, 0, 0, 0, 0, 0 }, + { 0x4136, CHIP_FAMILY_RS100, 0, 1, 0, 0, 1 }, + { 0x4137, CHIP_FAMILY_RS200, 0, 1, 0, 0, 1 }, + // {0x2a02, CHIP_FAMILY_RV770, 1, 1, 0, 0, 0 }, //Debug + { 0x4144, CHIP_FAMILY_R300, 0, 0, 0, 0, 0 }, + { 0x4145, CHIP_FAMILY_R300, 0, 0, 0, 0, 0 }, + { 0x4146, CHIP_FAMILY_R300, 0, 0, 0, 0, 0 }, + { 0x4147, CHIP_FAMILY_R300, 0, 0, 0, 0, 0 }, + { 0x4148, CHIP_FAMILY_R350, 0, 0, 0, 0, 0 }, + { 0x4149, CHIP_FAMILY_R350, 0, 0, 0, 0, 0 }, + { 0x414A, CHIP_FAMILY_R350, 0, 0, 0, 0, 0 }, + { 0x414B, CHIP_FAMILY_R350, 0, 0, 0, 0, 0 }, + { 0x4150, CHIP_FAMILY_RV350, 0, 0, 0, 0, 0 }, + { 0x4151, CHIP_FAMILY_RV350, 0, 0, 0, 0, 0 }, + { 0x4152, CHIP_FAMILY_RV350, 0, 0, 0, 0, 0 }, + { 0x4153, CHIP_FAMILY_RV350, 0, 0, 0, 0, 0 }, + { 0x4154, CHIP_FAMILY_RV350, 0, 0, 0, 0, 0 }, + { 0x4155, CHIP_FAMILY_RV350, 0, 0, 0, 0, 0 }, + { 0x4156, CHIP_FAMILY_RV350, 0, 0, 0, 0, 0 }, + { 0x4237, CHIP_FAMILY_RS200, 0, 1, 0, 0, 1 }, + { 0x4242, CHIP_FAMILY_R200, 0, 0, 0, 1, 0 }, + { 0x4243, CHIP_FAMILY_R200, 0, 0, 0, 1, 0 }, + { 0x4336, CHIP_FAMILY_RS100, 1, 1, 0, 0, 1 }, + { 0x4337, CHIP_FAMILY_RS200, 1, 1, 0, 0, 1 }, + { 0x4437, CHIP_FAMILY_RS200, 1, 1, 0, 0, 1 }, + { 0x4966, CHIP_FAMILY_RV250, 0, 0, 0, 0, 0 }, + { 0x4967, CHIP_FAMILY_RV250, 0, 0, 0, 0, 0 }, + { 0x4A48, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x4A49, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x4A4A, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x4A4B, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x4A4C, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x4A4D, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x4A4E, CHIP_FAMILY_R420, 1, 0, 0, 0, 0 }, + { 0x4A4F, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x4A50, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x4B49, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x4B4A, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x4B4B, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x4B4C, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x4C57, CHIP_FAMILY_RV200, 1, 0, 0, 0, 0 }, + { 0x4C58, CHIP_FAMILY_RV200, 1, 0, 0, 0, 0 }, + { 0x4C59, CHIP_FAMILY_RV100, 1, 0, 0, 0, 0 }, + { 0x4C5A, CHIP_FAMILY_RV100, 1, 0, 0, 0, 0 }, + { 0x4C64, CHIP_FAMILY_RV250, 1, 0, 0, 0, 0 }, + { 0x4C66, CHIP_FAMILY_RV250, 1, 0, 0, 0, 0 }, + { 0x4C67, CHIP_FAMILY_RV250, 1, 0, 0, 0, 0 }, + { 0x4E44, CHIP_FAMILY_R300, 0, 0, 0, 0, 0 }, + { 0x4E45, CHIP_FAMILY_R300, 0, 0, 0, 0, 0 }, + { 0x4E46, CHIP_FAMILY_R300, 0, 0, 0, 0, 0 }, + { 0x4E47, CHIP_FAMILY_R300, 0, 0, 0, 0, 0 }, + { 0x4E48, CHIP_FAMILY_R350, 0, 0, 0, 0, 0 }, + { 0x4E49, CHIP_FAMILY_R350, 0, 0, 0, 0, 0 }, + { 0x4E4A, CHIP_FAMILY_R350, 0, 0, 0, 0, 0 }, + { 0x4E4B, CHIP_FAMILY_R350, 0, 0, 0, 0, 0 }, + { 0x4E50, CHIP_FAMILY_RV350, 1, 0, 0, 0, 0 }, + { 0x4E51, CHIP_FAMILY_RV350, 1, 0, 0, 0, 0 }, + { 0x4E52, CHIP_FAMILY_RV350, 1, 0, 0, 0, 0 }, + { 0x4E53, CHIP_FAMILY_RV350, 1, 0, 0, 0, 0 }, + { 0x4E54, CHIP_FAMILY_RV350, 1, 0, 0, 0, 0 }, + { 0x4E56, CHIP_FAMILY_RV350, 1, 0, 0, 0, 0 }, + { 0x5144, CHIP_FAMILY_RADEON, 0, 0, 1, 1, 0 }, + { 0x5145, CHIP_FAMILY_RADEON, 0, 0, 1, 1, 0 }, + { 0x5146, CHIP_FAMILY_RADEON, 0, 0, 1, 1, 0 }, + { 0x5147, CHIP_FAMILY_RADEON, 0, 0, 1, 1, 0 }, + { 0x5148, CHIP_FAMILY_R200, 0, 0, 0, 1, 0 }, + { 0x514C, CHIP_FAMILY_R200, 0, 0, 0, 1, 0 }, + { 0x514D, CHIP_FAMILY_R200, 0, 0, 0, 1, 0 }, + { 0x5157, CHIP_FAMILY_RV200, 0, 0, 0, 0, 0 }, + { 0x5158, CHIP_FAMILY_RV200, 0, 0, 0, 0, 0 }, + { 0x5159, CHIP_FAMILY_RV100, 0, 0, 0, 0, 0 }, + { 0x515A, CHIP_FAMILY_RV100, 0, 0, 0, 0, 0 }, + { 0x515E, CHIP_FAMILY_RV100, 0, 0, 1, 0, 0 }, + { 0x5460, CHIP_FAMILY_RV380, 1, 0, 0, 0, 0 }, + { 0x5462, CHIP_FAMILY_RV380, 1, 0, 0, 0, 0 }, + { 0x5464, CHIP_FAMILY_RV380, 1, 0, 0, 0, 0 }, + { 0x5548, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x5549, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x554A, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x554B, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x554C, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x554D, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x554E, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x554F, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x5550, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x5551, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x5552, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x5554, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x564A, CHIP_FAMILY_RV410, 1, 0, 0, 0, 0 }, + { 0x564B, CHIP_FAMILY_RV410, 1, 0, 0, 0, 0 }, + { 0x564F, CHIP_FAMILY_RV410, 1, 0, 0, 0, 0 }, + { 0x5652, CHIP_FAMILY_RV410, 1, 0, 0, 0, 0 }, + { 0x5653, CHIP_FAMILY_RV410, 1, 0, 0, 0, 0 }, + { 0x5834, CHIP_FAMILY_RS300, 0, 1, 0, 0, 1 }, + { 0x5835, CHIP_FAMILY_RS300, 1, 1, 0, 0, 1 }, + { 0x5954, CHIP_FAMILY_RS400, 0, 1, 0, 0, 1 }, + { 0x5955, CHIP_FAMILY_RS400, 1, 1, 0, 0, 1 }, + { 0x5960, CHIP_FAMILY_RV280, 0, 0, 0, 0, 0 }, + { 0x5961, CHIP_FAMILY_RV280, 0, 0, 0, 0, 0 }, + { 0x5962, CHIP_FAMILY_RV280, 0, 0, 0, 0, 0 }, + { 0x5964, CHIP_FAMILY_RV280, 0, 0, 0, 0, 0 }, + { 0x5965, CHIP_FAMILY_RV280, 0, 0, 0, 0, 0 }, + { 0x5969, CHIP_FAMILY_RV100, 0, 0, 1, 0, 0 }, + { 0x5974, CHIP_FAMILY_RS400, 0, 1, 0, 0, 1 }, + { 0x5975, CHIP_FAMILY_RS400, 1, 1, 0, 0, 1 }, + { 0x5A41, CHIP_FAMILY_RS400, 0, 1, 0, 0, 1 }, + { 0x5A42, CHIP_FAMILY_RS400, 1, 1, 0, 0, 1 }, + { 0x5A61, CHIP_FAMILY_RS400, 0, 1, 0, 0, 1 }, + { 0x5A62, CHIP_FAMILY_RS400, 1, 1, 0, 0, 1 }, + { 0x5B60, CHIP_FAMILY_RV380, 0, 0, 0, 0, 0 }, + { 0x5B62, CHIP_FAMILY_RV380, 0, 0, 0, 0, 0 }, + { 0x5B63, CHIP_FAMILY_RV380, 0, 0, 0, 0, 0 }, + { 0x5657, CHIP_FAMILY_RV380, 0, 0, 0, 0, 0 }, + { 0x5B64, CHIP_FAMILY_RV380, 0, 0, 0, 0, 0 }, + { 0x5B65, CHIP_FAMILY_RV380, 0, 0, 0, 0, 0 }, + { 0x5C61, CHIP_FAMILY_RV280, 1, 0, 0, 0, 0 }, + { 0x5C63, CHIP_FAMILY_RV280, 1, 0, 0, 0, 0 }, + { 0x5D48, CHIP_FAMILY_R420, 1, 0, 0, 0, 0 }, + { 0x5D49, CHIP_FAMILY_R420, 1, 0, 0, 0, 0 }, + { 0x5D4A, CHIP_FAMILY_R420, 1, 0, 0, 0, 0 }, + { 0x5D4C, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x5D4D, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x5D4E, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x5D4F, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x5D50, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x5D52, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x5D57, CHIP_FAMILY_R420, 0, 0, 0, 0, 0 }, + { 0x5E48, CHIP_FAMILY_RV410, 0, 0, 0, 0, 0 }, + { 0x5E4A, CHIP_FAMILY_RV410, 0, 0, 0, 0, 0 }, + { 0x5E4B, CHIP_FAMILY_RV410, 0, 0, 0, 0, 0 }, + { 0x5E4C, CHIP_FAMILY_RV410, 0, 0, 0, 0, 0 }, + { 0x5E4D, CHIP_FAMILY_RV410, 0, 0, 0, 0, 0 }, + { 0x5E4F, CHIP_FAMILY_RV410, 0, 0, 0, 0, 0 }, + { 0x7100, CHIP_FAMILY_R520, 0, 0, 0, 0, 0 }, + { 0x7101, CHIP_FAMILY_R520, 1, 0, 0, 0, 0 }, + { 0x7102, CHIP_FAMILY_R520, 1, 0, 0, 0, 0 }, + { 0x7103, CHIP_FAMILY_R520, 1, 0, 0, 0, 0 }, + { 0x7104, CHIP_FAMILY_R520, 0, 0, 0, 0, 0 }, + { 0x7105, CHIP_FAMILY_R520, 0, 0, 0, 0, 0 }, + { 0x7106, CHIP_FAMILY_R520, 1, 0, 0, 0, 0 }, + { 0x7108, CHIP_FAMILY_R520, 0, 0, 0, 0, 0 }, + { 0x7109, CHIP_FAMILY_R520, 0, 0, 0, 0, 0 }, + { 0x710A, CHIP_FAMILY_R520, 0, 0, 0, 0, 0 }, + { 0x710B, CHIP_FAMILY_R520, 0, 0, 0, 0, 0 }, + { 0x710C, CHIP_FAMILY_R520, 0, 0, 0, 0, 0 }, + { 0x710E, CHIP_FAMILY_R520, 0, 0, 0, 0, 0 }, + { 0x710F, CHIP_FAMILY_R520, 0, 0, 0, 0, 0 }, + { 0x7140, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7141, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7142, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7143, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7144, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x7145, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x7146, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7147, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7149, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x714A, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x714B, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x714C, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x714D, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x714E, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x714F, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7151, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7152, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7153, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x715E, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x715F, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7180, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7181, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7183, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7186, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x7187, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7188, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x718A, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x718B, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x718C, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x718D, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x718F, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7193, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x7196, CHIP_FAMILY_RV515, 1, 0, 0, 0, 0 }, + { 0x719B, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x719F, CHIP_FAMILY_RV515, 0, 0, 0, 0, 0 }, + { 0x71C0, CHIP_FAMILY_RV530, 0, 0, 0, 0, 0 }, + { 0x71C1, CHIP_FAMILY_RV530, 0, 0, 0, 0, 0 }, + { 0x71C2, CHIP_FAMILY_RV530, 0, 0, 0, 0, 0 }, + { 0x71C3, CHIP_FAMILY_RV530, 0, 0, 0, 0, 0 }, + { 0x71C4, CHIP_FAMILY_RV530, 1, 0, 0, 0, 0 }, + { 0x71C5, CHIP_FAMILY_RV530, 1, 0, 0, 0, 0 }, + { 0x71C6, CHIP_FAMILY_RV530, 0, 0, 0, 0, 0 }, + { 0x71C7, CHIP_FAMILY_RV530, 0, 0, 0, 0, 0 }, + { 0x71CD, CHIP_FAMILY_RV530, 0, 0, 0, 0, 0 }, + { 0x71CE, CHIP_FAMILY_RV530, 0, 0, 0, 0, 0 }, + { 0x71D2, CHIP_FAMILY_RV530, 0, 0, 0, 0, 0 }, + { 0x71D4, CHIP_FAMILY_RV530, 1, 0, 0, 0, 0 }, + { 0x71D5, CHIP_FAMILY_RV530, 1, 0, 0, 0, 0 }, + { 0x71D6, CHIP_FAMILY_RV530, 1, 0, 0, 0, 0 }, + { 0x71DA, CHIP_FAMILY_RV530, 0, 0, 0, 0, 0 }, + { 0x71DE, CHIP_FAMILY_RV530, 1, 0, 0, 0, 0 }, + { 0x7200, CHIP_FAMILY_RV530, 0, 0, 0, 0, 0 }, + { 0x7210, CHIP_FAMILY_RV530, 1, 0, 0, 0, 0 }, + { 0x7211, CHIP_FAMILY_RV530, 1, 0, 0, 0, 0 }, + { 0x7240, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x7243, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x7244, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x7245, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x7246, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x7247, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x7248, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x7249, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x724A, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x724B, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x724C, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x724D, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x724E, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x724F, CHIP_FAMILY_R580, 0, 0, 0, 0, 0 }, + { 0x7280, CHIP_FAMILY_RV570, 0, 0, 0, 0, 0 }, + { 0x7281, CHIP_FAMILY_RV560, 0, 0, 0, 0, 0 }, + { 0x7283, CHIP_FAMILY_RV560, 0, 0, 0, 0, 0 }, + { 0x7284, CHIP_FAMILY_R580, 1, 0, 0, 0, 0 }, + { 0x7287, CHIP_FAMILY_RV560, 0, 0, 0, 0, 0 }, + { 0x7288, CHIP_FAMILY_RV570, 0, 0, 0, 0, 0 }, + { 0x7289, CHIP_FAMILY_RV570, 0, 0, 0, 0, 0 }, + { 0x728B, CHIP_FAMILY_RV570, 0, 0, 0, 0, 0 }, + { 0x728C, CHIP_FAMILY_RV570, 0, 0, 0, 0, 0 }, + { 0x7290, CHIP_FAMILY_RV560, 0, 0, 0, 0, 0 }, + { 0x7291, CHIP_FAMILY_RV560, 0, 0, 0, 0, 0 }, + { 0x7293, CHIP_FAMILY_RV560, 0, 0, 0, 0, 0 }, + { 0x7297, CHIP_FAMILY_RV560, 0, 0, 0, 0, 0 }, + { 0x7834, CHIP_FAMILY_RS300, 0, 1, 0, 0, 1 }, + { 0x7835, CHIP_FAMILY_RS300, 1, 1, 0, 0, 1 }, + { 0x791E, CHIP_FAMILY_RS690, 0, 1, 0, 0, 1 }, + { 0x791F, CHIP_FAMILY_RS690, 0, 1, 0, 0, 1 }, + { 0x796C, CHIP_FAMILY_RS740, 0, 1, 0, 0, 1 }, + { 0x796D, CHIP_FAMILY_RS740, 0, 1, 0, 0, 1 }, + { 0x796E, CHIP_FAMILY_RS740, 0, 1, 0, 0, 1 }, + { 0x796F, CHIP_FAMILY_RS740, 0, 1, 0, 0, 1 }, + { 0x9400, CHIP_FAMILY_R600, 0, 0, 0, 0, 0 }, + { 0x9401, CHIP_FAMILY_R600, 0, 0, 0, 0, 0 }, + { 0x9402, CHIP_FAMILY_R600, 0, 0, 0, 0, 0 }, + { 0x9403, CHIP_FAMILY_R600, 0, 0, 0, 0, 0 }, + { 0x9405, CHIP_FAMILY_R600, 0, 0, 0, 0, 0 }, + { 0x940A, CHIP_FAMILY_R600, 0, 0, 0, 0, 0 }, + { 0x940B, CHIP_FAMILY_R600, 0, 0, 0, 0, 0 }, + { 0x940F, CHIP_FAMILY_R600, 0, 0, 0, 0, 0 }, + { 0x9440, CHIP_FAMILY_RV770, 0, 0, 0, 0, 0 }, + { 0x9441, CHIP_FAMILY_RV700, 0, 0, 0, 0, 0 }, + { 0x9442, CHIP_FAMILY_RV770, 0, 0, 0, 0, 0 }, + { 0x9443, CHIP_FAMILY_RV700, 0, 0, 0, 0, 0 }, + { 0x9444, CHIP_FAMILY_RV700, 0, 0, 0, 0, 0 }, + { 0x9446, CHIP_FAMILY_RV700, 0, 0, 0, 0, 0 }, + { 0x9447, CHIP_FAMILY_RV700, 0, 0, 0, 0, 0 }, + { 0x944A, CHIP_FAMILY_RV770, 1, 0, 0, 0, 0 }, + { 0x944B, CHIP_FAMILY_RV770, 1, 0, 0, 0, 0 }, + { 0x944C, CHIP_FAMILY_RV770, 0, 0, 0, 0, 0 }, + { 0x944E, CHIP_FAMILY_RV770, 0, 0, 0, 0, 0 }, + { 0x9450, CHIP_FAMILY_RV770, 0, 0, 0, 0, 0 }, + { 0x9452, CHIP_FAMILY_RV770, 0, 0, 0, 0, 0 }, + { 0x9456, CHIP_FAMILY_RV770, 0, 0, 0, 0, 0 }, + { 0x945A, CHIP_FAMILY_RV770, 1, 0, 0, 0, 0 }, + { 0x945B, CHIP_FAMILY_RV770, 1, 0, 0, 0, 0 }, + { 0x9460, CHIP_FAMILY_RV790, 0, 0, 0, 0, 0 }, + { 0x9462, CHIP_FAMILY_RV790, 0, 0, 0, 0, 0 }, + { 0x946A, CHIP_FAMILY_RV790, 1, 0, 0, 0, 0 }, + { 0x946B, CHIP_FAMILY_RV790, 1, 0, 0, 0, 0 }, + { 0x947A, CHIP_FAMILY_RV790, 1, 0, 0, 0, 0 }, + { 0x947B, CHIP_FAMILY_RV790, 1, 0, 0, 0, 0 }, + { 0x9480, CHIP_FAMILY_R730, 1, 0, 0, 0, 0 }, + { 0x9487, CHIP_FAMILY_R730, 1, 0, 0, 0, 0 }, + { 0x9488, CHIP_FAMILY_R730, 1, 0, 0, 0, 0 }, + { 0x9489, CHIP_FAMILY_R730, 1, 0, 0, 0, 0 }, + { 0x948F, CHIP_FAMILY_R730, 1, 0, 0, 0, 0 }, + { 0x9490, CHIP_FAMILY_R730, 0, 0, 0, 0, 0 }, + { 0x9491, CHIP_FAMILY_R730, 0, 0, 0, 0, 0 }, + { 0x9495, CHIP_FAMILY_R730, 0, 0, 0, 0, 0 }, + { 0x9498, CHIP_FAMILY_R730, 0, 0, 0, 0, 0 }, + { 0x949C, CHIP_FAMILY_R730, 0, 0, 0, 0, 0 }, + { 0x949E, CHIP_FAMILY_R730, 0, 0, 0, 0, 0 }, + { 0x949F, CHIP_FAMILY_R730, 0, 0, 0, 0, 0 }, + { 0x94A0, CHIP_FAMILY_R730, 1, 0, 0, 0, 0 }, + { 0x94A1, CHIP_FAMILY_R730, 1, 0, 0, 0, 0 }, + { 0x94A3, CHIP_FAMILY_R730, 1, 0, 0, 0, 0 }, + { 0x94B1, CHIP_FAMILY_RV740, 0, 0, 0, 0, 0 }, + { 0x94B3, CHIP_FAMILY_RV740, 0, 0, 0, 0, 0 }, + { 0x94B4, CHIP_FAMILY_RV740, 0, 0, 0, 0, 0 }, + { 0x94B5, CHIP_FAMILY_RV740, 0, 0, 0, 0, 0 }, + { 0x94B9, CHIP_FAMILY_RV740, 0, 0, 0, 0, 0 }, + { 0x94C0, CHIP_FAMILY_RV610, 0, 0, 0, 0, 0 }, + { 0x94C1, CHIP_FAMILY_RV610, 0, 0, 0, 0, 0 }, + { 0x94C3, CHIP_FAMILY_RV610, 0, 0, 0, 0, 0 }, + { 0x94C4, CHIP_FAMILY_RV610, 0, 0, 0, 0, 0 }, + { 0x94C5, CHIP_FAMILY_RV610, 0, 0, 0, 0, 0 }, + { 0x94C6, CHIP_FAMILY_RV610, 0, 0, 0, 0, 0 }, + { 0x94C7, CHIP_FAMILY_RV610, 0, 0, 0, 0, 0 }, + { 0x94C8, CHIP_FAMILY_RV610, 1, 0, 0, 0, 0 }, + { 0x94C9, CHIP_FAMILY_RV610, 1, 0, 0, 0, 0 }, + { 0x94CB, CHIP_FAMILY_RV610, 1, 0, 0, 0, 0 }, + { 0x94CC, CHIP_FAMILY_RV610, 0, 0, 0, 0, 0 }, + { 0x94CD, CHIP_FAMILY_RV610, 0, 0, 0, 0, 0 }, + { 0x9500, CHIP_FAMILY_RV670, 0, 0, 0, 0, 0 }, + { 0x9501, CHIP_FAMILY_RV670, 0, 0, 0, 0, 0 }, + { 0x9504, CHIP_FAMILY_RV670, 1, 0, 0, 0, 0 }, + { 0x9505, CHIP_FAMILY_RV670, 0, 0, 0, 0, 0 }, + { 0x9506, CHIP_FAMILY_RV670, 1, 0, 0, 0, 0 }, + { 0x9507, CHIP_FAMILY_RV670, 0, 0, 0, 0, 0 }, + { 0x9508, CHIP_FAMILY_RV670, 1, 0, 0, 0, 0 }, + { 0x9509, CHIP_FAMILY_RV670, 1, 0, 0, 0, 0 }, + { 0x950F, CHIP_FAMILY_RV670, 0, 0, 0, 0, 0 }, + { 0x9511, CHIP_FAMILY_RV670, 0, 0, 0, 0, 0 }, + { 0x9513, CHIP_FAMILY_RV670, 0, 0, 0, 0, 0 }, + { 0x9515, CHIP_FAMILY_RV670, 0, 0, 0, 0, 0 }, + { 0x9517, CHIP_FAMILY_RV670, 0, 0, 0, 0, 0 }, + { 0x9519, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x9540, CHIP_FAMILY_R710, 0, 0, 0, 0, 0 }, + { 0x9541, CHIP_FAMILY_R710, 0, 0, 0, 0, 0 }, + { 0x9542, CHIP_FAMILY_R710, 0, 0, 0, 0, 0 }, + { 0x954E, CHIP_FAMILY_R710, 0, 0, 0, 0, 0 }, + { 0x954F, CHIP_FAMILY_R710, 0, 0, 0, 0, 0 }, + { 0x9552, CHIP_FAMILY_RV710, 1, 0, 0, 0, 0 }, + { 0x9553, CHIP_FAMILY_RV710, 1, 0, 0, 0, 0 }, + { 0x9555, CHIP_FAMILY_RV710, 1, 0, 0, 0, 0 }, + { 0x9557, CHIP_FAMILY_RV710, 1, 0, 0, 0, 0 }, + { 0x955E, CHIP_FAMILY_R710, 0, 0, 0, 0, 0 }, + { 0x9580, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x9581, CHIP_FAMILY_RV630, 1, 0, 0, 0, 0 }, + { 0x9583, CHIP_FAMILY_RV630, 1, 0, 0, 0, 0 }, + { 0x9586, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x9587, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x9588, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x9589, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x958A, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x958B, CHIP_FAMILY_RV630, 1, 0, 0, 0, 0 }, + { 0x958C, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x958D, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x958E, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x958F, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x9591, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x9593, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x9598, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x9599, CHIP_FAMILY_RV630, 0, 0, 0, 0, 0 }, + { 0x95C0, CHIP_FAMILY_RV620, 0, 0, 0, 0, 0 }, + { 0x95C2, CHIP_FAMILY_RV620, 1, 0, 0, 0, 0 }, + { 0x95C4, CHIP_FAMILY_RV620, 1, 0, 0, 0, 0 }, + { 0x95C5, CHIP_FAMILY_RV620, 0, 0, 0, 0, 0 }, + { 0x95C6, CHIP_FAMILY_RV620, 0, 0, 0, 0, 0 }, + { 0x95C7, CHIP_FAMILY_RV620, 0, 0, 0, 0, 0 }, + { 0x95C9, CHIP_FAMILY_RV620, 0, 0, 0, 0, 0 }, + { 0x95CD, CHIP_FAMILY_RV620, 0, 0, 0, 0, 0 }, + { 0x95CE, CHIP_FAMILY_RV620, 0, 0, 0, 0, 0 }, + { 0x95CF, CHIP_FAMILY_RV620, 0, 0, 0, 0, 0 }, + { 0x9610, CHIP_FAMILY_RS780, 1, 0, 0, 0, 0 }, + { 0x9611, CHIP_FAMILY_RS780, 1, 0, 0, 0, 0 }, + { 0x9614, CHIP_FAMILY_RS780, 1, 0, 0, 0, 0 }, + { 0x9616, CHIP_FAMILY_RS780, 1, 0, 0, 0, 0 }, + { 0x9710, CHIP_FAMILY_RS880, 1, 0, 0, 0, 0 }, + { 0x9711, CHIP_FAMILY_RS880, 1, 0, 0, 0, 0 }, + { 0x9712, CHIP_FAMILY_RS880, 1, 0, 0, 0, 0 }, + { 0x9713, CHIP_FAMILY_RS880, 1, 0, 0, 0, 0 }, + { 0x9714, CHIP_FAMILY_RS880, 1, 0, 0, 0, 0 }, + { 0x9715, CHIP_FAMILY_RS880, 1, 0, 0, 0, 0 }, + /* + // Oland: R7-240, 250 + { 0x6600, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 },// "AMD Radeon HD 8600/8700M", kNull }, // Mobile + { 0x6601, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 },// "AMD Radeon HD 8500/8700M", kNull }, // Mobile + // { 0x6602, 0x00000000, CHIP_FAMILY_OLAND, "AMD Radeon", kNull }, // Mobile + // { 0x6603, 0x00000000, CHIP_FAMILY_OLAND, "AMD Radeon", kNull }, // Mobile + { 0x6604, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 },// "AMD Radeon R7 M265", kNull }, // Mobile + { 0x6605, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 },// "AMD Radeon R7 M260", kNull }, // Mobile + { 0x6606, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 },// "AMD Radeon HD 8790M", kNull }, // Mobile + { 0x6607, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 },// "AMD Radeon R5 M240", kNull }, // Mobile + { 0x6608, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 },// "AMD FirePro W2100", kNull }, + { 0x6610, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 },// "AMD Radeon R7 250", kFutomaki }, + { 0x6611, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 },// "AMD Radeon R7 340 Series", kNull }, + { 0x6613, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 },// "AMD Radeon R7 240", kFutomaki }, + // { 0x6620, 0x00000000, CHIP_FAMILY_OLAND, "AMD Radeon", kNull }, // Mobile + // { 0x6621, 0x00000000, CHIP_FAMILY_OLAND, "AMD Radeon", kNull }, // Mobile + // { 0x6623, 0x00000000, CHIP_FAMILY_OLAND, "AMD Radeon", kNull }, // Mobile + // { 0x6631, 0x00000000, CHIP_FAMILY_OLAND, "AMD Radeon", kNull }, + + // BONAIRE + { 0x6640, CHIP_FAMILY_BONAIRE, 1, 0, 0, 0, 0 },// "AMD Radeon HD 8950", kNull }, // Mobile + { 0x6641, CHIP_FAMILY_BONAIRE, 1, 0, 0, 0, 0 },// "AMD Radeon HD 8930M", kNull }, // Mobile + { 0x6646, CHIP_FAMILY_BONAIRE, 1, 0, 0, 0, 0 },// "AMD Radeon R9 M280X", kNull }, // Mobile + { 0x6647, CHIP_FAMILY_BONAIRE, 1, 0, 0, 0, 0 },// "AMD Radeon R9 M270X", kNull }, // Mobile + { 0x6649, CHIP_FAMILY_BONAIRE, 1, 0, 0, 0, 0 },// "AMD FirePro W5100", kNull }, + // { 0x6650, 0x00000000, CHIP_FAMILY_BONAIRE, "AMD Radeon", kNull }, + // { 0x6651, 0x00000000, CHIP_FAMILY_BONAIRE, "AMD Radeon", kNull }, + { 0x6658, CHIP_FAMILY_BONAIRE, 0, 0, 0, 0, 0 },// "AMD Radeon R7 260X", kNull }, + { 0x665C, CHIP_FAMILY_BONAIRE, 0, 0, 0, 0, 0 },// "AMD Radeon HD 7790", kFutomaki }, + { 0x665D, CHIP_FAMILY_BONAIRE, 0, 0, 0, 0, 0 },// "AMD Radeon R9 260", kFutomaki }, + { 0x665F, CHIP_FAMILY_BONAIRE, 0, 0, 0, 0, 0 },// "AMD Radeon R9 360", kFutomaki }, + // HAINAN + { 0x6660, CHIP_FAMILY_HAINAN, 1, 0, 0, 0, 0 },// "AMD Radeon HD 8670M", kNull }, // Mobile + { 0x6663, CHIP_FAMILY_HAINAN, 1, 0, 0, 0, 0 },// "AMD Radeon HD 8570M", kNull }, // Mobile + { 0x6664, CHIP_FAMILY_HAINAN, 1, 0, 0, 0, 0 },// "AMD Radeon R5 M240", kNull }, // Mobile + { 0x6665, CHIP_FAMILY_HAINAN, 1, 0, 0, 0, 0 },// "AMD Radeon R5 M230", kNull }, // Mobile + { 0x6667, CHIP_FAMILY_HAINAN, 1, 0, 0, 0, 0 },// "AMD Radeon R5 M230", kNull }, // Mobile + { 0x666F, CHIP_FAMILY_HAINAN, 1, 0, 0, 0, 0 },// "AMD Radeon HD 8550M", kNull }, // Mobile R5 M230 in Lenovo + + { 0x6701, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6702, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6703, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6704, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6705, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6706, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6707, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6708, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6709, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + + { 0x6718, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6719, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x671C, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x671D, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + + { 0x6720, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6721, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6722, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6723, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6724, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6725, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6726, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6727, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6728, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6729, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + + { 0x6738, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6739, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x673E, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6740, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6741, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6742, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6743, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6744, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6745, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6746, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6747, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6748, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6749, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + + { 0x6750, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6758, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6759, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x675F, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6760, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6761, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6762, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6763, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6764, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6765, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6766, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6767, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6768, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6770, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6779, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, +// CHIP_FAMILY_TAHITI + { 0x6780, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 }, + { 0x6781, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 }, + { 0x6790, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 }, + { 0x6798, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 }, + { 0x679A, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 }, + { 0x679E, CHIP_FAMILY_TAHITI, 0, 0, 0, 0, 0 }, +//Hawaii + { 0x67B0, CHIP_FAMILY_HAWAII, 0, 0, 0, 0, 0 }, + { 0x67B1, CHIP_FAMILY_HAWAII, 0, 0, 0, 0, 0 }, + { 0x67B8, CHIP_FAMILY_HAWAII, 0, 0, 0, 0, 0 }, + { 0x67B9, CHIP_FAMILY_HAWAII, 0, 0, 0, 0, 0 }, +//Pitcairn + { 0x6800, CHIP_FAMILY_PITCAIRN, 0, 0, 0, 0, 0 }, + { 0x6818, CHIP_FAMILY_PITCAIRN, 0, 0, 0, 0, 0 }, + { 0x6819, CHIP_FAMILY_PITCAIRN, 0, 0, 0, 0, 0 }, + { 0x6820, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 }, + { 0x6821, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 }, + { 0x6825, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 }, + { 0x6827, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 }, + { 0x682D, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 }, + { 0x682F, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 }, + { 0x6839, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 }, + { 0x683B, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 }, + { 0x683D, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 }, + { 0x683F, CHIP_FAMILY_VERDE, 0, 0, 0, 0, 0 }, + + { 0x6840, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6880, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x688D, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6888, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6889, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6890, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6898, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6899, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x689C, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x689D, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x689E, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68A0, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68A1, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68A8, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68A9, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68B0, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68B1, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68B8, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68B9, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68BE, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68C0, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68C1, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68C8, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68C9, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68D0, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68D1, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68D8, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68D9, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68DA, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68DE, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68E0, CHIP_FAMILY_Evergreen, 1, 0, 0, 0, 0 }, + { 0x68E1, CHIP_FAMILY_Evergreen, 1, 0, 0, 0, 0 }, + { 0x68E8, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68E9, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68F0, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68F1, CHIP_FAMILY_Evergreen, 1, 0, 0, 0, 0 }, + { 0x68F8, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68F9, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x68FE, CHIP_FAMILY_Evergreen, 0, 0, 0, 0, 0 }, + { 0x6900, CHIP_FAMILY_TONGA, 1, 0, 0, 0, 0 },// "ATI Radeon R7 M260/M265", kExmoor }, + { 0x6901, CHIP_FAMILY_TONGA, 1, 0, 0, 0, 0 },// "ATI Radeon R5 M255", kExmoor }, + { 0x6920, CHIP_FAMILY_TONGA, 1, 0, 0, 0, 0 },// "ATI Radeon R9 M395", kLabrador }, + { 0x6921, CHIP_FAMILY_TONGA, 1, 0, 0, 0, 0 },// "ATI Radeon R9 M295X", kExmoor }, + { 0x692b, CHIP_FAMILY_TONGA, 0, 0, 0, 0, 0 },// "ATI Firepro W7100", kBaladi }, + { 0x6938, CHIP_FAMILY_TONGA, 1, 0, 0, 0, 0 },// "ATI Radeon R9 M295X", kExmoor }, + { 0x6939, CHIP_FAMILY_TONGA, 0, 0, 0, 0, 0 },// "ATI Radeon R9 285", kBaladi }, + */ + + {0, 0, 0, 0, 0, 0, 0 }, +}; diff --git a/plugins/GPUSensors/RadeonMonitor/radeon_chipsets.h b/plugins/GPUSensors/RadeonMonitor/radeon_chipsets.h new file mode 100755 index 0000000..7b553a5 --- /dev/null +++ b/plugins/GPUSensors/RadeonMonitor/radeon_chipsets.h @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2006 Claudio Ciccani + * + * Graphics driver for ATI Radeon cards written by + * Claudio Ciccani . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __RADEON_CHIPSETS_H__ +#define __RADEON_CHIPSETS_H__ + +#include +#include "atombios.h" + +/* trinity */ +#define TN_SMC_IND_INDEX_0 0x200 +#define TN_SMC_IND_DATA_0 0x204 + +#define CG_MULT_THERMAL_STATUS 0x740 +#define ASIC_TM(x) ((x) << 16) +#define ASIC_TM_MASK 0x3FF0000 +#define ASIC_TM_SHIFT 16 +#define CG_THERMAL_STATUS 0x7F4 +#define ASIC_T(x) ((x) << 0) +#define ASIC_T_MASK 0x1FF +#define ASIC_T_SHIFT 0 +#define CG_SI_THERMAL_STATUS 0x714 +#define CTF_TEMP(x) ((x) << 9) +#define CTF_TEMP_MASK 0x0003fe00 +#define CTF_TEMP_SHIFT 9 + +#define CG_CI_MULT_THERMAL_STATUS 0xC0300014 +#define CI_ASIC_MAX_TEMP(x) ((x) << 0) +#define CI_ASIC_MAX_TEMP_MASK 0x000001ff +#define CI_ASIC_MAX_TEMP_SHIFT 0 +#define CI_CTF_TEMP(x) ((x) << 9) +#define CI_CTF_TEMP_MASK 0x0003fe00 +#define CI_CTF_TEMP_SHIFT 9 + +#define CG_KV_MULT_THERMAL_STATUS 0xC0300E0C +//actual_temp = (temp / 8) - 49; + +//for Polaris +#define PPSMC_MSG_API_GetSclkFrequency ((uint16_t) 0x200) +#define PPSMC_MSG_API_GetMclkFrequency ((uint16_t) 0x201) +#define PPSMC_MSG_API_GetSclkBusy ((uint16_t) 0x202) +#define PPSMC_MSG_API_GetMclkBusy ((uint16_t) 0x203) +#define PPSMC_MSG_API_GetAsicPower ((uint16_t) 0x204) +#define PPSMC_MSG_SetFanRpmMax ((uint16_t) 0x205) +#define PPSMC_MSG_SetFanSclkTarget ((uint16_t) 0x206) +#define PPSMC_MSG_SetFanMinPwm ((uint16_t) 0x209) +#define PPSMC_MSG_SetFanTemperatureTarget ((uint16_t) 0x20A) + +//linux 4.14 +//using byte addressing instead of Linux u32 addressing +#define mmSMC_IND_INDEX_11 (0x1AC * 4) +#define mmSMC_IND_DATA_11 (0x1AD * 4) +#define mmSMC_MSG_ARG_0 (0xA4 * 4) +//#define mmSMC_MESSAGE_0 (0x008B * 4) //smu_6 +#define mmSMC_MESSAGE_0 (0x94 * 4) /* SMU_7 */ +#define mmSMC_RESP_0 (0x95 * 4) /* SMU_7 */ + +//SeaIsland+ +#define SMC_IND_INDEX_0 0x200 +#define SMC_IND_DATA_0 0x204 + +#define mmPCIE_INDEX (0x000C * 4) +#define mmPCIE_DATA (0x000D * 4) + +//VEGA10 +#define mmTHM_TCON_CUR_TMP 0x59800 +#define THM_TCON_CUR_TMP__CUR_TEMP__SHIFT 24 + + +typedef struct { + UInt16 device_id; + UInt16 ChipFamily; + int is_mobility; + int igp; + int nocrtc2; + int nointtvout; + int singledac; +} RADEONCardInfo; + +/* +* Chip families. Must fit in the low 16 bits of a long word +*/ +enum radeon_family { + CHIP_FAMILY_UNKNOW, + CHIP_FAMILY_LEGACY, + CHIP_FAMILY_RADEON, + CHIP_FAMILY_RV100, + CHIP_FAMILY_RS100, /* U1 (IGP320M) or A3 (IGP320)*/ + CHIP_FAMILY_RV200, + CHIP_FAMILY_RS200, /* U2 (IGP330M/340M/350M) or A4 (IGP330/340/345/350), RS250 (IGP 7000) */ + CHIP_FAMILY_R200, + CHIP_FAMILY_RV250, + CHIP_FAMILY_RS300, /* RS300/RS350 */ + CHIP_FAMILY_RV280, + CHIP_FAMILY_R300, + CHIP_FAMILY_R350, + CHIP_FAMILY_RV350, + CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */ + CHIP_FAMILY_R420, /* R420/R423/M18 */ + CHIP_FAMILY_RV410, /* RV410, M26 */ + CHIP_FAMILY_RS400, /* xpress 200, 200m (RS400/410/480) */ + CHIP_FAMILY_RV515, /* rv515 */ + CHIP_FAMILY_R520, /* r520 */ + CHIP_FAMILY_RV530, /* rv530 */ + CHIP_FAMILY_R580, /* r580 */ + CHIP_FAMILY_RV560, /* rv560 */ + CHIP_FAMILY_RV570, /* rv570 */ + CHIP_FAMILY_RS690, + CHIP_FAMILY_R600, /* r60 */ + CHIP_FAMILY_R630, + CHIP_FAMILY_RV610, + CHIP_FAMILY_RV630, + CHIP_FAMILY_RV670, + CHIP_FAMILY_RS740, + CHIP_FAMILY_RV620, + CHIP_FAMILY_RV635, //HD3600 + CHIP_FAMILY_R700, //HD4850 + CHIP_FAMILY_RV700, //ATI Radeon HD 4870 X2 + CHIP_FAMILY_RV710, //Mobility Radeon HD 4300 + CHIP_FAMILY_R710, //HD4350 + CHIP_FAMILY_R730, //HD4650 + CHIP_FAMILY_RV740, //HD4770 + CHIP_FAMILY_RV770, //HD4830 + CHIP_FAMILY_RS780, //AMD 760G + CHIP_FAMILY_RV790, + CHIP_FAMILY_RS880, + CHIP_FAMILY_Evergreen, + CHIP_FAMILY_CEDAR, // + CHIP_FAMILY_REDWOOD, + CHIP_FAMILY_JUNIPER, + CHIP_FAMILY_CYPRESS, + CHIP_FAMILY_HEMLOCK, + CHIP_FAMILY_PITCAIRN, + CHIP_FAMILY_TAHITI, + CHIP_FAMILY_VERDE, + CHIP_FAMILY_HAWAII, + CHIP_FAMILY_OLAND, + CHIP_FAMILY_BONAIRE, + CHIP_FAMILY_HAINAN, + CHIP_FAMILY_TONGA, + CHIP_FAMILY_POLARIS, + CHIP_FAMILY_VEGA, + CHIP_FAMILY_LAST, +}; + +#define IS_RV100_VARIAN (((rinfo)->ChipFamily == CHIP_FAMILY_RV100) || \ + ((rinfo)->ChipFamily == CHIP_FAMILY_RV200) || \ + ((rinfo)->ChipFamily == CHIP_FAMILY_RS100) || \ + ((rinfo)->ChipFamily == CHIP_FAMILY_RS200) || \ + ((rinfo)->ChipFamily == CHIP_FAMILY_RV250) || \ + ((rinfo)->ChipFamily == CHIP_FAMILY_RV280) || \ + ((rinfo)->ChipFamily == CHIP_RS300)) + + +#define IS_R300_VARIANT (((rinfo)->ChipFamily == CHIP_FAMILY_R300) || \ + ((rinfo)->ChipFamily == CHIP_FAMILY_RV350) || \ + ((rinfo)->ChipFamily == CHIP_FAMILY_R350) || \ + ((rinfo)->ChipFamily == CHIP_FAMILY_RV380) || \ + ((rinfo)->ChipFamily == CHIP_FAMILY_R420)) + +#define IS_AVIVO_VARIANT ((rinfo->ChipFamily >= CHIP_FAMILY_RV515)) + +#define IS_DCE3_VARIANT ((rinfo->ChipFamily >= CHIP_FAMILY_RV620)) + +#define IS_R500_3D ((rinfo->ChipFamily == CHIP_FAMILY_RV515) || \ + (rinfo->ChipFamily == CHIP_FAMILY_R520) || \ + (rinfo->ChipFamily == CHIP_FAMILY_RV530) || \ + (rinfo->ChipFamily == CHIP_FAMILY_R580) || \ + (rinfo->ChipFamily == CHIP_FAMILY_RV560) || \ + (rinfo->ChipFamily == CHIP_FAMILY_RV570)) + +#define IS_R300_3D ((rinfo->ChipFamily == CHIP_FAMILY_R300) || \ + (rinfo->ChipFamily == CHIP_FAMILY_RV350) || \ + (rinfo->ChipFamily == CHIP_FAMILY_R350) || \ + (rinfo->ChipFamily == CHIP_FAMILY_RV380) || \ + (rinfo->ChipFamily == CHIP_FAMILY_R420) || \ + (rinfo->ChipFamily == CHIP_FAMILY_RV410) || \ + (rinfo->ChipFamily == CHIP_FAMILY_RS690) || \ + (rinfo->ChipFamily == CHIP_FAMILY_RS600) || \ + (rinfo->ChipFamily == CHIP_FAMILY_RS740) || \ + (rinfo->ChipFamily == CHIP_FAMILY_RS400) || \ + (rinfo->ChipFamily == CHIP_FAMILY_RS480)) + + +#endif /* __RADEON_CHIPSETS_H__ */ diff --git a/plugins/SMIMonitor/SMIMonitor-Info.plist b/plugins/SMIMonitor/SMIMonitor-Info.plist new file mode 100644 index 0000000..43b8d77 --- /dev/null +++ b/plugins/SMIMonitor/SMIMonitor-Info.plist @@ -0,0 +1,66 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + IOKitPersonalities + + SMI Monitoring Plugin + + CFBundleIdentifier + org.slice.${PRODUCT_NAME} + FanMultiplier + 1 + FanNames + + CPU Fan + System Fan + GPU Fan + PSU Fan + Chipset Fan + Other Fan + + IOClass + SMIMonitor + IOMatchCategory + ${PRODUCT_NAME} + IOProviderClass + IOResources + IOResourceMatch + IOKit + + + NSHumanReadableCopyright + Copyright © 2014 Slice. All rights reserved. + OSBundleLibraries + + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.mach + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + + diff --git a/plugins/SMIMonitor/SMIMonitor-Prefix.pch b/plugins/SMIMonitor/SMIMonitor-Prefix.pch new file mode 100644 index 0000000..269d3a2 --- /dev/null +++ b/plugins/SMIMonitor/SMIMonitor-Prefix.pch @@ -0,0 +1,4 @@ +// +// Prefix header for all source files of the 'SMIMonitor' target in the 'SMIMonitor' project +// + diff --git a/plugins/SMIMonitor/SMIMonitor.cpp b/plugins/SMIMonitor/SMIMonitor.cpp new file mode 100644 index 0000000..63e07fd --- /dev/null +++ b/plugins/SMIMonitor/SMIMonitor.cpp @@ -0,0 +1,700 @@ +/* + * SMIMonitor.cpp + * HWSensors + * + * Copyright 2014 Slice. All rights reserved. + * + */ + +#include "SMIMonitor.h" +#include "FakeSMC.h" +#include "utils.h" + +#ifndef Debug +#define Debug FALSE +#endif + +#define LogPrefix "SMIMonitor: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +#define super IOService +OSDefineMetaClassAndStructors(SMIMonitor, IOService) + +bool SMIMonitor::addSensor(const char* key, const char* type, unsigned int size) { + if (!key || !type) { + return false; + } + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, (void *)key, + (void *)type, + (void *)(size_t)size, + (void *)this)) { + WarningLog("Can't add key %s to fake SMC device, kext will not load", key); + return false; + } + return true; +} + +// for example addTachometer(0, "System Fan"); +bool SMIMonitor::addTachometer(int index, const char* id) { + UInt8 length = 0; + void * data = 0; + if (!id) { + return false; + } + + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, + true, + (void *)KEY_FAN_NUMBER, + (void *)&length, + (void *)&data, + 0)) { + char key[5]; + length = 0; + + bcopy(data, &length, 1); + + snprintf(key, 5, KEY_FORMAT_FAN_SPEED, length); + + if (addSensor(key, TYPE_FPE2, 2)) { + if (id) { + FanTypeDescStruct fds; + snprintf(key, 5, KEY_FORMAT_FAN_ID, length); + fds.type = FAN_PWM_TACH; + fds.ui8Zone = 1; + fds.location = LEFT_LOWER_FRONT; + strncpy(fds.strFunction, id, DIAG_FUNCTION_STR_LEN); + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyValue, + false, + (void *)key, + (void *)TYPE_FDESC, + (void *)((UInt64)sizeof(fds)), + (void *)&fds)) { + + WarningLog("error adding tachometer id value"); + } + } + + length++; + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCSetKeyValue, + true, + (void *)KEY_FAN_NUMBER, + (void *)1, + (void *)&length, + 0)) { + WarningLog("error updating FNum value"); + } + return true; + } + } else { + WarningLog("error reading FNum value"); + } + + return false; +} + + +SMMRegisters *globalRegs; +static int gRc; +//static int fanMult; +//inline +static +int smm(SMMRegisters *regs) +{ + + int rc; + int eax = regs->eax; //input value + +#if __LP64__ + asm volatile("pushq %%rax\n\t" + "movl 0(%%rax),%%edx\n\t" + "pushq %%rdx\n\t" + "movl 4(%%rax),%%ebx\n\t" + "movl 8(%%rax),%%ecx\n\t" + "movl 12(%%rax),%%edx\n\t" + "movl 16(%%rax),%%esi\n\t" + "movl 20(%%rax),%%edi\n\t" + "popq %%rax\n\t" + "out %%al,$0xb2\n\t" + "out %%al,$0x84\n\t" + "xchgq %%rax,(%%rsp)\n\t" + "movl %%ebx,4(%%rax)\n\t" + "movl %%ecx,8(%%rax)\n\t" + "movl %%edx,12(%%rax)\n\t" + "movl %%esi,16(%%rax)\n\t" + "movl %%edi,20(%%rax)\n\t" + "popq %%rdx\n\t" + "movl %%edx,0(%%rax)\n\t" + "pushfq\n\t" + "popq %%rax\n\t" + "andl $1,%%eax\n" + : "=a"(rc) + : "a"(regs) + : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); +#else + asm volatile("pushl %%eax\n\t" + "movl 0(%%eax),%%edx\n\t" + "push %%edx\n\t" + "movl 4(%%eax),%%ebx\n\t" + "movl 8(%%eax),%%ecx\n\t" + "movl 12(%%eax),%%edx\n\t" + "movl 16(%%eax),%%esi\n\t" + "movl 20(%%eax),%%edi\n\t" + "popl %%eax\n\t" + "out %%al,$0xb2\n\t" + "out %%al,$0x84\n\t" + "xchgl %%eax,(%%esp)\n\t" + "movl %%ebx,4(%%eax)\n\t" + "movl %%ecx,8(%%eax)\n\t" + "movl %%edx,12(%%eax)\n\t" + "movl %%esi,16(%%eax)\n\t" + "movl %%edi,20(%%eax)\n\t" + "popl %%edx\n\t" + "movl %%edx,0(%%eax)\n\t" + "lahf\n\t" + "shrl $8,%%eax\n\t" + "andl $1,%%eax\n" + : "=a"(rc) + : "a"(regs) + : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); +#endif + + if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) { + return -1; + } + + return 0; +} + +void read_smi(void * magic) { + SMMRegisters *regs = (SMMRegisters *)magic; + volatile UInt32 i = cpu_number(); + if (i == 0) { /* SMM requires CPU 0 */ + gRc = smm(regs); + } else gRc = -1; +} + +int SMIMonitor::i8k_smm(SMMRegisters *regs) +{ + mp_rendezvous_no_intrs(read_smi, (void *)regs); + return gRc; +} + +//not works +/* +int SMIMonitor::i8k_get_bios_version(void) { + INIT_REGS; + int rc; + + regs.eax = I8K_SMM_BIOS_VERSION; + if ((rc = i8k_smm(®s)) < 0) { + return rc; + } + return regs.eax; +} */ + +/* + * Read the CPU temperature in Celcius. + */ +int SMIMonitor::i8k_get_temp(int sensor) { + INIT_REGS; + int rc; + int temp; + + regs.eax = I8K_SMM_GET_TEMP; + regs.ebx = sensor & 0xFF; + if ((rc=i8k_smm(®s)) < 0) { + return rc; + } + + temp = regs.eax & 0xff; + if (temp == 0x99) { + IOSleep(100); + regs.eax = I8K_SMM_GET_TEMP; + regs.ebx = sensor & 0xFF; + if ((rc=i8k_smm(®s)) < 0) { + return rc; + } + temp = regs.eax & 0xff; + } + return temp; +} + +int SMIMonitor::i8k_get_temp_type(int sensor) { + INIT_REGS; + int rc; + int type; + + regs.eax = I8K_SMM_GET_TEMP_TYPE; + regs.ebx = sensor & 0xFF; + if ((rc=i8k_smm(®s)) < 0) { + return rc; + } + + type = regs.eax & 0xff; + return type; +} + +const char * SMIMonitor::getKeyForTemp(int type) { +// int type = i8k_get_temp_type(sensor); + switch (type) { + case I8K_SMM_TEMP_CPU: + return KEY_CPU_PROXIMITY_TEMPERATURE; + case I8K_SMM_TEMP_GPU: + return KEY_GPU_PROXIMITY_TEMPERATURE; + case I8K_SMM_TEMP_MEMORY: + return KEY_DIMM_TEMPERATURE; + case I8K_SMM_TEMP_MISC: + return KEY_NORTHBRIDGE_TEMPERATURE; + case I8K_SMM_TEMP_AMBIENT: + return KEY_AMBIENT_TEMPERATURE; // + case I8K_SMM_TEMP_OTHER: + return KEY_AIRPORT_TEMPERATURE; + default: + break; + } + return NULL; +} + +bool SMIMonitor::i8k_get_dell_sig_aux(int fn) { + INIT_REGS; + int rc; + + regs.eax = fn; + if ((rc=i8k_smm(®s)) < 0) { + WarningLog("No function 0x%x", fn); + return false; + } + InfoLog("Got sigs %x and %x", regs.eax, regs.edx); + return ((regs.eax == 0x44494147 /*DIAG*/) && + (regs.edx == 0x44454C4C /*DELL*/)); +} + +bool SMIMonitor::i8k_get_dell_signature(void) { + + return (i8k_get_dell_sig_aux(I8K_SMM_GET_DELL_SIG1) || + i8k_get_dell_sig_aux(I8K_SMM_GET_DELL_SIG2)); +} + + +/* + * Read the power status. + */ +int SMIMonitor::i8k_get_power_status(void) { + INIT_REGS; + int rc; + /* + regs.eax = I8K_SMM_GET_POWER_TYPE; + i8k_smm(®s); + InfoLog("Got power type=%d", (regs.eax & 0xff)); + */ + regs.eax = I8K_SMM_GET_POWER_TYPE; //I8K_SMM_GET_POWER_STATUS; + if ((rc=i8k_smm(®s)) < 0) { + WarningLog("No power status"); + return rc; + } + InfoLog("Got power status=%d", (regs.eax & 0xff)); + return regs.eax & 0xff; // 0 = No Batt, 3 = No AC, 1 = Charging, 5 = Full. +} + +/* + * Read the fan speed in RPM. + */ +int SMIMonitor::i8k_get_fan_speed(int fan) { + INIT_REGS; + int rc; + int speed = 0; + + regs.eax = I8K_SMM_GET_SPEED; + regs.ebx = fan & 0xff; + if ((rc=i8k_smm(®s)) < 0) { + return rc; + } + speed = (regs.eax & 0xffff) * fanMult; + return speed; +} + +/* + * Read the fan status. + */ +int SMIMonitor::i8k_get_fan_status(int fan) { + INIT_REGS; + int rc; + + regs.eax = I8K_SMM_GET_FAN; + regs.ebx = fan & 0xff; + if ((rc=i8k_smm(®s)) < 0) { + return rc; + } + + return (regs.eax & 0xff); +} + +/* + * Read the fan status. + */ +int SMIMonitor::i8k_get_fan_type(int fan) { + INIT_REGS; + int rc; + + regs.eax = I8K_SMM_GET_FAN_TYPE; + regs.ebx = fan & 0xff; + if ((rc=i8k_smm(®s)) < 0) { + return rc; + } + + return (regs.eax & 0xff); +} + + +/* + * Read the fan nominal rpm for specific fan speed (0,1,2) or zero + */ +int SMIMonitor::i8k_get_fan_nominal_speed(int fan, int speed) +{ + INIT_REGS; + regs.eax = I8K_SMM_GET_NOM_SPEED; + regs.ebx = (fan & 0xff) | (speed << 8); + return i8k_smm(®s) ? 0 : (regs.eax & 0xffff) * fanMult; +} + +/* + * Set the fan speed (off, low, high). Returns the new fan status. + */ +int SMIMonitor::i8k_set_fan(int fan, int speed) +{ + INIT_REGS; + regs.eax = I8K_SMM_SET_FAN; + + speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); + regs.ebx = (fan & 0xff) | (speed << 8); + + return i8k_smm(®s) ? -1 : i8k_get_fan_status(fan); +} + +int SMIMonitor::i8k_set_fan_control_manual(int fan) +{ + INIT_REGS; + regs.eax = I8K_SMM_IO_DISABLE_FAN_CTL1; + regs.ebx = (fan & 0xff); + return i8k_smm(®s); +} + +int SMIMonitor::i8k_set_fan_control_auto(int fan) +{ + INIT_REGS; + regs.eax = I8K_SMM_IO_ENABLE_FAN_CTL1; + regs.ebx = (fan & 0xff); + return i8k_smm(®s); +} + + +IOService* SMIMonitor::probe(IOService *provider, SInt32 *score) { + if (super::probe(provider, score) != this) { return 0; } + + if (!i8k_get_dell_signature()) { + WarningLog("Unable to get Dell SMM signature!"); + return NULL; + } + + InfoLog("Based on I8kfan project adopted to HWSensors by Slice 2014"); +#if TEST + InfoLog("Dell BIOS version=%x", i8k_get_bios_version()); + InfoLog("Dump SMI ------------"); + INIT_REGS; + int rc; + + regs.eax = I8K_SMM_POWER_STATUS; + rc=i8k_smm(®s); + InfoLog("POWER_STATUS: rc=0x%x eax=0x%x", rc, regs.eax); + + for (int i=0; i<6; i++) { + memset(®s, 0, sizeof(regs)); + regs.eax = I8K_SMM_GET_FAN; + regs.ebx = i; + rc=i8k_smm(®s); + InfoLog("GET_FAN %d: rc=0x%x eax=0x%x", i, rc, regs.eax); + memset(®s, 0, sizeof(regs)); + if (rc < 0) continue; + regs.eax = I8K_SMM_FN_STATUS; + regs.ebx = i; + rc=i8k_smm(®s); + InfoLog("FN_STATUS %d: rc=0x%x eax=0x%x", i, rc, regs.eax); + if (rc < 0) continue; + memset(®s, 0, sizeof(regs)); + regs.eax = I8K_SMM_GET_FAN_TYPE; + regs.ebx = i; + rc=i8k_smm(®s); + InfoLog("GET_FAN_TYPE: rc=0x%x eax=0x%x", rc, regs.eax); + memset(®s, 0, sizeof(regs)); + regs.eax = I8K_SMM_GET_SPEED; + regs.ebx = i; + rc=i8k_smm(®s); + InfoLog("GET_SPEED: rc=0x%x eax=0x%x", rc, regs.eax); + memset(®s, 0, sizeof(regs)); + regs.eax = I8K_SMM_GET_NOM_SPEED; + regs.ebx = i; + rc=i8k_smm(®s); + InfoLog("GET_NOM_SPEED: rc=0x%x eax=0x%x", rc, regs.eax); + } + + for (int i=0; i<6; i++) { + memset(®s, 0, sizeof(regs)); + regs.eax = I8K_SMM_GET_TEMP; + regs.ebx = i; + rc=i8k_smm(®s); + if (rc < 0) continue; + InfoLog("GET_TEMP %d: rc=0x%x eax=0x%x", i, rc, regs.eax); + } +#endif + + i8k_get_power_status(); + + return this; +} + +bool SMIMonitor::start(IOService * provider) +{ + INIT_REGS; + int rc = 0; + if (!provider || !super::start(provider)) { return false; } + + if (!(fakeSMC = waitForService(serviceMatching(kFakeSMCDeviceService)))) { + WarningLog("Can't locate fake SMC device, kext will not load"); + return false; + } + + char key[5]; + + //Here are Fans in info.plist + OSArray* fanNames = OSDynamicCast(OSArray, getProperty("FanNames")); + fanNum = 0; + fansStatus = 0; + for (int fan = 0; fan < 6; fan++) { + + memset(®s, 0, sizeof(regs)); + regs.eax = I8K_SMM_GET_FAN; + regs.ebx = fan; + rc = i8k_smm(®s); + if (rc < 0) continue; //laptop has one fan, but desktop 0 and 2; continue search + i8k_set_fan_control_auto(fan); //force automatic control + + fanNum++; + snprintf(key, 5, "FAN%X", fan); + int fType = i8k_get_fan_type(fan); + InfoLog("found fan %d type %d", fan, fType); + if (fType < 0) { + fType = fan; + } + InfoLog(" min speed %d", i8k_get_fan_nominal_speed(fan, 1)); + InfoLog(" max speed %d", i8k_get_fan_nominal_speed(fan, 2)); + + OSString* name = NULL; + if (fanNames) { + name = OSDynamicCast(OSString, fanNames->getObject(fType)); + } + + if (!addTachometer(fan, name ? name->getCStringNoCopy() : 0)) { + WarningLog("Can't add tachometer sensor, key %s", key); + } + snprintf(key, 5, KEY_FORMAT_FAN_MIN_SPEED, fan); + addSensor(key, TYPE_FPE2, 2); //F0Mn + snprintf(key, 5, KEY_FORMAT_FAN_MAX_SPEED, fan); + addSensor(key, TYPE_FPE2, 2); //F0Mm + + //add special key for fan status control + snprintf(key, 5, "F%XAs", fan); + addSensor(key, TYPE_UI8, 1); //F0As + // individual fan control + snprintf(key, 5, KEY_FORMAT_FAN_MANUAL_DRIVE, fan); + addSensor(key, TYPE_UI8, 1); //F0As + } + snprintf(key, 5, KEY_FAN_FORCE); + addSensor(key, TYPE_UI16, 2); //FS! + + for (int i=0; i<6; i++) { + rc = i8k_get_temp(i); + if (rc >= 0) { + int type = i8k_get_temp_type(i); + if ((type >= I8K_SMM_TEMP_CPU) && (type <= I8K_SMM_TEMP_OTHER)) { + TempSensors[type] = i; + InfoLog("sensor %d type %d", i, type); + addSensor(getKeyForTemp(type), TYPE_SP78, 2); + } + } + } + + registerService(0); + return true; +} + +bool SMIMonitor::init(OSDictionary *properties) { + if (!super::init(properties)) { + return false; + } + if (!(sensors = OSDictionary::withCapacity(0))) { + return false; + } + fanMult = 1; //linux proposed to get nominal speed and if it high then change multiplier + OSNumber * Multiplier = OSDynamicCast(OSNumber, properties->getObject("FanMultiplier")); + if (Multiplier) + fanMult = Multiplier->unsigned32BitValue(); + return true; +} + +void SMIMonitor::stop(IOService* provider) { + sensors->flushCollection(); + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCRemoveKeyHandler, + true, + this, + NULL, + NULL, + NULL)) { + WarningLog("Can't remove key handler"); + IOSleep(500); + } + + super::stop(provider); +} + +void SMIMonitor::free() { + sensors->release(); + super::free(); +} + +#define MEGA10 10000000ull +IOReturn SMIMonitor::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4) { + const char* name = (const char*)param1; + UInt8 * data = (UInt8*)param2; + // UInt64 size = (UInt64)param3; + + size_t value; + UInt16 val; + + if (functionName->isEqualTo(kFakeSMCSetValueCallback)) { + if (name && data) { + InfoLog("Writing key=%s value=%x", name, *(UInt8*)data); + //OSObject * params[1]; + if ((name[0] == 'F') && (name[2] == 'A') && (name[3] == 's')) { //set fan status {off, low, high} + val = *(UInt8*)data & 3; //restrict possible values to 0,1,2,3 + int fan = (int)(name[1] - '0'); + int ret = i8k_set_fan(fan, val); //return new status, should we check it? + if (ret == val) { + return kIOReturnSuccess; + } + else { + return kIOReturnError; + } + } + else if ((name[0] == 'F') && (name[1] == 'S') && (name[2] == '!')) { + val = (data[0] << 8) + data[1]; //big endian data + int rc = 0; + for (int i = 0; i < fanNum; i++) { + if ((val & (1 << i)) != (fansStatus & (1 << i))) { + rc |= (val & (1 << i)) ? i8k_set_fan_control_manual(i) : i8k_set_fan_control_auto(i); + } + } + if (!rc) { + fansStatus = val; + return kIOReturnSuccess; + } + else { + return kIOReturnError; + } + } + else if ((name[0] == 'F') && (name[2] == 'M') && (name[3] == 'd')) { + val = data[0]; + int fan = (int)(name[1] - '0') & 0x7; //restrict to 7 fans + int rc = 0; + if (val != (fansStatus & (1 << fan))>>fan) { + rc |= val ? i8k_set_fan_control_manual(fan) : i8k_set_fan_control_auto(fan); + } + if (!rc) { + fansStatus = val ? (fansStatus | (1 << fan)): (fansStatus & ~(1 << fan)); + return kIOReturnSuccess; + } + else { + return kIOReturnError; + } + } } + return kIOReturnBadArgument; + } + + if (functionName->isEqualTo(kFakeSMCGetValueCallback)) { + if (name && data) { + val = 0; + if (name[0] == 'F') { + if ((name[2] == 'A') && (name[3] == 'c')) { + int fan = (int)(name[1] - '0'); + value = i8k_get_fan_speed(fan); + val = encode_fpe2(value); + bcopy(&val, data, 2); + return kIOReturnSuccess; + } + else if ((name[2] == 'A') && (name[3] == 's')) { + int fan = (int)(name[1] - '0'); + val = i8k_get_fan_status(fan); + bcopy(&val, data, 1); + return kIOReturnSuccess; + } + else if ((name[1] == 'S') && (name[2] == '!')) { + val = fansStatus; + data[0] = val >> 8; + data[1] = val & 0xFF; + return kIOReturnSuccess; + } + else if ((name[2] == 'M') && (name[3] == 'd')) { + int fan = (int)(name[1] - '0') & 0x7; + val = (fansStatus & (1 << fan)) >> fan; + bcopy(&val, data, 1); + return kIOReturnSuccess; + } + else if ((name[2] == 'M') && (name[3] == 'n')) { + int fan = (int)(name[1] - '0') & 0x7; + value = i8k_get_fan_nominal_speed(fan, 1); + val = encode_fpe2(value); + bcopy(&val, data, 2); + return kIOReturnSuccess; + } + else if ((name[2] == 'M') && (name[3] == 'm')) { + int fan = (int)(name[1] - '0') & 0x7; + value = i8k_get_fan_nominal_speed(fan, 2); + val = encode_fpe2(value); + bcopy(&val, data, 2); + return kIOReturnSuccess; + } + } else if ((name[0] == 'T') && (name[2] == '0') && (name[3] == 'P')) { + if (name[1] == 'C') { + val = i8k_get_temp(TempSensors[I8K_SMM_TEMP_CPU]); + } else if (name[1] == 'G') { + val = i8k_get_temp(TempSensors[I8K_SMM_TEMP_GPU]); + } else if (name[1] == 'm') { + val = i8k_get_temp(TempSensors[I8K_SMM_TEMP_MEMORY]); + } else if (name[1] == 'N') { + val = i8k_get_temp(TempSensors[I8K_SMM_TEMP_MISC]); + } else if (name[1] == 'A') { + val = i8k_get_temp(TempSensors[I8K_SMM_TEMP_AMBIENT]); + } else if (name[1] == 'W') { + val = i8k_get_temp(TempSensors[I8K_SMM_TEMP_OTHER]); + } + bcopy(&val, data, 1); + return kIOReturnSuccess; + } + return kIOReturnBadArgument; //no key or no pointer to data + } + //DebugLog("bad argument key name or data"); + return kIOReturnBadArgument; + } + + return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); +} + diff --git a/plugins/SMIMonitor/SMIMonitor.h b/plugins/SMIMonitor/SMIMonitor.h new file mode 100644 index 0000000..523eb68 --- /dev/null +++ b/plugins/SMIMonitor/SMIMonitor.h @@ -0,0 +1,144 @@ +/* + * SMIMonitor.h + * HWSensors + * + * Copyright (C) 2001 Massimo Dal Zotto + * http://www.debian.org/~dz/i8k/ + * more work https://www.diefer.de/i8kfan/index.html , 2007 + * + * FakeSMC plugin created by Slice 2014. + * + */ + +#include +#include "IOKit/acpi/IOACPIPlatformDevice.h" +#include +#include + +#define I8K_SMM_FN_STATUS 0x0025 +#define I8K_SMM_POWER_STATUS 0x0069 /* 0x85*/ /* not confirmed*/ +#define I8K_SMM_SET_FAN 0x01a3 +#define I8K_SMM_GET_FAN 0x00a3 +#define I8K_SMM_GET_SPEED 0x02a3 +#define I8K_SMM_GET_FAN_TYPE 0x03a3 +#define I8K_SMM_GET_NOM_SPEED 0x04a3 +#define I8K_SMM_GET_TOLERANCE 0x05a3 +#define I8K_SMM_GET_TEMP 0x10a3 +#define I8K_SMM_GET_TEMP_TYPE 0x11a3 +//0x12a3 arg 0x0003=NBSVC-Query +// arg 0x0000 = NBSVC - Clear +// arg 0x122 = NBSVC - Start Trend +// arg 0x0100 = NBSVC - Stop Trend +// arg 0x02 ? ? = NBSVC - Read +//0x21a3 ??? (2 args: 1 byte (oder 0x16) + 1 byte) +#define I8K_SMM_GET_POWER_TYPE 0x22a3 +//0x23a3 ??? (4 args: 2x 1 byte, 1xword, 1xdword) +#define I8K_SMM_GET_POWER_STATUS 0x24a3 +#define I8K_SMM_IO_DISABLE_FAN_CTL1 0x30a3 //No automatic speed control, arg = 0? fan? +#define I8K_SMM_IO_ENABLE_FAN_CTL1 0x31a3 +#define I8K_SMM_ENABLE_FN 0x32a3 +#define I8K_SMM_IO_DISABLE_FAN_CTL2 0x34a3 //A complete strike. no command. +#define I8K_SMM_IO_ENABLE_FAN_CTL2 0x35a3 +//0x36a3 get hotkey scancode list (args see diags) +#define I8K_SMM_GET_DOCK_STATE 0x40a3 +#define I8K_SMM_GET_DELL_SIG1 0xfea3 +#define I8K_SMM_GET_DELL_SIG2 0xffa3 +#define I8K_SMM_BIOS_VERSION 0x00a6 /* not confirmed*/ + +// GET_TEMP_TYPE result codes +#define I8K_SMM_TEMP_CPU 0 +#define I8K_SMM_TEMP_GPU 1 +#define I8K_SMM_TEMP_MEMORY 2 +#define I8K_SMM_TEMP_MISC 3 +#define I8K_SMM_TEMP_AMBIENT 4 +#define I8K_SMM_TEMP_OTHER 5 + +#define I8K_FAN_MULT 30 +#define I8K_MAX_TEMP 127 + +#define I8K_FAN_PROCESSOR 0 +#define I8K_FAN_SYSTEM 1 +#define I8K_FAN_GPU 2 +#define I8K_FAN_PSU 3 +#define I8K_FAN_CHIPSET 4 + +#define I8K_FAN_OFF 0 +#define I8K_FAN_LOW 1 +#define I8K_FAN_HIGH 2 +#define I8K_FAN_MAX I8K_FAN_HIGH + +#define I8K_POWER_AC 0x05 +#define I8K_POWER_BATTERY 0x01 +#define I8K_AC 1 +#define I8K_BATTERY 0 + +#define I8K_FN_NONE 0x00 +#define I8K_FN_UP 0x01 +#define I8K_FN_DOWN 0x02 +#define I8K_FN_MUTE 0x04 +#define I8K_FN_MASK 0x07 +#define I8K_FN_SHIFT 8 + +typedef struct { + unsigned int eax; + unsigned int ebx __attribute__ ((packed)); + unsigned int ecx __attribute__ ((packed)); + unsigned int edx __attribute__ ((packed)); + unsigned int esi __attribute__ ((packed)); + unsigned int edi __attribute__ ((packed)); +} SMMRegisters; + +#define INIT_REGS SMMRegisters regs = { 0, 0, 0, 0, 0, 0 } + +extern "C" { + void mp_rendezvous_no_intrs(void (*action_func)(void *), void * arg); + int cpu_number(void); +}; + + +class SMIMonitor : public IOService +{ + OSDeclareDefaultStructors(SMIMonitor) +private: + IOService* fakeSMC; + IOACPIPlatformDevice * acpiDevice; + OSDictionary* sensors; + int fanMult; + int fanNum; + UInt16 fansStatus; + int TempSensors[6]; + + bool addSensor(const char* key, const char* type, unsigned int size); + bool addTachometer(int index, const char* caption); + + int i8k_smm(SMMRegisters *regs); +// int i8k_get_bios_version(void); + bool i8k_get_dell_sig_aux(int fn); + bool i8k_get_dell_signature(void); + int i8k_get_temp(int sensor); + int i8k_get_temp_type(int sensor); + int i8k_get_power_status(void); + int i8k_get_fan_speed(int fan); + int i8k_get_fan_status(int fan); + int i8k_get_fan_type(int fan); + int i8k_get_fan_nominal_speed(int fan, int speed); + int i8k_set_fan(int fan, int speed); + int i8k_set_fan_control_manual(int fan); + int i8k_set_fan_control_auto(int fan); + const char * getKeyForTemp(int sensor); + + +public: + virtual IOService* probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual bool init(OSDictionary *properties=0); + virtual void free(void); + virtual void stop(IOService *provider); + + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); +}; diff --git a/plugins/SMIMonitor/en.lproj/InfoPlist.strings b/plugins/SMIMonitor/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/plugins/SMIMonitor/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/plugins/SuperIOSensors/Fintek718x/F718x-Info.plist b/plugins/SuperIOSensors/Fintek718x/F718x-Info.plist new file mode 100644 index 0000000..e56001b --- /dev/null +++ b/plugins/SuperIOSensors/Fintek718x/F718x-Info.plist @@ -0,0 +1,68 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + IOKitPersonalities + + Fintek F718x Monitor Plugin + + CFBundleIdentifier + org.mozodojo.${PRODUCT_NAME} + IOClass + F718x + IOMatchCategory + F718x + IOProbeScore + 3000 + IOProviderClass + IOResources + IOResourceMatch + IOKit + Sensors Configuration + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + + + + OSBundleLibraries + + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.mach + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + OSBundleRequired + Root + + diff --git a/plugins/SuperIOSensors/Fintek718x/F718x-pre106-Info.plist b/plugins/SuperIOSensors/Fintek718x/F718x-pre106-Info.plist new file mode 100644 index 0000000..6a1e287 --- /dev/null +++ b/plugins/SuperIOSensors/Fintek718x/F718x-pre106-Info.plist @@ -0,0 +1,66 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.mozodojo.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + IOKitPersonalities + + Fintek F718x Monitor Plugin + + CFBundleIdentifier + org.mozodojo.${PRODUCT_NAME} + IOClass + F718x + IOProbeScore + 3000 + IOMatchCategory + F718x + IOProviderClass + IOResources + IOResourceMatch + IOKit + Sensors Configuration + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + + + + OSBundleLibraries + + org.netkas.FakeSMC + 3.1.0 + com.apple.kernel.6.0 + 7.9.9 + com.apple.kernel.iokit + 7.9.9 + com.apple.kernel.libkern + 7.9.9 + + OSBundleRequired + Root + + diff --git a/plugins/SuperIOSensors/Fintek718x/F718x.cpp b/plugins/SuperIOSensors/Fintek718x/F718x.cpp new file mode 100644 index 0000000..5cbf4f3 --- /dev/null +++ b/plugins/SuperIOSensors/Fintek718x/F718x.cpp @@ -0,0 +1,306 @@ +/* + * F718x.cpp + * HWSensors + * + * Created by mozo on 16/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +#include "FakeSMC.h" +#include "F718x.h" +#include + +#define Debug FALSE + +#define LogPrefix "F718x: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +#define super SuperIOMonitor +OSDefineMetaClassAndStructors(F718x, SuperIOMonitor) + +UInt8 F718x::readByte(UInt8 reg) { + outb(address + FINTEK_ADDRESS_REGISTER_OFFSET, reg); + return inb(address + FINTEK_DATA_REGISTER_OFFSET); +} + +long F718x::readTemperature(unsigned long index) { + float value; + + switch (model) { + case F71858: { + int tableMode = 0x3 & readByte(FINTEK_TEMPERATURE_CONFIG_REG); + int high = readByte(FINTEK_TEMPERATURE_BASE_REG + 2 * index); + int low = readByte(FINTEK_TEMPERATURE_BASE_REG + 2 * index + 1); + + if (high != 0xbb && high != 0xcc) { + int bits = 0; + + switch (tableMode) { + case 0: bits = 0; break; + case 1: bits = 0; break; + case 2: bits = (high & 0x80) << 8; break; + case 3: bits = (low & 0x01) << 15; break; + } + bits |= high << 7; + bits |= (low & 0xe0) >> 1; + + short val = (short)(bits & 0xfff0); + + return (float)val / 128.0f; + } else { + return 0; + } + } + break; + default: { + value = readByte(FINTEK_TEMPERATURE_BASE_REG + 2 * (index + 1)); + } + break; + } + + return value; +} + +long F718x::readVoltage(unsigned long index) { + //UInt16 raw = readByte(FINTEK_VOLTAGE_BASE_REG + index); + //if (index == 0) m_RawVCore = raw; + + float V = (index == 1 ? 0.5f : 1.0f) * (readByte(FINTEK_VOLTAGE_BASE_REG + index) << 4); // * 0.001f Exclude by trauma + + return V; +} + +long F718x::readTachometer(unsigned long index) { + int value = readByte(FINTEK_FAN_TACHOMETER_REG[index]) << 8; + value |= readByte(FINTEK_FAN_TACHOMETER_REG[index] + 1); + + if (value > 0) { + value = (value < 0x0fff) ? 1.5e6f / value : 0; + } + + return value; +} + + +void F718x::enter() { + outb(registerPort, 0x87); + outb(registerPort, 0x87); +} + +void F718x::exit() { + outb(registerPort, 0xAA); + outb(registerPort, SUPERIO_CONFIGURATION_CONTROL_REGISTER); + outb(valuePort, 0x02); +} + +bool F718x::probePort() { + UInt8 logicalDeviceNumber = 0; + + UInt8 id = listenPortByte(FINTEK_CHIP_ID_REGISTER); + UInt8 revision = listenPortByte(FINTEK_CHIP_REVISION_REGISTER); + + if (id == 0 || id == 0xff || revision == 0 || revision == 0xff) { + return false; + } + + switch (id) { + case 0x05: { + switch (revision) { + case 0x07: + model = F71858; + logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN; + break; + case 0x41: + model = F71882; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + } + break; + case 0x06: { + switch (revision) { + case 0x01: + model = F71862; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + } + break; + case 0x07: { + switch (revision) { + case 0x23: + model = F71889F; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + } + break; + case 0x08: { + switch (revision) { + case 0x14: + model = F71869; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + } + break; + case 0x09: { + switch (revision) { + case 0x01: /*Add F71808 */ + model = F71808; /*Add F71808 */ + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; /*Add F71808 */ + break; /*Add F71808 */ + case 0x09: + model = F71889ED; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + } + break; + case 0x10: { + switch (revision) { + case 0x05: + model = F71889AD; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + } + break; + case 0x11: { + switch (revision) { + case 0x06: + model = F71868A; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + } + break; + } + + if (!model) { + InfoLog("Fintek: Found unsupported chip ID=0x%x REVISION=0x%x", id, revision); + return false; + } + + selectLogicalDevice(logicalDeviceNumber); + + if (!getLogicalDeviceAddress()) { + return false; + } + + return true; +} + +const char *F718x::getModelName() { + switch (model) { + case F71858: return "F71858"; + case F71862: return "F71862"; + case F71869: return "F71869"; + case F71882: return "F71882"; + case F71889ED: return "F71889ED"; + case F71889AD: return "F71889AD"; + case F71889F: return "F71889F"; + case F71808: return "F71808"; + } + + return "unknown"; +} + +bool F718x::init(OSDictionary *properties) { + //DebugLog("initialising..."); + if (!super::init(properties)) { + return false; + } + + return true; +} + +IOService* F718x::probe(IOService *provider, SInt32 *score) { + // DebugLog("probing..."); + + if (super::probe(provider, score) != this) { + return 0; + } + + InfoLog("based on code from Open Hardware Monitor project by Michael Möller (C) 2010"); + InfoLog("mozodojo (C) 2011"); + + return this; +} + +bool F718x::start(IOService * provider) { + DebugLog("starting..."); + + if (!super::start(provider)) { + return false; + } + + InfoLog("found Fintek %s", getModelName()); + + OSDictionary* configuration = OSDynamicCast(OSDictionary, getProperty("Sensors Configuration")); + + // Heatsink + if (!addSensor(KEY_CPU_HEATSINK_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 0)) { + WarningLog("error adding heatsink temperature sensor"); + } + // Northbridge + if (!addSensor(KEY_NORTHBRIDGE_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 1)) { + WarningLog("error adding system temperature sensor"); + } + + // Voltage + switch (model) { + case F71858: + break; + default: + // CPU Vcore + if (!addSensor(KEY_CPU_VOLTAGE_RAW, TYPE_FP2E, 2, kSuperIOVoltageSensor, 1)) { + WarningLog("error adding CPU voltage sensor"); + } + break; + } + + // Tachometers + for (int i = 0; i < (model == F71882 ? 4 : 3); i++) { + OSString* name = 0; + + if (configuration) { + char key[7]; + snprintf(key, 7, "FANIN%X", i); + name = OSDynamicCast(OSString, configuration->getObject(key)); + } + + size_t nameLength = name ? strlen(name->getCStringNoCopy()) : 0; + + if (readTachometer(i) > 10 || nameLength > 0) { + if (!addTachometer(i, (nameLength > 0 ? name->getCStringNoCopy() : 0))) { + WarningLog("error adding tachometer sensor %d", i); + } + } + } + + return true; +} + +void F718x::stop(IOService* provider) { +// DebugLog("stoping..."); + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCRemoveKeyHandler, + true, + this, + NULL, + NULL, + NULL)) { + WarningLog("Can't remove key handler"); + IOSleep(500); + } + + super::stop(provider); +} + +void F718x::free() { + //DebugLog("freeing..."); + super::free(); +} diff --git a/plugins/SuperIOSensors/Fintek718x/F718x.h b/plugins/SuperIOSensors/Fintek718x/F718x.h new file mode 100644 index 0000000..0880aae --- /dev/null +++ b/plugins/SuperIOSensors/Fintek718x/F718x.h @@ -0,0 +1,78 @@ +/* + * F718x.h + * HWSensors + * + * Created by mozo on 16/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +#include +#include +#include +#include +#include + + +#include "SuperIOFamily.h" + +// Registers +const UInt8 FINTEK_CONFIGURATION_CONTROL_REGISTER = 0x02; +const UInt8 FINTEK_DEVCIE_SELECT_REGISTER = 0x07; +const UInt8 FINTEK_CHIP_ID_REGISTER = 0x20; +const UInt8 FINTEK_CHIP_REVISION_REGISTER = 0x21; +const UInt8 FINTEK_BASE_ADDRESS_REGISTER = 0x60; + +const UInt8 FINTEK_VENDOR_ID_REGISTER = 0x23; +const UInt16 FINTEK_VENDOR_ID = 0x1934; +const UInt8 F71858_HARDWARE_MONITOR_LDN = 0x02; +const UInt8 FINTEK_HARDWARE_MONITOR_LDN = 0x04; + +// Hardware Monitor +const UInt8 FINTEK_ADDRESS_REGISTER_OFFSET = 0x05; +const UInt8 FINTEK_DATA_REGISTER_OFFSET = 0x06; + +// Hardware Monitor Registers +const UInt8 FINTEK_VOLTAGE_BASE_REG = 0x20; +const UInt8 FINTEK_TEMPERATURE_CONFIG_REG = 0x69; +const UInt8 FINTEK_TEMPERATURE_BASE_REG = 0x70; +const UInt8 FINTEK_FAN_TACHOMETER_REG[] = { 0xA0, 0xB0, 0xC0, 0xD0 }; + +enum F718xMode { + F71858 = 0x0507, + F71862 = 0x0601, + F71869 = 0x0814, + F71882 = 0x0541, + F71889ED = 0x0909, + F71889F = 0x0723, + F71808 = 0x0901, + F71889AD = 0x1005, + F71868A = 0x1106, +}; + +class F718x : public SuperIOMonitor { + OSDeclareDefaultStructors(F718x) + +private: + char vendor[40]; + char product[40]; + + UInt8 readByte(UInt8 reg); + + virtual bool probePort(); + virtual void enter(); + virtual void exit(); + + virtual long readTemperature(unsigned long index); + virtual long readVoltage(unsigned long index); + virtual long readTachometer(unsigned long index); + + virtual const char * getModelName(); + +public: + virtual bool init(OSDictionary *properties=0); + virtual IOService* probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual void stop(IOService *provider); + virtual void free(void); +}; diff --git a/plugins/SuperIOSensors/ITE87x/ITEIT87x-Info.plist b/plugins/SuperIOSensors/ITE87x/ITEIT87x-Info.plist new file mode 100755 index 0000000..333a271 --- /dev/null +++ b/plugins/SuperIOSensors/ITE87x/ITEIT87x-Info.plist @@ -0,0 +1,2069 @@ + + + + + BuildMachineOSBuild + 11D50b + CFBundleDevelopmentRegion + English + CFBundleExecutable + ITEIT87x + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + DTCompiler + 4.2 + DTPlatformBuild + 4D502 + DTPlatformVersion + GM + DTSDKBuild + 11D50b + DTSDKName + + DTXcode + 0421 + DTXcodeBuild + 4D502 + IOKitPersonalities + + ITE IT87x Monitor Plugin + + CFBundleIdentifier + org.mozodojo.ITEIT87x + IOClass + IT87x + IOMatchCategory + IT87x + IOProviderClass + IOResources + IOResourceMatch + IOKit + Sensors Configuration + + ASRock + + P55 Deluxe + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + CPU + TEMPIN1 + System + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + + VIN2 + 3VCC + VIN3 + + VIN4 + + Name + +12VC + Rf + 1000 + Ri + 3000 + VRef + 0 + + VIN5 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN6 + + VIN7 + + VIN8 + VBAT + + + ASUS + + Crosshair III Formula + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + CPU + TEMPIN1 + + TEMPIN2 + + VBATNeedUpdates + + VIN0 + + VIN1 + + VIN2 + + VIN3 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + VIN8 + VBAT + + M2N SLI DELUXE + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + CPU + TEMPIN1 + System + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + Name + +12VC + Rf + 1000 + Ri + 3000 + VRef + 0 + + VIN5 + + VIN6 + + VIN7 + + Name + +5VSB + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN8 + VBAT + + M4A79XTD EVO + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + CPU + TEMPIN1 + System + TEMPIN2 + + VBATNeedUpdates + + VIN0 + + VIN1 + + VIN2 + + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + VIN8 + VBAT + + + DFI + + LP BI P45-T2RS Elite + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + Ambient + VBATNeedUpdates + + VIN0 + CPU + VIN1 + + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + Name + +12VC + Rf + 1000 + Ri + 3000 + VRef + 0 + + VIN5 + + VIN6 + Memory + VIN7 + + Name + +5VSB + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN8 + VBAT + + LP DK P55-T3eH9 + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + Ambient + TEMPIN2 + CPU + VBATNeedUpdates + + VIN0 + CPU + VIN1 + + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + Name + +12VC + Rf + 1000 + Ri + 3000 + VRef + 0 + + VIN5 + + VIN6 + Memory + VIN7 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN8 + VBAT + + + Default + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + Ambient + VIN0 + CPU + VIN1 + Memory + VIN2 + + VIN3 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + VIN8 + + + ECS + + A890GXM-A + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + CPU + TEMPIN1 + Ambient + TEMPIN2 + System + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + + VIN3 + + Name + 3VCC + Rf + 100 + Ri + 100 + VRef + 0 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + Name + 3VSB + Rf + 100 + Ri + 100 + VRef + 0 + + VIN8 + VBAT + + + Gigabyte + + 965P-S3 + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN8 + VBAT + + EP43-UD3L + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + Ambient + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN8 + VBAT + + EP45-DS3 + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN8 + VBAT + + EP45-DS3R + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN8 + VBAT + + EP45-UD3R + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN8 + VBAT + + EX58-EXTREME + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + Ambient + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + VIN8 + VBAT + + GA-MA770T-UD3 + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN5 + + VIN6 + + VIN7 + + VIN8 + VBAT + + GA-MA785GMT-UD2H + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN5 + + VIN6 + + VIN7 + + VIN8 + VBAT + + H61M-S1 + + FANIN0 + CPUFan + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + Memory + TEMPIN2 + Ambient + VBATNeedUpdates + + VIN0 + CPU + VIN1 + + Name + Memory + Ri + 3 + + VIN2 + + Name + +12VC + Ri + 3 + + VIN3 + + Name + VBAT + Ri + 1 + + VIN4 + + VIN5 + + Name + 3VCC + Ri + 2 + + VIN6 + + VIN7 + + Name + +5VC + Ri + 2 + + VIN8 + + Name + 3VSB + Ri + 1 + + + Z170X-UD5 TH-CF + + FANIN0 + CPUFan + FANIN1 + SysFan + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + Memory + TEMPIN2 + Ambient + VBATNeedUpdates + + VIN0 + CPU + VIN1 + + Name + Memory + Ri + 3 + + VIN2 + + Name + +12VC + Ri + 3 + + VIN3 + + Name + VBAT + Ri + 1 + + VIN4 + + VIN5 + + Name + 3VCC + Ri + 2 + + VIN6 + + VIN7 + + Name + +5VC + Ri + 2 + + VIN8 + + Name + 3VSB + Ri + 1 + + + H67A-UD3H-B3 + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + + TEMPIN2 + CPU + VBATNeedUpdates + + VIN0 + + VIN1 + + Name + +5VC + Rf + 100 + Ri + 1500 + VRef + 0 + + VIN2 + + Name + +12VC + Rf + 220 + Ri + 680 + VRef + 0 + + VIN3 + + VIN4 + + VIN5 + CPU + VIN6 + Memory + VIN7 + + Name + 3VSB + Rf + 100 + Ri + 100 + VRef + 0 + + VIN8 + VBAT + + P35-DS3 + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + Ambient + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN8 + VBAT + + P35-DS3L + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + Ambient + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN8 + VBAT + + P55-UD3L + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN6 + + VIN7 + + VIN8 + VBAT + + P55-UD4 + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN6 + + VIN7 + + VIN8 + VBAT + + P55M-UD4 + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN6 + + VIN7 + + VIN8 + VBAT + + P67A-UD4-B3 + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + + TEMPIN2 + CPU + VBATNeedUpdates + + VIN0 + + Name + +12VC + Rf + 100 + Ri + 1000 + VRef + 0 + + VIN1 + + Name + +5VC + Rf + 100 + Ri + 1500 + VRef + 0 + + VIN2 + + VIN3 + + VIN4 + + VIN5 + CPU + VIN6 + Memory + VIN7 + + Name + 3VSB + Rf + 100 + Ri + 100 + VRef + 0 + + VIN8 + VBAT + + X38-DS5 + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN8 + VBAT + + X58A-UD3R + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + Ambient + TEMPIN1 + CPU + TEMPIN2 + System + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +5VC + Rf + 1000 + Ri + 680 + VRef + 0 + + VIN4 + + VIN5 + + Name + +12VC + Rf + 910 + Ri + 2700 + VRef + 0 + + VIN6 + + VIN7 + + VIN8 + VBAT + + Z68A-D3H-B3 + + FANIN0 + CPU Fan + FANIN1 + System Fan1 + FANIN2 + PWR Fan + FANIN3 + System Fan2 + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + + TEMPIN2 + CPU + VBATNeedUpdates + + VIN0 + + VIN1 + + Name + 3VCC + Rf + 2050 + Ri + 1330 + VRef + 0 + + VIN2 + + Name + +12VC + Rf + 220 + Ri + 680 + VRef + 0 + + VIN3 + + Name + +5VC + Rf + 2000 + Ri + 1430 + VRef + 0 + + VIN4 + + VIN5 + CPU + VIN6 + Memory + VIN7 + + Name + 3VSB + Rf + 100 + Ri + 100 + VRef + 0 + + VIN8 + + Name + VBAT + Rf + 100 + Ri + 100 + VRef + 0 + + + Z68AP-D3 + + FANIN0 + CPU Fan + FANIN1 + System Fan1 + FANIN2 + PWR Fan + FANIN3 + System Fan2 + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + + TEMPIN2 + CPU + VBATNeedUpdates + + VIN0 + + VIN1 + + Name + 3VCC + Rf + 2050 + Ri + 1330 + VRef + 0 + + VIN2 + + Name + +12VC + Rf + 220 + Ri + 680 + VRef + 0 + + VIN3 + + Name + +5VC + Rf + 2000 + Ri + 1430 + VRef + 0 + + VIN4 + + VIN5 + CPU + VIN6 + Memory + VIN7 + + Name + 3VSB + Rf + 100 + Ri + 100 + VRef + 0 + + VIN8 + + Name + VBAT + Rf + 100 + Ri + 100 + VRef + 0 + + + Z68X-UD7-B3 + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + + TEMPIN2 + CPU + VBATNeedUpdates + + VIN0 + + VIN1 + + Name + 3VCC + Rf + 2050 + Ri + 1330 + VRef + 0 + + VIN2 + + Name + +12VC + Rf + 220 + Ri + 680 + VRef + 0 + + VIN3 + + Name + +5VC + Rf + 2000 + Ri + 1430 + VRef + 0 + + VIN4 + + VIN5 + CPU + VIN6 + Memory + VIN7 + + Name + 3VSB + Rf + 100 + Ri + 100 + VRef + 0 + + VIN8 + VBAT + + Z87P-D3 + + FANIN0 + Processor Fan + FANIN1 + System Fan1 + FANIN2 + System Fan2 + FANIN3 + System Fan2 + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + Ambient + VBATNeedUpdates + + VIN0 + VID + VIN1 + + Name + 3VCC + Rf + 2050 + Ri + 1330 + VRef + 0 + + VIN2 + + Name + +12VC + Ri + 5 + + VIN3 + + Name + +5VC + Rf + 100 + Ri + 150 + VRef + 0 + + VIN4 + + VIN5 + CPU + VIN6 + Memory + VIN7 + + Name + 3VSB + Ri + 1 + + VIN8 + + Name + VBAT + Ri + 1 + + + + Shuttle + + FH67 + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + + SmartGuardian + + TEMPIN0 + System + TEMPIN1 + CPU + TEMPIN2 + + VBATNeedUpdates + + VIN0 + CPU + VIN1 + Memory + VIN2 + + VIN3 + + VIN4 + + VIN5 + + VIN6 + + VIN7 + + Name + 3VSB + Rf + 100 + Ri + 100 + VRef + 0 + + VIN8 + VBAT + + + + + + OSBundleLibraries + + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.mach + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + OSBundleRequired + Root + + diff --git a/plugins/SuperIOSensors/ITE87x/ITEIT87x-Prefix.pch b/plugins/SuperIOSensors/ITE87x/ITEIT87x-Prefix.pch new file mode 100755 index 0000000..52a87e1 --- /dev/null +++ b/plugins/SuperIOSensors/ITE87x/ITEIT87x-Prefix.pch @@ -0,0 +1,4 @@ +// +// Prefix header for all source files of the 'ITEIT87x' target in the 'ITEIT87x' project +// + diff --git a/plugins/SuperIOSensors/ITE87x/ITEIT87x.cpp b/plugins/SuperIOSensors/ITE87x/ITEIT87x.cpp new file mode 100755 index 0000000..1475736 --- /dev/null +++ b/plugins/SuperIOSensors/ITE87x/ITEIT87x.cpp @@ -0,0 +1,744 @@ +/* + * IT8718F.cpp + * HWSensors + * + * Created by mozo on 08/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * Modified by Navi 2012 + * + */ + +#include +#include "ITEIT87x.h" +#include "../../../fakesmc/FakeSMC.h" +//#include "FakeSMCUtils.h" +#include "../../../utils/utils.h" + +#define Debug FALSE + +#define LogPrefix "ITEIT87x: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +#define super SuperIOMonitor +OSDefineMetaClassAndStructors(IT87x, SuperIOMonitor) + +OSDefineMetaClassAndStructors(IT87xSensor, SuperIOSensor) + +#pragma mark IT87xSensor implementation + +SuperIOSensor * IT87xSensor::withOwner(SuperIOMonitor *aOwner, + const char* aKey, + const char* aType, + unsigned char aSize, + SuperIOSensorGroup aGroup, + unsigned long aIndex, + long aRi, + long aRf, + long aVf) { + SuperIOSensor *me = new IT87xSensor; + // DebugLog("with owner mults = %ld", aRi); + if (me && !me->initWithOwner(aOwner, aKey, aType, aSize, aGroup, aIndex ,aRi,aRf,aVf)) { + me->release(); + return 0; + } + + return me; +} + +long IT87xSensor::getValue() { + UInt16 value = 0; + switch (group) { + case kSuperIOTemperatureSensor: + value = owner->readTemperature(index); + break; + case kSuperIOVoltageSensor: + value = owner->readVoltage(index); + break; + case kSuperIOTachometerSensor: + value = owner->readTachometer(index); + break; + default: + switch ((SuperIOSensorGroupEx)group) { + case kSuperIOSmartGuardPWMControl: + value = OSDynamicCast(IT87x, owner)->readSmartGuardPWMControl(index); + break; + case kSuperIOSmartGuardTempFanStop: + value = OSDynamicCast(IT87x, owner)->readSmartGuardTempFanStop(index); + break; + case kSuperIOSmartGuardTempFanStart: + value = OSDynamicCast(IT87x, owner)->readSmartGuardTempFanStart(index); + break; + case kSuperIOSmartGuardTempFanFullOn: + value = OSDynamicCast(IT87x, owner)->readSmartGuardTempFanFullOn(index); + break; + case kSuperIOSmartGuardPWMStart: + value = OSDynamicCast(IT87x, owner)->readSmartGuardPWMStart(index); + break; + case kSuperIOSmartGuardTempFanFullOff: + value = OSDynamicCast(IT87x, owner)->readSmartGuardTempFanFullOff(index); + break; + case kSuperIOSmartGuardTempFanControl: + value = OSDynamicCast(IT87x, owner)->readSmartGuardFanControl(index); + break; + case kSuperIOSmartGuardMainControl: + value = OSDynamicCast(IT87x, owner)->readSmartGuardMainControl(index); + break; + case kSuperIOSmartGuardRegControl: + value = OSDynamicCast(IT87x, owner)->readSmartGuardRegControl(index); + break; + + default: + break; + } + } + + if (Rf == 0) { + Rf = 1; + WarningLog("Rf == 0 when getValue index=%d value=%04x", (int)index, value); + } + // DebugLog("value = %ld Ri=%ld Rf=%ld", (long)value, Ri, Rf); + value = value + ((value - Vf) * Ri)/Rf; + + if (*((uint32_t*)type) == *((uint32_t*)TYPE_FP2E)) { + value = encode_fp2e(value); + } else if (*((uint32_t*)type) == *((uint32_t*)TYPE_SP4B)) { + value = encode_sp4b(value); + } else if (*((uint32_t*)type) == *((uint32_t*)TYPE_FPE2)) { + value = encode_fpe2(value); + } + + // value = encodeValue(value, scale); + + return value; +} + + +void IT87xSensor::setValue(UInt16 value) { + switch ((SuperIOSensorGroupEx)group) { + case kSuperIOSmartGuardPWMControl: + OSDynamicCast(IT87x, owner)->writeSmartGuardPWMControl(index,value); + break; + case kSuperIOSmartGuardTempFanStop: + OSDynamicCast(IT87x, owner)->writeSmartGuardTempFanStop(index,value); + break; + case kSuperIOSmartGuardTempFanStart: + OSDynamicCast(IT87x, owner)->writeSmartGuardTempFanStart(index,value); + break; + case kSuperIOSmartGuardTempFanFullOn: + OSDynamicCast(IT87x, owner)->writeSmartGuardTempFanFullOn(index,value); + break; + case kSuperIOSmartGuardPWMStart: + OSDynamicCast(IT87x, owner)->writeSmartGuardPWMStart(index,value); + break; + case kSuperIOSmartGuardTempFanFullOff: + OSDynamicCast(IT87x, owner)->writeSmartGuardTempFanFullOff(index,value); + break; + case kSuperIOSmartGuardTempFanControl: + OSDynamicCast(IT87x, owner)->writeSmartGuardFanControl(index,value); + break; + case kSuperIOSmartGuardMainControl: + OSDynamicCast(IT87x, owner)->writeSmartGuardMainControl(index,value); + break; + case kSuperIOSmartGuardRegControl: + OSDynamicCast(IT87x, owner)->writeSmartGuardRegControl(index,value); + break; + default: + break; + } + + // Damn... need someone to explain the encoding scheme of SMC keys... but actually works well without it + // if (*((uint32_t*)type) == *((uint32_t*)TYPE_FP2E)) { + // value = encode_fp2e(value); + // } + // else if (*((uint32_t*)type) == *((uint32_t*)TYPE_FPE2)) { + // value = encode_fpe2(value); + // } + // + // return value; +} + +#pragma mark IT87x implementation + +long IT87x::readSmartGuardPWMControl(unsigned long index) { + return readByte(address, ITE_SMARTGUARDIAN_PWM_CONTROL[index]); +} + + +void IT87x::writeSmartGuardPWMControl(unsigned long index,UInt16 value) { + writeByte(address,ITE_SMARTGUARDIAN_PWM_CONTROL[index], value); +} + +long IT87x::readSmartGuardTempFanStop(unsigned long index) { + return readByte(address, ITE_SMARTGUARDIAN_TEMPERATURE_STOP[index]); +} + +void IT87x::writeSmartGuardTempFanStop(unsigned long index,UInt16 value) { + writeByte(address,ITE_SMARTGUARDIAN_TEMPERATURE_STOP[index], value); +} + +long IT87x::readSmartGuardTempFanStart(unsigned long index) { + return readByte(address, ITE_SMARTGUARDIAN_TEMPERATURE_START[index]); +} + +void IT87x::writeSmartGuardTempFanStart(unsigned long index,UInt16 value) { + writeByte(address, ITE_SMARTGUARDIAN_TEMPERATURE_START[index], value); +} + +long IT87x::readSmartGuardTempFanFullOn(unsigned long index) { + return readByte(address, ITE_SMARTGUARDIAN_TEMPERATURE_FULL_ON[index]); +} + +void IT87x::writeSmartGuardTempFanFullOn(unsigned long index,UInt16 value) { + writeByte(address,ITE_SMARTGUARDIAN_TEMPERATURE_FULL_ON[index], value); +} + +long IT87x::readSmartGuardPWMStart(unsigned long index) { + return readByte(address, ITE_SMARTGUARDIAN_START_PWM[index]); +} + +void IT87x::writeSmartGuardPWMStart(unsigned long index,UInt16 value) { + writeByte(address,ITE_SMARTGUARDIAN_START_PWM[index], value); +} + +long IT87x::readSmartGuardTempFanFullOff(unsigned long index) { + return readByte(address, ITE_SMARTGUARDIAN_TEMPERATURE_DELTA[index]); +} + +void IT87x::writeSmartGuardTempFanFullOff(unsigned long index,UInt16 value) { + writeByte(address,ITE_SMARTGUARDIAN_TEMPERATURE_DELTA[index], value); +} + +long IT87x::readSmartGuardFanControl(unsigned long index) { + return readByte(address, ITE_SMARTGUARDIAN_CONTROL[index]); +} + +void IT87x::writeSmartGuardFanControl(unsigned long index,UInt16 value) { + writeByte(address,ITE_SMARTGUARDIAN_CONTROL[index], value); +} + +long IT87x::readSmartGuardMainControl(unsigned long index) { + return readByte(address, ITE_SMARTGUARDIAN_MAIN_CONTROL); +} + +void IT87x::writeSmartGuardMainControl(unsigned long index,UInt16 value) { + writeByte(address,ITE_SMARTGUARDIAN_MAIN_CONTROL, value); +} + +long IT87x::readSmartGuardRegControl(unsigned long index) { + return readByte(address, ITE_SMARTGUARDIAN_REG_CONTROL); +} + +void IT87x::writeSmartGuardRegControl(unsigned long index,UInt16 value) { + writeByte(address,ITE_SMARTGUARDIAN_REG_CONTROL, value); +} + +long IT87x::readTemperature(unsigned long index) { + return readByte(address, ITE_TEMPERATURE_BASE_REG + index); +} + +long IT87x::readVoltage(unsigned long index) { + // Refresh VBAT reading on each access to the key + if (vbat_updates) { + writeByte(address, ITE_CONFIGURATION_REGISTER, readByte(address, ITE_CONFIGURATION_REGISTER) | 0x40); + } + return readByte(address, ITE_VOLTAGE_REG[index]) * voltageGain; + +} + +long IT87x::readTachometer(unsigned long index) { + int value = readByte(address, ITE_FAN_TACHOMETER_REG[index]); + + value |= readByte(address, ITE_FAN_TACHOMETER_EXT_REG[index]) << 8; + + return (value > 0x3f && value < 0xffff) ? (float)(1350000 + value) / (float)(value * 2) : 0; +} + +bool IT87x::probePort() { + UInt16 id = listenPortWord(SUPERIO_CHIP_ID_REGISTER); + + if (id == 0 || id == 0xffff) { + //DebugLog("invalid super I/O chip ID=0x%x", id); + return false; + } + + hasSmartGuardian = false; + switch (id) { + case IT8512F: + case IT8613F: + case IT8620F: + case IT8628F: + case IT8655F: + case IT8665F: + case IT8686E: + case IT8688E: + case IT8705F: + case IT8708F: + case IT8712F: + case IT8716F: + case IT8718F: + case IT8720F: + case IT8721F: + case IT8726F: + case IT8728F: + case IT8752F: + case IT8771E: + case IT8772E: + case IT8792E: + case IT8795E: + case IT8987E: + model = id; + break; + default: + DebugLog("found unsupported chip ID=0x%x", id); + return false; + } + + selectLogicalDevice(ITE_ENVIRONMENT_CONTROLLER_LDN); + + IOSleep(50); + + if (!getLogicalDeviceAddress()) { + DebugLog("can't get monitoring LDN address"); + return false; + } + + UInt8 vendor16 = readByte(address, ITE_VENDOR_ID_REGISTER); + + if (vendor16 != ITE_VENDOR_ID) { + DebugLog("invalid vendor ID=0x%x", vendor16); + return false; + } + + if ((readByte(address, ITE_CONFIGURATION_REGISTER) & 0x10) == 0) { + DebugLog("invalid configuration register value"); + return false; + } + + if (id == IT8721F || id == IT8726F || id == IT8728F || id == IT8752F || + id == IT8771E || id == IT8772E || id == IT8792E || id == IT8987E || + id == IT8620F || id == IT8628F || id == IT8613F || id == IT8795E || + id == IT8655F || id == IT8665F || id == IT8686E || id == IT8688E) { + voltageGain = 12; + } else { + voltageGain = 16; + } + UInt8 version = readByte(address, ITE_VERSION_REGISTER) & 0x0F; + + if (id == IT8712F && version < 8) { + has16bitFanCounter = false; + } else { + has16bitFanCounter = true; + } + return true; +} + +void IT87x::enter() { + outb(registerPort, 0x87); + outb(registerPort, 0x01); + outb(registerPort, 0x55); + + if (registerPort == 0x4e) { + outb(registerPort, 0xaa); + } else { + outb(registerPort, 0x55); + } +} + +void IT87x::exit() { + outb(registerPort, SUPERIO_CONFIGURATION_CONTROL_REGISTER); + outb(valuePort, 0x02); +} + +const char *IT87x::getModelName() { + switch (model) { + case IT8512F: return "IT8512F"; + case IT8613F: return "IT8613F"; + case IT8620F: return "IT8620F"; + case IT8628F: return "IT8628F"; + case IT8655F: return "IT8655F"; + case IT8665F: return "IT8665F"; + case IT8686E: return "IT8686E"; + case IT8688E: return "IT8688E"; + case IT8705F: return "IT8705F"; + case IT8708F: return "IT8708F"; + case IT8712F: return "IT8712F"; + case IT8716F: return "IT8716F"; + case IT8718F: return "IT8718F"; + case IT8720F: return "IT8720F"; + case IT8721F: return "IT8721F"; + case IT8726F: return "IT8726F"; + case IT8728F: return "IT8728F"; + case IT8752F: return "IT8752F"; + case IT8771E: return "IT8771E"; + case IT8772E: return "IT8772E"; + case IT8792E: return "IT8792E"; + case IT8795E: return "IT8795E"; + case IT8987E: return "IT8987E"; + } + + return "unknown"; +} + +bool IT87x::init(OSDictionary *properties) { + // DebugLog("initialising..."); + if (!super::init(properties)) + return false; + + return true; +} + +IOService* IT87x::probe(IOService *provider, SInt32 *score) { + // DebugLog("probing..."); + if (super::probe(provider, score) != this) + return 0; + + return this; +} + +void IT87x::stop (IOService* provider) { + DebugLog("stoping..."); + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCRemoveKeyHandler, + true, + this, + NULL, + NULL, + NULL)) { + WarningLog("Can't remove key handler"); + IOSleep(500); + } + + super::stop(provider); +} + +void IT87x::free() { + //DebugLog("freeing..."); + super::free(); +} + +bool IT87x::start(IOService * provider) { + DebugLog("starting ..."); + + if (!super::start(provider)) { + return false; + } + + InfoLog("found ITE %s", getModelName()); + OSDictionary* list = OSDynamicCast(OSDictionary, getProperty("Sensors Configuration")); + + OSDictionary *configuration=NULL; + IORegistryEntry * rootNode = fromPath("/efi/platform", gIODTPlane); + + if (rootNode) { + OSData *data = OSDynamicCast(OSData, rootNode->getProperty("OEMVendor")); + if (data) { + bcopy(data->getBytesNoCopy(), vendor, data->getLength()); + OSString * VendorNick = vendorID(OSString::withCString(vendor)); + if (VendorNick) { + data = OSDynamicCast(OSData, rootNode->getProperty("OEMBoard")); + if (!data) { + WarningLog("no OEMBoard"); + data = OSDynamicCast(OSData, rootNode->getProperty("OEMProduct")); + } + + if (data) { + bcopy(data->getBytesNoCopy(), product, data->getLength()); + OSDictionary *link = OSDynamicCast(OSDictionary, list->getObject(VendorNick)); + + if (link) { + configuration = OSDynamicCast(OSDictionary, link->getObject(OSString::withCString(product))); + InfoLog(" mother vendor=%s product=%s", vendor, product); + } + } + } else { + WarningLog("unknown OEMVendor %s", vendor); + } + } else { + WarningLog("no OEMVendor"); + } + } + + if (list && !configuration) { + configuration = OSDynamicCast(OSDictionary, list->getObject("Default")); + WarningLog("set default configuration"); + } + + if (configuration) { + this->setProperty("Current Configuration", configuration); + } + + // Temperature Sensors + if (configuration) { + for (int i = 0; i < 3; i++) { + char key[8]; + + snprintf(key, 8, "TEMPIN%X", i); + if (readTemperature(i)getObject(key))) { + if (name->isEqualTo("CPU")) { + if (!addSensor(KEY_CPU_HEATSINK_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, i)) { + WarningLog("error adding heatsink temperature sensor"); + } + } else if (name->isEqualTo("System")) { + if (!addSensor(KEY_NORTHBRIDGE_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor,i)) { + WarningLog("error adding system temperature sensor"); + } + } else if (name->isEqualTo("Ambient")) { + if (!addSensor(KEY_AMBIENT_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor,i)) { + WarningLog("error adding Ambient temperature sensor"); + } + } else if (name->isEqualTo("Memory")) { + if (!addSensor(KEY_DIMM_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor,i)) { + WarningLog("error adding Memory temperature sensor"); + } + } + } + } + } + } else { + if (readTemperature(0)getObject("VBATNeedUpdates")); + if (smartGuard && smartGuard->isTrue()) + vbat_updates=true; + } + // Refresh VBAT reading on each access to the key + if (vbat_updates) { + writeByte(address, ITE_CONFIGURATION_REGISTER, readByte(address, ITE_CONFIGURATION_REGISTER) | 0x40); + } + + if (configuration) { + for (int i = 0; i < 9; i++) { + char key[5]; + OSString * name; + long Ri=0; + long Rf=1; + long Vf=0; + + snprintf(key, 5, "VIN%X", i); + + if (process_sensor_entry(configuration->getObject(key), &name, &Ri, &Rf, &Vf)) { + //DebugLog("Entry %d name=%s Ri=%ld", i, name->getCStringNoCopy(), Ri); + if (name->isEqualTo("CPU")) { + if (!addSensor(KEY_CPU_VRM_SUPPLY0, TYPE_FP2E, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) { + WarningLog("error adding CPU voltage sensor"); + } + } else if (name->isEqualTo("Memory")) { + if (!addSensor(KEY_MEMORY_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) { + WarningLog("error adding memory voltage sensor"); + } + } else if (name->isEqualTo("+5VC")) { + if (!addSensor(KEY_5VC_VOLTAGE, TYPE_SP4B, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) { + WarningLog("ERROR Adding AVCC Voltage Sensor!"); + } + } else if (name->isEqualTo("+5VSB")) { + if (!addSensor(KEY_5VSB_VOLTAGE, TYPE_SP4B, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) { + WarningLog("ERROR Adding AVCC Voltage Sensor!"); + } + } else if (name->isEqualTo("+12VC")) { + if (!addSensor(KEY_12V_VOLTAGE, TYPE_SP4B, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) { + WarningLog("ERROR Adding 12V Voltage Sensor!"); + } + } else if (name->isEqualTo("-12VC")) { + if (!addSensor(KEY_N12VC_VOLTAGE, TYPE_SP4B, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) { + WarningLog("ERROR Adding 12V Voltage Sensor!"); + } + } else if (name->isEqualTo("3VCC")) { + if (!addSensor(KEY_3VCC_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) { + WarningLog("ERROR Adding 3VCC Voltage Sensor!"); + } + } else if (name->isEqualTo("3VSB")) { + if (!addSensor(KEY_3VSB_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) { + WarningLog("ERROR Adding 3VSB Voltage Sensor!"); + } + } else if (name->isEqualTo("VBAT")) { + if (!addSensor(KEY_VBAT_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) { + WarningLog("ERROR Adding VBAT Voltage Sensor!"); + } + } + } + } + } + + // Tachometers + for (int i = 0; i < 5; i++) { + OSString* name = NULL; + + if (configuration) { + char key_temp[7]; + snprintf(key_temp, 7, "FANIN%X", i); + name = OSDynamicCast(OSString, configuration->getObject(key_temp)); + } + + UInt32 nameLength = name ? (UInt32)strlen(name->getCStringNoCopy()) : 0; + + if (readTachometer(i) > 10 || nameLength > 0) { + // Pff WTF ??? Add tachometer if it doesn't exist in a system but only the name defined in the config??? + + if (!addTachometer(i, (nameLength > 0 ? name->getCStringNoCopy() : 0))) { + // Need to look at this a bit later + WarningLog("error adding tachometer sensor %d", i); + } + } + + // Check if this chip support SmartGuardian feature + + hasSmartGuardian = false; + if (configuration) { + if (OSBoolean* smartGuard=OSDynamicCast(OSBoolean, configuration->getObject("SmartGuardian"))) { + if (smartGuard->isTrue()) { + hasSmartGuardian = true; + } + } + + } + + if (hasSmartGuardian) { + char key[5]; + // Ugly development hack started for (SuperIOSensorGroup) + snprintf(key,5,KEY_FORMAT_FAN_TARGET_SPEED,i); + if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardPWMControl, i)) { + WarningLog("error adding PWM fan control"); + } + + snprintf(key,5,KEY_FORMAT_FAN_START_TEMP,i); + if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardTempFanStart, i)) { + WarningLog("error adding start temp fan control"); + } + + snprintf(key,5,KEY_FORMAT_FAN_OFF_TEMP,i); + if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardTempFanStop, i)) { + WarningLog("error adding stop temp fan control"); + } + + snprintf(key,5,KEY_FORMAT_FAN_FULL_TEMP,i); + if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardTempFanFullOn, i)) { + WarningLog("error adding full speed temp fan control"); + } + snprintf(key,5,KEY_FORMAT_FAN_START_PWM,i); + if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardPWMStart, i)) { + WarningLog("error adding start PWM fan control"); + } + + snprintf(key,5,KEY_FORMAT_FAN_TEMP_DELTA,i); + if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardTempFanFullOff, i)) { + WarningLog("error adding temp full off fan control"); + } + + snprintf(key,5,KEY_FORMAT_FAN_CONTROL,i); + if (!addSensor(key, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardTempFanControl, i)) { + WarningLog("error adding register fan control"); + } + } + } + + if (hasSmartGuardian) { + if (!addSensor(KEY_FORMAT_FAN_MAIN_CONTROL, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardMainControl, 0)) { + WarningLog("error adding Main fan control"); + } + + if (!addSensor(KEY_FORMAT_FAN_REG_CONTROL, TYPE_UI8, 1, (SuperIOSensorGroup)kSuperIOSmartGuardRegControl, 0)) { + WarningLog("error adding Main fan control"); + } + } + + return true; +} + +int IT87x::getPortsCount() { + return 2; +} + + +SuperIOSensor * IT87x::addSensor(const char* name, + const char* type, + unsigned int size, + SuperIOSensorGroup group, + unsigned long index, + long aRi, + long aRf, + long aVf) { + if (NULL != getSensor(name)) { + return 0; + } + //DebugLog("mults = %ld", aRi); + SuperIOSensor *sensor = IT87xSensor::withOwner(this, name, type, size, group, index, aRi, aRf, aVf); + + if (sensor && sensors->setObject(sensor)) { + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)name, + (void *)type, + (void *)(long long)size, + (void *)this)) { + return sensor; + } + } + return 0; +} + +IOReturn IT87x::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4) { + + if (functionName->isEqualTo(kFakeSMCGetValueCallback)) { + const char* name = (const char*)param1; + void * data = param2; + //UInt32 size = (UInt64)param3; + + if (name && data) { + SuperIOSensor * sensor = getSensor(name); + if (sensor) { + UInt16 value = sensor->getValue(); + bcopy(&value, data, 2); + return kIOReturnSuccess; + } + } + + return kIOReturnBadArgument; + } + + if (functionName->isEqualTo(kFakeSMCSetValueCallback)) { + const char* name = (const char*)param1; + void * data = param2; + //UInt32 size = (UInt64)param3; + + if (name && data) { + IT87xSensor *sensor = OSDynamicCast(IT87xSensor, getSensor(name)); + if (sensor) { + UInt16 value; + bcopy(data, &value, 2); + sensor->setValue(value); + return kIOReturnSuccess; + } + } + return kIOReturnBadArgument; + } + + return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); +} diff --git a/plugins/SuperIOSensors/ITE87x/ITEIT87x.h b/plugins/SuperIOSensors/ITE87x/ITEIT87x.h new file mode 100755 index 0000000..3419be4 --- /dev/null +++ b/plugins/SuperIOSensors/ITE87x/ITEIT87x.h @@ -0,0 +1,201 @@ +/* + * IT87x.h + * HWSensors + * + * Created by mozo on 08/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * + * Open Hardware Monitor Port + * + */ + +//Additional functionality added by Navi, inspired by FakeSMC development. Credits goes to Netkas, slice, Mozo, usr-sse2 and others... + +#include +#include +#include +#include +#include + +#include "../SuperIOFamily/SuperIOFamily.h" + +const UInt8 ITE_ENVIRONMENT_CONTROLLER_LDN = 0x04; + +// ITE +const UInt8 ITE_VENDOR_ID = 0x90; +const UInt8 ITE_VERSION_REGISTER = 0x22; + +// ITE Environment Controller +const UInt8 ITE_ADDRESS_REGISTER_OFFSET = 0x05; +const UInt8 ITE_DATA_REGISTER_OFFSET = 0x06; + +// ITE Environment Controller Registers +const UInt8 ITE_CONFIGURATION_REGISTER = 0x00; +const UInt8 ITE_TEMPERATURE_BASE_REG = 0x29; +const UInt8 ITE_VENDOR_ID_REGISTER = 0x58; +const UInt8 ITE_FAN_TACHOMETER_16_BIT_ENABLE_REGISTER = 0x0c; +const UInt8 ITE_FAN_TACHOMETER_REG[5] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 }; +const UInt8 ITE_FAN_TACHOMETER_EXT_REG[5] = { 0x18, 0x19, 0x1a, 0x81, 0x83 }; +const UInt8 ITE_VOLTAGE_REG[9] = { 0x20, 0x21, 0x22, 0x23, 0x24,0x25,0x26,0x27,0x28}; +const float ITE_VOLTAGE_GAIN[] = { 1, 1, 1, (6.8f / 10 + 1), 1, 1, 1, 1, 1 }; +const UInt8 ITE_ADC_CHANNEL_ENABLE = 0x50; + +const UInt8 ITE_SMARTGUARDIAN_MAIN_CONTROL = 0x13; +const UInt8 ITE_SMARTGUARDIAN_REG_CONTROL = 0x14; +const UInt8 ITE_SMARTGUARDIAN_PWM_CONTROL[5] = { 0x15, 0x16, 0x17, 0x88, 0x89 }; +const UInt8 ITE_SMARTGUARDIAN_TEMPERATURE_STOP[5] = { 0x60, 0x68, 0x70, 0x90, 0x98 }; +const UInt8 ITE_SMARTGUARDIAN_TEMPERATURE_START[5] = { 0x61, 0x69, 0x71, 0x91, 0x99 }; +const UInt8 ITE_SMARTGUARDIAN_TEMPERATURE_FULL_ON[5] = { 0x62, 0x6a, 0x72, 0x92, 0x9a }; +const UInt8 ITE_SMARTGUARDIAN_START_PWM[5] = { 0x63, 0x6b, 0x73, 0x93, 0x9b }; +const UInt8 ITE_SMARTGUARDIAN_CONTROL[5] = { 0x64, 0x6c, 0x74, 0x94, 0x9c }; +const UInt8 ITE_SMARTGUARDIAN_TEMPERATURE_DELTA[5] = { 0x65, 0x6d, 0x75, 0x95, 0x9d }; +// + +#define MAX_TEMP_THRESHOLD 127 + +enum IT87xModel +{ + IT8512F = 0x8512, + IT8613F = 0x8613, + IT8620F = 0x8620, + IT8628F = 0x8628, + IT8655F = 0x8655, + IT8665F = 0x8665, + IT8686E = 0x8686, + IT8688E = 0x8688, + IT8705F = 0x8705, + IT8708F = 0x8708, + IT8712F = 0x8712, + IT8716F = 0x8716, + IT8718F = 0x8718, + IT8720F = 0x8720, + IT8721F = 0x8721, + IT8726F = 0x8726, + IT8728F = 0x8728, + IT8752F = 0x8752, + IT8771E = 0x8771, + IT8772E = 0x8772, + IT8792E = 0x8792, + IT8795E = 0x8795, + IT8987E = 0x8987 +}; + +enum SuperIOSensorGroupEx { + kSuperIOSmartGuardPWMControl = kSuperIOVoltageSensor +1, + kSuperIOSmartGuardTempFanStop, + kSuperIOSmartGuardTempFanStart, + kSuperIOSmartGuardTempFanFullOn, + kSuperIOSmartGuardPWMStart, + kSuperIOSmartGuardTempFanFullOff, + kSuperIOSmartGuardTempFanControl, + kSuperIOSmartGuardMainControl, + kSuperIOSmartGuardRegControl +}; + +class IT87x; + +class IT87xSensor : public SuperIOSensor { + OSDeclareDefaultStructors(IT87xSensor) + + +public: + static SuperIOSensor *withOwner(SuperIOMonitor *aOwner, + const char* aKey, + const char* aType, + unsigned char aSize, + SuperIOSensorGroup aGroup, + unsigned long aIndex, + long aRi = 0, + long aRf = 1, + long aVf = 0); + + virtual long getValue(); + virtual void setValue(UInt16 value); +}; + +class IT87x : public SuperIOMonitor { + OSDeclareDefaultStructors(IT87x) + + +private: + long voltageGain; + bool has16bitFanCounter; + bool hasSmartGuardian; + bool vbat_updates; + + char vendor[40]; + char product[40]; + + virtual void enter(); + virtual void exit(); + + virtual long readTemperature(unsigned long index); + virtual long readVoltage(unsigned long index); + virtual long readTachometer(unsigned long index); + + virtual int getPortsCount(); + virtual const char * getModelName(); + +public: + virtual bool init(OSDictionary *properties=0); + virtual IOService* probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual void stop(IOService *provider); + virtual void free(void); + + + virtual bool probePort(); + + virtual long readSmartGuardPWMControl(unsigned long index); + virtual long readSmartGuardTempFanStop(unsigned long index); + virtual long readSmartGuardTempFanStart(unsigned long index); + virtual long readSmartGuardTempFanFullOn(unsigned long index); + virtual long readSmartGuardPWMStart(unsigned long index); + virtual long readSmartGuardTempFanFullOff(unsigned long index); + virtual long readSmartGuardFanControl(unsigned long index); + virtual long readSmartGuardMainControl(unsigned long index); + virtual long readSmartGuardRegControl(unsigned long index); + // New write SMC key value to SmartGuardian registers methods + virtual void writeSmartGuardPWMControl(unsigned long index, UInt16 value); + virtual void writeSmartGuardTempFanStop(unsigned long index, UInt16 value); + virtual void writeSmartGuardTempFanStart(unsigned long index, UInt16 value); + virtual void writeSmartGuardTempFanFullOn(unsigned long index, UInt16 value); + virtual void writeSmartGuardPWMStart(unsigned long index, UInt16 value); + virtual void writeSmartGuardTempFanFullOff(unsigned long index, UInt16 value); + virtual void writeSmartGuardFanControl(unsigned long index, UInt16 value); + virtual void writeSmartGuardMainControl(unsigned long index, UInt16 value); + virtual void writeSmartGuardRegControl(unsigned long index, UInt16 value); + + SuperIOSensor * addSensor(const char* key, + const char* type, + unsigned int size, + SuperIOSensorGroup group, + unsigned long index, + long aRi = 0, + long aRf = 1, + long aVf = 0); + + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); +}; + +inline UInt8 readByte(UInt16 address, UInt8 reg) { + outb(address + ITE_ADDRESS_REGISTER_OFFSET, reg); + + UInt8 value = inb(address + ITE_DATA_REGISTER_OFFSET); + __unused UInt8 check = inb(address + ITE_DATA_REGISTER_OFFSET); + return value; +} + +inline UInt16 readWord(UInt16 address,UInt8 reg1, UInt8 reg2) { + return (readByte(address,reg1) << 8) | readByte(address,reg2); +} + +inline void writeByte(UInt16 address,UInt8 reg, UInt8 value) { + outb(address + ITE_ADDRESS_REGISTER_OFFSET, reg); + outb(address + ITE_DATA_REGISTER_OFFSET, value); +} diff --git a/plugins/SuperIOSensors/ITE87x/en.lproj/InfoPlist.strings b/plugins/SuperIOSensors/ITE87x/en.lproj/InfoPlist.strings new file mode 100755 index 0000000..477b28f --- /dev/null +++ b/plugins/SuperIOSensors/ITE87x/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/plugins/SuperIOSensors/NSCPC8739x/PC8739x-Info.plist b/plugins/SuperIOSensors/NSCPC8739x/PC8739x-Info.plist new file mode 100644 index 0000000..5b8c335 --- /dev/null +++ b/plugins/SuperIOSensors/NSCPC8739x/PC8739x-Info.plist @@ -0,0 +1,70 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + IOKitPersonalities + + NSC PC8739x Monitor Plugin + + CFBundleIdentifier + org.slice.${PRODUCT_NAME} + IOClass + PC8739x + IOMatchCategory + PC8739x + IOProbeScore + 500 + IOProviderClass + IOResources + IOResourceMatch + IOKit + Sensors Configuration + + FANIN0 + System Fan + FANIN1 + + TEMPIN0 + System + TEMPIN1 + Auxiliary + TEMPIN2 + Processor + TEMPIN3 + Memory + + + + OSBundleLibraries + + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.mach + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + OSBundleRequired + Root + + diff --git a/plugins/SuperIOSensors/NSCPC8739x/PC8739x-pre106-Info.plist b/plugins/SuperIOSensors/NSCPC8739x/PC8739x-pre106-Info.plist new file mode 100644 index 0000000..c6ad8d8 --- /dev/null +++ b/plugins/SuperIOSensors/NSCPC8739x/PC8739x-pre106-Info.plist @@ -0,0 +1,66 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.slice.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + IOKitPersonalities + + NSC PC8739x Monitor Plugin + + CFBundleIdentifier + org.slice.${PRODUCT_NAME} + IOClass + PC8739x + IOProbeScore + 500 + IOMatchCategory + PC8739x + IOProviderClass + IOResources + IOResourceMatch + IOKit + Sensors Configuration + + FANIN0 + + FANIN1 + + FANIN2 + + FANIN3 + + FANIN4 + System Fan + + + + OSBundleLibraries + + org.netkas.FakeSMC + 3.1.0 + com.apple.kernel.6.0 + 7.9.9 + com.apple.kernel.iokit + 7.9.9 + com.apple.kernel.libkern + 7.9.9 + + OSBundleRequired + Root + + diff --git a/plugins/SuperIOSensors/NSCPC8739x/PC8739x.cpp b/plugins/SuperIOSensors/NSCPC8739x/PC8739x.cpp new file mode 100644 index 0000000..fb4196b --- /dev/null +++ b/plugins/SuperIOSensors/NSCPC8739x/PC8739x.cpp @@ -0,0 +1,204 @@ +/* + * PC8739x.cpp + * HWSensors + * + * Created by mozo on 16/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +#include "FakeSMC.h" +#include "PC8739x.h" + +#include + +#define Debug FALSE + +#define LogPrefix "PC8739x: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +#define super SuperIOMonitor +OSDefineMetaClassAndStructors(PC8739x, SuperIOMonitor) + +UInt8 PC8739x::readByte(UInt8 bank, UInt8 reg) { + // Not needed cose we already selected FAN device + //outb(m_RegisterPort, SUPERIO_DEVICE_SELECT_REGISTER); + //outb(m_ValuePort, ldn); + outb(registerPort, reg); + return inb(valuePort); +} + +void PC8739x::writeByte(UInt8 bank, UInt8 reg, UInt8 value) { + //outb(m_RegisterPort, SUPERIO_DEVICE_SELECT_REGISTER); + //outb(m_ValuePort, ldn); + outb(registerPort, reg); + outb(valuePort, value); +} + +long PC8739x::readTemperature(unsigned long index) { + return mmioBase[NSC_HARDWARE_MONITOR_REGS[0][index]]; +} + +long PC8739x::readTachometer(unsigned long index) { + return (0xff - (mmioBase[NSC_HARDWARE_MONITOR_REGS[1][index]] & 0xff)) * 20; +} + +bool PC8739x::probePort() { + UInt8 id = listenPortByte(SUPERIO_CHIP_ID_REGISTER); + revision = listenPortByte(NSC_CHIP_REVISION_REGISTER); + DebugLog("testing NSC id=%04x rev=%04x", id, revision); + + if (id == 0 || id == 0xff || revision == 0 || revision == 0xff) { + return false; + } + + if (id == 0xfc) { + selectLogicalDevice(NSC_HARDWARE_MONITOR_LDN); + + if (!getLogicalDeviceAddress(SUPERIO_BASE_ADDRESS_REGISTER)){ + DebugLog("NSC no getLogicalDeviceAddress"); + //return false; + } + //m_Address = ListenPortWord(SUPERIO_BASE_ADDRESS_REGISTER); + if (!listenPortByte(NSC_LDN_PRESENT)) { + DebugLog(" no NSC_LDN_PRESENT"); + return false; + } + + switch (revision) { + default: + model = PC8739xx; + break; + } + InfoLog("NSC: Found supported chip ID=0x%x REVISION=0x%x ", id, revision); + return true; + } + + return false; +} + +const char *PC8739x::getModelName() { + switch (model) { + case PC8739xx: return "PC8739xx"; + } + + return "unknown"; +} + +bool PC8739x::init(OSDictionary *properties) { + DebugLog("initialising..."); + + if (!super::init(properties)) { + return false; + } + + return true; +} + +IOService* PC8739x::probe(IOService *provider, SInt32 *score) { + DebugLog("probing..."); + + if (super::probe(provider, score) != this) { + return 0; + } + + InfoLog("slice (c) 2011"); + + return this; +} + +bool PC8739x::start(IOService * provider) { + DebugLog("starting..."); + + if (!super::start(provider)) + return false; + + InfoLog("found NSC %s, revision 0x%x", getModelName(), revision); + + OSDictionary* configuration = OSDynamicCast(OSDictionary, getProperty("Sensors Configuration")); + + UInt32 adr = + (listenPortByte(NSC_MEM) & 0xff) + + ((listenPortByte(NSC_MEM + 1) << 8) & 0xff00) + + ((listenPortByte(NSC_MEM + 2) & 0xff) << 16) + + ((listenPortByte(NSC_MEM + 3) & 0xff) << 24); + + IOPhysicalAddress bar = (IOPhysicalAddress)(adr & ~0xf); + IOMemoryDescriptor *theDescriptor = IOMemoryDescriptor::withPhysicalAddress(bar, + 0x200, + kIODirectionOutIn); + + if (theDescriptor) { + mmio = theDescriptor->map(); + if (mmio) { + mmioBase = (volatile UInt8 *)mmio->getVirtualAddress(); + } else { + WarningLog("MCHBAR failed to map"); + return false; + } + } + + // Heatsink + if (!addSensor(KEY_CPU_HEATSINK_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 2)) { + WarningLog("error adding heatsink temperature sensor"); + } + + // Northbridge + if (!addSensor(KEY_NORTHBRIDGE_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 0)) { + WarningLog("error adding system temperature sensor"); + } + + // DIMM + if (!addSensor(KEY_DIMM_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 1)) { + WarningLog("error adding DIMM temperature sensor"); + } + + // AUX + if (!addSensor(KEY_AMBIENT_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 3)) { + WarningLog("error adding AUX temperature sensor"); + } + + // Tachometers + //for (int i = 0; i < 5; i++) { //only one + OSString* name = 0; + int i=0; + + if (configuration) { + char key[7]; + snprintf(key, 7, "FANIN%X", i); + name = OSDynamicCast(OSString, configuration->getObject(key)); + } + + size_t nameLength = name ? strlen(name->getCStringNoCopy()) : 0; + + if (readTachometer(i) > 10 || nameLength > 0) { + if (!addTachometer(i, (nameLength > 0 ? name->getCStringNoCopy() : 0))) { + WarningLog("error adding tachometer sensor %d", i); + } + } + + return true; +} + +void PC8739x::stop(IOService* provider) { + DebugLog("stoping..."); + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCRemoveKeyHandler, + true, + this, + NULL, + NULL, + NULL)) { + WarningLog("Can't remove key handler"); + IOSleep(500); + } + + super::stop(provider); +} + +void PC8739x::free(void) { + DebugLog("freeing..."); + super::free(); +} + diff --git a/plugins/SuperIOSensors/NSCPC8739x/PC8739x.h b/plugins/SuperIOSensors/NSCPC8739x/PC8739x.h new file mode 100644 index 0000000..efc9415 --- /dev/null +++ b/plugins/SuperIOSensors/NSCPC8739x/PC8739x.h @@ -0,0 +1,60 @@ +/* + * PC8739x.h + * HWSensors + * + * Created by mozo on 16/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +#include +#include +#include +#include +#include + +#include "SuperIOFamily.h" +//temp and fans +const UInt16 NSC_HARDWARE_MONITOR_REGS[2][4] = {{0x61, 0x62, 0x63, 0x64}, {0x68, 0x68, 0x68, 0x68}}; + +// ITE Environment Controller +const UInt8 NSC_ADDRESS_REGISTER_OFFSET = 0x00; +const UInt8 NSC_DATA_REGISTER_OFFSET = 0x01; +const UInt8 NSC_BANK_SELECT_REGISTER = 0x07; +const UInt8 NSC_CHIP_ID_REGISTER = 0x20; +const UInt8 NSC_CHIP_REVISION_REGISTER = 0x27; +const UInt8 NSC_LDN_PRESENT = 0x30; + + +const UInt8 NSC_HARDWARE_MONITOR_LDN = 0x0F; +const UInt8 NSC_MEM = 0xF4; + +enum PC8739xModel { + PC8739xx = 0xfc00 +}; + +class PC8739x : public SuperIOMonitor { + OSDeclareDefaultStructors(PC8739x) + +private: + volatile UInt8 * mmioBase; + IOMemoryMap * mmio; + UInt8 revision; + + UInt8 readByte(UInt8 bank, UInt8 reg); + void writeByte(UInt8 bank, UInt8 reg, UInt8 value); + + virtual bool probePort(); + + virtual long readTemperature(unsigned long index); + virtual long readTachometer(unsigned long index); + + virtual const char * getModelName(); + +public: + virtual bool init(OSDictionary *properties=0); + virtual IOService * probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual void stop(IOService *provider); + virtual void free(void); +}; diff --git a/plugins/SuperIOSensors/SuperIOFamily/SuperIOFamily-Info.plist b/plugins/SuperIOSensors/SuperIOFamily/SuperIOFamily-Info.plist new file mode 100644 index 0000000..c60c8c8 --- /dev/null +++ b/plugins/SuperIOSensors/SuperIOFamily/SuperIOFamily-Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDocumentTypes + + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.mozodojo.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + IOKitPersonalities + + OSBundleCompatibleVersion + 1.0.0d1 + OSBundleLibraries + + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.mach + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + OSBundleRequired + Root + + diff --git a/plugins/SuperIOSensors/SuperIOFamily/SuperIOFamily-pre106-Info.plist b/plugins/SuperIOSensors/SuperIOFamily/SuperIOFamily-pre106-Info.plist new file mode 100644 index 0000000..4197995 --- /dev/null +++ b/plugins/SuperIOSensors/SuperIOFamily/SuperIOFamily-pre106-Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.mozodojo.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + IOKitPersonalities + + OSBundleLibraries + + org.netkas.FakeSMC + 3.1.0 + com.apple.iokit.IOPCIFamily + 2.4 + com.apple.iokit.IOACPIFamily + 1.0.0d1 + com.apple.kernel.6.0 + 7.9.9 + com.apple.kernel.iokit + 7.9.9 + com.apple.kernel.libkern + 7.9.9 + + OSBundleCompatibleVersion + 1.0.0d1 + OSBundleRequired + Root + + diff --git a/plugins/SuperIOSensors/SuperIOFamily/SuperIOFamily.cpp b/plugins/SuperIOSensors/SuperIOFamily/SuperIOFamily.cpp new file mode 100644 index 0000000..6cb8b16 --- /dev/null +++ b/plugins/SuperIOSensors/SuperIOFamily/SuperIOFamily.cpp @@ -0,0 +1,562 @@ +/* + * SuperIOFamily.cpp + * HWSensors + * + * Created by mozo on 08/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +#include +#include + +#include "SuperIOFamily.h" +#include "FakeSMC.h" +#include "utils.h" + +//#define Debug FALSE + +#define LogPrefix "SuperIOFamily: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +/* +inline UInt16 swap_value(UInt16 value) { + return ((value & 0xff00) >> 8) | ((value & 0xff) << 8); +} + +inline UInt16 encode_fp2e(UInt16 value) { + UInt16 dec = (float)value / 1000.0f; + UInt16 frc = value - (dec * 1000); + + return swap_value((dec << 14) | (frc << 4)); +} + +inline UInt16 encode_fpe2(UInt16 value) { + return swap_value(value << 2); +} +*/ + +OSString * vendorID(OSString * smbios_manufacturer) { + if (smbios_manufacturer) { + if (smbios_manufacturer->isEqualTo("Alienware")) return OSString::withCString("Alienware"); + if (smbios_manufacturer->isEqualTo("Apple Inc.")) return OSString::withCString("Apple"); + if (smbios_manufacturer->isEqualTo("ASRock")) return OSString::withCString("ASRock"); + if (smbios_manufacturer->isEqualTo("ASUSTeK Computer INC.")) return OSString::withCString("ASUS"); + if (smbios_manufacturer->isEqualTo("ASUSTeK COMPUTER INC.")) return OSString::withCString("ASUS"); + if (smbios_manufacturer->isEqualTo("Dell Inc.")) return OSString::withCString("Dell"); + if (smbios_manufacturer->isEqualTo("DFI")) return OSString::withCString("DFI"); + if (smbios_manufacturer->isEqualTo("DFI Inc.")) return OSString::withCString("DFI"); + if (smbios_manufacturer->isEqualTo("ECS")) return OSString::withCString("ECS"); + if (smbios_manufacturer->isEqualTo("EPoX COMPUTER CO., LTD")) return OSString::withCString("EPoX"); + if (smbios_manufacturer->isEqualTo("EVGA")) return OSString::withCString("EVGA"); + if (smbios_manufacturer->isEqualTo("First International Computer, Inc.")) return OSString::withCString("FIC"); + if (smbios_manufacturer->isEqualTo("FUJITSU")) return OSString::withCString("FUJITSU"); + if (smbios_manufacturer->isEqualTo("FUJITSU SIEMENS")) return OSString::withCString("FUJITSU"); + if (smbios_manufacturer->isEqualTo("Gigabyte Technology Co., Ltd.")) return OSString::withCString("Gigabyte"); + if (smbios_manufacturer->isEqualTo("Hewlett-Packard")) return OSString::withCString("HP"); + if (smbios_manufacturer->isEqualTo("IBM")) return OSString::withCString("IBM"); + if (smbios_manufacturer->isEqualTo("Intel")) return OSString::withCString("Intel"); + if (smbios_manufacturer->isEqualTo("Intel Corp.")) return OSString::withCString("Intel"); + if (smbios_manufacturer->isEqualTo("Intel Corporation")) return OSString::withCString("Intel"); + if (smbios_manufacturer->isEqualTo("INTEL Corporation")) return OSString::withCString("Intel"); + if (smbios_manufacturer->isEqualTo("Lenovo")) return OSString::withCString("Lenovo"); + if (smbios_manufacturer->isEqualTo("LENOVO")) return OSString::withCString("Lenovo"); + if (smbios_manufacturer->isEqualTo("Micro-Star International")) return OSString::withCString("MSI"); + if (smbios_manufacturer->isEqualTo("MICRO-STAR INTERNATIONAL CO., LTD")) return OSString::withCString("MSI"); + if (smbios_manufacturer->isEqualTo("MICRO-STAR INTERNATIONAL CO.,LTD")) return OSString::withCString("MSI"); + if (smbios_manufacturer->isEqualTo("MSI")) return OSString::withCString("MSI"); + if (smbios_manufacturer->isEqualTo("Shuttle")) return OSString::withCString("Shuttle"); + if (smbios_manufacturer->isEqualTo("TOSHIBA")) return OSString::withCString("TOSHIBA"); + if (smbios_manufacturer->isEqualTo("XFX")) return OSString::withCString("XFX"); + if (smbios_manufacturer->isEqualTo("To be filled by O.E.M.")) return NULL; + } + return NULL; +} + + +// Sensor + +OSDefineMetaClassAndStructors(SuperIOSensor, OSObject) + +SuperIOSensor *SuperIOSensor::withOwner(SuperIOMonitor *aOwner, + const char* aKey, + const char* aType, + unsigned char aSize, + SuperIOSensorGroup aGroup, + unsigned long aIndex, + long aRi, + long aRf, + long aVf) { + SuperIOSensor *me = new SuperIOSensor; + + if (me && !me->initWithOwner(aOwner, aKey, aType, aSize, aGroup, aIndex ,aRi,aRf,aVf)) { + me->release(); + return 0; + } + + return me; +} + +const char *SuperIOSensor::getName() { + return name; +} + +const char *SuperIOSensor::getType() { + return type; +} + +unsigned char SuperIOSensor::getSize() { + return size; +} + +SuperIOSensorGroup SuperIOSensor::getGroup() { + return group; +} + +unsigned long SuperIOSensor::getIndex() { + return index; +} + +inline UInt8 get_index(char c) { + return c > 96 && c < 103 ? c - 87 : c > 47 && c < 58 ? c - 48 : 0; +} + + +long SuperIOSensor::encodeValue(UInt32 value, int sscale) { //Vscale=1, Tscale=1000 + // UInt32 tmp = 0; + int svalue = (int)value; + if ((type[0] == 'u' || type[0] == 's') && type[1] == 'i') { + + bool minus = svalue < 0; + + if (type[0] == 'u' && minus) { + svalue = -svalue; + minus = false; + } + + switch (type[2]) { + case '8': + if (type[3] == '\0' && size == 1) { + UInt8 out = minus ? (UInt8)(-svalue) | 0x80 : (UInt8)svalue; + return out; + } + break; + case '1': + if (type[3] == '6' && size == 2) { + UInt16 out = OSSwapHostToBigInt16(minus ? (UInt16)(-svalue) | 0x8000 : (UInt16)value); + return out; + } + break; + case '3': + if (type[3] == '2' && size == 4) { + UInt32 out = OSSwapHostToBigInt32(minus ? (UInt32)(-svalue) | 0x80000000 : value); + return out; + } + break; + default: + return 0; + } + } else if ((type[0] == 'f' || type[0] == 's') && type[1] == 'p') { + + bool minus = svalue < 0; + UInt8 i = get_index(type[2]); + UInt8 f = get_index(type[3]); + + if (i + f == (type[0] == 'f' ? 16 : 15)) { + UInt64 mult = (minus ? -svalue : svalue) * sscale ; + UInt64 encoded = ((mult << f) / 1000) & 0xffff; + UInt16 out = OSSwapHostToBigInt16(minus ? (UInt16)(encoded | 0x8000) : (UInt16)encoded); + return out; + } + } + return svalue; +} + +long SuperIOSensor::getValue() { + UInt16 value = 0; + + switch (group) { + case kSuperIOTemperatureSensor: + value = owner->readTemperature(index); + break; + case kSuperIOVoltageSensor: + value = owner->readVoltage(index); + break; + case kSuperIOTachometerSensor: + value = owner->readTachometer(index); + break; + default: + break; + } + /* + if (*((uint32_t*)type) == *((uint32_t*)TYPE_FP2E)) { + value = encode_fp2e(value); + } + else if (*((uint32_t*)type) == *((uint32_t*)TYPE_FPE2)) { + value = encode_fpe2(value); + } + */ + if (*((uint32_t*)type) == *((uint32_t*)TYPE_FP2E)) { + value = encode_fp2e(value); + } else if (*((uint32_t*)type) == *((uint32_t*)TYPE_SP4B)) { + value = encode_sp4b(value); + } else if (*((uint32_t*)type) == *((uint32_t*)TYPE_FPE2)) { + value = encode_fpe2(value); + } + // value = encodeValue(value, scale); + return value; +} + +bool SuperIOSensor::initWithOwner(SuperIOMonitor *aOwner, + const char* aKey, + const char* aType, + unsigned char aSize, + SuperIOSensorGroup aGroup, + unsigned long aIndex, + long aRi, + long aRf, + long aVf) { + if (!OSObject::init()) { + return false; + } + + if (!(owner = aOwner)) { + return false; + } + + if (!(name = (char *)IOMalloc(5))) { + return false; + } + + bcopy(aKey, name, 4); + name[5] = '\0'; + + if (!(type = (char *)IOMalloc(5))) { + return false; + } + + bcopy(aType, type, 4); + type[5] = '\0'; + Ri = aRi; + Rf = aRf; + Vf = aVf; + + size = aSize; + group = aGroup; + index = aIndex; + switch (group) { + case kSuperIOTemperatureSensor: + case kSuperIOTachometerSensor: + scale = 1000; + break; + case kSuperIOVoltageSensor: + scale = 1; + break; + case kSuperIOFrequency: + scale = 10; + break; + } + + return true; +} + +void SuperIOSensor::free() { + if (name) { + IOFree(name, 5); + } + + if (type) { + IOFree(type, 5); + } + + OSObject::free(); +} + +// Monitor + +#define super IOService +OSDefineMetaClassAndAbstractStructors(SuperIOMonitor, IOService) + +UInt8 SuperIOMonitor::listenPortByte(UInt8 reg) { + outb(registerPort, reg); + return inb(valuePort); +} + +UInt16 SuperIOMonitor::listenPortWord(UInt8 reg) { + return ((listenPortByte(reg) << 8) | listenPortByte(reg + 1)); +} + +void SuperIOMonitor::selectLogicalDevice(UInt8 num) { + outb(registerPort, SUPERIO_DEVICE_SELECT_REGISTER); + outb(valuePort, num); +} + +bool SuperIOMonitor::getLogicalDeviceAddress(UInt8 reg) { + address = listenPortWord(reg); + + if (address < 0x100 || (address & 0xF007) != 0) { + return false; + } + IOSleep(250); + + if (address != listenPortWord(reg)) { + return false; + } + return true; +} + +int SuperIOMonitor::getPortsCount() { + return 2; +} + +void SuperIOMonitor::selectPort(unsigned char index) { + registerPort = SUPERIO_STANDART_PORT[index]; + valuePort = SUPERIO_STANDART_PORT[index] + 1; +} + +bool SuperIOMonitor::probePort() { + return true; +} + +long SuperIOMonitor::readVoltage(unsigned long index) { + return 0; +} + +long SuperIOMonitor::readTachometer(unsigned long index) { + return 0; +} + +long SuperIOMonitor::readTemperature(unsigned long index) { + return 0; +} + +void SuperIOMonitor::enter() { +}; + +void SuperIOMonitor::exit() { +}; + +bool SuperIOMonitor::updateSensor(const char *key, + const char *type, + unsigned int size, + SuperIOSensorGroup group, + unsigned long index) { + long value = 0; + + switch (group) { + case kSuperIOTemperatureSensor: + value = readTemperature(index); + break; + case kSuperIOVoltageSensor: + value = readVoltage(index); + break; + case kSuperIOTachometerSensor: + value = readTachometer(index); + break; + default: + break; + } + + if (strcmp(type, TYPE_FP2E) == 0) { + value = encode_fp2e(value); + } else if (strcmp(type, TYPE_FPE2) == 0) { + value = encode_fpe2(value); + } + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCSetKeyValue, + true, (void*)key, + (void*)(long long)size, + (void*)&value, 0)) { + return false; + } + + return true; +} + +const char *SuperIOMonitor::getModelName() { + return "Unknown"; +} + +SuperIOSensor *SuperIOMonitor::addSensor(const char* name, + const char* type, + unsigned int size, + SuperIOSensorGroup group, + unsigned long index, + long aRi, + long aRf, + long aVf) { + if (NULL != getSensor(name)) { + return 0; + } + + SuperIOSensor *sensor = SuperIOSensor::withOwner(this, name, type, size, group, index); + + if (sensor && sensors->setObject(sensor)) { + if(kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)name, + (void *)type, + (void *)(long long)size, + (void *)this)) { + return sensor; + } + } + return 0; +} + +SuperIOSensor *SuperIOMonitor::addTachometer(unsigned long index, const char* id) { + UInt8 length = 0; + void * data = 0; + + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCGetKeyValue, + true, + (void *)KEY_FAN_NUMBER, + (void *)&length, + (void *)&data, 0)) { + length = 0; + bcopy(data, &length, 1); + char name[5]; + + snprintf(name, 5, KEY_FORMAT_FAN_SPEED, length); + + if (SuperIOSensor *sensor = addSensor(name, TYPE_FPE2, 2, kSuperIOTachometerSensor, index)) { + if (id) { + FanTypeDescStruct fds; + snprintf(name, 5, KEY_FORMAT_FAN_ID, length); + fds.type = FAN_PWM_TACH; + fds.ui8Zone = 1; + fds.location = LEFT_LOWER_FRONT; + strncpy(fds.strFunction, id, DIAG_FUNCTION_STR_LEN); + + // if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyValue, false, (void *)name, (void *)TYPE_CH8, (void *)((UInt64)strlen(id)), (void *)id)) + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCAddKeyValue, + false, (void *)name, + (void *)TYPE_FDESC, + (void *)((UInt64)sizeof(fds)), + (void *)&fds)) { + WarningLog("error adding tachometer id value"); + } + } + + length++; + + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCSetKeyValue, + true, + (void *)KEY_FAN_NUMBER, + (void *)1, + (void *)&length, 0)) { + WarningLog("error updating FNum value"); + } + + return sensor; + } + } else { + WarningLog("error reading FNum value"); + } + + return 0; +} + +SuperIOSensor * SuperIOMonitor::getSensor(const char* key) { + if (OSCollectionIterator *iterator = OSCollectionIterator::withCollection(sensors)) { + UInt32 key1 = *((uint32_t*)key); + + while (SuperIOSensor *sensor = OSDynamicCast(SuperIOSensor, iterator->getNextObject())) { + UInt32 key2 = *((uint32_t*)sensor->getName()); + if (key1 == key2) { + return sensor; + } + } + } + + return 0; +} + +bool SuperIOMonitor::init(OSDictionary *properties) { + DebugLog("initialising..."); + if (!super::init(properties)) { + return false; + } + + if (!(sensors = OSArray::withCapacity(0))) { + return false; + } + + model = 0; + return true; +} + +IOService *SuperIOMonitor::probe(IOService *provider, SInt32 *score) { + DebugLog("probing..."); + if (super::probe(provider, score) != this) { + return 0; + } + + for (UInt8 i = 0; i < getPortsCount(); i++) { + selectPort(i); + enter(); + if (probePort()) { + exit(); + return this; + } + exit(); + } + + return 0; +} + +bool SuperIOMonitor::start(IOService *provider) { + DebugLog("starting..."); + if (!super::start(provider)) { + return false; + } + + if (!(fakeSMC = waitForService(serviceMatching(kFakeSMCDeviceService)))) { + WarningLog("can't locate fake SMC device, kext will not load"); + return false; + } + + return true; +} + +void SuperIOMonitor::stop(IOService* provider) { + DebugLog("stoping..."); + super::stop(provider); +} + +void SuperIOMonitor::free() { + DebugLog("freeing..."); + sensors->release(); + super::free(); +} + +IOReturn SuperIOMonitor::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4) { + if (functionName->isEqualTo(kFakeSMCGetValueCallback)) { + const char* name = (const char*)param1; + void * data = param2; + //UInt32 size = (UInt64)param3; + + if (name && data) { + if (SuperIOSensor *sensor = getSensor(name)) { + UInt16 value = sensor->getValue(); + bcopy(&value, data, 2); + return kIOReturnSuccess; + } + } + return kIOReturnBadArgument; + } + + return super::callPlatformFunction(functionName, + waitForFunction, + param1, + param2, + param3, + param4); +} diff --git a/plugins/SuperIOSensors/SuperIOFamily/SuperIOFamily.h b/plugins/SuperIOSensors/SuperIOFamily/SuperIOFamily.h new file mode 100644 index 0000000..fdd69ec --- /dev/null +++ b/plugins/SuperIOSensors/SuperIOFamily/SuperIOFamily.h @@ -0,0 +1,155 @@ +/* + * SuperIOFamily.h + * HWSensors + * + * Created by mozo on 08/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +#ifndef _SUPERIOMONITOR_H +#define _SUPERIOMONITOR_H + +#include +#include +#include + +OSString * vendorID(OSString * smbios_manufacturer); + +// Ports +const UInt8 SUPERIO_STANDART_PORT[] = { 0x2e, 0x4e }; + +// Registers +const UInt8 SUPERIO_CONFIGURATION_CONTROL_REGISTER = 0x02; +const UInt8 SUPERIO_DEVICE_SELECT_REGISTER = 0x07; +const UInt8 SUPERIO_CHIP_ID_REGISTER = 0x20; +const UInt8 SUPERIO_CHIP_REVISION_REGISTER = 0x21; +const UInt8 SUPERIO_BASE_ADDRESS_REGISTER = 0x60; +const UInt8 WINBOND_CHIP_IPD_REGISTER = 0x23; //Immediate Power Down +const UInt8 ITE_CHIP_SUSPEND_REGISTER = 0x24; +const UInt8 FINTEK_CHIP_IPD_REGISTER = 0x25; //Software Power Down + + +enum SuperIOSensorGroup { + kSuperIOTemperatureSensor, + kSuperIOTachometerSensor, + kSuperIOVoltageSensor, + kSuperIOFrequency +}; + +class SuperIOMonitor; + +class SuperIOSensor : public OSObject { + OSDeclareDefaultStructors(SuperIOSensor) + +protected: + SuperIOMonitor * owner; + char * name; + char * type; + unsigned char size; + SuperIOSensorGroup group; + unsigned long index; + int scale; + long Ri; + long Rf; + long Vf; + + +public: + static SuperIOSensor *withOwner(SuperIOMonitor *aOwner, + const char* aKey, + const char* aType, + unsigned char aSize, + SuperIOSensorGroup aGroup, + unsigned long aIndex, + long aRi=0, + long aRf=1, + long aVf=0); + + const char * getName(); + const char * getType(); + unsigned char getSize(); + SuperIOSensorGroup getGroup(); + unsigned long getIndex(); + long encodeValue(UInt32 value, int scale); + + virtual bool initWithOwner(SuperIOMonitor *aOwner, + const char* aKey, + const char* aType, + unsigned char aSize, + SuperIOSensorGroup aGroup, + unsigned long aIndex, + long aRi, + long aRf, + long aVf); + + virtual long getValue(); + virtual void free(); +}; + +class SuperIOMonitor : public IOService { + OSDeclareAbstractStructors(SuperIOMonitor) + +protected: + IOService * fakeSMC; + + UInt16 address; + UInt8 registerPort; + UInt8 valuePort; + + UInt32 model; + + OSArray * sensors; + + UInt8 listenPortByte(UInt8 reg); + UInt16 listenPortWord(UInt8 reg); + void selectLogicalDevice(UInt8 num); + bool getLogicalDeviceAddress(UInt8 reg = SUPERIO_BASE_ADDRESS_REGISTER); + + virtual int getPortsCount(); + virtual void selectPort(unsigned char index); + virtual bool probePort(); + virtual void enter(); + virtual void exit(); + + virtual const char *getModelName(); + + SuperIOSensor *addSensor(const char* key, + const char* type, + unsigned int size, + SuperIOSensorGroup group, + unsigned long index, + long aRi=0, + long aRf=1, + long aVf=0); + + SuperIOSensor *addTachometer(unsigned long index, const char* id = 0); + + SuperIOSensor *getSensor(const char* key); + + virtual bool updateSensor(const char *key, + const char *type, + unsigned int size, + SuperIOSensorGroup group, + unsigned long index); + +public: + virtual long readTemperature(unsigned long index); + virtual long readVoltage(unsigned long index); + virtual long readTachometer(unsigned long index); + + virtual bool init(OSDictionary *properties=0); + virtual IOService* probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual void stop(IOService *provider); + virtual void free(void); + + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); +}; + +#endif diff --git a/plugins/SuperIOSensors/WinbondW836x/WinbondW836x-Info.plist b/plugins/SuperIOSensors/WinbondW836x/WinbondW836x-Info.plist new file mode 100755 index 0000000..4c03adb --- /dev/null +++ b/plugins/SuperIOSensors/WinbondW836x/WinbondW836x-Info.plist @@ -0,0 +1,641 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(MODULE_VERSION) + IOKitPersonalities + + Winbond W836x Monitor Plugin + + CFBundleIdentifier + org.mozodojo.${PRODUCT_NAME} + IOClass + W836x + IOMatchCategory + W836x + IOProviderClass + IOResources + IOResourceMatch + IOKit + Sensors Configuration + + ASRock + + 880GMH/USB3 + + FANIN0 + Chasis Fan + FANIN1 + CPU Fan + FANIN2 + Power Fan + FANIN3 + + FANIN4 + + FANINLIMIT + 3 + TEMPIN0 + CPU + TEMPIN1 + + TEMPIN2 + System + VIN0 + CPU + VIN1 + + VIN2 + + VIN3 + + Name + 3VCC + Rf + 100 + Ri + 100 + VRef + 0 + + VIN4 + + VIN5 + + Name + +5VC + Rf + 75 + Ri + 150 + VRef + 0 + + VIN6 + + Name + +12VC + Rf + 100 + Ri + 560 + VRef + 0 + + VIN7 + + Name + 3VSB + Rf + 100 + Ri + 100 + VRef + 0 + + VIN8 + + Name + VBAT + Rf + 100 + Ri + 100 + VRef + 0 + + VIN9 + + + + ASUS + + P5E3 Premium + + FANIN0 + + FANIN1 + CPU Fan + FANIN2 + + FANIN3 + + FANIN4 + + FANINLIMIT + 5 + TEMPIN0FORCED + + TEMPIN1FORCED + + VIN0 + CPU + VIN1 + + Name + +12VC + Rf + 10 + Ri + 60 + VRef + 0 + + VIN2 + AVCC + VIN3 + 3VCC + VIN4 + + VIN5 + + Name + +5VC + Rf + 10 + Ri + 20 + VRef + 0 + + VIN6 + + VIN7 + + VIN8 + + + P6T + + FANIN0 + System Fan + FANIN1 + CPU Fan + FANIN2 + Auxiliary + FANIN3 + CPU Fan 2 + FANIN4 + Auxiliary Fan 2 + FANINLIMIT + 5 + TEMPIN0 + CPU + TEMPIN1 + + TEMPIN2 + System + VIN0 + CPU + VIN1 + + Name + +12VC + Rf + 191 + Ri + 1150 + VRef + 0 + + VIN2 + + VIN3 + + Name + 3VCC + Rf + 100 + Ri + 100 + VRef + 0 + + VIN4 + + Name + +5VC + Rf + 75 + Ri + 150 + VRef + 0 + + VIN5 + + VIN6 + + VIN7 + + Name + 3VSB + Rf + 100 + Ri + 100 + VRef + 0 + + VIN8 + + Name + VBAT + Rf + 100 + Ri + 100 + VRef + 0 + + VIN9 + + + P6T DELUXE V2 + + FANIN0 + System Fan + FANIN1 + CPU Fan + FANIN2 + Auxiliary + FANIN3 + CPU Fan 2 + FANIN4 + Auxiliary Fan 2 + FANINLIMIT + 5 + TEMPIN0 + CPU + TEMPIN1 + + TEMPIN2 + System + VIN0 + CPU + VIN1 + + Name + +12VC + Rf + 191 + Ri + 1150 + VRef + 0 + + VIN2 + + VIN3 + + Name + 3VCC + Rf + 100 + Ri + 100 + VRef + 0 + + VIN4 + + Name + +5VC + Rf + 75 + Ri + 150 + VRef + 0 + + VIN5 + + VIN6 + + VIN7 + + Name + 3VSB + Rf + 100 + Ri + 100 + VRef + 0 + + VIN8 + + Name + VBAT + Rf + 100 + Ri + 100 + VRef + 0 + + VIN9 + Power Supply 8 + + P6X58D-E + + FANIN0 + System Fan + FANIN1 + CPU Fan + FANIN2 + Auxiliary + FANIN3 + CPU Fan 2 + FANIN4 + Auxiliary Fan 2 + FANINLIMIT + 4 + TEMPIN0 + CPU + TEMPIN1 + + TEMPIN2 + System + VIN0 + CPU + VIN1 + + Name + +12VC + Rf + 191 + Ri + 1150 + VRef + 0 + + VIN2 + + VIN3 + + Name + 3VCC + Rf + 100 + Ri + 100 + VRef + 0 + + VIN4 + + Name + +5VC + Rf + 75 + Ri + 150 + VRef + 0 + + VIN5 + + VIN6 + + VIN7 + + Name + 3VSB + Rf + 100 + Ri + 100 + VRef + 0 + + VIN8 + + Name + VBAT + Rf + 100 + Ri + 100 + VRef + 0 + + VIN9 + Power Supply 8 + + P7P55D LE + + FANIN0 + Chassis Fan 1 + FANIN1 + CPU Fan + FANIN2 + Chassis Fan 2 + FANIN3 + Chassis Fan 3 + FANIN4 + Power Fan + FANINLIMIT + 4 + TEMPIN0 + CPU + TEMPIN1 + Ambient + TEMPIN2 + System + VIN0 + CPU + VIN1 + Memory + VIN2 + 3VCC + VIN3 + + Name + +12VC + Rf + 1000 + Ri + 7193 + VRef + + + VIN4 + + Name + +5VC + Rf + 1000 + Ri + 2000 + VRef + 0 + + VIN5 + + VIN6 + + VIN7 + + VIN8 + + + Rampage II GENE + + FANIN0 + System Fan + FANIN1 + CPU Fan + FANIN2 + Auxiliary + FANIN3 + CPU Fan 2 + FANIN4 + Auxiliary Fan 2 + FANINLIMIT + 4 + TEMPIN0 + CPU + TEMPIN1 + + TEMPIN2 + System + VIN0 + CPU + VIN1 + + Name + +12VC + Rf + 191 + Ri + 1150 + VRef + 0 + + VIN2 + + VIN3 + + Name + 3VCC + Rf + 100 + Ri + 100 + VRef + 0 + + VIN4 + + Name + +5VC + Rf + 75 + Ri + 150 + VRef + 0 + + VIN5 + + VIN6 + + VIN7 + + Name + 3VSB + Rf + 100 + Ri + 100 + VRef + 0 + + VIN8 + + Name + VBAT + Rf + 100 + Ri + 100 + VRef + 0 + + VIN9 + + + + Default + + FANIN0 + CPU Fan + FANIN1 + System Fan + FANIN2 + Aux Fan + FANIN3 + + FANIN4 + + FANINLIMIT + 3 + TEMPIN0FORCED + + TEMPIN1FORCED + + VIN0 + CPU + VIN1 + -12VC + VIN2 + AVSB + VIN3 + 3VCC + VIN4 + 5VCC + VIN5 + 12VC + VIN6 + + VIN7 + 3VSB + VIN8 + VBAT + + + + + OSBundleLibraries + + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.mach + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.3.0 + + OSBundleRequired + Root + + diff --git a/plugins/SuperIOSensors/WinbondW836x/WinbondW836x-Prefix.pch b/plugins/SuperIOSensors/WinbondW836x/WinbondW836x-Prefix.pch new file mode 100755 index 0000000..39bab81 --- /dev/null +++ b/plugins/SuperIOSensors/WinbondW836x/WinbondW836x-Prefix.pch @@ -0,0 +1,4 @@ +// +// Prefix header for all source files of the 'WinbondW836x' target in the 'WinbondW836x' project +// + diff --git a/plugins/SuperIOSensors/WinbondW836x/WinbondW836x.cpp b/plugins/SuperIOSensors/WinbondW836x/WinbondW836x.cpp new file mode 100755 index 0000000..d82c6ae --- /dev/null +++ b/plugins/SuperIOSensors/WinbondW836x/WinbondW836x.cpp @@ -0,0 +1,1008 @@ +/* + * W836x.cpp + * HWSensors + * + * Based on code from Open Hardware Monitor project by Michael Möller (C) 2011 + * + * Created by mozo on 14/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +/* + + Version: MPL 1.1/GPL 2.0/LGPL 2.1 + + The contents of this file are subject to the Mozilla Public License Version + 1.1 (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + The Original Code is the Open Hardware Monitor code. + + The Initial Developer of the Original Code is + Michael Möller . + Portions created by the Initial Developer are Copyright (C) 2011 + the Initial Developer. All Rights Reserved. + + Contributor(s): + + Alternatively, the contents of this file may be used under the terms of + either the GNU General Public License Version 2 or later (the "GPL"), or + the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + in which case the provisions of the GPL or the LGPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of either the GPL or the LGPL, and not to allow others to + use your version of this file under the terms of the MPL, indicate your + decision by deleting the provisions above and replace them with the notice + and other provisions required by the GPL or the LGPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the MPL, the GPL or the LGPL. + + */ + +#include "WinbondW836x.h" + +#include +//#include "cpuid.h" +#include "FakeSMC.h" +#include "../../../utils/utils.h" + +//#define Debug false + +#define LogPrefix "W836x: " +#define DebugLog(string, args...) do { if (Debug) { IOLog (LogPrefix "[Debug] " string "\n", ## args); } } while(0) +#define WarningLog(string, args...) do { IOLog (LogPrefix "[Warning] " string "\n", ## args); } while(0) +#define InfoLog(string, args...) do { IOLog (LogPrefix string "\n", ## args); } while(0) + +#define super SuperIOMonitor +OSDefineMetaClassAndStructors(W836x, SuperIOMonitor) + +OSDefineMetaClassAndStructors(W836xSensor, SuperIOSensor) + +#pragma mark W836xSensor implementation + +SuperIOSensor * W836xSensor::withOwner(SuperIOMonitor *aOwner, + const char* aKey, + const char* aType, + unsigned char aSize, + SuperIOSensorGroup aGroup, + unsigned long aIndex, + long aRi, + long aRf, + long aVf) { + SuperIOSensor *me = new W836xSensor; + // DebugLog("with owner mults = %ld", aRi); + if (me && !me->initWithOwner(aOwner, aKey, aType, aSize, aGroup, aIndex ,aRi,aRf,aVf)) { + me->release(); + return 0; + } + + return me; +} + +long W836xSensor::getValue() { + UInt16 value = 0; + switch (group) { + case kSuperIOTemperatureSensor: + value = owner->readTemperature(index); + break; + case kSuperIOVoltageSensor: + value = owner->readVoltage(index); + break; + case kSuperIOTachometerSensor: + value = owner->readTachometer(index); + break; + default: + break; + } + + if (Rf == 0) { + Rf = 1; + Ri = 0; + Vf = 0; + WarningLog("Rf == 0 when getValue index=%d value=%04x", (int)index, value); + } + // DebugLog("value = %ld Ri=%ld Rf=%ld", (long)value, Ri, Rf); + value = value + ((value - Vf) * Ri)/Rf; + + if (*((uint32_t*)type) == *((uint32_t*)TYPE_FP2E)) { + value = encode_fp2e(value); + } else if (*((uint32_t*)type) == *((uint32_t*)TYPE_SP4B)) { + value = encode_sp4b(value); + } else if (*((uint32_t*)type) == *((uint32_t*)TYPE_FPE2)) { + value = encode_fpe2(value); + } + + return value; +} + +UInt8 W836x::readByte(UInt8 bank, UInt8 reg) { + outb((UInt16)(address + WINBOND_ADDRESS_REGISTER_OFFSET), WINBOND_BANK_SELECT_REGISTER); + outb((UInt16)(address + WINBOND_DATA_REGISTER_OFFSET), bank); + outb((UInt16)(address + WINBOND_ADDRESS_REGISTER_OFFSET), reg); + return inb((UInt16)(address + WINBOND_DATA_REGISTER_OFFSET)); +} + +void W836x::writeByte(UInt8 bank, UInt8 reg, UInt8 value) { + outb((UInt16)(address + WINBOND_ADDRESS_REGISTER_OFFSET), WINBOND_BANK_SELECT_REGISTER); + outb((UInt16)(address + WINBOND_DATA_REGISTER_OFFSET), bank); + outb((UInt16)(address + WINBOND_ADDRESS_REGISTER_OFFSET), reg); + outb((UInt16)(address + WINBOND_DATA_REGISTER_OFFSET), value); +} + +UInt64 W836x::setBit(UInt64 target, UInt16 bit, UInt32 value) { + if (((value & 1) == value) && bit <= 63) { + UInt64 mask = (((UInt64)1) << bit); + return value > 0 ? target | mask : target & ~mask; + } + + return value; +} + +long W836x::readTemperature(unsigned long index) { + UInt32 bank, reg; + UInt32 value; + if (model >= NCT6681) { + bank = NUVOTON_NEW_TEMPERATURE1[index] >> 8; + reg = NUVOTON_NEW_TEMPERATURE1[index] & 0xFF; + } else { + bank = WINBOND_TEMPERATURE[index] >> 8; + reg = WINBOND_TEMPERATURE[index] & 0xFF; + } + value = readByte(bank, reg) << 1; + + if (bank > 0) { + value |= (readByte(bank, (UInt8)(reg + 1)) >> 7) & 1; + } + + float temperature = (float)value / 2.0f; + + return (temperature <= 125 && temperature >= -55) ? temperature : 0; +} + +long W836x::readVoltage(unsigned long index) { + UInt32 scale, reg, bank; + + if (model >= NCT6791D) { + scale = 8; + reg = NUVOTON_VOLTAGE_REG[index] & 0xFF; + bank = NUVOTON_VOLTAGE_REG[index] >> 8; + } else { + scale = WINBOND_VOLTAGE_SCALE[index]; + reg = WINBOND_VOLTAGE_REG[index] & 0xFF; + bank = WINBOND_VOLTAGE_REG[index] >> 8; + } + + if (index < 9) { + float value = readByte(bank, reg) * scale; + bool valid = value > 0; + + // check if battery voltage monitor is enabled + if (valid && reg == WINBOND_VOLTAGE_VBAT_REG) { + valid = (readByte(0, 0x5D) & 0x01) > 0; + } + + return valid ? value : 0; + } + + return 0; +} + +void W836x::updateTachometers() { + if (model >= NCT6681) { + for (int i = 0; i < fanLimit; i++) { + int bank = NUVOTON_TACHOMETER[i] >> 8; + int reg = NUVOTON_TACHOMETER[i] & 0xFF; + int16_t msbyte = readByte(bank, reg); + int16_t lsbyte = readByte(bank, reg + 1); + fanValue[i] = (msbyte << 8) + lsbyte; + fanValueObsolete[i] = false; + } + return; + } + + UInt64 bits = 0; + + for (int i = 0; i < 5; i++) { + bits = (bits << 8) | readByte(0, WINBOND_TACHOMETER_DIVISOR[i]); + } + + UInt64 newBits = bits; + + for (int i = 0; i < fanLimit; i++) { + // assemble fan divisor + UInt8 offset = (((bits >> WINBOND_TACHOMETER_DIVISOR2[i]) & 1) << 2) | + (((bits >> WINBOND_TACHOMETER_DIVISOR1[i]) & 1) << 1) | + ((bits >> WINBOND_TACHOMETER_DIVISOR0[i]) & 1); + + UInt8 divisor = 1 << offset; + UInt8 count = readByte(WINBOND_TACHOMETER_BANK[i], WINBOND_TACHOMETER[i]); + + // update fan divisor + if (count > 192 && offset < 7) { + offset++; + } else if (count < 96 && offset > 0) { + offset--; + } + + fanValue[i] = (count < 0xff) ? 1.35e6f / (float(count * divisor)) : 0; + fanValueObsolete[i] = false; + + newBits = setBit(newBits, WINBOND_TACHOMETER_DIVISOR2[i], (offset >> 2) & 1); + newBits = setBit(newBits, WINBOND_TACHOMETER_DIVISOR1[i], (offset >> 1) & 1); + newBits = setBit(newBits, WINBOND_TACHOMETER_DIVISOR0[i], offset & 1); + } + + // write new fan divisors + for (int i = 4; i >= 0; i--) { + UInt8 oldByte = bits & 0xff; + UInt8 newByte = newBits & 0xff; + + if (oldByte != newByte) { + writeByte(0, WINBOND_TACHOMETER_DIVISOR[i], newByte); + } + + bits = bits >> 8; + newBits = newBits >> 8; + } +} + + +long W836x::readTachometer(unsigned long index) { + if (fanValueObsolete[index]) { + updateTachometers(); + } + fanValueObsolete[index] = true; + + return fanValue[index]; +} + +void W836x::enter() { + outb(registerPort, 0x87); + outb(registerPort, 0x87); +} + +void W836x::exit() { + outb(registerPort, 0xAA); + //outb(registerPort, SUPERIO_CONFIGURATION_CONTROL_REGISTER); + //outb(valuePort, 0x02); +} + +bool W836x::probePort() { + model = 0; + UInt8 id =listenPortByte(SUPERIO_CHIP_ID_REGISTER); + + IOSleep(50); + + UInt8 revision = listenPortByte(SUPERIO_CHIP_REVISION_REGISTER); + + if (id == 0 || id == 0xff || revision == 0 || revision == 0xff) { + return false; + } + + fanLimit = 6; + + switch (id) { + case 0x52: { + switch (revision & 0xf0) { + case 0x10: + case 0x30: + case 0x40: + case 0x41: + model = W83627HF; + fanLimit = 3; + break; + /* + case 0x70: + model = W83977CTF; + break; + case 0xf0: + model = W83977EF; + break; + */ + } + } + case 0x59: { + switch (revision & 0xf0) { + case 0x50: + model = W83627SF; + fanLimit = 3; + break; + } + break; + } + case 0x60: { + switch (revision & 0xf0) { + case 0x10: + model = W83697HF; + fanLimit = 2; + break; + } + break; + } + /* + case 0x61: + { + switch (revision & 0xf0) + { + case 0x00: + model = W83L517D; + break; + } + break; + } + */ + case 0x68: { + switch (revision & 0xf0) { + case 0x10: + model = W83697SF; + fanLimit = 2; + break; + } + break; + } + case 0x70: { + switch (revision & 0xf0) { + case 0x80: + model = W83637HF; + fanLimit = 5; + break; + } + break; + } + case 0x82: { + switch (revision & 0xF0) { + case 0x80: + model = W83627THF; + fanLimit = 3; + break; + } + break; + } + case 0x85: { + switch (revision) { + case 0x41: + model = W83687THF; + fanLimit = 3; + // No datasheet + break; + } + break; + } + case 0x88: { + switch (revision & 0xF0) { + case 0x50: + case 0x60: + model = W83627EHF; + fanLimit = 5; + break; + } + break; + } + /* + case 0x97: + { + switch (revision) + { + case 0x71: + model = W83977FA; + break; + case 0x73: + model = W83977TF; + break; + case 0x74: + model = W83977ATF; + break; + case 0x77: + model = W83977AF; + break; + } + break; + } + */ + case 0xA0: { + switch (revision & 0xF0) { + case 0x20: + model = W83627DHG; + fanLimit = 5; + break; + } + break; + } + case 0xA2: { + switch (revision & 0xF0) { + case 0x30: + model = W83627UHG; + fanLimit = 2; + break; + } + break; + } + case 0xA5: { + switch (revision & 0xF0) { + case 0x10: + model = W83667HG; + fanLimit = 2; + break; + } + break; + } + case 0xB0: { + switch (revision & 0xF0) { + case 0x70: + model = W83627DHGP; + fanLimit = 5; + break; + } + break; + } + case 0xB3: { + switch (revision & 0xF0) { + case 0x50: + model = W83667HGB; + fanLimit = 4; + break; + } + break; + } + case 0xC2: + model = NCT6681; + fanLimit = 5; + break; + case 0xB4: + switch (revision & 0xF0) { + case 0x70: + model = NCT6771F; + //minFanRPM = (int)(1.35e6 / 0xFFFF); + break; + } + break; + case 0xC3: + switch (revision & 0xF0) { + case 0x30: + model = NCT6776F; + //minFanRPM = (int)(1.35e6 / 0x1FFF); + break; + } + break; + case 0xC5: + switch (revision & 0xF0) { + case 0x60: + model = NCT6779D; + //minFanRPM = (int)(1.35e6 / 0x1FFF); + break; + } + break; + case 0xC7: + model = NCT6683; + break; + case 0xC8: + model = NCT6791D; + //minFanRPM = (int)(1.35e6 / 0x1FFF); + break; + case 0xC9: + model = NCT6792D; + break; + case 0xD1: + model = NCT6793D; + break; + case 0xD3: + model = NCT6795D; + break; + case 0xD4: + switch (revision) { + case 0x23: + model = NCT6796D; + break; + case 0x28: + model = NCT6798D; + break; + case 0x2B: + model = NCT679BD; + break; + case 0x51: + model = NCT6797D; + break; + default: + break; + } + break; + default: + break; + } + + if (!model) { + WarningLog("found unsupported chip ID=0x%x REVISION=0x%x", id, revision); + return false; + } + + selectLogicalDevice(WINBOND_HARDWARE_MONITOR_LDN); + + IOSleep(50); + // UInt16 vendor = (UInt16)(readByte(0x80, WINBOND_VENDOR_ID_REGISTER) << 8) | readByte(0, WINBOND_VENDOR_ID_REGISTER); + // + // if (vendor != WINBOND_VENDOR_ID) + // { + // DebugLog("wrong vendor ID=0x%x", vendor); + // return false; + // } + // + // IOSleep(50); + + if (!getLogicalDeviceAddress()) { + DebugLog("can't get monitoring logical device address"); + return false; + } + + //now I want to dump several registers + InfoLog("Dump Nuvoton registers:"); + InfoLog("- 100: %02x", readByte(1, 0)); + InfoLog("- 200: %02x", readByte(2, 0)); + InfoLog("- 300: %02x", readByte(3, 0)); + InfoLog("- 73: %02x", readByte(0, 0x73)); + InfoLog("- 75: %02x", readByte(0, 0x75)); + InfoLog("- 77: %02x", readByte(0, 0x77)); + InfoLog("- 79: %02x", readByte(0, 0x79)); + + for (int i = 0; i<4; i++) { + int reg; + int bank, index; + reg = NUVOTON_TEMPERATURE[i]; + bank = reg >> 8; + index = reg & 0xFF; + + InfoLog("- %x: %02x", reg, readByte(bank, index)); + } + // + for (int i = 0; i<4; i++) { + int reg; + int bank, index; + reg = WINBOND_VOLTAGE_REG[i]; + bank = reg >> 8; + index = reg & 0xFF; + + InfoLog("- %x: %02x", reg, readByte(bank, index)); + } + + return true; +} + +bool W836x::init(OSDictionary *properties) { + DebugLog("initialising..."); + + if (!super::init(properties)) { + return false; + } + + return true; +} + +IOService* W836x::probe(IOService *provider, SInt32 *score) { + DebugLog("probing..."); + + if (super::probe(provider, score) != this) { + return 0; + } + + return this; +} + +void W836x::stop (IOService* provider) { + DebugLog("stoping..."); + if (kIOReturnSuccess != fakeSMC->callPlatformFunction(kFakeSMCRemoveKeyHandler, + true, + this, + NULL, + NULL, + NULL)) { + WarningLog("Can't remove key handler"); + IOSleep(500); + } + + super::stop(provider); +} + +void W836x::free() { + DebugLog("freeing..."); + super::free(); +} + +bool W836x::start(IOService * provider) { + DebugLog("starting ..."); + + if (!super::start(provider)) { + return false; + } + + InfoLog("found %s", getModelName()); + OSDictionary* list = OSDynamicCast(OSDictionary, getProperty("Sensors Configuration")); + OSDictionary *configuration=NULL; + IORegistryEntry * rootNode; + + rootNode = fromPath("/efi/platform", gIODTPlane); + + if (rootNode) { + OSData *data = OSDynamicCast(OSData, rootNode->getProperty("OEMVendor")); + if (data) { + bcopy(data->getBytesNoCopy(), vendor, data->getLength()); + OSString * VendorNick = vendorID(OSString::withCString(vendor)); + if (VendorNick) { + data = OSDynamicCast(OSData, rootNode->getProperty("OEMBoard")); + if (!data) { + WarningLog("no OEMBoard"); + data = OSDynamicCast(OSData, rootNode->getProperty("OEMProduct")); + } + if (data) { + bcopy(data->getBytesNoCopy(), product, data->getLength()); + OSDictionary *link = OSDynamicCast(OSDictionary, list->getObject(VendorNick)); + if (link) { + configuration = OSDynamicCast(OSDictionary, link->getObject(OSString::withCString(product))); + InfoLog(" mother vendor=%s product=%s", vendor, product); + } + } + } else { + WarningLog("unknown OEMVendor %s", vendor); + } + } else { + WarningLog("no OEMVendor"); + } + } + + if (list && !configuration) { + configuration = OSDynamicCast(OSDictionary, list->getObject("Default")); + WarningLog("set default configuration"); + } + + if (configuration) { + this->setProperty("Current Configuration", configuration); + } + + OSBoolean* tempin0forced = configuration ? OSDynamicCast(OSBoolean, configuration->getObject("TEMPIN0FORCED")) : 0; + OSBoolean* tempin1forced = configuration ? OSDynamicCast(OSBoolean, configuration->getObject("TEMPIN1FORCED")) : 0; + + if (OSNumber* fanlimit = configuration ? OSDynamicCast(OSNumber, configuration->getObject("FANINLIMIT")) : 0) + fanLimit = fanlimit->unsigned8BitValue(); + + // cpuid_update_generic_info(); + + bool isCpuCore_i = false; + + /* if (strcmp(cpuid_info()->cpuid_vendor, CPUID_VID_INTEL) == 0) + { + switch (cpuid_info()->cpuid_family) + { + case 0x6: + { + switch (cpuid_info()->cpuid_model) + { + case 0x1A: // Intel Core i7 LGA1366 (45nm) + case 0x1E: // Intel Core i5, i7 LGA1156 (45nm) + case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm) + case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core + isCpuCore_i = true; + break; + } + } break; + } + isCpuCore_i = (cpuid_info()->cpuid_model >= 0x1A); + } */ + + if (isCpuCore_i) { + // Heatsink + if (!addSensor(KEY_CPU_HEATSINK_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 2)) { + return false; + } + } else { + switch (model) { + case W83667HG: + case W83667HGB: { + // do not add temperature sensor registers that read PECI + UInt8 flag = readByte(0, WINBOND_TEMPERATURE_SOURCE_SELECT_REG); + + if ((flag & 0x04) == 0 || (tempin0forced && tempin0forced->getValue())) { + // Heatsink + if (!addSensor(KEY_CPU_HEATSINK_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 0)) { + WarningLog("error adding heatsink temperature sensor"); + } + } else if ((flag & 0x40) == 0 || (tempin1forced && tempin1forced->getValue())) { + // Ambient + if (!addSensor(KEY_AMBIENT_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 1)) { + WarningLog("error adding ambient temperature sensor"); + } + } + + // Northbridge + if (!addSensor(KEY_NORTHBRIDGE_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 2)) { + WarningLog("error adding system temperature sensor"); + } + break; + } + case W83627DHG: + case W83627DHGP: { + // do not add temperature sensor registers that read PECI + UInt8 sel = readByte(0, WINBOND_TEMPERATURE_SOURCE_SELECT_REG); + + if ((sel & 0x07) == 0 || (tempin0forced && tempin0forced->getValue())) { + // Heatsink + if (!addSensor(KEY_CPU_HEATSINK_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 0)) { + WarningLog("error adding heatsink temperature sensor"); + } + } else if ((sel & 0x70) == 0 || (tempin1forced && tempin1forced->getValue())) { + // Ambient + if (!addSensor(KEY_AMBIENT_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 1)) { + WarningLog("error adding ambient temperature sensor"); + } + } + + // Northbridge + if (!addSensor(KEY_NORTHBRIDGE_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 2)) { + WarningLog("error adding system temperature sensor"); + } + break; + } + default: { + // no PECI support, add all sensors + + // Heatsink + if (!addSensor(KEY_CPU_HEATSINK_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 0)) { + WarningLog("error adding heatsink temperature sensor"); + } + + // Ambient + if (!addSensor(KEY_AMBIENT_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 1)) { + WarningLog("error adding ambient temperature sensor"); + } + + // Northbridge + if (!addSensor(KEY_NORTHBRIDGE_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 2)) { + WarningLog("error adding system temperature sensor"); + } + + if (model >= NCT6771F) { + if (!addSensor(KEY_DIMM_TEMPERATURE, TYPE_SP78, 2, kSuperIOTemperatureSensor, 3)) { + WarningLog("error adding system temperature sensor"); + } + } + break; + } + } + } + + // Voltage + if (configuration) { + for (int i = 0; i < 9; i++) { + char key[5]; + long Ri=0; + long Rf=1; + long Vf=0; + OSString * name; + + snprintf(key, 5, "VIN%X", i); + + if (process_sensor_entry(configuration->getObject(key), &name, &Ri, &Rf, &Vf)) { + if (name->isEqualTo("CPU")) { + if (!addSensor(KEY_CPU_VRM_SUPPLY0, TYPE_FP2E, 2, kSuperIOVoltageSensor, i,Ri,Rf,Vf)) { + WarningLog("error adding CPU voltage sensor"); + } + } else if (name->isEqualTo("Memory")) { + if (!addSensor(KEY_MEMORY_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i, Ri, Rf, Vf)) { + WarningLog("error adding memory voltage sensor"); + } + } else if (name->isEqualTo("+5VC")) { + if (Ri == 0) { + Ri = 20; //Rodion + Rf = 10; + } + if (!addSensor(KEY_5VC_VOLTAGE, TYPE_SP4B, 2, kSuperIOVoltageSensor, i, Ri, Rf, Vf)) { + WarningLog("ERROR Adding AVCC Voltage Sensor!"); + } + } else if (name->isEqualTo("+5VSB")) { + if (Ri == 0) { + Ri = 20; //Rodion + Rf = 10; + } + + if (!addSensor(KEY_5VSB_VOLTAGE, TYPE_SP4B, 2, kSuperIOVoltageSensor, i, Ri, Rf, Vf)) { + WarningLog("ERROR Adding AVCC Voltage Sensor!"); + } + } else if (name->isEqualTo("+12VC")) { + if (Ri == 0) { + Ri = 60; //Rodion - 60, Datasheet 56 (?) + Rf = 10; + } + if (!addSensor(KEY_12V_VOLTAGE, TYPE_SP4B, 2, kSuperIOVoltageSensor, i, Ri, Rf, Vf)) { + WarningLog("ERROR Adding 12V Voltage Sensor!"); + } + } else if (name->isEqualTo("-12VC")) { + if (Ri == 0) { + Ri = 232; // Rodion - у меня нет такого. в datasheet 232 (?) + Rf = 10; + Vf = 2048; + } + + if (!addSensor(KEY_N12VC_VOLTAGE, TYPE_SP4B, 2, kSuperIOVoltageSensor, i, Ri, Rf, Vf)) { + WarningLog("ERROR Adding 12V Voltage Sensor!"); + } + } else if (name->isEqualTo("3VCC")) { + if (Ri == 0) { + // Ri = 34; Rodion + // Rf = 34; оно уже посчитано здесь { 8, 8, 16, 16, 8, 8, 8, 16, 16 }; + } + if (!addSensor(KEY_3VCC_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i, Ri, Rf, Vf)) { + WarningLog("ERROR Adding 3VCC Voltage Sensor!"); + } + } else if (name->isEqualTo("3VSB")) { + if (Ri == 0) { + // Ri = 34; + // Rf = 34; + } + if (!addSensor(KEY_3VSB_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i, Ri, Rf, Vf)) { + WarningLog("ERROR Adding 3VSB Voltage Sensor!"); + } + } else if (name->isEqualTo("VBAT")) { + if (Ri == 0) { + // Ri = 34; Rodion - проверить не могу...но, по аналогии )) + // Rf = 34; + } + if (!addSensor(KEY_VBAT_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i, Ri, Rf, Vf)) { + WarningLog("ERROR Adding VBAT Voltage Sensor!"); + } + } else if (name->isEqualTo("AVCC")) { + if (Ri == 0) { + // Ri = 34; + // Rf = 34; + } + if (!addSensor(KEY_AVCC_VOLTAGE, TYPE_FP2E, 2, kSuperIOVoltageSensor, i, Ri, Rf, Vf)) { + WarningLog("ERROR Adding AVCC Voltage Sensor!"); + } + } + } + } + } + + // FANs + for (int i = 0; i < fanLimit; i++) { + fanValueObsolete[i] = true; + } + + updateTachometers(); + + for (int i = 0; i < fanLimit; i++) { + OSString* name = 0; + + if (configuration) { + char key[7]; + snprintf(key, 7, "FANIN%X", i); + name = OSDynamicCast(OSString, configuration->getObject(key)); + } + + UInt64 nameLength = name ? name->getLength() : 0; + + if (readTachometer(i) > 10 || nameLength > 0) { + if (!addTachometer(i, (nameLength > 0 ? name->getCStringNoCopy() : 0))) { + WarningLog("error adding tachometer sensor %d", i); + } + } + } + + return true; +} + +const char *W836x::getModelName() { + switch (model) { + case W83627DHG: return "W83627DHG"; + case W83627DHGP: return "W83627DHG-P"; + case W83627EHF: return "W83627EHF"; + case W83627HF: return "W83627HF"; + case W83627THF: return "W83627THF"; + case W83667HG: return "W83667HG"; + case W83667HGB: return "W83667HG-B"; + case W83687THF: return "W83687THF"; + case W83627SF: return "W83627SF"; + case W83697HF: return "W83697HF"; + case W83637HF: return "W83637HF"; + case W83627UHG: return "W83627UHG"; + case W83697SF: return "W83697SF"; + case NCT6681: return "NCT6681"; + case NCT6683: return "NCT6683"; + case NCT6771F: return "NCT6771F"; + case NCT6776F: return "NCT6776F"; + case NCT6779D: return "NCT6779D"; + case NCT6791D: return "NCT6791D"; + case NCT6792D: return "NCT6792D"; + case NCT6793D: return "NCT6793D"; + case NCT6795D: return "NCT6795D"; + case NCT6796D: return "NCT6796D"; + case NCT6798D: return "NCT6798D"; + case NCT679BD: return "NCT679BD"; + case NCT6797D: return "NCT6797D"; + } + + return "unknown"; +} + +SuperIOSensor * W836x::addSensor(const char* name, + const char* type, + unsigned int size, + SuperIOSensorGroup group, + unsigned long index, + long aRi, + long aRf, + long aVf) { + if (NULL != getSensor(name)) { + return 0; + } + DebugLog("mults = %ld, %ld", aRi, aRf); + SuperIOSensor *sensor = W836xSensor::withOwner(this, + name, + type, + size, + group, + index, + aRi, + aRf, + aVf); + + if (sensor && sensors->setObject(sensor)) { + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)name, + (void *)type, + (void *)(long long)size, + (void *)this)) { + return sensor; + } + } + + return 0; +} + +IOReturn W836x::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4) { + if (functionName->isEqualTo(kFakeSMCGetValueCallback)) { + const char* name = (const char*)param1; + void * data = param2; + //UInt32 size = (UInt64)param3; + + if (name && data) { + SuperIOSensor * sensor = getSensor(name); + if (sensor) { + UInt16 value = sensor->getValue(); + bcopy(&value, data, 2); + return kIOReturnSuccess; + } + } + return kIOReturnBadArgument; + } +/* no write SMC in Winbond + if (functionName->isEqualTo(kFakeSMCSetValueCallback)) { + const char* name = (const char*)param1; + void * data = param2; + //UInt32 size = (UInt64)param3; + + if (name && data) { + W836xSensor *sensor = OSDynamicCast(W836xSensor, getSensor(name)); + if (sensor) { + UInt16 value; + bcopy(data, &value, 2); + sensor->setValue(value); + return kIOReturnSuccess; + } + } + return kIOReturnBadArgument; + } + */ + return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); +} + + diff --git a/plugins/SuperIOSensors/WinbondW836x/WinbondW836x.h b/plugins/SuperIOSensors/WinbondW836x/WinbondW836x.h new file mode 100755 index 0000000..49881a1 --- /dev/null +++ b/plugins/SuperIOSensors/WinbondW836x/WinbondW836x.h @@ -0,0 +1,210 @@ +/* + * W836x.h + * HWSensors + * + * Based on code from Open Hardware Monitor project by Michael Möller (C) 2011 + * + * Created by mozo on 14/10/10. + * Copyright 2010 mozodojo. All rights reserved. + * + */ + +/* + + Version: MPL 1.1/GPL 2.0/LGPL 2.1 + + The contents of this file are subject to the Mozilla Public License Version + 1.1 (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + The Original Code is the Open Hardware Monitor code. + + The Initial Developer of the Original Code is + Michael Möller . + Portions created by the Initial Developer are Copyright (C) 2011 + the Initial Developer. All Rights Reserved. + + Contributor(s): + + Alternatively, the contents of this file may be used under the terms of + either the GNU General Public License Version 2 or later (the "GPL"), or + the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + in which case the provisions of the GPL or the LGPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of either the GPL or the LGPL, and not to allow others to + use your version of this file under the terms of the MPL, indicate your + decision by deleting the provisions above and replace them with the notice + and other provisions required by the GPL or the LGPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the MPL, the GPL or the LGPL. + + */ + +#include +#include +#include +#include +#include + +#include "../SuperIOFamily/SuperIOFamily.h" + +const UInt8 WINBOND_HARDWARE_MONITOR_LDN = 0x0B; + +const UInt16 WINBOND_VENDOR_ID = 0x5CA3; +const UInt8 WINBOND_HIGH_BYTE = 0x80; + +// Winbond Hardware Monitor +const UInt8 WINBOND_ADDRESS_REGISTER_OFFSET = 0x05; +const UInt8 WINBOND_DATA_REGISTER_OFFSET = 0x06; + +// Winbond Hardware Monitor Registers +const UInt8 WINBOND_BANK_SELECT_REGISTER = 0x4E; +const UInt8 WINBOND_VENDOR_ID_REGISTER = 0x4F; +const UInt8 WINBOND_TEMPERATURE_SOURCE_SELECT_REG = 0x49; + +//private string[] TEMPERATURE_NAME = +//new string[] {"CPU", "Ambient", "System", "Memory"}; +const UInt16 WINBOND_TEMPERATURE[] = { 0x150, 0x250, 0x27 }; +const UInt16 NUVOTON_TEMPERATURE[] = { 0x150, 0x670, 0x27 }; +const UInt16 NUVOTON_NEW_TEMPERATURE1[] = { 0x75, 0x77, 0x73, 0x79 }; +const UInt16 NUVOTON_NEW_TEMPERATURE2[] = { 0x402, 0x401, 0x404, 0x405 }; + + +// Voltages VCORE AVSB 3VCC AVCC +12V1 -12V2 -5VIN3 3VSB VBAT +const UInt16 WINBOND_VOLTAGE_REG[] = { 0x20, 0x21, 0x23, 0x22, 0x24, 0x25, 0x26, 0x550, 0x551 }; +const float WINBOND_VOLTAGE_SCALE[] = { 8, 8, 16, 16, 8, 8, 8, 16, 16 }; +const UInt16 WINBOND_VOLTAGE_VBAT_REG = 0x0551; +const UInt16 NUVOTON_VOLTAGE_REG[] = { 0x480, 0x482, 0x483, 0x484, 0x485, 0x481, 0x486, 0x487, 0x488 }; + + +const UInt8 WINBOND_TACHOMETER[] = { 0x28, 0x29, 0x2A, 0x3F, 0x53 }; +const UInt8 WINBOND_TACHOMETER_BANK[] = { 0, 0, 0, 0, 5 }; + +// SYSFAN, CPUFAN, AUXFAN +const UInt16 NUVOTON_TACHOMETER[] = { 0x4C0, 0x4C2, 0x4C4, 0x4C6, 0x4C8, 0x4CA}; + +const UInt8 WINBOND_TACHOMETER_DIV0[] = { 0x47, 0x47, 0x4B, 0x59, 0x59 }; +const UInt8 WINBOND_TACHOMETER_DIV0_BIT[] = { 4, 6, 6, 0, 2 }; +const UInt8 WINBOND_TACHOMETER_DIV1[] = { 0x47, 0x47, 0x4B, 0x59, 0x59 }; +const UInt8 WINBOND_TACHOMETER_DIV1_BIT[] = { 5, 7, 7, 1, 3 }; +const UInt8 WINBOND_TACHOMETER_DIV2[] = { 0x5D, 0x5D, 0x5D, 0x4C, 0x59 }; +const UInt8 WINBOND_TACHOMETER_DIV2_BIT[] = { 5, 6, 7, 7, 7 }; + +const UInt8 WINBOND_TACHOMETER_DIVISOR[] = { 0x47, 0x4B, 0x4C, 0x59, 0x5D }; +const UInt8 WINBOND_TACHOMETER_DIVISOR0[] = { 36, 38, 30, 8, 10 }; +const UInt8 WINBOND_TACHOMETER_DIVISOR1[] = { 37, 39, 31, 9, 11 }; +const UInt8 WINBOND_TACHOMETER_DIVISOR2[] = { 5, 6, 7, 23, 15 }; + +// Fan Control +const UInt8 WINBOND_FAN_CONFIG[] = { 0x04, 0x04, 0x12, 0x62 }; +const UInt8 WINBOND_FAN_CONTROL_BIT[] = { 0x02, 0x04, 0x01, 0x04 }; +const UInt8 WINBOND_FAN_MODE_BIT[] = { 0x00, 0x01, 0x00, 0x06 }; +const UInt8 WINBOND_FAN_OUTPUT[] = { 0x01, 0x03, 0x11, 0x61 }; + +enum W836xModel { + W83627DHG = 0xA020, + W83627UHG = 0xA230, + W83627DHGP = 0xB070, + W83627EHF = 0x8800, + W83627HF = 0x5200, + W83627THF = 0x8280, + W83627SF = 0x5950, + W83637HF = 0x7080, + W83667HG = 0xA510, + W83667HGB = 0xB350, + W83687THF = 0x8541, + W83697HF = 0x6010, + W83697SF = 0x6810, + NCT6681 = 0xB270, + NCT6683 = 0xC730, + NCT6771F = 0xB470, + NCT6776F = 0xC330, + NCT6779D = 0xC560, + NCT6791D = 0xC803, + NCT6792D = 0xC911, + NCT6793D = 0xD121, + NCT6795D = 0xD352, + NCT6796D = 0xD423, + NCT6798D = 0xD428, + NCT679BD = 0xD42B, + NCT6797D = 0xD451, +}; + +class W836x; + +class W836xSensor : public SuperIOSensor { + OSDeclareDefaultStructors(W836xSensor) + +public: + static SuperIOSensor *withOwner(SuperIOMonitor *aOwner, + const char* aKey, + const char* aType, + unsigned char aSize, + SuperIOSensorGroup aGroup, + unsigned long aIndex, + long aRi = 0, + long aRf = 1, + long aVf = 0); + + virtual long getValue(); +// virtual void setValue(UInt16 value); +}; + + +class W836x : public SuperIOMonitor { + OSDeclareDefaultStructors(W836x) + +public: + virtual bool init(OSDictionary *properties=0); + virtual IOService* probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual void stop(IOService *provider); + virtual void free(void); + +private: + char vendor[40]; + char product[40]; + + UInt8 fanLimit; + UInt16 fanValue[5]; + bool fanValueObsolete[5]; + + void writeByte(UInt8 bank, UInt8 reg, UInt8 value); + UInt8 readByte(UInt8 bank, UInt8 reg); + UInt64 setBit(UInt64 target, UInt16 bit, UInt32 value); + + virtual bool probePort(); + // virtual bool startPlugin(); + virtual void enter(); + virtual void exit(); + + virtual long readTemperature(unsigned long index); + virtual long readVoltage(unsigned long index); + void updateTachometers(); + virtual long readTachometer(unsigned long index); + + virtual const char * getModelName(); + +public: + SuperIOSensor * addSensor(const char* key, + const char* type, + unsigned int size, + SuperIOSensorGroup group, + unsigned long index, + long aRi = 0, + long aRf = 1, + long aVf = 0); + + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); +}; diff --git a/plugins/SuperIOSensors/WinbondW836x/en.lproj/InfoPlist.strings b/plugins/SuperIOSensors/WinbondW836x/en.lproj/InfoPlist.strings new file mode 100755 index 0000000..477b28f --- /dev/null +++ b/plugins/SuperIOSensors/WinbondW836x/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/plugins/VoodooBattery/English.lproj/InfoPlist.strings b/plugins/VoodooBattery/English.lproj/InfoPlist.strings new file mode 100755 index 0000000..5e45963 Binary files /dev/null and b/plugins/VoodooBattery/English.lproj/InfoPlist.strings differ diff --git a/plugins/VoodooBattery/FakeSMC.h b/plugins/VoodooBattery/FakeSMC.h new file mode 100644 index 0000000..f365d9b --- /dev/null +++ b/plugins/VoodooBattery/FakeSMC.h @@ -0,0 +1,27 @@ +#ifndef _VIRTUALSMC_H +#define _VIRTUALSMC_H + +#include +#include +#include +#include +#include "FakeSMCDevice.h" +#include "FakeSMCKey.h" +#include "definitions.h" + + +class FakeSMC : public IOService { + OSDeclareDefaultStructors(FakeSMC) + +private: + FakeSMCDevice *smcDevice; + +public: + virtual bool init(OSDictionary *dictionary = 0); + virtual void free(void); + virtual IOService *probe(IOService *provider, SInt32 *score); + virtual bool start(IOService *provider); + virtual void stop(IOService *provider); +}; + +#endif diff --git a/plugins/VoodooBattery/Info.plist b/plugins/VoodooBattery/Info.plist new file mode 100755 index 0000000..2a93487 --- /dev/null +++ b/plugins/VoodooBattery/Info.plist @@ -0,0 +1,63 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleGetInfoString + 1.2.1, © 2009 Superhai, ${MODULE_VERSION} 2019 Slice + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + KEXT + CFBundleShortVersionString + $(MODULE_VERSION) + CFBundleSignature + ???? + CFBundleVersion + ${MODULE_VERSION} + IOKitPersonalities + + BatteryManager + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + IOClass + VoodooBattery + IOMatchCategory + VoodooBattery + IOProviderClass + IOResources + IOResourceMatch + IOKit + + + OSBundleLibraries + + com.apple.iokit.IOACPIFamily + 1.0.0 + com.apple.iokit.IOHIDSystem + 1.1 + com.apple.kpi.iokit + 9.0.0 + com.apple.kpi.libkern + 9.0.0 + com.apple.kpi.mach + 9.0.0 + com.apple.kpi.unsupported + 9.0.0 + org.netkas.FakeSMC + 3.4.0 + + OSBundleRequired + Root + + diff --git a/plugins/VoodooBattery/Support.h b/plugins/VoodooBattery/Support.h new file mode 100755 index 0000000..4b6ca82 --- /dev/null +++ b/plugins/VoodooBattery/Support.h @@ -0,0 +1,129 @@ +/* + --- Support --- + (C) 2008 Superhai + + Contact http://www.superhai.com/ + + */ + +// Information helpers + +#include + +#define defString(s) defXString(s) +#define defXString(s) #s + +const char * KextVersion = defString(KEXT_VERSION); +const char * KextProductName = defString(KEXT_PRODUCTNAME); +const char * KextOSX = defString(KEXT_OSX); +const char * KextConfig = defString(KEXT_CONFIG); +const char * KextBuildDate = __DATE__; +const char * KextBuildTime = __TIME__; + +const unsigned long Kilo = 1000; +const unsigned long Mega = Kilo * 1000; +const unsigned long Giga = Mega * 1000; + + +// Debug output support + +#define INFO 1 +#define ERROR 1 + +#if DEBUG +#define DebugLog(string, args...) IOLog("%s: [Debug] [%05u] " string "\n", KextProductName, __LINE__, ## args); IOSleep(100) +#define DebugMarker IOLog("%s: [Debug] [%s][%u] \n", KextProductName, __PRETTY_FUNCTION__, __LINE__); IOSleep(100) +#else +#define DebugLog(string, args...) +#define DebugMarker +#endif + +#if INFO +#define InfoLog(string, args...) IOLog("%s: " string "\n", KextProductName, ## args) +#else +#define InfoLog(string, args...) +#endif + +#if ERROR +#define ErrorLog(string, args...) IOLog("%s: [Error] " string "\n", KextProductName, ## args) +#define WarningLog(string, args...) IOLog("%s: [Warning] " string "\n", KextProductName, ## args) +#else +#define ErrorLog(string, args...) +#define WarningLog(string, args...) +#endif + +#if 0 + +// IOPMPowerSource class descriptive strings +// Power Source state is published as properties to the IORegistry under these +// keys. +#define kIOPMPSExternalConnectedKey "ExternalConnected" +#define kIOPMPSExternalChargeCapableKey "ExternalChargeCapable" +#define kIOPMPSBatteryInstalledKey "BatteryInstalled" +#define kIOPMPSIsChargingKey "IsCharging" +#define kIOPMFullyChargedKey "FullyCharged" +#define kIOPMPSAtWarnLevelKey "AtWarnLevel" +#define kIOPMPSAtCriticalLevelKey "AtCriticalLevel" +#define kIOPMPSCurrentCapacityKey "CurrentCapacity" +#define kIOPMPSMaxCapacityKey "MaxCapacity" +#define kIOPMPSDesignCapacityKey "DesignCapacity" +#define kIOPMPSTimeRemainingKey "TimeRemaining" +#define kIOPMPSAmperageKey "Amperage" +#define kIOPMPSVoltageKey "Voltage" +#define kIOPMPSCycleCountKey "CycleCount" +#define kIOPMPSMaxErrKey "MaxErr" +#define kIOPMPSAdapterInfoKey "AdapterInfo" +#define kIOPMPSLocationKey "Location" +#define kIOPMPSErrorConditionKey "ErrorCondition" +#define kIOPMPSManufacturerKey "Manufacturer" +#define kIOPMPSManufactureDateKey "ManufactureDate" +#define kIOPMPSModelKey "Model" +#define kIOPMPSSerialKey "Serial" +#define kIOPMDeviceNameKey "DeviceName" +#define kIOPMPSLegacyBatteryInfoKey "LegacyBatteryInfo" +#define kIOPMPSBatteryHealthKey "BatteryHealth" +#define kIOPMPSHealthConfidenceKey "HealthConfidence" +#define kIOPMPSCapacityEstimatedKey "CapacityEstimated" +#define kIOPMPSBatteryChargeStatusKey "ChargeStatus" +#define kIOPMPSBatteryTemperatureKey "Temperature" +#define kIOPMPSAdapterDetailsKey "AdapterDetails" +#define kIOPMPSChargerConfigurationKey "ChargerConfiguration" + +// kIOPMPSBatteryChargeStatusKey may have one of the following values, or may have +// no value. If kIOPMBatteryChargeStatusKey has a NULL value (or no value) associated with it +// then charge is proceeding normally. If one of these battery charge status reasons is listed, +// then the charge may have been interrupted. +#define kIOPMBatteryChargeStatusTooHot "HighTemperature" +#define kIOPMBatteryChargeStatusTooCold "LowTemperature" +#define kIOPMBatteryChargeStatusTooHotOrCold "HighOrLowTemperature" +#define kIOPMBatteryChargeStatusGradient "BatteryTemperatureGradient" + +// Definitions for battery location, in case of multiple batteries. +// A location of 0 is unspecified +// Location is undefined for single battery systems +enum { + kIOPMPSLocationLeft = 1001, + kIOPMPSLocationRight = 1002 +}; + +// Battery quality health types, specified by BatteryHealth and HealthConfidence +// properties in an IOPMPowerSource battery kext. +enum { + kIOPMUndefinedValue = 0, + kIOPMPoorValue = 1, + kIOPMFairValue = 2, + kIOPMGoodValue = 3 +}; + +// Keys for kIOPMPSAdapterDetailsKey dictionary +#define kIOPMPSAdapterDetailsIDKey "AdapterID" +#define kIOPMPSAdapterDetailsWattsKey "Watts" +#define kIOPMPSAdapterDetailsRevisionKey "AdapterRevision" +#define kIOPMPSAdapterDetailsSerialNumberKey "SerialNumber" +#define kIOPMPSAdapterDetailsFamilyKey "FamilyCode" +#define kIOPMPSAdapterDetailsAmperageKey "Amperage" +#define kIOPMPSAdapterDetailsDescriptionKey "Description" +#define kIOPMPSAdapterDetailsPMUConfigurationKey "PMUConfiguration" +#define kIOPMPSAdapterDetailsVoltage "AdapterVoltage" +#endif + diff --git a/plugins/VoodooBattery/VoodooBattery.cpp b/plugins/VoodooBattery/VoodooBattery.cpp new file mode 100755 index 0000000..a29ded1 --- /dev/null +++ b/plugins/VoodooBattery/VoodooBattery.cpp @@ -0,0 +1,1132 @@ +/* + --- VoodooBattery --- + (C) 2009 Superhai + + Changelog + ---------------------------------------------- + 1.2.0 19/1/09 + - Initial Release + 1.2.1 07/4/09 + - Bugfixes, minor mods + ---------------------------------------------- + + Contact http://www.superhai.com/ + + */ +/* + 1.2 - 1.4 small improvements + ... + 1.4.1 Slice 2017 + Make the kext is a plugin for FakeSMC to show battery state in HWMonitor + */ + +#include +#include + +#include "Support.h" +#include "VoodooBattery.h" +#include "../../utils/definitions.h" + +#pragma mark - +#pragma mark VoodooBattery Controller +#pragma mark - +#pragma mark IOService + +#undef super +#define super IOHIKeyboard + +OSDefineMetaClassAndStructors(Button, IOHIKeyboard) + +bool Button::sendEvent(UInt8 keyEvent) +{ + AbsoluteTime now; + clock_get_uptime((uint64_t*)&now); + + dispatchKeyboardEvent( keyEvent, + /*direction*/ true, + /*timeStamp*/ *((AbsoluteTime*)&now) ); + return true; +} + +bool Button::attach(IOService *provider) +{ + if( !super::attach(provider) ) return false; + _controller = (ButtonController *)provider; + _controller->retain(); + return true; +} + +void Button::detach( IOService * provider ) +{ + assert(_controller == provider); + _controller->release(); + _controller = 0; + + super::detach(provider); +} + + + +#undef super +#define super IOService + +OSDefineMetaClassAndStructors(ButtonController, IOService) + +bool ButtonController::init(OSDictionary * properties) +{ + // + // Initialize this object's minimal state. This is invoked right after this + // object is instantiated. + // + + if (!super::init(properties)) return false; + + return true; +} + +ButtonController * ButtonController::probe(IOService * provider, SInt32 * score) +{ + if (!super::probe(provider, score)) return 0; + return this; +} + +bool ButtonController::start(IOService * provider) +{ + if (!super::start(provider)) return false; + ACButton2 = new Button; +// ACButton2->registerService(); + return true; +} + +void ButtonController::stop(IOService * provider) +{ + if (ACButton2) ACButton2->release(); + super::stop(provider); +} + +bool ButtonController::sendEvent(UInt8 keyEvent) +{ + return ACButton2->sendEvent(keyEvent); +} + +OSDefineMetaClassAndStructors(VoodooBattery, IOService) + +#define kPowerStateCount 3 +static IOPMPowerState myStates[2] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0} +}; +/*static IOPMPowerState myStates[ kPowerStateCount ] = + { + { 1,0,0,0,0,0,0,0,0,0,0,0 }, + { 1,0,kIOPMDoze,kIOPMDoze,0,0,0,0,0,0,0,0 }, + { 1,kIOPMDeviceUsable,kIOPMPowerOn,kIOPMPowerOn,0,0,0,0,0,0,0,0 } + }; + */ + +bool VoodooBattery::addSensor(const char* key, const char* type, unsigned int size, int index) { + if (kIOReturnSuccess == fakeSMC->callPlatformFunction(kFakeSMCAddKeyHandler, + false, + (void *)key, + (void *)type, + (void *)(long long)size, + (void *)this)) { + if (sensors) { + return sensors->setObject(key, OSNumber::withNumber(index, 32)); + } + } + return false; +} + +bool VoodooBattery::init(OSDictionary *properties) { + if (!super::init(properties)) { + return false; + } + firstTime = true; + ExternalPowerConnected = false; + if (!(sensors = OSDictionary::withCapacity(0))) { + return false; + } + brightnessLevels = NULL; + brightnessCount = 0; + return true; +} + +IOService * VoodooBattery::probe(IOService * provider, SInt32 * score) { + + // Call superclass + if (IOService::probe(provider, score) != this) { return 0; } + + IORegistryIterator * iterator; + IORegistryEntry * entry; + OSString * pnp; + + // We need to look for batteries and if not found we unload + BatteryCount = 0; + iterator = IORegistryIterator::iterateOver(gIOACPIPlane, kIORegistryIterateRecursively); + pnp = OSString::withCString(PnpDeviceIdBattery); + + if (iterator) { + while ((entry = iterator->getNextObject())) { + if (entry->compareName(pnp)) { + DebugLog("Found acpi pnp battery"); + BatteryDevice[BatteryCount++] = OSDynamicCast(IOACPIPlatformDevice, entry); + if (BatteryCount >= MaxBatteriesSupported) break; + } + } + iterator->release(); + iterator = 0; + } + + IOLog("Found %u batteries\n", BatteryCount); + if (BatteryCount == 0) return 0; + + // We will also try to find an A/C adapter in acpi space + AcAdapterCount = 0; + iterator = IORegistryIterator::iterateOver(gIOACPIPlane, kIORegistryIterateRecursively); + pnp = OSString::withCString(PnpDeviceIdAcAdapter); + + if (iterator) { + while ((entry = iterator->getNextObject())) { + if (entry->compareName(pnp)) { + DebugLog("Found acpi pnp ac adapter"); + AcAdapterDevice[AcAdapterCount++] = OSDynamicCast(IOACPIPlatformDevice, entry); + if (AcAdapterCount >= MaxAcAdaptersSupported) break; + } + } + iterator->release(); + iterator = 0; + } + IOLog("Found %u ac adapters\n", AcAdapterCount); + + // look for LID device if any + iterator = IORegistryIterator::iterateOver(gIOACPIPlane, kIORegistryIterateRecursively); + pnp = OSString::withCString(PnpDeviceIdLid); + if (iterator) { + while ((entry = iterator->getNextObject())) { + if (entry->compareName(pnp)) { + DebugLog("Found Lid device"); + LidDevice = OSDynamicCast(IOACPIPlatformDevice, entry); + break; + } + } + iterator->release(); + iterator = 0; + } +//PNLFDevice APP0002 PnpDeviceIdPnlf + iterator = IORegistryIterator::iterateOver(gIOACPIPlane, kIORegistryIterateRecursively); + pnp = OSString::withCString(PnpDeviceIdPnlf); + if (iterator) { + while ((entry = iterator->getNextObject())) { + if (entry->compareName(pnp)) { + DebugLog("Found PNLF device"); + PNLFDevice = OSDynamicCast(IOACPIPlatformDevice, entry); + break; + } + } + iterator->release(); + iterator = 0; + } + + + return this; +} + +bool VoodooBattery::start(IOService * provider) { + bool isBattery = false; + char key[5]; + // Call superclass + if (!IOService::start(provider)) { return false; } + + if (!(fakeSMC = waitForService(serviceMatching(kFakeSMCDeviceService)))) { + WarningLog("Can't locate fake SMC device, kext will not load"); + return false; + } + + // Printout banner + InfoLog("%s %s (%s) %s %s", + KextProductName, + KextVersion, + KextConfig, + KextBuildDate, + KextBuildTime /*, + KextOSX */); + InfoLog("(C) 2009 Superhai, All Rights Reserved, 2017 Slice"); + + WorkLoop = getWorkLoop(); + Poller = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, + this, + &VoodooBattery::Update)); + if (!Poller || !WorkLoop) { return false; } + if (WorkLoop->addEventSource(Poller) != kIOReturnSuccess) { return false; } + + + for (UInt8 i = 0; i < BatteryCount; i++) { + DebugLog("Attaching and starting battery %s", BatteryDevice[i]->getName()); + BatteryPowerSource[i] = AppleSmartBattery::NewBattery(); + fBatteryGate[i] = IOCommandGate::commandGate(BatteryPowerSource[i]); + WorkLoop->addEventSource(fBatteryGate[i]); + + if (BatteryPowerSource[i]) { + if (BatteryPowerSource[i]->attach(BatteryDevice[i]) && BatteryPowerSource[i]->start(this)) { + BatteryPowerSource[i]->registerService(0); + BatteryPowerSource[i]->ParentService = this; + } else { + ErrorLog("Error on battery attach %u", i); + return false; + } + isBattery = true; + } + } + + for (UInt8 i = 0; i < AcAdapterCount; i++) { +// if (attach(AcAdapterDevice[i])) { + InfoLog("A/C adapter %s available", AcAdapterDevice[i]->getName()); + // } + } + +// if (PNLFDevice) { +// attach(PNLFDevice); +// } + +/// ACButtonController = new ButtonController; +// InfoLog("new"); +/// ACButtonController->start(provider); +// InfoLog("start"); +// ACButtonController->registerService(); +// InfoLog("register"); +// ACButtonController->attach(this); +// ACButtonController->IOService::start(this); + +/* ACButton = new Button; + ACButton->attach(this); + ACButton->registerService(); */ +/* ACButtonController = new ButtonController; + if (attach(ACButtonController)) { + InfoLog("ACButton available"); + ACButtonController->start(provider); +// ACButtonController->registerService(0); + } +*/ + + if (isBattery) { + PMinit(); // Powermanagement + // registerPowerDriver(this, myStates, kPowerStateCount); + registerPowerDriver(this, myStates, 2); + provider->joinPMtree(this); + } + + for (UInt32 i = 0; i < 5; i++) { + IOSleep(1000); + CheckDevices(); + } + + if (isBattery) { + for (int Index = 0; Index < BatteryCount; Index++) { + if (BatteryConnected[Index]) { + snprintf(key, 5, KEY_FORMAT_BAT_VOLTAGE, Index); + DebugLog("Adding key %s", key); + addSensor(key, TYPE_UI16, 2, Index); + snprintf(key, 5, KEY_FORMAT_BAT_AMPERAGE, Index); + DebugLog("Adding key %s", key); + addSensor(key, TYPE_UI16, 2, Index); + snprintf(key, 5, KEY_FORMAT_BAT_STATUS, Index); + DebugLog("Adding key %s", key); + addSensor(key, TYPE_UI16, 2, Index); + snprintf(key, 5, KEY_FORMAT_BAT_REMAINING_CAPACITY, Index); + DebugLog("Adding key %s", key); + addSensor(key, TYPE_UI16, 2, Index); + } + } + snprintf(key, 5, KEY_BAT_POWERED); + addSensor(key, TYPE_FLAG, 1, 0); + snprintf(key, 5, KEY_NUMBER_OF_BATTERIES); + addSensor(key, TYPE_UI8, 1, 0); + snprintf(key, 5, KEY_BAT_INSERTED); + addSensor(key, TYPE_UI8, 1, 0); + snprintf(key, 5, KEY_BAT_CHARGE_CODE); + addSensor(key, TYPE_UI8, 1, 0); + snprintf(key, 5, KEY_NUMBER_OF_ADAPTERS); + addSensor(key, TYPE_UI8, 1, 0); + snprintf(key, 5, KEY_CONNECTED_ADAPTER); + addSensor(key, TYPE_UI8, 1, 0); + snprintf(key, 5, KEY_ADAPTER_AMPERAGE); + addSensor(key, TYPE_UI16, 2, 0); + } + if (LidDevice && attach(LidDevice)) { + snprintf(key, 5, KEY_LID_CLOSED); + addSensor(key, TYPE_UI8, 1, 0); + } + + while (PNLFDevice) { + OSObject* result = 0; + // check for brightness methods + if (kIOReturnSuccess != PNLFDevice->validateObject(MethodBCL) || kIOReturnSuccess != PNLFDevice->validateObject(MethodBCM) || kIOReturnSuccess != PNLFDevice->validateObject(MethodBQC)) { + WarningLog("no methods in PNLF"); + break; + } + // methods are there, so now try to collect brightness levels + if (kIOReturnSuccess != PNLFDevice->evaluateObject(MethodBCL, &result)) { + WarningLog("no _BCL in PNLF"); + break; + } + OSArray* array = OSDynamicCast(OSArray, result); + if (!array) { + WarningLog("_BCL returned non-array package"); + break; + } + int count = array->getCount(); + if (count < 4) { + WarningLog("_BCL returned invalid package, <4"); + break; + } +/* brightnessCount = count; + brightnessLevels = new int[brightnessCount]; + if (!brightnessLevels) { + WarningLog("brightnessLevels new int[] failed"); + break; + } + for (int i = 0; i < brightnessCount; i++) { + OSNumber* num = OSDynamicCast(OSNumber, array->getObject(i)); + int brightness = num ? num->unsigned32BitValue() : 0; + brightnessLevels[i] = brightness; + DebugLog("brightness[%d]=%x", i, brightness); + } */ + break; + } + + return true; +} + +void VoodooBattery::stop(IOService * provider) +{ + sensors->flushCollection(); + Poller->cancelTimeout(); + PMstop(); + IOWorkLoop *wl = getWorkLoop(); + for (UInt8 i = 0; i < BatteryCount; i++) { + BatteryPowerSource[i]->ParentService = 0; + BatteryPowerSource[i]->detach(BatteryDevice[i]); + BatteryPowerSource[i]->stop(this); + + if (wl) { + wl->removeEventSource(fBatteryGate[i]); + } + fBatteryGate[i]->free(); + fBatteryGate[i] = NULL; + + } +/* ACButton->detach(this); + ACButton->release(); */ +// ACButtonController->detach(this); + ACButtonController->stop(this); + + if (brightnessLevels) + { + delete[] brightnessLevels; + brightnessLevels = 0; + } + + IOService::stop(provider); +} + +void VoodooBattery::free() { + sensors->release(); + IOService::free(); +} + +IOReturn VoodooBattery::setPowerState(unsigned long state, IOService * device) { + if (state) { + DebugLog("%s We are waking up", device->getName()); + QuickPoll = QuickPollCount; + CheckDevices(); + } else { + DebugLog("%s We are sleeping", device->getName()); + QuickPoll = 0; + } + return kIOPMAckImplied; +} + +IOReturn VoodooBattery::message(UInt32 type, IOService * provider, void * argument) { + if (type == kIOACPIMessageDeviceNotification) { + DebugLog("%s kIOACPIMessageDeviceNotification", provider->getName()); + QuickPoll = QuickPollCount; + CheckDevices(); + } else { + DebugLog("%s %08X", provider->getName(), type); + } + + return kIOReturnSuccess; +} + +#pragma mark Own + +void VoodooBattery::Update(void) { + DebugLog("ExternalPowerConnected %x BatteriesAreFull %x", ExternalPowerConnected, BatteriesAreFull); + if (ExternalPowerConnected && BatteriesAreFull) { + DebugLog("NoPoll"); + } else { + if (QuickPoll) { + DebugLog("QuickPoll %u", QuickPoll); + Poller->setTimeoutMS(QuickPollInterval); + QuickPoll--; + } else { + DebugLog("NormalPoll"); + Poller->setTimeoutMS(NormalPollInterval); + } + } + BatteriesAreFull = true; + for (UInt8 i = 0; i < BatteryCount; i++) { + if (BatteryConnected[i]) { BatteryStatus(i); } + if (!AcAdapterCount) { ExternalPowerConnected |= CalculatedAcAdapterConnected[i]; } + } + if (!AcAdapterCount) { ExternalPower(ExternalPowerConnected); } +} + +void VoodooBattery::CheckDevices(void) { + UInt32 acpi; + bool change; + bool wasConnected = ExternalPowerConnected; + Poller->cancelTimeout(); + BatteriesConnected = false; + DebugLog("CheckDevices"); + for (UInt8 i = 0; i < BatteryCount; i++) { + acpi = 0; + if (kIOReturnSuccess == BatteryDevice[i]->evaluateInteger(AcpiStatus, &acpi)) { //_STA + DebugLog("Return status %x\n", acpi); + change = BatteryConnected[i]; + BatteryConnected[i] = (acpi & 0x10) ? true : false; + if (BatteryConnected[i] != change) { BatteryInformation(i); } + BatteriesConnected |= BatteryConnected[i]; + } + } + ExternalPowerConnected = false; + for (UInt8 i = 0; i < AcAdapterCount; i++) { + acpi = 0; + if (kIOReturnSuccess == AcAdapterDevice[i]->evaluateInteger(AcpiPowerSource, &acpi)) { //_PSR + DebugLog("Return power source %x\n", acpi); + AcAdapterConnected[i] = acpi ? true : false; + ExternalPowerConnected |= AcAdapterConnected[i]; + } + } + if (BatteriesConnected) { + Update(); + } else { + ExternalPowerConnected = true; // Safe to assume without batteries you need ac + } + + if (wasConnected && !ExternalPowerConnected) { + //reduce brightness + DebugLog("reduce brightness "); +// ACButtonController->sendEvent(0x90); //0x90 //0x02 +// ChangeBrightness(-4); + } else if (!wasConnected && ExternalPowerConnected){ + //increase brightness + DebugLog("increase brightness "); +// ChangeBrightness(4); +// ACButtonController->sendEvent(0x91); //0x91 //0x03 + } //else nothing to do + ExternalPower(ExternalPowerConnected); + DebugLog("BatteriesConnected %x ExternalPowerConnected %x", BatteriesConnected, ExternalPowerConnected); +} + +void VoodooBattery::ChangeBrightness(int Shift) +{ + UInt32 BrightBefore = 0; + int index = 2; + if (PNLFDevice && (brightnessCount > 2)) { + PNLFDevice->evaluateInteger(MethodBQC, &BrightBefore); + DebugLog("BrightBefore = %x", BrightBefore); + while (index < brightnessCount) { + if (brightnessLevels[index++] >= BrightBefore) + break; + } + DebugLog("at index = %d", index); + index += Shift - 1; + index = (index < brightnessCount)? index : brightnessCount - 1; + index = (index > 2)? index: 2; + + OSNumber* num = OSNumber::withNumber(brightnessLevels[index], 32); + if (kIOReturnSuccess != PNLFDevice->evaluateObject(MethodBCM, NULL, (OSObject**)&num, 1)) { + DebugLog("_BCM returned error\n"); + } + num->release(); + } +} + +void VoodooBattery::GetBatteryInfoEx(UInt8 battery, OSObject * acpi) { + OSArray * info = OSDynamicCast(OSArray, acpi); + if (GetValueFromArray(info, 1) == 0x00000000) PowerUnitIsWatt = true; + Battery[battery].DesignCapacity = GetValueFromArray(info, 2); + Battery[battery].LastFullChargeCapacity = GetValueFromArray(info, 3); + Battery[battery].Technology = GetValueFromArray(info, 4); + Battery[battery].DesignVoltage = GetValueFromArray(info, 5); + Battery[battery].DesignCapacityWarning = GetValueFromArray(info, 6); + Battery[battery].DesignCapacityLow = GetValueFromArray(info, 7); + if (!Battery[battery].DesignVoltage) { Battery[battery].DesignVoltage = DummyVoltage; } + + if (PowerUnitIsWatt) { + UInt32 volt = Battery[battery].DesignVoltage / 1000; + InfoLog("Battery voltage %d,%03d", volt, Battery[battery].DesignVoltage % 1000); + if ((Battery[battery].DesignCapacity / volt) < 900) { + WarningLog("Battery reports mWh but uses mAh (%u)", + Battery[battery].DesignCapacity); + PowerUnitIsWatt = false; + } else { + Battery[battery].DesignCapacity /= volt; + Battery[battery].LastFullChargeCapacity /= volt; + Battery[battery].DesignCapacityWarning /= volt; + Battery[battery].DesignCapacityLow /= volt; + } + } + + if (Battery[battery].DesignCapacity < Battery[battery].LastFullChargeCapacity) { + WarningLog("Battery reports lower design capacity than maximum charged (%u/%u)", + Battery[battery].DesignCapacity, Battery[battery].LastFullChargeCapacity); + if (Battery[battery].LastFullChargeCapacity < AcpiMax) { + UInt32 temp = Battery[battery].DesignCapacity; + Battery[battery].DesignCapacity = Battery[battery].LastFullChargeCapacity; + Battery[battery].LastFullChargeCapacity = temp; + } + } + Battery[battery].Cycle = GetValueFromArray(info, 8); +} + +void VoodooBattery::GetBatteryInfo(UInt8 battery, OSObject * acpi) { + OSArray * info = OSDynamicCast(OSArray, acpi); + if (GetValueFromArray(info, 0) == 0x00000000) PowerUnitIsWatt = true; + Battery[battery].DesignCapacity = GetValueFromArray(info, 1); + Battery[battery].LastFullChargeCapacity = GetValueFromArray(info, 2); + Battery[battery].Technology = GetValueFromArray(info, 3); + Battery[battery].DesignVoltage = GetValueFromArray(info, 4); + Battery[battery].DesignCapacityWarning = GetValueFromArray(info, 5); + Battery[battery].DesignCapacityLow = GetValueFromArray(info, 6); + + if (!Battery[battery].DesignVoltage) { Battery[battery].DesignVoltage = DummyVoltage; } + + if (PowerUnitIsWatt) { + UInt32 volt = Battery[battery].DesignVoltage / 1000; + InfoLog("Battery voltage %d,%03d", volt, Battery[battery].DesignVoltage % 1000); + if ((Battery[battery].DesignCapacity / volt) < 900) { + WarningLog("Battery reports mWh but uses mAh (%u)", + Battery[battery].DesignCapacity); + PowerUnitIsWatt = false; + } else { + Battery[battery].DesignCapacity /= volt; + Battery[battery].LastFullChargeCapacity /= volt; + Battery[battery].DesignCapacityWarning /= volt; + Battery[battery].DesignCapacityLow /= volt; + } + } + + if (Battery[battery].DesignCapacity < Battery[battery].LastFullChargeCapacity) { + WarningLog("Battery reports lower design capacity than maximum charged (%u/%u)", + Battery[battery].DesignCapacity, Battery[battery].LastFullChargeCapacity); + if (Battery[battery].LastFullChargeCapacity < AcpiMax) { + UInt32 temp = Battery[battery].DesignCapacity; + Battery[battery].DesignCapacity = Battery[battery].LastFullChargeCapacity; + Battery[battery].LastFullChargeCapacity = temp; + } + } + + if (Battery[battery].LastFullChargeCapacity && Battery[battery].DesignCapacity) { + UInt32 last = Battery[battery].LastFullChargeCapacity; + UInt32 design = Battery[battery].DesignCapacity; + //UInt32 cycle = 2 * (10 - (last * 10 / design)) / 3; + Battery[battery].Cycle = (design - last) * 1000 / design; //assume battery designed for 1000 cycles + } +} + +void VoodooBattery::PublishBatteryInfo(UInt8 battery, OSObject * acpi, int Ext) +{ + OSArray * info = OSDynamicCast(OSArray, acpi); + // Publish to our IOKit powersource + BatteryPowerSource[battery]->setMaxCapacity(Battery[battery].LastFullChargeCapacity); + BatteryPowerSource[battery]->setDesignCapacity(Battery[battery].DesignCapacity); + BatteryPowerSource[battery]->setExternalChargeCapable(true); + BatteryPowerSource[battery]->setBatteryInstalled(true); + BatteryPowerSource[battery]->setLocation(StartLocation + battery); + BatteryPowerSource[battery]->setAdapterInfo(0); + BatteryPowerSource[battery]->setDeviceName(GetSymbolFromArray(info, 9 + Ext)); + BatteryPowerSource[battery]->setSerial(GetSymbolFromArray(info, 10 + Ext)); + BatteryPowerSource[battery]->setBatteryType(GetSymbolFromArray(info, 11 + Ext)); + BatteryPowerSource[battery]->setSerialString(GetSymbolFromArray(info, 10 + Ext)); + BatteryPowerSource[battery]->setManufacturer(GetSymbolFromArray(info, 12 + Ext)); + BatteryPowerSource[battery]->setCycleCount(Battery[battery].Cycle); +} + + +void VoodooBattery::BatteryInformation(UInt8 battery) { + PowerUnitIsWatt = false; + if (BatteryConnected[battery]) { + DebugLog("Battery %u Connected", battery); + OSObject * acpi = NULL; + + if (kIOReturnSuccess == BatteryDevice[battery]->evaluateObject(AcpiBatteryInformationEx, &acpi)) { //_BIX + if (acpi && (OSTypeIDInst(acpi) == OSTypeID(OSArray))) { + GetBatteryInfoEx(battery, acpi); + PublishBatteryInfo(battery, acpi, 7); + + BatteryPowerSource[battery]->updateStatus(); + acpi->release(); + return; + } else { + WarningLog("Error in ACPI data"); + //BatteryConnected[battery] = false; + //try to get _BIF + } + } + + if (kIOReturnSuccess == BatteryDevice[battery]->evaluateObject(AcpiBatteryInformation, &acpi)) { //_BIF + if (acpi && (OSTypeIDInst(acpi) == OSTypeID(OSArray))) { + GetBatteryInfo(battery, acpi); + PublishBatteryInfo(battery, acpi, 0); + acpi->release(); + } else { + WarningLog("Error in ACPI data"); + BatteryConnected[battery] = false; + } + } + } else { + DebugLog("Battery %u Disconnected", battery); + BatteryPowerSource[battery]->BlankOutBattery(); + CalculatedAcAdapterConnected[battery] = false; + } + BatteryPowerSource[battery]->updateStatus(); +} + +void VoodooBattery::BatteryStatus(UInt8 battery) { + OSObject * acpi = NULL; + + if (kIOReturnSuccess == BatteryDevice[battery]->evaluateObject(AcpiBatteryStatus, &acpi)) { //_BST + if (acpi && (OSTypeIDInst(acpi) == OSTypeID(OSArray))) { + OSArray * status = OSDynamicCast(OSArray, acpi); + setProperty(BatteryDevice[battery]->getName(), status); + + UInt32 TimeRemaining = 0; + UInt32 HighAverageBound, LowAverageBound; + bool bogus = false; + bool warning = false; + bool critical = false; + Battery[battery].State = GetValueFromArray(status, 0); + Battery[battery].PresentRate = GetValueFromArray(status, 1); + Battery[battery].RemainingCapacity = GetValueFromArray(status, 2); + Battery[battery].PresentVoltage = GetValueFromArray(status, 3); + + if (PowerUnitIsWatt) { + UInt32 volt = Battery[battery].DesignVoltage / 1000; + Battery[battery].PresentRate /= volt; + Battery[battery].RemainingCapacity /= volt; + } + // Average rate calculation + if (!Battery[battery].PresentRate || (Battery[battery].PresentRate == AcpiUnknown)) { + UInt32 delta = (Battery[battery].RemainingCapacity > Battery[battery].LastRemainingCapacity ? + Battery[battery].RemainingCapacity - Battery[battery].LastRemainingCapacity : + Battery[battery].LastRemainingCapacity - Battery[battery].RemainingCapacity); + UInt32 interval = QuickPoll ? 3600 / (QuickPollInterval / 1000) : 3600 / (NormalPollInterval / 1000); + Battery[battery].PresentRate = delta ? delta * interval : interval; + } + + if (!Battery[battery].AverageRate) { Battery[battery].AverageRate = Battery[battery].PresentRate; } + Battery[battery].AverageRate += Battery[battery].PresentRate; + Battery[battery].AverageRate >>= 1; + HighAverageBound = Battery[battery].PresentRate * (100 + AverageBoundPercent) / 100; + LowAverageBound = Battery[battery].PresentRate * (100 - AverageBoundPercent) / 100; + + if (Battery[battery].AverageRate > HighAverageBound) { + Battery[battery].AverageRate = HighAverageBound; + } + + if (Battery[battery].AverageRate < LowAverageBound) { + Battery[battery].AverageRate = LowAverageBound; + } + // Remaining capacity + if (!Battery[battery].RemainingCapacity || (Battery[battery].RemainingCapacity == AcpiUnknown)) { + WarningLog("Battery %u has no remaining capacity reported", battery); + } else { + TimeRemaining = (Battery[battery].AverageRate ? + 60 * Battery[battery].RemainingCapacity / Battery[battery].AverageRate : + 60 * Battery[battery].RemainingCapacity); + BatteryPowerSource[battery]->setTimeRemaining(TimeRemaining); + TimeRemaining = (Battery[battery].PresentRate ? + 60 * Battery[battery].RemainingCapacity / Battery[battery].PresentRate : + 60 * Battery[battery].RemainingCapacity); + BatteryPowerSource[battery]->setInstantaneousTimeToEmpty(TimeRemaining); + } + // Voltage + if (!Battery[battery].PresentVoltage || (Battery[battery].PresentVoltage == AcpiUnknown)) { + Battery[battery].PresentVoltage = Battery[battery].DesignVoltage; + } + // Check battery state + switch (Battery[battery].State & 0x3) { + case BatteryFullyCharged: + DebugLog("Battery %u Full", battery); + CalculatedAcAdapterConnected[battery] = true; + BatteriesAreFull &= true; + BatteryPowerSource[battery]->setIsCharging(false); + BatteryPowerSource[battery]->setFullyCharged(true); + + if ((Battery[battery].LastRemainingCapacity >= Battery[battery].DesignCapacity) || + (Battery[battery].LastRemainingCapacity == 0)) { + BatteryPowerSource[battery]->setCurrentCapacity(Battery[battery].LastFullChargeCapacity); + } else { + BatteryPowerSource[battery]->setCurrentCapacity(Battery[battery].LastRemainingCapacity); + } + + BatteryPowerSource[battery]->setInstantAmperage((SInt32) Battery[battery].PresentRate); + BatteryPowerSource[battery]->setAmperage((SInt32) Battery[battery].AverageRate); + break; + case BatteryDischarging: + DebugLog("Battery %u Discharging", battery); + CalculatedAcAdapterConnected[battery] = false; + BatteriesAreFull = false; + BatteryPowerSource[battery]->setIsCharging(false); + BatteryPowerSource[battery]->setFullyCharged(false); + BatteryPowerSource[battery]->setCurrentCapacity(Battery[battery].RemainingCapacity); + BatteryPowerSource[battery]->setInstantAmperage((SInt32) Battery[battery].PresentRate * -1); + BatteryPowerSource[battery]->setAmperage((SInt32) Battery[battery].AverageRate * -1); + break; + case BatteryCharging: + DebugLog("Battery %u Charging", battery); + CalculatedAcAdapterConnected[battery] = true; + BatteriesAreFull = false; + BatteryPowerSource[battery]->setIsCharging(true); + BatteryPowerSource[battery]->setFullyCharged(false); + BatteryPowerSource[battery]->setCurrentCapacity(Battery[battery].RemainingCapacity); + BatteryPowerSource[battery]->setInstantAmperage((SInt32) Battery[battery].PresentRate); + BatteryPowerSource[battery]->setAmperage((SInt32) Battery[battery].AverageRate); + break; + default: + WarningLog("Bogus status data from battery %u (%x)", battery, Battery[battery].State); + BatteriesAreFull = false; + BatteryPowerSource[battery]->setIsCharging(false); + BatteryPowerSource[battery]->setFullyCharged(false); + BatteryPowerSource[battery]->setCurrentCapacity(Battery[battery].RemainingCapacity); + bogus = true; + break; + } + warning = Battery[battery].RemainingCapacity <= Battery[battery].DesignCapacityWarning; + critical = Battery[battery].RemainingCapacity <= Battery[battery].DesignCapacityLow; + + if (Battery[battery].State & BatteryCritical) { + DebugLog("Battery %u is critical", battery); + critical = true; + } + + if (!warning && TimeRemaining < 10) { warning = true; } + if (!critical && TimeRemaining < 5) { critical = true; } + + BatteryPowerSource[battery]->setAtWarnLevel(warning); + BatteryPowerSource[battery]->setAtCriticalLevel(critical); + BatteryPowerSource[battery]->setVoltage(Battery[battery].PresentVoltage); + + if (critical && bogus) { + BatteryPowerSource[battery]->setErrorCondition((OSSymbol *) permanentFailureKey); + } + + BatteryPowerSource[battery]->rebuildLegacyIOBatteryInfo(); + BatteryPowerSource[battery]->settingsChangedSinceUpdate = true; + BatteryPowerSource[battery]->updateStatus(); + acpi->release(); + } else { + WarningLog("Error in ACPI data"); + BatteryConnected[battery] = false; + } + } + Battery[battery].LastRemainingCapacity = Battery[battery].RemainingCapacity; +} + +void VoodooBattery::ExternalPower(bool status) { + IOPMrootDomain * rd = getPMRootDomain(); + rd->receivePowerNotification(kIOPMSetACAdaptorConnected | (kIOPMSetValue * status)); + + for (UInt8 i = 0; i < BatteryCount; i++) { + BatteryPowerSource[i]->setExternalConnected(status); + } +} + +IOReturn VoodooBattery::callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4) { + SInt32 value; + UInt32 index = 0; + int batNum = 0; + // OSString* key; + + + if (functionName->isEqualTo(kFakeSMCGetValueCallback)) { + const char* name = (const char*)param1; + void* data = param2; + + if (name && data) { + // WarningLog("callPF for key %s", name); + if ((name[0] == 'B') && (name[2] == 'A')) { + batNum = name[1] - 0x30; + if (OSNumber *number = OSDynamicCast(OSNumber, sensors->getObject(name))) { + index = number->unsigned16BitValue(); + if (index >= MaxBatteriesSupported) { + WarningLog("called battery # %d for A%c", index, name[3]); + return kIOReturnBadArgument; + } + } + + BatteryStatus(batNum); + switch (name[3]) { + case 'C': + value = Battery[batNum].AverageRate; + break; + case 'V': + value = Battery[batNum].PresentVoltage; + break; + default: + return kIOReturnBadArgument; + } + memcpy(data, &value, 2); + return kIOReturnSuccess; + } else if ((name[0] == 'B') && (name[2] == 'S') && (name[3] == 't')) { + UInt32 state = 0; + batNum = name[1] - 0x30; + if (OSNumber *number = OSDynamicCast(OSNumber, sensors->getObject(name))) { + index = number->unsigned16BitValue(); + if (index >= MaxBatteriesSupported) { + WarningLog("called battery # %d for St", index); + return kIOReturnBadArgument; + } + } + BatteryStatus(batNum); + state = Battery[batNum].State; + value = kBInitializedStatusBit; + if (state & BatteryDischarging) + value |= kBDischargingStatusBit; + if (state & BatteryCritical) + value |= kBFullyDischargedStatusBit; + if ((state & 3) == BatteryFullyCharged) + value |= kBFullyChargedStatusBit | kBTerminateChargeAlarmBit; + memcpy(data, &value, 2); + return kIOReturnSuccess; + } else if ((name[0] == 'B') && (name[2] == 'R') && (name[3] == 'M')) { + batNum = name[1] - 0x30; + if (OSNumber *number = OSDynamicCast(OSNumber, sensors->getObject(name))) { + index = number->unsigned16BitValue(); + if (index >= MaxBatteriesSupported) { + WarningLog("called battery # %d for RM", index); + return kIOReturnBadArgument; + } + } + BatteryStatus(batNum); + value = Battery[batNum].RemainingCapacity; + memcpy(data, &value, 2); + return kIOReturnSuccess; + } else if ((name[0] == 'B') && (name[1] == 'R') && + (name[2] == 'S') && (name[3] == 'C')) { + UInt32 batrc = 0; + value = 0; + for (UInt8 i = 0; i < BatteryCount; i++) { + batNum = i; + if (BatteryConnected[batNum]) { + BatteryStatus(batNum); + batrc = Battery[batNum].RemainingCapacity * 100 / Battery[batNum].LastFullChargeCapacity; + value = (value << 8) | batrc; + } + } + memcpy(data, &value, 2); //assumes only two battery possible + return kIOReturnSuccess; + } else if ((name[0] == 'C') && (name[1] == 'H') && (name[2] == 'L') && (name[3] == 'C')) { + UInt32 state = 0; + value = 1; + for (UInt8 i = 0; i < BatteryCount; i++) { + batNum = i; + if (BatteryConnected[batNum]) { + BatteryStatus(batNum); + state = Battery[batNum].State; + if ((state & 3) == BatteryFullyCharged) { + value = 2; //if one battery is fully charged + break; + } + } + } + } + else if ((name[0] == 'M') && (name[1] == 'S') && + (name[2] == 'L') && (name[3] == 'D')) { + if (!LidDevice) { + return kIOReturnBadArgument; + } + UInt32 acpi = 0; + LidDevice->evaluateInteger(LidStatus, &acpi); + value = acpi ? 0 : 1; + } else if ((name[0] == 'B') && (name[1] == 'A') && + (name[2] == 'T') && (name[3] == 'P')) { + if (firstTime) { + value = 1; + firstTime = false; + } + else { + value = ExternalPowerConnected ? 0 : 1; + } + } else if ((name[0] == 'B') && (name[1] == 'B') && + (name[2] == 'I') && (name[3] == 'N')) { + value = BatteriesConnected; + } else if ((name[0] == 'B') && (name[1] == 'N') && + (name[2] == 'u') && (name[3] == 'm')) { + value = BatteryCount; + } else if ((name[0] == 'A') && (name[1] == 'C') && + (name[2] == '-') && (name[3] == 'N')) { + value = AcAdapterCount; + memcpy(data, &value, 2); + return kIOReturnSuccess; + } else if ((name[0] == 'A') && (name[1] == 'C') && + (name[2] == '-') && (name[3] == 'W')) { + value = 1; //numeration from 1 + } else if ((name[0] == 'A') && (name[1] == 'C') && + (name[2] == 'I') && (name[3] == 'C')) { + value = 0x0020; //big endian will be 0x2000 = 8192mA = 96W Is it enough? + memcpy(data, &value, 2); + return kIOReturnSuccess; + } else { + return kIOReturnBadArgument; + } + memcpy(data, &value, 1); + return kIOReturnSuccess; + } + return kIOReturnBadArgument; + } + + return IOService::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); + +} + +#pragma mark - +#pragma mark VoodooBattery PowerSource Device +#pragma mark - +#pragma mark IOPMPowerSource + +OSDefineMetaClassAndStructors(AppleSmartBattery, IOPMPowerSource) + +IOReturn AppleSmartBattery::message(UInt32 type, IOService * provider, void * argument) { + + if (ParentService) { + ParentService->message(type, provider, argument); + } + return kIOReturnSuccess; +} + +#pragma mark Own + +AppleSmartBattery * AppleSmartBattery::NewBattery(void) { + // Create and initialize our powersource + AppleSmartBattery * battery = new AppleSmartBattery; + if (battery) { + if (battery->init()) { return battery; } + battery->release(); + } + return 0; +} + +IOReturn AppleSmartBattery::setPowerState(unsigned long which, IOService *whom) +{ + return IOPMAckImplied; +} + +void AppleSmartBattery::BlankOutBattery(void) { + setBatteryInstalled(false); + setCycleCount(0); + setAdapterInfo(0); + setIsCharging(false); + setCurrentCapacity(0); + setMaxCapacity(0); + setTimeRemaining(0); + setAmperage(0); + setVoltage(0); + properties->removeObject(manufacturerKey); + removeProperty(manufacturerKey); + properties->removeObject(serialKey); + removeProperty(serialKey); + properties->removeObject(batteryInfoKey); + removeProperty(batteryInfoKey); + properties->removeObject(errorConditionKey); + removeProperty(errorConditionKey); + properties->removeObject(chargeStatusKey); + removeProperty(chargeStatusKey); + rebuildLegacyIOBatteryInfo(); +} + +void AppleSmartBattery::setDesignCapacity(unsigned int val) { + OSNumber *n = OSNumber::withNumber(val, 32); + setPSProperty(designCapacityKey, n); + n->release(); +} + +void AppleSmartBattery::setDeviceName(OSSymbol * sym) { + if (sym) { + setPSProperty(deviceNameKey, (OSObject *) sym); + } +} + +void AppleSmartBattery::setBatteryType(OSSymbol * sym) { + if (sym) { + setPSProperty(batteryTypeKey, (OSObject *) sym); + } +} + +void AppleSmartBattery::setFullyCharged(bool charged) { + setPSProperty(fullyChargedKey, + (charged ? kOSBooleanTrue:kOSBooleanFalse)); +} + +void AppleSmartBattery::setInstantAmperage(int mA) { + OSNumber *n = OSNumber::withNumber(mA, 32); + if (n) { + setPSProperty(instantAmperageKey, n); + n->release(); + } +} + +void AppleSmartBattery::setInstantaneousTimeToEmpty(int seconds) { + OSNumber *n = OSNumber::withNumber(seconds, 32); + if (n) { + setPSProperty(instantTimeToEmptyKey, n); + n->release(); + } +} + +void AppleSmartBattery::setSerialString(OSSymbol * sym) { + if (sym) { + setPSProperty(softwareSerialKey, (OSObject *) sym); + } +} + +void AppleSmartBattery::rebuildLegacyIOBatteryInfo(void) { + OSDictionary *legacyDict = OSDictionary::withCapacity(5); + uint32_t flags = 0; + OSNumber *flags_num = NULL; + + if(externalConnected()) { + flags |= kIOPMACInstalled; + } + + if(batteryInstalled()) { + flags |= kIOPMBatteryInstalled; + } + + if(isCharging()) { + flags |= kIOPMBatteryCharging; + } + + flags_num = OSNumber::withNumber((unsigned long long)flags, 32); + legacyDict->setObject(kIOBatteryFlagsKey, flags_num); + flags_num->release(); + + legacyDict->setObject(kIOBatteryCurrentChargeKey, properties->getObject(kIOPMPSCurrentCapacityKey)); + legacyDict->setObject(kIOBatteryCapacityKey, properties->getObject(kIOPMPSMaxCapacityKey)); + legacyDict->setObject(kIOBatteryVoltageKey, properties->getObject(kIOPMPSVoltageKey)); + legacyDict->setObject(kIOBatteryAmperageKey, properties->getObject(kIOPMPSAmperageKey)); + legacyDict->setObject(kIOBatteryCycleCountKey, properties->getObject(kIOPMPSCycleCountKey)); + + setLegacyIOBatteryInfo(legacyDict); + + legacyDict->release(); +} + diff --git a/plugins/VoodooBattery/VoodooBattery.h b/plugins/VoodooBattery/VoodooBattery.h new file mode 100755 index 0000000..cf4dcb8 --- /dev/null +++ b/plugins/VoodooBattery/VoodooBattery.h @@ -0,0 +1,339 @@ +/* + --- VoodooBattery --- + (C) 2009 Superhai + + Contact http://www.superhai.com/ + + */ + +#include +#include +#include +#include +#include +#include + +//#include "FakeSMC.h" + +// Constants + +const UInt8 MaxBatteriesSupported = 4; +const UInt8 MaxAcAdaptersSupported = 2; +const UInt8 AverageBoundPercent = 25; + +const UInt32 QuickPollInterval = 1000; +const UInt32 NormalPollInterval = 60000; +const UInt32 QuickPollPeriod = 60000; +const UInt32 QuickPollCount = QuickPollPeriod / QuickPollInterval; + +const UInt32 AcpiUnknown = 0xFFFFFFFF; +const UInt32 AcpiMax = 0x80000000; + +const UInt32 DummyVoltage = 12000; + + +const UInt32 StartLocation = kIOPMPSLocationLeft; + +// String constants + +const char * PnpDeviceIdBattery = "PNP0C0A"; +const char * PnpDeviceIdLid = "PNP0C0D"; +const char * PnpDeviceIdAcAdapter = "ACPI0003"; +const char * PnpDeviceIdPnlf = "APP0002"; +const char * AcpiStatus = "_STA"; +const char * AcpiPowerSource = "_PSR"; +const char * AcpiBatteryInformation = "_BIF"; +const char * AcpiBatteryInformationEx = "_BIX"; +const char * AcpiBatteryStatus = "_BST"; +const char * LidStatus = "_LID"; +const char * MethodBQC = "_BQC"; +const char * MethodBCM = "_BCM"; +const char * MethodBCL = "_BCL"; + +/* +// _BIF +Package { + Power Unit // Integer (DWORD) + Design Capacity // Integer (DWORD) + Last Full Charge Capacity // Integer (DWORD) + Battery Technology // Integer (DWORD) + Design Voltage // Integer (DWORD) + Design Capacity of Warning // Integer (DWORD) + Design Capacity of Low // Integer (DWORD) + Battery Capacity Granularity 1 // Integer (DWORD) + Battery Capacity Granularity 2 // Integer (DWORD) + Model Number // String (ASCIIZ) + Serial Number // String (ASCIIZ) + Battery Type // String (ASCIIZ) + OEM Information // String (ASCIIZ) +} + +// _BIX +Package { + // ASCIIZ is ASCII character string terminated with a 0x00. + Revision //Integer + Power Unit + Design Capacity + Last Full Charge Capacity //Integer (DWORD) + Battery Technology + Design Voltage + Design Capacity of Warning + Design Capacity of Low + Cycle Count //Integer (DWORD) + Measurement Accuracy //Integer (DWORD) + Max Sampling Time //Integer (DWORD) + Min Sampling Time //Integer (DWORD) + Max Averaging Interval //Integer (DWORD) + Min Averaging Interval //Integer (DWORD) + Battery Capacity Granularity 1 + Battery Capacity Granularity 2 + Model Number + Serial Number + Battery Type + OEM Information +} +*/ + +static const OSSymbol * unknownObjectKey = OSSymbol::withCString(""); +static const OSSymbol * designCapacityKey = OSSymbol::withCString(kIOPMPSDesignCapacityKey); +static const OSSymbol * deviceNameKey = OSSymbol::withCString(kIOPMDeviceNameKey); +static const OSSymbol * fullyChargedKey = OSSymbol::withCString(kIOPMFullyChargedKey); +static const OSSymbol * instantAmperageKey = OSSymbol::withCString("InstantAmperage"); +static const OSSymbol * instantTimeToEmptyKey = OSSymbol::withCString("InstantTimeToEmpty"); +static const OSSymbol * softwareSerialKey = OSSymbol::withCString("BatterySerialNumber"); +static const OSSymbol * chargeStatusKey = OSSymbol::withCString(kIOPMPSBatteryChargeStatusKey); +static const OSSymbol * permanentFailureKey = OSSymbol::withCString("Permanent Battery Failure"); +// +static const OSSymbol * batteryTypeKey = OSSymbol::withCString("BatteryType"); + +//static IOPMPowerState PowerStates[2] = +//{ {1,0,0,0,0,0,0,0,0,0,0,0}, {1,2,2,2,0,0,0,0,0,0,0,0} }; + +enum { // Apple loves to have the goodies private + kIOPMSetValue = (1<<16), + kIOPMSetDesktopMode = (1<<17), + kIOPMSetACAdaptorConnected = (1<<18) +}; + +// Battery state _BST +enum { + BatteryFullyCharged = 0, + BatteryDischarging = (1<<0), + BatteryCharging = (1<<1), + BatteryCritical = (1<<2), +// BatteryWithAc = (1<<7) +}; + +/* Smart Battery Status Message Bits */ +/* Smart Battery Data Specification - rev 1.1 */ +/* Section 5.4 page 42 */ +enum { + kBOverChargedAlarmBit = 0x8000, + kBTerminateChargeAlarmBit = 0x4000, + kBOverTempAlarmBit = 0x1000, + kBTerminateDischargeAlarmBit = 0x0800, + kBRemainingCapacityAlarmBit = 0x0200, + kBRemainingTimeAlarmBit = 0x0100, + kBInitializedStatusBit = 0x0080, + kBDischargingStatusBit = 0x0040, + kBFullyChargedStatusBit = 0x0020, + kBFullyDischargedStatusBit = 0x0010 +}; + +class ButtonController; +class Button : public IOHIKeyboard +{ + OSDeclareDefaultStructors(Button); +private: +// + bool pressed; + ButtonController * _controller; +public: + bool isPressed(); +public: + virtual bool sendEvent(UInt8); + + virtual bool attach(IOService * provider); + virtual void detach(IOService * provider); + +}; + +class ButtonController : public IOService +{ + OSDeclareDefaultStructors(ButtonController); + +private: + Button * ACButton2; + +public: + virtual bool init(OSDictionary * properties); + virtual ButtonController * probe(IOService * provider, SInt32 * score); + virtual bool start(IOService * provider); + virtual void stop(IOService * provider); + virtual bool sendEvent(UInt8 keyEvent); +}; + +struct BatteryClass { + UInt32 LastFullChargeCapacity; + UInt32 DesignCapacity; + UInt32 DesignCapacityWarning; + UInt32 DesignCapacityLow; + UInt32 DesignVoltage; + UInt32 Technology; + UInt32 State; + UInt32 PresentVoltage; + UInt32 PresentRate; + UInt32 AverageRate; + UInt32 RemainingCapacity; + UInt32 LastRemainingCapacity; + UInt32 Cycle; +}; + +class AppleSmartBattery : public IOPMPowerSource { + OSDeclareDefaultStructors(AppleSmartBattery) +private: +protected: + IOService * ParentService; + void BlankOutBattery(void); + void setDesignCapacity(unsigned int val); + void setDeviceName(OSSymbol * sym); + void setFullyCharged(bool charged); + void setInstantAmperage(int mA); + void setInstantaneousTimeToEmpty(int seconds); + void setSerialString(OSSymbol * sym); + void rebuildLegacyIOBatteryInfo(void); + void setBatteryType(OSSymbol * sym); + //----- new for ElCapitan + /* Protected "setter" methods for subclasses + * Subclasses should use these setters to modify all battery properties. + * + * Subclasses must follow all property changes with a call to updateStatus() + * to flush settings changes to upper level battery API clients. + * + */ +#if 0 + void setExternalConnected(bool); + void setExternalChargeCapable(bool); + void setBatteryInstalled(bool); + void setIsCharging(bool); + void setAtWarnLevel(bool); + void setAtCriticalLevel(bool); + + void setCurrentCapacity(unsigned int); + void setMaxCapacity(unsigned int); + void setTimeRemaining(int); + void setAmperage(int); + void setVoltage(unsigned int); + void setCycleCount(unsigned int); + void setAdapterInfo(int); + void setLocation(int); + + void setErrorCondition(OSSymbol *); + void setManufacturer(OSSymbol *); + void setModel(OSSymbol *); + void setSerial(OSSymbol *); + void setLegacyIOBatteryInfo(OSDictionary *); +#endif +public: + static AppleSmartBattery * NewBattery(void); + virtual IOReturn message(UInt32 type, IOService * provider, void * argument); + IOReturn setPowerState(unsigned long which, IOService *whom); + friend class VoodooBattery; +}; + +class VoodooBattery : public IOService { + OSDeclareDefaultStructors(VoodooBattery) +private: + IOService* fakeSMC; + OSDictionary* sensors; + + // *** Integers *** + UInt8 BatteryCount; + UInt8 AcAdapterCount; + UInt32 QuickPoll; + // *** Booleans *** + bool BatteryConnected[MaxBatteriesSupported]; + bool AcAdapterConnected[MaxAcAdaptersSupported]; + bool CalculatedAcAdapterConnected[MaxBatteriesSupported]; + bool ExternalPowerConnected; + bool BatteriesConnected; + bool BatteriesAreFull; + bool PowerUnitIsWatt; + bool firstTime; + // *** Other *** + BatteryClass Battery[MaxBatteriesSupported]; + IOACPIPlatformDevice * BatteryDevice[MaxBatteriesSupported]; + IOACPIPlatformDevice * AcAdapterDevice[MaxAcAdaptersSupported]; + AppleSmartBattery * BatteryPowerSource[MaxBatteriesSupported]; + IOACPIPlatformDevice * LidDevice; + ButtonController * ACButtonController; + IOACPIPlatformDevice * PNLFDevice; + Button * ACButton; + IOWorkLoop * WorkLoop; + IOTimerEventSource * Poller; + IOCommandGate * fBatteryGate[MaxBatteriesSupported]; + int * brightnessLevels; + int brightnessCount; + +// Button * ACButton; + // *** Methods *** + void Update(void); + void CheckDevices(void); + void GetBatteryInfoEx(UInt8 battery, OSObject * acpi); + void GetBatteryInfo(UInt8 battery, OSObject * acpi); + void PublishBatteryInfo(UInt8 battery, OSObject * acpi, int Ext); + void BatteryInformation(UInt8 battery); + void BatteryStatus(UInt8 battery); + void ExternalPower(bool status); + bool addSensor(const char* key, const char* type, unsigned int size, int index); + void ChangeBrightness(int Shift); + +protected: +// bool settingsChangedSinceUpdate; +public: + // *** IOService *** + virtual bool init(OSDictionary *properties=0); + virtual void free(void); + virtual IOService * probe(IOService * provider, SInt32 * score); + virtual bool start(IOService * provider); + virtual void stop(IOService * provider); + virtual IOReturn setPowerState(unsigned long state, IOService * device); + virtual IOReturn message(UInt32 type, IOService * provider, void * argument); + + virtual IOReturn callPlatformFunction(const OSSymbol *functionName, + bool waitForFunction, + void *param1, + void *param2, + void *param3, + void *param4); + +}; + +UInt32 GetValueFromArray(OSArray * array, UInt8 index) { + OSObject * object = array->getObject(index); + if (object && (OSTypeIDInst(object) == OSTypeID(OSNumber))) { + OSNumber * number = OSDynamicCast(OSNumber, object); + if (number) { + return number->unsigned32BitValue(); + } + } + return -1; +} + +OSSymbol * GetSymbolFromArray(OSArray * array, UInt8 index) { + OSObject * object = array->getObject(index); + if (object && (OSTypeIDInst(object) == OSTypeID(OSData))) { + OSData * data = OSDynamicCast(OSData, object); + if (data->appendByte(0x00, 1)) { + return (OSSymbol *) OSSymbol::withCString((const char *) data->getBytesNoCopy()); + } + } + + if (object && (OSTypeIDInst(object) == OSTypeID(OSString))) { + OSString * string = OSDynamicCast(OSString, object); + if (string) { + return OSDynamicCast(OSSymbol, string); + } + } + return (OSSymbol *) unknownObjectKey; +}