gp2x+wiz binary support, wiz code wip
[libpicofe.git] / gp2x / soc_pollux.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <sys/mman.h>
9 #include <unistd.h>
10 #include <sys/ioctl.h>
11 #include <linux/fb.h>
12
13 #include "soc.h"
14 #include "plat_gp2x.h"
15 #include "../common/emu.h"
16 #include "../common/arm_utils.h"
17 #include "pollux_set.h"
18
19 static volatile unsigned short *memregs;
20 static volatile unsigned long  *memregl;
21 static int memdev = -1;
22
23 extern void *gp2x_screens[4];
24
25 #define fb_buf_count 4
26 static unsigned int fb_paddr[fb_buf_count];
27 static int fb_work_buf;
28 static int fbdev = -1;
29
30
31 /* video stuff */
32 static void pollux_video_flip(int buf_count)
33 {
34         memregl[0x406C>>2] = fb_paddr[fb_work_buf];
35         memregl[0x4058>>2] |= 0x10;
36         fb_work_buf++;
37         if (fb_work_buf >= buf_count)
38                 fb_work_buf = 0;
39         g_screen_ptr = gp2x_screens[fb_work_buf];
40 }
41
42 static void gp2x_video_flip_(void)
43 {
44         pollux_video_flip(fb_buf_count);
45 }
46
47 /* doulblebuffered flip */
48 static void gp2x_video_flip2_(void)
49 {
50         pollux_video_flip(2);
51 }
52
53 static void gp2x_video_changemode_ll_(int bpp)
54 {
55         int code = 0, bytes = 2;
56         unsigned int r;
57         switch (bpp)
58         {
59                 case 8:
60                         code = 0x443a;
61                         bytes = 1;
62                         break;
63
64                 case 15:
65                 case 16:
66                         code = 0x4432;
67                         bytes = 2;
68                         break;
69
70                 default:
71                         printf("unhandled bpp request: %d\n", bpp);
72                         return;
73         }
74
75         memregl[0x405c>>2] = bytes;
76         memregl[0x4060>>2] = bytes * 320;
77
78         r = memregl[0x4058>>2];
79         r = (r & 0xffff) | (code << 16) | 0x10;
80         memregl[0x4058>>2] = r;
81 }
82
83 static void gp2x_video_setpalette_(int *pal, int len)
84 {
85         /* pollux palette is 16bpp only.. */
86         int i;
87         for (i = 0; i < len; i++)
88         {
89                 int c = pal[i];
90                 c = ((c >> 8) & 0xf800) | ((c >> 5) & 0x07c0) | ((c >> 3) & 0x001f);
91                 memregl[0x4070>>2] = (i << 24) | c;
92         }
93 }
94
95 static void gp2x_video_RGB_setscaling_(int ln_offs, int W, int H)
96 {
97         /* maybe a job for 3d hardware? */
98 }
99
100 static void gp2x_video_wait_vsync_(void)
101 {
102         while (!(memregl[0x308c>>2] & (1 << 10)));
103                 spend_cycles(128);
104         memregl[0x308c>>2] |= 1 << 10;
105 }
106
107 /* CPU clock */
108 static void gp2x_set_cpuclk_(unsigned int mhz)
109 {
110         char buff[24];
111         snprintf(buff, sizeof(buff), "cpuclk=%u", mhz);
112         pollux_set(memregs, buff);
113 }
114
115 /* misc */
116 static void pollux_set_fromenv(const char *env_var)
117 {
118         const char *set_string;
119         set_string = getenv(env_var);
120         if (set_string)
121                 pollux_set(memregs, set_string);
122         else
123                 printf("env var %s not defined.\n", env_var);
124 }
125
126 /* RAM timings */
127 static unsigned short memtimex[2];
128
129 static void set_ram_timings_(void)
130 {
131         pollux_set_fromenv("POLLUX_RAM_TIMINGS");
132 }
133
134 static void unset_ram_timings_(void)
135 {
136         int i;
137
138         memregs[0x14802>>1] = memtimex[0];
139         memregs[0x14804>>1] = memtimex[1] | 0x8000;
140
141         for (i = 0; i < 0x100000; i++)
142                 if (!(memregs[0x14804>>1] & 0x8000))
143                         break;
144
145         printf("RAM timings reset to startup values.\n");
146 }
147
148 /* LCD refresh */
149 static void set_lcd_custom_rate_(int is_pal)
150 {
151         char buff[32];
152
153         snprintf(buff, sizeof(buff), "POLLUX_LCD_TIMINGS_%s", is_pal ? "PAL" : "NTSC");
154         pollux_set_fromenv(buff);
155 }
156
157 static void unset_lcd_custom_rate_(void)
158 {
159 }
160
161 static void set_lcd_gamma_(int g100, int A_SNs_curve)
162 {
163         /* hm, the LCD possibly can do it (but not POLLUX) */
164 }
165
166 void pollux_init(void)
167 {
168         struct fb_fix_screeninfo fbfix;
169         int i, ret;
170
171         memdev = open("/dev/mem", O_RDWR);
172         if (memdev == -1) {
173                 perror("open(/dev/mem) failed");
174                 exit(1);
175         }
176
177         memregs = mmap(0, 0x20000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000);
178         if (memregs == MAP_FAILED) {
179                 perror("mmap(memregs) failed");
180                 exit(1);
181         }
182         memregl = (volatile void *)memregs;
183
184         fbdev = open("/dev/fb0", O_RDWR);
185         if (fbdev < 0) {
186                 perror("can't open fbdev");
187                 exit(1);
188         }
189
190         ret = ioctl(fbdev, FBIOGET_FSCREENINFO, &fbfix);
191         if (ret == -1) {
192                 perror("ioctl(fbdev) failed");
193                 exit(1);
194         }
195
196         printf("framebuffer: \"%s\" @ %08lx\n", fbfix.id, fbfix.smem_start);
197         fb_paddr[0] = fbfix.smem_start;
198
199         gp2x_screens[0] = mmap(0, 320*240*2*fb_buf_count, PROT_READ|PROT_WRITE,
200                         MAP_SHARED, memdev, fb_paddr[0]);
201         if (gp2x_screens[0] == MAP_FAILED)
202         {
203                 perror("mmap(gp2x_screens) failed");
204                 exit(1);
205         }
206         memset(gp2x_screens[0], 0, 320*240*2*fb_buf_count);
207
208         printf("  %p -> %08x\n", gp2x_screens[0], fb_paddr[0]);
209         for (i = 1; i < fb_buf_count; i++)
210         {
211                 fb_paddr[i] = fb_paddr[i-1] + 320*240*2;
212                 gp2x_screens[i] = (char *)gp2x_screens[i-1] + 320*240*2;
213                 printf("  %p -> %08x\n", gp2x_screens[i], fb_paddr[i]);
214         }
215         fb_work_buf = 0;
216         g_screen_ptr = gp2x_screens[0];
217
218         memtimex[0] = memregs[0x14802>>1];
219         memtimex[1] = memregs[0x14804>>1];
220
221         gp2x_video_flip = gp2x_video_flip_;
222         gp2x_video_flip2 = gp2x_video_flip2_;
223         gp2x_video_changemode_ll = gp2x_video_changemode_ll_;
224         gp2x_video_setpalette = gp2x_video_setpalette_;
225         gp2x_video_RGB_setscaling = gp2x_video_RGB_setscaling_;
226         gp2x_video_wait_vsync = gp2x_video_wait_vsync_;
227
228         gp2x_set_cpuclk = gp2x_set_cpuclk_;
229
230         set_lcd_custom_rate = set_lcd_custom_rate_;
231         unset_lcd_custom_rate = unset_lcd_custom_rate_;
232         set_lcd_gamma = set_lcd_gamma_;
233
234         set_ram_timings = set_ram_timings_;
235         unset_ram_timings = unset_ram_timings_;
236 }
237
238 void pollux_finish(void)
239 {
240         /* switch to default fb mem, turn portrait off */
241         memregl[0x406C>>2] = fb_paddr[0];
242         memregl[0x4058>>2] |= 0x10;
243 //      wiz_lcd_set_portrait(0);
244         close(fbdev);
245
246         munmap((void *)memregs, 0x20000);
247         close(memdev);
248 }
249