1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
28 #include "backlight-target.h"
31 /* Power and display status */
32 static bool power_on
= false; /* Is the power turned on? */
33 static bool display_on SHAREDBSS_ATTR
= false; /* Is the display turned on? */
34 static unsigned lcd_yuv_options SHAREDBSS_ATTR
= 0;
37 #define R_DISP_CONTROL_NORMAL 0x0004
38 #define R_DISP_CONTROL_REV 0x0000
39 static unsigned short r_disp_control_rev
= R_DISP_CONTROL_NORMAL
;
42 #define R_DRV_OUTPUT_CONTROL_NORMAL 0x101b
43 #define R_DRV_OUTPUT_CONTROL_FLIPPED 0x131b
44 static unsigned short r_drv_output_control
= R_DRV_OUTPUT_CONTROL_NORMAL
;
46 #define LCD_DATA_IN_GPIO GPIOB_INPUT_VAL
47 #define LCD_DATA_IN_PIN 6
49 #define LCD_DATA_OUT_GPIO GPIOB_OUTPUT_VAL
50 #define LCD_DATA_OUT_PIN 7
52 #define LCD_CLOCK_GPIO GPIOB_OUTPUT_VAL
53 #define LCD_CLOCK_PIN 5
55 #define LCD_CS_GPIO GPIOD_OUTPUT_VAL
58 #define LCD_REG_0 (*(volatile unsigned long *)(0xc2000000))
59 #define LCD_REG_1 (*(volatile unsigned long *)(0xc2000004))
60 #define LCD_REG_2 (*(volatile unsigned long *)(0xc2000008))
61 #define LCD_REG_3 (*(volatile unsigned long *)(0xc200000c))
62 #define LCD_REG_4 (*(volatile unsigned long *)(0xc2000010))
63 #define LCD_REG_5 (*(volatile unsigned long *)(0xc2000014))
64 #define LCD_REG_6 (*(volatile unsigned long *)(0xc2000018))
65 #define LCD_REG_7 (*(volatile unsigned long *)(0xc200001c))
66 #define LCD_REG_8 (*(volatile unsigned long *)(0xc2000020))
67 #define LCD_REG_9 (*(volatile unsigned long *)(0xc2000024))
68 #define LCD_FB_BASE_REG (*(volatile unsigned long *)(0xc2000028))
70 /* Taken from HD66789 datasheet and seems similar enough.
71 Definitely a Renesas chip though with a perfect register index
72 match but at least one bit seems to be set that that datasheet
73 doesn't show. It says T.B.D. on the regmap anyway. */
74 #define R_START_OSC 0x00
75 #define R_DRV_OUTPUT_CONTROL 0x01
76 #define R_DRV_WAVEFORM_CONTROL 0x02
77 #define R_ENTRY_MODE 0x03
78 #define R_COMPARE_REG1 0x04
79 #define R_COMPARE_REG2 0x05
80 #define R_DISP_CONTROL1 0x07
81 #define R_DISP_CONTROL2 0x08
82 #define R_DISP_CONTROL3 0x09
83 #define R_FRAME_CYCLE_CONTROL 0x0b
84 #define R_EXT_DISP_INTF_CONTROL 0x0c
85 #define R_POWER_CONTROL1 0x10
86 #define R_POWER_CONTROL2 0x11
87 #define R_POWER_CONTROL3 0x12
88 #define R_POWER_CONTROL4 0x13
89 #define R_RAM_ADDR_SET 0x21
90 #define R_RAM_READ_DATA 0x21
91 #define R_RAM_WRITE_DATA 0x22
92 #define R_RAM_WRITE_DATA_MASK1 0x23
93 #define R_RAM_WRITE_DATA_MASK2 0x24
94 #define R_GAMMA_FINE_ADJ_POS1 0x30
95 #define R_GAMMA_FINE_ADJ_POS2 0x31
96 #define R_GAMMA_FINE_ADJ_POS3 0x32
97 #define R_GAMMA_GRAD_ADJ_POS 0x33
98 #define R_GAMMA_FINE_ADJ_NEG1 0x34
99 #define R_GAMMA_FINE_ADJ_NEG2 0x35
100 #define R_GAMMA_FINE_ADJ_NEG3 0x36
101 #define R_GAMMA_GRAD_ADJ_NEG 0x37
102 #define R_GAMMA_AMP_ADJ_POS 0x38
103 #define R_GAMMA_AMP_ADJ_NEG 0x39
104 #define R_GATE_SCAN_START_POS 0x40
105 #define R_VERT_SCROLL_CONTROL 0x41
106 #define R_1ST_SCR_DRIVE_POS 0x42
107 #define R_2ND_SCR_DRIVE_POS 0x43
108 #define R_HORIZ_RAM_ADDR_POS 0x44
109 #define R_VERT_RAM_ADDR_POS 0x45
111 /* We don't know how to receive a DMA finished signal from the LCD controller.
112 * To avoid problems with flickering, we double-buffer the framebuffer.
113 * Align as in lcd-16bit.c and not cached. */
114 static fb_data lcd_driver_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
]
115 __attribute__((aligned(16))) NOCACHEBSS_ATTR
;
118 static void lcd_init_gpio(void)
120 GPIOB_ENABLE
|= (1<<7);
121 GPIOB_ENABLE
|= (1<<5);
122 GPIOB_OUTPUT_EN
|= (1<<7);
123 GPIOB_OUTPUT_EN
|= (1<<5);
124 GPIOD_ENABLE
|= (1<<6);
125 GPIOD_OUTPUT_EN
|= (1<<6);
129 static void lcd_bus_idle(void)
131 LCD_CLOCK_GPIO
|= (1 << LCD_CLOCK_PIN
);
132 LCD_DATA_OUT_GPIO
|= (1 << LCD_DATA_OUT_PIN
);
135 static void lcd_send_byte(unsigned char byte
)
140 for (i
= 7; i
>=0 ; i
--)
142 LCD_CLOCK_GPIO
&= ~(1 << LCD_CLOCK_PIN
);
145 LCD_DATA_OUT_GPIO
|= (1 << LCD_DATA_OUT_PIN
);
147 LCD_DATA_OUT_GPIO
&= ~(1 << LCD_DATA_OUT_PIN
);
150 LCD_CLOCK_GPIO
|= (1 << LCD_CLOCK_PIN
);
157 static void lcd_send_msg(unsigned char cmd
, unsigned int data
)
161 LCD_CS_GPIO
&= ~(1 << LCD_CS_PIN
);
164 lcd_send_byte((unsigned char)(data
>> 8));
165 lcd_send_byte((unsigned char)(data
& 0xff));
166 LCD_CS_GPIO
|= (1 << LCD_CS_PIN
);
171 static void lcd_write_reg(unsigned int reg
, unsigned int data
)
173 lcd_send_msg(0x70, reg
);
174 lcd_send_msg(0x72, data
);
177 /* Run the powerup sequence for the driver IC */
178 static void lcd_power_on(void)
180 /* Clear standby bit */
181 lcd_write_reg(R_POWER_CONTROL1
, 0x0000);
183 /** Power ON Sequence **/
184 lcd_write_reg(R_START_OSC
, 0x0001);
185 /* 10ms or more for oscillation circuit to stabilize */
188 /* SAP2-0=100, BT2-0=100, AP2-0=100, DK=1, SLP=0, STB=0 */
189 lcd_write_reg(R_POWER_CONTROL1
, 0x4444);
190 /* DC12-10=000, DC2-0=000, VC2-0=001 */
191 lcd_write_reg(R_POWER_CONTROL2
, 0x0001);
192 /* PON=0, VRH3-0=0011 */
193 lcd_write_reg(R_POWER_CONTROL3
, 0x0003);
194 /* VCOMG=0, VDV4-0=10001, VCM3-0=11001 */
195 lcd_write_reg(R_POWER_CONTROL4
, 0x1119);
196 /* PON=1, VRH3-0=0011 */
197 lcd_write_reg(R_POWER_CONTROL3
, 0x0013);
200 /* SAP2-0=100, BT2-0=100, AP2-0=100, DK=0, SLP=0, STB=0 */
201 lcd_write_reg(R_POWER_CONTROL1
, 0x4440);
202 /* VCOMG=1, VDV4-0=10001, VCM3-0=11001 */
203 lcd_write_reg(R_POWER_CONTROL4
, 0x3119);
206 /* VSPL=0, HSPL=0, DPL=1, EPL=0, SM=0, GS=x, SS=x, NL4-0=11011 */
207 lcd_write_reg(R_DRV_OUTPUT_CONTROL
, r_drv_output_control
);
208 /* FLD=0, FLD0=1, B/C=1, EOR=1, NW5-0=000000 */
209 lcd_write_reg(R_DRV_WAVEFORM_CONTROL
, 0x0700);
210 /* TRI=0, DFM1-0=11, BGR=0, HWM=1, ID1-0=10, AM=0, LG2-0=000
211 * AM: horizontal update direction
212 * ID1-0: H decrement, V increment
214 lcd_write_reg(R_ENTRY_MODE
, 0x6020);
215 lcd_write_reg(R_COMPARE_REG1
, 0x0000);
216 lcd_write_reg(R_COMPARE_REG2
, 0x0000);
217 /* FP3-0=0010, BP3-0=0010 */
218 lcd_write_reg(R_DISP_CONTROL2
, 0x0202);
219 /* PTG1-0=00 (normal scan), ISC3-0=0000 (ignored) */
220 lcd_write_reg(R_DISP_CONTROL3
, 0x0000);
221 /* NO2-0=01, SDT1-0=00, EQ1-0=01, DIV1-0=00, RTN3-0=0000 */
222 lcd_write_reg(R_FRAME_CYCLE_CONTROL
, 0x4400);
223 /* RM=1, DM1-0=01, RIM1-0=00 */
224 lcd_write_reg(R_EXT_DISP_INTF_CONTROL
, 0x0110);
225 /* SCN4-0=00000 - G1 if GS=0, G240 if GS=1 */
226 lcd_write_reg(R_GATE_SCAN_START_POS
, 0x0000);
227 /* VL7-0=00000000 (0 lines) */
228 lcd_write_reg(R_VERT_SCROLL_CONTROL
, 0x0000);
229 /* SE17-10=219, SS17-10=0 - 220 gates */
230 lcd_write_reg(R_1ST_SCR_DRIVE_POS
, (219 << 8));
231 /* SE27-10=0, SS27-10=0 - no second screen */
232 lcd_write_reg(R_2ND_SCR_DRIVE_POS
, 0x0000);
233 /* HEA=175, HSA=0 = H window from 0-175 */
234 lcd_write_reg(R_HORIZ_RAM_ADDR_POS
, (175 << 8));
235 /* VEA=219, VSA=0 = V window from 0-219 */
236 lcd_write_reg(R_VERT_RAM_ADDR_POS
, (219 << 8));
237 /* PKP12-10=000, PKP02-00=000 */
238 lcd_write_reg(R_GAMMA_FINE_ADJ_POS1
, 0x0000);
239 /* PKP32-30=111, PKP22-20=100 */
240 lcd_write_reg(R_GAMMA_FINE_ADJ_POS2
, 0x0704);
241 /* PKP52-50=001, PKP42-40=111 */
242 lcd_write_reg(R_GAMMA_FINE_ADJ_POS3
, 0x0107);
243 /* PRP12-10=111, PRP02-00=100 */
244 lcd_write_reg(R_GAMMA_GRAD_ADJ_POS
, 0x0704);
245 /* PKN12-10=001, PKN02-00=111 */
246 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG1
, 0x0107);
247 /* PKN32-30=000, PKN22-20=010 */
248 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG2
, 0x0002);
249 /* PKN52-50=111, PKN42-40=111 */
250 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG3
, 0x0707);
251 /* PRN12-10=101, PRN02-00=011 */
252 lcd_write_reg(R_GAMMA_GRAD_ADJ_NEG
, 0x0503);
253 /* VRP14-10=00000, VRP03-00=0000 */
254 lcd_write_reg(R_GAMMA_AMP_ADJ_POS
, 0x0000);
255 /* WRN14-10=00000, VRN03-00=0000 */
256 lcd_write_reg(R_GAMMA_AMP_ADJ_NEG
, 0x0000);
257 /* AD15-0=175 (upper right corner) */
258 lcd_write_reg(R_RAM_ADDR_SET
, 175);
259 /* RM=1, DM1-0=01, RIM1-0=00 */
260 lcd_write_reg(R_EXT_DISP_INTF_CONTROL
, 0x0110);
265 /* Run the display on sequence for the driver IC */
266 static void lcd_display_on(void)
270 /* Power has been turned off so full reinit is needed */
275 /* Restore what we fiddled with when turning display off */
276 /* PON=1, VRH3-0=0011 */
277 lcd_write_reg(R_POWER_CONTROL3
, 0x0013);
278 /* NO2-0=01, SDT1-0=00, EQ1-0=01, DIV1-0=00, RTN3-0=0000 */
279 lcd_write_reg(R_FRAME_CYCLE_CONTROL
, 0x4400);
280 /* VCOMG=1, VDV4-0=10001, VCM3-0=11001 */
281 lcd_write_reg(R_POWER_CONTROL4
, 0x3119);
284 /* SAP2-0=100, BT2-0=111, AP2-0=100, DK=1, SLP=0, STB=0 */
285 lcd_write_reg(R_POWER_CONTROL1
, 0x4740);
289 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=0, DTE=0, CL=0,
291 lcd_write_reg(R_DISP_CONTROL1
, 0x0041 | r_disp_control_rev
);
295 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=0, CL=0,
297 lcd_write_reg(R_DISP_CONTROL1
, 0x0061 | r_disp_control_rev
);
298 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=0, CL=0,
300 lcd_write_reg(R_DISP_CONTROL1
, 0x0063 | r_disp_control_rev
);
304 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=1, CL=0,
306 lcd_write_reg(R_DISP_CONTROL1
, 0x0073 | r_disp_control_rev
);
308 /* Go into write data mode */
309 lcd_send_msg(0x70, R_RAM_WRITE_DATA
);
311 /* tell that we're on now */
316 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
317 bool lcd_active(void)
322 /* Turn off visible display operations */
323 static void lcd_display_off(void)
325 /* block drawing operations and changing of first */
328 /* NO2-0=01, SDT1-0=00, EQ1-0=00, DIV1-0=00, RTN3-0=0000 */
329 lcd_write_reg(R_FRAME_CYCLE_CONTROL
, 0x4000);
331 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=1, CL=0,
333 lcd_write_reg(R_DISP_CONTROL1
, 0x0072 | r_disp_control_rev
);
337 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=0, CL=0,
339 lcd_write_reg(R_DISP_CONTROL1
, 0x0062 | r_disp_control_rev
);
343 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=0, GON=0, DTE=0, CL=0,
345 lcd_write_reg(R_DISP_CONTROL1
, 0x0000);
346 /* SAP2-0=000, BT2-0=000, AP2-0=000, DK=0, SLP=0, STBY=0 */
347 lcd_write_reg(R_POWER_CONTROL1
, 0x0000);
348 /* PON=0, VRH3-0=0011 */
349 lcd_write_reg(R_POWER_CONTROL3
, 0x0003);
350 /* VCOMG=0, VDV4-0=10001, VCM4-0=11001 */
351 lcd_write_reg(R_POWER_CONTROL4
, 0x1119);
355 void lcd_init_device(void)
357 /* All this is magic worked out by MrH */
359 /* Stop any DMA which is in progress */
363 #ifdef BOOTLOADER /* Bother at all to do this again? */
364 /* Init GPIO ports */
366 /* Controller init */
367 GPO32_ENABLE
|= (1 << 28);
368 GPO32_VAL
&= ~(1 << 28);
369 DEV_INIT1
= ( (DEV_INIT1
& 0x03ffffff) | (0x15 << 26) );
370 outl(((inl(0x70000014) & (0x0fffffff)) | (0x5 << 28)), 0x70000014);
371 outl((inl(0x70000020) & ~(0x3 << 10)), 0x70000020);
372 DEV_EN
|= DEV_LCD
; /* Enable controller */
373 outl(0x6, 0x600060d0);
374 DEV_RS
|= DEV_LCD
; /* Reset controller */
375 outl((inl(0x70000020) & ~(1 << 14)), 0x70000020);
377 DEV_RS
&=~DEV_LCD
; /* Clear reset */
380 LCD_REG_0
= (LCD_REG_0
& (0x00ffffff)) | (0x22 << 24);
381 LCD_REG_0
= (LCD_REG_0
& (0xff00ffff)) | (0x14 << 16);
382 LCD_REG_0
= (LCD_REG_0
& (0xffffc0ff)) | (0x3 << 8);
383 LCD_REG_0
= (LCD_REG_0
& (0xffffffc0)) | (0xa);
385 LCD_REG_1
&= 0x00ffffff;
386 LCD_REG_1
&= 0xff00ffff;
387 LCD_REG_1
= (LCD_REG_1
& 0xffff03ff) | (0x2 << 10);
388 LCD_REG_1
= (LCD_REG_1
& 0xfffffc00) | (0xdd);
390 LCD_REG_2
|= (1 << 5);
391 LCD_REG_2
|= (1 << 6);
392 LCD_REG_2
= (LCD_REG_2
& 0xfffffcff) | (0x2 << 8);
394 LCD_REG_7
&= (0xf800ffff);
395 LCD_REG_7
&= (0xfffff800);
397 LCD_REG_8
= (LCD_REG_8
& (0xf800ffff)) | (0xb0 << 16);
398 LCD_REG_8
= (LCD_REG_8
& (0xfffff800)) | (0xdc); /* X-Y Geometry? */
401 LCD_REG_5
= (LCD_REG_5
& ~(0x70)) | (0x3 << 4);
404 LCD_REG_6
&= ~(1 << 15);
405 LCD_REG_6
|= (0xe00);
406 LCD_REG_6
= (LCD_REG_6
& (0xffffff1f)) | (0x4 << 5);
407 LCD_REG_6
|= (1 << 4);
409 LCD_REG_5
&= ~(1 << 7);
410 /* lcd_driver_framebuffer is uncached therefore at the physical address */
411 LCD_FB_BASE_REG
= (long)lcd_driver_framebuffer
;
416 /* Pull RESET low, then high to reset driver IC */
417 GPO32_VAL
&= ~(1 << 28);
419 GPO32_VAL
|= (1 << 28);
424 /* Power and display already ON - switch framebuffer address and reset
426 /* lcd_driver_framebuffer is uncached therefore at the physical address */
427 LCD_FB_BASE_REG
= (long)lcd_driver_framebuffer
;
432 lcd_set_invert_display(false);
436 LCD_REG_6
|= 1; /* Start DMA */
439 #if defined(HAVE_LCD_ENABLE)
440 void lcd_enable(bool on
)
442 if (on
== display_on
)
447 DEV_EN
|= DEV_LCD
; /* Enable LCD controller */
448 lcd_display_on(); /* Turn on display */
449 lcd_update(); /* Resync display */
450 lcd_activation_call_hook();
451 LCD_REG_6
|= 1; /* Restart DMA */
452 sleep(HZ
/50); /* Wait for a frame to be written */
456 LCD_REG_6
&= ~1; /* Disable DMA */
457 sleep(HZ
/50); /* Wait for dma end (assuming 50Hz) */
458 lcd_display_off(); /* Turn off display */
459 DEV_EN
&= ~DEV_LCD
; /* Disable LCD controller */
464 #if defined(HAVE_LCD_SLEEP)
472 /* Turn off display */
479 /* Set standby mode */
480 /* SAP2-0=000, BT2-0=000, AP2-0=000, DK=0, SLP=0, STB=1 */
481 lcd_write_reg(R_POWER_CONTROL1
, 0x0001);
485 /* Copies a rectangle from one framebuffer to another. Can be used in
486 single transfer mode with width = num pixels, and height = 1 which
487 allows a full-width rectangle to be copied more efficiently. */
488 extern void lcd_copy_buffer_rect(fb_data
*dst
, const fb_data
*src
,
489 int width
, int height
);
490 void lcd_update_rect(int x
, int y
, int width
, int height
)
497 if (x
+ width
> LCD_WIDTH
)
498 width
= LCD_WIDTH
- x
; /* Clip right */
500 width
+= x
, x
= 0; /* Clip left */
502 return; /* nothing left to do */
504 if (y
+ height
> LCD_HEIGHT
)
505 height
= LCD_HEIGHT
- y
; /* Clip bottom */
507 height
+= y
, y
= 0; /* Clip top */
509 return; /* nothing left to do */
511 dst
= &lcd_driver_framebuffer
[y
][x
];
512 src
= &lcd_framebuffer
[y
][x
];
514 /* Copy part of the Rockbox framebuffer to the second framebuffer */
515 if (width
< LCD_WIDTH
)
517 /* Not full width - do line-by-line */
518 lcd_copy_buffer_rect(dst
, src
, width
, height
);
522 /* Full width - copy as one line */
523 lcd_copy_buffer_rect(dst
, src
, LCD_WIDTH
*height
, 1);
527 void lcd_update(void)
532 /* Copy the Rockbox framebuffer to the second framebuffer */
533 lcd_copy_buffer_rect(&lcd_driver_framebuffer
[0][0],
534 &lcd_framebuffer
[0][0], LCD_WIDTH
*LCD_HEIGHT
, 1);
538 /*** hardware configuration ***/
540 void lcd_set_contrast(int val
)
542 /* TODO: Implement lcd_set_contrast() */
546 void lcd_set_invert_display(bool yesno
)
548 bool dma_on
= LCD_REG_6
& 1;
552 LCD_REG_6
&= ~1; /* Disable DMA */
553 sleep(HZ
/50); /* Wait for dma end (assuming 50Hz) */
554 DEV_EN
&= ~DEV_LCD
; /* Disable LCD controller */
557 r_disp_control_rev
= yesno
? R_DISP_CONTROL_REV
:
558 R_DISP_CONTROL_NORMAL
;
562 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, CL=0,
563 DTE=1, REV=x, D1-0=11 */
564 lcd_write_reg(R_DISP_CONTROL1
, 0x0073 | r_disp_control_rev
);
569 DEV_EN
|= DEV_LCD
; /* Enable LCD controller */
570 lcd_send_msg(0x70, R_RAM_WRITE_DATA
); /* Set to RAM write mode */
571 LCD_REG_6
|= 1; /* Restart DMA */
575 /* turn the display upside down (call lcd_update() afterwards) */
576 void lcd_set_flip(bool yesno
)
578 bool dma_on
= LCD_REG_6
& 1;
582 LCD_REG_6
&= ~1; /* Disable DMA */
583 sleep(HZ
/50); /* Wait for dma end (assuming 50Hz) */
584 DEV_EN
&= ~DEV_LCD
; /* Disable LCD controller */
587 r_drv_output_control
= yesno
? R_DRV_OUTPUT_CONTROL_FLIPPED
:
588 R_DRV_OUTPUT_CONTROL_NORMAL
;
592 /* VSPL=0, HSPL=0, DPL=1, EPL=0, SM=0, GS=x, SS=x,
593 NL4-0=11011 (G1-G224) */
594 lcd_write_reg(R_DRV_OUTPUT_CONTROL
, r_drv_output_control
);
599 DEV_EN
|= DEV_LCD
; /* Enable LCD controller */
600 lcd_send_msg(0x70, R_RAM_WRITE_DATA
); /* Set to RAM write mode */
601 LCD_REG_6
|= 1; /* Restart DMA */
605 /* Blitting functions */
607 void lcd_yuv_set_options(unsigned options
)
609 lcd_yuv_options
= options
;
612 /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
613 extern void lcd_write_yuv420_lines(fb_data
*dst
,
614 unsigned char const * const src
[3],
617 extern void lcd_write_yuv420_lines_odither(fb_data
*dst
,
618 unsigned char const * const src
[3],
621 int x_screen
, /* To align dither pattern */
623 /* Performance function to blit a YUV bitmap directly to the LCD */
624 /* For the e200 - show it rotated */
625 /* So the LCD_WIDTH is now the height */
626 void lcd_blit_yuv(unsigned char * const src
[3],
627 int src_x
, int src_y
, int stride
,
628 int x
, int y
, int width
, int height
)
630 unsigned char const * yuv_src
[3];
636 /* Sorry, but width and height must be >= 2 or else */
640 y
= LCD_WIDTH
- 1 - y
;
641 fb_data
*dst
= &lcd_driver_framebuffer
[x
][y
];
644 yuv_src
[0] = src
[0] + z
+ src_x
;
645 yuv_src
[1] = src
[1] + (z
>> 2) + (src_x
>> 1);
646 yuv_src
[2] = src
[2] + (yuv_src
[1] - src
[1]);
648 if (lcd_yuv_options
& LCD_YUV_DITHER
)
652 lcd_write_yuv420_lines_odither(dst
, yuv_src
, width
, stride
, y
, x
);
653 yuv_src
[0] += stride
<< 1; /* Skip down two luma lines */
654 yuv_src
[1] += stride
>> 1; /* Skip down one chroma line */
655 yuv_src
[2] += stride
>> 1;
659 while (--height
> 0);
665 lcd_write_yuv420_lines(dst
, yuv_src
, width
, stride
);
666 yuv_src
[0] += stride
<< 1; /* Skip down two luma lines */
667 yuv_src
[1] += stride
>> 1; /* Skip down one chroma line */
668 yuv_src
[2] += stride
>> 1;
671 while (--height
> 0);