scePowerSetClockFrequency

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
SilverSpring
Posts: 110
Joined: Tue Feb 27, 2007 9:43 pm
Contact:

scePowerSetClockFrequency

Post by SilverSpring »

In psppower.h, prototype is this:

/**
* Set Clock Frequencies
*
* NOTE: Please use scePowerSetBusClockFrequency and
* scePowerSetCpuClockFrequency instead of this function
* for clock <= 222 and bus <= 111.
*
* @param cpufreq - cpu frequency, valid from 1-333
* @param ramfreq - ram frequency, valid from 1-333
* @param busfreq - bus frequency, valid from 1-166
*/
int scePowerSetClockFrequency(int cpufreq, int ramfreq, int busfreq);

I think should be:

/**
* Set Clock Frequencies
*
* @param pllfreq - pll frequency, valid from 19-333
* @param cpufreq - cpu frequency, valid from 1-333
* @param busfreq - bus frequency, valid from 1-167
*
* and:
*
* cpufreq <= pllfreq
* busfreq*2 <= pllfreq
*
*/
int scePowerSetClockFrequency(int pllfreq, int cpufreq, int busfreq);
SilverSpring
Posts: 110
Joined: Tue Feb 27, 2007 9:43 pm
Contact:

Post by SilverSpring »

Just to confirm:

scePowerGetPllClockFrequencyInt()
scePowerGetCpuClockFrequencyInt()
scePowerGetBusClockFrequencyInt()

does in fact return the 1st, 2nd, & 3rd arguments of

scePowerSetClockFrequency(pllfreq, cpufreq, busfreq);


eg.

setting scePowerSetClockFrequency(333, 266, 111);

then,

scePowerGetPllClockFrequencyInt() returned 333
scePowerGetCpuClockFrequencyInt() returned 265
scePowerGetBusClockFrequencyInt() returned 110

Thus the prototype should be changed accordingly, as per above post.
jimparis
Posts: 1145
Joined: Fri Jun 10, 2005 4:21 am
Location: Boston

Post by jimparis »

I applied the changes manually, thanks.
In the future a patch (from "svn diff") is preferred.
User avatar
Saotome
Posts: 182
Joined: Sat Apr 03, 2004 3:45 am

Post by Saotome »

does this mean that this:

Code: Select all

* NOTE&#58; Please use scePowerSetBusClockFrequency and 
* scePowerSetCpuClockFrequency instead of this function 
* for clock <= 222 and bus <= 111.
is also not valid anymore? (I guess this was just assumed because the wrong parameters didn't bring the expected results (?))

EDIT: anyway... sorry if this sounds stupid, but what's the "pll frequency" (what does it do)?
infj
SilverSpring
Posts: 110
Joined: Tue Feb 27, 2007 9:43 pm
Contact:

Post by SilverSpring »

The pllfreq is what the cpu & bus freq is derived from. Its based on a ratio of x/511 of the pllfreq. Thats why even trying to set a definite freq eg. scePowerSetClockFrequency(333, 266, 111), cpu & bus wont return that exact frequency.

cpufreq will actually return (approx) 265.89 (which is 408/511 times pllfreq)
busfreq*2 will actually return (appox) 221.57 (which is 340/511 times pllfreq)

The ratio is stored 0xBC200000 for cpu & 0xBC200004 for bus (numerator is 1st 9 bits of upper halfword, denominator is 1st 9 bits of lower halfword).

You can get the ratio's with these:

// Get cpufreq ratio
int sceSysreg_driver_44704E1D(int *numerator, int *denominator);

// get busfreq ratio
int sceSysreg_driver_377F035F(int *numerator, int *denominator);

or set ratio:

// 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);

// set busfreq ratio
int sceSysreg_driver_584AD989(int numerator, int denominator);

or set/get freq by float value:

// Set cpufreq by float
// Will set to nearest granuality
// eg. sceSysreg_drver_AB3185FD(200.0) will only give 199.84 (460/511 = 90.02% of default pllfreq (222))
int sceSysreg_drver_AB3185FD(float cpufreq);

// Get cpufreq
float sceSysreg_driver_0EA487FA(void);

// set busfreq
int sceSysreg_driver_136E8F5A(float busfreq);

// get busfreq
float sceSysreg_driver_F4811E00(void);


Thats about all I know....
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

i knew it , i knew it ! thanx for your confirmation XD
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

It seems, from some quick testing, that the media engine cpu frequency is equal to the pll frequency.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

crazyc wrote:It seems, from some quick testing, that the media engine cpu frequency is equal to the pll frequency.
what do you mean ? that me cpu frequency is always 1.0 * pllfreq ?
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

hlide wrote:
crazyc wrote:It seems, from some quick testing, that the media engine cpu frequency is equal to the pll frequency.
what do you mean ? that me cpu frequency is always 1.0 * pllfreq ?
Or maybe the ME num/den regs haven't been located yet. I would imagine the PSP kernel would simply set the ME and CPU to 1.0 and the BUS to 0.5. I'm probably complete wrong :), but it seems like the simplest thing to do.
User avatar
dot_blank
Posts: 498
Joined: Wed Sep 28, 2005 8:47 am
Location: Brasil

Post by dot_blank »

i am so glad this is finally confirmed :) great job SS
10011011 00101010 11010111 10001001 10111010
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

J.F. wrote: Or maybe the ME num/den regs haven't been located yet. I would imagine the PSP kernel would simply set the ME and CPU to 1.0 and the BUS to 0.5. I'm probably complete wrong :), but it seems like the simplest thing to do.
Some more testing shows that the media engine can set it's own frequency using the same rules as above, or so it would seem. When I set 0xbc200000 on the me to 0x00ff01ff or a ratio of 255/511 and set the me to the same, the me goes a lot faster. In fact when I set the pll to 222 and the me to a ratio of .5 the me is at the same clock as the sc when it is set to 191 or 86% of the PLL frequency. The me actually runs at ~50% of pllfreq at a ratio of 55/511.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

how do you measure the difference on SC and ME processors ? because I don't see any good way to do so. you'd probably need to let SC and ME processors to read their own COP0 Count register, preferrably without any interrupts.

SC processor side :

Code: Select all

int i, j;
*_sc_count = 1;
*_me_count = 0;
me_start&#40;&#41;; // launch ME code
*_sc_count = 0;
j = _mfc0&#40;COP0_Count&#41;;
do &#123; i = _mfc0&#40;COP0_Count&#41; - j; &#125; while &#40;&#40;_me_count != 0&#41; || i > 8192&#41;;
*_sc_count = i;

ME processor side :

Code: Select all

int i, j;
while &#40;*_sc_count&#41;; // wait for SC synch
j = _mfc0&#40;COP0_Count&#41;;
do &#123; i = _mfc0&#40;COP0_Count&#41; - j; &#125; while &#40;&#40;_sc_count != 0&#41; || i > 8192&#41;;
*_me_count = i;
_me_count and _sc_count are volatile non cached addresses to be readable for both processors.

ME code would wait until SC synchronizes and start to count cycles. So you should get _sc_count ~= _me_count when they use the same PLL, CPU and BUS frequencies. But you seem to tell us we would rather get something like _sc_count ~= _me_count/2 instead. Is that so ?

if 8192 is too small, just increase it.

NOTE: you could also use the ME/SC mutex to synch them.
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

crazyc wrote:
J.F. wrote: Or maybe the ME num/den regs haven't been located yet. I would imagine the PSP kernel would simply set the ME and CPU to 1.0 and the BUS to 0.5. I'm probably complete wrong :), but it seems like the simplest thing to do.
Some more testing shows that the media engine can set it's own frequency using the same rules as above, or so it would seem. When I set 0xbc200000 on the me to 0x00ff01ff or a ratio of 255/511 and set the me to the same, the me goes a lot faster. In fact when I set the pll to 222 and the me to a ratio of .5 the me is at the same clock as the sc when it is set to 191 or 86% of the PLL frequency. The me actually runs at ~50% of pllfreq at a ratio of 55/511.
Sounds like maybe the ME has a different restriction on the divisor. Maybe it only uses 8bits instead of 9, so 0x00ff01ff is REALLY 255/255, not 255/511. That would account for the speed difference you think you saw.
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

J.F. wrote: Sounds like maybe the ME has a different restriction on the divisor. Maybe it only uses 8bits instead of 9, so 0x00ff01ff is REALLY 255/255, not 255/511. That would account for the speed difference you think you saw.
The default is 0x01ff01ff and then the me clock is the equal to pllfreq. Also, when I use 1/9 (0x00010009) instead of 55/511 (0x003701ff) the me still runs at ~50% pllfreq.
how do you measure the difference on SC and ME processors ? because I don't see any good way to do so. you'd probably need to let SC and ME processors to read their own COP0 Count register, preferrably without any interrupts.
That's what I did. Added the mutex per your suggestion.

Code: Select all

#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <psppower.h>
#include <stdlib.h>
#include <string.h>

PSP_MODULE_INFO&#40;"me_clock_test", 0x1000, 1, 1&#41;;
PSP_MAIN_THREAD_ATTR&#40;0&#41;;

#define set_count&#40;val&#41; __asm__ &#40;"mtc0 %0, $9\n"&#58;&#58;"r"&#40;val&#41;&#41;
#define read_count&#40;val&#41; __asm__ volatile &#40;"mfc0 %0, $9\n"&#58;"=r"&#40;val&#41;&#41;

#define sysreg_lock *&#40;&#40;unsigned int volatile *&#41;0xbc100048&#41;
#define try_lock&#40;cpu&#41; &#40;&#40;&#40;sysreg_lock = &#40;cpu+1&#41;&#41; & 3&#41; == &#40;cpu+1&#41;&#41;
#define free_lock&#40;&#41; &#40;sysreg_lock = 0&#41;

void me_run&#40;void&#41;;
void me_end&#40;void&#41;;

int main&#40;int argc, char *argv&#91;&#93;&#41;
&#123;
	SceCtrlData ctl;
	unsigned int count, me_count;
	int status;

	pspDebugScreenInit&#40;&#41;;

	sceCtrlSetSamplingCycle&#40;0&#41;;
	sceCtrlSetSamplingMode&#40;PSP_CTRL_MODE_DIGITAL&#41;;

	memcpy&#40;&#40;void *&#41;0xbfc00040, me_run, &#40;int&#41;&#40;me_end - me_run&#41;&#41;;
	sceKernelDcacheWritebackAll&#40;&#41;;
	scePowerSetClockFrequency&#40;222, 111, 111&#41;;

	try_lock&#40;0&#41;;

	sceSysregMeResetEnable&#40;&#41;;
	sceSysregMeBusClockEnable&#40;&#41;;
	sceSysregMeResetDisable&#40;&#41;;
	sceSysregVmeResetDisable&#40;&#41;;
	status = pspSdkDisableInterrupts&#40;&#41;;
	free_lock&#40;&#41;;
	__asm__&#40;"sync\n"&#41;;
	set_count&#40;0&#41;;
	pspSdkEnableInterrupts&#40;status&#41;;
	
	while&#40;1&#41;
	&#123;
		pspDebugScreenSetXY&#40;0, 1&#41;;
		sceKernelDcacheWritebackInvalidateAll&#40;&#41;;
		read_count&#40;count&#41;;
		me_count = _lw&#40;0xbfc00600&#41;;
		pspDebugScreenPrintf&#40;"%08x %08x %f\n", count, me_count, &#40;float&#41;count/&#40;float&#41;me_count&#41;;
		sceCtrlReadBufferPositive&#40;&ctl, 1&#41;;
		if&#40;ctl.Buttons & PSP_CTRL_HOME&#41;
		&#123;
			sceKernelExitGame&#40;&#41;;
		&#125;

		sceDisplayWaitVblankStart&#40;&#41;;
	&#125;
	sceSysregMeBusClockDisable&#40;&#41;;
	return 0;
&#125;

Code: Select all

	.set noreorder

	.global me_run
	.global me_end

	.ent me_run

me_run&#58;
	li $2, 0xbc100000
	li $3, 7
	sw $3, 80&#40;$2&#41;
	
1&#58;
	lw $3, 72&#40;$2&#41;
	bne $3, $0, 1b
	nop

	mtc0 $0, $9

	li $2, 0xbc200000
	li $3, 0x00010009
	sw $3, 0&#40;$2&#41;
	li $2, 0xbfc00000
0&#58;
	mfc0 $3, $9
	b 0b
	sw $3, 0x600&#40;$2&#41;
me_end&#58;

	.end me_run
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

huh, beware that an access to memory switchs CPU frequency to BUS frequency temporary so you should avoid having a different code when running on SC and ME processors (not speaking about miss cache too).

So you should really have the same code running a certain time as I showed above without any call to external functions for instance.

EDIT:

i read somewhere that instructions like lb/lbu/lh/lhu/lw/lwl/lwr/sb/sh/sw/swl/swr runs at bus frequency and not at cpu frequency. So if you have 63 cycles for a lw instruction (miss-cache), it doesn't mean 63 cycles at 333 MHz but rather at 166 MHz.
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

hlide wrote:huh, beware that an access to memory switchs CPU frequency to BUS frequency temporary so you should avoid having a different code when running on SC and ME processors (not speaking about miss cache too).

So you should really have the same code running a certain time as I showed above without any call to external functions for instance.

EDIT:

i read somewhere that instructions like lb/lbu/lh/lhu/lw/lwl/lwr/sb/sh/sw/swl/swr runs at bus frequency and not at cpu frequency. So if you have 63 cycles for a lw instruction (miss-cache), it doesn't mean 63 cycles at 333 MHz but rather at 166 MHz.
This may be part of the problem, but with this code, if I set cpufreq==pllfreq and the me clock multiplier to 1, both cpus run at very nearly the same rate.
sakya
Posts: 190
Joined: Fri Apr 28, 2006 5:48 pm
Contact:

Post by sakya »

Hi! :)

I'm not able to set the bus clock to 14Mhz (or anithing less than 37Mhz != 9Mhz).
Can someone help me?
Reading here and also here http://lan.st/archive/index.php/t-854.html that's what I tried:

If I do:

Code: Select all

scePowerSetClockFrequency&#40;222, 222, 111&#41;;
Using these functions

Code: Select all

// get pllfreq &#40;default is 222Mhz&#41;
float sceSysreg_driver_B21B6CBF&#40;void&#41;;

// get index value &#40;default is 3&#41;
int sceSysreg_driver_B4560C45&#40;void&#41;;

// set pllfreq based on table
// index is the index for the float table &#40;0-5&#41;
int sceSysreg_driver_DCA57573&#40;int index&#41;;

// get basefreq &#40;hardcoded as 37Mhz in prx&#41;
float sceSysreg_driver_53A6838B&#40;void&#41;;

// Get cpufreq ratio
int sceSysreg_driver_44704E1D&#40;int *numerator, int *denominator&#41;;

// get busfreq ratio
int sceSysreg_driver_377F035F&#40;int *numerator, int *denominator&#41;; 

// Set cpufreq by ratio
// both values have to between 1-511
// obviously numerator cant be greater than denominator
// eg. sceSysreg_driver_5664F8B5&#40;511, 511&#41; gives 100% of pllfreq
int sceSysreg_driver_5664F8B5&#40;int numerator, int denominator&#41;;

// set busfreq ratio
int sceSysreg_driver_584AD989&#40;int numerator, int denominator&#41;; 
I get this info:

Code: Select all

CPU      &#58; 222       
CPU RATIO&#58; 511/511
BUS      &#58; 111     
BUS RATIO&#58; 511/511
PLL      &#58; 222      
PLL index&#58; 3
basefreq &#58; 37 
As I understand there's this list of values:

Code: Select all

const float table&#91;6&#93; =
&#123;
0x3DE38E39, // == 0.11111111
0x3EE38E39, // == 0.44444445
0x3F124925, // == 0.57142860
0x3F2AAAAB, // == 0.66666669
0x3F4CCCCD, // == 0.80000001
0x3F800000 // == 1
&#125;;
That represent the PLL index.
PLL clock is calculated this way:

Code: Select all

PLL = 37*9*table&#91;PLL_index&#93;
PLL = 37*9*0.66666669 --> 222
While CPU clock is calculated from PLL amd a ratio:

Code: Select all

CPU = PLL * &#40;numerator/denominator&#41;
CPU = 222 * &#40;511/511&#41; --> 222
The BUS is:

Code: Select all

BUS = PLL/2 * &#40;numerator/denominator&#41;
BUS = 222/2 * &#40;511/511&#41; --> 111
The strange thing is that if I try:

Code: Select all

scePowerSetClockFrequency&#40;29, 29, 14&#41;;
I obtain this info:

Code: Select all

CPU      &#58; 28        = 74*&#40;200/511&#41;
CPU RATIO&#58; 200/511   
BUS      &#58; 37        = 74/2*&#40;511/511&#41;
BUS RATIO&#58; 511/511
PLL      &#58; 74        = 37*9*0,225225225 &#40;?&#41;
PLL index&#58; 9
basefreq &#58; 37
What's that PLL index = 9? Shouldn't it be from 0 to 5?
Also changing numerator and denominator with

Code: Select all

sceSysreg_driver_584AD989&#40;280, 511&#41;;
BUS = 74/2 * &#40;280/511&#41; --> 20
doesen't have any affect.

Another strange thing IMHO:
If I do

Code: Select all

scePowerSetClockFrequency&#40;29, 29, 14&#41;;
so the PLL index is equal to 9.
Then execute:

Code: Select all

	sceSysreg_driver_DCA57573&#40;8&#41;;
	scePowerSetClockFrequency&#40;29, 29, 14&#41;;
This is the info I get (BUS 9 and CPU 18):

Code: Select all

CPU      &#58; 18
CPU RATIO&#58; 511/511
BUS      &#58; 9
BUS RATIO&#58; 511/511
PLL      &#58; 18
PLL index&#58; 8
basefreq &#58; 37
I'm a little confused. ;)

Many thanks :)
Ciaooo
Sakya
SilverSpring
Posts: 110
Joined: Tue Feb 27, 2007 9:43 pm
Contact:

Post by SilverSpring »

Im pretty sure the reason why you cannot go lower than 37MHz is because the PLL basefreq is 37MHz, so that is as low as you can go. Trying to go lower will cause funny effects.
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

sakya wrote: What's that PLL index = 9? Shouldn't it be from 0 to 5?
Actually the list is longer then 5. Here's what I came up with after a little testing. I got it to work at 18.6Mhz but only with a light load. For everyone, don't try to set pllfreq to anything higher then 333Mhz unless you can handle wrecking it. I set it to 370 once but only by accident.

Code: Select all

pll fractions  0xbc100068, to set OR index with 0x80
0 1/9 &#40;.111&#41;
1 4/9 &#40;.444&#41;
2 5/9 &#40;.571&#41;
3 6/9 &#40;.667&#41;
4 7/9 &#40;.8&#41;
5 9/9 &#40;1&#41;
6 0?
7 0?
8 1/18 &#40;.056&#41;
9 2/9  &#40;.222&#41;
a 5/18 &#40;.286&#41;
b 3/9  &#40;.333&#41;
c 7/18 &#40;.4&#41;
d 9/18 &#40;.5&#41;
e 0?
f 0?

pll multiplers  0xbc1000fc 8&#58;16
9
11
13
15

base clock = 37
		     9	   11	   13	   15
0.056		18.6	&#40;multipler doesn't matter&#41;
0.111		37.0	&#40;"&#41;
0.222		74.0	90.4	107	123
0.286		95.2	116	138	159
0.333		111	135	160	184
0.400		133	163	192	222
0.444		148	181	214	246
0.500		167	204	241	278
0.571		190	232	275	317
0.667		222	271	321	370
0.800		266	326	385	444
1.000		333	407	481	555
Post Reply