2823a4c8 |
1 | /* cpuctrl.c for GP2X (CPU/LCD/RAM-Tuner Version 2.0) |
2 | Copyright (C) 2006 god_at_hell |
3 | original CPU-Overclocker (c) by Hermes/PS2Reality |
4 | the gamma-routine was provided by theoddbot |
5 | parts (c) Rlyehs Work |
6 | |
7 | This program is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 2 of the License, or |
10 | (at your option) any later version. |
11 | |
12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with this program; if not, write to the Free Software |
19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
20 | |
21 | */ |
22 | |
23 | |
24 | /****************************************************************************************************************************************/ |
25 | // CPU CONTROL |
26 | /****************************************************************************************************************************************/ |
27 | |
a6c41a38 |
28 | //#include <sys/mman.h> |
2823a4c8 |
29 | #include <math.h> |
30 | #include <stdio.h> |
a6c41a38 |
31 | //#include "gp2xminilib.h" |
2823a4c8 |
32 | |
33 | #define SYS_CLK_FREQ 7372800 |
34 | |
35 | //from minimal library rlyeh |
36 | |
a6c41a38 |
37 | //extern unsigned long gp2x_dev[4]; |
2823a4c8 |
38 | extern unsigned short *gp2x_memregs; |
39 | |
40 | // system registers |
41 | static struct |
42 | { |
43 | unsigned short SYSCLKENREG,SYSCSETREG,FPLLVSETREG,DUALINT920,DUALINT940,DUALCTRL940,DISPCSETREG,MEMTIMEX0; |
44 | unsigned short MEMTIMEX1,MEMREFX,MLC_GAMM_BYPATH,MLC_GAMMA_A,MLC_GAMMA_D,YBNKLVL; |
45 | } |
46 | system_reg; |
47 | |
48 | volatile unsigned short *MEM_REG; |
49 | unsigned MDIV,PDIV,SCALE; |
50 | volatile unsigned *arm940code; |
51 | |
52 | void cpuctrl_init() |
53 | { |
54 | MEM_REG=&gp2x_memregs[0]; |
55 | } |
56 | |
57 | void save_system_regs() |
58 | { |
59 | system_reg.SYSCSETREG=MEM_REG[0x91c>>1]; |
60 | system_reg.FPLLVSETREG=MEM_REG[0x912>>1]; |
61 | system_reg.SYSCLKENREG=MEM_REG[0x904>>1]; |
62 | system_reg.DUALINT920=MEM_REG[0x3B40>>1]; |
63 | system_reg.DUALINT940=MEM_REG[0x3B42>>1]; |
64 | system_reg.DUALCTRL940=MEM_REG[0x3B48>>1]; |
65 | system_reg.DISPCSETREG=MEM_REG[0x924>>1]; |
66 | system_reg.MEMTIMEX0=MEM_REG[0x3802>>1]; |
67 | system_reg.MEMTIMEX1=MEM_REG[0x3804>>1]; |
68 | system_reg.MEMREFX=MEM_REG[0x3808>>1]; |
69 | system_reg.MLC_GAMM_BYPATH=MEM_REG[0x2880>>1]; |
70 | system_reg.MLC_GAMMA_A=MEM_REG[0x295C>>1]; |
71 | system_reg.MLC_GAMMA_D=MEM_REG[0x295E>>1]; |
72 | system_reg.YBNKLVL=MEM_REG[0x283A>>1]; |
73 | } |
74 | |
75 | void load_system_regs() |
76 | { |
77 | MEM_REG[0x91c>>1]=system_reg.SYSCSETREG; |
78 | MEM_REG[0x910>>1]=system_reg.FPLLVSETREG; |
79 | MEM_REG[0x3B40>>1]=system_reg.DUALINT920; |
80 | MEM_REG[0x3B42>>1]=system_reg.DUALINT940; |
81 | MEM_REG[0x3B48>>1]=system_reg.DUALCTRL940; |
82 | MEM_REG[0x904>>1]=system_reg.SYSCLKENREG; |
83 | /* Set UPLLSETVREG to 0x4F02, which gives 80MHz */ |
84 | MEM_REG[0x0914>>1] = 0x4F02; |
85 | /* Wait for clock change to start */ |
86 | while (MEM_REG[0x0902>>1] & 2); |
87 | /* Wait for clock change to be verified */ |
88 | while (MEM_REG[0x0916>>1] != 0x4F02); |
89 | MEM_REG[0x3802>>1]=system_reg.MEMTIMEX0; |
90 | MEM_REG[0x3804>>1]=system_reg.MEMTIMEX1; |
91 | MEM_REG[0x3808>>1]=system_reg.MEMREFX; |
92 | MEM_REG[0x2880>>1]=system_reg.MLC_GAMM_BYPATH; |
93 | MEM_REG[0x295C>>1]=system_reg.MLC_GAMMA_A; |
94 | MEM_REG[0x295E>>1]=system_reg.MLC_GAMMA_D; |
95 | MEM_REG[0x283A>>1]=system_reg.YBNKLVL; |
96 | } |
97 | |
98 | |
99 | void set_FCLK(unsigned MHZ) |
100 | { |
101 | printf ("set CPU-Frequency = %uMHz\r\n",MHZ); |
102 | unsigned v; |
103 | unsigned mdiv,pdiv=3,scale=0; |
104 | MHZ*=1000000; |
105 | mdiv=(MHZ*pdiv)/SYS_CLK_FREQ; |
106 | //printf ("Old value = %04X\r",MEM_REG[0x924>>1]," "); |
107 | //printf ("APLL = %04X\r",MEM_REG[0x91A>>1]," "); |
108 | mdiv=((mdiv-8)<<8) & 0xff00; |
109 | pdiv=((pdiv-2)<<2) & 0xfc; |
110 | scale&=3; |
111 | v=mdiv | pdiv | scale; |
112 | MEM_REG[0x910>>1]=v; |
113 | } |
114 | |
115 | unsigned get_FCLK() |
116 | { |
117 | return MEM_REG[0x910>>1]; |
118 | } |
119 | |
a6c41a38 |
120 | #if 0 |
2823a4c8 |
121 | void set_add_FLCDCLK(int addclock) |
122 | { |
123 | //Set LCD controller to use FPLL |
124 | printf ("...set to FPLL-Clockgen...\r\n"); |
125 | printf ("set Timing-Prescaler = %i\r\n",addclock); |
126 | MEM_REG[0x924>>1]= 0x5A00 + ((addclock)<<8); |
127 | //If you change the initial timing, don't forget to shift your intervall-borders in "cpu_speed.c" |
128 | } |
129 | |
130 | void set_add_ULCDCLK(int addclock) |
131 | { |
132 | //Set LCD controller to use UPLL |
133 | printf ("...set to UPLL-Clockgen...\r\n"); |
134 | printf ("set Timing-Prescaler = %i\r\n",addclock); |
135 | MEM_REG[0x0924>>1] = 0x8900 + ((addclock)<<8); |
136 | //If you change the initial timing, don't forget to shift your intervall-borders in "cpu_speed.c" |
137 | } |
138 | |
139 | unsigned get_LCDClk() |
140 | { |
141 | if (MEM_REG[0x0924>>1] < 0x7A01) return((MEM_REG[0x0924>>1] - 0x5A00)>>8); |
142 | else return((MEM_REG[0x0924>>1] - 0x8900)>>8); |
143 | } |
144 | |
145 | char get_Clkgen() |
146 | { |
147 | if (MEM_REG[0x0924>>1] < 0x7A01) return(0); |
148 | else return(1); |
149 | } |
150 | |
151 | unsigned get_freq_UCLK() |
152 | { |
153 | unsigned i; |
154 | unsigned reg,mdiv,pdiv,scale; |
155 | i = MEM_REG[0x900>>1]; |
156 | i = ((i >> 7) & 1) ; |
157 | if(i) return 0; |
158 | reg=MEM_REG[0x916>>1]; |
159 | mdiv = ((reg & 0xff00) >> 8) + 8; |
160 | pdiv = ((reg & 0xfc) >> 2) + 2; |
161 | scale = reg & 3; |
162 | return ((SYS_CLK_FREQ * mdiv) / (pdiv << scale)); |
163 | } |
164 | |
165 | unsigned get_freq_ACLK() |
166 | { |
167 | unsigned i; |
168 | unsigned reg,mdiv,pdiv,scale; |
169 | i = MEM_REG[0x900>>1]; |
170 | i = ((i >> 8) & 1) ; |
171 | if(i) return 0; |
172 | reg=MEM_REG[0x918>>1]; |
173 | mdiv = ((reg & 0xff00) >> 8) + 8; |
174 | pdiv = ((reg & 0xfc) >> 2) + 2; |
175 | scale = reg & 3; |
176 | return ((SYS_CLK_FREQ * mdiv)/(pdiv << scale)); |
177 | } |
178 | |
179 | unsigned get_freq_920_CLK() |
180 | { |
181 | unsigned i; |
182 | unsigned reg,mdiv,pdiv,scale; |
183 | reg=MEM_REG[0x912>>1]; |
184 | mdiv = ((reg & 0xff00) >> 8) + 8; |
185 | pdiv = ((reg & 0xfc) >> 2) + 2; |
186 | scale = reg & 3; |
187 | MDIV=mdiv; |
188 | PDIV=pdiv; |
189 | SCALE=scale; |
190 | i = (MEM_REG[0x91c>>1] & 7)+1; |
191 | return ((SYS_CLK_FREQ * mdiv)/(pdiv << scale))/i; |
192 | } |
193 | |
194 | unsigned get_freq_940_CLK() |
195 | { |
196 | unsigned i; |
197 | unsigned reg,mdiv,pdiv,scale; |
198 | reg=MEM_REG[0x912>>1]; |
199 | mdiv = ((reg & 0xff00) >> 8) + 8; |
200 | pdiv = ((reg & 0xfc) >> 2) + 2; |
201 | scale = reg & 3; |
202 | i = ((MEM_REG[0x91c>>1]>>3) & 7)+1; |
203 | return ((SYS_CLK_FREQ * mdiv) / (pdiv << scale))/i; |
204 | } |
205 | |
206 | unsigned get_freq_DCLK() |
207 | { |
208 | unsigned i; |
209 | unsigned reg,mdiv,pdiv,scale; |
210 | reg=MEM_REG[0x912>>1]; |
211 | mdiv = ((reg & 0xff00) >> 8) + 8; |
212 | pdiv = ((reg & 0xfc) >> 2) + 2; |
213 | scale = reg & 3; |
214 | i = ((MEM_REG[0x91c>>1]>>6) & 7)+1; |
215 | return ((SYS_CLK_FREQ * mdiv) / (pdiv << scale))/i; |
216 | } |
217 | |
218 | void set_920_Div(unsigned short div) |
219 | { |
220 | printf ("set divider for CPU-Clock = %u\r\n",div+1); |
221 | unsigned short v; |
222 | v = MEM_REG[0x91c>>1] & (~0x3); |
223 | MEM_REG[0x91c>>1] = (div & 0x7) | v; |
224 | } |
225 | |
226 | unsigned short get_920_Div() |
227 | { |
228 | return (MEM_REG[0x91c>>1] & 0x7); |
229 | } |
230 | |
231 | void set_940_Div(unsigned short div) |
232 | { |
233 | unsigned short v; |
234 | v = (unsigned short)( MEM_REG[0x91c>>1] & (~(0x7 << 3))); |
235 | MEM_REG[0x91c>>1] = ((div & 0x7) << 3) | v; |
236 | } |
237 | |
238 | unsigned short get_940_Div() |
239 | { |
240 | return ((MEM_REG[0x91c>>1] >> 3) & 0x7); |
241 | } |
242 | |
243 | void set_DCLK_Div( unsigned short div ) |
244 | { |
245 | printf ("set divider for RAM-Clock = %u\r\n",div+1); |
246 | unsigned short v; |
247 | v = (unsigned short)( MEM_REG[0x91c>>1] & (~(0x7 << 6))); |
248 | MEM_REG[0x91c>>1] = ((div & 0x7) << 6) | v; |
249 | } |
250 | |
251 | unsigned short get_DCLK_Div() |
252 | { |
253 | return ((MEM_REG[0x91c>>1] >> 6) & 0x7); |
254 | } |
255 | |
256 | unsigned short Disable_Int_920() |
257 | { |
258 | unsigned short ret; |
259 | ret=MEM_REG[0x3B40>>1]; |
260 | MEM_REG[0x3B40>>1]=0; |
261 | MEM_REG[0x3B44>>1]=0xffff; |
262 | return ret; |
263 | } |
264 | |
265 | unsigned short Disable_Int_940() |
266 | { |
267 | unsigned short ret; |
268 | ret=MEM_REG[0x3B42>>1]; |
269 | MEM_REG[0x3B42>>1]=0; |
270 | MEM_REG[0x3B46>>1]=0xffff; |
271 | return ret; |
272 | } |
273 | |
274 | unsigned get_state940() |
275 | { |
276 | return MEM_REG[0x904>>1]; |
277 | } |
278 | |
279 | |
280 | void Enable_Int_920(unsigned short flag) |
281 | { |
282 | MEM_REG[0x3B40>>1]=flag; |
283 | } |
284 | |
285 | void Enable_Int_940(unsigned short flag) |
286 | { |
287 | MEM_REG[0x3B42>>1]=flag; |
288 | } |
289 | |
290 | void Disable_940() |
291 | { |
292 | Disable_Int_940(); |
293 | MEM_REG[0x3B48>>1]|= (1 << 7); |
294 | MEM_REG[0x904>>1]&=0xfffe; |
295 | } |
296 | |
297 | void Load_940_code(unsigned *code,int size) |
298 | { |
299 | unsigned *cp; |
300 | int i; |
301 | arm940code=(unsigned short *)mmap(0, 0x100000, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], 0x03000000); |
302 | Disable_940(); |
303 | cp=(unsigned *) code; |
304 | for (i = 0; i < size/4; i ++) |
305 | { |
306 | arm940code[i] = cp[i]; |
307 | } |
308 | for (i = 0; i < 64; i ++) |
309 | { |
310 | arm940code[0x3FC0+i] = 0; |
311 | } |
312 | MEM_REG[0x3B48>>1]=(MEM_REG[0x3B48>>1] & 0xFF00) | 0x03; // allow 940 |
313 | } |
314 | |
315 | void clock_940_off() |
316 | { |
317 | MEM_REG[0x904>>1]&=0xfffe; |
318 | } |
319 | |
320 | void clock_940_on() |
321 | { |
322 | MEM_REG[0x904>>1]|=1; |
323 | } |
a6c41a38 |
324 | #endif |
2823a4c8 |
325 | |
326 | |
327 | //-------------- |
328 | //Memory Timings |
329 | //-------------- |
330 | |
331 | //get |
332 | |
333 | unsigned get_CAS() |
334 | { |
335 | return ((MEM_REG[0x3804>>1] >> 12) & 0x1); |
336 | } |
337 | |
338 | unsigned get_tRC() |
339 | { |
340 | return ((MEM_REG[0x3804>>1] >> 8) & 0xF); |
341 | } |
342 | |
343 | unsigned get_tRAS() |
344 | { |
345 | return ((MEM_REG[0x3804>>1] >> 4) & 0xF); |
346 | } |
347 | |
348 | unsigned get_tWR() |
349 | { |
350 | return (MEM_REG[0x3804>>1] & 0xF); |
351 | } |
352 | |
353 | unsigned get_tMRD() |
354 | { |
355 | return ((MEM_REG[0x3802>>1] >> 12) & 0xF); |
356 | } |
357 | |
358 | unsigned get_tRFC() |
359 | { |
360 | return ((MEM_REG[0x3802>>1] >> 8) & 0xF); |
361 | } |
362 | |
363 | unsigned get_tRP() |
364 | { |
365 | return ((MEM_REG[0x3802>>1] >> 4) & 0xF); |
366 | } |
367 | |
368 | unsigned get_tRCD() |
369 | { |
370 | return (MEM_REG[0x3802>>1] & 0xF); |
371 | } |
372 | |
373 | unsigned get_REFPERD() |
374 | { |
375 | return MEM_REG[0x3808>>1]; |
376 | } |
377 | |
378 | |
379 | //set |
380 | |
381 | void set_CAS(unsigned short timing) |
382 | { |
383 | printf ("set CAS = %u\r\n",timing+2); |
384 | unsigned short v; |
385 | v = (unsigned short)(MEM_REG[0x3804>>1] & (~(0x1 << 12))); |
386 | MEM_REG[0x3804>>1] = ((timing & 0x1) << 12) | v; |
387 | } |
388 | |
389 | void set_tRC(unsigned short timing) |
390 | { |
391 | printf ("set tRC = %u\r\n",timing+1); |
392 | unsigned short v; |
393 | v = (unsigned short)(MEM_REG[0x3804>>1] & (~(0xF << 8))); |
394 | MEM_REG[0x3804>>1] = ((timing & 0xF) << 8) | v; |
395 | } |
396 | |
397 | void set_tRAS(unsigned short timing) |
398 | { |
399 | printf ("set tRAS = %u\r\n",timing+1); |
400 | unsigned short v; |
401 | v = (unsigned short)(MEM_REG[0x3804>>1] & (~(0xF << 4))); |
402 | MEM_REG[0x3804>>1] = ((timing & 0xF) << 4) | v; |
403 | } |
404 | |
405 | void set_tWR(unsigned short timing) |
406 | { |
407 | printf ("set tWR = %u\r\n",timing+1); |
408 | unsigned short v; |
409 | v = (unsigned short)(MEM_REG[0x3804>>1] & (~(0xF))); |
410 | MEM_REG[0x3804>>1] = (timing & 0xF) | v; |
411 | } |
412 | |
413 | void set_tMRD(unsigned short timing) |
414 | { |
415 | printf ("set tMRD = %u\r\n",timing+1); |
416 | unsigned short v; |
417 | v = (unsigned short)(MEM_REG[0x3802>>1] & (~(0xF << 12))); |
418 | MEM_REG[0x3802>>1] = ((timing & 0xF) << 12) | v; |
419 | } |
420 | |
421 | void set_tRFC(unsigned short timing) |
422 | { |
423 | printf ("set tRFC = %u\r\n",timing+1); |
424 | unsigned short v; |
425 | v = (unsigned short)(MEM_REG[0x3802>>1] & (~(0xF << 8))); |
426 | MEM_REG[0x3802>>1] = ((timing & 0xF) << 8) | v; |
427 | } |
428 | |
429 | void set_tRP(unsigned short timing) |
430 | { |
431 | printf ("set tRP = %u\r\n",timing+1); |
432 | unsigned short v; |
433 | v = (unsigned short)(MEM_REG[0x3802>>1] & (~(0xF << 4))); |
434 | MEM_REG[0x3802>>1] = ((timing & 0xF) << 4) | v; |
435 | } |
436 | |
437 | void set_tRCD(unsigned short timing) |
438 | { |
439 | printf ("set tRCD = %u\r\n",timing+1); |
440 | unsigned short v; |
441 | v = (unsigned short)(MEM_REG[0x3802>>1] & (~(0xF))); |
442 | MEM_REG[0x3802>>1] = (timing & 0xF) | v; |
443 | } |
444 | |
445 | void set_REFPERD(unsigned short timing) |
446 | { |
447 | printf ("set Refresh Period = %u\r\n",timing+1); |
448 | MEM_REG[0x3808>>1] = timing; |
449 | } |
450 | |
451 | |
452 | //----- |
453 | //Gamma |
454 | //----- |
455 | |
456 | void set_gamma(float gamma) |
457 | { |
458 | printf ("set gamma = %f\r\n",gamma); |
459 | int i; |
460 | gamma = 1/gamma; |
461 | |
462 | //enable gamma |
463 | MEM_REG[0x2880>>1]&=~(1<<12); |
464 | |
465 | MEM_REG[0x295C>>1]=0; |
466 | for(i=0; i<256; i++) |
467 | { |
468 | unsigned char g; |
469 | unsigned short s; |
470 | g =(unsigned char)(255.0*pow(i/255.0,gamma)); |
471 | s = (g<<8) | g; |
472 | MEM_REG[0x295E>>1]= s; |
473 | MEM_REG[0x295E>>1]= g; |
474 | } |
475 | } |
476 | |
477 | unsigned get_YBNKLVL() |
478 | { |
479 | return (MEM_REG[0x283A>>1] & 0x3FF); |
480 | } |
481 | |
482 | void set_YBNKLVL(unsigned short val) |
483 | { |
484 | unsigned short temp = (unsigned short)(MEM_REG[0x3808>>1] & (~(0x3FF))); |
485 | MEM_REG[0x3808>>1] = (val & 0x3FF) | temp; |
486 | } |