I've just spent the last few days bothering to understand the Eris cpu frequency manipulation in the recently released kernel. I know a few people have already released kernels and ROMs with an overclock-enabled kernel based upon the work done for the Hero, but there are some additional complications with this one.
TECHNICAL INFO FOR GEEKS
There are 4 "clock sources" on this thing, at least. They're called txc0 (the base clock), mpll (modem phase lock loop), gpll (global PLL), and bpll0 (backup PLL zero). The processor can handle a bpll1 as well, but if it's there, it's nearly completely unconfigured. They run at these frequencies:
- txc0: 19200kHz
- mpll: 245760kHz
- gpll: 960000kHz
- bpll0: 1056000kHz
The way our cpu handles changing frequencies (at least by default) is to select between these 4 sources, and apply a divider of 1 through 16 to it. There are a number of frequencies that the kernel steps through when changing between frequencies, and they're all specified as source/divider conbinations in the acpuclock-arm11.c file in the kernel, but the only ones exported to the cpufreq module (the thing that setcpu uses) are the following (these are the same frequencies you'll see in SetCPU if you select msm7k turbo, aka Hero):
- 19200 (txc0)
- 122880 (mpll/5)
- 160000 (gpll/6)
- 245760 (mpll)
- 480000 (gpll/2)
- 528000 (bpll0/2)
If you're particularly math-savvy, you'll realize that there's no way to get any frequencies between 528MHz and 960MHz using this whole "source/divider" method. It's been tried, by myself and others, to clock our cpu at 960MHz...it simply doesn't work, sorry guys.
So, someone really bright figured out that you can actually change the configuration of bpll0 itself on the Hero, by writing a multiplier (of the txc0 frequency) to a magic location on the board. This way, we could set the bpll0 source to whatever base frequency we wanted! That worked quite well for the Hero -- set the bpll0 source to the cpu frequency we wanted, and remove the divider, and you get any multiple of 19.2MHz that you'd like.
In the overly complicated (and redundant) table of frequencies in the acpuclock-arm11.c source code, there's an AHB frequency field, and an AHB clock divider. The AHB bus is like the PCI bus on a computer -- it runs wifi, usb, and things like that. The frequency listed in the table is completely for humans, as the code doesn't use it anywhere. However, the divider is applied to the *CPU frequency*, and the max it can be is 4 (it's only a 2-bit field, 0, 1, 2, or 3 -- add one to the value to get the divider value). At 528MHz cpu speed, the bus is at 132MHz with the max multiplier, and there's no way to overclock the CPU without also overclocking the AHB bus. C'est la vie.
On the Eris, there are further issues. The first of which is PerfLock.
Even before trying of overclock, I'm sure some of you installed setcpu and noticed that you could set the sliders to anything you wanted, and the cpu ignored you. It would stay at 480min/528max, no matter what, while the screen was on. (It actually went to 245.76min/254.76max while the screen was off, but that's harder to notice.) This is because the lovely people at HTC were trying to conserve power by scaling down the cpu when you weren't using the phone, and still have it be responsive when you were actually fiddling with it. In order to have setcpu work, we need to disable the perflock hooks into the cpufreq module.
The second issue is that bpll0 is used by something other than the CPU. I don't know what, but I do know that setting the base clock to much less than 700MHz makes it mighty unstable, and that it gets even *more* unstable as you *decrease* the frequency, which means that whatever else is using that source really doesn't like to get underclocked. So, we have a balancing game: The bpll0 source needs to be high enough that we're not severely underclocking the other hardware, and low enough that we're not cooking the CPU.
I tried two ways around this. First, I decided to become really bright myself, and I found the config locations for the gpll and mpll sources as well, and tried using the gpll source instead of bpll0. I did manage to clock gpll up and down, but anything other than 960MHz seemed very unstable. I suspect that a lot of the phone hardware is based on that source -- it is called "global", after all. The second way was to overclock the bpll0 source and keep the divider of 2, instead of underclocking it. That actually worked, but became unstable when the frequency got much higher than 650. So, I reverted to using bpll0 at 768 with no divider, which has been very stable thus far.
I tried, in fact, every multiple of 19.2 between 528 and 864. The sweet spot of stability is at 768, and anything higher or lower rapidly loses stability.
The next issue, also related to power saving, is the power collapse stepping. The kernel actually steps the kernel down to "idle", consuming the least amount of power, by bringing the cpu all the way down to 19.2MHz when idle. For every jump of more than 256MHz, up or down, the phone goes through this series of frequency jumps specified by the "up" and "down" fields of the frequency table, which are just indexes into the same table for the next frequency in the sequence. Existing patches that simply copy the 528 line as a whole and alter only the frequency and divider will lead to problems in two ways: First, if you try to jump from 480 to, say, 768, it will fail. The kernel will tell you that it's now running at 768, but it will actually still be running at 480, because the "up" field of the 480 entry is invalid and the difference is greater than 256. The 528 frequency is within 256 of 480, so there was no reason to put a valid entry there. This means that if you're using the ondemand governor, *sometimes* it will successfully overclock, and sometimes it won't. I observed this with my own testing, both in performance tests and in the debug logs for the kernel. Second, if you try to collapse *down* from 768, the "down" field of the 528 entry brings it down to 352, which is going to be more than 256, which causes the CPU to become unstable.
With the existing patches, it would just *leave* the bpll0 multiplier at the lower value, meaning that during power collapse, the intermediate frequencies would be different than the driver suspected, and larger than 256MHz of a jump as well, making the phone significantly less stable. It's just bad all around.
To make matters even more complicated, if you actually get rid of the perflock hooks, the cpufreq module defaults to setting the min and max to the lowest and highest available frequencies, causing major mayhem if your phone can't actually handle the overclocked frequencies that are enabled in the kernel.
WHAT I'VE DONE
This patch (attached), when applied to the Eris 2.1 kernel source from HTC, with the config taken directly from the leaked rom of the phone, will give you a kernel that will obey setcpu, will set the default min/max upon boot to 245.76/528 so you're not overclocking by default, enables the "auto" mode of setcpu, adds a frequency of 768MHz, and fixes up the step up/down fields of the table to make the ondemand and power collapse dynamic frequency steppings work consistently and as expected (by restoring the correct PLL multiplier for every frequency, adding correct steppings to 528, 480, and 768 entries, and being sure increase divider and decrease multipliers before decreasing dividers or increasing multipliers). Oh, and I enabled the netfilter module required by DroidWall, because about five million people asked me to.
Because I'm nice and a lot of people don't like compiling their own kernels, I've also attached a flashable update.zip that flashes a new boot.img (ramdisk+kernel) and installs the corresponding wifi driver.
I get a 50% increase in Linpack scores with the below patch. (I'm running Ivan's 0.8T2 right now, went from 2.2 at 528MHz to 3.3 at 768MHz.)
EDITED TO ADD:
A number of people have asked what my SetCPU profiles look like. They look like this:
Default: 480/768 (I have it clock down to 480 instead of 528 because 480 actually uses a lower voltage.)
Standby: 160/245 (I like battery life. It takes a while to show me who's calling, though, when it rings while in standby.)
Failsafe: 40C/245/245 (40 degrees is probably too hot. I want to stop it before it melts, which would be around 50 degrees.)
So, 768MHz is the sweet spot on *my* phone, but apparently not all are created equal. I've added two more frequencies, 604.8MHz (overclocking bpll0 to 1209.6MHz and dividing by 2) and 710.4MHz (underclocking bpll0 to 710.4MHz). There's a notable gap between 604.8 and 710.4 to avoid the particularly unstable bpll0 settings. Everyone's phone seems to be able to handle 710, though. Everyone should be able to safely scale up and down through these frequencies.
I've added every frequency step between 710.4MHz and 864MHz in this one, skipping over the unstable frequencies between 604.8MHz and 710.4MHz. On my own phone, I started getting really odd performance issues at 806.4MHz, and it insta-crashed at 844.8MHz. It's worth noting that all frequencies above 768 have an additional power collapse frequency to step through -- I noticed some *average* performance decreases, even though the fastest linpack runs were still faster than at 768MHz.
HOW TO USE
If you're just wanting to run the kernel and enable overclocking, do the following:
- Install SetCPU, if you haven't already. It's available here on XDA for free and for $0.99 on the Market.
- In SetCPU, choose the "HTC Hero/Tattoo [MSM7k Turbo]" option from the device selection menu. The CPU will happily ignore you, but setting it to this means that you won't enter a reboot loop after patching when SetCPU starts and overclocks your CPU entirely too much.
- Make sure the "Set on Boot" option is unchecked, until you're absolutely certain that the settings you've got won't freeze your phone. Also, turn off profiles.
- Flash the latest kernel-overclock-update-v*.zip below, using your favorite method, and boot your phone. Note that this kernel update will not overclock your phone until SetCPU tells it to -- the default policy is 245.76MHz min, 528MHz max, ondemand.
- Start SetCPU, hit menu, and go to device selection. This time, select "Autodetect Settings". Make sure that the FIRST thing you do after device selection is move the max slider down to 528, so your phone doesn't insta-lock on you when SetCPU applies settings.
- Change the governor to "performance" (which means it will always use the highest frequency in the range), and start incrementing the max up from 528MHz, one step at a time, releasing your finger each step (SetCPU applies the change when you let go of the slider), until your phone freezes.
- Remember the bit about not checking the "Set at Boot" option? This is why. Reboot your phone (this will probably involve pulling the battery, if the phone didn't reboot on its own), and start SetCPU again. SetCPU very nicely shows you the last settings you saved, but does not apply them, which is nice because those settings will lock your phone. Lower the max setting to something that won't lock your phone, put the governor back to "ondemand", and set up profiles how you like.
If you would like to add this kernel to your ROM, do the following:
- Create a boot.img for your rom, using the "zImage" file in the latest kernel-overclock-zimage-v*.zip below. You'll likely need mkbootimg for this. If you're making your own ROMs, you should already know everything needed for this except perhaps that you need to use the "--base 0x11200000" option.
- Make sure your ROM places the wlan.ko file from the same zipfile at "/system/lib/modules/wlan.ko".
If you'd like to apply this patch and compile the kernel for yourself, do the following:
- Download and extract the latest Eris kernel source. This patch is applied against the source distributed as "desirec_2.6.29_8a03cb9a.tar.bz2". Google is your friend for finding it.
- Install the Android NDK, if you haven't already. I recommend version r3. Make sure that "build/prebuilt/linux-x86/arm-eabi-4.4.0/bin" under the top-level NDK directory is in your PATH, or the kernel build won't be able to find your compilers.
- In the top-level directory of the kernel source, run "make desirec_defconfig". This will generate the .config file used to configure the kernel.
- Download the latest "kernel-overclock-v*.patch.txt" file below, to the top-level kernel source directory. (It actually doesn't matter where you download it, just be sure to specify the correct path to it in the command below.)
- In the top-level kernel source directory, run "patch -p1 < kernel-overclock-v*.patch.txt". (I assume here that you have the "patch" utility. If not, go get it.)
- Still in the top-level kernel source directory, run "make". When all is said and done, you'll have the compiled kernel at "arch/arm/boot/zImage".
- Get the wlan.ko driver source. Easiest way is to install git and run "git clone git://android.git.kernel.org/platform/system/wlan/ti.git" in the directory you'd like to download it to.
- Change to the sta_dk_4_0_4_32 directory under the wlan.ko source.
- Set the KERNEL_DIR environment variable to the path to your top-level kernel source from above, and run "make". When all is said and done, the wlan.ko module will be in the same directory.
V1 RELEASE FILES:
eris21-overclock-v1.patch.txt - patch for the kernel source code. To apply, untar the kernel source, run "make desirec_defconfig", then apply the patch (usually "patch -p1 < eris21-overclock.patch.txt"). Modify how you like and build.
kernel-overclock-zimage-v1.zip - zip containing the the kernel itself and the wlan.ko module, for addition to other ROMs.
V2 RELEASE FILES
eris21-overclock-v2.patch.txt - patch for the kernel source code. To apply, untar the kernel source, run "make desirec_defconfig", then apply the patch (usually "patch -p1 < eris21-overclock.patch.txt"). Modify how you like and build.
kernel-overclock-zimage-v2.zip - non-flashable zip containing the the kernel itself and wlan.ko module, for addition to other ROMs.
V3 RELEASE FILES
eris21-overclock-v3.patch.txt - patch for the kernel source code. To apply, untar the kernel source, run "make desirec_defconfig", then apply the patch (usually "patch -p1 < eris21-overclock.patch.txt"). Modify how you like and build.
kernel-overclock-update-v3.zip - flashable update.zip to install boot.img containing the built OC kernel and corresponding wifi module.
kernel-overclock-zimage-v3.zip - non-flashable zip containing the the kernel itself and wlan.ko module, for addition to other ROMs.
NOTES ON SETCPU
SetCPU doesn't actually set parameters until you make a change, and it will default to min/max at 19.2/864, which is clearly going to crash on every Eris we've tried. When you flash this, be sure to do the following, or it's your own darn fault if you get stuck in a reboot loop!
- Clear out your setcpu settings before you flash. This means deleting the file /data/data/com.mhuang.overclocking/shared_prefs/setcpu.xml .
- Select "Autodetect" on the device selection screen
- Make sure that SetCPU is not set to start at boot, until you know you've found settings that won't freeze your phone on boot.
- Make sure that the first thing you set is to move the max down to a value you know is stable. If it's your first time, set it to 528 and increment up from there.
- The "performance" governor is like "always use the highest frequency of the range". It's useful for testing.