pollux_dpc_set integrated
[gpsp.git] / gp2x / pollux_dpc_set.c
1 /*
2  * quick tool to set LCD timings for Wiz
3  * (c) notaz, 2009
4  * code dedicated to public domain.
5  *
6  * HTOTAL:    X VTOTAL:  341
7  * HSWIDTH:   1 VSWIDTH:   0
8  * HASTART:  37 VASTART:  17
9  * HAEND:   277 VAEND:   337
10  *
11  * 120Hz
12  * pcd  8, 447: + 594us
13  * pcd  9, 397: +  36us
14  * pcd 10, 357: - 523us
15  * pcd 11, 325: +1153us
16  *
17  * 'lcd_timings=397,1,37,277,341,0,17,337;clkdiv0=9'
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include "pollux_dpc_set.h"
24
25 /*
26  * set LCD timings based on preformated string (see usage() below for params).
27  * returns 0 on success.
28  */
29 int pollux_dpc_set(volatile unsigned short *memregs, const char *str)
30 {
31         int timings[8], have_timings = 0;
32         int pcd = 0, have_pcd = 0;
33         const char *p;
34         int i, ret;
35
36         if (str == NULL)
37                 return -1;
38
39         p = str;
40         while (1)
41         {
42                 if (strncmp(p, "lcd_timings=", 12) == 0)
43                 {
44                         int c;
45                         p += 12;
46                         ret = sscanf(p, "%d,%d,%d,%d,%d,%d,%d,%d",
47                                 &timings[0], &timings[1], &timings[2], &timings[3],
48                                 &timings[4], &timings[5], &timings[6], &timings[7]);
49                         if (ret != 8)
50                                 break;
51                         /* skip seven commas */
52                         for (c = 0; c < 7 && *p != 0; p++)
53                                 if (*p == ',')
54                                                 c++;
55                         if (c != 7)
56                                 break;
57                         /* skip last number */
58                         while ('0' <= *p && *p <= '9')
59                                 p++;
60                         have_timings = 1;
61                 }
62                 else if (strncmp(p, "clkdiv0=", 8) == 0)
63                 {
64                         char *ep;
65                         p += 8;
66                         pcd = strtoul(p, &ep, 10);
67                         if (p == ep)
68                                 break;
69                         p = ep;
70                         have_pcd = 1;
71                 }
72                 else
73                         break;
74
75                 while (*p == ';' || *p == ' ')
76                         p++;
77                 if (*p == 0)
78                         goto parse_done;
79         }
80
81         fprintf(stderr, "dpc_set parser: error at '%s'\n", p);
82         return -1;
83
84 parse_done:
85         /* some validation */
86         if (have_timings)
87         {
88                 for (i = 0; i < 8; i++)
89                         if (timings[i] & ~0xffff) {
90                                 fprintf(stderr, "dpc_set: invalid timing %d: %d\n", i, timings[i]);
91                                 return -1;
92                         }
93         }
94
95         if (have_pcd)
96         {
97                 if ((pcd - 1) & ~0x3f) {
98                         fprintf(stderr, "dpc_set: invalid clkdiv0: %d\n", pcd);
99                         return -1;
100                 }
101         }
102
103         /* write */
104         if (have_timings)
105         {
106                 for (i = 0; i < 8; i++)
107                         memregs[(0x307c>>1) + i] = timings[i];
108         }
109
110         if (have_pcd)
111         {
112                 int tmp;
113                 pcd = (pcd - 1) & 0x3f;
114                 tmp = memregs[0x31c4>>1];
115                 memregs[0x31c4>>1] = (tmp & ~0x3f0) | (pcd << 4);
116         }
117
118         return 0;
119 }
120
121 #ifdef BINARY
122 #include <sys/types.h>
123 #include <sys/stat.h>
124 #include <fcntl.h>
125 #include <sys/mman.h>
126 #include <unistd.h>
127
128 static void usage(const char *binary)
129 {
130         printf("usage:\n%s <set_str[;set_str[;...]]>\n"
131                 "set_str:\n"
132                 "  lcd_timings=<htotal,hswidth,hastart,haend,vtotal,vswidth,vastart,vaend>\n"
133                 "  clkdiv0=<divider>\n", binary);
134 }
135
136 int main(int argc, char *argv[])
137 {
138         volatile unsigned short *memregs;
139         int ret, memdev;
140
141         if (argc != 2) {
142                 usage(argv[0]);
143                 return 1;
144         }
145
146         memdev = open("/dev/mem", O_RDWR);
147         if (memdev == -1)
148         {
149                 perror("open(/dev/mem) failed");
150                 return 1;
151         }
152
153         memregs = mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000);
154         if (memregs == MAP_FAILED)
155         {
156                 perror("mmap(memregs) failed");
157                 close(memdev);
158                 return 1;
159         }
160
161         ret = pollux_dpc_set(memregs, argv[1]);
162
163         munmap((void *)memregs, 0x10000);
164         close(memdev);
165
166         return ret;
167 }
168 #endif