summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2007-10-14 23:05:56 +0000
committerJens Arnold <amiconn@rockbox.org>2007-10-14 23:05:56 +0000
commit99f955088149d5938ce4c9ca5624377f464b1380 (patch)
tree403178f0198f8ef0b57c49be3b25f085be52aa8a
parent57418b2192f4eb4decab716d50e09232ba22f7f4 (diff)
downloadrockbox-99f955088149d5938ce4c9ca5624377f464b1380.tar.gz
rockbox-99f955088149d5938ce4c9ca5624377f464b1380.zip
H300, X5: Optimised lcd_yuv_blit(), using line-pair zig-zag writing to the LCD controller. ~7% speedup on H300, ~5% speedup on X5.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15111 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/target/coldfire/iaudio/x5/lcd-as-x5.S131
-rw-r--r--firmware/target/coldfire/iaudio/x5/lcd-x5.c77
-rw-r--r--firmware/target/coldfire/iriver/h300/lcd-as-h300.S129
-rw-r--r--firmware/target/coldfire/iriver/h300/lcd-h300.c45
4 files changed, 255 insertions, 127 deletions
diff --git a/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S b/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S
index 11150203af..879235ebf2 100644
--- a/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S
+++ b/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S
@@ -45,6 +45,23 @@
45 * |B| |19611723 33976259 0| |Cr - 128| >> 26 45 * |B| |19611723 33976259 0| |Cr - 128| >> 26
46 * 46 *
47 * Needs EMAC set to saturated, signed integer mode. 47 * Needs EMAC set to saturated, signed integer mode.
48 *
49 * register usage:
50 * %a0 - LCD data port
51 * %a1 - Y pointer
52 * %a2 - C pointer
53 * %a3 - C width
54 * %a4 - Y end address
55 * %a5 - Y factor
56 * %a6 - BU factor
57 * %d0 - scratch
58 * %d1 - B, previous Y \ alternating
59 * %d2 - U / B, previous Y /
60 * %d3 - V / G
61 * %d4 - R / output pixel
62 * %d5 - GU factor
63 * %d6 - GV factor
64 * %d7 - RGB signed -> unsigned conversion mask
48 */ 65 */
49 .align 2 66 .align 2
50 .global lcd_write_yuv420_lines 67 .global lcd_write_yuv420_lines
@@ -55,8 +72,8 @@ lcd_write_yuv420_lines:
55 movem.l %d2-%d7/%a2-%a6, (%sp) 72 movem.l %d2-%d7/%a2-%a6, (%sp)
56 73
57 lea.l 0xf0008002, %a0 /* LCD data port */ 74 lea.l 0xf0008002, %a0 /* LCD data port */
58 movem.l (44+4, %sp), %a1-%a4 /* Y data, Cb data, Cr data, width */ 75 movem.l (44+4, %sp), %a1-%a3 /* Y data, C data, C width */
59 lea.l (%a1, %a4), %a4 /* end address */ 76 lea.l (%a1, %a3*2), %a4 /* Y end address */
60 77
61 move.l #19611723, %a5 /* y factor */ 78 move.l #19611723, %a5 /* y factor */
62 move.l #33976259, %a6 /* bu factor */ 79 move.l #33976259, %a6 /* bu factor */
@@ -65,11 +82,11 @@ lcd_write_yuv420_lines:
65 move.l #0x01040820, %d7 /* bitmask for signed->unsigned conversion 82 move.l #0x01040820, %d7 /* bitmask for signed->unsigned conversion
66 * of R, G and B within RGGB6666 at once */ 83 * of R, G and B within RGGB6666 at once */
67 84
68 /* chroma for (very) first & second pixel */ 85 /* chroma for first 2x2 block */
86 clr.l %d3 /* load v component */
87 move.b (%a2, %a3), %d3
69 clr.l %d2 /* load u component */ 88 clr.l %d2 /* load u component */
70 move.b (%a2)+, %d2 89 move.b (%a2)+, %d2
71 clr.l %d3 /* load v component */
72 move.b (%a3)+, %d3
73 moveq.l #-128, %d0 90 moveq.l #-128, %d0
74 add.l %d0, %d2 91 add.l %d0, %d2
75 add.l %d0, %d3 92 add.l %d0, %d3
@@ -80,9 +97,9 @@ lcd_write_yuv420_lines:
80 move.l #26881894, %d0 /* rv factor */ 97 move.l #26881894, %d0 /* rv factor */
81 mac.l %d0, %d3, %acc2 /* rv */ 98 mac.l %d0, %d3, %acc2 /* rv */
82 99
83 /* luma for (very) first pixel */ 100 /* luma for very first pixel (top left) */
84 clr.l %d1 101 clr.l %d1
85 move.b (%a1)+, %d1 102 move.b (%a1, %a3*2), %d1
86 moveq.l #-126, %d0 103 moveq.l #-126, %d0
87 add.l %d1, %d0 /* y' (-0.5 ... +0.5) */ 104 add.l %d1, %d0 /* y' (-0.5 ... +0.5) */
88 mac.l %a5, %d0, %acc0 105 mac.l %a5, %d0, %acc0
@@ -92,11 +109,11 @@ lcd_write_yuv420_lines:
92 bra.b .yuv_line_entry 109 bra.b .yuv_line_entry
93 110
94.yuv_line_loop: 111.yuv_line_loop:
95 /* chroma for first & second pixel */ 112 /* chroma for 2x2 pixel block */
113 clr.l %d3 /* load v component */
114 move.b (%a2, %a3), %d3
96 clr.l %d2 /* load u component */ 115 clr.l %d2 /* load u component */
97 move.b (%a2)+, %d2 116 move.b (%a2)+, %d2
98 clr.l %d3 /* load v component */
99 move.b (%a3)+, %d3
100 moveq.l #-128, %d0 117 moveq.l #-128, %d0
101 add.l %d0, %d2 118 add.l %d0, %d2
102 add.l %d0, %d3 119 add.l %d0, %d3
@@ -107,9 +124,9 @@ lcd_write_yuv420_lines:
107 move.l #26881894, %d0 /* rv factor */ 124 move.l #26881894, %d0 /* rv factor */
108 mac.l %d0, %d3, %acc2 /* rv */ 125 mac.l %d0, %d3, %acc2 /* rv */
109 126
110 /* luma for first pixel */ 127 /* luma for first pixel (top left) */
111 clr.l %d1 128 clr.l %d1
112 move.b (%a1)+, %d1 129 move.b (%a1, %a3*2), %d1
113 moveq.l #-126, %d0 130 moveq.l #-126, %d0
114 add.l %d1, %d0 /* y' (-0.5 ... +0.5) */ 131 add.l %d1, %d0 /* y' (-0.5 ... +0.5) */
115 mac.l %a5, %d0, %acc0 132 mac.l %a5, %d0, %acc0
@@ -140,9 +157,10 @@ lcd_write_yuv420_lines:
140 move.w %d4, (%a0) 157 move.w %d4, (%a0)
141 swap %d4 158 swap %d4
142 159
143 /* luma for second pixel as delta from the first */ 160 /* luma for second pixel (bottom left) as delta from the first */
144 clr.l %d0 161 clr.l %d2
145 move.b (%a1)+, %d0 162 move.b (%a1)+, %d2
163 move.l %d2, %d0
146 sub.l %d1, %d0 164 sub.l %d1, %d0
147 mac.l %a5, %d0, %acc0 165 mac.l %a5, %d0, %acc0
148 mac.l %a5, %d0, %acc1 166 mac.l %a5, %d0, %acc1
@@ -153,13 +171,45 @@ lcd_write_yuv420_lines:
153 171
154 /* convert to RGB666, pack and output */ 172 /* convert to RGB666, pack and output */
155 moveq.l #26, %d0 173 moveq.l #26, %d0
156 movclr.l %acc0, %d4 174 move.l %acc0, %d4
157 movclr.l %acc1, %d3 175 move.l %acc1, %d3
158 movclr.l %acc2, %d2 176 move.l %acc2, %d1
159 lsr.l %d0, %d4 177 lsr.l %d0, %d4
160 lsr.l %d0, %d3 178 lsr.l %d0, %d3
161 lsr.l %d0, %d2 179 lsr.l %d0, %d1
180
181 lsl.l #6, %d1
182 or.l %d3, %d1 /* |00000000|00000000|0000Rrrr|rrGggggg| */
183 lsl.l #7, %d1
184 or.l %d1, %d3 /* |00000000|00000Rrr|rrrGgggg|g0Gggggg| */
185 lsl.l #6, %d3
186 or.l %d3, %d4 /* |0000000R|rrrrrGgg|ggg0Gggg|ggBbbbbb| */
187 eor.l %d7, %d4 /* |0000000r|rrrrrggg|ggg0gggg|ggbbbbbb| */
188 swap %d4
189 move.w %d4, (%a0)
190 swap %d4
191
192 /* luma for third pixel (top right) as delta from the second */
193 clr.l %d1
194 move.b (%a1, %a3*2), %d1
195 move.l %d1, %d0
196 sub.l %d2, %d0
197 mac.l %a5, %d0, %acc0
198 mac.l %a5, %d0, %acc1
199 mac.l %a5, %d0, %acc2
200
201 move.w %d4, (%a0)
202 /* 2nd LCD write is delayed one pixel to use it for filling the EMAC latency */
162 203
204 /* convert to RGB666, pack and output */
205 moveq.l #26, %d0
206 move.l %acc0, %d4
207 move.l %acc1, %d3
208 move.l %acc2, %d2
209 lsr.l %d0, %d4
210 lsr.l %d0, %d3
211 lsr.l %d0, %d2
212
163 lsl.l #6, %d2 213 lsl.l #6, %d2
164 or.l %d3, %d2 /* |00000000|00000000|0000Rrrr|rrGggggg| */ 214 or.l %d3, %d2 /* |00000000|00000000|0000Rrrr|rrGggggg| */
165 lsl.l #7, %d2 215 lsl.l #7, %d2
@@ -171,24 +221,45 @@ lcd_write_yuv420_lines:
171 move.w %d4, (%a0) 221 move.w %d4, (%a0)
172 swap %d4 222 swap %d4
173 223
224 /* luma for fourth pixel (bottom right) as delta from the thrid */
225 clr.l %d2
226 move.b (%a1)+, %d2
227 move.l %d2, %d0
228 sub.l %d1, %d0
229 mac.l %a5, %d0, %acc0
230 mac.l %a5, %d0, %acc1
231 mac.l %a5, %d0, %acc2
232
233 move.w %d4, (%a0)
234 /* 2nd LCD write is delayed one pixel to use it for filling the EMAC latency */
235
236 /* convert to RGB666, pack and output */
237 moveq.l #26, %d0
238 movclr.l %acc0, %d4
239 movclr.l %acc1, %d3
240 movclr.l %acc2, %d1
241 lsr.l %d0, %d4
242 lsr.l %d0, %d3
243 lsr.l %d0, %d1
244
245 lsl.l #6, %d1
246 or.l %d3, %d1 /* |00000000|00000000|0000Rrrr|rrGggggg| */
247 lsl.l #7, %d1
248 or.l %d1, %d3 /* |00000000|00000Rrr|rrrGgggg|g0Gggggg| */
249 lsl.l #6, %d3
250 or.l %d3, %d4 /* |0000000R|rrrrrGgg|ggg0Gggg|ggBbbbbb| */
251 eor.l %d7, %d4 /* |0000000r|rrrrrggg|ggg0gggg|ggbbbbbb| */
252 swap %d4
253 move.w %d4, (%a0)
254 swap %d4
255
174 cmp.l %a1, %a4 /* run %a1 up to end of line */ 256 cmp.l %a1, %a4 /* run %a1 up to end of line */
175 bhi.w .yuv_line_loop 257 bhi.w .yuv_line_loop
176 258
177 tst.l (44+4, %sp) /* use original Y pointer as a flag to */
178 beq.b .yuv_exit /* distinguish between first and second */
179 clr.l (44+4, %sp) /* pixel line */
180
181 /* Rewind chroma pointers */
182 movem.l (44+8, %sp), %a2-%a4 /* Cb data, Cr data, width */
183 lea.l (%a1, %a4), %a4 /* end address */
184 bra.w .yuv_line_loop
185
186.yuv_exit:
187 move.w %d4, (%a0) /* write (very) last 2nd word */ 259 move.w %d4, (%a0) /* write (very) last 2nd word */
188 260
189 movem.l (%sp), %d2-%d7/%a2-%a6 261 movem.l (%sp), %d2-%d7/%a2-%a6
190 lea.l (44, %sp), %sp /* restore registers */ 262 lea.l (44, %sp), %sp /* restore registers */
191
192 rts 263 rts
193.yuv_end: 264.yuv_end:
194 .size lcd_write_yuv420_lines, yuv_end - lcd_write_yuv420_lines 265 .size lcd_write_yuv420_lines, yuv_end - lcd_write_yuv420_lines
diff --git a/firmware/target/coldfire/iaudio/x5/lcd-x5.c b/firmware/target/coldfire/iaudio/x5/lcd-x5.c
index 2cc5b5ba65..5ca2cb508c 100644
--- a/firmware/target/coldfire/iaudio/x5/lcd-x5.c
+++ b/firmware/target/coldfire/iaudio/x5/lcd-x5.c
@@ -50,11 +50,6 @@ static unsigned short r_gate_scan_start_pos = 0x0002;
50static unsigned short r_drv_output_control = 0x0313; 50static unsigned short r_drv_output_control = 0x0313;
51static unsigned short r_horiz_ram_addr_pos = 0x7f00; 51static unsigned short r_horiz_ram_addr_pos = 0x7f00;
52 52
53/* Dithering */
54#define R_ENTRY_MODE_SOLID 0x1038
55#define R_ENTRY_MODE_DIT 0x9038
56static unsigned short r_entry_mode = R_ENTRY_MODE_SOLID;
57
58/* Forward declarations */ 53/* Forward declarations */
59static void lcd_display_off(void); 54static void lcd_display_off(void);
60 55
@@ -97,6 +92,9 @@ static void lcd_display_off(void);
97#define R_GAMMA_AMP_ADJ_POS 0x3a 92#define R_GAMMA_AMP_ADJ_POS 0x3a
98#define R_GAMMA_AMP_ADJ_NEG 0x3b 93#define R_GAMMA_AMP_ADJ_NEG 0x3b
99 94
95#define R_ENTRY_MODE_SOLID_VERT 0x1038
96#define R_ENTRY_MODE_DIT_HORZ 0x9030
97
100/* called very frequently - inline! */ 98/* called very frequently - inline! */
101static inline void lcd_write_reg(int reg, int val) 99static inline void lcd_write_reg(int reg, int val)
102{ 100{
@@ -113,14 +111,6 @@ static inline void lcd_begin_write_gram(void)
113 LCD_CMD = R_WRITE_DATA_2_GRAM << 1; 111 LCD_CMD = R_WRITE_DATA_2_GRAM << 1;
114} 112}
115 113
116/* set hard dither mode on/off */
117static void hw_dither(bool on)
118{
119 /* DIT=x, BGR=1, HWM=0, I/D1-0=11, AM=1, LG2-0=000 */
120 r_entry_mode = on ? R_ENTRY_MODE_DIT : R_ENTRY_MODE_SOLID;
121 lcd_write_reg(R_ENTRY_MODE, r_entry_mode);
122}
123
124/*** hardware configuration ***/ 114/*** hardware configuration ***/
125 115
126int lcd_default_contrast(void) 116int lcd_default_contrast(void)
@@ -233,7 +223,7 @@ static void lcd_power_on(void)
233 /* FLD1-0=01 (1 field), B/C=1, EOR=1 (C-pat), NW5-0=000000 (1 row) */ 223 /* FLD1-0=01 (1 field), B/C=1, EOR=1 (C-pat), NW5-0=000000 (1 row) */
234 lcd_write_reg(R_DRV_AC_CONTROL, 0x0700); 224 lcd_write_reg(R_DRV_AC_CONTROL, 0x0700);
235 /* DIT=x, BGR=1, HWM=0, I/D1-0=11, AM=1, LG2-0=000 */ 225 /* DIT=x, BGR=1, HWM=0, I/D1-0=11, AM=1, LG2-0=000 */
236 lcd_write_reg(R_ENTRY_MODE, r_entry_mode); 226 lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_SOLID_VERT);
237 /* CP15-0=0000000000000000 */ 227 /* CP15-0=0000000000000000 */
238 lcd_write_reg(R_COMPARE_REG, 0x0000); 228 lcd_write_reg(R_COMPARE_REG, 0x0000);
239 /* NO1-0=01, SDT1-0=00, EQ1-0=00, DIV1-0=00, RTN3-00000 */ 229 /* NO1-0=01, SDT1-0=00, EQ1-0=00, DIV1-0=00, RTN3-00000 */
@@ -377,7 +367,8 @@ void lcd_init_device(void)
377 lcd_set_contrast(DEFAULT_CONTRAST_SETTING); 367 lcd_set_contrast(DEFAULT_CONTRAST_SETTING);
378 lcd_set_invert_display(false); 368 lcd_set_invert_display(false);
379 lcd_set_flip(false); 369 lcd_set_flip(false);
380 hw_dither(false); /* do this or all bootloaders will need reflashing */ 370 lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_SOLID_VERT);
371 /* do this or all bootloaders will need reflashing */
381#endif 372#endif
382} 373}
383 374
@@ -432,13 +423,12 @@ void lcd_blit(const fb_data* data, int x, int by, int width,
432} 423}
433 424
434/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. 425/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420.
435 * y should have two lines of Y back to back. 426 * y should have two lines of Y back to back, 2nd line first.
436 * bu and rv should contain the Cb and Cr data for the two lines of Y. 427 * c should contain the Cb and Cr data for the two lines of Y back to back.
437 * Needs EMAC set to saturated, signed integer mode. 428 * Needs EMAC set to saturated, signed integer mode.
438 */ 429 */
439extern void lcd_write_yuv420_lines(const unsigned char *y, 430extern void lcd_write_yuv420_lines(const unsigned char *y,
440 const unsigned char *bu, 431 const unsigned char *c, int width);
441 const unsigned char *rv, int width);
442 432
443/* Performance function to blit a YUV bitmap directly to the LCD 433/* Performance function to blit a YUV bitmap directly to the LCD
444 * src_x, src_y, width and height should be even and within the LCD's 434 * src_x, src_y, width and height should be even and within the LCD's
@@ -450,25 +440,19 @@ void lcd_yuv_blit(unsigned char * const src[3],
450{ 440{
451 /* IRAM Y, Cb/bu, guv and Cb/rv buffers. */ 441 /* IRAM Y, Cb/bu, guv and Cb/rv buffers. */
452 unsigned char y_ibuf[LCD_WIDTH*2]; 442 unsigned char y_ibuf[LCD_WIDTH*2];
453 unsigned char bu_ibuf[LCD_WIDTH/2]; 443 unsigned char c_ibuf[LCD_WIDTH];
454 unsigned char rv_ibuf[LCD_WIDTH/2];
455 const unsigned char *ysrc, *usrc, *vsrc; 444 const unsigned char *ysrc, *usrc, *vsrc;
456 const unsigned char *ysrc_max; 445 const unsigned char *ysrc_max;
457 446
458 if (!display_on) 447 if (!display_on)
459 return; 448 return;
460 449
461 if (r_entry_mode == R_ENTRY_MODE_SOLID)
462 hw_dither(true);
463
464 width &= ~1; /* stay on the safe side */ 450 width &= ~1; /* stay on the safe side */
465 height &= ~1; 451 height &= ~1;
466 452
453 lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_DIT_HORZ);
467 /* Set start position and window */ 454 /* Set start position and window */
468 lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | (y + y_offset)); 455 lcd_write_reg(R_VERT_RAM_ADDR_POS, (LCD_WIDTH-1) << 8);
469 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x);
470
471 lcd_begin_write_gram();
472 456
473 ysrc = src[0] + src_y * stride + src_x; 457 ysrc = src[0] + src_y * stride + src_x;
474 usrc = src[1] + (src_y * stride >> 2) + (src_x >> 1); 458 usrc = src[1] + (src_y * stride >> 2) + (src_x >> 1);
@@ -478,11 +462,17 @@ void lcd_yuv_blit(unsigned char * const src[3],
478 coldfire_set_macsr(EMAC_SATURATE); 462 coldfire_set_macsr(EMAC_SATURATE);
479 do 463 do
480 { 464 {
481 memcpy(y_ibuf, ysrc, width); 465 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, ((y + y_offset + 1) << 8) | (y + y_offset));
482 memcpy(y_ibuf + width, ysrc + stride, width); 466 lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | (y + y_offset));
483 memcpy(bu_ibuf, usrc, width >> 1); 467 lcd_begin_write_gram();
484 memcpy(rv_ibuf, vsrc, width >> 1); 468
485 lcd_write_yuv420_lines(y_ibuf, bu_ibuf, rv_ibuf, width); 469 memcpy(y_ibuf + width, ysrc, width);
470 memcpy(y_ibuf, ysrc + stride, width);
471 memcpy(c_ibuf, usrc, width >> 1);
472 memcpy(c_ibuf + (width >> 1), vsrc, width >> 1);
473 lcd_write_yuv420_lines(y_ibuf, c_ibuf, width >> 1);
474
475 y += 2;
486 ysrc += 2 * stride; 476 ysrc += 2 * stride;
487 usrc += stride >> 1; 477 usrc += stride >> 1;
488 vsrc += stride >> 1; 478 vsrc += stride >> 1;
@@ -499,17 +489,16 @@ void lcd_update(void)
499 if (!display_on) 489 if (!display_on)
500 return; 490 return;
501 491
502 if (r_entry_mode == R_ENTRY_MODE_DIT) 492 lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_SOLID_VERT);
503 hw_dither(false);
504
505 /* Set start position and window */ 493 /* Set start position and window */
506 lcd_write_reg(R_RAM_ADDR_SET, y_offset); /* X == 0 */ 494 lcd_write_reg(R_HORIZ_RAM_ADDR_POS,
495 ((y_offset + LCD_HEIGHT-1) << 8) | y_offset);
507 lcd_write_reg(R_VERT_RAM_ADDR_POS, (LCD_WIDTH-1) << 8); 496 lcd_write_reg(R_VERT_RAM_ADDR_POS, (LCD_WIDTH-1) << 8);
497 lcd_write_reg(R_RAM_ADDR_SET, y_offset);
508 498
509 lcd_begin_write_gram(); 499 lcd_begin_write_gram();
510 500
511 lcd_write_data((unsigned short *)lcd_framebuffer, 501 lcd_write_data((unsigned short *)lcd_framebuffer, LCD_WIDTH*LCD_HEIGHT);
512 LCD_WIDTH*LCD_HEIGHT);
513} /* lcd_update */ 502} /* lcd_update */
514 503
515/* Update a fraction of the display. */ 504/* Update a fraction of the display. */
@@ -521,9 +510,6 @@ void lcd_update_rect(int x, int y, int width, int height)
521 if (!display_on) 510 if (!display_on)
522 return; 511 return;
523 512
524 if (r_entry_mode == R_ENTRY_MODE_DIT)
525 hw_dither(false);
526
527 if (x + width > LCD_WIDTH) 513 if (x + width > LCD_WIDTH)
528 width = LCD_WIDTH - x; /* Clip right */ 514 width = LCD_WIDTH - x; /* Clip right */
529 if (x < 0) 515 if (x < 0)
@@ -539,9 +525,12 @@ void lcd_update_rect(int x, int y, int width, int height)
539 if (y >= ymax) 525 if (y >= ymax)
540 return; /* nothing left to do */ 526 return; /* nothing left to do */
541 527
528 lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_SOLID_VERT);
542 /* Set start position and window */ 529 /* Set start position and window */
543 lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | (y + y_offset)); 530 lcd_write_reg(R_HORIZ_RAM_ADDR_POS,
531 ((y_offset + LCD_HEIGHT-1) << 8) | y_offset);
544 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x); 532 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x);
533 lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | (y + y_offset));
545 534
546 lcd_begin_write_gram(); 535 lcd_begin_write_gram();
547 536
diff --git a/firmware/target/coldfire/iriver/h300/lcd-as-h300.S b/firmware/target/coldfire/iriver/h300/lcd-as-h300.S
index 1873b905c6..9106e22c1c 100644
--- a/firmware/target/coldfire/iriver/h300/lcd-as-h300.S
+++ b/firmware/target/coldfire/iriver/h300/lcd-as-h300.S
@@ -44,6 +44,23 @@
44 * |B| |19611723 33976259 0| |Cr - 128| >> 27 44 * |B| |19611723 33976259 0| |Cr - 128| >> 27
45 * 45 *
46 * Needs EMAC set to saturated, signed integer mode. 46 * Needs EMAC set to saturated, signed integer mode.
47 *
48 * register usage:
49 * %a0 - LCD data port
50 * %a1 - Y pointer
51 * %a2 - C pointer
52 * %a3 - C width
53 * %a4 - Y end address
54 * %a5 - Y factor
55 * %a6 - BU factor
56 * %d0 - scratch
57 * %d1 - B, previous Y \ alternating
58 * %d2 - U / B, previous Y /
59 * %d3 - V / G
60 * %d4 - R / output pixel
61 * %d5 - GU factor
62 * %d6 - GV factor
63 * %d7 - RGB signed -> unsigned conversion mask
47 */ 64 */
48 .align 2 65 .align 2
49 .global lcd_write_yuv420_lines 66 .global lcd_write_yuv420_lines
@@ -52,10 +69,10 @@
52lcd_write_yuv420_lines: 69lcd_write_yuv420_lines:
53 lea.l (-44, %sp), %sp /* free up some registers */ 70 lea.l (-44, %sp), %sp /* free up some registers */
54 movem.l %d2-%d7/%a2-%a6, (%sp) 71 movem.l %d2-%d7/%a2-%a6, (%sp)
55 72
56 lea.l 0xf0000002, %a0 /* LCD data port */ 73 lea.l 0xf0000002, %a0 /* LCD data port */
57 movem.l (44+4, %sp), %a1-%a4 /* Y data, Cb data, Cr data, width */ 74 movem.l (44+4, %sp), %a1-%a3 /* Y data, C data, C width */
58 lea.l (%a1, %a4), %a4 /* end address */ 75 lea.l (%a1, %a3*2), %a4 /* Y end address */
59 76
60 move.l #19611723, %a5 /* y factor */ 77 move.l #19611723, %a5 /* y factor */
61 move.l #33976259, %a6 /* bu factor */ 78 move.l #33976259, %a6 /* bu factor */
@@ -64,11 +81,11 @@ lcd_write_yuv420_lines:
64 move.l #0x8410, %d7 /* bitmask for signed->unsigned conversion 81 move.l #0x8410, %d7 /* bitmask for signed->unsigned conversion
65 * of R, G and B within RGB565 at once */ 82 * of R, G and B within RGB565 at once */
66 83
67 /* chroma for (very) first & second pixel */ 84 /* chroma for first 2x2 pixel block */
85 clr.l %d3 /* load v component */
86 move.b (%a2, %a3), %d3
68 clr.l %d2 /* load u component */ 87 clr.l %d2 /* load u component */
69 move.b (%a2)+, %d2 88 move.b (%a2)+, %d2
70 clr.l %d3 /* load v component */
71 move.b (%a3)+, %d3
72 moveq.l #-128, %d0 89 moveq.l #-128, %d0
73 add.l %d0, %d2 90 add.l %d0, %d2
74 add.l %d0, %d3 91 add.l %d0, %d3
@@ -79,9 +96,9 @@ lcd_write_yuv420_lines:
79 move.l #26881894, %d0 /* rv factor */ 96 move.l #26881894, %d0 /* rv factor */
80 mac.l %d0, %d3, %acc2 /* rv */ 97 mac.l %d0, %d3, %acc2 /* rv */
81 98
82 /* luma for (very) first pixel */ 99 /* luma for very first pixel (top left) */
83 clr.l %d1 100 clr.l %d1
84 move.b (%a1)+, %d1 101 move.b (%a1, %a3*2), %d1
85 moveq.l #-126, %d0 102 moveq.l #-126, %d0
86 add.l %d1, %d0 /* y' (-0.5 ... +0.5) */ 103 add.l %d1, %d0 /* y' (-0.5 ... +0.5) */
87 mac.l %a5, %d0, %acc0 104 mac.l %a5, %d0, %acc0
@@ -91,11 +108,11 @@ lcd_write_yuv420_lines:
91 bra.b .yuv_line_entry 108 bra.b .yuv_line_entry
92 109
93.yuv_line_loop: 110.yuv_line_loop:
94 /* chroma for first & second pixel */ 111 /* chroma for 2x2 pixel block */
112 clr.l %d3 /* load v component */
113 move.b (%a2, %a3), %d3
95 clr.l %d2 /* load u component */ 114 clr.l %d2 /* load u component */
96 move.b (%a2)+, %d2 115 move.b (%a2)+, %d2
97 clr.l %d3 /* load v component */
98 move.b (%a3)+, %d3
99 moveq.l #-128, %d0 116 moveq.l #-128, %d0
100 add.l %d0, %d2 117 add.l %d0, %d2
101 add.l %d0, %d3 118 add.l %d0, %d3
@@ -106,16 +123,16 @@ lcd_write_yuv420_lines:
106 move.l #26881894, %d0 /* rv factor */ 123 move.l #26881894, %d0 /* rv factor */
107 mac.l %d0, %d3, %acc2 /* rv */ 124 mac.l %d0, %d3, %acc2 /* rv */
108 125
109 /* luma for first pixel */ 126 /* luma for first pixel (top left) */
110 clr.l %d1 127 clr.l %d1
111 move.b (%a1)+, %d1 128 move.b (%a1, %a3*2), %d1
112 moveq.l #-126, %d0 129 moveq.l #-126, %d0
113 add.l %d1, %d0 /* y' (-0.5 ... +0.5) */ 130 add.l %d1, %d0 /* y' (-0.5 ... +0.5) */
114 mac.l %a5, %d0, %acc0 131 mac.l %a5, %d0, %acc0
115 mac.l %a5, %d0, %acc1 132 mac.l %a5, %d0, %acc1
116 mac.l %a5, %d0, %acc2 133 mac.l %a5, %d0, %acc2
117 134
118 move.w %d4, (%a0) 135 move.w %d4, (%a0)
119 /* LCD write is delayed one pixel to use it for filling the EMAC latency */ 136 /* LCD write is delayed one pixel to use it for filling the EMAC latency */
120 137
121 /* convert to RGB565, pack and output */ 138 /* convert to RGB565, pack and output */
@@ -134,22 +151,50 @@ lcd_write_yuv420_lines:
134 or.l %d2, %d4 151 or.l %d2, %d4
135 eor.l %d7, %d4 152 eor.l %d7, %d4
136 153
137 /* luma for second pixel as delta from the first */ 154 /* luma for second pixel (bottom left) as delta from the first */
138 clr.l %d0 155 clr.l %d2
139 move.b (%a1)+, %d0 156 move.b (%a1)+, %d2
157 move.l %d2, %d0
140 sub.l %d1, %d0 158 sub.l %d1, %d0
141 mac.l %a5, %d0, %acc0 159 mac.l %a5, %d0, %acc0
142 mac.l %a5, %d0, %acc1 160 mac.l %a5, %d0, %acc1
143 mac.l %a5, %d0, %acc2 161 mac.l %a5, %d0, %acc2
144 162
145 move.w %d4, (%a0) 163 move.w %d4, (%a0)
146 /* LCD write is delayed one pixel to use it for filling the EMAC latency */ 164 /* LCD write is delayed one pixel to use it for filling the EMAC latency */
147 165
148 /* convert to RGB565, pack and output */ 166 /* convert to RGB565, pack and output */
149 moveq.l #27, %d0 167 moveq.l #27, %d0
150 movclr.l %acc0, %d2 168 move.l %acc0, %d1
151 movclr.l %acc1, %d3 169 move.l %acc1, %d3
152 movclr.l %acc2, %d4 170 move.l %acc2, %d4
171 lsr.l %d0, %d1
172 lsr.l %d0, %d4
173 moveq.l #26, %d0
174 lsr.l %d0, %d3
175 lsl.l #6, %d4
176 or.l %d3, %d4
177 lsl.l #5, %d4
178 or.l %d1, %d4
179 eor.l %d7, %d4
180
181 /* luma for third pixel (top right) as delta from the second */
182 clr.l %d1
183 move.b (%a1, %a3*2), %d1
184 move.l %d1, %d0
185 sub.l %d2, %d0
186 mac.l %a5, %d0, %acc0
187 mac.l %a5, %d0, %acc1
188 mac.l %a5, %d0, %acc2
189
190 move.w %d4, (%a0)
191 /* LCD write is delayed one pixel to use it for filling the EMAC latency */
192
193 /* convert to RGB565, pack and output */
194 moveq.l #27, %d0
195 move.l %acc0, %d2
196 move.l %acc1, %d3
197 move.l %acc2, %d4
153 lsr.l %d0, %d2 198 lsr.l %d0, %d2
154 lsr.l %d0, %d4 199 lsr.l %d0, %d4
155 moveq.l #26, %d0 200 moveq.l #26, %d0
@@ -160,24 +205,40 @@ lcd_write_yuv420_lines:
160 or.l %d2, %d4 205 or.l %d2, %d4
161 eor.l %d7, %d4 206 eor.l %d7, %d4
162 207
208 /* luma for fourth pixel (bottom right) as delta from the third */
209 clr.l %d2
210 move.b (%a1)+, %d2
211 move.l %d2, %d0
212 sub.l %d1, %d0
213 mac.l %a5, %d0, %acc0
214 mac.l %a5, %d0, %acc1
215 mac.l %a5, %d0, %acc2
216
217 move.w %d4, (%a0)
218 /* LCD write is delayed one pixel to use it for filling the EMAC latency */
219
220 /* convert to RGB565, pack and output */
221 moveq.l #27, %d0
222 movclr.l %acc0, %d1
223 movclr.l %acc1, %d3
224 movclr.l %acc2, %d4
225 lsr.l %d0, %d1
226 lsr.l %d0, %d4
227 moveq.l #26, %d0
228 lsr.l %d0, %d3
229 lsl.l #6, %d4
230 or.l %d3, %d4
231 lsl.l #5, %d4
232 or.l %d1, %d4
233 eor.l %d7, %d4
234
163 cmp.l %a1, %a4 /* run %a1 up to end of line */ 235 cmp.l %a1, %a4 /* run %a1 up to end of line */
164 bhi.w .yuv_line_loop 236 bhi.w .yuv_line_loop
165 237
166 tst.l (44+4, %sp) /* use original Y pointer as a flag to */
167 beq.b .yuv_exit /* distinguish between first and second */
168 clr.l (44+4, %sp) /* pixel line */
169
170 /* Rewind chroma pointers */
171 movem.l (44+8, %sp), %a2-%a4 /* Cb data, Cr data, width */
172 lea.l (%a1, %a4), %a4 /* end address */
173 bra.w .yuv_line_loop
174
175.yuv_exit:
176 move.w %d4, (%a0) /* write (very) last pixel */ 238 move.w %d4, (%a0) /* write (very) last pixel */
177 239
178 movem.l (%sp), %d2-%d7/%a2-%a6 240 movem.l (%sp), %d2-%d7/%a2-%a6
179 lea.l (44, %sp), %sp /* restore registers */ 241 lea.l (44, %sp), %sp /* restore registers */
180
181 rts 242 rts
182.yuv_end: 243.yuv_end:
183 .size lcd_write_yuv420_lines, .yuv_end - lcd_write_yuv420_lines 244 .size lcd_write_yuv420_lines, .yuv_end - lcd_write_yuv420_lines
diff --git a/firmware/target/coldfire/iriver/h300/lcd-h300.c b/firmware/target/coldfire/iriver/h300/lcd-h300.c
index 8f76d5255a..00662e16f9 100644
--- a/firmware/target/coldfire/iriver/h300/lcd-h300.c
+++ b/firmware/target/coldfire/iriver/h300/lcd-h300.c
@@ -80,6 +80,9 @@ static int xoffset = 0; /* needed for flip */
80#define LCD_CMD (*(volatile unsigned short *)0xf0000000) 80#define LCD_CMD (*(volatile unsigned short *)0xf0000000)
81#define LCD_DATA (*(volatile unsigned short *)0xf0000002) 81#define LCD_DATA (*(volatile unsigned short *)0xf0000002)
82 82
83#define R_ENTRY_MODE_HORZ 0x7030
84#define R_ENTRY_MODE_VERT 0x7038
85
83/* called very frequently - inline! */ 86/* called very frequently - inline! */
84static inline void lcd_write_reg(int reg, int val) 87static inline void lcd_write_reg(int reg, int val)
85{ 88{
@@ -307,13 +310,12 @@ void lcd_blit(const fb_data* data, int x, int by, int width,
307} 310}
308 311
309/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. 312/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420.
310 * y should have two lines of Y back to back. 313 * y should have two lines of Y back to back, 2nd line first.
311 * bu and rv should contain the Cb and Cr data for the two lines of Y. 314 * c should contain the Cb and Cr data for the two lines of Y back to back.
312 * Needs EMAC set to saturated, signed integer mode. 315 * Needs EMAC set to saturated, signed integer mode.
313 */ 316 */
314extern void lcd_write_yuv420_lines(const unsigned char *y, 317extern void lcd_write_yuv420_lines(const unsigned char *y,
315 const unsigned char *bu, 318 const unsigned char *c, int cwidth);
316 const unsigned char *rv, int width);
317 319
318/* Performance function to blit a YUV bitmap directly to the LCD 320/* Performance function to blit a YUV bitmap directly to the LCD
319 * src_x, src_y, width and height should be even 321 * src_x, src_y, width and height should be even
@@ -325,8 +327,7 @@ void lcd_yuv_blit(unsigned char * const src[3],
325{ 327{
326 /* IRAM Y, Cb and Cb buffers. */ 328 /* IRAM Y, Cb and Cb buffers. */
327 unsigned char y_ibuf[LCD_WIDTH*2]; 329 unsigned char y_ibuf[LCD_WIDTH*2];
328 unsigned char bu_ibuf[LCD_WIDTH/2]; 330 unsigned char c_ibuf[LCD_WIDTH];
329 unsigned char rv_ibuf[LCD_WIDTH/2];
330 const unsigned char *ysrc, *usrc, *vsrc; 331 const unsigned char *ysrc, *usrc, *vsrc;
331 const unsigned char *ysrc_max; 332 const unsigned char *ysrc_max;
332 333
@@ -336,11 +337,9 @@ void lcd_yuv_blit(unsigned char * const src[3],
336 width &= ~1; /* stay on the safe side */ 337 width &= ~1; /* stay on the safe side */
337 height &= ~1; 338 height &= ~1;
338 339
340 lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_HORZ);
339 /* Set start position and window */ 341 /* Set start position and window */
340 lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+xoffset+width-1) << 8) | (x+xoffset)); 342 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((xoffset + 219) << 8) | xoffset);
341 lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y);
342
343 lcd_begin_write_gram();
344 343
345 ysrc = src[0] + src_y * stride + src_x; 344 ysrc = src[0] + src_y * stride + src_x;
346 usrc = src[1] + (src_y * stride >> 2) + (src_x >> 1); 345 usrc = src[1] + (src_y * stride >> 2) + (src_x >> 1);
@@ -350,11 +349,17 @@ void lcd_yuv_blit(unsigned char * const src[3],
350 coldfire_set_macsr(EMAC_SATURATE); 349 coldfire_set_macsr(EMAC_SATURATE);
351 do 350 do
352 { 351 {
353 memcpy(y_ibuf, ysrc, width); 352 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, ((y + 1) << 8) | y);
354 memcpy(y_ibuf + width, ysrc + stride, width); 353 lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y);
355 memcpy(bu_ibuf, usrc, width >> 1); 354 lcd_begin_write_gram();
356 memcpy(rv_ibuf, vsrc, width >> 1); 355
357 lcd_write_yuv420_lines(y_ibuf, bu_ibuf, rv_ibuf, width); 356 memcpy(y_ibuf + width, ysrc, width);
357 memcpy(y_ibuf, ysrc + stride, width);
358 memcpy(c_ibuf, usrc, width >> 1);
359 memcpy(c_ibuf + (width >> 1), vsrc, width >> 1);
360 lcd_write_yuv420_lines(y_ibuf, c_ibuf, width >> 1);
361
362 y += 2;
358 ysrc += 2 * stride; 363 ysrc += 2 * stride;
359 usrc += stride >> 1; 364 usrc += stride >> 1;
360 vsrc += stride >> 1; 365 vsrc += stride >> 1;
@@ -368,11 +373,12 @@ void lcd_update(void) ICODE_ATTR;
368void lcd_update(void) 373void lcd_update(void)
369{ 374{
370 if(display_on){ 375 if(display_on){
371 /* reset update window */ 376 lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_VERT);
377 /* set start position window */
378 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, 175 << 8);
372 lcd_write_reg(R_VERT_RAM_ADDR_POS,((xoffset+219)<<8) | xoffset); 379 lcd_write_reg(R_VERT_RAM_ADDR_POS,((xoffset+219)<<8) | xoffset);
373
374 /* Copy display bitmap to hardware */
375 lcd_write_reg(R_RAM_ADDR_SET, xoffset << 8); 380 lcd_write_reg(R_RAM_ADDR_SET, xoffset << 8);
381
376 lcd_begin_write_gram(); 382 lcd_begin_write_gram();
377 383
378 DAR3 = 0xf0000002; 384 DAR3 = 0xf0000002;
@@ -403,8 +409,9 @@ void lcd_update_rect(int x, int y, int width, int height)
403 if(y + height > LCD_HEIGHT) 409 if(y + height > LCD_HEIGHT)
404 height = LCD_HEIGHT - y; 410 height = LCD_HEIGHT - y;
405 411
412 lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_VERT);
406 /* set update window */ 413 /* set update window */
407 414 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, 175 << 8);
408 lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+xoffset+width-1) << 8) | (x+xoffset)); 415 lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+xoffset+width-1) << 8) | (x+xoffset));
409 lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y); 416 lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y);
410 lcd_begin_write_gram(); 417 lcd_begin_write_gram();