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