diff options
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 | } |