SilverSpring
03-15-2007, 05:34 PM
I've been having a look at the possibility to overclock the cpu via software.
I had a brief attempt but I got stuck at trying to overclock pllfreq.
Im pretty sure that if you overclock pllfreq, cpufreq will be overclocked.
Since I dont have much time, Im posting everything I found in the hope that someone with more time & energy may continue to work on it. Im stopping for now.
Here's what I found out so far:
(Note: a lot of this is based on guesswork, so it may not be entirely accurate or correct)
The cpu & bus frequency is dependant on the PLL frequency (ie. they're derived from the pllfreq).
You can only change the cpu & bus freq based on a percentage of the PLL frequency.
The ratio (percentage) is stored at 0xBC200000 for cpu & 0xBC200004 for bus. It uses the upper halfword for the numerator and the lower halfword for the denominator, but only uses 9 bits for each.
So the fraction is stored like this:
xxxxxxxAAAAAAAAA xxxxxxxBBBBBBBBB
A/B then becomes the fraction. Since the denominator can only be a maximum of 511 the best granuality is only 1/511 = approx 0.2%.
You cant have any more accuracy than that.
So having a default PLLfreq of 222Mhz, using 511/511 = 100% gives a cpufreq of 222 (ie. writing 0x01FF01FF to 0xBC200000). The next lower freq will be pllfreq * 510/511 = 221.57 Mhz (99.80%) etc etc. Even trying to set a definite cpufreq will be rounded to the nearest granuality (eg. setting the cpufreq at 200.0 will actually give 199.84Mhz, which is 460/511 = 90.02% of 222).
There are several ways to set the cpufreq:
// Set cpufreq by float
// Will set to nearest granuality
// eg. sceSysreg_drver_AB3185FD(200.0) will only give 199.84
// setting cpufreq higher than current pllfreq will default back to pllfreq
int sceSysreg_drver_AB3185FD(float cpufreq);
// Get cpufreq
float sceSysreg_driver_0EA487FA(void);
// Set cpufreq by ratio
// both values have to between 1-511
// obviously numerator cant be greater than denominator
// eg. sceSysreg_driver_5664F8B5(511, 511) gives 100% of pllfreq
int sceSysreg_driver_5664F8B5(int numerator, int denominator);
// Get cpufreq ratio
int sceSysreg_driver_44704E1D(int *numerator, int *denominator);
Respectively for busfreq:
// set busfreq
int sceSysreg_driver_136E8F5A(float busfreq);
// get busfreq
float sceSysreg_driver_F4811E00(void);
// set busfreq ratio
int sceSysreg_driver_584AD989(int numerator, int denominator);
// get busfreq ratio
int sceSysreg_driver_377F035F(int *numerator, int *denominator);
Note the scePowerSet*** etc functions just call the above. Also, what I had previously written about scePowerLimit*** functions, they're only effective for scePower***. They have no bearing on sceSysreg*** functions. So using those limit functions seem quite limited (eg. scePowerLimitScCpuClock(333, 400), or something similar, definitely wont work).
So obviously to overclock the cpu (or bus), pllfreq must be overclocked.
The pllfreq uses a base freq of 37Mhz (times a multiplier to get 222Mhz).
Actually the pllfreq is set like this: pllfreq = (multiplier*basefreq) * table[index].
Multiplier & index is stored at 0xBC1000FC & 0xBC100068 respectively.
The basefreq and table is hardcoded into the prx.
The table consists of 32bit single precision floats.
const float table[6] =
{
0x3DE38E39, // == 0.11111111
0x3EE38E39, // == 0.44444445
0x3F124925, // == 0.57142860
0x3F2AAAAB, // == 0.66666669
0x3F4CCCCD, // == 0.80000001
0x3F800000 // == 1
}
Default values are multiplier=9, basefreq=37, index=3.
So default pllfreq = 9*37 * 0.66666 = 222Mhz.
You can change the pllfreq with this function:
// set pllfreq based on table
// index is the index for the float table (0-5)
int sceSysreg_driver_DCA57573(int index);
// get pllfreq (default is 222Mhz)
float sceSysreg_driver_B21B6CBF(void);
// get basefreq (hardcoded as 37Mhz in prx)
float sceSysreg_driver_53A6838B(void);
// get index value (default is 3)
int sceSysreg_driver_B4560C45(void);
So, to set pllfreq to 333Mhz use sceSysreg_driver_DCA57573(5), which will use table[5]=1, pllfreq=333*1 (note this will then also make cpufreq=333Mhz, provided cpufreq has been set to 100% of pllfreq ie sceSysreg_driver_5664F8B5(511, 511), which I think is the default setting anyway).
Note, you can use sceDdrChangePllClock to do the same thing (eg. sceDdrChangePllClock(5)).
So, some ideas on overclocking pllfreq (these may not work at all, since there might be hardware restrictions):
1) mod the hardcoded table (eg. change table[5]=1 to table[5]=1.1 etc.)
2) mod the hardcoded basefreq (probably wont work, since since basefreq is probably based on actual crystal)
3) mod the multiplier at 0xBC1000FC
Im 99% sure that if pllfreq is overclocked, cpu (& bus) freq will also be overclocked.
As long as cpufreq is set at 100% of pllfreq, it will follow it.
If anyone has more info, please post it here. Hopefully, more people can now work on it.
(Again, note: I only briefly looked at this issue so the info here may not be entirely accurate)
EDIT:
Forgot some NIDs I found for sceSysreg:
0xE8533DCA sceSysregApbTimerClkEnable
0xF6D83AD0 sceSysregApbTimerClkDisable
0xB21B6CBF sceSysregPllGetFrequency
0x53A6838B sceSysregPllGetBaseFrequency
0xBB3623DF sceSysregPllUpdateFrequency
I had a brief attempt but I got stuck at trying to overclock pllfreq.
Im pretty sure that if you overclock pllfreq, cpufreq will be overclocked.
Since I dont have much time, Im posting everything I found in the hope that someone with more time & energy may continue to work on it. Im stopping for now.
Here's what I found out so far:
(Note: a lot of this is based on guesswork, so it may not be entirely accurate or correct)
The cpu & bus frequency is dependant on the PLL frequency (ie. they're derived from the pllfreq).
You can only change the cpu & bus freq based on a percentage of the PLL frequency.
The ratio (percentage) is stored at 0xBC200000 for cpu & 0xBC200004 for bus. It uses the upper halfword for the numerator and the lower halfword for the denominator, but only uses 9 bits for each.
So the fraction is stored like this:
xxxxxxxAAAAAAAAA xxxxxxxBBBBBBBBB
A/B then becomes the fraction. Since the denominator can only be a maximum of 511 the best granuality is only 1/511 = approx 0.2%.
You cant have any more accuracy than that.
So having a default PLLfreq of 222Mhz, using 511/511 = 100% gives a cpufreq of 222 (ie. writing 0x01FF01FF to 0xBC200000). The next lower freq will be pllfreq * 510/511 = 221.57 Mhz (99.80%) etc etc. Even trying to set a definite cpufreq will be rounded to the nearest granuality (eg. setting the cpufreq at 200.0 will actually give 199.84Mhz, which is 460/511 = 90.02% of 222).
There are several ways to set the cpufreq:
// Set cpufreq by float
// Will set to nearest granuality
// eg. sceSysreg_drver_AB3185FD(200.0) will only give 199.84
// setting cpufreq higher than current pllfreq will default back to pllfreq
int sceSysreg_drver_AB3185FD(float cpufreq);
// Get cpufreq
float sceSysreg_driver_0EA487FA(void);
// Set cpufreq by ratio
// both values have to between 1-511
// obviously numerator cant be greater than denominator
// eg. sceSysreg_driver_5664F8B5(511, 511) gives 100% of pllfreq
int sceSysreg_driver_5664F8B5(int numerator, int denominator);
// Get cpufreq ratio
int sceSysreg_driver_44704E1D(int *numerator, int *denominator);
Respectively for busfreq:
// set busfreq
int sceSysreg_driver_136E8F5A(float busfreq);
// get busfreq
float sceSysreg_driver_F4811E00(void);
// set busfreq ratio
int sceSysreg_driver_584AD989(int numerator, int denominator);
// get busfreq ratio
int sceSysreg_driver_377F035F(int *numerator, int *denominator);
Note the scePowerSet*** etc functions just call the above. Also, what I had previously written about scePowerLimit*** functions, they're only effective for scePower***. They have no bearing on sceSysreg*** functions. So using those limit functions seem quite limited (eg. scePowerLimitScCpuClock(333, 400), or something similar, definitely wont work).
So obviously to overclock the cpu (or bus), pllfreq must be overclocked.
The pllfreq uses a base freq of 37Mhz (times a multiplier to get 222Mhz).
Actually the pllfreq is set like this: pllfreq = (multiplier*basefreq) * table[index].
Multiplier & index is stored at 0xBC1000FC & 0xBC100068 respectively.
The basefreq and table is hardcoded into the prx.
The table consists of 32bit single precision floats.
const float table[6] =
{
0x3DE38E39, // == 0.11111111
0x3EE38E39, // == 0.44444445
0x3F124925, // == 0.57142860
0x3F2AAAAB, // == 0.66666669
0x3F4CCCCD, // == 0.80000001
0x3F800000 // == 1
}
Default values are multiplier=9, basefreq=37, index=3.
So default pllfreq = 9*37 * 0.66666 = 222Mhz.
You can change the pllfreq with this function:
// set pllfreq based on table
// index is the index for the float table (0-5)
int sceSysreg_driver_DCA57573(int index);
// get pllfreq (default is 222Mhz)
float sceSysreg_driver_B21B6CBF(void);
// get basefreq (hardcoded as 37Mhz in prx)
float sceSysreg_driver_53A6838B(void);
// get index value (default is 3)
int sceSysreg_driver_B4560C45(void);
So, to set pllfreq to 333Mhz use sceSysreg_driver_DCA57573(5), which will use table[5]=1, pllfreq=333*1 (note this will then also make cpufreq=333Mhz, provided cpufreq has been set to 100% of pllfreq ie sceSysreg_driver_5664F8B5(511, 511), which I think is the default setting anyway).
Note, you can use sceDdrChangePllClock to do the same thing (eg. sceDdrChangePllClock(5)).
So, some ideas on overclocking pllfreq (these may not work at all, since there might be hardware restrictions):
1) mod the hardcoded table (eg. change table[5]=1 to table[5]=1.1 etc.)
2) mod the hardcoded basefreq (probably wont work, since since basefreq is probably based on actual crystal)
3) mod the multiplier at 0xBC1000FC
Im 99% sure that if pllfreq is overclocked, cpu (& bus) freq will also be overclocked.
As long as cpufreq is set at 100% of pllfreq, it will follow it.
If anyone has more info, please post it here. Hopefully, more people can now work on it.
(Again, note: I only briefly looked at this issue so the info here may not be entirely accurate)
EDIT:
Forgot some NIDs I found for sceSysreg:
0xE8533DCA sceSysregApbTimerClkEnable
0xF6D83AD0 sceSysregApbTimerClkDisable
0xB21B6CBF sceSysregPllGetFrequency
0x53A6838B sceSysregPllGetBaseFrequency
0xBB3623DF sceSysregPllUpdateFrequency