1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 by Mark Arigo
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
26 static unsigned lcd_yuv_options SHAREDBSS_ATTR
= 0;
28 /* LCD command set for Samsung S6B33B2 */
31 #define R_OSCILLATION_MODE 0x02
32 #define R_DRIVER_OUTPUT_MODE 0x10
33 #define R_DCDC_SET 0x20
34 #define R_BIAS_SET 0x22
35 #define R_DCDC_CLOCK_DIV 0x24
36 #define R_DCDC_AMP_ONOFF 0x26
37 #define R_TEMP_COMPENSATION 0x28
38 #define R_CONTRAST_CONTROL1 0x2a
39 #define R_CONTRAST_CONTROL2 0x2b
40 #define R_STANDBY_OFF 0x2c
41 #define R_STANDBY_ON 0x2d
42 #define R_DDRAM_BURST_OFF 0x2e
43 #define R_DDRAM_BURST_ON 0x2f
44 #define R_ADDRESSING_MODE 0x30
45 #define R_ROW_VECTOR_MODE 0x32
46 #define R_N_LINE_INVERSION 0x34
47 #define R_FRAME_FREQ_CONTROL 0x36
48 #define R_RED_PALETTE 0x38
49 #define R_GREEN_PALETTE 0x3a
50 #define R_BLUE_PALETTE 0x3c
51 #define R_ENTRY_MODE 0x40
52 #define R_X_ADDR_AREA 0x42
53 #define R_Y_ADDR_AREA 0x43
54 #define R_RAM_SKIP_AREA 0x45
55 #define R_DISPLAY_OFF 0x50
56 #define R_DISPLAY_ON 0x51
57 #define R_SPEC_DISPLAY_PATTERN 0x53
58 #define R_PARTIAL_DISPLAY_MODE 0x55
59 #define R_PARTIAL_START_LINE 0x56
60 #define R_PARTIAL_END_LINE 0x57
61 #define R_AREA_SCROLL_MODE 0x59
62 #define R_SCROLL_START_LINE 0x5a
63 #define R_DATA_FORMAT_SELECT 0x60
65 /* TCC77x specific defines */
66 #define LCD_BASE 0x50000000
67 #define LCD_CMD *(volatile unsigned char*)(LCD_BASE)
68 #define LCD_DATA *(volatile unsigned char*)(LCD_BASE+1)
70 static void lcd_send_command(unsigned cmd
)
81 static void lcd_send_data(unsigned data
)
83 LCD_DATA
= (data
& 0xff00) >> 8;
84 LCD_DATA
= (data
& 0x00ff);
87 /* End of TCC77x specific defines */
90 void lcd_init_device(void)
94 /* Telechips init the same as the original firmware */
95 bus_width
= ((MCFG
>> 11) & 0x3) ^ 3;
97 CSCFG1
= (bus_width
<< 28) |
98 (3 << 26) | /* MTYPE = 3 */
99 ((LCD_BASE
>> 28) << 22) | /* CSBASE = 0x5 */
100 (1 << 20) | /* Unknown */
101 (2 << 11) | /* Setup time = 2 cycles */
102 (2 << 3) | /* Pulse width = 2+1 cycles */
103 (2 << 0); /* Hold time = 2 cycle */
106 sleep(HZ
/100); /* 10ms */
109 sleep(HZ
/100); /* 10ms */
111 lcd_send_command(R_STANDBY_OFF
);
112 sleep(HZ
/20); /* 50ms */
114 lcd_send_command(R_OSCILLATION_MODE
);
115 lcd_send_command(0x01);
116 sleep(HZ
/100); /* 10ms */
118 lcd_send_command(R_DCDC_AMP_ONOFF
);
119 lcd_send_command(0x01);
120 sleep(HZ
/100); /* 10ms */
122 lcd_send_command(R_DCDC_AMP_ONOFF
);
123 lcd_send_command(0x09);
124 sleep(HZ
/100); /* 10ms */
126 lcd_send_command(R_DCDC_AMP_ONOFF
);
127 lcd_send_command(0x0b);
128 sleep(HZ
/100); /* 10ms */
130 lcd_send_command(R_DCDC_AMP_ONOFF
);
131 lcd_send_command(0x0f);
132 sleep(HZ
/100); /* 10ms */
134 lcd_send_command(R_DCDC_SET
);
135 lcd_send_command(0x01);
136 sleep(HZ
/100); /* 10ms */
137 sleep(HZ
/10); /* 100ms */
139 lcd_send_command(R_TEMP_COMPENSATION
);
140 lcd_send_command(0x01);
141 sleep(HZ
/100); /* 10ms */
143 lcd_send_command(R_DRIVER_OUTPUT_MODE
);
144 lcd_send_command(0x03);
146 lcd_send_command(R_ENTRY_MODE
);
147 lcd_send_command(0x81);
149 lcd_send_command(R_N_LINE_INVERSION
);
150 lcd_send_command(0x04);
151 lcd_send_command(0xfa);
152 lcd_send_command(0x5f);
154 lcd_set_contrast(0x28);
156 lcd_send_command(R_SPEC_DISPLAY_PATTERN
);
157 lcd_send_command(0x0);
158 sleep(HZ
/100); /* 10ms */
160 lcd_send_command(R_ADDRESSING_MODE
);
161 lcd_send_command(0x0);
162 sleep(HZ
/100); /* 10ms */
164 lcd_send_command(R_PARTIAL_DISPLAY_MODE
);
165 lcd_send_command(0x0);
166 sleep(HZ
/100); /* 10ms */
168 lcd_send_command(R_X_ADDR_AREA
);
170 lcd_send_command(0x80);
172 lcd_send_command(R_Y_ADDR_AREA
);
173 lcd_send_command(0x0);
174 lcd_send_command(0x80);
176 lcd_send_command(R_DISPLAY_ON
);
178 lcd_send_command(R_SPEC_DISPLAY_PATTERN
);
179 lcd_send_command(0x0);
186 /*** hardware configuration ***/
187 int lcd_default_contrast(void)
192 void lcd_set_contrast(int val
)
195 lcd_send_command(R_CONTRAST_CONTROL1
);
196 lcd_send_command(val
);
199 void lcd_set_invert_display(bool yesno
)
201 /* TODO: Implement lcd_set_invert_display() */
205 /* turn the display upside down (call lcd_update() afterwards) */
206 void lcd_set_flip(bool yesno
)
208 lcd_send_command(R_DRIVER_OUTPUT_MODE
);
209 lcd_send_command(yesno
? 0x02 : 0x07);
212 /*** update functions ***/
214 /*** update functions ***/
216 void lcd_yuv_set_options(unsigned options
)
218 lcd_yuv_options
= options
;
221 /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
222 extern void lcd_write_yuv420_lines(unsigned char const * const src
[3],
225 extern void lcd_write_yuv420_lines_odither(unsigned char const * const src
[3],
228 int x_screen
, /* To align dither pattern */
230 /* Performance function to blit a YUV bitmap directly to the LCD */
231 void lcd_blit_yuv(unsigned char * const src
[3],
232 int src_x
, int src_y
, int stride
,
233 int x
, int y
, int width
, int height
)
235 unsigned char const * yuv_src
[3];
238 /* Sorry, but width and height must be >= 2 or else */
245 yuv_src
[0] = src
[0] + z
+ src_x
;
246 yuv_src
[1] = src
[1] + (z
>> 2) + (src_x
>> 1);
247 yuv_src
[2] = src
[2] + (yuv_src
[1] - src
[1]);
249 lcd_send_command(R_ENTRY_MODE
);
250 lcd_send_command(0x80);
252 lcd_send_command(R_X_ADDR_AREA
);
254 lcd_send_command(x
+ width
- 1);
256 if (lcd_yuv_options
& LCD_YUV_DITHER
)
260 lcd_send_command(R_Y_ADDR_AREA
);
262 lcd_send_command(y
+ 1);
264 /* NOP needed because on some c200s, the previous lcd_send_command
265 is interpreted as a separate command instead of part of
267 lcd_send_command(R_NOP
);
269 lcd_write_yuv420_lines_odither(yuv_src
, width
, stride
, x
, y
);
270 yuv_src
[0] += stride
<< 1; /* Skip down two luma lines */
271 yuv_src
[1] += stride
>> 1; /* Skip down one chroma line */
272 yuv_src
[2] += stride
>> 1;
275 while (--height
> 0);
281 lcd_send_command(R_Y_ADDR_AREA
);
283 lcd_send_command(y
+ 1);
285 lcd_send_command(R_NOP
);
287 lcd_write_yuv420_lines(yuv_src
, width
, stride
);
288 yuv_src
[0] += stride
<< 1; /* Skip down two luma lines */
289 yuv_src
[1] += stride
>> 1; /* Skip down one chroma line */
290 yuv_src
[2] += stride
>> 1;
293 while (--height
> 0);
298 /* Update the display.
299 This must be called after all other LCD functions that change the display. */
300 void lcd_update(void)
302 lcd_update_rect(0, 0, LCD_WIDTH
, LCD_HEIGHT
);
305 /* Update a fraction of the display. */
306 void lcd_update_rect(int x
, int y
, int width
, int height
)
310 if (x
+ width
>= LCD_WIDTH
)
311 width
= LCD_WIDTH
- x
;
312 if (y
+ height
>= LCD_HEIGHT
)
313 height
= LCD_HEIGHT
- y
;
315 if ((width
<= 0) || (height
<= 0))
316 return; /* Nothing left to do. */
318 addr
= &lcd_framebuffer
[y
][x
];
321 lcd_send_command(R_ENTRY_MODE
); /* The X end address must be larger */
322 lcd_send_command(0x80); /* that the X start address, so we */
323 lcd_send_command(R_X_ADDR_AREA
); /* switch to vertical mode for */
324 lcd_send_command(x
); /* single column updates and set */
325 lcd_send_command(x
+ 1); /* the window width to 2 */
327 lcd_send_command(R_ENTRY_MODE
);
328 lcd_send_command(0x82);
329 lcd_send_command(R_X_ADDR_AREA
);
331 lcd_send_command(x
+ width
- 1);
334 lcd_send_command(R_Y_ADDR_AREA
);
336 lcd_send_command(y
+ height
- 1);
338 /* NOP needed because on some c200s, the previous lcd_send_command is
339 interpreted as a separate command instead of part of R_Y_ADDR_AREA. */
340 lcd_send_command(R_NOP
);
345 lcd_send_data(*addr
++);
347 addr
+= LCD_WIDTH
- width
;
348 } while (--height
> 0);