summaryrefslogtreecommitdiff
path: root/firmware/target/arm
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-07-08 13:02:52 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-07-08 13:02:52 +0000
commit1bbd58e2d8e4bf9c9942c5b70ff4e480a6fc56f2 (patch)
tree3dd2b077a3df6468b6226623db692c14fc27d0f9 /firmware/target/arm
parent32eddb44be92d8d14ad757e87de652fd67b59c89 (diff)
downloadrockbox-1bbd58e2d8e4bf9c9942c5b70ff4e480a6fc56f2.tar.gz
rockbox-1bbd58e2d8e4bf9c9942c5b70ff4e480a6fc56f2.zip
e200 lcd mashup: 1) Enable flipped and inverted mode. 2) Fully enable all power options so that LCD driver IC's visible display is shut down with backlight and make the Sleep option available 3) Better framebuffer copy routine in assembly that confines updates to the specified rectangle _and_ is faster than memcpy 4) Some other offhand changes out of preference.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13818 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/sandisk/sansa-e200/lcd-as-e200.S89
-rw-r--r--firmware/target/arm/sandisk/sansa-e200/lcd-e200.c496
2 files changed, 440 insertions, 145 deletions
diff --git a/firmware/target/arm/sandisk/sansa-e200/lcd-as-e200.S b/firmware/target/arm/sandisk/sansa-e200/lcd-as-e200.S
index 9e130cf54b..f4805fd1e1 100644
--- a/firmware/target/arm/sandisk/sansa-e200/lcd-as-e200.S
+++ b/firmware/target/arm/sandisk/sansa-e200/lcd-as-e200.S
@@ -21,6 +21,87 @@
21#include "cpu.h" 21#include "cpu.h"
22 22
23/**************************************************************************** 23/****************************************************************************
24 * void lcd_copy_buffer_rect(fb_data *dst, fb_data *src, int width,
25 * int height);
26 */
27 .section .icode, "ax", %progbits
28 .align 2
29 .global lcd_copy_buffer_rect
30 .type lcd_copy_buffer_rect, %function
31 @ r0 = dst
32 @ r1 = src
33 @ r2 = width
34 @ r3 = height
35lcd_copy_buffer_rect: @
36 stmfd sp!, { r4-r12, lr } @ save non-scratch regs
37 mov r5, r2 @ r5 = cached width
38 rsb r4, r2, #LCD_WIDTH @ r4 = LCD_WIDTH - width
3910: @ copy line @
40 subs r2, r5, #1 @ r2 = width - 1
41 beq 40f @ finish line @ one halfword? skip to trailing copy
42 tst r0, #2 @ word aligned?
43 beq 20f @ rem copy @ yes? skip to word copy
44 ldrh r6, [r1], #2 @ copy leading halfword
45 subs r2, r2, #1 @
46 strh r6, [r0], #2 @
47 ble 40f @ finish line @ next line if lt or finish
48 @ trailing halfword if eq
4920: @ rem copy @
50 add r14, r2, #1 @ get remaining width mod 16 after word
51 @ align (rw)
52 and r14, r14, #0xe @ r14 = 0 (16), 2, 4, 6, 8, 10, 12, 14
53 add pc, pc, r14, lsl #3 @ branch to 32-byte align
54 nop @
55 b 30f @ rw % 16 = 0 or 1? use octword loop
56 nop @
57 nop @
58 nop @
59 ldr r6, [r1], #4 @ rw % 16 = 2 or 3
60 subs r2, r2, #2 @
61 str r6, [r0], #4 @
62 b 25f @ copy up done @
63 ldmia r1!, { r6-r7 } @ rw % 16 = 4 or 5
64 subs r2, r2, #4 @
65 stmia r0!, { r6-r7 } @
66 b 25f @ copy up done @
67 ldmia r1!, { r6-r8 } @ rw % 16 = 6 or 7
68 subs r2, r2, #6 @
69 stmia r0!, { r6-r8 } @
70 b 25f @ copy up done @
71 ldmia r1!, { r6-r9 } @ rw % 16 = 8 or 9
72 subs r2, r2, #8 @
73 stmia r0!, { r6-r9 } @
74 b 25f @ copy up done @
75 ldmia r1!, { r6-r10 } @ rw % 16 = 10 or 11
76 subs r2, r2, #10 @
77 stmia r0!, { r6-r10 } @
78 b 25f @ copy up done @
79 ldmia r1!, { r6-r11 } @ rw % 16 = 12 or 13
80 subs r2, r2, #12 @
81 stmia r0!, { r6-r11 } @
82 b 25f @ copy up done @
83 ldmia r1!, { r6-r12 } @ rw % 16 = 14 or 15
84 subs r2, r2, #14 @
85 stmia r0!, { r6-r12 } @
8625: @ copy up done @
87 ble 40f @ finish line @ no 32-byte segments remaining?
8830: @ octword loop @ copy 16 pixels per loop
89 ldmia r1!, { r6-r12, r14 } @
90 subs r2, r2, #16 @
91 stmia r0!, { r6-r12, r14 } @
92 bgt 30b @ octword loop @
9340: @ finish line @
94 ldreqh r6, [r1], #2 @ finish last halfword if eq ...
95 add r1, r1, r4, lsl #1 @
96 streqh r6, [r0], #2 @ ...
97 add r0, r0, r4, lsl #1 @
98 subs r3, r3, #1 @ next line
99 bgt 10b @ copy line @
100 ldmfd sp!, { r4-r12, pc } @ restore regs and return
101 .size lcd_copy_buffer_rect, .-lcd_copy_buffer_rect
102
103
104/****************************************************************************
24 * void lcd_write_yuv_420_lines(fb_data *dst, 105 * void lcd_write_yuv_420_lines(fb_data *dst,
25 * unsigned char chroma_buf[LCD_HEIGHT/2*3], 106 * unsigned char chroma_buf[LCD_HEIGHT/2*3],
26 unsigned char const * const src[3], 107 unsigned char const * const src[3],
@@ -45,8 +126,8 @@ lcd_write_yuv420_lines:
45 @ r2 = yuv_src 126 @ r2 = yuv_src
46 @ r3 = width 127 @ r3 = width
47 @ [sp] = stride 128 @ [sp] = stride
48 stmdb sp!, { r4-r12, lr } @ save non-scratch 129 stmfd sp!, { r4-r12, lr } @ save non-scratch
49 stmdb sp!, { r0, r3 } @ save dst and width 130 stmfd sp!, { r0, r3 } @ save dst and width
50 mov r14, #74 @ r14 = Y factor 131 mov r14, #74 @ r14 = Y factor
51 ldmia r2, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p 132 ldmia r2, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
52 @ r5 = yuv_src[1] = Cb_p 133 @ r5 = yuv_src[1] = Cb_p
@@ -140,7 +221,7 @@ lcd_write_yuv420_lines:
140 bgt 10b @ loop line 1 @ 221 bgt 10b @ loop line 1 @
141 @ do second line 222 @ do second line
142 @ 223 @
143 ldmia sp!, { r0, r3 } @ pop dst and width 224 ldmfd sp!, { r0, r3 } @ pop dst and width
144 sub r0, r0, #2 @ set dst to start of next line 225 sub r0, r0, #2 @ set dst to start of next line
145 sub r1, r1, r3, asl #1 @ rewind chroma pointer... 226 sub r1, r1, r3, asl #1 @ rewind chroma pointer...
146 ldr r2, [sp, #40] @ r2 = stride 227 ldr r2, [sp, #40] @ r2 = stride
@@ -218,5 +299,5 @@ lcd_write_yuv420_lines:
218 subs r3, r3, #2 @ 299 subs r3, r3, #2 @
219 bgt 20b @ loop line 2 @ 300 bgt 20b @ loop line 2 @
220 @ 301 @
221 ldmia sp!, { r4-r12, pc } @ restore registers and return 302 ldmfd sp!, { r4-r12, pc } @ restore registers and return
222 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines 303 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
diff --git a/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c b/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c
index 86f12567b4..3b55bdd15e 100644
--- a/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c
+++ b/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c
@@ -26,6 +26,20 @@
26#include "backlight-target.h" 26#include "backlight-target.h"
27#include "pp5024.h" 27#include "pp5024.h"
28 28
29/* Power and display status */
30static bool power_on = false; /* Is the power turned on? */
31static bool display_on NOCACHEBSS_ATTR = false; /* Is the display turned on? */
32
33/* Reverse Flag */
34#define R_DISP_CONTROL_NORMAL 0x0004
35#define R_DISP_CONTROL_REV 0x0000
36static unsigned short r_disp_control_rev = R_DISP_CONTROL_NORMAL;
37
38/* Flipping */
39#define R_DRV_OUTPUT_CONTROL_NORMAL 0x101b
40#define R_DRV_OUTPUT_CONTROL_FLIPPED 0x131b
41static unsigned short r_drv_output_control = R_DRV_OUTPUT_CONTROL_NORMAL;
42
29#define LCD_DATA_IN_GPIO GPIOB_INPUT_VAL 43#define LCD_DATA_IN_GPIO GPIOB_INPUT_VAL
30#define LCD_DATA_IN_PIN 6 44#define LCD_DATA_IN_PIN 6
31 45
@@ -168,7 +182,177 @@ static unsigned long phys_fb_address(unsigned long address)
168 } 182 }
169} 183}
170 184
171inline void lcd_init_device(void) 185/* Run the powerup sequence for the driver IC */
186static void lcd_power_on(void)
187{
188 /* Clear standby bit */
189 lcd_write_reg(R_POWER_CONTROL1, 0x0000);
190
191 /** Power ON Sequence **/
192 lcd_write_reg(R_START_OSC, 0x0001);
193 /* 10ms or more for oscillation circuit to stabilize */
194 sleep(HZ/50);
195
196 /* SAP2-0=100, BT2-0=100, AP2-0=100, DK=1, SLP=0, STB=0 */
197 lcd_write_reg(R_POWER_CONTROL1, 0x4444);
198 /* DC12-10=000, DC2-0=000, VC2-0=001 */
199 lcd_write_reg(R_POWER_CONTROL2, 0x0001);
200 /* PON=0, VRH3-0=0011 */
201 lcd_write_reg(R_POWER_CONTROL3, 0x0003);
202 /* VCOMG=0, VDV4-0=10001, VCM3-0=11001 */
203 lcd_write_reg(R_POWER_CONTROL4, 0x1119);
204 /* PON=1, VRH3-0=0011 */
205 lcd_write_reg(R_POWER_CONTROL3, 0x0013);
206 sleep(HZ/25);
207
208 /* SAP2-0=100, BT2-0=100, AP2-0=100, DK=0, SLP=0, STB=0 */
209 lcd_write_reg(R_POWER_CONTROL1, 0x4440);
210 /* VCOMG=1, VDV4-0=10001, VCM3-0=11001 */
211 lcd_write_reg(R_POWER_CONTROL4, 0x3119);
212 sleep(HZ/6);
213
214 /* VSPL=0, HSPL=0, DPL=1, EPL=0, SM=0, GS=x, SS=x, NL4-0=11011 */
215 lcd_write_reg(R_DRV_OUTPUT_CONTROL, r_drv_output_control);
216 /* FLD=0, FLD0=1, B/C=1, EOR=1, NW5-0=000000 */
217 lcd_write_reg(R_DRV_WAVEFORM_CONTROL, 0x0700);
218 /* TRI=0, DFM1-0=11, BGR=0, HWM=1, ID1-0=10, AM=0, LG2-0=000
219 * AM: horizontal update direction
220 * ID1-0: H decrement, V increment
221 */
222 lcd_write_reg(R_ENTRY_MODE, 0x6020);
223 lcd_write_reg(R_COMPARE_REG1, 0x0000);
224 lcd_write_reg(R_COMPARE_REG2, 0x0000);
225 /* FP3-0=0001, BP3-0=0010 */
226 lcd_write_reg(R_DISP_CONTROL2, 0x0102);
227 /* PTG1-0=00 (normal scan), ISC3-0=0000 (ignored) */
228 lcd_write_reg(R_DISP_CONTROL3, 0x0000);
229 /* NO2-0=01, SDT1-0=00, EQ1-0=01, DIV1-0=00, RTN3-0=0000 */
230 lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x4400);
231 /* RM=1, DM1-0=01, RIM1-0=00 */
232 lcd_write_reg(R_EXT_DISP_INTF_CONTROL, 0x0110);
233 /* SCN4-0=00000 - G1 if GS=0, G240 if GS=1 */
234 lcd_write_reg(R_GATE_SCAN_START_POS, 0x0000);
235 /* VL7-0=00000000 (0 lines) */
236 lcd_write_reg(R_VERT_SCROLL_CONTROL, 0x0000);
237 /* SE17-10=219, SS17-10=0 - 220 gates */
238 lcd_write_reg(R_1ST_SCR_DRIVE_POS, (219 << 8));
239 /* SE27-10=0, SS27-10=0 - no second screen */
240 lcd_write_reg(R_2ND_SCR_DRIVE_POS, 0x0000);
241 /* HEA=175, HSA=0 = H window from 0-175 */
242 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (175 << 8));
243 /* VEA=219, VSA=0 = V window from 0-219 */
244 lcd_write_reg(R_VERT_RAM_ADDR_POS, (219 << 8));
245 /* PKP12-10=000, PKP02-00=000 */
246 lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0000);
247 /* PKP32-30=111, PKP22-20=100 */
248 lcd_write_reg(R_GAMMA_FINE_ADJ_POS2, 0x0704);
249 /* PKP52-50=001, PKP42-40=111 */
250 lcd_write_reg(R_GAMMA_FINE_ADJ_POS3, 0x0107);
251 /* PRP12-10=111, PRP02-00=100 */
252 lcd_write_reg(R_GAMMA_GRAD_ADJ_POS, 0x0704);
253 /* PKN12-10=001, PKN02-00=111 */
254 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG1, 0x0107);
255 /* PKN32-30=000, PKN22-20=010 */
256 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG2, 0x0002);
257 /* PKN52-50=111, PKN42-40=111 */
258 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG3, 0x0707);
259 /* PRN12-10=101, PRN02-00=011 */
260 lcd_write_reg(R_GAMMA_GRAD_ADJ_NEG, 0x0503);
261 /* VRP14-10=00000, VRP03-00=0000 */
262 lcd_write_reg(R_GAMMA_AMP_ADJ_POS, 0x0000);
263 /* WRN14-10=00000, VRN03-00=0000 */
264 lcd_write_reg(R_GAMMA_AMP_ADJ_NEG, 0x0000);
265 /* AD15-0=175 (upper right corner) */
266 lcd_write_reg(R_RAM_ADDR_SET, 175);
267 /* RM=1, DM1-0=01, RIM1-0=00 */
268 lcd_write_reg(R_EXT_DISP_INTF_CONTROL, 0x0110);
269
270 power_on = true;
271}
272
273/* Run the display on sequence for the driver IC */
274static void lcd_display_on(void)
275{
276 if (!power_on)
277 {
278 /* Power has been turned off so full reinit is needed */
279 lcd_power_on();
280 }
281 else
282 {
283 /* Restore what we fiddled with when turning display off */
284 /* PON=1, VRH3-0=0011 */
285 lcd_write_reg(R_POWER_CONTROL3, 0x0013);
286 /* NO2-0=01, SDT1-0=00, EQ1-0=01, DIV1-0=00, RTN3-0=0000 */
287 lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x4400);
288 /* VCOMG=1, VDV4-0=10001, VCM3-0=11001 */
289 lcd_write_reg(R_POWER_CONTROL4, 0x3119);
290 }
291
292 /* SAP2-0=100, BT2-0=111, AP2-0=100, DK=1, SLP=0, STB=0 */
293 lcd_write_reg(R_POWER_CONTROL1, 0x4740);
294
295 sleep(HZ/25);
296
297 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=0, DTE=0, CL=0,
298 REV=x, D1-0=01 */
299 lcd_write_reg(R_DISP_CONTROL1, 0x0041 | r_disp_control_rev);
300
301 udelay(HZ/20);
302
303 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=0, CL=0,
304 REV=x, D1-0=01 */
305 lcd_write_reg(R_DISP_CONTROL1, 0x0061 | r_disp_control_rev);
306 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=0, CL=0,
307 REV=x, D1-0=11 */
308 lcd_write_reg(R_DISP_CONTROL1, 0x0063 | r_disp_control_rev);
309
310 udelay(HZ/20);
311
312 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, DTE=1, CL=0,
313 REV=x, D1-0=11 */
314 lcd_write_reg(R_DISP_CONTROL1, 0x0073 | r_disp_control_rev);
315
316 /* Go into write data mode */
317 lcd_send_msg(0x70, R_RAM_WRITE_DATA);
318
319 /* tell that we're on now */
320 display_on = true;
321}
322
323/* Turn off visible display operations */
324static void lcd_display_off(void)
325{
326 /* block drawing operations and changing of first */
327 display_on = false;
328
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);
331
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);
335
336 sleep(HZ/25);
337
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);
341
342 sleep(HZ/25);
343
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);
353}
354
355void lcd_init_device(void)
172{ 356{
173/* All this is magic worked out by MrH */ 357/* All this is magic worked out by MrH */
174 358
@@ -176,6 +360,7 @@ inline void lcd_init_device(void)
176 LCD_REG_6 &= ~1; 360 LCD_REG_6 &= ~1;
177 udelay(100000); 361 udelay(100000);
178 362
363#ifdef BOOTLOADER /* Bother at all to do this again? */
179/* Init GPIO ports */ 364/* Init GPIO ports */
180 lcd_init_gpio(); 365 lcd_init_gpio();
181/* Controller init */ 366/* Controller init */
@@ -227,145 +412,128 @@ inline void lcd_init_device(void)
227 udelay(100000); 412 udelay(100000);
228 413
229/* LCD init */ 414/* LCD init */
230 415 /* Pull RESET low, then high to reset driver IC */
231 /* TODO: Eliminate some of this outside the bootloader since this
232 will already be setup and that will eliminate white-screen */
233
234 /* Pull RESET low, then high */
235 outl((inl(0x70000080) & ~(1 << 28)), 0x70000080); 416 outl((inl(0x70000080) & ~(1 << 28)), 0x70000080);
236 udelay(10000); 417 udelay(10000);
237 outl((inl(0x70000080) | (1 << 28)), 0x70000080); 418 outl((inl(0x70000080) | (1 << 28)), 0x70000080);
238 udelay(10000); 419 udelay(10000);
239 420
240 lcd_write_reg(R_POWER_CONTROL1, 0x4444); 421 lcd_display_on();
241 lcd_write_reg(R_POWER_CONTROL2, 0x0001); 422#else
242 lcd_write_reg(R_POWER_CONTROL3, 0x0003); 423 /* Power and display already ON - switch framebuffer address and reset
243 lcd_write_reg(R_POWER_CONTROL4, 0x1119); 424 settings */
244 lcd_write_reg(R_POWER_CONTROL3, 0x0013); 425 LCD_FB_BASE_REG = phys_fb_address((unsigned long)lcd_driver_framebuffer);
245 udelay(50000);
246
247 lcd_write_reg(R_POWER_CONTROL1, 0x4440);
248 lcd_write_reg(R_POWER_CONTROL4, 0x3119);
249 udelay(150000);
250
251 lcd_write_reg(R_DRV_OUTPUT_CONTROL, 0x101b);
252 lcd_write_reg(R_DRV_WAVEFORM_CONTROL, 0x0700);
253 lcd_write_reg(R_ENTRY_MODE, 0x6020);
254 lcd_write_reg(R_COMPARE_REG1, 0x0000);
255 lcd_write_reg(R_COMPARE_REG2, 0x0000);
256 lcd_write_reg(R_DISP_CONTROL2, 0x0102);
257 lcd_write_reg(R_DISP_CONTROL3, 0x0000);
258 lcd_write_reg(R_FRAME_CYCLE_CONTROL, 0x4400);
259 lcd_write_reg(R_EXT_DISP_INTF_CONTROL, 0x0110);
260
261 lcd_write_reg(R_GATE_SCAN_START_POS, 0x0000);
262 lcd_write_reg(R_VERT_SCROLL_CONTROL, 0x0000);
263 lcd_write_reg(R_1ST_SCR_DRIVE_POS, (219 << 8));
264 lcd_write_reg(R_2ND_SCR_DRIVE_POS, 0x0000);
265 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (175 << 8));
266 lcd_write_reg(R_VERT_RAM_ADDR_POS, (219 << 8));
267
268 lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0000);
269 lcd_write_reg(R_GAMMA_FINE_ADJ_POS2, 0x0704);
270 lcd_write_reg(R_GAMMA_FINE_ADJ_POS3, 0x0107);
271 lcd_write_reg(R_GAMMA_GRAD_ADJ_POS, 0x0704);
272 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG1, 0x0107);
273 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG2, 0x0002);
274 lcd_write_reg(R_GAMMA_FINE_ADJ_NEG3, 0x0707);
275 lcd_write_reg(R_GAMMA_GRAD_ADJ_NEG, 0x0503);
276 lcd_write_reg(R_GAMMA_AMP_ADJ_POS, 0x0000);
277 lcd_write_reg(R_GAMMA_AMP_ADJ_NEG, 0x0000);
278
279 lcd_write_reg(R_RAM_ADDR_SET, 175);
280
281 lcd_write_reg(R_EXT_DISP_INTF_CONTROL, 0x0110);
282
283 lcd_write_reg(R_POWER_CONTROL1, 0x4740);
284
285 lcd_write_reg(R_DISP_CONTROL1, 0x0045);
286
287 udelay(50000);
288
289 lcd_write_reg(R_DISP_CONTROL1, 0x0065);
290 lcd_write_reg(R_DISP_CONTROL1, 0x0067);
291
292 udelay(50000);
293 426
294 lcd_write_reg(R_DISP_CONTROL1, 0x0077); 427 power_on = true;
428 display_on = true;
295 429
296 lcd_send_msg(0x70, R_RAM_WRITE_DATA); 430 lcd_set_invert_display(false);
431 lcd_set_flip(false);
432#endif
297 433
298 LCD_REG_6 |= 1; /* Start DMA */ 434 LCD_REG_6 |= 1; /* Start DMA */
299} 435}
300 436
301void lcd_enable(bool on) 437void lcd_enable(bool on)
302{ 438{
303 if(on) 439 if (on == display_on)
440 return;
441
442 if (on)
304 { 443 {
305 if(!(DEV_EN & DEV_LCD)) 444 DEV_EN |= DEV_LCD; /* Enable LCD controller */
306 { 445 lcd_display_on(); /* Turn on display */
307 DEV_EN |= DEV_LCD; /* Enable LCD controller */ 446 lcd_update(); /* Resync display */
308 lcd_update(); /* Resync display */ 447 LCD_REG_6 |= 1; /* Restart DMA */
309 LCD_REG_6 |= 1; /* Restart DMA */ 448 sleep(HZ/25); /* Wait for a frame to be written by
310 } 449 DMA or a white flash will happen */
311 } 450 }
312 else 451 else
313 { 452 {
314 if(DEV_EN & DEV_LCD) 453 LCD_REG_6 &= ~1; /* Disable DMA */
315 { 454 sleep(HZ/50); /* Wait for dma end (assuming 50Hz) */
316 LCD_REG_6 &= ~1; /* Disable DMA */ 455 lcd_display_off(); /* Turn off display */
317 udelay(20000); /* Wait for dma end (assuming 50Hz) */ 456 DEV_EN &= ~DEV_LCD; /* Disable LCD controller */
318 DEV_EN &= ~DEV_LCD; /* Disable LCD controller */
319 }
320 } 457 }
321} 458}
322 459
323void lcd_update_rect(int x, int y, int width, int height) 460void lcd_sleep(void)
324{ 461{
325 (void)x; 462 LCD_REG_6 &= ~1;
326 (void)width; 463 sleep(HZ/50);
327 464
328 if(DEV_EN & DEV_LCD) 465 if (power_on)
329 { 466 {
330#if 0 467 /* Turn off display */
331 /* Turn off DMA and wait for the transfer to complete */ 468 if (display_on)
332 /* TODO: Work out the proper delay */ 469 lcd_display_off();
333 LCD_REG_6 &= ~1; 470
334 udelay(1000); 471 power_on = false;
335#endif
336 /* Copy the Rockbox framebuffer to the second framebuffer */
337 /* TODO: Move the second framebuffer into uncached SDRAM */
338 memcpy(((char*)&lcd_driver_framebuffer)+(y * sizeof(fb_data) * LCD_WIDTH),
339 ((char *)&lcd_framebuffer)+(y * sizeof(fb_data) * LCD_WIDTH),
340 ((height * sizeof(fb_data) * LCD_WIDTH)));
341 flush_icache();
342#if 0
343 /* Restart DMA */
344 LCD_REG_6 |= 1;
345#endif
346 } 472 }
473
474 /* Set standby mode */
475 /* SAP2-0=000, BT2-0=000, AP2-0=000, DK=0, SLP=0, STB=1 */
476 lcd_write_reg(R_POWER_CONTROL1, 0x0001);
347} 477}
348 478
349void lcd_update(void) 479/* Copies a rectangle from one framebuffer to another. Can be used in
480 single transfer mode with width = num pixels, and height = 1 which
481 allows a full-width rectangle to be copied more efficiently. */
482extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src,
483 int width, int height);
484void lcd_update_rect(int x, int y, int width, int height)
350{ 485{
351 if(DEV_EN & DEV_LCD) 486 fb_data *dst, *src;
487
488 if (!display_on)
489 return;
490
491 if (x + width > LCD_WIDTH)
492 width = LCD_WIDTH - x; /* Clip right */
493 if (x < 0)
494 width += x, x = 0; /* Clip left */
495 if (width <= 0)
496 return; /* nothing left to do */
497
498 if (y + height > LCD_HEIGHT)
499 height = LCD_HEIGHT - y; /* Clip bottom */
500 if (y < 0)
501 height += y, y = 0; /* Clip top */
502 if (height <= 0)
503 return; /* nothing left to do */
504
505 /* TODO: It may be faster to swap the addresses of lcd_driver_framebuffer
506 * and lcd_framebuffer */
507 dst = &lcd_driver_framebuffer[y][x];
508 src = &lcd_framebuffer[y][x];
509
510 /* Copy part of the Rockbox framebuffer to the second framebuffer */
511 if (width < LCD_WIDTH)
352 { 512 {
353 /* TODO: It may be faster to swap the addresses of lcd_driver_framebuffer 513 /* Not full width - do line-by-line */
354 * and lcd_framebuffer */ 514 lcd_copy_buffer_rect(dst, src, width, height);
355#if 0 515 }
356 /* Turn off DMA and wait for the transfer to complete */ 516 else
357 LCD_REG_6 &= ~1; 517 {
358 udelay(1000); 518 /* Full width - copy as one line */
359#endif 519 lcd_copy_buffer_rect(dst, src, LCD_WIDTH*height, 1);
360 /* Copy the Rockbox framebuffer to the second framebuffer */
361 memcpy(lcd_driver_framebuffer, lcd_framebuffer,
362 sizeof(fb_data) * LCD_WIDTH * LCD_HEIGHT);
363 flush_icache();
364#if 0
365 /* Restart DMA */
366 LCD_REG_6 |= 1;
367#endif
368 } 520 }
521
522 flush_icache();
523}
524
525void lcd_update(void)
526{
527 if (!display_on)
528 return;
529
530 /* TODO: It may be faster to swap the addresses of lcd_driver_framebuffer
531 * and lcd_framebuffer */
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);
535
536 flush_icache();
369} 537}
370 538
371 539
@@ -379,15 +547,61 @@ void lcd_set_contrast(int val)
379 547
380void lcd_set_invert_display(bool yesno) 548void lcd_set_invert_display(bool yesno)
381{ 549{
382 /* TODO: Implement lcd_set_invert_display() */ 550 bool dma_on = LCD_REG_6 & 1;
383 (void)yesno; 551
552 if (dma_on)
553 {
554 LCD_REG_6 &= ~1; /* Disable DMA */
555 sleep(HZ/50); /* Wait for dma end (assuming 50Hz) */
556 DEV_EN &= ~DEV_LCD; /* Disable LCD controller */
557 }
558
559 r_disp_control_rev = yesno ? R_DISP_CONTROL_REV :
560 R_DISP_CONTROL_NORMAL;
561
562 if (display_on)
563 {
564 /* PT1-0=00, VLE2-1=00, SPT=0, IB6(??)=1, GON=1, CL=0,
565 DTE=1, REV=x, D1-0=11 */
566 lcd_write_reg(R_DISP_CONTROL1, 0x0073 | r_disp_control_rev);
567 }
568
569 if (dma_on)
570 {
571 DEV_EN |= DEV_LCD; /* Enable LCD controller */
572 lcd_send_msg(0x70, R_RAM_WRITE_DATA); /* Set to RAM write mode */
573 LCD_REG_6 |= 1; /* Restart DMA */
574 }
384} 575}
385 576
386/* turn the display upside down (call lcd_update() afterwards) */ 577/* turn the display upside down (call lcd_update() afterwards) */
387void lcd_set_flip(bool yesno) 578void lcd_set_flip(bool yesno)
388{ 579{
389 /* TODO: Implement lcd_set_flip() */ 580 bool dma_on = LCD_REG_6 & 1;
390 (void)yesno; 581
582 if (dma_on)
583 {
584 LCD_REG_6 &= ~1; /* Disable DMA */
585 sleep(HZ/50); /* Wait for dma end (assuming 50Hz) */
586 DEV_EN &= ~DEV_LCD; /* Disable LCD controller */
587 }
588
589 r_drv_output_control = yesno ? R_DRV_OUTPUT_CONTROL_FLIPPED :
590 R_DRV_OUTPUT_CONTROL_NORMAL;
591
592 if (power_on)
593 {
594 /* VSPL=0, HSPL=0, DPL=1, EPL=0, SM=0, GS=x, SS=x,
595 NL4-0=11011 (G1-G224) */
596 lcd_write_reg(R_DRV_OUTPUT_CONTROL, r_drv_output_control);
597 }
598
599 if (dma_on)
600 {
601 DEV_EN |= DEV_LCD; /* Enable LCD controller */
602 lcd_send_msg(0x70, R_RAM_WRITE_DATA); /* Set to RAM write mode */
603 LCD_REG_6 |= 1; /* Restart DMA */
604 }
391} 605}
392 606
393/* Blitting functions */ 607/* Blitting functions */
@@ -417,35 +631,35 @@ void lcd_yuv_blit(unsigned char * const src[3],
417 int src_x, int src_y, int stride, 631 int src_x, int src_y, int stride,
418 int x, int y, int width, int height) 632 int x, int y, int width, int height)
419{ 633{
420 if(DEV_EN & DEV_LCD) 634 /* Caches for chroma data so it only need be recaculated every other
421 { 635 line */
422 /* Caches for chroma data so it only need be recaculated every other 636 static unsigned char chroma_buf[LCD_HEIGHT/2*3]; /* 330 bytes */
423 line */ 637 unsigned char const * yuv_src[3];
424 static unsigned char chroma_buf[LCD_HEIGHT/2*3]; /* 330 bytes */ 638 off_t z;
425 unsigned char const * yuv_src[3];
426 off_t z;
427 639
428 /* Sorry, but width and height must be >= 2 or else */ 640 if (!display_on)
429 width &= ~1; 641 return;
430 height >>= 1;
431 642
432 fb_data *dst = (fb_data*)lcd_driver_framebuffer + 643 /* Sorry, but width and height must be >= 2 or else */
433 x * LCD_WIDTH + (LCD_WIDTH - y) - 1; 644 width &= ~1;
645 height >>= 1;
434 646
435 z = stride*src_y; 647 fb_data *dst = (fb_data*)lcd_driver_framebuffer +
436 yuv_src[0] = src[0] + z + src_x; 648 x * LCD_WIDTH + (LCD_WIDTH - y) - 1;
437 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
438 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
439 649
440 do 650 z = stride*src_y;
441 { 651 yuv_src[0] = src[0] + z + src_x;
442 lcd_write_yuv420_lines(dst, chroma_buf, yuv_src, width, 652 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
443 stride); 653 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
444 yuv_src[0] += stride << 1; /* Skip down two luma lines */ 654
445 yuv_src[1] += stride >> 1; /* Skip down one chroma line */ 655 do
446 yuv_src[2] += stride >> 1; 656 {
447 dst -= 2; 657 lcd_write_yuv420_lines(dst, chroma_buf, yuv_src, width,
448 } 658 stride);
449 while (--height > 0); 659 yuv_src[0] += stride << 1; /* Skip down two luma lines */
660 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
661 yuv_src[2] += stride >> 1;
662 dst -= 2;
450 } 663 }
664 while (--height > 0);
451} 665}