pollux_set.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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. #include <stdio.h>
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include "pollux_set.h"
  46. /* parse stuff */
  47. static int parse_lcd_timings(const char *str, void *data)
  48. {
  49. int *lcd_timings = data;
  50. const char *p = str;
  51. int ret, c;
  52. ret = sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d",
  53. &lcd_timings[0], &lcd_timings[1], &lcd_timings[2], &lcd_timings[3],
  54. &lcd_timings[4], &lcd_timings[5], &lcd_timings[6], &lcd_timings[7]);
  55. if (ret != 8)
  56. return -1;
  57. /* skip seven commas */
  58. for (c = 0; c < 7 && *p != 0; p++)
  59. if (*p == ',')
  60. c++;
  61. if (c != 7)
  62. return -1;
  63. /* skip last number */
  64. while ('0' <= *p && *p <= '9')
  65. p++;
  66. return p - str;
  67. }
  68. static int parse_ram_timings(const char *str, void *data)
  69. {
  70. int *ram_timings = data;
  71. const char *p = str;
  72. int ret, c;
  73. float cas;
  74. ret = sscanf(p, "%f,%d,%d,%d,%d,%d,%d",
  75. &cas, &ram_timings[1], &ram_timings[2], &ram_timings[3],
  76. &ram_timings[4], &ram_timings[5], &ram_timings[6]);
  77. if (ret != 7)
  78. return -1;
  79. if (cas == 2)
  80. ram_timings[0] = 1;
  81. else if (cas == 2.5)
  82. ram_timings[0] = 2;
  83. else if (cas == 3)
  84. ram_timings[0] = 3;
  85. else
  86. return -1;
  87. for (c = 0; c < 6 && *p != 0; p++)
  88. if (*p == ',')
  89. c++;
  90. if (c != 6)
  91. return -1;
  92. while ('0' <= *p && *p <= '9')
  93. p++;
  94. return p - str;
  95. }
  96. static int parse_decimal(const char *str, void *data)
  97. {
  98. char *ep;
  99. *(int *)data = strtoul(str, &ep, 10);
  100. if (ep == str)
  101. return -1;
  102. return ep - str;
  103. }
  104. /* validate and apply stuff */
  105. static int apply_lcd_timings(volatile unsigned short *memregs, void *data)
  106. {
  107. int *lcd_timings = data;
  108. int i;
  109. for (i = 0; i < 8; i++) {
  110. if (lcd_timings[i] & ~0xffff) {
  111. fprintf(stderr, "pollux_set: invalid lcd timing %d: %d\n", i, lcd_timings[i]);
  112. return -1;
  113. }
  114. }
  115. for (i = 0; i < 8; i++)
  116. memregs[(0x307c>>1) + i] = lcd_timings[i];
  117. return 0;
  118. }
  119. static const struct {
  120. signed char adj; /* how to adjust value passed by user */
  121. signed short min; /* range of */
  122. signed short max; /* allowed values (inclusive) */
  123. }
  124. ram_ranges[] = {
  125. { 0, 1, 3 }, /* cas (cl) */
  126. { -2, 0, 15 }, /* trc */
  127. { -2, 0, 15 }, /* tras */
  128. { 0, 0, 15 }, /* twr */
  129. { 0, 0, 15 }, /* tmrd */
  130. { 0, 0, 15 }, /* trp */
  131. { 0, 0, 15 }, /* trcd */
  132. };
  133. static int apply_ram_timings(volatile unsigned short *memregs, void *data)
  134. {
  135. int *ram_timings = data;
  136. int i, val;
  137. for (i = 0; i < 7; i++)
  138. {
  139. ram_timings[i] += ram_ranges[i].adj;
  140. if (ram_timings[i] < ram_ranges[i].min || ram_timings[i] > ram_ranges[i].max) {
  141. fprintf(stderr, "pollux_set: invalid RAM timing %d\n", i);
  142. return -1;
  143. }
  144. }
  145. val = memregs[0x14802>>1] & 0x0f00;
  146. val |= (ram_timings[4] << 12) | (ram_timings[5] << 4) | ram_timings[6];
  147. memregs[0x14802>>1] = val;
  148. val = memregs[0x14804>>1] & 0x4000;
  149. val |= (ram_timings[0] << 12) | (ram_timings[1] << 8) |
  150. (ram_timings[2] << 4) | ram_timings[3];
  151. val |= 0x8000;
  152. memregs[0x14804>>1] = val;
  153. for (i = 0; i < 0x100000 && (memregs[0x14804>>1] & 0x8000); i++)
  154. ;
  155. return 0;
  156. }
  157. static int apply_dpc_clkdiv0(volatile unsigned short *memregs, void *data)
  158. {
  159. int pcd = *(int *)data;
  160. int tmp;
  161. if ((pcd - 1) & ~0x3f) {
  162. fprintf(stderr, "pollux_set: invalid lcd clkdiv0: %d\n", pcd);
  163. return -1;
  164. }
  165. pcd = (pcd - 1) & 0x3f;
  166. tmp = memregs[0x31c4>>1];
  167. memregs[0x31c4>>1] = (tmp & ~0x3f0) | (pcd << 4);
  168. return 0;
  169. }
  170. static int apply_cpuclk(volatile unsigned short *memregs, void *data)
  171. {
  172. volatile unsigned int *memregl = (volatile void *)memregs;
  173. int mhz = *(int *)data;
  174. int adiv, mdiv, pdiv, sdiv = 0;
  175. int i, vf000, vf004;
  176. // m = MDIV, p = PDIV, s = SDIV
  177. #define SYS_CLK_FREQ 27
  178. pdiv = 9;
  179. mdiv = (mhz * pdiv) / SYS_CLK_FREQ;
  180. if (mdiv & ~0x3ff)
  181. return -1;
  182. vf004 = (pdiv<<18) | (mdiv<<8) | sdiv;
  183. // attempt to keep AHB the divider close to 250, but not higher
  184. for (adiv = 1; mhz / adiv > 250; adiv++)
  185. ;
  186. vf000 = memregl[0xf000>>2];
  187. vf000 = (vf000 & ~0x3c0) | ((adiv - 1) << 6);
  188. memregl[0xf000>>2] = vf000;
  189. memregl[0xf004>>2] = vf004;
  190. memregl[0xf07c>>2] |= 0x8000;
  191. for (i = 0; (memregl[0xf07c>>2] & 0x8000) && i < 0x100000; i++)
  192. ;
  193. printf("clock set to %dMHz, AHB set to %dMHz\n", mhz, mhz / adiv);
  194. return 0;
  195. }
  196. static int lcd_timings[8];
  197. static int ram_timings[7];
  198. static int dpc_clkdiv0;
  199. static int cpuclk;
  200. static const char lcd_t_help[] = "htotal,hswidth,hastart,haend,vtotal,vswidth,vastart,vaend";
  201. static const char ram_t_help[] = "CAS,tRC,tRAS,tWR,tMRD,tRP,tRCD";
  202. static const struct {
  203. const char *name;
  204. const char *help;
  205. int (*parse)(const char *str, void *data);
  206. int (*apply)(volatile unsigned short *memregs, void *data);
  207. void *data;
  208. }
  209. all_params[] = {
  210. { "lcd_timings", lcd_t_help, parse_lcd_timings, apply_lcd_timings, lcd_timings },
  211. { "ram_timings", ram_t_help, parse_ram_timings, apply_ram_timings, ram_timings },
  212. { "dpc_clkdiv0", "divider", parse_decimal, apply_dpc_clkdiv0, &dpc_clkdiv0 },
  213. { "clkdiv0", "divider", parse_decimal, apply_dpc_clkdiv0, &dpc_clkdiv0 }, /* alias */
  214. { "cpuclk", "MHZ", parse_decimal, apply_cpuclk, &cpuclk },
  215. };
  216. #define ALL_PARAM_COUNT (sizeof(all_params) / sizeof(all_params[0]))
  217. /*
  218. * set timings based on preformated string
  219. * returns 0 on success.
  220. */
  221. int pollux_set(volatile unsigned short *memregs, const char *str)
  222. {
  223. int parsed_params[ALL_PARAM_COUNT];
  224. int applied_params[ALL_PARAM_COUNT];
  225. int applied_something = 0;
  226. const char *p, *po;
  227. int i, ret;
  228. if (str == NULL)
  229. return -1;
  230. memset(parsed_params, 0, sizeof(parsed_params));
  231. memset(applied_params, 0, sizeof(applied_params));
  232. p = str;
  233. while (1)
  234. {
  235. again:
  236. while (*p == ';' || *p == ' ')
  237. p++;
  238. if (*p == 0)
  239. break;
  240. for (i = 0; i < ALL_PARAM_COUNT; i++)
  241. {
  242. int param_len = strlen(all_params[i].name);
  243. if (strncmp(p, all_params[i].name, param_len) == 0 && p[param_len] == '=')
  244. {
  245. p += param_len + 1;
  246. ret = all_params[i].parse(p, all_params[i].data);
  247. if (ret < 0) {
  248. fprintf(stderr, "pollux_set parser: error at %-10s\n", p);
  249. fprintf(stderr, " valid format is: <%s>\n", all_params[i].help);
  250. return -1;
  251. }
  252. parsed_params[i] = 1;
  253. p += ret;
  254. goto again;
  255. }
  256. }
  257. /* Unknown param. Attempt to be forward compatible and ignore it. */
  258. for (po = p; *p != 0 && *p != ';'; p++)
  259. ;
  260. fprintf(stderr, "unhandled param: ");
  261. fwrite(po, 1, p - po, stderr);
  262. fprintf(stderr, "\n");
  263. }
  264. /* validate and apply */
  265. for (i = 0; i < ALL_PARAM_COUNT; i++)
  266. {
  267. if (!parsed_params[i])
  268. continue;
  269. ret = all_params[i].apply(memregs, all_params[i].data);
  270. if (ret < 0) {
  271. fprintf(stderr, "pollux_set: failed to apply %s (bad value?)\n",
  272. all_params[i].name);
  273. continue;
  274. }
  275. applied_something = 1;
  276. applied_params[i] = 1;
  277. }
  278. if (applied_something)
  279. {
  280. int c;
  281. printf("applied: ");
  282. for (i = c = 0; i < ALL_PARAM_COUNT; i++)
  283. {
  284. if (!applied_params[i])
  285. continue;
  286. if (c != 0)
  287. printf(", ");
  288. printf("%s", all_params[i].name);
  289. c++;
  290. }
  291. printf("\n");
  292. }
  293. return 0;
  294. }
  295. #ifdef BINARY
  296. #include <sys/types.h>
  297. #include <sys/stat.h>
  298. #include <fcntl.h>
  299. #include <sys/mman.h>
  300. #include <unistd.h>
  301. static void usage(const char *binary)
  302. {
  303. int i;
  304. printf("usage:\n%s <set_str[;set_str[;...]]>\n"
  305. "set_str:\n", binary);
  306. for (i = 0; i < ALL_PARAM_COUNT; i++)
  307. printf(" %s=<%s>\n", all_params[i].name, all_params[i].help);
  308. }
  309. int main(int argc, char *argv[])
  310. {
  311. volatile unsigned short *memregs;
  312. int ret, memdev;
  313. if (argc != 2) {
  314. usage(argv[0]);
  315. return 1;
  316. }
  317. memdev = open("/dev/mem", O_RDWR);
  318. if (memdev == -1)
  319. {
  320. perror("open(/dev/mem) failed");
  321. return 1;
  322. }
  323. memregs = mmap(0, 0x20000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000);
  324. if (memregs == MAP_FAILED)
  325. {
  326. perror("mmap(memregs) failed");
  327. close(memdev);
  328. return 1;
  329. }
  330. ret = pollux_set(memregs, argv[1]);
  331. munmap((void *)memregs, 0x20000);
  332. close(memdev);
  333. return ret;
  334. }
  335. #endif