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 | |
28 | #include <sys/mman.h> |
29 | #include <math.h> |
30 | #include <stdio.h> |
31 | #include "gp2xminilib.h" |
32 | |
33 | #define SYS_CLK_FREQ 7372800 |
34 | |
35 | //from minimal library rlyeh |
36 | |
37 | extern unsigned long gp2x_dev[4]; |
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 | |
120 | void set_add_FLCDCLK(int addclock) |
121 | { |
122 | //Set LCD controller to use FPLL |
123 | printf ("...set to FPLL-Clockgen...\r\n"); |
124 | printf ("set Timing-Prescaler = %i\r\n",addclock); |
125 | MEM_REG[0x924>>1]= 0x5A00 + ((addclock)<<8); |
126 | //If you change the initial timing, don't forget to shift your intervall-borders in "cpu_speed.c" |
127 | } |
128 | |
129 | void set_add_ULCDCLK(int addclock) |
130 | { |
131 | //Set LCD controller to use UPLL |
132 | printf ("...set to UPLL-Clockgen...\r\n"); |
133 | printf ("set Timing-Prescaler = %i\r\n",addclock); |
134 | MEM_REG[0x0924>>1] = 0x8900 + ((addclock)<<8); |
135 | //If you change the initial timing, don't forget to shift your intervall-borders in "cpu_speed.c" |
136 | } |
137 | |
138 | unsigned get_LCDClk() |
139 | { |
140 | if (MEM_REG[0x0924>>1] < 0x7A01) return((MEM_REG[0x0924>>1] - 0x5A00)>>8); |
141 | else return((MEM_REG[0x0924>>1] - 0x8900)>>8); |
142 | } |
143 | |
144 | char get_Clkgen() |
145 | { |
146 | if (MEM_REG[0x0924>>1] < 0x7A01) return(0); |
147 | else return(1); |
148 | } |
149 | |
150 | unsigned get_freq_UCLK() |
151 | { |
152 | unsigned i; |
153 | unsigned reg,mdiv,pdiv,scale; |
154 | i = MEM_REG[0x900>>1]; |
155 | i = ((i >> 7) & 1) ; |
156 | if(i) return 0; |
157 | reg=MEM_REG[0x916>>1]; |
158 | mdiv = ((reg & 0xff00) >> 8) + 8; |
159 | pdiv = ((reg & 0xfc) >> 2) + 2; |
160 | scale = reg & 3; |
161 | return ((SYS_CLK_FREQ * mdiv) / (pdiv << scale)); |
162 | } |
163 | |
164 | unsigned get_freq_ACLK() |
165 | { |
166 | unsigned i; |
167 | unsigned reg,mdiv,pdiv,scale; |
168 | i = MEM_REG[0x900>>1]; |
169 | i = ((i >> 8) & 1) ; |
170 | if(i) return 0; |
171 | reg=MEM_REG[0x918>>1]; |
172 | mdiv = ((reg & 0xff00) >> 8) + 8; |
173 | pdiv = ((reg & 0xfc) >> 2) + 2; |
174 | scale = reg & 3; |
175 | return ((SYS_CLK_FREQ * mdiv)/(pdiv << scale)); |
176 | } |
177 | |
178 | unsigned get_freq_920_CLK() |
179 | { |
180 | unsigned i; |
181 | unsigned reg,mdiv,pdiv,scale; |
182 | reg=MEM_REG[0x912>>1]; |
183 | mdiv = ((reg & 0xff00) >> 8) + 8; |
184 | pdiv = ((reg & 0xfc) >> 2) + 2; |
185 | scale = reg & 3; |
186 | MDIV=mdiv; |
187 | PDIV=pdiv; |
188 | SCALE=scale; |
189 | i = (MEM_REG[0x91c>>1] & 7)+1; |
190 | return ((SYS_CLK_FREQ * mdiv)/(pdiv << scale))/i; |
191 | } |
192 | |
193 | unsigned get_freq_940_CLK() |
194 | { |
195 | unsigned i; |
196 | unsigned reg,mdiv,pdiv,scale; |
197 | reg=MEM_REG[0x912>>1]; |
198 | mdiv = ((reg & 0xff00) >> 8) + 8; |
199 | pdiv = ((reg & 0xfc) >> 2) + 2; |
200 | scale = reg & 3; |
201 | i = ((MEM_REG[0x91c>>1]>>3) & 7)+1; |
202 | return ((SYS_CLK_FREQ * mdiv) / (pdiv << scale))/i; |
203 | } |
204 | |
205 | unsigned get_freq_DCLK() |
206 | { |
207 | unsigned i; |
208 | unsigned reg,mdiv,pdiv,scale; |
209 | reg=MEM_REG[0x912>>1]; |
210 | mdiv = ((reg & 0xff00) >> 8) + 8; |
211 | pdiv = ((reg & 0xfc) >> 2) + 2; |
212 | scale = reg & 3; |
213 | i = ((MEM_REG[0x91c>>1]>>6) & 7)+1; |
214 | return ((SYS_CLK_FREQ * mdiv) / (pdiv << scale))/i; |
215 | } |
216 | |
217 | void set_920_Div(unsigned short div) |
218 | { |
219 | printf ("set divider for CPU-Clock = %u\r\n",div+1); |
220 | unsigned short v; |
221 | v = MEM_REG[0x91c>>1] & (~0x3); |
222 | MEM_REG[0x91c>>1] = (div & 0x7) | v; |
223 | } |
224 | |
225 | unsigned short get_920_Div() |
226 | { |
227 | return (MEM_REG[0x91c>>1] & 0x7); |
228 | } |
229 | |
230 | void set_940_Div(unsigned short div) |
231 | { |
232 | unsigned short v; |
233 | v = (unsigned short)( MEM_REG[0x91c>>1] & (~(0x7 << 3))); |
234 | MEM_REG[0x91c>>1] = ((div & 0x7) << 3) | v; |
235 | } |
236 | |
237 | unsigned short get_940_Div() |
238 | { |
239 | return ((MEM_REG[0x91c>>1] >> 3) & 0x7); |
240 | } |
241 | |
242 | void set_DCLK_Div( unsigned short div ) |
243 | { |
244 | printf ("set divider for RAM-Clock = %u\r\n",div+1); |
245 | unsigned short v; |
246 | v = (unsigned short)( MEM_REG[0x91c>>1] & (~(0x7 << 6))); |
247 | MEM_REG[0x91c>>1] = ((div & 0x7) << 6) | v; |
248 | } |
249 | |
250 | unsigned short get_DCLK_Div() |
251 | { |
252 | return ((MEM_REG[0x91c>>1] >> 6) & 0x7); |
253 | } |
254 | |
255 | unsigned short Disable_Int_920() |
256 | { |
257 | unsigned short ret; |
258 | ret=MEM_REG[0x3B40>>1]; |
259 | MEM_REG[0x3B40>>1]=0; |
260 | MEM_REG[0x3B44>>1]=0xffff; |
261 | return ret; |
262 | } |
263 | |
264 | unsigned short Disable_Int_940() |
265 | { |
266 | unsigned short ret; |
267 | ret=MEM_REG[0x3B42>>1]; |
268 | MEM_REG[0x3B42>>1]=0; |
269 | MEM_REG[0x3B46>>1]=0xffff; |
270 | return ret; |
271 | } |
272 | |
273 | unsigned get_state940() |
274 | { |
275 | return MEM_REG[0x904>>1]; |
276 | } |
277 | |
278 | |
279 | void Enable_Int_920(unsigned short flag) |
280 | { |
281 | MEM_REG[0x3B40>>1]=flag; |
282 | } |
283 | |
284 | void Enable_Int_940(unsigned short flag) |
285 | { |
286 | MEM_REG[0x3B42>>1]=flag; |
287 | } |
288 | |
289 | void Disable_940() |
290 | { |
291 | Disable_Int_940(); |
292 | MEM_REG[0x3B48>>1]|= (1 << 7); |
293 | MEM_REG[0x904>>1]&=0xfffe; |
294 | } |
295 | |
296 | void Load_940_code(unsigned *code,int size) |
297 | { |
298 | unsigned *cp; |
299 | int i; |
300 | arm940code=(unsigned short *)mmap(0, 0x100000, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], 0x03000000); |
301 | Disable_940(); |
302 | cp=(unsigned *) code; |
303 | for (i = 0; i < size/4; i ++) |
304 | { |
305 | arm940code[i] = cp[i]; |
306 | } |
307 | for (i = 0; i < 64; i ++) |
308 | { |
309 | arm940code[0x3FC0+i] = 0; |
310 | } |
311 | MEM_REG[0x3B48>>1]=(MEM_REG[0x3B48>>1] & 0xFF00) | 0x03; // allow 940 |
312 | } |
313 | |
314 | void clock_940_off() |
315 | { |
316 | MEM_REG[0x904>>1]&=0xfffe; |
317 | } |
318 | |
319 | void clock_940_on() |
320 | { |
321 | MEM_REG[0x904>>1]|=1; |
322 | } |
323 | |
324 | |
325 | //-------------- |
326 | //Memory Timings |
327 | //-------------- |
328 | |
329 | //get |
330 | |
331 | unsigned get_CAS() |
332 | { |
333 | return ((MEM_REG[0x3804>>1] >> 12) & 0x1); |
334 | } |
335 | |
336 | unsigned get_tRC() |
337 | { |
338 | return ((MEM_REG[0x3804>>1] >> 8) & 0xF); |
339 | } |
340 | |
341 | unsigned get_tRAS() |
342 | { |
343 | return ((MEM_REG[0x3804>>1] >> 4) & 0xF); |
344 | } |
345 | |
346 | unsigned get_tWR() |
347 | { |
348 | return (MEM_REG[0x3804>>1] & 0xF); |
349 | } |
350 | |
351 | unsigned get_tMRD() |
352 | { |
353 | return ((MEM_REG[0x3802>>1] >> 12) & 0xF); |
354 | } |
355 | |
356 | unsigned get_tRFC() |
357 | { |
358 | return ((MEM_REG[0x3802>>1] >> 8) & 0xF); |
359 | } |
360 | |
361 | unsigned get_tRP() |
362 | { |
363 | return ((MEM_REG[0x3802>>1] >> 4) & 0xF); |
364 | } |
365 | |
366 | unsigned get_tRCD() |
367 | { |
368 | return (MEM_REG[0x3802>>1] & 0xF); |
369 | } |
370 | |
371 | unsigned get_REFPERD() |
372 | { |
373 | return MEM_REG[0x3808>>1]; |
374 | } |
375 | |
376 | |
377 | //set |
378 | |
379 | void set_CAS(unsigned short timing) |
380 | { |
381 | printf ("set CAS = %u\r\n",timing+2); |
382 | unsigned short v; |
383 | v = (unsigned short)(MEM_REG[0x3804>>1] & (~(0x1 << 12))); |
384 | MEM_REG[0x3804>>1] = ((timing & 0x1) << 12) | v; |
385 | } |
386 | |
387 | void set_tRC(unsigned short timing) |
388 | { |
389 | printf ("set tRC = %u\r\n",timing+1); |
390 | unsigned short v; |
391 | v = (unsigned short)(MEM_REG[0x3804>>1] & (~(0xF << 8))); |
392 | MEM_REG[0x3804>>1] = ((timing & 0xF) << 8) | v; |
393 | } |
394 | |
395 | void set_tRAS(unsigned short timing) |
396 | { |
397 | printf ("set tRAS = %u\r\n",timing+1); |
398 | unsigned short v; |
399 | v = (unsigned short)(MEM_REG[0x3804>>1] & (~(0xF << 4))); |
400 | MEM_REG[0x3804>>1] = ((timing & 0xF) << 4) | v; |
401 | } |
402 | |
403 | void set_tWR(unsigned short timing) |
404 | { |
405 | printf ("set tWR = %u\r\n",timing+1); |
406 | unsigned short v; |
407 | v = (unsigned short)(MEM_REG[0x3804>>1] & (~(0xF))); |
408 | MEM_REG[0x3804>>1] = (timing & 0xF) | v; |
409 | } |
410 | |
411 | void set_tMRD(unsigned short timing) |
412 | { |
413 | printf ("set tMRD = %u\r\n",timing+1); |
414 | unsigned short v; |
415 | v = (unsigned short)(MEM_REG[0x3802>>1] & (~(0xF << 12))); |
416 | MEM_REG[0x3802>>1] = ((timing & 0xF) << 12) | v; |
417 | } |
418 | |
419 | void set_tRFC(unsigned short timing) |
420 | { |
421 | printf ("set tRFC = %u\r\n",timing+1); |
422 | unsigned short v; |
423 | v = (unsigned short)(MEM_REG[0x3802>>1] & (~(0xF << 8))); |
424 | MEM_REG[0x3802>>1] = ((timing & 0xF) << 8) | v; |
425 | } |
426 | |
427 | void set_tRP(unsigned short timing) |
428 | { |
429 | printf ("set tRP = %u\r\n",timing+1); |
430 | unsigned short v; |
431 | v = (unsigned short)(MEM_REG[0x3802>>1] & (~(0xF << 4))); |
432 | MEM_REG[0x3802>>1] = ((timing & 0xF) << 4) | v; |
433 | } |
434 | |
435 | void set_tRCD(unsigned short timing) |
436 | { |
437 | printf ("set tRCD = %u\r\n",timing+1); |
438 | unsigned short v; |
439 | v = (unsigned short)(MEM_REG[0x3802>>1] & (~(0xF))); |
440 | MEM_REG[0x3802>>1] = (timing & 0xF) | v; |
441 | } |
442 | |
443 | void set_REFPERD(unsigned short timing) |
444 | { |
445 | printf ("set Refresh Period = %u\r\n",timing+1); |
446 | MEM_REG[0x3808>>1] = timing; |
447 | } |
448 | |
449 | |
450 | //----- |
451 | //Gamma |
452 | //----- |
453 | |
454 | void set_gamma(float gamma) |
455 | { |
456 | printf ("set gamma = %f\r\n",gamma); |
457 | int i; |
458 | gamma = 1/gamma; |
459 | |
460 | //enable gamma |
461 | MEM_REG[0x2880>>1]&=~(1<<12); |
462 | |
463 | MEM_REG[0x295C>>1]=0; |
464 | for(i=0; i<256; i++) |
465 | { |
466 | unsigned char g; |
467 | unsigned short s; |
468 | g =(unsigned char)(255.0*pow(i/255.0,gamma)); |
469 | s = (g<<8) | g; |
470 | MEM_REG[0x295E>>1]= s; |
471 | MEM_REG[0x295E>>1]= g; |
472 | } |
473 | } |
474 | |
475 | unsigned get_YBNKLVL() |
476 | { |
477 | return (MEM_REG[0x283A>>1] & 0x3FF); |
478 | } |
479 | |
480 | void set_YBNKLVL(unsigned short val) |
481 | { |
482 | unsigned short temp = (unsigned short)(MEM_REG[0x3808>>1] & (~(0x3FF))); |
483 | MEM_REG[0x3808>>1] = (val & 0x3FF) | temp; |
484 | } |