Move c/h files implementing/defining standard library stuff into a new libc directory...
[kugel-rb.git] / firmware / target / arm / sandisk / sansa-e200 / lcd-e200.c
blob0f9ca9b0468491760df85a017cfb11ba2c068187
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Rockbox driver for Sansa e200 LCDs
12 * Based on reverse engineering done my MrH
14 * Copyright (c) 2006 Daniel Ankers
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
24 ****************************************************************************/
25 #include <sys/types.h> /* off_t */
26 #include <string.h>
27 #include "cpu.h"
28 #include "system.h"
29 #include "backlight-target.h"
30 #include "lcd.h"
32 /* Power and display status */
33 static bool power_on = false; /* Is the power turned on? */
34 static bool display_on SHAREDBSS_ATTR = false; /* Is the display turned on? */
35 static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
37 /* Reverse Flag */
38 #define R_DISP_CONTROL_NORMAL 0x0004
39 #define R_DISP_CONTROL_REV 0x0000
40 static unsigned short r_disp_control_rev = R_DISP_CONTROL_NORMAL;
42 /* Flipping */
43 #define R_DRV_OUTPUT_CONTROL_NORMAL 0x101b
44 #define R_DRV_OUTPUT_CONTROL_FLIPPED 0x131b
45 static unsigned short r_drv_output_control = R_DRV_OUTPUT_CONTROL_NORMAL;
47 #define LCD_DATA_IN_GPIO GPIOB_INPUT_VAL
48 #define LCD_DATA_IN_PIN 6
50 #define LCD_DATA_OUT_GPIO GPIOB_OUTPUT_VAL
51 #define LCD_DATA_OUT_PIN 7
53 #define LCD_CLOCK_GPIO GPIOB_OUTPUT_VAL
54 #define LCD_CLOCK_PIN 5
56 #define LCD_CS_GPIO GPIOD_OUTPUT_VAL
57 #define LCD_CS_PIN 6
59 #define LCD_REG_0 (*(volatile unsigned long *)(0xc2000000))
60 #define LCD_REG_1 (*(volatile unsigned long *)(0xc2000004))
61 #define LCD_REG_2 (*(volatile unsigned long *)(0xc2000008))
62 #define LCD_REG_3 (*(volatile unsigned long *)(0xc200000c))
63 #define LCD_REG_4 (*(volatile unsigned long *)(0xc2000010))
64 #define LCD_REG_5 (*(volatile unsigned long *)(0xc2000014))
65 #define LCD_REG_6 (*(volatile unsigned long *)(0xc2000018))
66 #define LCD_REG_7 (*(volatile unsigned long *)(0xc200001c))
67 #define LCD_REG_8 (*(volatile unsigned long *)(0xc2000020))
68 #define LCD_REG_9 (*(volatile unsigned long *)(0xc2000024))
69 #define LCD_FB_BASE_REG (*(volatile unsigned long *)(0xc2000028))
71 /* Taken from HD66789 datasheet and seems similar enough.
72 Definitely a Renesas chip though with a perfect register index
73 match but at least one bit seems to be set that that datasheet
74 doesn't show. It says T.B.D. on the regmap anyway. */
75 #define R_START_OSC 0x00
76 #define R_DRV_OUTPUT_CONTROL 0x01
77 #define R_DRV_WAVEFORM_CONTROL 0x02
78 #define R_ENTRY_MODE 0x03
79 #define R_COMPARE_REG1 0x04
80 #define R_COMPARE_REG2 0x05
81 #define R_DISP_CONTROL1 0x07
82 #define R_DISP_CONTROL2 0x08
83 #define R_DISP_CONTROL3 0x09
84 #define R_FRAME_CYCLE_CONTROL 0x0b
85 #define R_EXT_DISP_INTF_CONTROL 0x0c
86 #define R_POWER_CONTROL1 0x10
87 #define R_POWER_CONTROL2 0x11
88 #define R_POWER_CONTROL3 0x12
89 #define R_POWER_CONTROL4 0x13
90 #define R_RAM_ADDR_SET 0x21
91 #define R_RAM_READ_DATA 0x21
92 #define R_RAM_WRITE_DATA 0x22
93 #define R_RAM_WRITE_DATA_MASK1 0x23
94 #define R_RAM_WRITE_DATA_MASK2 0x24
95 #define R_GAMMA_FINE_ADJ_POS1 0x30
96 #define R_GAMMA_FINE_ADJ_POS2 0x31
97 #define R_GAMMA_FINE_ADJ_POS3 0x32
98 #define R_GAMMA_GRAD_ADJ_POS 0x33
99 #define R_GAMMA_FINE_ADJ_NEG1 0x34
100 #define R_GAMMA_FINE_ADJ_NEG2 0x35
101 #define R_GAMMA_FINE_ADJ_NEG3 0x36
102 #define R_GAMMA_GRAD_ADJ_NEG 0x37
103 #define R_GAMMA_AMP_ADJ_POS 0x38
104 #define R_GAMMA_AMP_ADJ_NEG 0x39
105 #define R_GATE_SCAN_START_POS 0x40
106 #define R_VERT_SCROLL_CONTROL 0x41
107 #define R_1ST_SCR_DRIVE_POS 0x42
108 #define R_2ND_SCR_DRIVE_POS 0x43
109 #define R_HORIZ_RAM_ADDR_POS 0x44
110 #define R_VERT_RAM_ADDR_POS 0x45
112 /* We don't know how to receive a DMA finished signal from the LCD controller.
113 * To avoid problems with flickering, we double-buffer the framebuffer.
114 * Align as in lcd-16bit.c and not cached. */
115 static fb_data lcd_driver_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH]
116 __attribute__((aligned(16))) NOCACHEBSS_ATTR;
118 #ifdef BOOTLOADER
119 static void lcd_init_gpio(void)
121 GPIOB_ENABLE |= (1<<7);
122 GPIOB_ENABLE |= (1<<5);
123 GPIOB_OUTPUT_EN |= (1<<7);
124 GPIOB_OUTPUT_EN |= (1<<5);
125 GPIOD_ENABLE |= (1<<6);
126 GPIOD_OUTPUT_EN |= (1<<6);
128 #endif
130 static void lcd_bus_idle(void)
132 LCD_CLOCK_GPIO |= (1 << LCD_CLOCK_PIN);
133 LCD_DATA_OUT_GPIO |= (1 << LCD_DATA_OUT_PIN);
136 static void lcd_send_byte(unsigned char byte)
139 int i;
141 for (i = 7; i >=0 ; i--)
143 LCD_CLOCK_GPIO &= ~(1 << LCD_CLOCK_PIN);
144 if ((byte >> i) & 1)
146 LCD_DATA_OUT_GPIO |= (1 << LCD_DATA_OUT_PIN);
147 } else {
148 LCD_DATA_OUT_GPIO &= ~(1 << LCD_DATA_OUT_PIN);
150 udelay(1);
151 LCD_CLOCK_GPIO |= (1 << LCD_CLOCK_PIN);
152 udelay(1);
153 lcd_bus_idle();
154 udelay(3);
158 static void lcd_send_msg(unsigned char cmd, unsigned int data)
160 lcd_bus_idle();
161 udelay(1);
162 LCD_CS_GPIO &= ~(1 << LCD_CS_PIN);
163 udelay(10);
164 lcd_send_byte(cmd);
165 lcd_send_byte((unsigned char)(data >> 8));
166 lcd_send_byte((unsigned char)(data & 0xff));
167 LCD_CS_GPIO |= (1 << LCD_CS_PIN);
168 udelay(1);
169 lcd_bus_idle();
172 static void lcd_write_reg(unsigned int reg, unsigned int data)
174 lcd_send_msg(0x70, reg);
175 lcd_send_msg(0x72, data);
178 /* Run the powerup sequence for the driver IC */
179 static void lcd_power_on(void)
181 /* Clear standby bit */
182 lcd_write_reg(R_POWER_CONTROL1, 0x0000);
184 /** Power ON Sequence **/
185 lcd_write_reg(R_START_OSC, 0x0001);
186 /* 10ms or more for oscillation circuit to stabilize */
187 sleep(HZ/50);
189 /* SAP2-0=100, BT2-0=100, AP2-0=100, DK=1, SLP=0, STB=0 */
190 lcd_write_reg(R_POWER_CONTROL1, 0x4444);
191 /* DC12-10=000, DC2-0=000, VC2-0=001 */
192 lcd_write_reg(R_POWER_CONTROL2, 0x0001);
193 /* PON=0, VRH3-0=0011 */
194 lcd_write_reg(R_POWER_CONTROL3, 0x0003);
195 /* VCOMG=0, VDV4-0=10001, VCM3-0=11001 */
196 lcd_write_reg(R_POWER_CONTROL4, 0x1119);
197 /* PON=1, VRH3-0=0011 */
198 lcd_write_reg(R_POWER_CONTROL3, 0x0013);
199 sleep(HZ/25);
201 /* SAP2-0=100, BT2-0=100, AP2-0=100, DK=0, SLP=0, STB=0 */
202 lcd_write_reg(R_POWER_CONTROL1, 0x4440);
203 /* VCOMG=1, VDV4-0=10001, VCM3-0=11001 */
204 lcd_write_reg(R_POWER_CONTROL4, 0x3119);
205 sleep(HZ/6);
207 /* VSPL=0, HSPL=0, DPL=1, EPL=0, SM=0, GS=x, SS=x, NL4-0=11011 */
208 lcd_write_reg(R_DRV_OUTPUT_CONTROL, r_drv_output_control);
209 /* FLD=0, FLD0=1, B/C=1, EOR=1, NW5-0=000000 */
210 lcd_write_reg(R_DRV_WAVEFORM_CONTROL, 0x0700);
211 /* TRI=0, DFM1-0=11, BGR=0, HWM=1, ID1-0=10, AM=0, LG2-0=000
212 * AM: horizontal update direction
213 * ID1-0: H decrement, V increment
215 lcd_write_reg(R_ENTRY_MODE, 0x6020);
216 lcd_write_reg(R_COMPARE_REG1, 0x0000);
217 lcd_write_reg(R_COMPARE_REG2, 0x0000);
218 /* FP3-0=0010, BP3-0=0010 */
219 lcd_write_reg(R_DISP_CONTROL2, 0x0202);
220 /* PTG1-0=00 (normal scan), ISC3-0=0000 (ignored) */
221 lcd_write_reg(R_DISP_CONTROL3, 0x0000);
222 /* NO2-0=01, SDT1-0=00, EQ1-0=01, DIV1-0=00, RTN3-0=0000 */
223 lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x4400);
224 /* RM=1, DM1-0=01, RIM1-0=00 */
225 lcd_write_reg(R_EXT_DISP_INTF_CONTROL, 0x0110);
226 /* SCN4-0=00000 - G1 if GS=0, G240 if GS=1 */
227 lcd_write_reg(R_GATE_SCAN_START_POS, 0x0000);
228 /* VL7-0=00000000 (0 lines) */
229 lcd_write_reg(R_VERT_SCROLL_CONTROL, 0x0000);
230 /* SE17-10=219, SS17-10=0 - 220 gates */
231 lcd_write_reg(R_1ST_SCR_DRIVE_POS, (219 << 8));
232 /* SE27-10=0, SS27-10=0 - no second screen */
233 lcd_write_reg(R_2ND_SCR_DRIVE_POS, 0x0000);
234 /* HEA=175, HSA=0 = H window from 0-175 */
235 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (175 << 8));
236 /* VEA=219, VSA=0 = V window from 0-219 */
237 lcd_write_reg(R_VERT_RAM_ADDR_POS, (219 << 8));
238 /* PKP12-10=000, PKP02-00=000 */
239 lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0000);
240 /* PKP32-30=111, PKP22-20=100 */
241 lcd_write_reg(R_GAMMA_FINE_ADJ_POS2, 0x0704);
242 /* PKP52-50=001, PKP42-40=111 */
243 lcd_write_reg(R_GAMMA_FINE_ADJ_POS3, 0x0107);
244 /* PRP12-10=111, PRP02-00=100 */
245 lcd_write_reg(R_GAMMA_GRAD_ADJ_POS, 0x0704);
246 /* PKN12-10=001, PKN02-00=111 */
247 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG1, 0x0107);
248 /* PKN32-30=000, PKN22-20=010 */
249 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG2, 0x0002);
250 /* PKN52-50=111, PKN42-40=111 */
251 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG3, 0x0707);
252 /* PRN12-10=101, PRN02-00=011 */
253 lcd_write_reg(R_GAMMA_GRAD_ADJ_NEG, 0x0503);
254 /* VRP14-10=00000, VRP03-00=0000 */
255 lcd_write_reg(R_GAMMA_AMP_ADJ_POS, 0x0000);
256 /* WRN14-10=00000, VRN03-00=0000 */
257 lcd_write_reg(R_GAMMA_AMP_ADJ_NEG, 0x0000);
258 /* AD15-0=175 (upper right corner) */
259 lcd_write_reg(R_RAM_ADDR_SET, 175);
260 /* RM=1, DM1-0=01, RIM1-0=00 */
261 lcd_write_reg(R_EXT_DISP_INTF_CONTROL, 0x0110);
263 power_on = true;
266 /* Run the display on sequence for the driver IC */
267 static void lcd_display_on(void)
269 if (!power_on)
271 /* Power has been turned off so full reinit is needed */
272 lcd_power_on();
274 else
276 /* Restore what we fiddled with when turning display off */
277 /* PON=1, VRH3-0=0011 */
278 lcd_write_reg(R_POWER_CONTROL3, 0x0013);
279 /* NO2-0=01, SDT1-0=00, EQ1-0=01, DIV1-0=00, RTN3-0=0000 */
280 lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x4400);
281 /* VCOMG=1, VDV4-0=10001, VCM3-0=11001 */
282 lcd_write_reg(R_POWER_CONTROL4, 0x3119);
285 /* SAP2-0=100, BT2-0=111, AP2-0=100, DK=1, SLP=0, STB=0 */
286 lcd_write_reg(R_POWER_CONTROL1, 0x4740);
288 sleep(HZ/25);
290 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=0, DTE=0, CL=0,
291 REV=x, D1-0=01 */
292 lcd_write_reg(R_DISP_CONTROL1, 0x0041 | r_disp_control_rev);
294 sleep(HZ/30);
296 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=0, CL=0,
297 REV=x, D1-0=01 */
298 lcd_write_reg(R_DISP_CONTROL1, 0x0061 | r_disp_control_rev);
299 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=0, CL=0,
300 REV=x, D1-0=11 */
301 lcd_write_reg(R_DISP_CONTROL1, 0x0063 | r_disp_control_rev);
303 sleep(HZ/30);
305 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=1, CL=0,
306 REV=x, D1-0=11 */
307 lcd_write_reg(R_DISP_CONTROL1, 0x0073 | r_disp_control_rev);
309 /* Go into write data mode */
310 lcd_send_msg(0x70, R_RAM_WRITE_DATA);
312 /* tell that we're on now */
313 display_on = true;
317 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
318 bool lcd_active(void)
320 return display_on;
323 /* Turn off visible display operations */
324 static void lcd_display_off(void)
326 /* block drawing operations and changing of first */
327 display_on = false;
329 /* NO2-0=01, SDT1-0=00, EQ1-0=00, DIV1-0=00, RTN3-0=0000 */
330 lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x4000);
332 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=1, CL=0,
333 REV=x, D1-0=10 */
334 lcd_write_reg(R_DISP_CONTROL1, 0x0072 | r_disp_control_rev);
336 sleep(HZ/25);
338 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=0, CL=0,
339 REV=x, D1-0=10 */
340 lcd_write_reg(R_DISP_CONTROL1, 0x0062 | r_disp_control_rev);
342 sleep(HZ/25);
344 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=0, GON=0, DTE=0, CL=0,
345 REV=0, D1-0=00 */
346 lcd_write_reg(R_DISP_CONTROL1, 0x0000);
347 /* SAP2-0=000, BT2-0=000, AP2-0=000, DK=0, SLP=0, STBY=0 */
348 lcd_write_reg(R_POWER_CONTROL1, 0x0000);
349 /* PON=0, VRH3-0=0011 */
350 lcd_write_reg(R_POWER_CONTROL3, 0x0003);
351 /* VCOMG=0, VDV4-0=10001, VCM4-0=11001 */
352 lcd_write_reg(R_POWER_CONTROL4, 0x1119);
354 #endif
356 void lcd_init_device(void)
358 /* All this is magic worked out by MrH */
360 /* Stop any DMA which is in progress */
361 LCD_REG_6 &= ~1;
362 udelay(100000);
364 #ifdef BOOTLOADER /* Bother at all to do this again? */
365 /* Init GPIO ports */
366 lcd_init_gpio();
367 /* Controller init */
368 GPO32_ENABLE |= (1 << 28);
369 GPO32_VAL &= ~(1 << 28);
370 DEV_INIT1 = ( (DEV_INIT1 & 0x03ffffff) | (0x15 << 26) );
371 outl(((inl(0x70000014) & (0x0fffffff)) | (0x5 << 28)), 0x70000014);
372 outl((inl(0x70000020) & ~(0x3 << 10)), 0x70000020);
373 DEV_EN |= DEV_LCD; /* Enable controller */
374 outl(0x6, 0x600060d0);
375 DEV_RS |= DEV_LCD; /* Reset controller */
376 outl((inl(0x70000020) & ~(1 << 14)), 0x70000020);
377 lcd_bus_idle();
378 DEV_RS &=~DEV_LCD; /* Clear reset */
379 udelay(1000);
381 LCD_REG_0 = (LCD_REG_0 & (0x00ffffff)) | (0x22 << 24);
382 LCD_REG_0 = (LCD_REG_0 & (0xff00ffff)) | (0x14 << 16);
383 LCD_REG_0 = (LCD_REG_0 & (0xffffc0ff)) | (0x3 << 8);
384 LCD_REG_0 = (LCD_REG_0 & (0xffffffc0)) | (0xa);
386 LCD_REG_1 &= 0x00ffffff;
387 LCD_REG_1 &= 0xff00ffff;
388 LCD_REG_1 = (LCD_REG_1 & 0xffff03ff) | (0x2 << 10);
389 LCD_REG_1 = (LCD_REG_1 & 0xfffffc00) | (0xdd);
391 LCD_REG_2 |= (1 << 5);
392 LCD_REG_2 |= (1 << 6);
393 LCD_REG_2 = (LCD_REG_2 & 0xfffffcff) | (0x2 << 8);
395 LCD_REG_7 &= (0xf800ffff);
396 LCD_REG_7 &= (0xfffff800);
398 LCD_REG_8 = (LCD_REG_8 & (0xf800ffff)) | (0xb0 << 16);
399 LCD_REG_8 = (LCD_REG_8 & (0xfffff800)) | (0xdc); /* X-Y Geometry? */
401 LCD_REG_5 |= 0xc;
402 LCD_REG_5 = (LCD_REG_5 & ~(0x70)) | (0x3 << 4);
403 LCD_REG_5 |= 2;
405 LCD_REG_6 &= ~(1 << 15);
406 LCD_REG_6 |= (0xe00);
407 LCD_REG_6 = (LCD_REG_6 & (0xffffff1f)) | (0x4 << 5);
408 LCD_REG_6 |= (1 << 4);
410 LCD_REG_5 &= ~(1 << 7);
411 /* lcd_driver_framebuffer is uncached therefore at the physical address */
412 LCD_FB_BASE_REG = (long)lcd_driver_framebuffer;
414 udelay(100000);
416 /* LCD init */
417 /* Pull RESET low, then high to reset driver IC */
418 GPO32_VAL &= ~(1 << 28);
419 udelay(10000);
420 GPO32_VAL |= (1 << 28);
421 udelay(10000);
423 lcd_display_on();
424 #else
425 /* Power and display already ON - switch framebuffer address and reset
426 settings */
427 /* lcd_driver_framebuffer is uncached therefore at the physical address */
428 LCD_FB_BASE_REG = (long)lcd_driver_framebuffer;
430 power_on = true;
431 display_on = true;
433 lcd_set_invert_display(false);
434 lcd_set_flip(false);
435 #endif
437 LCD_REG_6 |= 1; /* Start DMA */
440 #if defined(HAVE_LCD_ENABLE)
441 void lcd_enable(bool on)
443 if (on == display_on)
444 return;
446 if (on)
448 DEV_EN |= DEV_LCD; /* Enable LCD controller */
449 lcd_display_on(); /* Turn on display */
450 lcd_update(); /* Resync display */
451 send_event(LCD_EVENT_ACTIVATION, NULL);
452 LCD_REG_6 |= 1; /* Restart DMA */
453 sleep(HZ/50); /* Wait for a frame to be written */
455 else
457 LCD_REG_6 &= ~1; /* Disable DMA */
458 sleep(HZ/50); /* Wait for dma end (assuming 50Hz) */
459 lcd_display_off(); /* Turn off display */
460 DEV_EN &= ~DEV_LCD; /* Disable LCD controller */
463 #endif
465 #if defined(HAVE_LCD_SLEEP)
466 void lcd_sleep(void)
468 LCD_REG_6 &= ~1;
469 sleep(HZ/50);
471 if (power_on)
473 /* Turn off display */
474 if (display_on)
475 lcd_display_off();
477 power_on = false;
480 /* Set standby mode */
481 /* SAP2-0=000, BT2-0=000, AP2-0=000, DK=0, SLP=0, STB=1 */
482 lcd_write_reg(R_POWER_CONTROL1, 0x0001);
484 #endif
486 /* Copies a rectangle from one framebuffer to another. Can be used in
487 single transfer mode with width = num pixels, and height = 1 which
488 allows a full-width rectangle to be copied more efficiently. */
489 extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src,
490 int width, int height);
491 void lcd_update_rect(int x, int y, int width, int height)
493 fb_data *dst, *src;
495 if (!display_on)
496 return;
498 if (x + width > LCD_WIDTH)
499 width = LCD_WIDTH - x; /* Clip right */
500 if (x < 0)
501 width += x, x = 0; /* Clip left */
502 if (width <= 0)
503 return; /* nothing left to do */
505 if (y + height > LCD_HEIGHT)
506 height = LCD_HEIGHT - y; /* Clip bottom */
507 if (y < 0)
508 height += y, y = 0; /* Clip top */
509 if (height <= 0)
510 return; /* nothing left to do */
512 dst = &lcd_driver_framebuffer[y][x];
513 src = &lcd_framebuffer[y][x];
515 /* Copy part of the Rockbox framebuffer to the second framebuffer */
516 if (width < LCD_WIDTH)
518 /* Not full width - do line-by-line */
519 lcd_copy_buffer_rect(dst, src, width, height);
521 else
523 /* Full width - copy as one line */
524 lcd_copy_buffer_rect(dst, src, LCD_WIDTH*height, 1);
528 void lcd_update(void)
530 if (!display_on)
531 return;
533 /* Copy the Rockbox framebuffer to the second framebuffer */
534 lcd_copy_buffer_rect(&lcd_driver_framebuffer[0][0],
535 &lcd_framebuffer[0][0], LCD_WIDTH*LCD_HEIGHT, 1);
539 /*** hardware configuration ***/
541 void lcd_set_contrast(int val)
543 /* TODO: Implement lcd_set_contrast() */
544 (void)val;
547 void lcd_set_invert_display(bool yesno)
549 bool dma_on = LCD_REG_6 & 1;
551 if (dma_on)
553 LCD_REG_6 &= ~1; /* Disable DMA */
554 sleep(HZ/50); /* Wait for dma end (assuming 50Hz) */
555 DEV_EN &= ~DEV_LCD; /* Disable LCD controller */
558 r_disp_control_rev = yesno ? R_DISP_CONTROL_REV :
559 R_DISP_CONTROL_NORMAL;
561 if (display_on)
563 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, CL=0,
564 DTE=1, REV=x, D1-0=11 */
565 lcd_write_reg(R_DISP_CONTROL1, 0x0073 | r_disp_control_rev);
568 if (dma_on)
570 DEV_EN |= DEV_LCD; /* Enable LCD controller */
571 lcd_send_msg(0x70, R_RAM_WRITE_DATA); /* Set to RAM write mode */
572 LCD_REG_6 |= 1; /* Restart DMA */
576 /* turn the display upside down (call lcd_update() afterwards) */
577 void lcd_set_flip(bool yesno)
579 bool dma_on = LCD_REG_6 & 1;
581 if (dma_on)
583 LCD_REG_6 &= ~1; /* Disable DMA */
584 sleep(HZ/50); /* Wait for dma end (assuming 50Hz) */
585 DEV_EN &= ~DEV_LCD; /* Disable LCD controller */
588 r_drv_output_control = yesno ? R_DRV_OUTPUT_CONTROL_FLIPPED :
589 R_DRV_OUTPUT_CONTROL_NORMAL;
591 if (power_on)
593 /* VSPL=0, HSPL=0, DPL=1, EPL=0, SM=0, GS=x, SS=x,
594 NL4-0=11011 (G1-G224) */
595 lcd_write_reg(R_DRV_OUTPUT_CONTROL, r_drv_output_control);
598 if (dma_on)
600 DEV_EN |= DEV_LCD; /* Enable LCD controller */
601 lcd_send_msg(0x70, R_RAM_WRITE_DATA); /* Set to RAM write mode */
602 LCD_REG_6 |= 1; /* Restart DMA */
606 /* Blitting functions */
608 void lcd_yuv_set_options(unsigned options)
610 lcd_yuv_options = options;
613 /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
614 extern void lcd_write_yuv420_lines(fb_data *dst,
615 unsigned char const * const src[3],
616 int width,
617 int stride);
618 extern void lcd_write_yuv420_lines_odither(fb_data *dst,
619 unsigned char const * const src[3],
620 int width,
621 int stride,
622 int x_screen, /* To align dither pattern */
623 int y_screen);
624 /* Performance function to blit a YUV bitmap directly to the LCD */
625 /* For the e200 - show it rotated */
626 /* So the LCD_WIDTH is now the height */
627 void lcd_blit_yuv(unsigned char * const src[3],
628 int src_x, int src_y, int stride,
629 int x, int y, int width, int height)
631 unsigned char const * yuv_src[3];
632 off_t z;
634 if (!display_on)
635 return;
637 /* Sorry, but width and height must be >= 2 or else */
638 width &= ~1;
639 height >>= 1;
641 y = LCD_WIDTH - 1 - y;
642 fb_data *dst = &lcd_driver_framebuffer[x][y];
644 z = stride*src_y;
645 yuv_src[0] = src[0] + z + src_x;
646 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
647 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
649 if (lcd_yuv_options & LCD_YUV_DITHER)
653 lcd_write_yuv420_lines_odither(dst, yuv_src, width, stride, y, x);
654 yuv_src[0] += stride << 1; /* Skip down two luma lines */
655 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
656 yuv_src[2] += stride >> 1;
657 dst -= 2;
658 y -= 2;
660 while (--height > 0);
662 else
666 lcd_write_yuv420_lines(dst, yuv_src, width, stride);
667 yuv_src[0] += stride << 1; /* Skip down two luma lines */
668 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
669 yuv_src[2] += stride >> 1;
670 dst -= 2;
672 while (--height > 0);