diff options
Diffstat (limited to 'firmware/target/arm/pbell/vibe500/lcd-vibe500.c')
-rw-r--r-- | firmware/target/arm/pbell/vibe500/lcd-vibe500.c | 503 |
1 files changed, 503 insertions, 0 deletions
diff --git a/firmware/target/arm/pbell/vibe500/lcd-vibe500.c b/firmware/target/arm/pbell/vibe500/lcd-vibe500.c new file mode 100644 index 0000000000..ca483f74ea --- /dev/null +++ b/firmware/target/arm/pbell/vibe500/lcd-vibe500.c | |||
@@ -0,0 +1,503 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id:$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Szymon Dziok | ||
11 | * Based on the Iriver H10 code by Barry Wardell | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #include "config.h" | ||
23 | #include "cpu.h" | ||
24 | #include "lcd.h" | ||
25 | #include "kernel.h" | ||
26 | #include "system.h" | ||
27 | |||
28 | /** Initialized in lcd_init_device() **/ | ||
29 | /* Is the power turned on? */ | ||
30 | static bool power_on; | ||
31 | /* Is the display turned on? */ | ||
32 | static bool display_on; | ||
33 | /* Reverse flag. Must be remembered when display is turned off. */ | ||
34 | static unsigned short disp_control_rev; | ||
35 | /* Contrast setting << 8 */ | ||
36 | static int lcd_contrast; | ||
37 | |||
38 | static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0; | ||
39 | |||
40 | /* Forward declarations */ | ||
41 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | ||
42 | static void lcd_display_off(void); | ||
43 | #endif | ||
44 | |||
45 | /* register defines for the Renesas HD66773R */ | ||
46 | /* | ||
47 | In Packard Bell from the OF - it seems to be | ||
48 | HD66774(gate) with HD66772(source) - registers | ||
49 | are very similar but not all the same | ||
50 | */ | ||
51 | #define R_START_OSC 0x00 | ||
52 | #define R_DEVICE_CODE_READ 0x00 | ||
53 | #define R_DRV_OUTPUT_CONTROL 0x01 | ||
54 | #define R_DRV_AC_CONTROL 0x02 | ||
55 | #define R_POWER_CONTROL1 0x03 | ||
56 | #define R_POWER_CONTROL2 0x04 | ||
57 | #define R_ENTRY_MODE 0x05 | ||
58 | #define R_COMPARE_REG 0x06 | ||
59 | #define R_DISP_CONTROL 0x07 | ||
60 | #define R_FRAME_CYCLE_CONTROL 0x0b | ||
61 | #define R_POWER_CONTROL3 0x0c | ||
62 | #define R_POWER_CONTROL4 0x0d | ||
63 | #define R_POWER_CONTROL5 0x0e | ||
64 | #define R_GATE_SCAN_START_POS 0x0f | ||
65 | #define R_VERT_SCROLL_CONTROL 0x11 | ||
66 | #define R_1ST_SCR_DRV_POS 0x14 | ||
67 | #define R_2ND_SCR_DRV_POS 0x15 | ||
68 | #define R_HORIZ_RAM_ADDR_POS 0x16 | ||
69 | #define R_VERT_RAM_ADDR_POS 0x17 | ||
70 | #define R_RAM_WRITE_DATA_MASK 0x20 | ||
71 | #define R_RAM_ADDR_SET 0x21 | ||
72 | #define R_WRITE_DATA_2_GRAM 0x22 | ||
73 | #define R_RAM_READ_DATA 0x22 | ||
74 | #define R_GAMMA_FINE_ADJ_POS1 0x30 | ||
75 | #define R_GAMMA_FINE_ADJ_POS2 0x31 | ||
76 | #define R_GAMMA_FINE_ADJ_POS3 0x32 | ||
77 | #define R_GAMMA_GRAD_ADJ_POS 0x33 | ||
78 | #define R_GAMMA_FINE_ADJ_NEG1 0x34 | ||
79 | #define R_GAMMA_FINE_ADJ_NEG2 0x35 | ||
80 | #define R_GAMMA_FINE_ADJ_NEG3 0x36 | ||
81 | #define R_GAMMA_GRAD_ADJ_NEG 0x37 | ||
82 | #define R_GAMMA_AMP_ADJ_POS 0x3a | ||
83 | #define R_GAMMA_AMP_ADJ_NEG 0x3b | ||
84 | |||
85 | static inline void lcd_wait_write(void) | ||
86 | { | ||
87 | while (LCD1_CONTROL & LCD1_BUSY_MASK); | ||
88 | } | ||
89 | |||
90 | /* Send command */ | ||
91 | static inline void lcd_send_cmd(unsigned v) | ||
92 | { | ||
93 | lcd_wait_write(); | ||
94 | LCD1_CMD = (v >> 8); | ||
95 | lcd_wait_write(); | ||
96 | LCD1_CMD = (v & 0xff); | ||
97 | } | ||
98 | |||
99 | /* Send 16-bit data */ | ||
100 | static inline void lcd_send_data(unsigned v) | ||
101 | { | ||
102 | lcd_wait_write(); | ||
103 | LCD1_DATA = (v >> 8); | ||
104 | lcd_wait_write(); | ||
105 | LCD1_DATA = (v & 0xff); | ||
106 | } | ||
107 | |||
108 | /* Send 16-bit data byte-swapped. */ | ||
109 | static inline void lcd_send_data_swapped(unsigned v) | ||
110 | { | ||
111 | lcd_wait_write(); | ||
112 | LCD1_DATA = (v & 0xff); | ||
113 | lcd_wait_write(); | ||
114 | LCD1_DATA = (v >> 8); | ||
115 | } | ||
116 | |||
117 | /* Write value to register */ | ||
118 | static void lcd_write_reg(int reg, int val) | ||
119 | { | ||
120 | lcd_send_cmd(reg); | ||
121 | lcd_send_data(val); | ||
122 | } | ||
123 | |||
124 | /*** hardware configuration ***/ | ||
125 | |||
126 | int lcd_default_contrast(void) | ||
127 | { | ||
128 | return DEFAULT_CONTRAST_SETTING; | ||
129 | } | ||
130 | |||
131 | void lcd_set_contrast(int val) | ||
132 | { | ||
133 | lcd_contrast = (val&0x1f) << 8; | ||
134 | if (!power_on) return; | ||
135 | |||
136 | /* VCOMG=1, VDV4-0=xxxxx, VCM4-0=11000 */ | ||
137 | lcd_write_reg(R_POWER_CONTROL5, 0x2018 | lcd_contrast); | ||
138 | } | ||
139 | |||
140 | void lcd_set_invert_display(bool yesno) | ||
141 | { | ||
142 | if (yesno == (disp_control_rev == 0x0000)) | ||
143 | return; | ||
144 | |||
145 | disp_control_rev = yesno ? 0x0000 : 0x0004; | ||
146 | |||
147 | if (!display_on) | ||
148 | return; | ||
149 | |||
150 | /* PT1-0=00, VLE2-1=00, SPT=0, GON=1, DTE=1, REV=x, D1-0=11 */ | ||
151 | lcd_write_reg(R_DISP_CONTROL, 0x0033 | disp_control_rev); | ||
152 | } | ||
153 | |||
154 | /* turn the display upside down (call lcd_update() afterwards) */ | ||
155 | void lcd_set_flip(bool yesno) | ||
156 | { | ||
157 | if (!power_on) | ||
158 | return; | ||
159 | |||
160 | /* SM=0, GS=x, SS=x, NL4-0=10011 (G1-G160) */ | ||
161 | lcd_write_reg(R_DRV_OUTPUT_CONTROL, yesno ? 0x0313 : 0x0013); | ||
162 | } | ||
163 | |||
164 | /* LCD init */ | ||
165 | void lcd_init_device(void) | ||
166 | { | ||
167 | power_on = true; | ||
168 | display_on = true; | ||
169 | disp_control_rev = 0x0004; | ||
170 | lcd_contrast = DEFAULT_CONTRAST_SETTING << 8; | ||
171 | } | ||
172 | |||
173 | #ifdef HAVE_LCD_SLEEP | ||
174 | static void lcd_power_on(void) | ||
175 | { | ||
176 | /* from the OF */ | ||
177 | lcd_write_reg(R_START_OSC,0x01); /* START_OSC */ | ||
178 | sleep(HZ/40); /* 25ms */ | ||
179 | /* set 396x160 dots, SM=0, GS=x, SS=0, NL4-0=10011 G1-G160)*/ | ||
180 | lcd_write_reg(R_DRV_OUTPUT_CONTROL,0x13); | ||
181 | /* FLD1-0=01 (1 field), B/C=1, EOR=1 (C-pat), NW5-0=000000 (1 row) */ | ||
182 | lcd_write_reg(R_DRV_AC_CONTROL,7 << 8); | ||
183 | /* DIT=0, BGR=1, HWM=0, I/D1-0=0 - decrement AC, AM=1, LG2-0=000 */ | ||
184 | lcd_write_reg(R_ENTRY_MODE,0x1008); | ||
185 | lcd_write_reg(0x25,0x0000); /* - ?? */ | ||
186 | lcd_write_reg(0x26,0x0202); /* - ?? */ | ||
187 | lcd_write_reg(0x0A,0x0000); /* - ?? */ | ||
188 | lcd_write_reg(R_FRAME_CYCLE_CONTROL,0x0000); | ||
189 | lcd_write_reg(R_POWER_CONTROL4,0x0000); | ||
190 | sleep(HZ/67); /* 15ms */ | ||
191 | lcd_write_reg(R_POWER_CONTROL5,0x0000); | ||
192 | sleep(HZ/67); /* 15ms */ | ||
193 | lcd_write_reg(R_POWER_CONTROL3,0x0000); | ||
194 | lcd_write_reg(0x09,0x0008); /* - ?? */ | ||
195 | sleep(HZ/67); /* 15ms */ | ||
196 | lcd_write_reg(R_POWER_CONTROL4,0x0003); | ||
197 | sleep(HZ/67); /* 15ms */ | ||
198 | lcd_write_reg(R_POWER_CONTROL5,0x1019); | ||
199 | sleep(HZ/20); /* 50ms */ | ||
200 | lcd_write_reg(R_POWER_CONTROL4,0x0013); | ||
201 | sleep(HZ/67); /* 15ms */ | ||
202 | lcd_write_reg(R_POWER_CONTROL1,0x0010); | ||
203 | sleep(HZ/67); /* 15ms */ | ||
204 | lcd_write_reg(0x09,0x0000); /* - ?? */ | ||
205 | sleep(HZ/67); /* 15ms */ | ||
206 | lcd_write_reg(R_POWER_CONTROL1,0x0010); | ||
207 | sleep(HZ/67); /* 15ms */ | ||
208 | lcd_write_reg(R_POWER_CONTROL5,0x3019); | ||
209 | sleep(HZ/6.6);/* 150ms */ | ||
210 | lcd_write_reg(0x09,0x0002); /* - ?? */ | ||
211 | sleep(HZ/67); /* 15ms */ | ||
212 | lcd_write_reg(R_POWER_CONTROL4,0x0018); | ||
213 | sleep(HZ/20); /* 50ms */ | ||
214 | /* RAM Address set (0x0000) */ | ||
215 | lcd_write_reg(R_RAM_ADDR_SET,0x0000); | ||
216 | /* Gamma settings */ | ||
217 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS1,0x0004); | ||
218 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS2,0x0606); | ||
219 | lcd_write_reg(R_GAMMA_FINE_ADJ_POS3,0x0505); | ||
220 | lcd_write_reg(R_GAMMA_GRAD_ADJ_POS,0x0206); | ||
221 | lcd_write_reg(R_GAMMA_FINE_ADJ_NEG1,0x0505); | ||
222 | lcd_write_reg(R_GAMMA_FINE_ADJ_NEG2,0x0707); | ||
223 | lcd_write_reg(R_GAMMA_FINE_ADJ_NEG3,0x0105); | ||
224 | lcd_write_reg(R_GAMMA_GRAD_ADJ_NEG,0x0301); | ||
225 | lcd_write_reg(R_GAMMA_AMP_ADJ_POS,0x1A00); | ||
226 | lcd_write_reg(R_GAMMA_AMP_ADJ_NEG,0x010E); | ||
227 | |||
228 | lcd_write_reg(R_GATE_SCAN_START_POS,0x0000); | ||
229 | /* Horizontal ram address start/end position (0,127); */ | ||
230 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS,0x7F00); | ||
231 | /* Vertical ram address start/end position (0,159); */ | ||
232 | lcd_write_reg(R_VERT_RAM_ADDR_POS,0x9F00); | ||
233 | |||
234 | lcd_write_reg(R_DISP_CONTROL,0x0005); | ||
235 | sleep(HZ/25); /* 40ms */ | ||
236 | lcd_write_reg(R_DISP_CONTROL,0x0025); | ||
237 | lcd_write_reg(R_DISP_CONTROL,0x0027); | ||
238 | sleep(HZ/25); /* 40ms */ | ||
239 | lcd_write_reg(R_DISP_CONTROL,0x0033 | disp_control_rev); | ||
240 | sleep(HZ/100); /* 10ms */ | ||
241 | lcd_write_reg(R_POWER_CONTROL1,0x0110); | ||
242 | lcd_write_reg(R_FRAME_CYCLE_CONTROL,0x0000); | ||
243 | lcd_write_reg(R_POWER_CONTROL4,0x0013); | ||
244 | lcd_write_reg(R_POWER_CONTROL5,0x2018 | lcd_contrast); | ||
245 | sleep(HZ/20); /* 50ms */ | ||
246 | |||
247 | power_on = true; | ||
248 | } | ||
249 | |||
250 | static void lcd_power_off(void) | ||
251 | { | ||
252 | /* Display must be off first */ | ||
253 | if (display_on) | ||
254 | lcd_display_off(); | ||
255 | |||
256 | /* power_on = false; */ | ||
257 | |||
258 | /** Power OFF sequence **/ | ||
259 | /* The method is unknown */ | ||
260 | } | ||
261 | |||
262 | void lcd_sleep(void) | ||
263 | { | ||
264 | if (power_on) | ||
265 | lcd_power_off(); | ||
266 | |||
267 | /* Set standby mode */ | ||
268 | /* Because we dont know how to power off display | ||
269 | we cannot set standby */ | ||
270 | /* BT2-0=000, DC2-0=000, AP2-0=000, SLP=0, STB=1 */ | ||
271 | /* lcd_write_reg(R_POWER_CONTROL1, 0x0001); */ | ||
272 | } | ||
273 | #endif | ||
274 | |||
275 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | ||
276 | static void lcd_display_off(void) | ||
277 | { | ||
278 | display_on = false; | ||
279 | |||
280 | /** Display OFF sequence **/ | ||
281 | /* In the OF it is called "EnterStandby" */ | ||
282 | |||
283 | /* PT1-0=00, VLE2-1=00, SPT=0, GON=1, DTE=1, REV=x, D1-0=10 */ | ||
284 | lcd_write_reg(R_DISP_CONTROL, 0x0032 | disp_control_rev); | ||
285 | sleep(HZ/22); /* 45ms */ | ||
286 | /* PT1-0=00, VLE2-1=00, SPT=0, GON=1, DTE=0, REV=x, D1-0=10 */ | ||
287 | lcd_write_reg(R_DISP_CONTROL, 0x0022 | disp_control_rev); | ||
288 | sleep(HZ/22); /* 45ms */ | ||
289 | /* PT1-0=00, VLE2-1=00, SPT=0, GON=0, DTE=0, REV=0, D1-0=00 */ | ||
290 | lcd_write_reg(R_DISP_CONTROL, 0x0000); | ||
291 | |||
292 | lcd_write_reg(R_POWER_CONTROL1, 0x0000); | ||
293 | lcd_write_reg(0x09, 0x0000); /* -?? */ | ||
294 | lcd_write_reg(R_POWER_CONTROL4, 0x0000); | ||
295 | |||
296 | sleep(HZ/22); /* 45ms */ | ||
297 | } | ||
298 | #endif | ||
299 | |||
300 | #if defined(HAVE_LCD_ENABLE) | ||
301 | static void lcd_display_on(void) | ||
302 | { | ||
303 | /* Be sure power is on first */ | ||
304 | if (!power_on) | ||
305 | lcd_power_on(); | ||
306 | |||
307 | /** Display ON Sequence **/ | ||
308 | /* In the OF it is called "ExitStandby" */ | ||
309 | |||
310 | lcd_write_reg(R_START_OSC,1); | ||
311 | sleep(HZ/40); /* 25ms */ | ||
312 | lcd_write_reg(R_POWER_CONTROL4,0); | ||
313 | sleep(HZ/67); /* 15ms */ | ||
314 | lcd_write_reg(R_POWER_CONTROL5,0); | ||
315 | sleep(HZ/67); /* 15ms */ | ||
316 | lcd_write_reg(R_DISP_CONTROL,0); | ||
317 | sleep(HZ/67); /* 15ms */ | ||
318 | lcd_write_reg(R_POWER_CONTROL3,0); | ||
319 | lcd_write_reg(0x09,8); /* -?? */ | ||
320 | sleep(HZ/67); /* 15ms */ | ||
321 | lcd_write_reg(R_POWER_CONTROL4,3); | ||
322 | sleep(HZ/67); /* 15ms */ | ||
323 | lcd_write_reg(R_POWER_CONTROL5,0x1019); | ||
324 | sleep(HZ/20); /* 50ms */ | ||
325 | lcd_write_reg(R_POWER_CONTROL4,0x13); | ||
326 | sleep(HZ/67); /* 15ms */ | ||
327 | lcd_write_reg(R_POWER_CONTROL1,0x10); | ||
328 | sleep(HZ/20); /* 50ms */ | ||
329 | lcd_write_reg(0x09,0); /* -?? */ | ||
330 | sleep(HZ/67); /* 15ms */ | ||
331 | lcd_write_reg(R_POWER_CONTROL1,0x10); | ||
332 | sleep(HZ/67); /* 15ms */ | ||
333 | lcd_write_reg(R_POWER_CONTROL5,0x3019); | ||
334 | sleep(HZ/6.6);/* 150ms */ | ||
335 | lcd_write_reg(0x09,2); /* -?? */ | ||
336 | sleep(HZ/20); /* 50ms */ | ||
337 | lcd_write_reg(R_DISP_CONTROL,5); | ||
338 | sleep(HZ/22); /* 45ms */ | ||
339 | lcd_write_reg(R_DISP_CONTROL,0x25); | ||
340 | sleep(HZ/22); /* 45ms */ | ||
341 | lcd_write_reg(R_DISP_CONTROL,0x27); | ||
342 | sleep(HZ/25); /* 40ms */ | ||
343 | lcd_write_reg(R_DISP_CONTROL,0x33 | disp_control_rev); | ||
344 | sleep(HZ/22); /* 45ms */ | ||
345 | /* fix contrast */ | ||
346 | lcd_write_reg(R_POWER_CONTROL5, 0x2018 | lcd_contrast); | ||
347 | |||
348 | display_on = true; | ||
349 | } | ||
350 | |||
351 | void lcd_enable(bool on) | ||
352 | { | ||
353 | if (on == display_on) | ||
354 | return; | ||
355 | |||
356 | if (on) | ||
357 | { | ||
358 | lcd_display_on(); | ||
359 | /* Probably out of sync and we don't wanna pepper the code with | ||
360 | lcd_update() calls for this. */ | ||
361 | lcd_update(); | ||
362 | send_event(LCD_EVENT_ACTIVATION, NULL); | ||
363 | } | ||
364 | else | ||
365 | { | ||
366 | lcd_display_off(); | ||
367 | } | ||
368 | } | ||
369 | #endif | ||
370 | |||
371 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | ||
372 | bool lcd_active(void) | ||
373 | { | ||
374 | return display_on; | ||
375 | } | ||
376 | #endif | ||
377 | |||
378 | /*** update functions ***/ | ||
379 | |||
380 | void lcd_yuv_set_options(unsigned options) | ||
381 | { | ||
382 | lcd_yuv_options = options; | ||
383 | } | ||
384 | |||
385 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ | ||
386 | |||
387 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
388 | int width, | ||
389 | int stride); | ||
390 | extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
391 | int width, | ||
392 | int stride, | ||
393 | int x_screen, /* To align dither pattern */ | ||
394 | int y_screen); | ||
395 | |||
396 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
397 | void lcd_blit_yuv(unsigned char * const src[3], | ||
398 | int src_x, int src_y, int stride, | ||
399 | int x, int y, int width, int height) | ||
400 | { | ||
401 | const unsigned char *yuv_src[3]; | ||
402 | const unsigned char *ysrc_max; | ||
403 | int y0; | ||
404 | int options; | ||
405 | |||
406 | if (!display_on) | ||
407 | return; | ||
408 | |||
409 | width &= ~1; | ||
410 | height &= ~1; | ||
411 | |||
412 | lcd_write_reg(R_VERT_RAM_ADDR_POS, ((LCD_WIDTH - 1 - x) << 8) | | ||
413 | ((LCD_WIDTH-1) - (x + width - 1))); | ||
414 | |||
415 | y0 = LCD_HEIGHT - 1 - y; | ||
416 | |||
417 | lcd_write_reg(R_ENTRY_MODE,0x1000); | ||
418 | |||
419 | yuv_src[0] = src[0] + src_y * stride + src_x; | ||
420 | yuv_src[1] = src[1] + (src_y * stride >> 2) + (src_x >> 1); | ||
421 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
422 | ysrc_max = yuv_src[0] + height * stride; | ||
423 | |||
424 | options = lcd_yuv_options; | ||
425 | |||
426 | do | ||
427 | { | ||
428 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (y0 << 8) | (y0 - 1)); | ||
429 | lcd_write_reg(R_RAM_ADDR_SET, ((LCD_WIDTH - 1 - x) << 8) | y0); | ||
430 | |||
431 | /* start drawing */ | ||
432 | lcd_send_cmd(R_WRITE_DATA_2_GRAM); | ||
433 | |||
434 | if (options & LCD_YUV_DITHER) | ||
435 | { | ||
436 | lcd_write_yuv420_lines_odither(yuv_src, width, stride,x, y); | ||
437 | y -= 2; | ||
438 | } | ||
439 | else | ||
440 | { | ||
441 | lcd_write_yuv420_lines(yuv_src, width, stride); | ||
442 | } | ||
443 | |||
444 | y0 -= 2; | ||
445 | yuv_src[0] += stride << 1; | ||
446 | yuv_src[1] += stride >> 1; | ||
447 | yuv_src[2] += stride >> 1; | ||
448 | } | ||
449 | while (yuv_src[0] < ysrc_max); | ||
450 | lcd_write_reg(R_ENTRY_MODE,0x1008); | ||
451 | } | ||
452 | |||
453 | /* Update a fraction of the display. */ | ||
454 | void lcd_update_rect(int x0, int y0, int width, int height) | ||
455 | { | ||
456 | const fb_data *addr; | ||
457 | int x1, y1; | ||
458 | |||
459 | if (!display_on) | ||
460 | return; | ||
461 | |||
462 | if ((width<=0)||(height<=0)) | ||
463 | return; | ||
464 | |||
465 | if ((x0 + width)>=LCD_WIDTH) | ||
466 | width = LCD_WIDTH - x0; | ||
467 | if ((y0 + height)>=LCD_HEIGHT) | ||
468 | height = LCD_HEIGHT - y0; | ||
469 | |||
470 | y1 = (y0 + height) - 1; | ||
471 | x1 = (x0 + width) - 1; | ||
472 | |||
473 | /* In the PB Vibe LCD is flipped and the RAM addresses are decremented */ | ||
474 | lcd_send_cmd(R_HORIZ_RAM_ADDR_POS); | ||
475 | lcd_send_data( (((LCD_HEIGHT-1)-y0) << 8) | ((LCD_HEIGHT-1)-y1)); | ||
476 | |||
477 | lcd_send_cmd(R_VERT_RAM_ADDR_POS); | ||
478 | lcd_send_data( (((LCD_WIDTH -1)-x0) << 8) | ((LCD_WIDTH -1)-x1)); | ||
479 | |||
480 | lcd_send_cmd(R_RAM_ADDR_SET); | ||
481 | lcd_send_data( (((LCD_WIDTH -1)-x0) << 8) | ((LCD_HEIGHT-1)-y0)); | ||
482 | |||
483 | /* start drawing */ | ||
484 | lcd_send_cmd(R_WRITE_DATA_2_GRAM); | ||
485 | |||
486 | addr = &lcd_framebuffer[y0][x0]; | ||
487 | |||
488 | int c, r; | ||
489 | for (r = 0; r < height; r++) | ||
490 | { | ||
491 | for (c = 0; c < width; c++) | ||
492 | lcd_send_data_swapped(*addr++); | ||
493 | addr += LCD_WIDTH - width; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | /* Update the display. | ||
498 | This must be called after all other LCD | ||
499 | functions that change the display. */ | ||
500 | void lcd_update(void) | ||
501 | { | ||
502 | lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); | ||
503 | } | ||