summaryrefslogtreecommitdiff
path: root/firmware/target/arm/sandisk
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/sandisk')
-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}