I have figured out how to control the fan speed on UX31 UX31A UX32A UX32VD and possibly many other ASUS laptops.
I don't have a program that would control the fan speed, but hopefully one of you can develop one now that the fan control functions are known! It is fairly trivial to do on Linux, you can modify asus-laptop.c kernel module using something like that, but you would need to make adaptations for the newer kernels. On Windows, I wouldn't even know where to start, to be honest!
The basic idea is to use ACPI call methods to set the fan speed. All the fan control methods can be fround in the DSDT table for these laptops (see DSDT for UX32VD)
There are TWO fans that can be controlled.
Fan1 - is CPU fan
Fan2 - is GPU fan (exists on models with dedicated GPU)
WARNING: Everything is not properly tested and you might end up completely turning off the fans! In the worst case, do a complete Shutdown of your computer to reset the fan values.
Tools you need
You will need work with ACPI (call methods, read variables) and tools to read/set values on the Embedded Controller.
For ACPI, I am not sure what would work on Windows, but for Linux you can use acpi_call kernel module
For reading/writing to the EmbeddedController you can use RWEverything on Windows and acer_ec.pl on Linux.
FAN CONTROL
The fan logic is not in the ACPI, but it is most likely in the Embedded Controller firmware (unconfirmed). Nevertheless, there exist functions in ACPI that let you control the speed of the fan(s) and read their speed as long as the fan(s) are in AUTOMATIC mode. If the fan is not in automatic mode, the speed reporting is NOT supported!
Once again, you can only see the speed of the fan if it is in automatic fan speed mode (default). You cannot see speed of the fan in manual fan speed mode (user changed using SFNV).
General: Differences in laptop models
Some laptops have only one fan (ex. UX31) vs. others have two (ex. UX32VD). If your laptop has only one fan, then controlling the 2nd fan will have no effect.
There are TWO fans that can be controlled.
Fan1 - CPU fan
Fan2 - GPU fan (exists on models with dedicated GPU, such as UX32VD)
Fan speed
Please note: speed will not be reported if the fan is in set to MANUAL speed mode using SFNV.
Read fan speed in RPM.
Arg0:
0 - for Fan1
1 - for Fan2
Code:\_SB.PCI0.LPCB.EC0.TACH Arg0Read fan speed in 100s of RPMCode:Method (TACH, 1, Serialized) { Name (_T_0, Zero) If (ECAV ()) { While (One) { Store (Arg0, _T_0) If (LEqual (_T_0, Zero)) { Store (TAH0, Local0) Break } Else { If (LEqual (_T_0, One)) { Store (TAH1, Local0) Break } Else { Return (Ones) } } Break } Multiply (Local0, 0x02, Local0) If (LNotEqual (Local0, Zero)) { Divide (0x0041CDB4, Local0, Local1, Local0) Return (Local0) } Else { Return (Ones) } } Else { Return (Ones) } }
Arg0:
0 - for Fan1
1 - for Fan2
This method is more generic and cleaner, but more "expensive" as it has to interact with SystemIO
Code:\_TZ.RFANRead fan speed in some units (to convert to RPM see the TACH method above for the formula).Code:Method (RFAN, 1, NotSerialized) { If (\_SB.PCI0.LPCB.EC0.ECAV ()) { Store (\_SB.PCI0.LPCB.EC0.ST83 (Arg0), Local0) // Gets the fan speed. 0x0 - OFF, 0x5a, 0x62, 0x79, 0xFF-reporting disabled? If (LEqual (Local0, 0xFF)) { Return (Local0) } Store (\_SB.PCI0.LPCB.EC0.TACH (Arg0), Local0) Divide (Local0, 0x64, Local1, Local0) Add (Local0, One, Local0) If (LLessEqual (Local0, 0x3C)) { Store (Local0, FANS) } Else { Store (FANS, Local0) } } Else { Store (Zero, Local0) } Return (Local0) }
Can also be read directly from the Embedded Controller at 0x93 for Fan1 and 0x95 for Fan2Code:\_SB.PCI0.LPCB.EC0.TAH0 //for Fan1 \_SB.PCI0.LPCB.EC0.TAH1 // for Fan2
NOTE: The fan speed is in 16-bit, not 8-bit so need to take into acount the next byte.
Code:OperationRegion (ECOR, EmbeddedControl, Zero, 0xFF) Field (ECOR, ByteAcc, Lock, Preserve) { ....... Offset (0x93), TAH0, 16, // Fan0 Tachometer TAH1, 16, // Fan1 Tachometer TSTP, 8, // some sort of Fan control. 0x1 if fan(s) on, 0x0 if fan(s) off, maybe other values... ....... }
Fan maximum speed
The MAXIMUM_ALLOWED fan speed can be anywhere from 0x00 (0 in decimal) to 0xFF (255 in decimal). Which is from OFF to MAX_POSSIBLE.
By default, the MAXIMUM_ALLOWED fan speed is set to 0xFF. This setting affects the fan speed both in manual and in automatic fan speed mode. You can change the MAXIMUM_ALLOWED fan speed to any level you want. Here is how
Set the Quiet Mode: limits the fan speed(s) to the given value: 0x00 (OFF) to 0xFF (MAX). Default is 0xFF
The "hacky" method:
Where Arg0:Code:\_SB.PCI0.LPCB.EC0.ST98 Arg0
0x00 (OFF) ot 0xFF (MAX) - MAXIMUM_ALLOWED fan speed.
This is not the best way to do this, however.
The clean method (how it should be done, ideally):
First write the fan speed value to:
And then call:Code:\_SB.QFAN // some place in SystemMemoryWhere Arg0:Code:\_SB.ATKD.QMOD Arg0
0 - just returns
1 - sets quiet mode to QFAN value
2 - sets quiet mode to 0xFF (that's the default value)
Code:Method (QMOD, 1, NotSerialized) { If (LEqual (Arg0, Zero)) { Return (One) } If (LEqual (Arg0, One)) { ^^PCI0.LPCB.EC0.ST98 (QFAN) } If (LEqual (Arg0, 0x02)) { ^^PCI0.LPCB.EC0.ST98 (0xFF) } Return (One) }
Fan speed MANUAL
WARNING: When fan speed is set to custom value, the fan is not properly powered down when in Standby (you can hear high pitch sound coming from the fan), therefore you must set it back to AUTO before going into Standby and the resume the manual values after.
Set custom fan speeds
Arg0: 0 - to reset fan(s) back to AUTO control (will only work if you previously called it with Arg0=1, or Arg0=2)Code:\_SB.PCI0.LPCB.EC0.SFNV Arg0 Arg1
1 - fan1
2 - fan2
Arg1
if Arg0 == 0, then set this one to 0 too.
otherwise, it is fan speed from 0x00 (OFF) to 0xFF (MAX)
For example:
Code:\_SB.PCI0.LPCB.EC0.SFNV 1 0x7D //set Fan1 speed to 0x7D (125) \_SB.PCI0.LPCB.EC0.SFNV 2 0x00 //set Fan1 speed to 0x00 (0) \_SB.PCI0.LPCB.EC0.SFNV 0 0 //reset fans back to Automatic fan controlIdeally, it is better to use \_SB.ATKD.SFNS as it is a more generic implementation (could work for other Asus laptops without having to change anything), but it requires ACPI memory allocation to pass it the arguments which is, in some cases, non-trivial.Code:Name (DECF, Zero) // stores which fans were set to manual control, for later resetting back to auto Method (SFNV, 2, Serialized) { If (LEqual (Arg0, Zero)) { If (And (DECF, One)) // reset Fan1 back to Auto speed control { Store (RRAM (0x0521), Local0) Or (Local0, 0x80, Local0) WRAM (0x0521, Local0) // 0x8d auto ON/OFF } If (And (DECF, 0x02)) // reset Fan2 back to Auto speed control { Store (RRAM (0x0522), Local0) Or (Local0, 0x80, Local0) WRAM (0x0522, Local0) // 0x8e auto ON/OFF } Store (Zero, DECF) Return (Zero) } If (LEqual (Arg0, One)) // set fan speed manually for Fan1 { Store (RRAM (0x0521), Local0) And (Local0, 0x7F, Local0) WRAM (0x0521, Local0) // 0xd manually set Or (DECF, One, DECF) ST84 (Zero, Arg1) Return (Zero) } If (LEqual (Arg0, 0x02)) // set fan speed manually for Fan2 { Store (RRAM (0x0522), Local0) And (Local0, 0x7F, Local0) WRAM (0x0522, Local0) // 0xe manually set Or (DECF, 0x02, DECF) ST84 (One, Arg1) Return (Zero) } Return (Zero) }
Additionally, I found in a config file of NoteBook FanControl that TSTP (Embedded Controller byte 0x97) is some sort of a manual fan control byte. It goes from 0 (MIN) to 8 (MAX) and is 9 (RESET/AUTO). I have not tested it, but throwing it out there in case anyone wants to have a look at it.
Reset fan speed back to AUTO
First, reset the MAXIMUM_ALLOWED fan speed:And then reset the fans back to auto modeCode:\_SB.ATKD.QMOD 0x02
Code:\_SB.PCI0.LPCB.EC0.SFNV 0 0
TEMPERATURE
CPU temperature
Can be read via ACPI in degrees Celsius:
Code:\_SB.PCI0.LPCB.EC0.ECPUOR (better, because more generic and clean)Code:IndexField (BRAI, BRAD, ByteAcc, NoLock, Preserve) { ..... Offset (0x98), ECPU, 8, // CPU Current temerature ECRT, 8, // CPU Critical Temperature (Tj Max) EPSV, 8, // CPU Passive Cooling Temperature ..... }
Code:\_TZ.RTMPYou can also read directly from the Embedded Controller at the offset of 0xA0 or 0xA6 (maybe this one is Intel GPU?) (can view with RWEverything on Windows and acer_ec.pl on Linux)Code:Method (RTMP, 0, NotSerialized) { If (\_SB.PCI0.LPCB.EC0.ECAV ()) { Store (\_SB.PCI0.LPCB.EC0.ECPU, Local0) If (LLess (Local0, 0x80)) { Store (Local0, LTMP) } } Return (LTMP) }
GPU (Intel) Temperature
Same as CPU temperature as Intel GPU is located on the CPU die.
GPU (Nvidia) Temperature (only on laptops with Nvidia GPU) (such as UX32VD)
When GPU is in off state, the temperatute reported is 0C, otherwise you get actual temperature +/-1C of what you would get in Nvidia Control Panel.
Can be read via ACPI in degrees Celsius:
Code:\_SB.PCI0.LPCB.EC0.TH1RYou can also read directly from the Embedded Controller at the offset of 0xA4 (can view with RWEverything on Windows and acer_ec.pl on Linux)Code:OperationRegion (ECOR, EmbeddedControl, Zero, 0xFF) Field (ECOR, ByteAcc, Lock, Preserve) { ....... Offset (0xA0), ECPU, 8, // CPU Current temerature ECRT, 8, // CPU Critical Temperature (Tj Max) EPSV, 8, // CPU Passive Cooling Temperature EACT, 8, // CPU Active Cooling Temperature? TH1R, 8, // Nvidia GPU temperature1 TH1L, 8, // Nvidia GPU temperature2 TH0R, 8, // CPU temperature? Intel GPU temperature? TH0L, 8, // always 0, so no idea what this is (shows temperature on older asus laptop) ......... }
There is also THR1L ( 0xA5) which is somehow related, but I am not sure what it is.
You may also want to check out my other post right here: http://forum.notebookreview.com/asus/687758-asus-ux32a-fan-goes-off-off-21.html#post9073025
-
-
Hello, thank you for your work !
we are curently working on installing MAC OSX 10.8 on Zenbookks prime on this thread : Zenbook Prime fixes, mods, tweaks, etc - OSx86 10.8 (Mountain Lion) - InsanelyMac Forum
One of our lastest ideas was to controll the fan speed cleverly, like on windows when the fans stops when the processors and GPU don't need
I'm hopping you know where put your methods in ours DSDT.aml, that controls the ACPI, and if they need to be called etc, a little how to patch would be great!
Thanks in advance and excuse my low english level. -
Getting the fan speed in RPM
If you do not know what hexadecimal number is and what a byte is then please read: Hexadecimal - Wikipedia, the free encyclopedia (understand what it is and how to convert to dec->hex and hex->dec) Byte - Wikipedia, the free encyclopedia (understand the definition)
You can read Fan1 and Fan2 speeds in the EC memory using RWEverything on Windows or acer_ec.pl on Linux. The fan speed is reported in some units (whatever they are) and can be converted to RPM using a certain formula. The fan speed is reported as 2-byte value.
Code:0x93 - Fan1: 1st byte of the speed 0x94 - Fan1: 2nd byte of the speed 0x95 - Fan2: 1st byte of the speed 0x96 - Fan2: 2nd byte of the speed
Code:00 01 02 03 04 05 06 07 | 08 09 0A 0B 0C 0D 0E 0F __ __ __ __ __ __ __ __ | __ __ __ __ __ __ __ __ 00 | 0A 80 01 -- -- -- -- -- | -- -- B7 B8 B7 B8 B7 B8 10 | B7 B8 05 -- 05 -- -- 19 | -- -- 17 21 55 58 33 32 20 | 2D 36 35 -- -- -- -- -- | -- -- -- -- -- -- -- -- 30 | -- -- -- -- -- -- -- -- | -- -- -- -- 07 -- -- -- 40 | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- 50 | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- 60 | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- 70 | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- 80 | 03 10 -- -- -- 80 -- 0A | -- -- -- -- -- -- -- -- 90 | -- -- -- 40 03 64 03 02 | -- -- -- -- -- -- -- -- A0 | 37 6C 6E 69 -- -- 37 -- | 01 -- -- -- -- -- -- -- B0 | 63 -- 7E 20 E7 18 44 19 | 01 60 E0 -- -- -- EB 0B C0 | -- -- D0 20 -- -- -- -- | -- -- -- -- -- -- -- -- D0 | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- E0 | -- -- -- -- -- -- -- -- | -- -- -- -- -- -- -- -- F0 | 78 19 E8 1C D0 20 C0 -- | -- -- -- -- -- -- -- --
Code:Fan1: [0x94][0x93], which in my case is: 0x94->0x03, 0x93->0x40, so fan speed: 0x340 Fan2: [0x96][0x95], which in my case is: 0x96->0x03, 0x95->0x64, so fan speed: 0x364
Code:0x0041CDB4 / (SPEED * 0x2) Which is the same as: 4312500 / (SPEED * 2)
Code:Fan1 - CPU: 0x0041CDB4 / (0x340 * 0x2) = 0xa1f which is in decimal: 2591 RPM Fan2 - GPU: 0x0041CDB4 / (0x364 * 0x2) = 0x9b4 which is in decimal: 2484 RPM
-
Hi there,
today I found your thread. Is there any progress on this topic?
I googled a lot but it seems you are the only one currently working on this topic (on Linux)?
It would be a good start if one could increase the "FAN GOES ON" temperature from ~50°C to 65°C. This would avoid that disturbing fan on off on off.
Would it be complicated to achieve this? -
For a while I used acpi_call kernel module to directly issue ACPI calls to change the fan speed, but that had it's own drawbacks.
Then a fellow forum user found the tools that could be used to extract and modify BIOS. I tried to find the Embedded Controller firmware (the chip that controls the fans) in the BIOS file, but I was not successful. I was planning to extract it, decompile it, fix the fan table in the firmware and then flash the new firmware. Since I wasn't able to find EC firmware, I had nothing to modify. And even if I had managed to modify it, I still don't know if there is a way to flash the modified firmware back to EC. There is a linux application superiotools (part of coreboot) that can read/write Embedded Controller firmware, however it did not support the chip on Zenbooks as there was no readily available documentation for it.
Eventually, the fan stopped bothering me and it wasn't worth the effort to make a fan control application. Now that you brought it up, it is starting to bother me again...
-
Thank you for your detailed answer. I have tried / compiled your peace of code ( fancntrl.c: Asus UX32VD fan control proof of concept - Pastebin.com)
It does really work on my UX31A Prime, I can control the fan. So as you stated it seems to work generally on all ASUS netbooks.
Sadly I can only handle some python/batch scripts, but I am not into deep C/C++ or else I would try it on my own
I am sure a there are a lot of Zenbook Linux users out there who would really appreciate your work.
edit: I just realized how wonderful it is to work with a silent environment. NBFC works so great under windows, I really hope someone will help us out here for Linux :/ -
HTML:<?xml version="1.0"?> <FanControlConfig xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <UniqueId>Asus Zenbook UX31A</UniqueId> <NotebookModel>UX31A</NotebookModel> <ReadRegister>151</ReadRegister> <WriteRegister>151</WriteRegister> <MinSpeedValue>0</MinSpeedValue> <MaxSpeedValue>8</MaxSpeedValue> <FanSpeedResetValue>9</FanSpeedResetValue> <ReadWriteWords>false</ReadWriteWords> <EcPollInterval>300</EcPollInterval> <AdjustFanControlMode>false</AdjustFanControlMode> <EcConfigurationRegister>0</EcConfigurationRegister> <ManualControlModeValue>0</ManualControlModeValue> <AutoControlModeValue>0</AutoControlModeValue> <FakeTemperature>false</FakeTemperature> <TemperatureRegister>0</TemperatureRegister> <ThermalZoneRegister>0</ThermalZoneRegister> <FakeTemperatureValue>0</FakeTemperatureValue> <TemperatureResetValue>0</TemperatureResetValue> <ThermalZonesIndices> <int>1</int> </ThermalZonesIndices> <TemperatureThresholds> <TemperatureThreshold> <UpThreshold>0</UpThreshold> <DownThreshold>0</DownThreshold> <FanSpeed>0</FanSpeed> </TemperatureThreshold> <TemperatureThreshold> <UpThreshold>65</UpThreshold> <DownThreshold>58</DownThreshold> <FanSpeed>22.5</FanSpeed> </TemperatureThreshold> <TemperatureThreshold> <UpThreshold>67</UpThreshold> <DownThreshold>61</DownThreshold> <FanSpeed>40</FanSpeed> </TemperatureThreshold> <TemperatureThreshold> <UpThreshold>69</UpThreshold> <DownThreshold>64</DownThreshold> <FanSpeed>65</FanSpeed> </TemperatureThreshold> <TemperatureThreshold> <UpThreshold>71</UpThreshold> <DownThreshold>67</DownThreshold> <FanSpeed>102.38095238095238</FanSpeed> </TemperatureThreshold> </TemperatureThresholds> <RegisterWriteRequests> <RegisterWriteRequest> <WriteMode>Set</WriteMode> <Register>160</Register> <Value>45</Value> </RegisterWriteRequest> <RegisterWriteRequest> <WriteMode>Set</WriteMode> <Register>166</Register> <Value>45</Value> </RegisterWriteRequest> </RegisterWriteRequests> </FanControlConfig>
1. The program reads/writes fan speed to EC register 151 or 0x97.
2. The minimum fan speed is 0 and max is 8. This is what it writes to that 0x97 register.
3. The fan speed reset value is 9. This is what you write to register 0x97 if you want to turn auto fan control back on (such as at program exit, at termination, etc).
4. The program polls the value of the temperature every 300ms.
5. Temperature is received from the Thermal Zone 1. Which you can get on Linux by reading /sys/devices/virtual/thermal/thermal_zone0/temp (which is preferred) or by accessing EC register 0xA0 (not advised).
6. The temperature thresholds are such:
Code:Fan on: 0 C, speed down: 0 C speed: 0 % Fan on: 65 C, speed down: 58 C speed: 22.5 % Fan on: 67 C, speed down: 61 C speed: 40% Fan on: 69 C, speed down: 64 C speed: 65 % Fan on: 71 C, speed down: 67 C speed: 102 % (uhhh. what?)
Write CPU temperature of 45 to EC 160 or 0xA0
Write CPU temperature of 45 to EC 166 or 0xA6
(As far as I know this is done to prevent computer from controlling the fan speeds automatically based on that temperature)
So, it is possible to write a relatively small script to do the NBFC behaviour on Linux and make it behave like it does on Windows. You may ask: "Why haven't you done this prikolchik if you are so clever?" Well, the reason why I didn't do this is because it is a very hacky and "unsafe" way and consumes a lot (relatively speaking, it is not really noticeable to the user) of CPU time (due to interrupts when writing to EC memory). I don't think it is a solution worth implementing, but it certainly works on Windows and it should definitely work on Linux.
Anyway, give it a try, experiment. Make use of acer_ec.pl script to play around with EC memory and see what you can come up with.
ALSO, if you want to go a different route... You can make a simple bash/python script that reads the ThermalZone CPU temperature as described above (in Step 5), but it controls the fan using the appropriate ACPI call methods (SFNV, ST98 as described in first post of this thread) via acpi_call kernel module. It should be fairly trivial to implement, even easier than doing all that Embedded Controller stuff like NBFC does it. For example:
Code:#!/bin/bash # make sure to run this with root permissions # assuming that you have acpi_call kernel module loaded # executes `\_SB.PCI0.LPCB.EC0.ST98 0x45' ACPI call to limit the maximum fan speed to 0x45 (with 0xFF being the maximum). # the script prints the return of the called function, which in this case is 0 for success and anything else is failure ACPI_CALL=/proc/acpi/call command='_SB.PCI0.LPCB.EC0.ST98 0x45' echo -E '\'"$command" > "${ACPI_CALL}"; echo $(cat "${ACPI_CALL}")
-
WOW! Thank you, this was a REALLY helpful answer. I will definitely try both of your suggested ways regulating the fan and post my solution if it works.
-
And it is a lot easier to be the guy-who-figured-out-fan-control than the guy-who-made-fan-control-work. It is like all I do is some investigation and documentation and I get most of the credit! It is a no-brainer
-
I wrote a simple Linux kernel module, and it works perfectly for me. I'll send a patch upstream soon.
https://gist.github.com/felipec/6169047 -
Is there any further progress on this, anyone? This only happens to me when I have my external monitor plugged in (why? I don't know, I also lose DVORAK keyboard layout and all default shortcuts if I boot up with it plugged in as well...ah Linux..) but in any case it is annoying as hell. I have to switch back to Windows until this is fixed. I'd gladly put in money towards a fix!
It's also not just an issue with needing to mod the BIOS - in Windows, even without NBFC installed, when it goes over the ~48 degree threshold, it turns on and off the fan at a low speed. In Ubuntu, once it goes over it turns it on max. There is no in between speeds, so as a result the problem is far worse in Linux.
Even there was a fix for Ubuntu so that the fan came on at the BIOS set shelves (which are too low but still not totally on/totally off), this would still be far better... -
Furthermore, there was a bios update 219 for the UX31A with changelog (updated thermal policy) that appears to have fixed the fan speed, if that helps to provide a basis for comparison....
-
Kinda late to the game, but with useful information ( https://github.com/daringer/asus-fan ) ... forked the good work from "felipec" and pushed it a little more, means there is:
- support for the second fan inside the nvidia zenbooks
- fix for "not showing fan speed while in manual mode"
- fix for "crazy up/down/up/down" spin behavior
(looks like my acpi data was not entirely correct, the module sets the most obvious/useful fan settings on load)
- support for all zenbooks listed on the wikipedia zenbook page
(if you wanna try another model, just mail me)
- if there are two fans (e.g., ux32vd) both may be controlled separately, and both show up as "cooling_deviceX"
- I managed to even set the max speed for each one, but thermal_cooling_device_* only provides "cur_state" and "max_state", which means, I can access it from inside but right now there is no way to use this feature from inside the userland...
https://github.com/daringer/asus-fan
Fan Control on Asus Prime UX31/UX31A/UX32A/UX32VD
Discussion in 'Asus' started by prikolchik, Jan 24, 2013.