summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525/sansa-fuze/lcd-fuze.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/as3525/sansa-fuze/lcd-fuze.c')
-rw-r--r--firmware/target/arm/as3525/sansa-fuze/lcd-fuze.c449
1 files changed, 449 insertions, 0 deletions
diff --git a/firmware/target/arm/as3525/sansa-fuze/lcd-fuze.c b/firmware/target/arm/as3525/sansa-fuze/lcd-fuze.c
new file mode 100644
index 0000000000..ff62949dcd
--- /dev/null
+++ b/firmware/target/arm/as3525/sansa-fuze/lcd-fuze.c
@@ -0,0 +1,449 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 by Dave Chapman
11 *
12 * LCD driver for the Sansa Fuze - controller unknown
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23#include "config.h"
24
25#include "cpu.h"
26#include "lcd.h"
27
28static bool display_on = false; /* is the display turned on? */
29static bool display_flipped = false;
30static int xoffset = 20; /* needed for flip */
31
32/* TODO: Implement this function */
33static void lcd_delay(int x)
34{
35 /* This is just arbitrary - the OF does something more complex */
36 x *= 1024;
37 while (x--);
38}
39
40static void as3525_dbop_init(void)
41{
42 CGU_DBOP = (1<<3) | (4-1);
43
44 DBOP_TIMPOL_01 = 0xe167e167;
45 DBOP_TIMPOL_23 = 0xe167006e;
46 DBOP_CTRL = 0x41008;
47
48 GPIOB_AFSEL = 0xfc;
49 GPIOC_AFSEL = 0xff;
50
51 DBOP_TIMPOL_23 = 0x6000e;
52 DBOP_CTRL = 0x51008;
53 DBOP_TIMPOL_01 = 0x6e167;
54 DBOP_TIMPOL_23 = 0xa167e06f;
55
56 /* TODO: The OF calls some other functions here, but maybe not important */
57}
58
59static void lcd_write_cmd(int cmd)
60{
61 int x;
62
63 /* Write register */
64 DBOP_CTRL &= ~(1<<14);
65
66 DBOP_TIMPOL_23 = 0xa167006e;
67
68 DBOP_DOUT = cmd;
69
70 /* Wait for fifo to empty */
71 while ((DBOP_STAT & (1<<10)) == 0);
72
73 /* This loop is unique to the Fuze */
74 x = 0;
75 do {
76 asm volatile ("nop\n");
77 } while (x++ < 4);
78
79
80 DBOP_TIMPOL_23 = 0xa167e06f;
81}
82
83void lcd_write_data(const fb_data* p_bytes, int count)
84{
85 while (count--)
86 {
87 DBOP_DOUT = *p_bytes++;
88
89 /* Wait for fifo to empty */
90 while ((DBOP_STAT & (1<<10)) == 0);
91 }
92}
93
94static void lcd_write_reg(int reg, int value)
95{
96 unsigned short data = value;
97
98 lcd_write_cmd(reg);
99 lcd_write_data(&data, 1);
100}
101
102/*** hardware configuration ***/
103
104void lcd_set_contrast(int val)
105{
106 (void)val;
107}
108
109void lcd_set_invert_display(bool yesno)
110{
111 (void)yesno;
112}
113
114static void flip_lcd(bool yesno)
115{
116 (void)yesno;
117}
118
119
120/* turn the display upside down (call lcd_update() afterwards) */
121void lcd_set_flip(bool yesno)
122{
123 display_flipped = yesno;
124 xoffset = yesno ? 20 : 0; /* A guess */
125
126 if (display_on)
127 flip_lcd(yesno);
128}
129
130
131static void _display_on(void)
132{
133 /* Initialise in the same way as the original firmare */
134
135 lcd_write_reg(0x07, 0);
136 lcd_write_reg(0x13, 0);
137
138 lcd_delay(10);
139
140 lcd_write_reg(0x11, 0x3704);
141 lcd_write_reg(0x14, 0x1a1b);
142 lcd_write_reg(0x10, 0x3860);
143 lcd_write_reg(0x13, 0x40);
144
145 lcd_delay(10);
146
147 lcd_write_reg(0x13, 0x60);
148
149 lcd_delay(50);
150
151 lcd_write_reg(0x13, 0x70);
152
153 lcd_delay(40);
154
155 lcd_write_reg(0x01, 277);
156 lcd_write_reg(0x02, (7<<8));
157 lcd_write_reg(0x03, 0x30);
158 lcd_write_reg(0x08, 0x01);
159 lcd_write_reg(0x0b, (1<<10));
160 lcd_write_reg(0x0c, 0);
161
162 lcd_write_reg(0x30, 0x40);
163 lcd_write_reg(0x31, 0x0687);
164 lcd_write_reg(0x32, 0x0306);
165 lcd_write_reg(0x33, 0x104);
166 lcd_write_reg(0x34, 0x0585);
167 lcd_write_reg(0x35, 255+66);
168 lcd_write_reg(0x36, 0x0687+128);
169 lcd_write_reg(0x37, 259);
170 lcd_write_reg(0x38, 0);
171 lcd_write_reg(0x39, 0);
172
173 lcd_write_reg(0x42, (LCD_WIDTH - 1));
174 lcd_write_reg(0x43, 0);
175 lcd_write_reg(0x44, (LCD_WIDTH - 1));
176 lcd_write_reg(0x45, 0);
177 lcd_write_reg(0x46, (((LCD_WIDTH - 1) + xoffset) << 8) | xoffset);
178 lcd_write_reg(0x47, (LCD_HEIGHT - 1));
179 lcd_write_reg(0x48, 0x0);
180
181 lcd_write_reg(0x07, 0x11);
182
183 lcd_delay(40);
184
185 lcd_write_reg(0x07, 0x17);
186
187 display_on = true; /* must be done before calling lcd_update() */
188 lcd_update();
189}
190
191/* (e.g. 0, 219) */
192static void lcd_window_x(int r0, int r1)
193{
194 int r2, r3, r4;
195
196 r3 = (LCD_WIDTH - 1);
197 r2 = (LCD_WIDTH - 1);
198
199 if (r0 < LCD_WIDTH)
200 r2 = r0;
201
202 if (r1 < LCD_WIDTH)
203 r3 = r1;
204
205#if 0
206 r1 = 0x1db12;
207
208 [r1] = 1; /* byte */
209#endif
210
211 r3 += xoffset;
212
213 r4 = r2;
214
215 r4 += xoffset;
216
217 r0 = (r3 << 8);
218
219 r0 |= r4;
220
221 r1 = (r0 << 16) >> 16;
222
223 lcd_write_reg(0x46, r1);
224
225 r1 = (r4 << 16) >> 16;
226
227 lcd_write_reg(0x20, r1);
228
229 lcd_write_reg(0x03, 0x30);
230
231#if 0
232 r0 := 0x1e0c4
233 r1 := 0x216a8
234
235 r0 := [r0]
236 r2 := [r1]
237
238 r0 := (r0 >> 2) << 2;
239
240 if (r0 != r2) {
241#endif
242 lcd_write_reg(0x00, 0x0001);
243 lcd_write_reg(0x11, 0x3704);
244 lcd_write_reg(0x14, 0x1a1b);
245 lcd_write_reg(0x10, 0x3860);
246 lcd_write_reg(0x13, 0x0070);
247 lcd_write_reg(0x07, 0x0017);
248 lcd_write_reg(0x01, 277);
249 lcd_write_reg(0x02, (7<<8));
250 lcd_write_reg(0x08, 0x0001);
251 lcd_write_reg(0x0b, (1<<10));
252 lcd_write_reg(0x0c, 0x0000);
253 lcd_write_reg(0x30, 0x0040);
254 lcd_write_reg(0x31, 0x0687);
255 lcd_write_reg(0x32, 0x0306);
256 lcd_write_reg(0x33, 260);
257 lcd_write_reg(0x34, 0x0585);
258 lcd_write_reg(0x35, 255+66);
259 lcd_write_reg(0x36, 0x687+128);
260 lcd_write_reg(0x37, 259);
261 lcd_write_reg(0x38, 0);
262 lcd_write_reg(0x39, 0);
263 lcd_write_reg(0x40, 0);
264 lcd_write_reg(0x41, 0);
265 lcd_write_reg(0x42, (LCD_WIDTH - 1));
266 lcd_write_reg(0x43, 0);
267 lcd_write_reg(0x44, (LCD_WIDTH - 1));
268 lcd_write_reg(0x45, 0);
269 lcd_write_reg(0x15, 0);
270 lcd_write_reg(0x73, 0);
271#if 0
272 }
273#endif
274}
275
276/* - e.g. 0, 175 */
277static void lcd_window_y(int r0, int r1)
278{
279 int r2, r4;
280
281 r2 = (LCD_HEIGHT - 1);
282 r4 = (LCD_HEIGHT - 1);
283
284 if (r0 < LCD_HEIGHT)
285 r4 = r0;
286
287 if (r1 < LCD_HEIGHT)
288 r2 = r1;
289
290 r1 = (r2 << 16) >> 16;
291
292 lcd_write_reg(0x47, r1);
293
294 r1 = (r4 << 16) >> 16;
295
296 lcd_write_reg(0x48, r1);
297
298 /* ??Start address - (x<<8) | y0 */
299 lcd_write_reg(0x21, r1);
300
301 /* Start write to GRAM */
302 lcd_write_cmd(0x22);
303}
304
305/* I'm guessing this function is lcd_enable, but it may not be... */
306void lcd_enable(int r0)
307{
308#if 0
309 r4 = 0x1db12;
310 [r4] = 1;
311#endif
312
313 if (r0 != 0) {
314 lcd_write_reg(0, 1);
315
316 lcd_delay(10);
317
318 lcd_write_reg(0x10, 0);
319 lcd_write_reg(0x11, 0x3704);
320 lcd_write_reg(0x14, 0x1a1b);
321 lcd_write_reg(0x10, 0x3860);
322 lcd_write_reg(0x13, 0x40);
323
324 lcd_delay(10);
325
326 lcd_write_reg(0x13, 0x60);
327
328 lcd_delay(50);
329
330 lcd_write_reg(0x13, 112);
331
332 lcd_delay(40);
333
334 lcd_write_reg(0x07, 0x11);
335
336 lcd_delay(40);
337
338 lcd_write_reg(0x07, 0x17);
339 } else {
340 lcd_write_reg(0x07, 0x22);
341
342 lcd_delay(40);
343
344 lcd_write_reg(0x07, 0);
345
346 lcd_delay(40);
347
348 lcd_write_reg(0x10, 1);
349 }
350
351#if 0
352 [r4] = 0;
353#endif
354}
355
356void lcd_init_device()
357{
358 as3525_dbop_init();
359
360 GPIOA_DIR |= (1<<5);
361 GPIOA_PIN(5) = 0;
362
363 GPIOA_PIN(3) = (1<<3);
364
365 GPIOA_DIR |= (1<<4) | (1<<3);
366
367 GPIOA_PIN(3) = (1<<3);
368
369 GPIOA_PIN(4) = 0;
370
371 GPIOA_DIR |= (1<<7);
372 GPIOA_PIN(7) = 0;
373
374 CCU_IO &= ~4;
375 CCU_IO &= ~8;
376
377 GPIOD_DIR |= (1<<7);
378
379#if 0
380 if (byte[0x21b24] == 0) {
381 GPIOD_PIN(7) = (1<<7);
382 GPIOD_DIR |= (1<<7);
383 }
384#endif
385
386 lcd_delay(1);
387
388 GPIOA_PIN(5) = (1<<5);
389
390 lcd_delay(1);
391
392 _display_on();
393}
394
395/* Update the display.
396 This must be called after all other LCD functions that change the display. */
397void lcd_update(void)
398{
399 if (!display_on)
400 return;
401
402 lcd_window_x(0, (LCD_WIDTH - 1));
403
404 lcd_window_y(0, (LCD_HEIGHT - 1));
405
406 lcd_write_data((unsigned short *)lcd_framebuffer, LCD_WIDTH*LCD_HEIGHT);
407
408}
409
410/* Update a fraction of the display. */
411void lcd_update_rect(int x, int y, int width, int height)
412{
413 int xmax, ymax;
414 const unsigned short *ptr;
415
416 if (!display_on)
417 return;
418
419 xmax = x + width - 1;
420 if (xmax >= LCD_WIDTH)
421 xmax = LCD_WIDTH - 1; /* Clip right */
422 if (x < 0)
423 x = 0; /* Clip left */
424 if (x >= xmax)
425 return; /* nothing left to do */
426
427 ymax = y + height;
428 if (ymax > LCD_HEIGHT)
429 ymax = LCD_HEIGHT - 1; /* Clip bottom */
430 if (y < 0)
431 y = 0; /* Clip top */
432 if (y >= ymax)
433 return; /* nothing left to do */
434
435
436 lcd_window_x(x, xmax);
437 lcd_window_y(y, ymax);
438
439 ptr = (unsigned short *)&lcd_framebuffer[y][x];
440
441 do
442 {
443 lcd_write_data(ptr, width);
444 ptr += LCD_WIDTH;
445 }
446 while (++y < ymax);
447
448 lcd_write_data((unsigned short *)lcd_framebuffer, LCD_WIDTH*LCD_HEIGHT);
449}