720ee7f6 |
1 | /* cpuctrl for GP2X |
576fc637 |
2 | Copyright (C) 2005 Hermes/PS2Reality |
720ee7f6 |
3 | the gamma-routine was provided by theoddbot |
576fc637 |
4 | parts (c) Rlyehs Work & (C) 2006 god_at_hell |
720ee7f6 |
5 | |
6 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 2 of the License, or |
9 | (at your option) any later version. |
10 | |
11 | This program is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | GNU General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along with this program; if not, write to the Free Software |
18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
19 | |
20 | */ |
21 | |
22 | |
576fc637 |
23 | #include <stdio.h> |
720ee7f6 |
24 | #include <math.h> |
25 | #include "cpuctrl.h" |
26 | |
27 | |
28 | /* system registers */ |
576fc637 |
29 | static struct |
720ee7f6 |
30 | { |
576fc637 |
31 | unsigned short SYSCLKENREG,SYSCSETREG,UPLLVSETREG,FPLLVSETREG, |
32 | DUALINT920,DUALINT940,DUALCTRL940,MEMTIMEX0,MEMTIMEX1,DISPCSETREG, |
33 | DPC_HS_WIDTH,DPC_HS_STR,DPC_HS_END,DPC_VS_END,DPC_DE; |
720ee7f6 |
34 | } |
35 | system_reg; |
36 | |
720ee7f6 |
37 | static volatile unsigned short *MEM_REG; |
38 | |
39 | #define SYS_CLK_FREQ 7372800 |
40 | |
576fc637 |
41 | // Fout = (m * Fin) / (p * 2^s) |
42 | // m = MDIV+8, p = PDIV+2, s = SDIV |
43 | |
44 | // m = (Fout * p * 2^s) / Fin |
720ee7f6 |
45 | |
46 | void cpuctrl_init(void) |
47 | { |
48 | extern volatile unsigned short *gp2x_memregs; /* from minimal library rlyeh */ |
49 | MEM_REG=&gp2x_memregs[0]; |
576fc637 |
50 | system_reg.DISPCSETREG=MEM_REG[0x924>>1]; |
51 | system_reg.UPLLVSETREG=MEM_REG[0x916>>1]; |
720ee7f6 |
52 | system_reg.FPLLVSETREG=MEM_REG[0x912>>1]; |
576fc637 |
53 | system_reg.SYSCSETREG=MEM_REG[0x91c>>1]; |
720ee7f6 |
54 | system_reg.SYSCLKENREG=MEM_REG[0x904>>1]; |
55 | system_reg.DUALINT920=MEM_REG[0x3B40>>1]; |
56 | system_reg.DUALINT940=MEM_REG[0x3B42>>1]; |
57 | system_reg.DUALCTRL940=MEM_REG[0x3B48>>1]; |
58 | system_reg.MEMTIMEX0=MEM_REG[0x3802>>1]; |
59 | system_reg.MEMTIMEX1=MEM_REG[0x3804>>1]; |
576fc637 |
60 | system_reg.DPC_HS_WIDTH=MEM_REG[0x281A>>1]; |
61 | system_reg.DPC_HS_STR=MEM_REG[0x281C>>1]; |
62 | system_reg.DPC_HS_END=MEM_REG[0x281E>>1]; |
63 | system_reg.DPC_VS_END=MEM_REG[0x2822>>1]; |
64 | system_reg.DPC_DE=MEM_REG[0x2826>>1]; |
720ee7f6 |
65 | } |
66 | |
67 | |
68 | void cpuctrl_deinit(void) |
69 | { |
720ee7f6 |
70 | MEM_REG[0x910>>1]=system_reg.FPLLVSETREG; |
576fc637 |
71 | MEM_REG[0x91c>>1]=system_reg.SYSCSETREG; |
720ee7f6 |
72 | MEM_REG[0x3B40>>1]=system_reg.DUALINT920; |
73 | MEM_REG[0x3B42>>1]=system_reg.DUALINT940; |
74 | MEM_REG[0x3B48>>1]=system_reg.DUALCTRL940; |
75 | MEM_REG[0x904>>1]=system_reg.SYSCLKENREG; |
720ee7f6 |
76 | MEM_REG[0x3802>>1]=system_reg.MEMTIMEX0; |
77 | MEM_REG[0x3804>>1]=system_reg.MEMTIMEX1 /*| 0x9000*/; |
576fc637 |
78 | unset_LCD_custom_rate(); |
720ee7f6 |
79 | } |
80 | |
81 | |
82 | void set_display_clock_div(unsigned div) |
83 | { |
84 | div=((div & 63) | 64)<<8; |
85 | MEM_REG[0x924>>1]=(MEM_REG[0x924>>1] & ~(255<<8)) | div; |
86 | } |
87 | |
88 | |
89 | void set_FCLK(unsigned MHZ) |
90 | { |
91 | unsigned v; |
92 | unsigned mdiv,pdiv=3,scale=0; |
93 | MHZ*=1000000; |
94 | mdiv=(MHZ*pdiv)/SYS_CLK_FREQ; |
95 | mdiv=((mdiv-8)<<8) & 0xff00; |
96 | pdiv=((pdiv-2)<<2) & 0xfc; |
97 | scale&=3; |
98 | v=mdiv | pdiv | scale; |
99 | MEM_REG[0x910>>1]=v; |
100 | } |
101 | |
102 | |
103 | void set_920_Div(unsigned short div) |
104 | { |
105 | unsigned short v; |
106 | v = MEM_REG[0x91c>>1] & (~0x3); |
576fc637 |
107 | MEM_REG[0x91c>>1] = (div & 0x7) | v; |
720ee7f6 |
108 | } |
109 | |
110 | |
111 | void set_DCLK_Div( unsigned short div ) |
112 | { |
113 | unsigned short v; |
114 | v = (unsigned short)( MEM_REG[0x91c>>1] & (~(0x7 << 6)) ); |
576fc637 |
115 | MEM_REG[0x91c>>1] = ((div & 0x7) << 6) | v; |
720ee7f6 |
116 | } |
117 | |
118 | /* |
119 | void Disable_940(void) |
120 | { |
121 | MEM_REG[0x3B42>>1]; |
122 | MEM_REG[0x3B42>>1]=0; |
576fc637 |
123 | MEM_REG[0x3B46>>1]=0xffff; |
720ee7f6 |
124 | MEM_REG[0x3B48>>1]|= (1 << 7); |
125 | MEM_REG[0x904>>1]&=0xfffe; |
126 | } |
127 | */ |
128 | |
576fc637 |
129 | |
130 | typedef struct |
131 | { |
132 | unsigned short reg, valmask, val; |
133 | } |
134 | reg_setting; |
135 | |
136 | // ~59.998, couldn't figure closer values |
137 | static reg_setting rate_almost60[] = |
138 | { |
139 | { 0x0914, 0xffff, (212<<8)|(2<<2)|1 }, /* UPLLSETVREG */ |
140 | { 0x0924, 0xff00, (2<<14)|(36<<8) }, /* DISPCSETREG */ |
141 | { 0x281A, 0x00ff, 1 }, /* .HSWID(T2) */ |
142 | { 0x281C, 0x00ff, 0 }, /* .HSSTR(T8) */ |
143 | { 0x281E, 0x00ff, 2 }, /* .HSEND(T7) */ |
144 | { 0x2822, 0x01ff, 12 }, /* .VSEND (T9) */ |
145 | { 0x2826, 0x0ff0, 34<<4 }, /* .DESTR(T3) */ |
146 | { 0, 0, 0 } |
147 | }; |
148 | |
149 | // perfect 50Hz? |
150 | static reg_setting rate_50[] = |
151 | { |
152 | { 0x0914, 0xffff, (39<<8)|(0<<2)|2 }, /* UPLLSETVREG */ |
153 | { 0x0924, 0xff00, (2<<14)|(7<<8) }, /* DISPCSETREG */ |
154 | { 0x281A, 0x00ff, 31 }, /* .HSWID(T2) */ |
155 | { 0x281C, 0x00ff, 16 }, /* .HSSTR(T8) */ |
156 | { 0x281E, 0x00ff, 15 }, /* .HSEND(T7) */ |
157 | { 0x2822, 0x01ff, 15 }, /* .VSEND (T9) */ |
158 | { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */ |
159 | { 0, 0, 0 } |
160 | }; |
161 | |
162 | // 16639/2 ~120.20 |
163 | static reg_setting rate_120_20[] = |
164 | { |
165 | { 0x0914, 0xffff, (96<<8)|(0<<2)|2 }, /* UPLLSETVREG */ |
166 | { 0x0924, 0xff00, (2<<14)|(7<<8) }, /* DISPCSETREG */ |
167 | { 0x281A, 0x00ff, 19 }, /* .HSWID(T2) */ |
168 | { 0x281C, 0x00ff, 7 }, /* .HSSTR(T8) */ |
169 | { 0x281E, 0x00ff, 7 }, /* .HSEND(T7) */ |
170 | { 0x2822, 0x01ff, 12 }, /* .VSEND (T9) */ |
171 | { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */ |
172 | { 0, 0, 0 } |
173 | }; |
174 | |
175 | // 19997/2 ~100.02 |
176 | static reg_setting rate_100_02[] = |
177 | { |
178 | { 0x0914, 0xffff, (98<<8)|(0<<2)|2 }, /* UPLLSETVREG */ |
179 | { 0x0924, 0xff00, (2<<14)|(8<<8) }, /* DISPCSETREG */ |
180 | { 0x281A, 0x00ff, 26 }, /* .HSWID(T2) */ |
181 | { 0x281C, 0x00ff, 6 }, /* .HSSTR(T8) */ |
182 | { 0x281E, 0x00ff, 6 }, /* .HSEND(T7) */ |
183 | { 0x2822, 0x01ff, 31 }, /* .VSEND (T9) */ |
184 | { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */ |
185 | { 0, 0, 0 } |
186 | }; |
187 | |
188 | // 120.00 97/0/2/7|25/ 7/ 7/11/37 |
189 | static reg_setting rate_120[] = |
190 | { |
191 | { 0x0914, 0xffff, (97<<8)|(0<<2)|2 }, /* UPLLSETVREG */ |
192 | { 0x0924, 0xff00, (2<<14)|(7<<8) }, /* DISPCSETREG */ |
193 | { 0x281A, 0x00ff, 25 }, /* .HSWID(T2) */ |
194 | { 0x281C, 0x00ff, 7 }, /* .HSSTR(T8) */ |
195 | { 0x281E, 0x00ff, 7 }, /* .HSEND(T7) */ |
196 | { 0x2822, 0x01ff, 11 }, /* .VSEND (T9) */ |
197 | { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */ |
198 | { 0, 0, 0 } |
199 | }; |
200 | |
201 | // 100.00 96/0/2/7|29/25/53/15/37 |
202 | static reg_setting rate_100[] = |
203 | { |
204 | { 0x0914, 0xffff, (96<<8)|(0<<2)|2 }, /* UPLLSETVREG */ |
205 | { 0x0924, 0xff00, (2<<14)|(7<<8) }, /* DISPCSETREG */ |
206 | { 0x281A, 0x00ff, 29 }, /* .HSWID(T2) */ |
207 | { 0x281C, 0x00ff, 25 }, /* .HSSTR(T8) */ |
208 | { 0x281E, 0x00ff, 53 }, /* .HSEND(T7) */ |
209 | { 0x2822, 0x01ff, 15 }, /* .VSEND (T9) */ |
210 | { 0x2826, 0x0ff0, 37<<4 }, /* .DESTR(T3) */ |
211 | { 0, 0, 0 } |
212 | }; |
213 | |
214 | |
215 | |
216 | static reg_setting *possible_rates[] = { rate_almost60, rate_50, rate_120_20, rate_100_02, rate_120, rate_100 }; |
217 | |
218 | void set_LCD_custom_rate(lcd_rate_t rate) |
219 | { |
220 | reg_setting *set; |
221 | |
222 | if (MEM_REG[0x2800>>1] & 0x100) // tv-out |
223 | { |
224 | return; |
225 | } |
226 | |
227 | printf("setting custom LCD refresh, mode=%i... ", rate); fflush(stdout); |
228 | for (set = possible_rates[rate]; set->reg; set++) |
229 | { |
230 | unsigned short val = MEM_REG[set->reg >> 1]; |
231 | val &= ~set->valmask; |
232 | val |= set->val; |
233 | MEM_REG[set->reg >> 1] = val; |
234 | } |
235 | printf("done.\n"); |
236 | } |
237 | |
238 | void unset_LCD_custom_rate(void) |
239 | { |
240 | printf("reset to prev LCD refresh.\n"); |
241 | MEM_REG[0x914>>1]=system_reg.UPLLVSETREG; |
242 | MEM_REG[0x924>>1]=system_reg.DISPCSETREG; |
243 | MEM_REG[0x281A>>1]=system_reg.DPC_HS_WIDTH; |
244 | MEM_REG[0x281C>>1]=system_reg.DPC_HS_STR; |
245 | MEM_REG[0x281E>>1]=system_reg.DPC_HS_END; |
246 | MEM_REG[0x2822>>1]=system_reg.DPC_VS_END; |
247 | MEM_REG[0x2826>>1]=system_reg.DPC_DE; |
248 | } |
249 | |
720ee7f6 |
250 | void set_RAM_Timings(int tRC, int tRAS, int tWR, int tMRD, int tRFC, int tRP, int tRCD) |
251 | { |
252 | tRC -= 1; tRAS -= 1; tWR -= 1; tMRD -= 1; tRFC -= 1; tRP -= 1; tRCD -= 1; // ??? |
253 | MEM_REG[0x3802>>1] = ((tMRD & 0xF) << 12) | ((tRFC & 0xF) << 8) | ((tRP & 0xF) << 4) | (tRCD & 0xF); |
254 | MEM_REG[0x3804>>1] = /*0x9000 |*/ ((tRC & 0xF) << 8) | ((tRAS & 0xF) << 4) | (tWR & 0xF); |
255 | } |
256 | |
257 | |
55a951dd |
258 | void set_gamma(int g100, int A_SNs_curve) |
720ee7f6 |
259 | { |
260 | float gamma = (float) g100 / 100; |
261 | int i; |
720ee7f6 |
262 | gamma = 1/gamma; |
263 | |
55a951dd |
264 | //enable gamma |
265 | MEM_REG[0x2880>>1]&=~(1<<12); |
720ee7f6 |
266 | |
55a951dd |
267 | MEM_REG[0x295C>>1]=0; |
268 | for(i=0; i<256; i++) |
269 | { |
720ee7f6 |
270 | unsigned char g; |
55a951dd |
271 | unsigned short s; |
272 | const unsigned short grey50=143, grey75=177, grey25=97; |
273 | float blah; |
274 | |
275 | if (A_SNs_curve) |
276 | { |
277 | // The next formula is all about gaussian interpolation |
278 | blah = (( -128 * exp(-powf((float) i/64.0f + 2.0f , 2.0f))) + |
279 | ( -64 * exp(-powf((float) i/64.0f + 1.0f , 2.0f))) + |
280 | (grey25 * exp(-powf((float) i/64.0f - 1.0f , 2.0f))) + |
281 | (grey50 * exp(-powf((float) i/64.0f - 2.0f , 2.0f))) + |
282 | (grey75 * exp(-powf((float) i/64.0f - 3.0f , 2.0f))) + |
283 | ( 256 * exp(-powf((float) i/64.0f - 4.0f , 2.0f))) + |
284 | ( 320 * exp(-powf((float) i/64.0f - 5.0f , 2.0f))) + |
285 | ( 384 * exp(-powf((float) i/64.0f - 6.0f , 2.0f)))) / (1.772637f); |
286 | blah += 0.5f; |
287 | } |
288 | else |
289 | { |
290 | blah = i; |
291 | } |
292 | |
293 | g = (unsigned char)(255.0*pow(blah/255.0,gamma)); |
294 | //printf("%d : %d\n", i, g); |
295 | s = (g<<8) | g; |
720ee7f6 |
296 | MEM_REG[0x295E>>1]= s; |
55a951dd |
297 | MEM_REG[0x295E>>1]= g; |
298 | } |
720ee7f6 |
299 | } |
300 | |