diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2007-07-08 13:02:52 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2007-07-08 13:02:52 +0000 |
commit | 1bbd58e2d8e4bf9c9942c5b70ff4e480a6fc56f2 (patch) | |
tree | 3dd2b077a3df6468b6226623db692c14fc27d0f9 /firmware/target | |
parent | 32eddb44be92d8d14ad757e87de652fd67b59c89 (diff) | |
download | rockbox-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')
-rw-r--r-- | firmware/target/arm/sandisk/sansa-e200/lcd-as-e200.S | 89 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/sansa-e200/lcd-e200.c | 496 |
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 | ||
35 | lcd_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 | ||
39 | 10: @ 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 | ||
49 | 20: @ 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 } @ | ||
86 | 25: @ copy up done @ | ||
87 | ble 40f @ finish line @ no 32-byte segments remaining? | ||
88 | 30: @ 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 @ | ||
93 | 40: @ 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 */ | ||
30 | static bool power_on = false; /* Is the power turned on? */ | ||
31 | static 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 | ||
36 | static 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 | ||
41 | static 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 | ||
171 | inline void lcd_init_device(void) | 185 | /* Run the powerup sequence for the driver IC */ |
186 | static 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 */ | ||
274 | static 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 */ | ||
324 | static 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 | |||
355 | void 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 | ||
301 | void lcd_enable(bool on) | 437 | void 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 | ||
323 | void lcd_update_rect(int x, int y, int width, int height) | 460 | void 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 | ||
349 | void 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. */ | ||
482 | extern void lcd_copy_buffer_rect(fb_data *dst, const fb_data *src, | ||
483 | int width, int height); | ||
484 | void 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 | |||
525 | void 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 | ||
380 | void lcd_set_invert_display(bool yesno) | 548 | void 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) */ |
387 | void lcd_set_flip(bool yesno) | 578 | void 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 | } |