menu adjustments (L, R for range controls)
[libpicofe.git] / gp2x / pollux_set.c
CommitLineData
fa8d1331 1/*
2 * quick tool to set various timings for Wiz
3 *
4 * Copyright (c) GraÅžvydas "notaz" Ignotas, 2009
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the organization nor the
14 * names of its contributors may be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * HTOTAL: X VTOTAL: 341
29 * HSWIDTH: 1 VSWIDTH: 0
30 * HASTART: 37 VASTART: 17
31 * HAEND: 277 VAEND: 337
32 *
33 * 120Hz
34 * pcd 8, 447: + 594us
35 * pcd 9, 397: + 36us
36 * pcd 10, 357: - 523us
37 * pcd 11, 325: +1153us
38 *
39 * 'lcd_timings=397,1,37,277,341,0,17,337;dpc_clkdiv0=9'
40 * 'ram_timings=2,9,4,1,1,1,1'
41 */
42
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include "pollux_set.h"
47
48/* parse stuff */
49static int parse_lcd_timings(const char *str, void *data)
50{
51 int *lcd_timings = data;
52 const char *p = str;
53 int ret, c;
54 ret = sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d",
55 &lcd_timings[0], &lcd_timings[1], &lcd_timings[2], &lcd_timings[3],
56 &lcd_timings[4], &lcd_timings[5], &lcd_timings[6], &lcd_timings[7]);
57 if (ret != 8)
58 return -1;
59 /* skip seven commas */
60 for (c = 0; c < 7 && *p != 0; p++)
61 if (*p == ',')
62 c++;
63 if (c != 7)
64 return -1;
65 /* skip last number */
66 while ('0' <= *p && *p <= '9')
67 p++;
68
69 return p - str;
70}
71
72static int parse_ram_timings(const char *str, void *data)
73{
74 int *ram_timings = data;
75 const char *p = str;
76 int ret, c;
77 float cas;
78
79 ret = sscanf(p, "%f,%d,%d,%d,%d,%d,%d",
80 &cas, &ram_timings[1], &ram_timings[2], &ram_timings[3],
81 &ram_timings[4], &ram_timings[5], &ram_timings[6]);
82 if (ret != 7)
83 return -1;
84 if (cas == 2)
85 ram_timings[0] = 1;
86 else if (cas == 2.5)
87 ram_timings[0] = 2;
88 else if (cas == 3)
89 ram_timings[0] = 3;
90 else
91 return -1;
92 for (c = 0; c < 6 && *p != 0; p++)
93 if (*p == ',')
94 c++;
95 if (c != 6)
96 return -1;
97 while ('0' <= *p && *p <= '9')
98 p++;
99
100 return p - str;
101}
102
103static int parse_decimal(const char *str, void *data)
104{
105 char *ep;
106
107 *(int *)data = strtoul(str, &ep, 10);
108 if (ep == str)
109 return -1;
110
111 return ep - str;
112}
113
114/* validate and apply stuff */
115static int apply_lcd_timings(volatile unsigned short *memregs, void *data)
116{
117 int *lcd_timings = data;
118 int i;
119
120 for (i = 0; i < 8; i++) {
121 if (lcd_timings[i] & ~0xffff) {
122 fprintf(stderr, "pollux_set: invalid lcd timing %d: %d\n", i, lcd_timings[i]);
123 return -1;
124 }
125 }
126
127 for (i = 0; i < 8; i++)
128 memregs[(0x307c>>1) + i] = lcd_timings[i];
129
130 return 0;
131}
132
133static const struct {
134 signed char adj; /* how to adjust value passed by user */
135 signed short min; /* range of */
136 signed short max; /* allowed values (inclusive) */
137}
138ram_ranges[] = {
139 { 0, 1, 3 }, /* cas (cl) */
140 { -2, 0, 15 }, /* trc */
141 { -2, 0, 15 }, /* tras */
142 { 0, 0, 15 }, /* twr */
143 { 0, 0, 15 }, /* tmrd */
144 { 0, 0, 15 }, /* trp */
145 { 0, 0, 15 }, /* trcd */
146};
147
148static int apply_ram_timings(volatile unsigned short *memregs, void *data)
149{
150 int *ram_timings = data;
151 int i, val;
152
153 for (i = 0; i < 7; i++)
154 {
155 ram_timings[i] += ram_ranges[i].adj;
156 if (ram_timings[i] < ram_ranges[i].min || ram_timings[i] > ram_ranges[i].max) {
157 fprintf(stderr, "pollux_set: invalid RAM timing %d\n", i);
158 return -1;
159 }
160 }
161
162 val = memregs[0x14802>>1] & 0x0f00;
163 val |= (ram_timings[4] << 12) | (ram_timings[5] << 4) | ram_timings[6];
164 memregs[0x14802>>1] = val;
165
166 val = memregs[0x14804>>1] & 0x4000;
167 val |= (ram_timings[0] << 12) | (ram_timings[1] << 8) |
168 (ram_timings[2] << 4) | ram_timings[3];
169 val |= 0x8000;
170 memregs[0x14804>>1] = val;
171
172 for (i = 0; i < 0x100000 && (memregs[0x14804>>1] & 0x8000); i++)
173 ;
174
175 return 0;
176}
177
178static int apply_dpc_clkdiv0(volatile unsigned short *memregs, void *data)
179{
180 int pcd = *(int *)data;
181 int tmp;
182
183 if ((pcd - 1) & ~0x3f) {
184 fprintf(stderr, "pollux_set: invalid lcd clkdiv0: %d\n", pcd);
185 return -1;
186 }
187
188 pcd = (pcd - 1) & 0x3f;
189 tmp = memregs[0x31c4>>1];
190 memregs[0x31c4>>1] = (tmp & ~0x3f0) | (pcd << 4);
191
192 return 0;
193}
194
195static int apply_cpuclk(volatile unsigned short *memregs, void *data)
196{
197 volatile unsigned int *memregl = (volatile void *)memregs;
198 int mhz = *(int *)data;
199 int mdiv, pdiv, sdiv = 0;
200 int i, v;
201
202 // m = MDIV, p = PDIV, s = SDIV
203 #define SYS_CLK_FREQ 27
204 pdiv = 9;
205 mdiv = (mhz * pdiv) / SYS_CLK_FREQ;
206 if (mdiv & ~0x3ff)
207 return -1;
208 v = (pdiv<<18) | (mdiv<<8) | sdiv;
209
210 memregl[0xf004>>2] = v;
211 memregl[0xf07c>>2] |= 0x8000;
212 for (i = 0; (memregl[0xf07c>>2] & 0x8000) && i < 0x100000; i++)
213 ;
214
215 return 0;
216}
217
218static int lcd_timings[8];
219static int ram_timings[7];
220static int dpc_clkdiv0;
221static int cpuclk;
222
223static const char lcd_t_help[] = "htotal,hswidth,hastart,haend,vtotal,vswidth,vastart,vaend";
224static const char ram_t_help[] = "CAS,tRC,tRAS,tWR,tMRD,tRP,tRCD";
225
226static const struct {
227 const char *name;
228 const char *help;
229 int (*parse)(const char *str, void *data);
230 int (*apply)(volatile unsigned short *memregs, void *data);
231 void *data;
232}
233all_params[] = {
234 { "lcd_timings", lcd_t_help, parse_lcd_timings, apply_lcd_timings, lcd_timings },
235 { "ram_timings", ram_t_help, parse_ram_timings, apply_ram_timings, ram_timings },
236 { "dpc_clkdiv0", "divider", parse_decimal, apply_dpc_clkdiv0, &dpc_clkdiv0 },
237 { "clkdiv0", "divider", parse_decimal, apply_dpc_clkdiv0, &dpc_clkdiv0 }, /* alias */
238 { "cpuclk", "MHZ", parse_decimal, apply_cpuclk, &cpuclk },
239};
240#define ALL_PARAM_COUNT (sizeof(all_params) / sizeof(all_params[0]))
241
242/*
243 * set timings based on preformated string
244 * returns 0 on success.
245 */
246int pollux_set(volatile unsigned short *memregs, const char *str)
247{
248 int parsed_params[ALL_PARAM_COUNT];
249 int applied_params[ALL_PARAM_COUNT];
250 int applied_something = 0;
251 const char *p, *po;
252 int i, ret;
253
254 if (str == NULL)
255 return -1;
256
257 memset(parsed_params, 0, sizeof(parsed_params));
258 memset(applied_params, 0, sizeof(applied_params));
259
260 p = str;
261 while (1)
262 {
263again:
264 while (*p == ';' || *p == ' ')
265 p++;
266 if (*p == 0)
267 break;
268
269 for (i = 0; i < ALL_PARAM_COUNT; i++)
270 {
271 int param_len = strlen(all_params[i].name);
272 if (strncmp(p, all_params[i].name, param_len) == 0 && p[param_len] == '=')
273 {
274 p += param_len + 1;
275 ret = all_params[i].parse(p, all_params[i].data);
276 if (ret < 0) {
277 fprintf(stderr, "pollux_set parser: error at %-10s\n", p);
278 fprintf(stderr, " valid format is: <%s>\n", all_params[i].help);
279 return -1;
280 }
281 parsed_params[i] = 1;
282 p += ret;
283 goto again;
284 }
285 }
286
287 /* Unknown param. Attempt to be forward compatible and ignore it. */
288 for (po = p; *p != 0 && *p != ';'; p++)
289 ;
290
291 fprintf(stderr, "unhandled param: ");
292 fwrite(po, 1, p - po, stderr);
293 fprintf(stderr, "\n");
294 }
295
296 /* validate and apply */
297 for (i = 0; i < ALL_PARAM_COUNT; i++)
298 {
299 if (!parsed_params[i])
300 continue;
301
302 ret = all_params[i].apply(memregs, all_params[i].data);
303 if (ret < 0) {
304 fprintf(stderr, "pollux_set: failed to apply %s (bad value?)\n",
305 all_params[i].name);
306 continue;
307 }
308
309 applied_something = 1;
310 applied_params[i] = 1;
311 }
312
313 if (applied_something)
314 {
315 int c;
316 printf("applied: ");
317 for (i = c = 0; i < ALL_PARAM_COUNT; i++)
318 {
319 if (!applied_params[i])
320 continue;
321 if (c != 0)
322 printf(", ");
323 printf("%s", all_params[i].name);
324 c++;
325 }
326 printf("\n");
327 }
328
329 return 0;
330}
331
332#ifdef BINARY
333#include <sys/types.h>
334#include <sys/stat.h>
335#include <fcntl.h>
336#include <sys/mman.h>
337#include <unistd.h>
338
339static void usage(const char *binary)
340{
341 int i;
342 printf("usage:\n%s <set_str[;set_str[;...]]>\n"
343 "set_str:\n", binary);
344 for (i = 0; i < ALL_PARAM_COUNT; i++)
345 printf(" %s=<%s>\n", all_params[i].name, all_params[i].help);
346}
347
348int main(int argc, char *argv[])
349{
350 volatile unsigned short *memregs;
351 int ret, memdev;
352
353 if (argc != 2) {
354 usage(argv[0]);
355 return 1;
356 }
357
358 memdev = open("/dev/mem", O_RDWR);
359 if (memdev == -1)
360 {
361 perror("open(/dev/mem) failed");
362 return 1;
363 }
364
365 memregs = mmap(0, 0x20000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000);
366 if (memregs == MAP_FAILED)
367 {
368 perror("mmap(memregs) failed");
369 close(memdev);
370 return 1;
371 }
372
373 ret = pollux_set(memregs, argv[1]);
374
375 munmap((void *)memregs, 0x20000);
376 close(memdev);
377
378 return ret;
379}
380#endif