pollux_dpc_set integrated
authornotaz <notaz@pixelinis>
Wed, 24 Jun 2009 18:18:37 +0000 (21:18 +0300)
committernotaz <notaz@pixelinis>
Wed, 24 Jun 2009 18:18:37 +0000 (21:18 +0300)
gp2x/Makefile
gp2x/gp2x.c
gp2x/pollux_dpc_set.c [new file with mode: 0644]
gp2x/pollux_dpc_set.h [new file with mode: 0644]

index 376970b..ed01178 100644 (file)
@@ -12,6 +12,7 @@ OBJS      = main.o cpu.o memory.u video.o input.o sound.o gp2x.o gui.o        \
             cheats.o zip.o cpu_threaded.z arm_stub.o video_blend.o            \
             warm.o upscale_aspect.o
 ifeq ($(WIZ),1)
+OBJS      += pollux_dpc_set.o
 BIN       = gpsp_wiz
 else
 BIN       = gpsp_gp2x
index 6d9f82e..41e3f8b 100644 (file)
@@ -29,6 +29,7 @@
 #include "../common.h"
 #include "gp2x.h"
 #include "warm.h"
+#include "pollux_dpc_set.h"
 
 u32 gp2x_audio_volume = 74/2;
 u32 gpsp_gp2x_dev_audio = 0;
@@ -124,6 +125,9 @@ void wiz_lcd_set_portrait(int y)
   gpsp_gp2x_memregl[0x4004>>2] = y ? 0x013f00ef : 0x00ef013f;
   gpsp_gp2x_memregl[0x4000>>2] |= 1 << 3;
   old_y = y;
+
+  /* the above ioctl resets LCD timings, so set them here */
+  pollux_dpc_set(gpsp_gp2x_memregs, getenv("pollux_dpc_set"));
 }
 
 static void fb_video_exit()
diff --git a/gp2x/pollux_dpc_set.c b/gp2x/pollux_dpc_set.c
new file mode 100644 (file)
index 0000000..beddc21
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * quick tool to set LCD timings for Wiz
+ * (c) notaz, 2009
+ * code dedicated to public domain.
+ *
+ * HTOTAL:    X VTOTAL:  341
+ * HSWIDTH:   1 VSWIDTH:   0
+ * HASTART:  37 VASTART:  17
+ * HAEND:   277 VAEND:   337
+ *
+ * 120Hz
+ * pcd  8, 447: + 594us
+ * pcd  9, 397: +  36us
+ * pcd 10, 357: - 523us
+ * pcd 11, 325: +1153us
+ *
+ * 'lcd_timings=397,1,37,277,341,0,17,337;clkdiv0=9'
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pollux_dpc_set.h"
+
+/*
+ * set LCD timings based on preformated string (see usage() below for params).
+ * returns 0 on success.
+ */
+int pollux_dpc_set(volatile unsigned short *memregs, const char *str)
+{
+       int timings[8], have_timings = 0;
+       int pcd = 0, have_pcd = 0;
+       const char *p;
+       int i, ret;
+
+       if (str == NULL)
+               return -1;
+
+       p = str;
+       while (1)
+       {
+               if (strncmp(p, "lcd_timings=", 12) == 0)
+               {
+                       int c;
+                       p += 12;
+                       ret = sscanf(p, "%d,%d,%d,%d,%d,%d,%d,%d",
+                               &timings[0], &timings[1], &timings[2], &timings[3],
+                               &timings[4], &timings[5], &timings[6], &timings[7]);
+                       if (ret != 8)
+                               break;
+                       /* skip seven commas */
+                       for (c = 0; c < 7 && *p != 0; p++)
+                               if (*p == ',')
+                                               c++;
+                       if (c != 7)
+                               break;
+                       /* skip last number */
+                       while ('0' <= *p && *p <= '9')
+                               p++;
+                       have_timings = 1;
+               }
+               else if (strncmp(p, "clkdiv0=", 8) == 0)
+               {
+                       char *ep;
+                       p += 8;
+                       pcd = strtoul(p, &ep, 10);
+                       if (p == ep)
+                               break;
+                       p = ep;
+                       have_pcd = 1;
+               }
+               else
+                       break;
+
+               while (*p == ';' || *p == ' ')
+                       p++;
+               if (*p == 0)
+                       goto parse_done;
+       }
+
+       fprintf(stderr, "dpc_set parser: error at '%s'\n", p);
+       return -1;
+
+parse_done:
+       /* some validation */
+       if (have_timings)
+       {
+               for (i = 0; i < 8; i++)
+                       if (timings[i] & ~0xffff) {
+                               fprintf(stderr, "dpc_set: invalid timing %d: %d\n", i, timings[i]);
+                               return -1;
+                       }
+       }
+
+       if (have_pcd)
+       {
+               if ((pcd - 1) & ~0x3f) {
+                       fprintf(stderr, "dpc_set: invalid clkdiv0: %d\n", pcd);
+                       return -1;
+               }
+       }
+
+       /* write */
+       if (have_timings)
+       {
+               for (i = 0; i < 8; i++)
+                       memregs[(0x307c>>1) + i] = timings[i];
+       }
+
+       if (have_pcd)
+       {
+               int tmp;
+               pcd = (pcd - 1) & 0x3f;
+               tmp = memregs[0x31c4>>1];
+               memregs[0x31c4>>1] = (tmp & ~0x3f0) | (pcd << 4);
+       }
+
+       return 0;
+}
+
+#ifdef BINARY
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+static void usage(const char *binary)
+{
+       printf("usage:\n%s <set_str[;set_str[;...]]>\n"
+               "set_str:\n"
+               "  lcd_timings=<htotal,hswidth,hastart,haend,vtotal,vswidth,vastart,vaend>\n"
+               "  clkdiv0=<divider>\n", binary);
+}
+
+int main(int argc, char *argv[])
+{
+       volatile unsigned short *memregs;
+       int ret, memdev;
+
+       if (argc != 2) {
+               usage(argv[0]);
+               return 1;
+       }
+
+       memdev = open("/dev/mem", O_RDWR);
+       if (memdev == -1)
+       {
+               perror("open(/dev/mem) failed");
+               return 1;
+       }
+
+       memregs = mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000);
+       if (memregs == MAP_FAILED)
+       {
+               perror("mmap(memregs) failed");
+               close(memdev);
+               return 1;
+       }
+
+       ret = pollux_dpc_set(memregs, argv[1]);
+
+       munmap((void *)memregs, 0x10000);
+       close(memdev);
+
+       return ret;
+}
+#endif
diff --git a/gp2x/pollux_dpc_set.h b/gp2x/pollux_dpc_set.h
new file mode 100644 (file)
index 0000000..53155d1
--- /dev/null
@@ -0,0 +1,10 @@
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+int pollux_dpc_set(volatile unsigned short *memregs, const char *str);
+
+#ifdef __cplusplus
+}
+#endif