diff options
Diffstat (limited to 'firmware/target/coldfire/iaudio/x5')
-rw-r--r-- | firmware/target/coldfire/iaudio/x5/lcd-as-x5.S | 242 | ||||
-rw-r--r-- | firmware/target/coldfire/iaudio/x5/lcd-x5.c | 63 |
2 files changed, 305 insertions, 0 deletions
diff --git a/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S b/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S index b319d745ca..e6621e1dea 100644 --- a/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S +++ b/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S | |||
@@ -25,6 +25,248 @@ | |||
25 | 25 | ||
26 | .section .icode,"ax",@progbits | 26 | .section .icode,"ax",@progbits |
27 | 27 | ||
28 | /* begin lcd_write_yuv420_lines | ||
29 | * | ||
30 | * See http://en.wikipedia.org/wiki/YCbCr | ||
31 | * ITU-R BT.601 (formerly CCIR 601): | ||
32 | * |Y'| | 0.299000 0.587000 0.114000| |R| | ||
33 | * |Pb| = |-0.168736 -0.331264 0.500000| |G| or 0.564334*(B - Y') | ||
34 | * |Pr| | 0.500000 -0.418688 0.081312| |B| or 0.713267*(R - Y') | ||
35 | * Scaled, normalized and rounded: | ||
36 | * |Y'| | 65 129 25| |R| + 16 : 16->235 | ||
37 | * |Cb| = |-38 -74 112| |G| + 128 : 16->240 | ||
38 | * |Cr| |112 -94 -18| |B| + 128 : 16->240 | ||
39 | * | ||
40 | * The inverse: | ||
41 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
42 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
43 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
44 | * Scaled, normalized, rounded and tweaked to yield RGB 666: | ||
45 | * |R| |19611723 0 26881894| |Y' - 16| >> 26 | ||
46 | * |G| = |19611723 -6406711 -13692816| |Cb - 128| >> 26 | ||
47 | * |B| |19611723 33976259 0| |Cr - 128| >> 26 | ||
48 | * | ||
49 | * Needs EMAC set to saturated, signed integer mode. | ||
50 | * | ||
51 | * register usage: | ||
52 | * %a0 - LCD data port | ||
53 | * %a1 - Y pointer | ||
54 | * %a2 - C pointer | ||
55 | * %a3 - C width | ||
56 | * %a4 - Y end address | ||
57 | * %a5 - Y factor | ||
58 | * %a6 - BU factor | ||
59 | * %d0 - scratch | ||
60 | * %d1 - B, previous Y \ alternating | ||
61 | * %d2 - U / B, previous Y / | ||
62 | * %d3 - V / G | ||
63 | * %d4 - R / output pixel | ||
64 | * %d5 - GU factor | ||
65 | * %d6 - GV factor | ||
66 | * %d7 - RGB signed -> unsigned conversion mask | ||
67 | */ | ||
68 | .align 2 | ||
69 | .global lcd_write_yuv420_lines | ||
70 | .type lcd_write_yuv420_lines, @function | ||
71 | |||
72 | lcd_write_yuv420_lines: | ||
73 | lea.l (-44, %sp), %sp /* free up some registers */ | ||
74 | movem.l %d2-%d7/%a2-%a6, (%sp) | ||
75 | |||
76 | lea.l 0xf0008002, %a0 /* LCD data port */ | ||
77 | movem.l (44+4, %sp), %a1-%a3 /* Y data, C data, C width */ | ||
78 | lea.l (%a1, %a3*2), %a4 /* Y end address */ | ||
79 | |||
80 | move.l #19611723, %a5 /* y factor */ | ||
81 | move.l #33976259, %a6 /* bu factor */ | ||
82 | move.l #-6406711, %d5 /* gu factor */ | ||
83 | move.l #-13692816, %d6 /* gv factor */ | ||
84 | move.l #0x01040820, %d7 /* bitmask for signed->unsigned conversion | ||
85 | * of R, G and B within RGGB6666 at once */ | ||
86 | |||
87 | /* chroma for first 2x2 block */ | ||
88 | clr.l %d3 /* load v component */ | ||
89 | move.b (%a2, %a3), %d3 | ||
90 | clr.l %d2 /* load u component */ | ||
91 | move.b (%a2)+, %d2 | ||
92 | moveq.l #-128, %d0 | ||
93 | add.l %d0, %d2 | ||
94 | add.l %d0, %d3 | ||
95 | |||
96 | mac.l %a6, %d2, %acc0 /* bu */ | ||
97 | mac.l %d5, %d2, %acc1 /* gu */ | ||
98 | mac.l %d6, %d3, %acc1 /* gv */ | ||
99 | move.l #26881894, %d0 /* rv factor */ | ||
100 | mac.l %d0, %d3, %acc2 /* rv */ | ||
101 | |||
102 | /* luma for very first pixel (top left) */ | ||
103 | clr.l %d1 | ||
104 | move.b (%a1, %a3*2), %d1 | ||
105 | moveq.l #-126, %d0 | ||
106 | add.l %d1, %d0 /* y' (-0.5 ... +0.5) */ | ||
107 | mac.l %a5, %d0, %acc0 | ||
108 | mac.l %a5, %d0, %acc1 | ||
109 | mac.l %a5, %d0, %acc2 | ||
110 | |||
111 | bra.b .yuv_line_entry | ||
112 | |||
113 | .yuv_line_loop: | ||
114 | /* chroma for 2x2 pixel block */ | ||
115 | clr.l %d3 /* load v component */ | ||
116 | move.b (%a2, %a3), %d3 | ||
117 | clr.l %d2 /* load u component */ | ||
118 | move.b (%a2)+, %d2 | ||
119 | moveq.l #-128, %d0 | ||
120 | add.l %d0, %d2 | ||
121 | add.l %d0, %d3 | ||
122 | |||
123 | mac.l %a6, %d2, %acc0 /* bu */ | ||
124 | mac.l %d5, %d2, %acc1 /* gu */ | ||
125 | mac.l %d6, %d3, %acc1 /* gv */ | ||
126 | move.l #26881894, %d0 /* rv factor */ | ||
127 | mac.l %d0, %d3, %acc2 /* rv */ | ||
128 | |||
129 | /* luma for first pixel (top left) */ | ||
130 | clr.l %d1 | ||
131 | move.b (%a1, %a3*2), %d1 | ||
132 | moveq.l #-126, %d0 | ||
133 | add.l %d1, %d0 /* y' (-0.5 ... +0.5) */ | ||
134 | mac.l %a5, %d0, %acc0 | ||
135 | mac.l %a5, %d0, %acc1 | ||
136 | mac.l %a5, %d0, %acc2 | ||
137 | |||
138 | move.w %d4, (%a0) | ||
139 | /* 2nd LCD write is delayed one pixel to use it for filling the EMAC latency */ | ||
140 | |||
141 | /* convert to RGB666, pack and output */ | ||
142 | .yuv_line_entry: | ||
143 | moveq.l #26, %d0 | ||
144 | move.l %acc0, %d4 | ||
145 | move.l %acc1, %d3 | ||
146 | move.l %acc2, %d2 | ||
147 | lsr.l %d0, %d4 | ||
148 | lsr.l %d0, %d3 | ||
149 | lsr.l %d0, %d2 | ||
150 | |||
151 | lsl.l #6, %d2 | ||
152 | or.l %d3, %d2 /* |00000000|00000000|0000Rrrr|rrGggggg| */ | ||
153 | lsl.l #7, %d2 | ||
154 | or.l %d2, %d3 /* |00000000|00000Rrr|rrrGgggg|g0Gggggg| */ | ||
155 | lsl.l #6, %d3 | ||
156 | or.l %d3, %d4 /* |0000000R|rrrrrGgg|ggg0Gggg|ggBbbbbb| */ | ||
157 | eor.l %d7, %d4 /* |0000000r|rrrrrggg|ggg0gggg|ggbbbbbb| */ | ||
158 | swap %d4 | ||
159 | move.w %d4, (%a0) | ||
160 | swap %d4 | ||
161 | |||
162 | /* luma for second pixel (bottom left) as delta from the first */ | ||
163 | clr.l %d2 | ||
164 | move.b (%a1)+, %d2 | ||
165 | move.l %d2, %d0 | ||
166 | sub.l %d1, %d0 | ||
167 | mac.l %a5, %d0, %acc0 | ||
168 | mac.l %a5, %d0, %acc1 | ||
169 | mac.l %a5, %d0, %acc2 | ||
170 | |||
171 | move.w %d4, (%a0) | ||
172 | /* 2nd LCD write is delayed one pixel to use it for filling the EMAC latency */ | ||
173 | |||
174 | /* convert to RGB666, pack and output */ | ||
175 | moveq.l #26, %d0 | ||
176 | move.l %acc0, %d4 | ||
177 | move.l %acc1, %d3 | ||
178 | move.l %acc2, %d1 | ||
179 | lsr.l %d0, %d4 | ||
180 | lsr.l %d0, %d3 | ||
181 | lsr.l %d0, %d1 | ||
182 | |||
183 | lsl.l #6, %d1 | ||
184 | or.l %d3, %d1 /* |00000000|00000000|0000Rrrr|rrGggggg| */ | ||
185 | lsl.l #7, %d1 | ||
186 | or.l %d1, %d3 /* |00000000|00000Rrr|rrrGgggg|g0Gggggg| */ | ||
187 | lsl.l #6, %d3 | ||
188 | or.l %d3, %d4 /* |0000000R|rrrrrGgg|ggg0Gggg|ggBbbbbb| */ | ||
189 | eor.l %d7, %d4 /* |0000000r|rrrrrggg|ggg0gggg|ggbbbbbb| */ | ||
190 | swap %d4 | ||
191 | move.w %d4, (%a0) | ||
192 | swap %d4 | ||
193 | |||
194 | /* luma for third pixel (top right) as delta from the second */ | ||
195 | clr.l %d1 | ||
196 | move.b (%a1, %a3*2), %d1 | ||
197 | move.l %d1, %d0 | ||
198 | sub.l %d2, %d0 | ||
199 | mac.l %a5, %d0, %acc0 | ||
200 | mac.l %a5, %d0, %acc1 | ||
201 | mac.l %a5, %d0, %acc2 | ||
202 | |||
203 | move.w %d4, (%a0) | ||
204 | /* 2nd LCD write is delayed one pixel to use it for filling the EMAC latency */ | ||
205 | |||
206 | /* convert to RGB666, pack and output */ | ||
207 | moveq.l #26, %d0 | ||
208 | move.l %acc0, %d4 | ||
209 | move.l %acc1, %d3 | ||
210 | move.l %acc2, %d2 | ||
211 | lsr.l %d0, %d4 | ||
212 | lsr.l %d0, %d3 | ||
213 | lsr.l %d0, %d2 | ||
214 | |||
215 | lsl.l #6, %d2 | ||
216 | or.l %d3, %d2 /* |00000000|00000000|0000Rrrr|rrGggggg| */ | ||
217 | lsl.l #7, %d2 | ||
218 | or.l %d2, %d3 /* |00000000|00000Rrr|rrrGgggg|g0Gggggg| */ | ||
219 | lsl.l #6, %d3 | ||
220 | or.l %d3, %d4 /* |0000000R|rrrrrGgg|ggg0Gggg|ggBbbbbb| */ | ||
221 | eor.l %d7, %d4 /* |0000000r|rrrrrggg|ggg0gggg|ggbbbbbb| */ | ||
222 | swap %d4 | ||
223 | move.w %d4, (%a0) | ||
224 | swap %d4 | ||
225 | |||
226 | /* luma for fourth pixel (bottom right) as delta from the thrid */ | ||
227 | clr.l %d2 | ||
228 | move.b (%a1)+, %d2 | ||
229 | move.l %d2, %d0 | ||
230 | sub.l %d1, %d0 | ||
231 | mac.l %a5, %d0, %acc0 | ||
232 | mac.l %a5, %d0, %acc1 | ||
233 | mac.l %a5, %d0, %acc2 | ||
234 | |||
235 | move.w %d4, (%a0) | ||
236 | /* 2nd LCD write is delayed one pixel to use it for filling the EMAC latency */ | ||
237 | |||
238 | /* convert to RGB666, pack and output */ | ||
239 | moveq.l #26, %d0 | ||
240 | movclr.l %acc0, %d4 | ||
241 | movclr.l %acc1, %d3 | ||
242 | movclr.l %acc2, %d1 | ||
243 | lsr.l %d0, %d4 | ||
244 | lsr.l %d0, %d3 | ||
245 | lsr.l %d0, %d1 | ||
246 | |||
247 | lsl.l #6, %d1 | ||
248 | or.l %d3, %d1 /* |00000000|00000000|0000Rrrr|rrGggggg| */ | ||
249 | lsl.l #7, %d1 | ||
250 | or.l %d1, %d3 /* |00000000|00000Rrr|rrrGgggg|g0Gggggg| */ | ||
251 | lsl.l #6, %d3 | ||
252 | or.l %d3, %d4 /* |0000000R|rrrrrGgg|ggg0Gggg|ggBbbbbb| */ | ||
253 | eor.l %d7, %d4 /* |0000000r|rrrrrggg|ggg0gggg|ggbbbbbb| */ | ||
254 | swap %d4 | ||
255 | move.w %d4, (%a0) | ||
256 | swap %d4 | ||
257 | |||
258 | cmp.l %a1, %a4 /* run %a1 up to end of line */ | ||
259 | bhi.w .yuv_line_loop | ||
260 | |||
261 | move.w %d4, (%a0) /* write (very) last 2nd word */ | ||
262 | |||
263 | movem.l (%sp), %d2-%d7/%a2-%a6 | ||
264 | lea.l (44, %sp), %sp /* restore registers */ | ||
265 | rts | ||
266 | .yuv_end: | ||
267 | .size lcd_write_yuv420_lines, .yuv_end - lcd_write_yuv420_lines | ||
268 | |||
269 | |||
28 | /* begin lcd_write_data */ | 270 | /* begin lcd_write_data */ |
29 | .align 2 | 271 | .align 2 |
30 | .global lcd_write_data | 272 | .global lcd_write_data |
diff --git a/firmware/target/coldfire/iaudio/x5/lcd-x5.c b/firmware/target/coldfire/iaudio/x5/lcd-x5.c index a6a4fc0176..266a381c40 100644 --- a/firmware/target/coldfire/iaudio/x5/lcd-x5.c +++ b/firmware/target/coldfire/iaudio/x5/lcd-x5.c | |||
@@ -414,6 +414,69 @@ bool lcd_active(void) | |||
414 | #endif | 414 | #endif |
415 | /*** update functions ***/ | 415 | /*** update functions ***/ |
416 | 416 | ||
417 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. | ||
418 | * y should have two lines of Y back to back, 2nd line first. | ||
419 | * c should contain the Cb and Cr data for the two lines of Y back to back. | ||
420 | * Needs EMAC set to saturated, signed integer mode. | ||
421 | */ | ||
422 | extern void lcd_write_yuv420_lines(const unsigned char *y, | ||
423 | const unsigned char *c, int width); | ||
424 | |||
425 | /* Performance function to blit a YUV bitmap directly to the LCD | ||
426 | * src_x, src_y, width and height should be even and within the LCD's | ||
427 | * boundaries. | ||
428 | */ | ||
429 | void lcd_blit_yuv(unsigned char * const src[3], | ||
430 | int src_x, int src_y, int stride, | ||
431 | int x, int y, int width, int height) | ||
432 | { | ||
433 | /* IRAM Y, Cb/bu, guv and Cb/rv buffers. */ | ||
434 | unsigned char y_ibuf[LCD_WIDTH*2]; | ||
435 | unsigned char c_ibuf[LCD_WIDTH]; | ||
436 | const unsigned char *ysrc, *usrc, *vsrc; | ||
437 | const unsigned char *ysrc_max; | ||
438 | |||
439 | if (!display_on) | ||
440 | return; | ||
441 | |||
442 | width &= ~1; /* stay on the safe side */ | ||
443 | height &= ~1; | ||
444 | |||
445 | lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_DIT_HORZ); | ||
446 | /* Set start position and window */ | ||
447 | lcd_write_reg(R_VERT_RAM_ADDR_POS, (LCD_WIDTH-1) << 8); | ||
448 | |||
449 | ysrc = src[0] + src_y * stride + src_x; | ||
450 | usrc = src[1] + (src_y * stride >> 2) + (src_x >> 1); | ||
451 | vsrc = src[2] + (src_y * stride >> 2) + (src_x >> 1); | ||
452 | ysrc_max = ysrc + height * stride; | ||
453 | |||
454 | unsigned long macsr = coldfire_get_macsr(); | ||
455 | coldfire_set_macsr(EMAC_SATURATE); | ||
456 | |||
457 | do | ||
458 | { | ||
459 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, ((y + y_offset + 1) << 8) | (y + y_offset)); | ||
460 | lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | (y + y_offset)); | ||
461 | lcd_begin_write_gram(); | ||
462 | |||
463 | memcpy(y_ibuf + width, ysrc, width); | ||
464 | memcpy(y_ibuf, ysrc + stride, width); | ||
465 | memcpy(c_ibuf, usrc, width >> 1); | ||
466 | memcpy(c_ibuf + (width >> 1), vsrc, width >> 1); | ||
467 | lcd_write_yuv420_lines(y_ibuf, c_ibuf, width >> 1); | ||
468 | |||
469 | y += 2; | ||
470 | ysrc += 2 * stride; | ||
471 | usrc += stride >> 1; | ||
472 | vsrc += stride >> 1; | ||
473 | } | ||
474 | while (ysrc < ysrc_max); | ||
475 | |||
476 | coldfire_set_macsr(macsr); | ||
477 | } /* lcd_yuv_blit */ | ||
478 | |||
479 | |||
417 | /* Update the display. | 480 | /* Update the display. |
418 | This must be called after all other LCD functions that change the | 481 | This must be called after all other LCD functions that change the |
419 | lcd frame buffer. */ | 482 | lcd frame buffer. */ |