32x: drc: new smc handling, write handlers adjusted.
[picodrive.git] / platform / gp2x / soc_pollux.c
... / ...
CommitLineData
1/*
2 * <random_info=mem_map>
3 * 00000000-029fffff linux (42MB)
4 * 02a00000-02dfffff fb (4MB, 153600B really used)
5 * 02e00000-02ffffff sound dma (2MB)
6 * 03000000-03ffffff MPEGDEC (?, 16MB)
7 * </random_info>
8 */
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <math.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <fcntl.h>
16#include <sys/mman.h>
17#include <unistd.h>
18#include <sys/ioctl.h>
19#include <linux/fb.h>
20
21#include "soc.h"
22#include "plat_gp2x.h"
23#include "../common/emu.h"
24#include "../common/arm_utils.h"
25#include "pollux_set.h"
26
27static volatile unsigned short *memregs;
28static volatile unsigned long *memregl;
29static int memdev = -1;
30static int battdev = -1;
31
32extern void *gp2x_screens[4];
33
34#define fb_buf_count 4
35static unsigned int fb_paddr[fb_buf_count];
36static int fb_work_buf;
37static int fbdev = -1;
38
39static char cpuclk_was_changed = 0;
40static unsigned short memtimex_old[2];
41static unsigned int pllsetreg0;
42static int last_pal_setting = 0;
43
44
45/* misc */
46static void pollux_set_fromenv(const char *env_var)
47{
48 const char *set_string;
49 set_string = getenv(env_var);
50 if (set_string)
51 pollux_set(memregs, set_string);
52 else
53 printf("env var %s not defined.\n", env_var);
54}
55
56/* video stuff */
57static void pollux_video_flip(int buf_count)
58{
59 memregl[0x406C>>2] = fb_paddr[fb_work_buf];
60 memregl[0x4058>>2] |= 0x10;
61 fb_work_buf++;
62 if (fb_work_buf >= buf_count)
63 fb_work_buf = 0;
64 g_screen_ptr = gp2x_screens[fb_work_buf];
65}
66
67static void gp2x_video_flip_(void)
68{
69 pollux_video_flip(fb_buf_count);
70}
71
72/* doulblebuffered flip */
73static void gp2x_video_flip2_(void)
74{
75 pollux_video_flip(2);
76}
77
78static void gp2x_video_changemode_ll_(int bpp)
79{
80 static int prev_bpp = 0;
81 int code = 0, bytes = 2;
82 int rot_cmd[2] = { 0, 0 };
83 unsigned int r;
84 char buff[32];
85 int ret;
86
87 if (bpp == prev_bpp)
88 return;
89 prev_bpp = bpp;
90
91 printf("changemode: %dbpp rot=%d\n", abs(bpp), bpp < 0);
92
93 /* negative bpp means rotated mode */
94 rot_cmd[0] = (bpp < 0) ? 6 : 5;
95 ret = ioctl(fbdev, _IOW('D', 90, int[2]), rot_cmd);
96 if (ret < 0)
97 perror("rot ioctl failed");
98 memregl[0x4004>>2] = (bpp < 0) ? 0x013f00ef : 0x00ef013f;
99 memregl[0x4000>>2] |= 1 << 3;
100
101 /* the above ioctl resets LCD timings, so set them here */
102 snprintf(buff, sizeof(buff), "POLLUX_LCD_TIMINGS_%s", last_pal_setting ? "PAL" : "NTSC");
103 pollux_set_fromenv(buff);
104
105 switch (abs(bpp))
106 {
107 case 8:
108 code = 0x443a;
109 bytes = 1;
110 break;
111
112 case 15:
113 case 16:
114 code = 0x4432;
115 bytes = 2;
116 break;
117
118 default:
119 printf("unhandled bpp request: %d\n", abs(bpp));
120 return;
121 }
122
123 memregl[0x405c>>2] = bytes;
124 memregl[0x4060>>2] = bytes * (bpp < 0 ? 240 : 320);
125
126 r = memregl[0x4058>>2];
127 r = (r & 0xffff) | (code << 16) | 0x10;
128 memregl[0x4058>>2] = r;
129}
130
131static void gp2x_video_setpalette_(int *pal, int len)
132{
133 /* pollux palette is 16bpp only.. */
134 int i;
135 for (i = 0; i < len; i++)
136 {
137 int c = pal[i];
138 c = ((c >> 8) & 0xf800) | ((c >> 5) & 0x07c0) | ((c >> 3) & 0x001f);
139 memregl[0x4070>>2] = (i << 24) | c;
140 }
141}
142
143static void gp2x_video_RGB_setscaling_(int ln_offs, int W, int H)
144{
145 /* maybe a job for 3d hardware? */
146}
147
148static void gp2x_video_wait_vsync_(void)
149{
150 while (!(memregl[0x308c>>2] & (1 << 10)));
151 spend_cycles(128);
152 memregl[0x308c>>2] |= 1 << 10;
153}
154
155/* CPU clock */
156static void gp2x_set_cpuclk_(unsigned int mhz)
157{
158 char buff[24];
159 snprintf(buff, sizeof(buff), "cpuclk=%u", mhz);
160 pollux_set(memregs, buff);
161
162 cpuclk_was_changed = 1;
163}
164
165/* RAM timings */
166static void set_ram_timings_(void)
167{
168 pollux_set_fromenv("POLLUX_RAM_TIMINGS");
169}
170
171static void unset_ram_timings_(void)
172{
173 int i;
174
175 memregs[0x14802>>1] = memtimex_old[0];
176 memregs[0x14804>>1] = memtimex_old[1] | 0x8000;
177
178 for (i = 0; i < 0x100000; i++)
179 if (!(memregs[0x14804>>1] & 0x8000))
180 break;
181
182 printf("RAM timings reset to startup values.\n");
183}
184
185/* LCD refresh */
186static void set_lcd_custom_rate_(int is_pal)
187{
188 /* just remember PAL/NTSC. We always set timings in _changemode_ll() */
189 last_pal_setting = is_pal;
190}
191
192static void unset_lcd_custom_rate_(void)
193{
194}
195
196static void set_lcd_gamma_(int g100, int A_SNs_curve)
197{
198 /* hm, the LCD possibly can do it (but not POLLUX) */
199}
200
201static int gp2x_read_battery_(void)
202{
203 unsigned short magic_val = 0;
204
205 if (battdev < 0)
206 return -1;
207 if (read(battdev, &magic_val, sizeof(magic_val)) != sizeof(magic_val))
208 return -1;
209 switch (magic_val) {
210 default:
211 case 1: return 100;
212 case 2: return 66;
213 case 3: return 40;
214 case 4: return 0;
215 }
216}
217
218#define TIMER_BASE3 0x1980
219#define TIMER_REG(x) memregl[(TIMER_BASE3 + x) >> 2]
220
221unsigned int gp2x_get_ticks_us_(void)
222{
223 TIMER_REG(0x08) = 0x4b; /* run timer, latch value */
224 return TIMER_REG(0);
225}
226
227unsigned int gp2x_get_ticks_ms_(void)
228{
229 /* approximate /= 1000 */
230 unsigned long long v64;
231 v64 = (unsigned long long)gp2x_get_ticks_us_() * 4294968;
232 return v64 >> 32;
233}
234
235static void timer_cleanup(void)
236{
237 TIMER_REG(0x40) = 0x0c; /* be sure clocks are on */
238 TIMER_REG(0x08) = 0x23; /* stop the timer, clear irq in case it's pending */
239 TIMER_REG(0x00) = 0; /* clear counter */
240 TIMER_REG(0x40) = 0; /* clocks off */
241 TIMER_REG(0x44) = 0; /* dividers back to default */
242}
243
244void pollux_init(void)
245{
246 struct fb_fix_screeninfo fbfix;
247 int i, ret;
248
249 memdev = open("/dev/mem", O_RDWR);
250 if (memdev == -1) {
251 perror("open(/dev/mem) failed");
252 exit(1);
253 }
254
255 memregs = mmap(0, 0x20000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000);
256 if (memregs == MAP_FAILED) {
257 perror("mmap(memregs) failed");
258 exit(1);
259 }
260 memregl = (volatile void *)memregs;
261
262 fbdev = open("/dev/fb0", O_RDWR);
263 if (fbdev < 0) {
264 perror("can't open fbdev");
265 exit(1);
266 }
267
268 ret = ioctl(fbdev, FBIOGET_FSCREENINFO, &fbfix);
269 if (ret == -1) {
270 perror("ioctl(fbdev) failed");
271 exit(1);
272 }
273
274 printf("framebuffer: \"%s\" @ %08lx\n", fbfix.id, fbfix.smem_start);
275 fb_paddr[0] = fbfix.smem_start;
276
277 gp2x_screens[0] = mmap(0, 320*240*2*fb_buf_count, PROT_READ|PROT_WRITE,
278 MAP_SHARED, memdev, fb_paddr[0]);
279 if (gp2x_screens[0] == MAP_FAILED)
280 {
281 perror("mmap(gp2x_screens) failed");
282 exit(1);
283 }
284 memset(gp2x_screens[0], 0, 320*240*2*fb_buf_count);
285
286 printf(" %p -> %08x\n", gp2x_screens[0], fb_paddr[0]);
287 for (i = 1; i < fb_buf_count; i++)
288 {
289 fb_paddr[i] = fb_paddr[i-1] + 320*240*2;
290 gp2x_screens[i] = (char *)gp2x_screens[i-1] + 320*240*2;
291 printf(" %p -> %08x\n", gp2x_screens[i], fb_paddr[i]);
292 }
293 fb_work_buf = 0;
294 g_screen_ptr = gp2x_screens[0];
295
296 battdev = open("/dev/pollux_batt", O_RDONLY);
297 if (battdev < 0)
298 perror("Warning: could't open pollux_batt");
299
300 /* setup timer */
301 if (TIMER_REG(0x08) & 8)
302 timer_cleanup();
303
304 TIMER_REG(0x44) = 0x922; /* using PLL1, divider value 147 */
305 TIMER_REG(0x40) = 0x0c; /* clocks on */
306 TIMER_REG(0x08) = 0x6b; /* run timer, clear irq, latch value */
307
308 pllsetreg0 = memregl[0xf004>>2];
309 memtimex_old[0] = memregs[0x14802>>1];
310 memtimex_old[1] = memregs[0x14804>>1];
311
312 gp2x_video_flip = gp2x_video_flip_;
313 gp2x_video_flip2 = gp2x_video_flip2_;
314 gp2x_video_changemode_ll = gp2x_video_changemode_ll_;
315 gp2x_video_setpalette = gp2x_video_setpalette_;
316 gp2x_video_RGB_setscaling = gp2x_video_RGB_setscaling_;
317 gp2x_video_wait_vsync = gp2x_video_wait_vsync_;
318
319 gp2x_set_cpuclk = gp2x_set_cpuclk_;
320
321 set_lcd_custom_rate = set_lcd_custom_rate_;
322 unset_lcd_custom_rate = unset_lcd_custom_rate_;
323 set_lcd_gamma = set_lcd_gamma_;
324
325 set_ram_timings = set_ram_timings_;
326 unset_ram_timings = unset_ram_timings_;
327 gp2x_read_battery = gp2x_read_battery_;
328
329 gp2x_get_ticks_ms = gp2x_get_ticks_ms_;
330 gp2x_get_ticks_us = gp2x_get_ticks_us_;
331}
332
333void pollux_finish(void)
334{
335 /* switch to default fb mem, turn portrait off */
336 memregl[0x406C>>2] = fb_paddr[0];
337 memregl[0x4058>>2] |= 0x10;
338 close(fbdev);
339
340 gp2x_video_changemode_ll_(16);
341 unset_ram_timings_();
342 if (cpuclk_was_changed) {
343 memregl[0xf004>>2] = pllsetreg0;
344 memregl[0xf07c>>2] |= 0x8000;
345 }
346
347 munmap((void *)memregs, 0x20000);
348 close(memdev);
349 if (battdev >= 0)
350 close(battdev);
351}
352