2 * quick tool to set various timings for Wiz
4 * Copyright (c) GraÅžvydas "notaz" Ignotas, 2009
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.
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.
28 * HTOTAL: X VTOTAL: 341
29 * HSWIDTH: 1 VSWIDTH: 0
30 * HASTART: 37 VASTART: 17
31 * HAEND: 277 VAEND: 337
36 * pcd 10, 357: - 523us
37 * pcd 11, 325: +1153us
39 * 'lcd_timings=397,1,37,277,341,0,17,337;dpc_clkdiv0=9'
40 * 'ram_timings=2,9,4,1,1,1,1'
46 //#include "pollux_set.h"
50 static int parse_lcd_timings(const char *str, void *data)
52 int *lcd_timings = data;
55 ret = sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d",
56 &lcd_timings[0], &lcd_timings[1], &lcd_timings[2], &lcd_timings[3],
57 &lcd_timings[4], &lcd_timings[5], &lcd_timings[6], &lcd_timings[7]);
60 /* skip seven commas */
61 for (c = 0; c < 7 && *p != 0; p++)
66 /* skip last number */
67 while ('0' <= *p && *p <= '9')
73 static int parse_ram_timings(const char *str, void *data)
75 int *ram_timings = data;
80 ret = sscanf(p, "%f,%d,%d,%d,%d,%d,%d",
81 &cas, &ram_timings[1], &ram_timings[2], &ram_timings[3],
82 &ram_timings[4], &ram_timings[5], &ram_timings[6]);
93 for (c = 0; c < 6 && *p != 0; p++)
98 while ('0' <= *p && *p <= '9')
104 static int parse_decimal(const char *str, void *data)
108 *(int *)data = strtoul(str, &ep, 10);
115 /* validate and apply stuff */
116 static int apply_lcd_timings(volatile unsigned short *memregs, void *data)
118 int *lcd_timings = data;
121 for (i = 0; i < 8; i++) {
122 if (lcd_timings[i] & ~0xffff) {
123 fprintf(stderr, "pollux_set: invalid lcd timing %d: %d\n", i, lcd_timings[i]);
128 for (i = 0; i < 8; i++)
129 memregs[(0x307c>>1) + i] = lcd_timings[i];
134 static const struct {
135 signed char adj; /* how to adjust value passed by user */
136 signed short min; /* range of */
137 signed short max; /* allowed values (inclusive) */
140 { 0, 1, 3 }, /* cas (cl) */
141 { -2, 0, 15 }, /* trc */
142 { -2, 0, 15 }, /* tras */
143 { 0, 0, 15 }, /* twr */
144 { 0, 0, 15 }, /* tmrd */
145 { 0, 0, 15 }, /* trp */
146 { 0, 0, 15 }, /* trcd */
149 static int apply_ram_timings(volatile unsigned short *memregs, void *data)
151 int *ram_timings = data;
154 for (i = 0; i < 7; i++)
156 ram_timings[i] += ram_ranges[i].adj;
157 if (ram_timings[i] < ram_ranges[i].min || ram_timings[i] > ram_ranges[i].max) {
158 fprintf(stderr, "pollux_set: invalid RAM timing %d\n", i);
163 val = memregs[0x14802>>1] & 0x0f00;
164 val |= (ram_timings[4] << 12) | (ram_timings[5] << 4) | ram_timings[6];
165 memregs[0x14802>>1] = val;
167 val = memregs[0x14804>>1] & 0x4000;
168 val |= (ram_timings[0] << 12) | (ram_timings[1] << 8) |
169 (ram_timings[2] << 4) | ram_timings[3];
171 memregs[0x14804>>1] = val;
173 for (i = 0; i < 0x100000 && (memregs[0x14804>>1] & 0x8000); i++)
179 static int apply_dpc_clkdiv0(volatile unsigned short *memregs, void *data)
181 int pcd = *(int *)data;
184 if ((pcd - 1) & ~0x3f) {
185 fprintf(stderr, "pollux_set: invalid lcd clkdiv0: %d\n", pcd);
189 pcd = (pcd - 1) & 0x3f;
190 tmp = memregs[0x31c4>>1];
191 memregs[0x31c4>>1] = (tmp & ~0x3f0) | (pcd << 4);
196 static int apply_cpuclk(volatile unsigned short *memregs, void *data)
198 volatile unsigned int *memregl = (volatile void *)memregs;
199 int mhz = *(int *)data;
200 int adiv, mdiv, pdiv, sdiv = 0;
203 // m = MDIV, p = PDIV, s = SDIV
204 #define SYS_CLK_FREQ 27
206 mdiv = (mhz * pdiv) / SYS_CLK_FREQ;
209 vf004 = (pdiv<<18) | (mdiv<<8) | sdiv;
211 // attempt to keep AHB the divider close to 250, but not higher
212 for (adiv = 1; mhz / adiv > 250; adiv++)
215 vf000 = memregl[0xf000>>2];
216 vf000 = (vf000 & ~0x3c0) | ((adiv - 1) << 6);
217 memregl[0xf000>>2] = vf000;
218 memregl[0xf004>>2] = vf004;
219 memregl[0xf07c>>2] |= 0x8000;
220 for (i = 0; (memregl[0xf07c>>2] & 0x8000) && i < 0x100000; i++)
223 printf("clock set to %dMHz, AHB set to %dMHz\n", mhz, mhz / adiv);
227 static int lcd_timings[8];
228 static int ram_timings[7];
229 static int dpc_clkdiv0;
232 static const char lcd_t_help[] = "htotal,hswidth,hastart,haend,vtotal,vswidth,vastart,vaend";
233 static const char ram_t_help[] = "CAS,tRC,tRAS,tWR,tMRD,tRP,tRCD";
235 static const struct {
238 int (*parse)(const char *str, void *data);
239 int (*apply)(volatile unsigned short *memregs, void *data);
243 { "lcd_timings", lcd_t_help, parse_lcd_timings, apply_lcd_timings, lcd_timings },
244 { "ram_timings", ram_t_help, parse_ram_timings, apply_ram_timings, ram_timings },
245 { "dpc_clkdiv0", "divider", parse_decimal, apply_dpc_clkdiv0, &dpc_clkdiv0 },
246 { "clkdiv0", "divider", parse_decimal, apply_dpc_clkdiv0, &dpc_clkdiv0 }, /* alias */
247 { "cpuclk", "MHZ", parse_decimal, apply_cpuclk, &cpuclk },
249 #define ALL_PARAM_COUNT (sizeof(all_params) / sizeof(all_params[0]))
252 * set timings based on preformated string
253 * returns 0 on success.
255 int pollux_set(volatile unsigned short *memregs, const char *str)
257 int parsed_params[ALL_PARAM_COUNT];
258 int applied_params[ALL_PARAM_COUNT];
259 int applied_something = 0;
266 memset(parsed_params, 0, sizeof(parsed_params));
267 memset(applied_params, 0, sizeof(applied_params));
273 while (*p == ';' || *p == ' ')
278 for (i = 0; i < ALL_PARAM_COUNT; i++)
280 int param_len = strlen(all_params[i].name);
281 if (strncmp(p, all_params[i].name, param_len) == 0 && p[param_len] == '=')
284 ret = all_params[i].parse(p, all_params[i].data);
286 fprintf(stderr, "pollux_set parser: error at %-10s\n", p);
287 fprintf(stderr, " valid format is: <%s>\n", all_params[i].help);
290 parsed_params[i] = 1;
296 /* Unknown param. Attempt to be forward compatible and ignore it. */
297 for (po = p; *p != 0 && *p != ';'; p++)
300 fprintf(stderr, "unhandled param: ");
301 fwrite(po, 1, p - po, stderr);
302 fprintf(stderr, "\n");
305 /* validate and apply */
306 for (i = 0; i < ALL_PARAM_COUNT; i++)
308 if (!parsed_params[i])
311 ret = all_params[i].apply(memregs, all_params[i].data);
313 fprintf(stderr, "pollux_set: failed to apply %s (bad value?)\n",
318 applied_something = 1;
319 applied_params[i] = 1;
322 if (applied_something)
326 for (i = c = 0; i < ALL_PARAM_COUNT; i++)
328 if (!applied_params[i])
332 printf("%s", all_params[i].name);
342 #include <sys/types.h>
343 #include <sys/stat.h>
345 #include <sys/mman.h>
348 static void usage(const char *binary)
351 printf("usage:\n%s <set_str[;set_str[;...]]>\n"
352 "set_str:\n", binary);
353 for (i = 0; i < ALL_PARAM_COUNT; i++)
354 printf(" %s=<%s>\n", all_params[i].name, all_params[i].help);
357 int main(int argc, char *argv[])
359 volatile unsigned short *memregs;
367 memdev = open("/dev/mem", O_RDWR);
370 perror("open(/dev/mem) failed");
374 memregs = mmap(0, 0x20000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000);
375 if (memregs == MAP_FAILED)
377 perror("mmap(memregs) failed");
382 ret = pollux_set(memregs, argv[1]);
384 munmap((void *)memregs, 0x20000);