diff options
Diffstat (limited to 'firmware/target/arm')
38 files changed, 7762 insertions, 1 deletions
diff --git a/firmware/target/arm/as3525/lcd-as-e200v2-fuze-fuzev2.S b/firmware/target/arm/as3525/lcd-as-e200v2-fuze-fuzev2.S new file mode 100644 index 0000000000..feffe6fb96 --- /dev/null +++ b/firmware/target/arm/as3525/lcd-as-e200v2-fuze-fuzev2.S | |||
@@ -0,0 +1,550 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Jens Arnold | ||
11 | * Heavily based on lcd-as-memframe.c by Michael Sevakis | ||
12 | * Adapted for Sansa Fuze/e200v2 by Rafaël Carré | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | #include "config.h" | ||
25 | #include "cpu.h" | ||
26 | |||
27 | #define DBOP_BUSY (1<<10) | ||
28 | |||
29 | /**************************************************************************** | ||
30 | * void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
31 | * int width, | ||
32 | * int stride); | ||
33 | * | ||
34 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
35 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
36 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
37 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
38 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
39 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
40 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
41 | * | ||
42 | * Write four RGB565 pixels in the following order on each loop: | ||
43 | * 1 3 + > down | ||
44 | * 2 4 \/ left | ||
45 | */ | ||
46 | .section .icode, "ax", %progbits | ||
47 | .align 2 | ||
48 | .global lcd_write_yuv420_lines | ||
49 | .type lcd_write_yuv420_lines, %function | ||
50 | lcd_write_yuv420_lines: | ||
51 | @ r0 = yuv_src | ||
52 | @ r1 = width | ||
53 | @ r2 = stride | ||
54 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
55 | |||
56 | mov r3, #0xC8000000 @ | ||
57 | orr r3, r3, #0x120000 @ r3 = DBOP_BASE | ||
58 | |||
59 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
60 | @ r5 = yuv_src[1] = Cb_p | ||
61 | @ r6 = yuv_src[2] = Cr_p | ||
62 | @ r0 = scratch | ||
63 | ldr r12, [r3, #8] @ | ||
64 | sub r2, r2, #1 @ stride -= 1 | ||
65 | orr r12, r12, #3<<13 @ DBOP_CTRL |= (1<<13|1<<14) (32bit mode) | ||
66 | #ifdef SANSA_FUZEV2 | ||
67 | bic r12, r12, #1<<13 @ DBOP_CTRL &= ~(1<<13),still 32bit mode | ||
68 | #endif | ||
69 | str r12, [r3, #8] @ | ||
70 | 10: @ loop line @ | ||
71 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
72 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
73 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
74 | @ | ||
75 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 | ||
76 | add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right | ||
77 | add r7, r12, r7, asl #5 @ by one less when adding - same for all | ||
78 | @ | ||
79 | sub r8, r8, #128 @ Cb -= 128 | ||
80 | sub r9, r9, #128 @ Cr -= 128 | ||
81 | @ | ||
82 | add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 | ||
83 | add r10, r10, r10, asl #4 @ | ||
84 | add r10, r10, r8, asl #3 @ | ||
85 | add r10, r10, r8, asl #4 @ | ||
86 | @ | ||
87 | add lr, r9, r9, asl #2 @ r9 = Cr*101 | ||
88 | add lr, lr, r9, asl #5 @ | ||
89 | add r9, lr, r9, asl #6 @ | ||
90 | @ | ||
91 | add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 | ||
92 | mov r8, r8, asr #2 @ | ||
93 | add r9, r9, #256 @ r9 = rv = (r9 + 256) >> 9 | ||
94 | mov r9, r9, asr #9 @ | ||
95 | rsb r10, r10, #128 @ r10 = guv = (-r10 + 128) >> 8 | ||
96 | mov r10, r10, asr #8 @ | ||
97 | @ compute R, G, and B | ||
98 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
99 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
100 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
101 | @ | ||
102 | orr r12, r0, lr @ check if clamping is needed... | ||
103 | orr r12, r12, r7, asr #1 @ ...at all | ||
104 | cmp r12, #31 @ | ||
105 | bls 15f @ no clamp @ | ||
106 | cmp r0, #31 @ clamp b | ||
107 | mvnhi r0, r0, asr #31 @ | ||
108 | andhi r0, r0, #31 @ | ||
109 | cmp lr, #31 @ clamp r | ||
110 | mvnhi lr, lr, asr #31 @ | ||
111 | andhi lr, lr, #31 @ | ||
112 | cmp r7, #63 @ clamp g | ||
113 | mvnhi r7, r7, asr #31 @ | ||
114 | andhi r7, r7, #63 @ | ||
115 | 15: @ no clamp @ | ||
116 | @ | ||
117 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
118 | @ | ||
119 | orr r0, r0, lr, lsl #11 @ r0 = (r << 11) | b | ||
120 | orr r11, r0, r7, lsl #5 @ r11 = (r << 11) | (g << 5) | b | ||
121 | orr r11, r0, r7, lsl #5 @ r11 = (r << 11) | (g << 5) | b | ||
122 | #ifdef SANSA_FUZEV2 | ||
123 | mov r0, r11, lsr #8 @ | ||
124 | bic r11, r11, #0xff00 @ | ||
125 | orr r11, r0, r11, lsl #8 @ swap bytes | ||
126 | #endif | ||
127 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
128 | add r12, r7, r7, asl #2 @ | ||
129 | add r7, r12, r7, asl #5 @ | ||
130 | @ compute R, G, and B | ||
131 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
132 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
133 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
134 | @ | ||
135 | orr r12, r0, lr @ check if clamping is needed... | ||
136 | orr r12, r12, r7, asr #1 @ ...at all | ||
137 | cmp r12, #31 @ | ||
138 | bls 15f @ no clamp @ | ||
139 | cmp r0, #31 @ clamp b | ||
140 | mvnhi r0, r0, asr #31 @ | ||
141 | andhi r0, r0, #31 @ | ||
142 | cmp lr, #31 @ clamp r | ||
143 | mvnhi lr, lr, asr #31 @ | ||
144 | andhi lr, lr, #31 @ | ||
145 | cmp r7, #63 @ clamp g | ||
146 | mvnhi r7, r7, asr #31 @ | ||
147 | andhi r7, r7, #63 @ | ||
148 | 15: @ no clamp @ | ||
149 | @ | ||
150 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
151 | @ | ||
152 | orr r0, r0, lr, lsl #11 @ r0 = (r << 11) | b | ||
153 | orr r0, r0, r7, lsl #5 @ r0 = (r << 11) | (g << 5) | b | ||
154 | |||
155 | #ifdef SANSA_FUZEV2 | ||
156 | mov r7, r0, lsr #8 @ | ||
157 | bic r7, r7, #0xff00 @ | ||
158 | orr r0, r7, r0, lsl #8 @ swap bytes | ||
159 | #endif | ||
160 | |||
161 | orr r0, r11, r0, lsl#16 @ pack with 2nd pixel | ||
162 | str r0, [r3, #0x10] @ write pixel | ||
163 | @ | ||
164 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
165 | add r12, r7, r7, asl #2 @ | ||
166 | add r7, r12, r7, asl #5 @ | ||
167 | @ compute R, G, and B | ||
168 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
169 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
170 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
171 | @ | ||
172 | orr r12, r0, lr @ check if clamping is needed... | ||
173 | orr r12, r12, r7, asr #1 @ ...at all | ||
174 | cmp r12, #31 @ | ||
175 | bls 15f @ no clamp @ | ||
176 | cmp r0, #31 @ clamp b | ||
177 | mvnhi r0, r0, asr #31 @ | ||
178 | andhi r0, r0, #31 @ | ||
179 | cmp lr, #31 @ clamp r | ||
180 | mvnhi lr, lr, asr #31 @ | ||
181 | andhi lr, lr, #31 @ | ||
182 | cmp r7, #63 @ clamp g | ||
183 | mvnhi r7, r7, asr #31 @ | ||
184 | andhi r7, r7, #63 @ | ||
185 | 15: @ no clamp @ | ||
186 | @ | ||
187 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
188 | @ | ||
189 | @ | ||
190 | orr r0, r0, lr, lsl #11 @ r0 = (r << 11) | b | ||
191 | orr r11, r0, r7, lsl #5 @ r0 = (r << 11) | (g << 5) | b | ||
192 | |||
193 | #ifdef SANSA_FUZEV2 | ||
194 | mov r0, r11, lsr #8 @ | ||
195 | bic r11, r11, #0xff00 @ | ||
196 | orr r11, r0, r11, lsl #8 @ swap byte | ||
197 | #endif | ||
198 | |||
199 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
200 | add r12, r7, r7, asl #2 @ | ||
201 | add r7, r12, r7, asl #5 @ | ||
202 | @ compute R, G, and B | ||
203 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
204 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
205 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
206 | @ | ||
207 | orr r12, r0, lr @ check if clamping is needed... | ||
208 | orr r12, r12, r7, asr #1 @ ...at all | ||
209 | cmp r12, #31 @ | ||
210 | bls 15f @ no clamp @ | ||
211 | cmp r0, #31 @ clamp b | ||
212 | mvnhi r0, r0, asr #31 @ | ||
213 | andhi r0, r0, #31 @ | ||
214 | cmp lr, #31 @ clamp r | ||
215 | mvnhi lr, lr, asr #31 @ | ||
216 | andhi lr, lr, #31 @ | ||
217 | cmp r7, #63 @ clamp g | ||
218 | mvnhi r7, r7, asr #31 @ | ||
219 | andhi r7, r7, #63 @ | ||
220 | 15: @ no clamp @ | ||
221 | @ | ||
222 | orr r0, r0, lr, lsl #11 @ r0 = (r << 11) | b | ||
223 | orr r0, r0, r7, lsl #5 @ r0 = (r << 11) | (g << 5) | b | ||
224 | |||
225 | #ifdef SANSA_FUZEV2 | ||
226 | mov r7, r0, lsr #8 @ | ||
227 | bic r7, r7, #0xff00 @ | ||
228 | orr r0, r7, r0, lsl #8 @ swap bytes | ||
229 | #endif | ||
230 | |||
231 | orr r0, r11, r0, lsl#16 @ pack with 2nd pixel | ||
232 | str r0, [r3, #0x10] @ write pixel | ||
233 | @ | ||
234 | subs r1, r1, #2 @ subtract block from width | ||
235 | bgt 10b @ loop line @ | ||
236 | @ | ||
237 | 1: @ busy | ||
238 | @ writing at max 110*32 (LCD_WIDTH/2), the fifo is bigger | ||
239 | @ so polling fifo empty only after each line is save | ||
240 | ldr r7, [r3,#0xc] @ r7 = DBOP_STATUS | ||
241 | tst r7, #DBOP_BUSY @ fifo not empty? | ||
242 | beq 1b @ | ||
243 | |||
244 | ldmpc regs=r4-r11 @ restore registers and return | ||
245 | .ltorg @ dump constant pool | ||
246 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
247 | |||
248 | /**************************************************************************** | ||
249 | * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
250 | * int width, | ||
251 | * int stride, | ||
252 | * int x_screen, | ||
253 | * int y_screen); | ||
254 | * | ||
255 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
256 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
257 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
258 | * Red scaled at twice g & b but at same precision to place it in correct | ||
259 | * bit position after multiply and leave instruction count lower. | ||
260 | * |R| |258 0 408| |Y' - 16| | ||
261 | * |G| = |149 -49 -104| |Cb - 128| | ||
262 | * |B| |149 258 0| |Cr - 128| | ||
263 | * | ||
264 | * Write four RGB565 pixels in the following order on each loop: | ||
265 | * 1 3 + > down | ||
266 | * 2 4 \/ left | ||
267 | * | ||
268 | * Kernel pattern (raw|rotated|use order): | ||
269 | * 5 3 4 2 2 6 3 7 row0 row2 > down | ||
270 | * 1 7 0 6 | 4 0 5 1 | 2 4 6 0 3 5 7 1 col0 left | ||
271 | * 4 2 5 3 | 3 7 2 6 | 3 5 7 1 2 4 6 0 col2 \/ | ||
272 | * 0 6 1 7 5 1 4 0 | ||
273 | */ | ||
274 | .section .icode, "ax", %progbits | ||
275 | .align 2 | ||
276 | .global lcd_write_yuv420_lines_odither | ||
277 | .type lcd_write_yuv420_lines_odither, %function | ||
278 | lcd_write_yuv420_lines_odither: | ||
279 | @ r0 = yuv_src | ||
280 | @ r1 = width | ||
281 | @ r2 = stride | ||
282 | @ r3 = x_screen | ||
283 | @ [sp] = y_screen | ||
284 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
285 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
286 | @ r5 = yuv_src[1] = Cb_p | ||
287 | @ r6 = yuv_src[2] = Cr_p | ||
288 | @ | ||
289 | ldr r14, [sp, #36] @ Line up pattern and kernel quadrant | ||
290 | sub r2, r2, #1 @ stride =- 1 | ||
291 | eor r14, r14, r3 @ | ||
292 | and r14, r14, #0x2 @ | ||
293 | mov r14, r14, lsl #6 @ 0x00 or 0x80 | ||
294 | |||
295 | mov r3, #0xC8000000 @ | ||
296 | orr r3, r3, #0x120000 @ r3 = DBOP_BASE, need to be redone | ||
297 | @ due to lack of registers | ||
298 | ldr r12, [r3, #8] @ | ||
299 | orr r12, r12, #3<<13 @ DBOP_CTRL |= (1<<13|1<<14) | ||
300 | #ifdef SANSA_FUZEV2 | ||
301 | bic r12, r12, #1<<13 @ DBOP_CTRL &= ~(1<<13), still 32bit mode | ||
302 | #endif | ||
303 | str r12, [r3, #8] @ (32bit mode) | ||
304 | 10: @ loop line @ | ||
305 | @ | ||
306 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
307 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
308 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
309 | @ | ||
310 | eor r14, r14, #0x80 @ flip pattern quadrant | ||
311 | @ | ||
312 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149 | ||
313 | add r12, r7, r7, asl #2 @ | ||
314 | add r12, r12, r12, asl #4 @ | ||
315 | add r7, r12, r7, asl #6 @ | ||
316 | @ | ||
317 | sub r8, r8, #128 @ Cb -= 128 | ||
318 | sub r9, r9, #128 @ Cr -= 128 | ||
319 | @ | ||
320 | add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49 | ||
321 | add r10, r10, r8, asl #5 @ | ||
322 | add r10, r10, r9, asl #3 @ | ||
323 | add r10, r10, r9, asl #5 @ | ||
324 | add r10, r10, r9, asl #6 @ | ||
325 | @ | ||
326 | mov r8, r8, asl #1 @ r8 = bu = Cb*258 | ||
327 | add r8, r8, r8, asl #7 @ | ||
328 | @ | ||
329 | add r9, r9, r9, asl #1 @ r9 = rv = Cr*408 | ||
330 | add r9, r9, r9, asl #4 @ | ||
331 | mov r9, r9, asl #3 @ | ||
332 | @ | ||
333 | @ compute R, G, and B | ||
334 | add r0, r8, r7 @ r0 = b' = Y + bu | ||
335 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
336 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
337 | @ | ||
338 | @ r8 = bu, r9 = rv, r10 = guv | ||
339 | @ | ||
340 | sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256 | ||
341 | add r0, r12, r0, lsr #8 @ | ||
342 | @ | ||
343 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
344 | add r11, r12, r11, lsr #8 @ | ||
345 | @ | ||
346 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
347 | add r7, r12, r7, lsr #8 @ | ||
348 | @ | ||
349 | add r12, r14, #0x100 @ | ||
350 | @ | ||
351 | add r0, r0, r12 @ b = r0 + delta | ||
352 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
353 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
354 | @ | ||
355 | orr r12, r0, r11, asr #1 @ check if clamping is needed... | ||
356 | orr r12, r12, r7 @ ...at all | ||
357 | movs r12, r12, asr #15 @ | ||
358 | beq 15f @ no clamp @ | ||
359 | movs r12, r0, asr #15 @ clamp b | ||
360 | mvnne r0, r12, lsr #15 @ | ||
361 | andne r0, r0, #0x7c00 @ mask b only if clamped | ||
362 | movs r12, r11, asr #16 @ clamp r | ||
363 | mvnne r11, r12, lsr #16 @ | ||
364 | movs r12, r7, asr #15 @ clamp g | ||
365 | mvnne r7, r12, lsr #15 @ | ||
366 | 15: @ no clamp @ | ||
367 | @ | ||
368 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
369 | @ | ||
370 | and r11, r11, #0xf800 @ pack pixel | ||
371 | and r7, r7, #0x7e00 @ r0 = pixel = (r & 0xf800) | | ||
372 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
373 | orr r3, r11, r0, lsr #10 @ (b >> 10) | ||
374 | #ifdef SANSA_FUZEV2 | ||
375 | mov r7, r3, lsr #8 @ | ||
376 | bic r3, r3, #0xff00 @ | ||
377 | orr r3, r7, r3, lsl #8 @ swap pixel | ||
378 | #endif | ||
379 | @ save pixel | ||
380 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
381 | add r12, r7, r7, asl #2 @ | ||
382 | add r12, r12, r12, asl #4 @ | ||
383 | add r7, r12, r7, asl #6 @ | ||
384 | @ compute R, G, and B | ||
385 | add r0, r8, r7 @ r0 = b' = Y + bu | ||
386 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
387 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
388 | @ | ||
389 | sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256 | ||
390 | add r0, r12, r0, lsr #8 @ | ||
391 | @ | ||
392 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
393 | add r11, r12, r11, lsr #8 @ | ||
394 | @ | ||
395 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
396 | add r7, r12, r7, lsr #8 @ | ||
397 | @ | ||
398 | add r12, r14, #0x200 @ | ||
399 | @ | ||
400 | add r0, r0, r12 @ b = r0 + delta | ||
401 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
402 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
403 | @ | ||
404 | orr r12, r0, r11, asr #1 @ check if clamping is needed... | ||
405 | orr r12, r12, r7 @ ...at all | ||
406 | movs r12, r12, asr #15 @ | ||
407 | beq 15f @ no clamp @ | ||
408 | movs r12, r0, asr #15 @ clamp b | ||
409 | mvnne r0, r12, lsr #15 @ | ||
410 | andne r0, r0, #0x7c00 @ mask b only if clamped | ||
411 | movs r12, r11, asr #16 @ clamp r | ||
412 | mvnne r11, r12, lsr #16 @ | ||
413 | movs r12, r7, asr #15 @ clamp g | ||
414 | mvnne r7, r12, lsr #15 @ | ||
415 | 15: @ no clamp @ | ||
416 | @ | ||
417 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
418 | |||
419 | and r11, r11, #0xf800 @ pack pixel | ||
420 | and r7, r7, #0x7e00 @ r0 = pixel = (r & 0xf800) | | ||
421 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
422 | orr r0, r11, r0, lsr #10 @ (b >> 10) | ||
423 | #ifdef SANSA_FUZEV2 | ||
424 | mov r7, r0, lsr #8 @ | ||
425 | bic r0, r0, #0xff00 @ | ||
426 | orr r0, r7, r0, lsl #8 @ swap pixel | ||
427 | #endif | ||
428 | orr r3, r3, r0, lsl#16 @ pack with 2nd pixel | ||
429 | mov r0, #0xC8000000 @ | ||
430 | orr r0, r0, #0x120000 @ r3 = DBOP_BASE | ||
431 | |||
432 | str r3, [r0, #0x10] @ write pixel | ||
433 | @ | ||
434 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
435 | add r12, r7, r7, asl #2 @ | ||
436 | add r12, r12, r12, asl #4 @ | ||
437 | add r7, r12, r7, asl #6 @ | ||
438 | @ compute R, G, and B | ||
439 | add r0, r8, r7 @ r0 = b' = Y + bu | ||
440 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
441 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
442 | @ | ||
443 | @ r8 = bu, r9 = rv, r10 = guv | ||
444 | @ | ||
445 | sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256 | ||
446 | add r0, r12, r0, lsr #8 @ | ||
447 | @ | ||
448 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
449 | add r11, r12, r11, lsr #8 @ | ||
450 | @ | ||
451 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
452 | add r7, r12, r7, lsr #8 @ | ||
453 | @ | ||
454 | add r12, r14, #0x300 @ | ||
455 | @ | ||
456 | add r0, r0, r12 @ b = r0 + delta | ||
457 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
458 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
459 | @ | ||
460 | orr r12, r0, r11, asr #1 @ check if clamping is needed... | ||
461 | orr r12, r12, r7 @ ...at all | ||
462 | movs r12, r12, asr #15 @ | ||
463 | beq 15f @ no clamp @ | ||
464 | movs r12, r0, asr #15 @ clamp b | ||
465 | mvnne r0, r12, lsr #15 @ | ||
466 | andne r0, r0, #0x7c00 @ mask b only if clamped | ||
467 | movs r12, r11, asr #16 @ clamp r | ||
468 | mvnne r11, r12, lsr #16 @ | ||
469 | movs r12, r7, asr #15 @ clamp g | ||
470 | mvnne r7, r12, lsr #15 @ | ||
471 | 15: @ no clamp @ | ||
472 | @ | ||
473 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
474 | @ | ||
475 | and r11, r11, #0xf800 @ pack pixel | ||
476 | and r7, r7, #0x7e00 @ r0 = pixel = (r & 0xf800) | | ||
477 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
478 | orr r3, r11, r0, lsr #10 @ (b >> 10) | ||
479 | #ifdef SANSA_FUZEV2 | ||
480 | mov r7, r3, lsr #8 @ | ||
481 | bic r3, r3, #0xff00 @ | ||
482 | orr r3, r7, r3, lsl #8 @ swap pixel | ||
483 | #endif | ||
484 | @ save pixel | ||
485 | @ | ||
486 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
487 | add r12, r7, r7, asl #2 @ | ||
488 | add r12, r12, r12, asl #4 @ | ||
489 | add r7, r12, r7, asl #6 @ | ||
490 | @ compute R, G, and B | ||
491 | add r0, r8, r7 @ r0 = b' = Y + bu | ||
492 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
493 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
494 | @ | ||
495 | sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256 | ||
496 | add r0, r12, r0, lsr #8 @ | ||
497 | @ | ||
498 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
499 | add r11, r12, r11, lsr #8 @ | ||
500 | @ | ||
501 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
502 | add r7, r12, r7, lsr #8 @ | ||
503 | @ | ||
504 | @ This element is zero - use r14 @ | ||
505 | @ | ||
506 | add r0, r0, r14 @ b = r0 + delta | ||
507 | add r11, r11, r14, lsl #1 @ r = r11 + delta*2 | ||
508 | add r7, r7, r14, lsr #1 @ g = r7 + delta/2 | ||
509 | @ | ||
510 | orr r12, r0, r11, asr #1 @ check if clamping is needed... | ||
511 | orr r12, r12, r7 @ ...at all | ||
512 | movs r12, r12, asr #15 @ | ||
513 | beq 15f @ no clamp @ | ||
514 | movs r12, r0, asr #15 @ clamp b | ||
515 | mvnne r0, r12, lsr #15 @ | ||
516 | andne r0, r0, #0x7c00 @ mask b only if clamped | ||
517 | movs r12, r11, asr #16 @ clamp r | ||
518 | mvnne r11, r12, lsr #16 @ | ||
519 | movs r12, r7, asr #15 @ clamp g | ||
520 | mvnne r7, r12, lsr #15 @ | ||
521 | 15: @ no clamp @ | ||
522 | @ | ||
523 | and r11, r11, #0xf800 @ pack pixel | ||
524 | and r7, r7, #0x7e00 @ r0 = pixel = (r & 0xf800) | | ||
525 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
526 | orr r0, r11, r0, lsr #10 @ (b >> 10) | ||
527 | #ifdef SANSA_FUZEV2 | ||
528 | mov r7, r0, lsr #8 @ | ||
529 | bic r0, r0, #0xff00 @ | ||
530 | orr r0, r7, r0, lsl #8 @ swap pixel | ||
531 | #endif | ||
532 | orr r3, r3, r0, lsl#16 @ pack with 2nd pixel | ||
533 | mov r0, #0xC8000000 @ | ||
534 | orr r0, r0, #0x120000 @ r3 = DBOP_BASE | ||
535 | |||
536 | str r3, [r0, #0x10] @ write pixel | ||
537 | @ | ||
538 | subs r1, r1, #2 @ subtract block from width | ||
539 | bgt 10b @ loop line @ | ||
540 | @ | ||
541 | 1: @ busy @ | ||
542 | @ writing at max 110*32 (LCD_WIDTH/2), the fifo is bigger (128*32) | ||
543 | @ so polling fifo empty only after each line is save | ||
544 | ldr r7, [r0,#0xc] @ r7 = DBOP_STATUS | ||
545 | tst r7, #DBOP_BUSY @ fifo not empty? | ||
546 | beq 1b @ | ||
547 | |||
548 | ldmpc regs=r4-r11 @ restore registers and return | ||
549 | .ltorg @ dump constant pool | ||
550 | .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither | ||
diff --git a/firmware/target/arm/as3525/lcd-fuze.c b/firmware/target/arm/as3525/lcd-fuze.c index b1f62a1c95..a1ccea348d 100644 --- a/firmware/target/arm/as3525/lcd-fuze.c +++ b/firmware/target/arm/as3525/lcd-fuze.c | |||
@@ -197,6 +197,86 @@ static void lcd_window_y(int ymin, int ymax) | |||
197 | lcd_write_reg(R_RAM_ADDR_SET, ymin); | 197 | lcd_write_reg(R_RAM_ADDR_SET, ymin); |
198 | } | 198 | } |
199 | 199 | ||
200 | static unsigned lcd_yuv_options = 0; | ||
201 | |||
202 | void lcd_yuv_set_options(unsigned options) | ||
203 | { | ||
204 | lcd_yuv_options = options; | ||
205 | } | ||
206 | |||
207 | |||
208 | #ifndef BOOTLOADER | ||
209 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ | ||
210 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
211 | int width, | ||
212 | int stride); | ||
213 | extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
214 | int width, | ||
215 | int stride, | ||
216 | int x_screen, /* To align dither pattern */ | ||
217 | int y_screen); | ||
218 | |||
219 | /* Performance function to blit a YUV bitmap directly to the LCD | ||
220 | * src_x, src_y, width and height should be even | ||
221 | * x, y, width and height have to be within LCD bounds | ||
222 | */ | ||
223 | void lcd_blit_yuv(unsigned char * const src[3], | ||
224 | int src_x, int src_y, int stride, | ||
225 | int x, int y, int width, int height) | ||
226 | { | ||
227 | unsigned char const * yuv_src[3]; | ||
228 | off_t z; | ||
229 | |||
230 | /* Sorry, but width and height must be >= 2 or else */ | ||
231 | width &= ~1; | ||
232 | height >>= 1; | ||
233 | |||
234 | z = stride*src_y; | ||
235 | yuv_src[0] = src[0] + z + src_x; | ||
236 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
237 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
238 | |||
239 | lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_VIDEO); | ||
240 | |||
241 | lcd_window_x(x, x + width - 1); | ||
242 | |||
243 | if (lcd_yuv_options & LCD_YUV_DITHER) | ||
244 | { | ||
245 | do | ||
246 | { | ||
247 | lcd_window_y(y, y + 1); | ||
248 | |||
249 | lcd_write_cmd(R_WRITE_DATA_2_GRAM); | ||
250 | |||
251 | lcd_write_yuv420_lines_odither(yuv_src, width, stride, x, y); | ||
252 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
253 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
254 | yuv_src[2] += stride >> 1; | ||
255 | y += 2; | ||
256 | } | ||
257 | while (--height > 0); | ||
258 | } | ||
259 | else | ||
260 | { | ||
261 | do | ||
262 | { | ||
263 | lcd_window_y(y, y + 1); | ||
264 | |||
265 | lcd_write_cmd(R_WRITE_DATA_2_GRAM); | ||
266 | |||
267 | lcd_write_yuv420_lines(yuv_src, width, stride); | ||
268 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
269 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
270 | yuv_src[2] += stride >> 1; | ||
271 | y += 2; | ||
272 | } | ||
273 | while (--height > 0); | ||
274 | } | ||
275 | } | ||
276 | |||
277 | #endif | ||
278 | |||
279 | |||
200 | /* Update the display. | 280 | /* Update the display. |
201 | This must be called after all other LCD functions that change the display. */ | 281 | This must be called after all other LCD functions that change the display. */ |
202 | void lcd_update(void) | 282 | void lcd_update(void) |
diff --git a/firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c b/firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c index 141340c003..f69ad48793 100644 --- a/firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c +++ b/firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c | |||
@@ -336,6 +336,104 @@ bool lcd_active(void) | |||
336 | 336 | ||
337 | /*** update functions ***/ | 337 | /*** update functions ***/ |
338 | 338 | ||
339 | static unsigned lcd_yuv_options = 0; | ||
340 | |||
341 | void lcd_yuv_set_options(unsigned options) | ||
342 | { | ||
343 | lcd_yuv_options = options; | ||
344 | } | ||
345 | |||
346 | |||
347 | #ifndef BOOTLOADER | ||
348 | static void lcd_window_blit(int xmin, int ymin, int xmax, int ymax) | ||
349 | { | ||
350 | if (!display_flipped) | ||
351 | { | ||
352 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, | ||
353 | ((LCD_WIDTH-1 - xmin) << 8) | (LCD_WIDTH-1 - xmax)); | ||
354 | lcd_write_reg(R_VERT_RAM_ADDR_POS, (ymax << 8) | ymin); | ||
355 | lcd_write_reg(R_RAM_ADDR_SET, | ||
356 | (ymin << 8) | (LCD_WIDTH-1 - xmin)); | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (xmax << 8) | xmin); | ||
361 | lcd_write_reg(R_VERT_RAM_ADDR_POS, (ymax << 8) | ymin); | ||
362 | lcd_write_reg(R_RAM_ADDR_SET, (ymax << 8) | xmin); | ||
363 | } | ||
364 | } | ||
365 | |||
366 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ | ||
367 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
368 | int width, | ||
369 | int stride); | ||
370 | extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
371 | int width, | ||
372 | int stride, | ||
373 | int x_screen, /* To align dither pattern */ | ||
374 | int y_screen); | ||
375 | |||
376 | /* Performance function to blit a YUV bitmap directly to the LCD | ||
377 | * src_x, src_y, width and height should be even | ||
378 | * x, y, width and height have to be within LCD bounds | ||
379 | */ | ||
380 | void lcd_blit_yuv(unsigned char * const src[3], | ||
381 | int src_x, int src_y, int stride, | ||
382 | int x, int y, int width, int height) | ||
383 | { | ||
384 | unsigned char const * yuv_src[3]; | ||
385 | off_t z; | ||
386 | |||
387 | /* Sorry, but width and height must be >= 2 or else */ | ||
388 | width &= ~1; | ||
389 | height >>= 1; | ||
390 | |||
391 | z = stride*src_y; | ||
392 | yuv_src[0] = src[0] + z + src_x; | ||
393 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
394 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
395 | |||
396 | lcd_write_reg(R_ENTRY_MODE, | ||
397 | display_flipped ? R_ENTRY_MODE_VIDEO_FLIPPED : R_ENTRY_MODE_VIDEO_NORMAL | ||
398 | ); | ||
399 | |||
400 | if (lcd_yuv_options & LCD_YUV_DITHER) | ||
401 | { | ||
402 | do | ||
403 | { | ||
404 | lcd_window_blit(y, x, y+1, x+width-1); | ||
405 | |||
406 | lcd_write_cmd(R_WRITE_DATA_2_GRAM); | ||
407 | |||
408 | lcd_write_yuv420_lines_odither(yuv_src, width, stride, x, y); | ||
409 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
410 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
411 | yuv_src[2] += stride >> 1; | ||
412 | y += 2; | ||
413 | } | ||
414 | while (--height > 0); | ||
415 | } | ||
416 | else | ||
417 | { | ||
418 | do | ||
419 | { | ||
420 | lcd_window_blit(y, x, y+1, x+width-1); | ||
421 | |||
422 | lcd_write_cmd(R_WRITE_DATA_2_GRAM); | ||
423 | |||
424 | lcd_write_yuv420_lines(yuv_src, width, stride); | ||
425 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
426 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
427 | yuv_src[2] += stride >> 1; | ||
428 | y += 2; | ||
429 | } | ||
430 | while (--height > 0); | ||
431 | } | ||
432 | } | ||
433 | |||
434 | #endif | ||
435 | |||
436 | |||
339 | /* Update the display. | 437 | /* Update the display. |
340 | This must be called after all other LCD functions that change the display. */ | 438 | This must be called after all other LCD functions that change the display. */ |
341 | void lcd_update(void) | 439 | void lcd_update(void) |
diff --git a/firmware/target/arm/ipod/lcd-as-color-nano.S b/firmware/target/arm/ipod/lcd-as-color-nano.S new file mode 100644 index 0000000000..f6f9cc5be3 --- /dev/null +++ b/firmware/target/arm/ipod/lcd-as-color-nano.S | |||
@@ -0,0 +1,287 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id:$ | ||
9 | * | ||
10 | * Copyright (C) 2010-2011 by Andree Buschmann | ||
11 | * | ||
12 | * Generic asm helper function used by YUV blitting. | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | #include "config.h" | ||
25 | #include "cpu.h" | ||
26 | |||
27 | /**************************************************************************** | ||
28 | * #define FORCE_FIFO_WAIT | ||
29 | * | ||
30 | * This is not needed in YUV blitting when the LCD IF is fast enough. In this | ||
31 | * case YUV-to-RGB conversion per pixel needs longer than the transfer of a | ||
32 | * pixel via the LCD IF. | ||
33 | ****************************************************************************/ | ||
34 | |||
35 | #include "config.h" | ||
36 | |||
37 | /* Set FIFO wait for both iPod Color and iPod nano1G until we know for which | ||
38 | * devices we can switch this off. */ | ||
39 | #define FORCE_FIFO_WAIT | ||
40 | |||
41 | .section .icode, "ax", %progbits | ||
42 | |||
43 | /**************************************************************************** | ||
44 | * extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
45 | * const unsigned LCD_BASE, | ||
46 | * int width, | ||
47 | * int stride); | ||
48 | * | ||
49 | * Conversion from Motion JPEG and MPEG Y'PbPr to RGB is: | ||
50 | * |R| |1.164 0.000 1.596| |Y' - 16| | ||
51 | * |G| = |1.164 -0.391 -0.813| |Pb - 128| | ||
52 | * |B| |1.164 2.018 0.000| |Pr - 128| | ||
53 | * | ||
54 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
55 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
56 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
57 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
58 | * | ||
59 | * Converts two lines from YUV to RGB565 and writes to LCD at once. First loop | ||
60 | * loads Cb/Cr, calculates the chroma offset and saves them to buffer. Within | ||
61 | * the second loop these chroma offset are reloaded from buffer. Within each | ||
62 | * loop two pixels are calculated and written to LCD. | ||
63 | */ | ||
64 | .align 2 | ||
65 | .global lcd_write_yuv420_lines | ||
66 | .type lcd_write_yuv420_lines, %function | ||
67 | lcd_write_yuv420_lines: | ||
68 | /* r0 = src = yuv_src */ | ||
69 | /* r1 = dst = LCD_BASE */ | ||
70 | /* r2 = width */ | ||
71 | /* r3 = stride */ | ||
72 | stmfd sp!, { r4-r10, lr } /* save non-scratch */ | ||
73 | ldmia r0, { r9, r10, r12 } /* r9 = yuv_src[0] = Y'_p */ | ||
74 | /* r10 = yuv_src[1] = Cb_p */ | ||
75 | /* r12 = yuv_src[2] = Cr_p */ | ||
76 | add r3, r9, r3 /* r3 = &ysrc[stride] */ | ||
77 | add r4, r2, r2, asr #1 /* chroma buffer lenght = width/2 *3 */ | ||
78 | mov r4, r4, asl #2 /* use words for str/ldm possibility */ | ||
79 | add r4, r4, #19 /* plus room for 4 additional words, */ | ||
80 | bic r4, r4, #3 /* rounded up to multiples of 4 byte */ | ||
81 | sub sp, sp, r4 /* and allocate on stack */ | ||
82 | stmia sp, {r1-r4} /* LCD_BASE, width, &ysrc[stride], stack_alloc */ | ||
83 | |||
84 | mov r7, r2 /* r7 = loop count */ | ||
85 | add r8, sp, #16 /* chroma buffer */ | ||
86 | add lr, r1, #0x100 /* LCD data port = LCD2_BASE + 0x100 */ | ||
87 | |||
88 | /* 1st loop start */ | ||
89 | 10: /* loop start */ | ||
90 | |||
91 | ldrb r0, [r10], #1 /* r0 = *usrc++ = *Cb_p++ */ | ||
92 | ldrb r1, [r12], #1 /* r1 = *vsrc++ = *Cr_p++ */ | ||
93 | |||
94 | sub r0, r0, #128 /* r0 = Cb-128 */ | ||
95 | sub r1, r1, #128 /* r1 = Cr-128 */ | ||
96 | |||
97 | add r2, r1, r1, asl #1 /* r2 = Cr*51 + Cb*24 */ | ||
98 | add r2, r2, r2, asl #4 | ||
99 | add r2, r2, r0, asl #3 | ||
100 | add r2, r2, r0, asl #4 | ||
101 | |||
102 | add r4, r1, r1, asl #2 /* r1 = Cr*101 */ | ||
103 | add r4, r4, r1, asl #5 | ||
104 | add r1, r4, r1, asl #6 | ||
105 | |||
106 | add r1, r1, #256 /* r1 = rv = (r1 + 256) >> 9 */ | ||
107 | mov r1, r1, asr #9 | ||
108 | rsb r2, r2, #128 /* r2 = guv = (-r2 + 128) >> 8 */ | ||
109 | mov r2, r2, asr #8 | ||
110 | add r0, r0, #2 /* r0 = bu = (Cb*128 + 256) >> 9 */ | ||
111 | mov r0, r0, asr #2 | ||
112 | stmia r8!, {r0-r2} /* store r0, r1 and r2 to chroma buffer */ | ||
113 | |||
114 | /* 1st loop, first pixel */ | ||
115 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
116 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
117 | add r3, r5, r5, asl #2 | ||
118 | add r5, r3, r5, asl #5 | ||
119 | |||
120 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
121 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
122 | add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */ | ||
123 | |||
124 | orr r5, r6, r4 /* check if clamping is needed... */ | ||
125 | orr r5, r5, r3, asr #1 /* ...at all */ | ||
126 | cmp r5, #31 | ||
127 | bls 15f /* -> no clamp */ | ||
128 | cmp r6, #31 /* clamp r */ | ||
129 | mvnhi r6, r6, asr #31 | ||
130 | andhi r6, r6, #31 | ||
131 | cmp r3, #63 /* clamp g */ | ||
132 | mvnhi r3, r3, asr #31 | ||
133 | andhi r3, r3, #63 | ||
134 | cmp r4, #31 /* clamp b */ | ||
135 | mvnhi r4, r4, asr #31 | ||
136 | andhi r4, r4, #31 | ||
137 | 15: /* no clamp */ | ||
138 | |||
139 | /* calculate pixel_1 and save to r4 for later pixel packing */ | ||
140 | orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */ | ||
141 | orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */ | ||
142 | |||
143 | /* 1st loop, second pixel */ | ||
144 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
145 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
146 | add r3, r5, r5, asl #2 | ||
147 | add r5, r3, r5, asl #5 | ||
148 | |||
149 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
150 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
151 | add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */ | ||
152 | |||
153 | orr r0, r6, r5 /* check if clamping is needed... */ | ||
154 | orr r0, r0, r3, asr #1 /* ...at all */ | ||
155 | cmp r0, #31 | ||
156 | bls 15f /* -> no clamp */ | ||
157 | cmp r6, #31 /* clamp r */ | ||
158 | mvnhi r6, r6, asr #31 | ||
159 | andhi r6, r6, #31 | ||
160 | cmp r3, #63 /* clamp g */ | ||
161 | mvnhi r3, r3, asr #31 | ||
162 | andhi r3, r3, #63 | ||
163 | cmp r5, #31 /* clamp b */ | ||
164 | mvnhi r5, r5, asr #31 | ||
165 | andhi r5, r5, #31 | ||
166 | 15: /* no clamp */ | ||
167 | |||
168 | /* calculate pixel_2 and pack with pixel_1 before writing */ | ||
169 | orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ | ||
170 | orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */ | ||
171 | #ifdef FORCE_FIFO_WAIT | ||
172 | /* wait for FIFO half full */ | ||
173 | .fifo_wait1: | ||
174 | ldr r3, [lr, #-0xE0] /* while !(LCD2_BLOCK_CTRL & 0x1000000); */ | ||
175 | tst r3, #0x1000000 | ||
176 | beq .fifo_wait1 | ||
177 | #endif | ||
178 | |||
179 | mov r3, r4, lsl #8 /* swap pixel_1 */ | ||
180 | and r3, r3, #0xff00 | ||
181 | add r4, r3, r4, lsr #8 | ||
182 | |||
183 | orr r4, r4, r5, lsl #24 /* swap pixel_2 and pack with pixel_1 */ | ||
184 | mov r5, r5, lsr #8 | ||
185 | orr r4, r4, r5, lsl #16 | ||
186 | |||
187 | str r4, [lr] /* write pixel_1 and pixel_2 */ | ||
188 | |||
189 | subs r7, r7, #2 /* check for loop end */ | ||
190 | bgt 10b /* back to beginning */ | ||
191 | /* 1st loop end */ | ||
192 | |||
193 | /* Reload several registers for pointer rewinding for next loop */ | ||
194 | add r8, sp, #16 /* chroma buffer */ | ||
195 | ldmia sp, { r1, r7, r9} /* r1 = LCD_BASE */ | ||
196 | /* r7 = loop count */ | ||
197 | /* r9 = &ysrc[stride] */ | ||
198 | |||
199 | /* 2nd loop start */ | ||
200 | 20: /* loop start */ | ||
201 | /* restore r0 (bu), r1 (rv) and r2 (guv) from chroma buffer */ | ||
202 | ldmia r8!, {r0-r2} | ||
203 | |||
204 | /* 2nd loop, first pixel */ | ||
205 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
206 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
207 | add r3, r5, r5, asl #2 | ||
208 | add r5, r3, r5, asl #5 | ||
209 | |||
210 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
211 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
212 | add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */ | ||
213 | |||
214 | orr r5, r6, r4 /* check if clamping is needed... */ | ||
215 | orr r5, r5, r3, asr #1 /* ...at all */ | ||
216 | cmp r5, #31 | ||
217 | bls 15f /* -> no clamp */ | ||
218 | cmp r6, #31 /* clamp r */ | ||
219 | mvnhi r6, r6, asr #31 | ||
220 | andhi r6, r6, #31 | ||
221 | cmp r3, #63 /* clamp g */ | ||
222 | mvnhi r3, r3, asr #31 | ||
223 | andhi r3, r3, #63 | ||
224 | cmp r4, #31 /* clamp b */ | ||
225 | mvnhi r4, r4, asr #31 | ||
226 | andhi r4, r4, #31 | ||
227 | 15: /* no clamp */ | ||
228 | /* calculate pixel_1 and save to r4 for later pixel packing */ | ||
229 | orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */ | ||
230 | orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */ | ||
231 | |||
232 | /* 2nd loop, second pixel */ | ||
233 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
234 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
235 | add r3, r5, r5, asl #2 | ||
236 | add r5, r3, r5, asl #5 | ||
237 | |||
238 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
239 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
240 | add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */ | ||
241 | |||
242 | orr r0, r6, r5 /* check if clamping is needed... */ | ||
243 | orr r0, r0, r3, asr #1 /* ...at all */ | ||
244 | cmp r0, #31 | ||
245 | bls 15f /* -> no clamp */ | ||
246 | cmp r6, #31 /* clamp r */ | ||
247 | mvnhi r6, r6, asr #31 | ||
248 | andhi r6, r6, #31 | ||
249 | cmp r3, #63 /* clamp g */ | ||
250 | mvnhi r3, r3, asr #31 | ||
251 | andhi r3, r3, #63 | ||
252 | cmp r5, #31 /* clamp b */ | ||
253 | mvnhi r5, r5, asr #31 | ||
254 | andhi r5, r5, #31 | ||
255 | 15: /* no clamp */ | ||
256 | |||
257 | /* calculate pixel_2 and pack with pixel_1 before writing */ | ||
258 | orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ | ||
259 | orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */ | ||
260 | #ifdef FORCE_FIFO_WAIT | ||
261 | /* wait for FIFO half full */ | ||
262 | .fifo_wait2: | ||
263 | ldr r3, [lr, #-0xE0] /* while !(LCD2_BLOCK_CTRL & 0x1000000); */ | ||
264 | tst r3, #0x1000000 | ||
265 | beq .fifo_wait2 | ||
266 | #endif | ||
267 | |||
268 | mov r3, r4, lsl #8 /* swap pixel_1 */ | ||
269 | and r3, r3, #0xff00 | ||
270 | add r4, r3, r4, lsr #8 | ||
271 | |||
272 | orr r4, r4, r5, lsl #24 /* swap pixel_2 and pack with pixel_1 */ | ||
273 | mov r5, r5, lsr #8 | ||
274 | orr r4, r4, r5, lsl #16 | ||
275 | |||
276 | str r4, [lr] /* write pixel_1 and pixel_2 */ | ||
277 | |||
278 | subs r7, r7, #2 /* check for loop end */ | ||
279 | bgt 20b /* back to beginning */ | ||
280 | /* 2nd loop end */ | ||
281 | |||
282 | ldr r3, [sp, #12] | ||
283 | add sp, sp, r3 /* deallocate buffer */ | ||
284 | ldmpc regs=r4-r10 /* restore registers */ | ||
285 | |||
286 | .ltorg | ||
287 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
diff --git a/firmware/target/arm/ipod/lcd-color_nano.c b/firmware/target/arm/ipod/lcd-color_nano.c index 71ae22cb23..67d26aa862 100644 --- a/firmware/target/arm/ipod/lcd-color_nano.c +++ b/firmware/target/arm/ipod/lcd-color_nano.c | |||
@@ -202,6 +202,62 @@ static void lcd_setup_drawing_region(int x, int y, int width, int height) | |||
202 | } | 202 | } |
203 | } | 203 | } |
204 | 204 | ||
205 | /* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */ | ||
206 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
207 | const unsigned int lcd_baseadress, | ||
208 | int width, | ||
209 | int stride); | ||
210 | |||
211 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
212 | void lcd_blit_yuv(unsigned char * const src[3], | ||
213 | int src_x, int src_y, int stride, | ||
214 | int x, int y, int width, int height) | ||
215 | { | ||
216 | int z; | ||
217 | unsigned char const * yuv_src[3]; | ||
218 | |||
219 | width = (width + 1) & ~1; /* ensure width is even */ | ||
220 | height = (height + 1) & ~1; /* ensure height is even */ | ||
221 | |||
222 | lcd_setup_drawing_region(x, y, width, height); | ||
223 | |||
224 | z = stride * src_y; | ||
225 | yuv_src[0] = src[0] + z + src_x; | ||
226 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
227 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
228 | |||
229 | while (height > 0) { | ||
230 | int r, h, pixels_to_write; | ||
231 | |||
232 | pixels_to_write = (width * height) * 2; | ||
233 | h = height; | ||
234 | |||
235 | /* calculate how much we can do in one go */ | ||
236 | if (pixels_to_write > 0x10000) { | ||
237 | h = ((0x10000/2) / width) & ~1; /* ensure h is even */ | ||
238 | pixels_to_write = (width * h) * 2; | ||
239 | } | ||
240 | |||
241 | LCD2_BLOCK_CTRL = 0x10000080; | ||
242 | LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1); | ||
243 | LCD2_BLOCK_CTRL = 0x34000000; | ||
244 | |||
245 | r = h>>1; /* lcd_write_yuv420_lines writes two lines at once */ | ||
246 | do { | ||
247 | lcd_write_yuv420_lines(yuv_src, LCD2_BASE, width, stride); | ||
248 | yuv_src[0] += stride << 1; | ||
249 | yuv_src[1] += stride >> 1; | ||
250 | yuv_src[2] += stride >> 1; | ||
251 | } while (--r > 0); | ||
252 | |||
253 | /* transfer of pixels_to_write bytes finished */ | ||
254 | while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY)); | ||
255 | LCD2_BLOCK_CONFIG = 0; | ||
256 | |||
257 | height -= h; | ||
258 | } | ||
259 | } | ||
260 | |||
205 | /* Helper function writes 'count' consecutive pixels from src to LCD IF */ | 261 | /* Helper function writes 'count' consecutive pixels from src to LCD IF */ |
206 | static void lcd_write_line(int count, unsigned long *src) | 262 | static void lcd_write_line(int count, unsigned long *src) |
207 | { | 263 | { |
diff --git a/firmware/target/arm/ipod/video/lcd-as-video.S b/firmware/target/arm/ipod/video/lcd-as-video.S index 1b982c75ce..47155b8c75 100644 --- a/firmware/target/arm/ipod/video/lcd-as-video.S +++ b/firmware/target/arm/ipod/video/lcd-as-video.S | |||
@@ -63,3 +63,240 @@ lcd_write_data: /* r1 = pixel count, must be even */ | |||
63 | strne r3, [lr] | 63 | strne r3, [lr] |
64 | 64 | ||
65 | ldmpc regs=r4 | 65 | ldmpc regs=r4 |
66 | |||
67 | /**************************************************************************** | ||
68 | * extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
69 | * unsigned bcmaddr | ||
70 | * int width, | ||
71 | * int stride); | ||
72 | * | ||
73 | * Conversion from Motion JPEG and MPEG Y'PbPr to RGB is: | ||
74 | * |R| |1.164 0.000 1.596| |Y' - 16| | ||
75 | * |G| = |1.164 -0.391 -0.813| |Pb - 128| | ||
76 | * |B| |1.164 2.018 0.000| |Pr - 128| | ||
77 | * | ||
78 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
79 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
80 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
81 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
82 | * | ||
83 | * Converts two lines from YUV to RGB565 and writes to BCM at once. First loop | ||
84 | * loads Cb/Cr, calculates the chroma offset and saves them to buffer. Within | ||
85 | * the second loop these chroma offset are reloaded from buffer. | ||
86 | * Within each loop two pixels are calculated and written to BCM. Before each | ||
87 | * loop the desired destination address is transmitted to BCM. | ||
88 | */ | ||
89 | .align 2 | ||
90 | .global lcd_write_yuv420_lines | ||
91 | .type lcd_write_yuv420_lines, %function | ||
92 | lcd_write_yuv420_lines: | ||
93 | /* r0 = src = yuv_src */ | ||
94 | /* r1 = dst = bcmaddr */ | ||
95 | /* r2 = width */ | ||
96 | /* r3 = stride */ | ||
97 | stmfd sp!, { r4-r10, lr } /* save non-scratch */ | ||
98 | ldmia r0, { r9, r10, r12 } /* r9 = yuv_src[0] = Y'_p */ | ||
99 | /* r10 = yuv_src[1] = Cb_p */ | ||
100 | /* r12 = yuv_src[2] = Cr_p */ | ||
101 | add r3, r9, r3 /* r3 = &ysrc[stride] */ | ||
102 | add r4, r2, r2, asr #1 /* chroma buffer lenght = width/2 *3 */ | ||
103 | mov r4, r4, asl #2 /* use words for str/ldm possibility */ | ||
104 | add r4, r4, #19 /* plus room for 4 additional words, */ | ||
105 | bic r4, r4, #3 /* rounded up to multiples of 4 byte */ | ||
106 | sub sp, sp, r4 /* and allocate on stack */ | ||
107 | stmia sp, {r1-r4} /* bcmaddr, width, &ysrc[stride], stack_alloc */ | ||
108 | |||
109 | mov r7, r2 /* r7 = loop count */ | ||
110 | add r8, sp, #16 /* chroma buffer */ | ||
111 | mov lr, #0x30000000 /* LCD data port */ | ||
112 | |||
113 | /* The following writes dest address to BCM and waits for write ready */ | ||
114 | orr r2, lr, #0x00010000 /* r2 = BCM_WR_ADDR32 */ | ||
115 | orr r6, lr, #0x00030000 /* r6 = BCM_CONTROL */ | ||
116 | str r1, [r2] /* BCM_WR_ADDR32 = bcmaddr */ | ||
117 | .busy_1: | ||
118 | ldrh r1, [r6] /* while (!(BCM_CONTROL & 0x2)) */ | ||
119 | tst r1, #0x2 | ||
120 | beq .busy_1 | ||
121 | |||
122 | /* 1st loop start */ | ||
123 | 10: /* loop start */ | ||
124 | |||
125 | ldrb r0, [r10], #1 /* r0 = *usrc++ = *Cb_p++ */ | ||
126 | ldrb r1, [r12], #1 /* r1 = *vsrc++ = *Cr_p++ */ | ||
127 | |||
128 | sub r0, r0, #128 /* r0 = Cb-128 */ | ||
129 | sub r1, r1, #128 /* r1 = Cr-128 */ | ||
130 | |||
131 | add r2, r1, r1, asl #1 /* r2 = Cr*51 + Cb*24 */ | ||
132 | add r2, r2, r2, asl #4 | ||
133 | add r2, r2, r0, asl #3 | ||
134 | add r2, r2, r0, asl #4 | ||
135 | |||
136 | add r4, r1, r1, asl #2 /* r1 = Cr*101 */ | ||
137 | add r4, r4, r1, asl #5 | ||
138 | add r1, r4, r1, asl #6 | ||
139 | |||
140 | add r1, r1, #256 /* r1 = rv = (r1 + 256) >> 9 */ | ||
141 | mov r1, r1, asr #9 | ||
142 | rsb r2, r2, #128 /* r2 = guv = (-r2 + 128) >> 8 */ | ||
143 | mov r2, r2, asr #8 | ||
144 | add r0, r0, #2 /* r0 = bu = (Cb*128 + 256) >> 9 */ | ||
145 | mov r0, r0, asr #2 | ||
146 | stmia r8!, {r0-r2} /* store r0, r1 and r2 to chroma buffer */ | ||
147 | |||
148 | /* 1st loop, first pixel */ | ||
149 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
150 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
151 | add r3, r5, r5, asl #2 | ||
152 | add r5, r3, r5, asl #5 | ||
153 | |||
154 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
155 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
156 | add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */ | ||
157 | |||
158 | orr r5, r6, r4 /* check if clamping is needed... */ | ||
159 | orr r5, r5, r3, asr #1 /* ...at all */ | ||
160 | cmp r5, #31 | ||
161 | bls 15f /* -> no clamp */ | ||
162 | cmp r6, #31 /* clamp r */ | ||
163 | mvnhi r6, r6, asr #31 | ||
164 | andhi r6, r6, #31 | ||
165 | cmp r3, #63 /* clamp g */ | ||
166 | mvnhi r3, r3, asr #31 | ||
167 | andhi r3, r3, #63 | ||
168 | cmp r4, #31 /* clamp b */ | ||
169 | mvnhi r4, r4, asr #31 | ||
170 | andhi r4, r4, #31 | ||
171 | 15: /* no clamp */ | ||
172 | |||
173 | /* calculate pixel_1 and save to r5 for later pixel packing */ | ||
174 | orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */ | ||
175 | orr r5, r4, r6, lsl #11 /* r5 = pixel_1 */ | ||
176 | |||
177 | /* 1st loop, second pixel */ | ||
178 | ldrb r4, [r9], #1 /* r4 = *ysrc++ = *Y'_p++ */ | ||
179 | sub r4, r4, #16 /* r4 = (Y'-16) * 74 */ | ||
180 | add r3, r4, r4, asl #2 | ||
181 | add r4, r3, r4, asl #5 | ||
182 | |||
183 | add r6, r1, r4, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
184 | add r3, r2, r4, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
185 | add r4, r0, r4, asr #8 /* r4 = b = (Y >> 9) + bu */ | ||
186 | |||
187 | orr r0, r6, r4 /* check if clamping is needed... */ | ||
188 | orr r0, r0, r3, asr #1 /* ...at all */ | ||
189 | cmp r0, #31 | ||
190 | bls 15f /* -> no clamp */ | ||
191 | cmp r6, #31 /* clamp r */ | ||
192 | mvnhi r6, r6, asr #31 | ||
193 | andhi r6, r6, #31 | ||
194 | cmp r3, #63 /* clamp g */ | ||
195 | mvnhi r3, r3, asr #31 | ||
196 | andhi r3, r3, #63 | ||
197 | cmp r4, #31 /* clamp b */ | ||
198 | mvnhi r4, r4, asr #31 | ||
199 | andhi r4, r4, #31 | ||
200 | 15: /* no clamp */ | ||
201 | |||
202 | /* calculate pixel_2 and pack with pixel_1 before writing */ | ||
203 | orr r4, r4, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ | ||
204 | orr r4, r4, r6, lsl #11 /* r4 = pixel_2 */ | ||
205 | orr r4, r5, r4, lsl #16 /* r4 = pixel_2<<16 | pixel_1 */ | ||
206 | str r4, [lr] /* write packed pixels */ | ||
207 | |||
208 | subs r7, r7, #2 /* check for loop end */ | ||
209 | bgt 10b /* back to beginning */ | ||
210 | /* 1st loop end */ | ||
211 | |||
212 | /* Reload several registers for pointer rewinding for next loop */ | ||
213 | add r8, sp, #16 /* chroma buffer */ | ||
214 | ldmia sp, { r1, r7, r9} /* r1 = bcmaddr */ | ||
215 | /* r7 = loop count */ | ||
216 | /* r9 = &ysrc[stride] */ | ||
217 | |||
218 | /* The following writes dest address to BCM and waits for write ready */ | ||
219 | orr r2, lr, #0x00010000 /* r2 = BCM_WR_ADDR32 */ | ||
220 | orr r6, lr, #0x00030000 /* r6 = BCM_CONTROL */ | ||
221 | add r1, r1, #640 /* dst += (LCD_WIDTH*2) */ | ||
222 | str r1, [r2] /* BCM_WR_ADDR32 = dst */ | ||
223 | .busy_2: | ||
224 | ldrh r1, [r6] /* while (!(BCM_CONTROL & 0x2)) */ | ||
225 | tst r1, #0x2 | ||
226 | beq .busy_2 | ||
227 | |||
228 | |||
229 | /* 2nd loop start */ | ||
230 | 20: /* loop start */ | ||
231 | /* restore r0 (bu), r1 (rv) and r2 (guv) from chroma buffer */ | ||
232 | ldmia r8!, {r0-r2} | ||
233 | |||
234 | /* 2nd loop, first pixel */ | ||
235 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
236 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
237 | add r3, r5, r5, asl #2 | ||
238 | add r5, r3, r5, asl #5 | ||
239 | |||
240 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
241 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
242 | add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */ | ||
243 | |||
244 | orr r5, r6, r4 /* check if clamping is needed... */ | ||
245 | orr r5, r5, r3, asr #1 /* ...at all */ | ||
246 | cmp r5, #31 | ||
247 | bls 15f /* -> no clamp */ | ||
248 | cmp r6, #31 /* clamp r */ | ||
249 | mvnhi r6, r6, asr #31 | ||
250 | andhi r6, r6, #31 | ||
251 | cmp r3, #63 /* clamp g */ | ||
252 | mvnhi r3, r3, asr #31 | ||
253 | andhi r3, r3, #63 | ||
254 | cmp r4, #31 /* clamp b */ | ||
255 | mvnhi r4, r4, asr #31 | ||
256 | andhi r4, r4, #31 | ||
257 | 15: /* no clamp */ | ||
258 | /* calculate pixel_1 and save to r5 for later pixel packing */ | ||
259 | orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */ | ||
260 | orr r5, r4, r6, lsl #11 /* r5 = pixel_1 */ | ||
261 | |||
262 | /* 2nd loop, second pixel */ | ||
263 | ldrb r4, [r9], #1 /* r4 = *ysrc++ = *Y'_p++ */ | ||
264 | sub r4, r4, #16 /* r4 = (Y'-16) * 74 */ | ||
265 | add r3, r4, r4, asl #2 | ||
266 | add r4, r3, r4, asl #5 | ||
267 | |||
268 | add r6, r1, r4, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
269 | add r3, r2, r4, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
270 | add r4, r0, r4, asr #8 /* r4 = b = (Y >> 9) + bu */ | ||
271 | |||
272 | orr r0, r6, r4 /* check if clamping is needed... */ | ||
273 | orr r0, r0, r3, asr #1 /* ...at all */ | ||
274 | cmp r0, #31 | ||
275 | bls 15f /* -> no clamp */ | ||
276 | cmp r6, #31 /* clamp r */ | ||
277 | mvnhi r6, r6, asr #31 | ||
278 | andhi r6, r6, #31 | ||
279 | cmp r3, #63 /* clamp g */ | ||
280 | mvnhi r3, r3, asr #31 | ||
281 | andhi r3, r3, #63 | ||
282 | cmp r4, #31 /* clamp b */ | ||
283 | mvnhi r4, r4, asr #31 | ||
284 | andhi r4, r4, #31 | ||
285 | 15: /* no clamp */ | ||
286 | |||
287 | /* calculate pixel_2 and pack with pixel_1 before writing */ | ||
288 | orr r4, r4, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ | ||
289 | orr r4, r4, r6, lsl #11 /* r4 = pixel_2 */ | ||
290 | orr r4, r5, r4, lsl #16 /* r4 = pixel_2<<16 | pixel_1 */ | ||
291 | str r4, [lr] /* write packed pixels */ | ||
292 | |||
293 | subs r7, r7, #2 /* check for loop end */ | ||
294 | bgt 20b /* back to beginning */ | ||
295 | /* 2nd loop end */ | ||
296 | |||
297 | ldr r3, [sp, #12] | ||
298 | add sp, sp, r3 /* deallocate buffer */ | ||
299 | ldmpc regs=r4-r10 /* restore registers */ | ||
300 | |||
301 | .ltorg | ||
302 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
diff --git a/firmware/target/arm/ipod/video/lcd-video.c b/firmware/target/arm/ipod/video/lcd-video.c index 494bec8429..27d889aafa 100644 --- a/firmware/target/arm/ipod/video/lcd-video.c +++ b/firmware/target/arm/ipod/video/lcd-video.c | |||
@@ -439,6 +439,53 @@ void lcd_update(void) | |||
439 | lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); | 439 | lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); |
440 | } | 440 | } |
441 | 441 | ||
442 | /* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */ | ||
443 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
444 | unsigned bcmaddr, | ||
445 | int width, | ||
446 | int stride); | ||
447 | |||
448 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
449 | void lcd_blit_yuv(unsigned char * const src[3], | ||
450 | int src_x, int src_y, int stride, | ||
451 | int x, int y, int width, int height) | ||
452 | { | ||
453 | unsigned bcmaddr; | ||
454 | off_t z; | ||
455 | unsigned char const * yuv_src[3]; | ||
456 | |||
457 | #ifdef HAVE_LCD_SLEEP | ||
458 | if (!lcd_state.display_on) | ||
459 | return; | ||
460 | #endif | ||
461 | |||
462 | /* Sorry, but width and height must be >= 2 or else */ | ||
463 | width &= ~1; | ||
464 | |||
465 | z = stride * src_y; | ||
466 | yuv_src[0] = src[0] + z + src_x; | ||
467 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
468 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
469 | |||
470 | /* Prevent the tick from triggering BCM updates while we're writing. */ | ||
471 | lcd_block_tick(); | ||
472 | |||
473 | bcmaddr = BCMA_CMDPARAM + (LCD_WIDTH*2) * y + (x << 1); | ||
474 | height >>= 1; | ||
475 | |||
476 | do | ||
477 | { | ||
478 | lcd_write_yuv420_lines(yuv_src, bcmaddr, width, stride); | ||
479 | bcmaddr += (LCD_WIDTH*4); /* Skip up two lines */ | ||
480 | yuv_src[0] += stride << 1; | ||
481 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
482 | yuv_src[2] += stride >> 1; | ||
483 | } | ||
484 | while (--height > 0); | ||
485 | |||
486 | lcd_unblock_and_update(); | ||
487 | } | ||
488 | |||
442 | #ifdef HAVE_LCD_SLEEP | 489 | #ifdef HAVE_LCD_SLEEP |
443 | /* Executes a BCM command immediately and waits for it to complete. | 490 | /* Executes a BCM command immediately and waits for it to complete. |
444 | Other BCM commands (eg. LCD updates or lcd_tick) must not interfere. | 491 | Other BCM commands (eg. LCD updates or lcd_tick) must not interfere. |
diff --git a/firmware/target/arm/iriver/h10/lcd-as-h10.S b/firmware/target/arm/iriver/h10/lcd-as-h10.S new file mode 100644 index 0000000000..8ac8b4289f --- /dev/null +++ b/firmware/target/arm/iriver/h10/lcd-as-h10.S | |||
@@ -0,0 +1,538 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007-2008 by Michael Sevakis | ||
11 | * | ||
12 | * H10 20GB LCD assembly routines | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | #include "config.h" | ||
25 | #include "cpu.h" | ||
26 | |||
27 | /**************************************************************************** | ||
28 | * void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
29 | * int width, | ||
30 | * int stride); | ||
31 | * | ||
32 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
33 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
34 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
35 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
36 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
37 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
38 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
39 | * | ||
40 | * Write four RGB565 pixels in the following order on each loop: | ||
41 | * 1 3 + > down | ||
42 | * 2 4 \/ left | ||
43 | */ | ||
44 | .section .icode, "ax", %progbits | ||
45 | .align 2 | ||
46 | .global lcd_write_yuv420_lines | ||
47 | .type lcd_write_yuv420_lines, %function | ||
48 | lcd_write_yuv420_lines: | ||
49 | @ r0 = yuv_src | ||
50 | @ r1 = width | ||
51 | @ r2 = stride | ||
52 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
53 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
54 | @ r5 = yuv_src[1] = Cb_p | ||
55 | @ r6 = yuv_src[2] = Cr_p | ||
56 | @ | ||
57 | mov r0, #0x7000000c @ r0 = &LCD2_PORT = 0x70008a0c | ||
58 | add r0, r0, #0x8a00 @ | ||
59 | mov r14, #LCD2_DATA_MASK @ | ||
60 | @ | ||
61 | sub r2, r2, #1 @ Adjust stride because of increment | ||
62 | 10: @ loop line @ | ||
63 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
64 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
65 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
66 | @ | ||
67 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 | ||
68 | add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right | ||
69 | add r7, r12, r7, asl #5 @ by one less when adding - same for all | ||
70 | @ | ||
71 | sub r8, r8, #128 @ Cb -= 128 | ||
72 | sub r9, r9, #128 @ Cr -= 128 | ||
73 | @ | ||
74 | add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 | ||
75 | add r10, r10, r10, asl #4 @ | ||
76 | add r10, r10, r8, asl #3 @ | ||
77 | add r10, r10, r8, asl #4 @ | ||
78 | @ | ||
79 | add r11, r9, r9, asl #2 @ r9 = Cr*101 | ||
80 | add r11, r11, r9, asl #5 @ | ||
81 | add r9, r11, r9, asl #6 @ | ||
82 | @ | ||
83 | add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 | ||
84 | mov r8, r8, asr #2 @ | ||
85 | add r9, r9, #256 @ r9 = rv = (r8 + 256) >> 9 | ||
86 | mov r9, r9, asr #9 @ | ||
87 | rsb r10, r10, #128 @ r10 = guv = (-r9 + 128) >> 8 | ||
88 | mov r10, r10, asr #8 @ | ||
89 | @ compute R, G, and B | ||
90 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
91 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
92 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
93 | @ | ||
94 | orr r12, r3, r11 @ check if clamping is needed... | ||
95 | orr r12, r12, r7, asr #1 @ ...at all | ||
96 | cmp r12, #31 @ | ||
97 | bls 15f @ no clamp @ | ||
98 | cmp r3, #31 @ clamp b | ||
99 | mvnhi r3, r3, asr #31 @ | ||
100 | andhi r3, r3, #31 @ | ||
101 | cmp r11, #31 @ clamp r | ||
102 | mvnhi r11, r11, asr #31 @ | ||
103 | andhi r11, r11, #31 @ | ||
104 | cmp r7, #63 @ clamp g | ||
105 | mvnhi r7, r7, asr #31 @ | ||
106 | andhi r7, r7, #63 @ | ||
107 | 15: @ no clamp @ | ||
108 | @ | ||
109 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
110 | @ | ||
111 | orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11) | ||
112 | orr r3, r3, r7, lsl #5 @ r3 |= (g << 5) | ||
113 | @ | ||
114 | orr r7, r14, r3, lsr #8 @ store pixel | ||
115 | orr r11, r14, r3 @ | ||
116 | 20: @ | ||
117 | ldr r3, [r0] @ | ||
118 | tst r3, #LCD2_BUSY_MASK @ | ||
119 | bne 20b @ | ||
120 | str r7, [r0] @ | ||
121 | str r11, [r0] @ | ||
122 | @ | ||
123 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
124 | add r12, r7, r7, asl #2 @ | ||
125 | add r7, r12, r7, asl #5 @ | ||
126 | @ compute R, G, and B | ||
127 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
128 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
129 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
130 | @ | ||
131 | orr r12, r3, r11 @ check if clamping is needed... | ||
132 | orr r12, r12, r7, asr #1 @ ...at all | ||
133 | cmp r12, #31 @ | ||
134 | bls 15f @ no clamp @ | ||
135 | cmp r3, #31 @ clamp b | ||
136 | mvnhi r3, r3, asr #31 @ | ||
137 | andhi r3, r3, #31 @ | ||
138 | cmp r11, #31 @ clamp r | ||
139 | mvnhi r11, r11, asr #31 @ | ||
140 | andhi r11, r11, #31 @ | ||
141 | cmp r7, #63 @ clamp g | ||
142 | mvnhi r7, r7, asr #31 @ | ||
143 | andhi r7, r7, #63 @ | ||
144 | 15: @ no clamp @ | ||
145 | @ | ||
146 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
147 | @ | ||
148 | orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11) | ||
149 | orr r3, r3, r7, lsl #5 @ r3 |= (g << 5) | ||
150 | @ | ||
151 | orr r7, r14, r3, lsr #8 @ store pixel | ||
152 | orr r11, r14, r3 @ | ||
153 | 20: @ | ||
154 | ldr r3, [r0] @ | ||
155 | tst r3, #LCD2_BUSY_MASK @ | ||
156 | bne 20b @ | ||
157 | str r7, [r0] @ | ||
158 | str r11, [r0] @ | ||
159 | @ | ||
160 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
161 | add r12, r7, r7, asl #2 @ | ||
162 | add r7, r12, r7, asl #5 @ | ||
163 | @ compute R, G, and B | ||
164 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
165 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
166 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
167 | @ | ||
168 | orr r12, r3, r11 @ check if clamping is needed... | ||
169 | orr r12, r12, r7, asr #1 @ ...at all | ||
170 | cmp r12, #31 @ | ||
171 | bls 15f @ no clamp @ | ||
172 | cmp r3, #31 @ clamp b | ||
173 | mvnhi r3, r3, asr #31 @ | ||
174 | andhi r3, r3, #31 @ | ||
175 | cmp r11, #31 @ clamp r | ||
176 | mvnhi r11, r11, asr #31 @ | ||
177 | andhi r11, r11, #31 @ | ||
178 | cmp r7, #63 @ clamp g | ||
179 | mvnhi r7, r7, asr #31 @ | ||
180 | andhi r7, r7, #63 @ | ||
181 | 15: @ no clamp @ | ||
182 | @ | ||
183 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
184 | @ | ||
185 | orr r3, r3, r7, lsl #5 @ r3 = b | (g << 5) | ||
186 | orr r3, r3, r11, lsl #11 @ r3 |= (r << 11) | ||
187 | @ | ||
188 | orr r7, r14, r3, lsr #8 @ store pixel | ||
189 | orr r11, r14, r3 @ | ||
190 | 20: @ | ||
191 | ldr r3, [r0] @ | ||
192 | tst r3, #LCD2_BUSY_MASK @ | ||
193 | bne 20b @ | ||
194 | str r7, [r0] @ | ||
195 | str r11, [r0] @ | ||
196 | @ | ||
197 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
198 | add r12, r7, r7, asl #2 @ | ||
199 | add r7, r12, r7, asl #5 @ | ||
200 | @ compute R, G, and B | ||
201 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
202 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
203 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
204 | @ | ||
205 | orr r12, r3, r11 @ check if clamping is needed... | ||
206 | orr r12, r12, r7, asr #1 @ ...at all | ||
207 | cmp r12, #31 @ | ||
208 | bls 15f @ no clamp @ | ||
209 | cmp r3, #31 @ clamp b | ||
210 | mvnhi r3, r3, asr #31 @ | ||
211 | andhi r3, r3, #31 @ | ||
212 | cmp r11, #31 @ clamp r | ||
213 | mvnhi r11, r11, asr #31 @ | ||
214 | andhi r11, r11, #31 @ | ||
215 | cmp r7, #63 @ clamp g | ||
216 | mvnhi r7, r7, asr #31 @ | ||
217 | andhi r7, r7, #63 @ | ||
218 | 15: @ no clamp @ | ||
219 | @ | ||
220 | orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11) | ||
221 | orr r3, r3, r7, lsl #5 @ r3 |= (g << 5) | ||
222 | @ | ||
223 | orr r7, r14, r3, lsr #8 @ store pixel | ||
224 | orr r11, r14, r3 @ | ||
225 | 20: @ | ||
226 | ldr r3, [r0] @ | ||
227 | tst r3, #LCD2_BUSY_MASK @ | ||
228 | bne 20b @ | ||
229 | str r7, [r0] @ | ||
230 | str r11, [r0] @ | ||
231 | @ | ||
232 | subs r1, r1, #2 @ subtract block from width | ||
233 | bgt 10b @ loop line @ | ||
234 | @ | ||
235 | ldmpc regs=r4-r11 @ restore registers and return | ||
236 | .ltorg @ dump constant pool | ||
237 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
238 | |||
239 | |||
240 | /**************************************************************************** | ||
241 | * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
242 | * int width, | ||
243 | * int stride, | ||
244 | * int x_screen, | ||
245 | * int y_screen); | ||
246 | * | ||
247 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
248 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
249 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
250 | * Red scaled at twice g & b but at same precision to place it in correct | ||
251 | * bit position after multiply and leave instruction count lower. | ||
252 | * |R| |258 0 408| |Y' - 16| | ||
253 | * |G| = |149 -49 -104| |Cb - 128| | ||
254 | * |B| |149 258 0| |Cr - 128| | ||
255 | * | ||
256 | * Write four RGB565 pixels in the following order on each loop: | ||
257 | * 1 3 + > down | ||
258 | * 2 4 \/ left | ||
259 | * | ||
260 | * Kernel pattern (raw|use order): | ||
261 | * 5 3 4 2 row0 row2 > down | ||
262 | * 1 7 0 6 | 5 1 3 7 4 0 2 6 col0 left | ||
263 | * 4 2 5 3 | 4 0 2 6 5 1 3 7 col2 \/ | ||
264 | * 0 6 1 7 | ||
265 | */ | ||
266 | .section .icode, "ax", %progbits | ||
267 | .align 2 | ||
268 | .global lcd_write_yuv420_lines_odither | ||
269 | .type lcd_write_yuv420_lines_odither, %function | ||
270 | lcd_write_yuv420_lines_odither: | ||
271 | @ r0 = yuv_src | ||
272 | @ r1 = width | ||
273 | @ r2 = stride | ||
274 | @ r3 = x_screen | ||
275 | @ [sp] = y_screen | ||
276 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
277 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
278 | @ r5 = yuv_src[1] = Cb_p | ||
279 | @ r6 = yuv_src[2] = Cr_p | ||
280 | @ | ||
281 | ldr r0, [sp, #36] @ Line up pattern and kernel quadrant | ||
282 | eor r14, r3, r0 @ | ||
283 | and r14, r14, #0x2 @ | ||
284 | mov r14, r14, lsl #6 @ 0x00 or 0x80 | ||
285 | @ | ||
286 | mov r0, #0x7000000c @ r0 = &LCD2_PORT = 0x70008a0c | ||
287 | add r0, r0, #0x8a00 @ | ||
288 | @ | ||
289 | sub r2, r2, #1 @ Adjust stride because of increment | ||
290 | 10: @ loop line @ | ||
291 | @ | ||
292 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
293 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
294 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
295 | @ | ||
296 | eor r14, r14, #0x80 @ flip pattern quadrant | ||
297 | @ | ||
298 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149 | ||
299 | add r12, r7, r7, asl #2 @ | ||
300 | add r12, r12, r12, asl #4 @ | ||
301 | add r7, r12, r7, asl #6 @ | ||
302 | @ | ||
303 | sub r8, r8, #128 @ Cb -= 128 | ||
304 | sub r9, r9, #128 @ Cr -= 128 | ||
305 | @ | ||
306 | add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49 | ||
307 | add r10, r10, r8, asl #5 @ | ||
308 | add r10, r10, r9, asl #3 @ | ||
309 | add r10, r10, r9, asl #5 @ | ||
310 | add r10, r10, r9, asl #6 @ | ||
311 | @ | ||
312 | mov r8, r8, asl #1 @ r8 = bu = Cb*258 | ||
313 | add r8, r8, r8, asl #7 @ | ||
314 | @ | ||
315 | add r9, r9, r9, asl #1 @ r9 = rv = Cr*408 | ||
316 | add r9, r9, r9, asl #4 @ | ||
317 | mov r9, r9, asl #3 @ | ||
318 | @ | ||
319 | @ compute R, G, and B | ||
320 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
321 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
322 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
323 | @ | ||
324 | @ r8 = bu, r9 = rv, r10 = guv | ||
325 | @ | ||
326 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256 | ||
327 | add r3, r12, r3, lsr #8 @ | ||
328 | @ | ||
329 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
330 | add r11, r12, r11, lsr #8 @ | ||
331 | @ | ||
332 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
333 | add r7, r12, r7, lsr #8 @ | ||
334 | @ | ||
335 | add r12, r14, #0x200 @ | ||
336 | @ | ||
337 | add r3, r3, r12 @ b = r3 + delta | ||
338 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
339 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
340 | @ | ||
341 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
342 | orr r12, r12, r7 @ ...at all | ||
343 | movs r12, r12, asr #15 @ | ||
344 | beq 15f @ no clamp @ | ||
345 | movs r12, r3, asr #15 @ clamp b | ||
346 | mvnne r3, r12, lsr #15 @ | ||
347 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
348 | movs r12, r11, asr #16 @ clamp r | ||
349 | mvnne r11, r12, lsr #16 @ | ||
350 | movs r12, r7, asr #15 @ clamp g | ||
351 | mvnne r7, r12, lsr #15 @ | ||
352 | 15: @ no clamp @ | ||
353 | @ | ||
354 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
355 | @ | ||
356 | and r11, r11, #0xf800 @ pack pixel | ||
357 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
358 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
359 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
360 | @ | ||
361 | mov r11, #LCD2_DATA_MASK @ store pixel | ||
362 | orr r7, r11, r3, lsr #8 @ | ||
363 | orr r11, r11, r3 @ | ||
364 | 20: @ | ||
365 | ldr r3, [r0] @ | ||
366 | tst r3, #LCD2_BUSY_MASK @ | ||
367 | bne 20b @ | ||
368 | str r7, [r0] @ | ||
369 | str r11, [r0] @ | ||
370 | @ | ||
371 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
372 | add r12, r7, r7, asl #2 @ | ||
373 | add r12, r12, r12, asl #4 @ | ||
374 | add r7, r12, r7, asl #6 @ | ||
375 | @ compute R, G, and B | ||
376 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
377 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
378 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
379 | @ | ||
380 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256 | ||
381 | add r3, r12, r3, lsr #8 @ | ||
382 | @ | ||
383 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
384 | add r11, r12, r11, lsr #8 @ | ||
385 | @ | ||
386 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
387 | add r7, r12, r7, lsr #8 @ | ||
388 | @ | ||
389 | @ This element is zero - use r14 @ | ||
390 | @ | ||
391 | add r3, r3, r14 @ b = r3 + delta | ||
392 | add r11, r11, r14, lsl #1 @ r = r11 + delta*2 | ||
393 | add r7, r7, r14, lsr #1 @ g = r7 + delta/2 | ||
394 | @ | ||
395 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
396 | orr r12, r12, r7 @ ...at all | ||
397 | movs r12, r12, asr #15 @ | ||
398 | beq 15f @ no clamp @ | ||
399 | movs r12, r3, asr #15 @ clamp b | ||
400 | mvnne r3, r12, lsr #15 @ | ||
401 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
402 | movs r12, r11, asr #16 @ clamp r | ||
403 | mvnne r11, r12, lsr #16 @ | ||
404 | movs r12, r7, asr #15 @ clamp g | ||
405 | mvnne r7, r12, lsr #15 @ | ||
406 | 15: @ no clamp @ | ||
407 | @ | ||
408 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
409 | @ | ||
410 | and r11, r11, #0xf800 @ pack pixel | ||
411 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
412 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
413 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
414 | @ | ||
415 | mov r11, #LCD2_DATA_MASK @ store pixel | ||
416 | orr r7, r11, r3, lsr #8 @ | ||
417 | orr r11, r11, r3 @ | ||
418 | 20: @ | ||
419 | ldr r3, [r0] @ | ||
420 | tst r3, #LCD2_BUSY_MASK @ | ||
421 | bne 20b @ | ||
422 | str r7, [r0] @ | ||
423 | str r11, [r0] @ | ||
424 | @ | ||
425 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
426 | add r12, r7, r7, asl #2 @ | ||
427 | add r12, r12, r12, asl #4 @ | ||
428 | add r7, r12, r7, asl #6 @ | ||
429 | @ compute R, G, and B | ||
430 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
431 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
432 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
433 | @ | ||
434 | @ r8 = bu, r9 = rv, r10 = guv | ||
435 | @ | ||
436 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256 | ||
437 | add r3, r12, r3, lsr #8 @ | ||
438 | @ | ||
439 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
440 | add r11, r12, r11, lsr #8 @ | ||
441 | @ | ||
442 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
443 | add r7, r12, r7, lsr #8 @ | ||
444 | @ | ||
445 | add r12, r14, #0x100 @ | ||
446 | @ | ||
447 | add r3, r3, r12 @ b = r3 + delta | ||
448 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
449 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
450 | @ | ||
451 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
452 | orr r12, r12, r7 @ ...at all | ||
453 | movs r12, r12, asr #15 @ | ||
454 | beq 15f @ no clamp @ | ||
455 | movs r12, r3, asr #15 @ clamp b | ||
456 | mvnne r3, r12, lsr #15 @ | ||
457 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
458 | movs r12, r11, asr #16 @ clamp r | ||
459 | mvnne r11, r12, lsr #16 @ | ||
460 | movs r12, r7, asr #15 @ clamp g | ||
461 | mvnne r7, r12, lsr #15 @ | ||
462 | 15: @ no clamp @ | ||
463 | @ | ||
464 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
465 | @ | ||
466 | and r11, r11, #0xf800 @ pack pixel | ||
467 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
468 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
469 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
470 | @ | ||
471 | mov r11, #LCD2_DATA_MASK @ store pixel | ||
472 | orr r7, r11, r3, lsr #8 @ | ||
473 | orr r11, r11, r3 @ | ||
474 | 20: @ | ||
475 | ldr r3, [r0] @ | ||
476 | tst r3, #LCD2_BUSY_MASK @ | ||
477 | bne 20b @ | ||
478 | str r7, [r0] @ | ||
479 | str r11, [r0] @ | ||
480 | @ | ||
481 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
482 | add r12, r7, r7, asl #2 @ | ||
483 | add r12, r12, r12, asl #4 @ | ||
484 | add r7, r12, r7, asl #6 @ | ||
485 | @ compute R, G, and B | ||
486 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
487 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
488 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
489 | @ | ||
490 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256 | ||
491 | add r3, r12, r3, lsr #8 @ | ||
492 | @ | ||
493 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
494 | add r11, r12, r11, lsr #8 @ | ||
495 | @ | ||
496 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
497 | add r7, r12, r7, lsr #8 @ | ||
498 | @ | ||
499 | add r12, r14, #0x300 @ | ||
500 | @ | ||
501 | add r3, r3, r12 @ b = r3 + delta | ||
502 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
503 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
504 | @ | ||
505 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
506 | orr r12, r12, r7 @ ...at all | ||
507 | movs r12, r12, asr #15 @ | ||
508 | beq 15f @ no clamp @ | ||
509 | movs r12, r3, asr #15 @ clamp b | ||
510 | mvnne r3, r12, lsr #15 @ | ||
511 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
512 | movs r12, r11, asr #16 @ clamp r | ||
513 | mvnne r11, r12, lsr #16 @ | ||
514 | movs r12, r7, asr #15 @ clamp g | ||
515 | mvnne r7, r12, lsr #15 @ | ||
516 | 15: @ no clamp @ | ||
517 | @ | ||
518 | and r11, r11, #0xf800 @ pack pixel | ||
519 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
520 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
521 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
522 | @ | ||
523 | mov r11, #LCD2_DATA_MASK @ store pixel | ||
524 | orr r7, r11, r3, lsr #8 @ | ||
525 | orr r11, r11, r3 @ | ||
526 | 20: @ | ||
527 | ldr r3, [r0] @ | ||
528 | tst r3, #LCD2_BUSY_MASK @ | ||
529 | bne 20b @ | ||
530 | str r7, [r0] @ | ||
531 | str r11, [r0] @ | ||
532 | @ | ||
533 | subs r1, r1, #2 @ subtract block from width | ||
534 | bgt 10b @ loop line @ | ||
535 | @ | ||
536 | ldmpc regs=r4-r11 @ restore registers and return | ||
537 | .ltorg @ dump constant pool | ||
538 | .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither | ||
diff --git a/firmware/target/arm/iriver/h10/lcd-h10_20gb.c b/firmware/target/arm/iriver/h10/lcd-h10_20gb.c index 403c1c19e0..c7e339295d 100644 --- a/firmware/target/arm/iriver/h10/lcd-h10_20gb.c +++ b/firmware/target/arm/iriver/h10/lcd-h10_20gb.c | |||
@@ -36,6 +36,8 @@ static unsigned short disp_control_rev; | |||
36 | /* Contrast setting << 8 */ | 36 | /* Contrast setting << 8 */ |
37 | static int lcd_contrast; | 37 | static int lcd_contrast; |
38 | 38 | ||
39 | static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0; | ||
40 | |||
39 | /* Forward declarations */ | 41 | /* Forward declarations */ |
40 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | 42 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) |
41 | static void lcd_display_off(void); | 43 | static void lcd_display_off(void); |
@@ -396,6 +398,94 @@ bool lcd_active(void) | |||
396 | 398 | ||
397 | /*** update functions ***/ | 399 | /*** update functions ***/ |
398 | 400 | ||
401 | void lcd_yuv_set_options(unsigned options) | ||
402 | { | ||
403 | lcd_yuv_options = options; | ||
404 | } | ||
405 | |||
406 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ | ||
407 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
408 | int width, | ||
409 | int stride); | ||
410 | extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
411 | int width, | ||
412 | int stride, | ||
413 | int x_screen, /* To align dither pattern */ | ||
414 | int y_screen); | ||
415 | |||
416 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
417 | void lcd_blit_yuv(unsigned char * const src[3], | ||
418 | int src_x, int src_y, int stride, | ||
419 | int x, int y, int width, int height) | ||
420 | { | ||
421 | const unsigned char *yuv_src[3]; | ||
422 | const unsigned char *ysrc_max; | ||
423 | int y0; | ||
424 | int options; | ||
425 | |||
426 | if (!display_on) | ||
427 | return; | ||
428 | |||
429 | width &= ~1; | ||
430 | height &= ~1; | ||
431 | |||
432 | /* calculate the drawing region */ | ||
433 | |||
434 | /* The 20GB LCD is actually 128x160 but rotated 90 degrees so the origin | ||
435 | * is actually the bottom left and horizontal and vertical are swapped. | ||
436 | * Rockbox expects the origin to be the top left so we need to use | ||
437 | * 127 - y instead of just y */ | ||
438 | |||
439 | /* max vert << 8 | start vert */ | ||
440 | lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x); | ||
441 | |||
442 | y0 = LCD_HEIGHT - 1 - y + y_offset; | ||
443 | |||
444 | /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=0, LG2-0=000 */ | ||
445 | lcd_write_reg(R_ENTRY_MODE, 0x1020); | ||
446 | |||
447 | yuv_src[0] = src[0] + src_y * stride + src_x; | ||
448 | yuv_src[1] = src[1] + (src_y * stride >> 2) + (src_x >> 1); | ||
449 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
450 | ysrc_max = yuv_src[0] + height * stride; | ||
451 | |||
452 | options = lcd_yuv_options; | ||
453 | |||
454 | do | ||
455 | { | ||
456 | /* max horiz << 8 | start horiz */ | ||
457 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (y0 << 8) | (y0 - 1)); | ||
458 | |||
459 | /* position cursor (set AD0-AD15) */ | ||
460 | /* start vert << 8 | start horiz */ | ||
461 | lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | y0); | ||
462 | |||
463 | /* start drawing */ | ||
464 | lcd_send_cmd(R_WRITE_DATA_2_GRAM); | ||
465 | |||
466 | if (options & LCD_YUV_DITHER) | ||
467 | { | ||
468 | lcd_write_yuv420_lines_odither(yuv_src, width, stride, | ||
469 | x, y); | ||
470 | y -= 2; | ||
471 | } | ||
472 | else | ||
473 | { | ||
474 | lcd_write_yuv420_lines(yuv_src, width, stride); | ||
475 | } | ||
476 | |||
477 | y0 -= 2; | ||
478 | yuv_src[0] += stride << 1; | ||
479 | yuv_src[1] += stride >> 1; | ||
480 | yuv_src[2] += stride >> 1; | ||
481 | } | ||
482 | while (yuv_src[0] < ysrc_max); | ||
483 | |||
484 | /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=1, LG2-0=000 */ | ||
485 | lcd_write_reg(R_ENTRY_MODE, 0x1028); | ||
486 | } | ||
487 | |||
488 | |||
399 | /* Update a fraction of the display. */ | 489 | /* Update a fraction of the display. */ |
400 | void lcd_update_rect(int x0, int y0, int width, int height) | 490 | void lcd_update_rect(int x0, int y0, int width, int height) |
401 | { | 491 | { |
diff --git a/firmware/target/arm/iriver/h10/lcd-h10_5gb.c b/firmware/target/arm/iriver/h10/lcd-h10_5gb.c index 4386e1670c..5e1ad9ce23 100644 --- a/firmware/target/arm/iriver/h10/lcd-h10_5gb.c +++ b/firmware/target/arm/iriver/h10/lcd-h10_5gb.c | |||
@@ -118,6 +118,168 @@ void lcd_init_device(void) | |||
118 | 118 | ||
119 | /*** update functions ***/ | 119 | /*** update functions ***/ |
120 | 120 | ||
121 | #define CSUB_X 2 | ||
122 | #define CSUB_Y 2 | ||
123 | |||
124 | #define RYFAC (31*257) | ||
125 | #define GYFAC (31*257) | ||
126 | #define BYFAC (31*257) | ||
127 | #define RVFAC 11170 /* 31 * 257 * 1.402 */ | ||
128 | #define GVFAC (-5690) /* 31 * 257 * -0.714136 */ | ||
129 | #define GUFAC (-2742) /* 31 * 257 * -0.344136 */ | ||
130 | #define BUFAC 14118 /* 31 * 257 * 1.772 */ | ||
131 | |||
132 | #define ROUNDOFFS (127*257) | ||
133 | #define ROUNDOFFSG (63*257) | ||
134 | |||
135 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
136 | void lcd_blit_yuv(unsigned char * const src[3], | ||
137 | int src_x, int src_y, int stride, | ||
138 | int x, int y, int width, int height) | ||
139 | { | ||
140 | int y0, x0, y1, x1; | ||
141 | int ymax; | ||
142 | |||
143 | width = (width + 1) & ~1; | ||
144 | |||
145 | /* calculate the drawing region */ | ||
146 | x0 = x; | ||
147 | x1 = x + width - 1; | ||
148 | y0 = y; | ||
149 | y1 = y + height - 1; | ||
150 | |||
151 | /* max horiz << 8 | start horiz */ | ||
152 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (x1 << 8) | x0); | ||
153 | |||
154 | /* max vert << 8 | start vert */ | ||
155 | lcd_write_reg(R_VERT_RAM_ADDR_POS, (y1 << 8) | y0); | ||
156 | |||
157 | /* start vert << 8 | start horiz */ | ||
158 | lcd_write_reg(R_RAM_ADDR_SET, (y0 << 8) | x0); | ||
159 | |||
160 | /* start drawing */ | ||
161 | lcd_send_cmd(R_WRITE_DATA_2_GRAM); | ||
162 | |||
163 | ymax = y + height - 1 ; | ||
164 | |||
165 | const int stride_div_csub_x = stride/CSUB_X; | ||
166 | |||
167 | for (; y <= ymax ; y++) | ||
168 | { | ||
169 | /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ | ||
170 | const unsigned char *ysrc = src[0] + stride * src_y + src_x; | ||
171 | |||
172 | const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) + | ||
173 | (src_x/CSUB_X); | ||
174 | |||
175 | const unsigned char *usrc = src[1] + uvoffset; | ||
176 | const unsigned char *vsrc = src[2] + uvoffset; | ||
177 | const unsigned char *row_end = ysrc + width; | ||
178 | |||
179 | int y, u, v; | ||
180 | int red1, green1, blue1; | ||
181 | int red2, green2, blue2; | ||
182 | unsigned rbits, gbits, bbits; | ||
183 | |||
184 | int rc, gc, bc; | ||
185 | |||
186 | do | ||
187 | { | ||
188 | u = *usrc++ - 128; | ||
189 | v = *vsrc++ - 128; | ||
190 | rc = RVFAC * v + ROUNDOFFS; | ||
191 | gc = GVFAC * v + GUFAC * u + ROUNDOFFSG; | ||
192 | bc = BUFAC * u + ROUNDOFFS; | ||
193 | |||
194 | /* Pixel 1 */ | ||
195 | y = *ysrc++; | ||
196 | |||
197 | red1 = RYFAC * y + rc; | ||
198 | green1 = GYFAC * y + gc; | ||
199 | blue1 = BYFAC * y + bc; | ||
200 | |||
201 | /* Pixel 2 */ | ||
202 | y = *ysrc++; | ||
203 | red2 = RYFAC * y + rc; | ||
204 | green2 = GYFAC * y + gc; | ||
205 | blue2 = BYFAC * y + bc; | ||
206 | |||
207 | /* Since out of bounds errors are relatively rare, we check two | ||
208 | pixels at once to see if any components are out of bounds, and | ||
209 | then fix whichever is broken. This works due to high values and | ||
210 | negative values both becoming larger than the cutoff when | ||
211 | casted to unsigned. And ORing them together checks all of them | ||
212 | simultaneously. */ | ||
213 | if (((unsigned)(red1 | green1 | blue1 | | ||
214 | red2 | green2 | blue2)) > (RYFAC*255+ROUNDOFFS)) { | ||
215 | if (((unsigned)(red1 | green1 | blue1)) > | ||
216 | (RYFAC*255+ROUNDOFFS)) { | ||
217 | if ((unsigned)red1 > (RYFAC*255+ROUNDOFFS)) | ||
218 | { | ||
219 | if (red1 < 0) | ||
220 | red1 = 0; | ||
221 | else | ||
222 | red1 = (RYFAC*255+ROUNDOFFS); | ||
223 | } | ||
224 | if ((unsigned)green1 > (GYFAC*255+ROUNDOFFSG)) | ||
225 | { | ||
226 | if (green1 < 0) | ||
227 | green1 = 0; | ||
228 | else | ||
229 | green1 = (GYFAC*255+ROUNDOFFSG); | ||
230 | } | ||
231 | if ((unsigned)blue1 > (BYFAC*255+ROUNDOFFS)) | ||
232 | { | ||
233 | if (blue1 < 0) | ||
234 | blue1 = 0; | ||
235 | else | ||
236 | blue1 = (BYFAC*255+ROUNDOFFS); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | if (((unsigned)(red2 | green2 | blue2)) > | ||
241 | (RYFAC*255+ROUNDOFFS)) { | ||
242 | if ((unsigned)red2 > (RYFAC*255+ROUNDOFFS)) | ||
243 | { | ||
244 | if (red2 < 0) | ||
245 | red2 = 0; | ||
246 | else | ||
247 | red2 = (RYFAC*255+ROUNDOFFS); | ||
248 | } | ||
249 | if ((unsigned)green2 > (GYFAC*255+ROUNDOFFSG)) | ||
250 | { | ||
251 | if (green2 < 0) | ||
252 | green2 = 0; | ||
253 | else | ||
254 | green2 = (GYFAC*255+ROUNDOFFSG); | ||
255 | } | ||
256 | if ((unsigned)blue2 > (BYFAC*255+ROUNDOFFS)) | ||
257 | { | ||
258 | if (blue2 < 0) | ||
259 | blue2 = 0; | ||
260 | else | ||
261 | blue2 = (BYFAC*255+ROUNDOFFS); | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | |||
266 | rbits = red1 >> 16 ; | ||
267 | gbits = green1 >> 15 ; | ||
268 | bbits = blue1 >> 16 ; | ||
269 | lcd_send_data((rbits << 11) | (gbits << 5) | bbits); | ||
270 | |||
271 | rbits = red2 >> 16 ; | ||
272 | gbits = green2 >> 15 ; | ||
273 | bbits = blue2 >> 16 ; | ||
274 | lcd_send_data((rbits << 11) | (gbits << 5) | bbits); | ||
275 | } | ||
276 | while (ysrc < row_end); | ||
277 | |||
278 | src_y++; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | |||
121 | /* Update a fraction of the display. */ | 283 | /* Update a fraction of the display. */ |
122 | void lcd_update_rect(int x0, int y0, int width, int height) | 284 | void lcd_update_rect(int x0, int y0, int width, int height) |
123 | { | 285 | { |
diff --git a/firmware/target/arm/lcd-c200_c200v2.c b/firmware/target/arm/lcd-c200_c200v2.c index 665c82f292..38877ccac9 100644 --- a/firmware/target/arm/lcd-c200_c200v2.c +++ b/firmware/target/arm/lcd-c200_c200v2.c | |||
@@ -30,6 +30,9 @@ | |||
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | /* Display status */ | 32 | /* Display status */ |
33 | #if MEMORYSIZE > 2 | ||
34 | static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0; | ||
35 | #endif | ||
33 | static bool is_lcd_enabled = true; | 36 | static bool is_lcd_enabled = true; |
34 | 37 | ||
35 | /* LCD command set for Samsung S6B33B2 */ | 38 | /* LCD command set for Samsung S6B33B2 */ |
@@ -298,6 +301,80 @@ void lcd_set_flip(bool yesno) | |||
298 | 301 | ||
299 | /*** update functions ***/ | 302 | /*** update functions ***/ |
300 | 303 | ||
304 | #if MEMORYSIZE > 2 /* not for C200V2 */ | ||
305 | void lcd_yuv_set_options(unsigned options) | ||
306 | { | ||
307 | lcd_yuv_options = options; | ||
308 | } | ||
309 | |||
310 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ | ||
311 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
312 | int width, | ||
313 | int stride); | ||
314 | extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
315 | int width, | ||
316 | int stride, | ||
317 | int x_screen, /* To align dither pattern */ | ||
318 | int y_screen); | ||
319 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
320 | void lcd_blit_yuv(unsigned char * const src[3], | ||
321 | int src_x, int src_y, int stride, | ||
322 | int x, int y, int width, int height) | ||
323 | { | ||
324 | unsigned char const * yuv_src[3]; | ||
325 | off_t z; | ||
326 | |||
327 | /* Sorry, but width and height must be >= 2 or else */ | ||
328 | width &= ~1; | ||
329 | height >>= 1; | ||
330 | |||
331 | y += 0x1a; | ||
332 | |||
333 | z = stride*src_y; | ||
334 | yuv_src[0] = src[0] + z + src_x; | ||
335 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
336 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
337 | |||
338 | lcd_send_command(R_ENTRY_MODE, 0x80); | ||
339 | |||
340 | lcd_send_command(R_X_ADDR_AREA, x); | ||
341 | lcd_send_command(x + width - 1, 0); | ||
342 | |||
343 | if (lcd_yuv_options & LCD_YUV_DITHER) | ||
344 | { | ||
345 | do | ||
346 | { | ||
347 | lcd_send_command(R_Y_ADDR_AREA, y); | ||
348 | lcd_send_command(y + 1, 0); | ||
349 | |||
350 | lcd_write_yuv420_lines_odither(yuv_src, width, stride, x, y); | ||
351 | |||
352 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
353 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
354 | yuv_src[2] += stride >> 1; | ||
355 | y += 2; | ||
356 | } | ||
357 | while (--height > 0); | ||
358 | } | ||
359 | else | ||
360 | { | ||
361 | do | ||
362 | { | ||
363 | lcd_send_command(R_Y_ADDR_AREA, y); | ||
364 | lcd_send_command(y + 1, 0); | ||
365 | |||
366 | lcd_write_yuv420_lines(yuv_src, width, stride); | ||
367 | |||
368 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
369 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
370 | yuv_src[2] += stride >> 1; | ||
371 | y += 2; | ||
372 | } | ||
373 | while (--height > 0); | ||
374 | } | ||
375 | } | ||
376 | #endif /* MEMORYSIZE > 2 */ | ||
377 | |||
301 | /* Update the display. | 378 | /* Update the display. |
302 | This must be called after all other LCD functions that change the display. */ | 379 | This must be called after all other LCD functions that change the display. */ |
303 | void lcd_update(void) | 380 | void lcd_update(void) |
diff --git a/firmware/target/arm/pbell/vibe500/lcd-as-vibe500.S b/firmware/target/arm/pbell/vibe500/lcd-as-vibe500.S new file mode 100644 index 0000000000..e03011c168 --- /dev/null +++ b/firmware/target/arm/pbell/vibe500/lcd-as-vibe500.S | |||
@@ -0,0 +1,556 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id:$ | ||
9 | * | ||
10 | * Copyright (C) 2007-2008 by Michael Sevakis | ||
11 | * Adapted for the Packard Bell Vibe 500 by Szymon Dziok | ||
12 | * | ||
13 | * Packard Bell Vibe 500 LCD assembly routines | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version 2 | ||
18 | * of the License, or (at your option) any later version. | ||
19 | * | ||
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
21 | * KIND, either express or implied. | ||
22 | * | ||
23 | ****************************************************************************/ | ||
24 | |||
25 | #include "config.h" | ||
26 | #include "cpu.h" | ||
27 | |||
28 | /**************************************************************************** | ||
29 | * void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
30 | * int width, | ||
31 | * int stride); | ||
32 | * | ||
33 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
34 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
35 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
36 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
37 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
38 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
39 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
40 | * | ||
41 | * Write four RGB565 pixels in the following order on each loop: | ||
42 | * 1 3 + > down | ||
43 | * 2 4 \/ left | ||
44 | */ | ||
45 | .section .icode, "ax", %progbits | ||
46 | .align 2 | ||
47 | .global lcd_write_yuv420_lines | ||
48 | .type lcd_write_yuv420_lines, %function | ||
49 | lcd_write_yuv420_lines: | ||
50 | @ r0 = yuv_src | ||
51 | @ r1 = width | ||
52 | @ r2 = stride | ||
53 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
54 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
55 | @ r5 = yuv_src[1] = Cb_p | ||
56 | @ r6 = yuv_src[2] = Cr_p | ||
57 | @ | ||
58 | ldr r0, =LCD1_BASE @ | ||
59 | @ | ||
60 | sub r2, r2, #1 @ Adjust stride because of increment | ||
61 | 10: @ loop line @ | ||
62 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
63 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
64 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
65 | @ | ||
66 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 | ||
67 | add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right | ||
68 | add r7, r12, r7, asl #5 @ by one less when adding - same for all | ||
69 | @ | ||
70 | sub r8, r8, #128 @ Cb -= 128 | ||
71 | sub r9, r9, #128 @ Cr -= 128 | ||
72 | @ | ||
73 | add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 | ||
74 | add r10, r10, r10, asl #4 @ | ||
75 | add r10, r10, r8, asl #3 @ | ||
76 | add r10, r10, r8, asl #4 @ | ||
77 | @ | ||
78 | add r11, r9, r9, asl #2 @ r9 = Cr*101 | ||
79 | add r11, r11, r9, asl #5 @ | ||
80 | add r9, r11, r9, asl #6 @ | ||
81 | @ | ||
82 | add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 | ||
83 | mov r8, r8, asr #2 @ | ||
84 | add r9, r9, #256 @ r9 = rv = (r8 + 256) >> 9 | ||
85 | mov r9, r9, asr #9 @ | ||
86 | rsb r10, r10, #128 @ r10 = guv = (-r9 + 128) >> 8 | ||
87 | mov r10, r10, asr #8 @ | ||
88 | @ compute R, G, and B | ||
89 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
90 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
91 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
92 | @ | ||
93 | orr r12, r3, r11 @ check if clamping is needed... | ||
94 | orr r12, r12, r7, asr #1 @ ...at all | ||
95 | cmp r12, #31 @ | ||
96 | bls 15f @ no clamp @ | ||
97 | cmp r3, #31 @ clamp b | ||
98 | mvnhi r3, r3, asr #31 @ | ||
99 | andhi r3, r3, #31 @ | ||
100 | cmp r11, #31 @ clamp r | ||
101 | mvnhi r11, r11, asr #31 @ | ||
102 | andhi r11, r11, #31 @ | ||
103 | cmp r7, #63 @ clamp g | ||
104 | mvnhi r7, r7, asr #31 @ | ||
105 | andhi r7, r7, #63 @ | ||
106 | 15: @ no clamp @ | ||
107 | @ | ||
108 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
109 | @ | ||
110 | orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11) | ||
111 | orr r3, r3, r7, lsl #5 @ r3 |= (g << 5) | ||
112 | @ | ||
113 | movs r7, r3, lsr #8 @ store pixel | ||
114 | 20: @ | ||
115 | ldr r11, [r0] @ | ||
116 | tst r11, #LCD1_BUSY_MASK @ | ||
117 | bne 20b @ | ||
118 | str r7, [r0, #0x10] @ | ||
119 | 25: @ | ||
120 | ldr r11, [r0] @ | ||
121 | tst r11, #LCD1_BUSY_MASK @ | ||
122 | bne 25b @ | ||
123 | str r3, [r0, #0x10] @ | ||
124 | @ | ||
125 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
126 | add r12, r7, r7, asl #2 @ | ||
127 | add r7, r12, r7, asl #5 @ | ||
128 | @ compute R, G, and B | ||
129 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
130 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
131 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
132 | @ | ||
133 | orr r12, r3, r11 @ check if clamping is needed... | ||
134 | orr r12, r12, r7, asr #1 @ ...at all | ||
135 | cmp r12, #31 @ | ||
136 | bls 15f @ no clamp @ | ||
137 | cmp r3, #31 @ clamp b | ||
138 | mvnhi r3, r3, asr #31 @ | ||
139 | andhi r3, r3, #31 @ | ||
140 | cmp r11, #31 @ clamp r | ||
141 | mvnhi r11, r11, asr #31 @ | ||
142 | andhi r11, r11, #31 @ | ||
143 | cmp r7, #63 @ clamp g | ||
144 | mvnhi r7, r7, asr #31 @ | ||
145 | andhi r7, r7, #63 @ | ||
146 | 15: @ no clamp @ | ||
147 | @ | ||
148 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
149 | @ | ||
150 | orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11) | ||
151 | orr r3, r3, r7, lsl #5 @ r3 |= (g << 5) | ||
152 | @ | ||
153 | movs r7, r3, lsr #8 @ store pixel | ||
154 | 20: @ | ||
155 | ldr r11, [r0] @ | ||
156 | tst r11, #LCD1_BUSY_MASK @ | ||
157 | bne 20b @ | ||
158 | str r7, [r0, #0x10] @ | ||
159 | 25: @ | ||
160 | ldr r11, [r0] @ | ||
161 | tst r11, #LCD1_BUSY_MASK @ | ||
162 | bne 25b @ | ||
163 | str r3, [r0, #0x10] @ | ||
164 | @ | ||
165 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
166 | add r12, r7, r7, asl #2 @ | ||
167 | add r7, r12, r7, asl #5 @ | ||
168 | @ compute R, G, and B | ||
169 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
170 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
171 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
172 | @ | ||
173 | orr r12, r3, r11 @ check if clamping is needed... | ||
174 | orr r12, r12, r7, asr #1 @ ...at all | ||
175 | cmp r12, #31 @ | ||
176 | bls 15f @ no clamp @ | ||
177 | cmp r3, #31 @ clamp b | ||
178 | mvnhi r3, r3, asr #31 @ | ||
179 | andhi r3, r3, #31 @ | ||
180 | cmp r11, #31 @ clamp r | ||
181 | mvnhi r11, r11, asr #31 @ | ||
182 | andhi r11, r11, #31 @ | ||
183 | cmp r7, #63 @ clamp g | ||
184 | mvnhi r7, r7, asr #31 @ | ||
185 | andhi r7, r7, #63 @ | ||
186 | 15: @ no clamp @ | ||
187 | @ | ||
188 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
189 | @ | ||
190 | orr r3, r3, r7, lsl #5 @ r3 = b | (g << 5) | ||
191 | orr r3, r3, r11, lsl #11 @ r3 |= (r << 11) | ||
192 | @ | ||
193 | movs r7, r3, lsr #8 @ store pixel | ||
194 | 20: @ | ||
195 | ldr r11, [r0] @ | ||
196 | tst r11, #LCD1_BUSY_MASK @ | ||
197 | bne 20b @ | ||
198 | str r7, [r0, #0x10] @ | ||
199 | 25: @ | ||
200 | ldr r11, [r0] @ | ||
201 | tst r11, #LCD1_BUSY_MASK @ | ||
202 | bne 25b @ | ||
203 | str r3, [r0, #0x10] @ | ||
204 | @ | ||
205 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
206 | add r12, r7, r7, asl #2 @ | ||
207 | add r7, r12, r7, asl #5 @ | ||
208 | @ compute R, G, and B | ||
209 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
210 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
211 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
212 | @ | ||
213 | orr r12, r3, r11 @ check if clamping is needed... | ||
214 | orr r12, r12, r7, asr #1 @ ...at all | ||
215 | cmp r12, #31 @ | ||
216 | bls 15f @ no clamp @ | ||
217 | cmp r3, #31 @ clamp b | ||
218 | mvnhi r3, r3, asr #31 @ | ||
219 | andhi r3, r3, #31 @ | ||
220 | cmp r11, #31 @ clamp r | ||
221 | mvnhi r11, r11, asr #31 @ | ||
222 | andhi r11, r11, #31 @ | ||
223 | cmp r7, #63 @ clamp g | ||
224 | mvnhi r7, r7, asr #31 @ | ||
225 | andhi r7, r7, #63 @ | ||
226 | 15: @ no clamp @ | ||
227 | @ | ||
228 | orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11) | ||
229 | orr r3, r3, r7, lsl #5 @ r3 |= (g << 5) | ||
230 | @ | ||
231 | movs r7, r3, lsr #8 @ store pixel | ||
232 | 20: @ | ||
233 | ldr r11, [r0] @ | ||
234 | tst r11, #LCD1_BUSY_MASK @ | ||
235 | bne 20b @ | ||
236 | str r7, [r0, #0x10] @ | ||
237 | 25: @ | ||
238 | ldr r11, [r0] @ | ||
239 | tst r11, #LCD1_BUSY_MASK @ | ||
240 | bne 25b @ | ||
241 | str r3, [r0, #0x10] @ | ||
242 | @ | ||
243 | subs r1, r1, #2 @ subtract block from width | ||
244 | bgt 10b @ loop line @ | ||
245 | @ | ||
246 | ldmpc regs=r4-r11 @ restore registers and return | ||
247 | .ltorg @ dump constant pool | ||
248 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
249 | |||
250 | |||
251 | /**************************************************************************** | ||
252 | * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
253 | * int width, | ||
254 | * int stride, | ||
255 | * int x_screen, | ||
256 | * int y_screen); | ||
257 | * | ||
258 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
259 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
260 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
261 | * Red scaled at twice g & b but at same precision to place it in correct | ||
262 | * bit position after multiply and leave instruction count lower. | ||
263 | * |R| |258 0 408| |Y' - 16| | ||
264 | * |G| = |149 -49 -104| |Cb - 128| | ||
265 | * |B| |149 258 0| |Cr - 128| | ||
266 | * | ||
267 | * Write four RGB565 pixels in the following order on each loop: | ||
268 | * 1 3 + > down | ||
269 | * 2 4 \/ left | ||
270 | * | ||
271 | * Kernel pattern (raw|use order): | ||
272 | * 5 3 4 2 row0 row2 > down | ||
273 | * 1 7 0 6 | 5 1 3 7 4 0 2 6 col0 left | ||
274 | * 4 2 5 3 | 4 0 2 6 5 1 3 7 col2 \/ | ||
275 | * 0 6 1 7 | ||
276 | */ | ||
277 | .section .icode, "ax", %progbits | ||
278 | .align 2 | ||
279 | .global lcd_write_yuv420_lines_odither | ||
280 | .type lcd_write_yuv420_lines_odither, %function | ||
281 | lcd_write_yuv420_lines_odither: | ||
282 | @ r0 = yuv_src | ||
283 | @ r1 = width | ||
284 | @ r2 = stride | ||
285 | @ r3 = x_screen | ||
286 | @ [sp] = y_screen | ||
287 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
288 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
289 | @ r5 = yuv_src[1] = Cb_p | ||
290 | @ r6 = yuv_src[2] = Cr_p | ||
291 | @ | ||
292 | ldr r0, [sp, #36] @ Line up pattern and kernel quadrant | ||
293 | eor r14, r3, r0 @ | ||
294 | and r14, r14, #0x2 @ | ||
295 | mov r14, r14, lsl #6 @ 0x00 or 0x80 | ||
296 | @ | ||
297 | ldr r0, =LCD1_BASE @ | ||
298 | @ | ||
299 | sub r2, r2, #1 @ Adjust stride because of increment | ||
300 | 10: @ loop line @ | ||
301 | @ | ||
302 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
303 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
304 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
305 | @ | ||
306 | eor r14, r14, #0x80 @ flip pattern quadrant | ||
307 | @ | ||
308 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149 | ||
309 | add r12, r7, r7, asl #2 @ | ||
310 | add r12, r12, r12, asl #4 @ | ||
311 | add r7, r12, r7, asl #6 @ | ||
312 | @ | ||
313 | sub r8, r8, #128 @ Cb -= 128 | ||
314 | sub r9, r9, #128 @ Cr -= 128 | ||
315 | @ | ||
316 | add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49 | ||
317 | add r10, r10, r8, asl #5 @ | ||
318 | add r10, r10, r9, asl #3 @ | ||
319 | add r10, r10, r9, asl #5 @ | ||
320 | add r10, r10, r9, asl #6 @ | ||
321 | @ | ||
322 | mov r8, r8, asl #1 @ r8 = bu = Cb*258 | ||
323 | add r8, r8, r8, asl #7 @ | ||
324 | @ | ||
325 | add r9, r9, r9, asl #1 @ r9 = rv = Cr*408 | ||
326 | add r9, r9, r9, asl #4 @ | ||
327 | mov r9, r9, asl #3 @ | ||
328 | @ | ||
329 | @ compute R, G, and B | ||
330 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
331 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
332 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
333 | @ | ||
334 | @ r8 = bu, r9 = rv, r10 = guv | ||
335 | @ | ||
336 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256 | ||
337 | add r3, r12, r3, lsr #8 @ | ||
338 | @ | ||
339 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
340 | add r11, r12, r11, lsr #8 @ | ||
341 | @ | ||
342 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
343 | add r7, r12, r7, lsr #8 @ | ||
344 | @ | ||
345 | add r12, r14, #0x200 @ | ||
346 | @ | ||
347 | add r3, r3, r12 @ b = r3 + delta | ||
348 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
349 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
350 | @ | ||
351 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
352 | orr r12, r12, r7 @ ...at all | ||
353 | movs r12, r12, asr #15 @ | ||
354 | beq 15f @ no clamp @ | ||
355 | movs r12, r3, asr #15 @ clamp b | ||
356 | mvnne r3, r12, lsr #15 @ | ||
357 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
358 | movs r12, r11, asr #16 @ clamp r | ||
359 | mvnne r11, r12, lsr #16 @ | ||
360 | movs r12, r7, asr #15 @ clamp g | ||
361 | mvnne r7, r12, lsr #15 @ | ||
362 | 15: @ no clamp @ | ||
363 | @ | ||
364 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
365 | @ | ||
366 | and r11, r11, #0xf800 @ pack pixel | ||
367 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
368 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
369 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
370 | @ | ||
371 | movs r7, r3, lsr #8 @ store pixel | ||
372 | 20: @ | ||
373 | ldr r11, [r0] @ | ||
374 | tst r11, #LCD1_BUSY_MASK @ | ||
375 | bne 20b @ | ||
376 | str r7, [r0, #0x10] @ | ||
377 | 25: @ | ||
378 | ldr r11, [r0] @ | ||
379 | tst r11, #LCD1_BUSY_MASK @ | ||
380 | bne 25b @ | ||
381 | str r3, [r0, #0x10] @ | ||
382 | @ | ||
383 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
384 | add r12, r7, r7, asl #2 @ | ||
385 | add r12, r12, r12, asl #4 @ | ||
386 | add r7, r12, r7, asl #6 @ | ||
387 | @ compute R, G, and B | ||
388 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
389 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
390 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
391 | @ | ||
392 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256 | ||
393 | add r3, r12, r3, lsr #8 @ | ||
394 | @ | ||
395 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
396 | add r11, r12, r11, lsr #8 @ | ||
397 | @ | ||
398 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
399 | add r7, r12, r7, lsr #8 @ | ||
400 | @ | ||
401 | @ This element is zero - use r14 @ | ||
402 | @ | ||
403 | add r3, r3, r14 @ b = r3 + delta | ||
404 | add r11, r11, r14, lsl #1 @ r = r11 + delta*2 | ||
405 | add r7, r7, r14, lsr #1 @ g = r7 + delta/2 | ||
406 | @ | ||
407 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
408 | orr r12, r12, r7 @ ...at all | ||
409 | movs r12, r12, asr #15 @ | ||
410 | beq 15f @ no clamp @ | ||
411 | movs r12, r3, asr #15 @ clamp b | ||
412 | mvnne r3, r12, lsr #15 @ | ||
413 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
414 | movs r12, r11, asr #16 @ clamp r | ||
415 | mvnne r11, r12, lsr #16 @ | ||
416 | movs r12, r7, asr #15 @ clamp g | ||
417 | mvnne r7, r12, lsr #15 @ | ||
418 | 15: @ no clamp @ | ||
419 | @ | ||
420 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
421 | @ | ||
422 | and r11, r11, #0xf800 @ pack pixel | ||
423 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
424 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
425 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
426 | @ | ||
427 | movs r7, r3, lsr #8 @ store pixel | ||
428 | 20: @ | ||
429 | ldr r11, [r0] @ | ||
430 | tst r11, #LCD1_BUSY_MASK @ | ||
431 | bne 20b @ | ||
432 | str r7, [r0, #0x10] @ | ||
433 | 25: @ | ||
434 | ldr r11, [r0] @ | ||
435 | tst r11, #LCD1_BUSY_MASK @ | ||
436 | bne 25b @ | ||
437 | str r3, [r0, #0x10] @ | ||
438 | @ | ||
439 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
440 | add r12, r7, r7, asl #2 @ | ||
441 | add r12, r12, r12, asl #4 @ | ||
442 | add r7, r12, r7, asl #6 @ | ||
443 | @ compute R, G, and B | ||
444 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
445 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
446 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
447 | @ | ||
448 | @ r8 = bu, r9 = rv, r10 = guv | ||
449 | @ | ||
450 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256 | ||
451 | add r3, r12, r3, lsr #8 @ | ||
452 | @ | ||
453 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
454 | add r11, r12, r11, lsr #8 @ | ||
455 | @ | ||
456 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
457 | add r7, r12, r7, lsr #8 @ | ||
458 | @ | ||
459 | add r12, r14, #0x100 @ | ||
460 | @ | ||
461 | add r3, r3, r12 @ b = r3 + delta | ||
462 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
463 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
464 | @ | ||
465 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
466 | orr r12, r12, r7 @ ...at all | ||
467 | movs r12, r12, asr #15 @ | ||
468 | beq 15f @ no clamp @ | ||
469 | movs r12, r3, asr #15 @ clamp b | ||
470 | mvnne r3, r12, lsr #15 @ | ||
471 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
472 | movs r12, r11, asr #16 @ clamp r | ||
473 | mvnne r11, r12, lsr #16 @ | ||
474 | movs r12, r7, asr #15 @ clamp g | ||
475 | mvnne r7, r12, lsr #15 @ | ||
476 | 15: @ no clamp @ | ||
477 | @ | ||
478 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
479 | @ | ||
480 | and r11, r11, #0xf800 @ pack pixel | ||
481 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
482 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
483 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
484 | @ | ||
485 | movs r7, r3, lsr #8 @ store pixel | ||
486 | 20: @ | ||
487 | ldr r11, [r0] @ | ||
488 | tst r11, #LCD1_BUSY_MASK @ | ||
489 | bne 20b @ | ||
490 | str r7, [r0, #0x10] @ | ||
491 | 25: @ | ||
492 | ldr r11, [r0] @ | ||
493 | tst r11, #LCD1_BUSY_MASK @ | ||
494 | bne 25b @ | ||
495 | str r3, [r0, #0x10] @ | ||
496 | @ | ||
497 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
498 | add r12, r7, r7, asl #2 @ | ||
499 | add r12, r12, r12, asl #4 @ | ||
500 | add r7, r12, r7, asl #6 @ | ||
501 | @ compute R, G, and B | ||
502 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
503 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
504 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
505 | @ | ||
506 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256 | ||
507 | add r3, r12, r3, lsr #8 @ | ||
508 | @ | ||
509 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
510 | add r11, r12, r11, lsr #8 @ | ||
511 | @ | ||
512 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
513 | add r7, r12, r7, lsr #8 @ | ||
514 | @ | ||
515 | add r12, r14, #0x300 @ | ||
516 | @ | ||
517 | add r3, r3, r12 @ b = r3 + delta | ||
518 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
519 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
520 | @ | ||
521 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
522 | orr r12, r12, r7 @ ...at all | ||
523 | movs r12, r12, asr #15 @ | ||
524 | beq 15f @ no clamp @ | ||
525 | movs r12, r3, asr #15 @ clamp b | ||
526 | mvnne r3, r12, lsr #15 @ | ||
527 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
528 | movs r12, r11, asr #16 @ clamp r | ||
529 | mvnne r11, r12, lsr #16 @ | ||
530 | movs r12, r7, asr #15 @ clamp g | ||
531 | mvnne r7, r12, lsr #15 @ | ||
532 | 15: @ no clamp @ | ||
533 | @ | ||
534 | and r11, r11, #0xf800 @ pack pixel | ||
535 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
536 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
537 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
538 | @ | ||
539 | movs r7, r3, lsr #8 @ store pixel | ||
540 | 20: @ | ||
541 | ldr r11, [r0] @ | ||
542 | tst r11, #LCD1_BUSY_MASK @ | ||
543 | bne 20b @ | ||
544 | str r7, [r0, #0x10] @ | ||
545 | 25: @ | ||
546 | ldr r11, [r0] @ | ||
547 | tst r11, #LCD1_BUSY_MASK @ | ||
548 | bne 25b @ | ||
549 | str r3, [r0, #0x10] @ | ||
550 | @ | ||
551 | subs r1, r1, #2 @ subtract block from width | ||
552 | bgt 10b @ loop line @ | ||
553 | @ | ||
554 | ldmpc regs=r4-r11 @ restore registers and return | ||
555 | .ltorg @ dump constant pool | ||
556 | .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither | ||
diff --git a/firmware/target/arm/pbell/vibe500/lcd-vibe500.c b/firmware/target/arm/pbell/vibe500/lcd-vibe500.c index 2daa5def74..047ef2bf53 100644 --- a/firmware/target/arm/pbell/vibe500/lcd-vibe500.c +++ b/firmware/target/arm/pbell/vibe500/lcd-vibe500.c | |||
@@ -35,6 +35,8 @@ static unsigned short disp_control_rev; | |||
35 | /* Contrast setting << 8 */ | 35 | /* Contrast setting << 8 */ |
36 | static int lcd_contrast; | 36 | static int lcd_contrast; |
37 | 37 | ||
38 | static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0; | ||
39 | |||
38 | /* Forward declarations */ | 40 | /* Forward declarations */ |
39 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | 41 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) |
40 | static void lcd_display_off(void); | 42 | static void lcd_display_off(void); |
@@ -375,6 +377,79 @@ bool lcd_active(void) | |||
375 | 377 | ||
376 | /*** update functions ***/ | 378 | /*** update functions ***/ |
377 | 379 | ||
380 | void lcd_yuv_set_options(unsigned options) | ||
381 | { | ||
382 | lcd_yuv_options = options; | ||
383 | } | ||
384 | |||
385 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ | ||
386 | |||
387 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
388 | int width, | ||
389 | int stride); | ||
390 | extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
391 | int width, | ||
392 | int stride, | ||
393 | int x_screen, /* To align dither pattern */ | ||
394 | int y_screen); | ||
395 | |||
396 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
397 | void lcd_blit_yuv(unsigned char * const src[3], | ||
398 | int src_x, int src_y, int stride, | ||
399 | int x, int y, int width, int height) | ||
400 | { | ||
401 | const unsigned char *yuv_src[3]; | ||
402 | const unsigned char *ysrc_max; | ||
403 | int y0; | ||
404 | int options; | ||
405 | |||
406 | if (!display_on) | ||
407 | return; | ||
408 | |||
409 | width &= ~1; | ||
410 | height &= ~1; | ||
411 | |||
412 | lcd_write_reg(R_VERT_RAM_ADDR_POS, ((LCD_WIDTH - 1 - x) << 8) | | ||
413 | ((LCD_WIDTH-1) - (x + width - 1))); | ||
414 | |||
415 | y0 = LCD_HEIGHT - 1 - y; | ||
416 | |||
417 | lcd_write_reg(R_ENTRY_MODE,0x1000); | ||
418 | |||
419 | yuv_src[0] = src[0] + src_y * stride + src_x; | ||
420 | yuv_src[1] = src[1] + (src_y * stride >> 2) + (src_x >> 1); | ||
421 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
422 | ysrc_max = yuv_src[0] + height * stride; | ||
423 | |||
424 | options = lcd_yuv_options; | ||
425 | |||
426 | do | ||
427 | { | ||
428 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (y0 << 8) | (y0 - 1)); | ||
429 | lcd_write_reg(R_RAM_ADDR_SET, ((LCD_WIDTH - 1 - x) << 8) | y0); | ||
430 | |||
431 | /* start drawing */ | ||
432 | lcd_send_cmd(R_WRITE_DATA_2_GRAM); | ||
433 | |||
434 | if (options & LCD_YUV_DITHER) | ||
435 | { | ||
436 | lcd_write_yuv420_lines_odither(yuv_src, width, stride,x, y); | ||
437 | y -= 2; | ||
438 | } | ||
439 | else | ||
440 | { | ||
441 | lcd_write_yuv420_lines(yuv_src, width, stride); | ||
442 | } | ||
443 | |||
444 | y0 -= 2; | ||
445 | yuv_src[0] += stride << 1; | ||
446 | yuv_src[1] += stride >> 1; | ||
447 | yuv_src[2] += stride >> 1; | ||
448 | } | ||
449 | while (yuv_src[0] < ysrc_max); | ||
450 | lcd_write_reg(R_ENTRY_MODE,0x1008); | ||
451 | } | ||
452 | |||
378 | /* Update a fraction of the display. */ | 453 | /* Update a fraction of the display. */ |
379 | void lcd_update_rect(int x0, int y0, int width, int height) | 454 | void lcd_update_rect(int x0, int y0, int width, int height) |
380 | { | 455 | { |
diff --git a/firmware/target/arm/philips/hdd1630/lcd-as-hdd1630.S b/firmware/target/arm/philips/hdd1630/lcd-as-hdd1630.S new file mode 100644 index 0000000000..3bb3530917 --- /dev/null +++ b/firmware/target/arm/philips/hdd1630/lcd-as-hdd1630.S | |||
@@ -0,0 +1,570 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007-2008 by Michael Sevakis | ||
11 | * | ||
12 | * H10 20GB LCD assembly routines | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | #include "config.h" | ||
25 | #include "cpu.h" | ||
26 | |||
27 | /**************************************************************************** | ||
28 | * void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
29 | * int width, | ||
30 | * int stride); | ||
31 | * | ||
32 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
33 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
34 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
35 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
36 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
37 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
38 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
39 | * | ||
40 | * Write four RGB565 pixels in the following order on each loop: | ||
41 | * 1 3 + > down | ||
42 | * 2 4 \/ left | ||
43 | */ | ||
44 | .section .icode, "ax", %progbits | ||
45 | .align 2 | ||
46 | .global lcd_write_yuv420_lines | ||
47 | .type lcd_write_yuv420_lines, %function | ||
48 | lcd_write_yuv420_lines: | ||
49 | @ r0 = yuv_src | ||
50 | @ r1 = width | ||
51 | @ r2 = stride | ||
52 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
53 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
54 | @ r5 = yuv_src[1] = Cb_p | ||
55 | @ r6 = yuv_src[2] = Cr_p | ||
56 | @ | ||
57 | mov r0, #0x7000000c @ r0 = &LCD2_PORT = 0x70008a0c | ||
58 | add r0, r0, #0x8a00 @ | ||
59 | mov r14, #LCD2_DATA_MASK @ | ||
60 | @ | ||
61 | sub r2, r2, #1 @ Adjust stride because of increment | ||
62 | 10: @ loop line @ | ||
63 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
64 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
65 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
66 | @ | ||
67 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 | ||
68 | add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right | ||
69 | add r7, r12, r7, asl #5 @ by one less when adding - same for all | ||
70 | @ | ||
71 | sub r8, r8, #128 @ Cb -= 128 | ||
72 | sub r9, r9, #128 @ Cr -= 128 | ||
73 | @ | ||
74 | add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 | ||
75 | add r10, r10, r10, asl #4 @ | ||
76 | add r10, r10, r8, asl #3 @ | ||
77 | add r10, r10, r8, asl #4 @ | ||
78 | @ | ||
79 | add r11, r9, r9, asl #2 @ r9 = Cr*101 | ||
80 | add r11, r11, r9, asl #5 @ | ||
81 | add r9, r11, r9, asl #6 @ | ||
82 | @ | ||
83 | add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 | ||
84 | mov r8, r8, asr #2 @ | ||
85 | add r9, r9, #256 @ r9 = rv = (r8 + 256) >> 9 | ||
86 | mov r9, r9, asr #9 @ | ||
87 | rsb r10, r10, #128 @ r10 = guv = (-r9 + 128) >> 8 | ||
88 | mov r10, r10, asr #8 @ | ||
89 | @ compute R, G, and B | ||
90 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
91 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
92 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
93 | @ | ||
94 | orr r12, r3, r11 @ check if clamping is needed... | ||
95 | orr r12, r12, r7, asr #1 @ ...at all | ||
96 | cmp r12, #31 @ | ||
97 | bls 15f @ no clamp @ | ||
98 | cmp r3, #31 @ clamp b | ||
99 | mvnhi r3, r3, asr #31 @ | ||
100 | andhi r3, r3, #31 @ | ||
101 | cmp r11, #31 @ clamp r | ||
102 | mvnhi r11, r11, asr #31 @ | ||
103 | andhi r11, r11, #31 @ | ||
104 | cmp r7, #63 @ clamp g | ||
105 | mvnhi r7, r7, asr #31 @ | ||
106 | andhi r7, r7, #63 @ | ||
107 | 15: @ no clamp @ | ||
108 | @ | ||
109 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
110 | @ | ||
111 | orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11) | ||
112 | orr r3, r3, r7, lsl #5 @ r3 |= (g << 5) | ||
113 | @ | ||
114 | orr r7, r14, r3, lsr #8 @ store pixel | ||
115 | orr r11, r14, r3 @ | ||
116 | 20: @ | ||
117 | ldr r3, [r0] @ | ||
118 | tst r3, #LCD2_BUSY_MASK @ | ||
119 | bne 20b @ | ||
120 | str r7, [r0] @ | ||
121 | 20: @ | ||
122 | ldr r3, [r0] @ | ||
123 | tst r3, #LCD2_BUSY_MASK @ | ||
124 | bne 20b @ | ||
125 | str r11, [r0] @ | ||
126 | @ | ||
127 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
128 | add r12, r7, r7, asl #2 @ | ||
129 | add r7, r12, r7, asl #5 @ | ||
130 | @ compute R, G, and B | ||
131 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
132 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
133 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
134 | @ | ||
135 | orr r12, r3, r11 @ check if clamping is needed... | ||
136 | orr r12, r12, r7, asr #1 @ ...at all | ||
137 | cmp r12, #31 @ | ||
138 | bls 15f @ no clamp @ | ||
139 | cmp r3, #31 @ clamp b | ||
140 | mvnhi r3, r3, asr #31 @ | ||
141 | andhi r3, r3, #31 @ | ||
142 | cmp r11, #31 @ clamp r | ||
143 | mvnhi r11, r11, asr #31 @ | ||
144 | andhi r11, r11, #31 @ | ||
145 | cmp r7, #63 @ clamp g | ||
146 | mvnhi r7, r7, asr #31 @ | ||
147 | andhi r7, r7, #63 @ | ||
148 | 15: @ no clamp @ | ||
149 | @ | ||
150 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
151 | @ | ||
152 | orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11) | ||
153 | orr r3, r3, r7, lsl #5 @ r3 |= (g << 5) | ||
154 | @ | ||
155 | orr r7, r14, r3, lsr #8 @ store pixel | ||
156 | orr r11, r14, r3 @ | ||
157 | 20: @ | ||
158 | ldr r3, [r0] @ | ||
159 | tst r3, #LCD2_BUSY_MASK @ | ||
160 | bne 20b @ | ||
161 | str r7, [r0] @ | ||
162 | 20: @ | ||
163 | ldr r3, [r0] @ | ||
164 | tst r3, #LCD2_BUSY_MASK @ | ||
165 | bne 20b @ | ||
166 | str r11, [r0] @ | ||
167 | @ | ||
168 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
169 | add r12, r7, r7, asl #2 @ | ||
170 | add r7, r12, r7, asl #5 @ | ||
171 | @ compute R, G, and B | ||
172 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
173 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
174 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
175 | @ | ||
176 | orr r12, r3, r11 @ check if clamping is needed... | ||
177 | orr r12, r12, r7, asr #1 @ ...at all | ||
178 | cmp r12, #31 @ | ||
179 | bls 15f @ no clamp @ | ||
180 | cmp r3, #31 @ clamp b | ||
181 | mvnhi r3, r3, asr #31 @ | ||
182 | andhi r3, r3, #31 @ | ||
183 | cmp r11, #31 @ clamp r | ||
184 | mvnhi r11, r11, asr #31 @ | ||
185 | andhi r11, r11, #31 @ | ||
186 | cmp r7, #63 @ clamp g | ||
187 | mvnhi r7, r7, asr #31 @ | ||
188 | andhi r7, r7, #63 @ | ||
189 | 15: @ no clamp @ | ||
190 | @ | ||
191 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
192 | @ | ||
193 | orr r3, r3, r7, lsl #5 @ r3 = b | (g << 5) | ||
194 | orr r3, r3, r11, lsl #11 @ r3 |= (r << 11) | ||
195 | @ | ||
196 | orr r7, r14, r3, lsr #8 @ store pixel | ||
197 | orr r11, r14, r3 @ | ||
198 | 20: @ | ||
199 | ldr r3, [r0] @ | ||
200 | tst r3, #LCD2_BUSY_MASK @ | ||
201 | bne 20b @ | ||
202 | str r7, [r0] @ | ||
203 | 20: @ | ||
204 | ldr r3, [r0] @ | ||
205 | tst r3, #LCD2_BUSY_MASK @ | ||
206 | bne 20b @ | ||
207 | str r11, [r0] @ | ||
208 | @ | ||
209 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
210 | add r12, r7, r7, asl #2 @ | ||
211 | add r7, r12, r7, asl #5 @ | ||
212 | @ compute R, G, and B | ||
213 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
214 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
215 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
216 | @ | ||
217 | orr r12, r3, r11 @ check if clamping is needed... | ||
218 | orr r12, r12, r7, asr #1 @ ...at all | ||
219 | cmp r12, #31 @ | ||
220 | bls 15f @ no clamp @ | ||
221 | cmp r3, #31 @ clamp b | ||
222 | mvnhi r3, r3, asr #31 @ | ||
223 | andhi r3, r3, #31 @ | ||
224 | cmp r11, #31 @ clamp r | ||
225 | mvnhi r11, r11, asr #31 @ | ||
226 | andhi r11, r11, #31 @ | ||
227 | cmp r7, #63 @ clamp g | ||
228 | mvnhi r7, r7, asr #31 @ | ||
229 | andhi r7, r7, #63 @ | ||
230 | 15: @ no clamp @ | ||
231 | @ | ||
232 | orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11) | ||
233 | orr r3, r3, r7, lsl #5 @ r3 |= (g << 5) | ||
234 | @ | ||
235 | orr r7, r14, r3, lsr #8 @ store pixel | ||
236 | orr r11, r14, r3 @ | ||
237 | 20: @ | ||
238 | ldr r3, [r0] @ | ||
239 | tst r3, #LCD2_BUSY_MASK @ | ||
240 | bne 20b @ | ||
241 | str r7, [r0] @ | ||
242 | 20: @ | ||
243 | ldr r3, [r0] @ | ||
244 | tst r3, #LCD2_BUSY_MASK @ | ||
245 | bne 20b @ | ||
246 | str r11, [r0] @ | ||
247 | @ | ||
248 | subs r1, r1, #2 @ subtract block from width | ||
249 | bgt 10b @ loop line @ | ||
250 | @ | ||
251 | ldmpc regs=r4-r11 @ restore registers and return | ||
252 | .ltorg @ dump constant pool | ||
253 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
254 | |||
255 | |||
256 | /**************************************************************************** | ||
257 | * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
258 | * int width, | ||
259 | * int stride, | ||
260 | * int x_screen, | ||
261 | * int y_screen); | ||
262 | * | ||
263 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
264 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
265 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
266 | * Red scaled at twice g & b but at same precision to place it in correct | ||
267 | * bit position after multiply and leave instruction count lower. | ||
268 | * |R| |258 0 408| |Y' - 16| | ||
269 | * |G| = |149 -49 -104| |Cb - 128| | ||
270 | * |B| |149 258 0| |Cr - 128| | ||
271 | * | ||
272 | * Write four RGB565 pixels in the following order on each loop: | ||
273 | * 1 3 + > down | ||
274 | * 2 4 \/ left | ||
275 | * | ||
276 | * Kernel pattern (raw|use order): | ||
277 | * 5 3 4 2 row0 row2 > down | ||
278 | * 1 7 0 6 | 5 1 3 7 4 0 2 6 col0 left | ||
279 | * 4 2 5 3 | 4 0 2 6 5 1 3 7 col2 \/ | ||
280 | * 0 6 1 7 | ||
281 | */ | ||
282 | .section .icode, "ax", %progbits | ||
283 | .align 2 | ||
284 | .global lcd_write_yuv420_lines_odither | ||
285 | .type lcd_write_yuv420_lines_odither, %function | ||
286 | lcd_write_yuv420_lines_odither: | ||
287 | @ r0 = yuv_src | ||
288 | @ r1 = width | ||
289 | @ r2 = stride | ||
290 | @ r3 = x_screen | ||
291 | @ [sp] = y_screen | ||
292 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
293 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
294 | @ r5 = yuv_src[1] = Cb_p | ||
295 | @ r6 = yuv_src[2] = Cr_p | ||
296 | @ | ||
297 | ldr r0, [sp, #36] @ Line up pattern and kernel quadrant | ||
298 | eor r14, r3, r0 @ | ||
299 | and r14, r14, #0x2 @ | ||
300 | mov r14, r14, lsl #6 @ 0x00 or 0x80 | ||
301 | @ | ||
302 | mov r0, #0x7000000c @ r0 = &LCD2_PORT = 0x70008a0c | ||
303 | add r0, r0, #0x8a00 @ | ||
304 | @ | ||
305 | sub r2, r2, #1 @ Adjust stride because of increment | ||
306 | 10: @ loop line @ | ||
307 | @ | ||
308 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
309 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
310 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
311 | @ | ||
312 | eor r14, r14, #0x80 @ flip pattern quadrant | ||
313 | @ | ||
314 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149 | ||
315 | add r12, r7, r7, asl #2 @ | ||
316 | add r12, r12, r12, asl #4 @ | ||
317 | add r7, r12, r7, asl #6 @ | ||
318 | @ | ||
319 | sub r8, r8, #128 @ Cb -= 128 | ||
320 | sub r9, r9, #128 @ Cr -= 128 | ||
321 | @ | ||
322 | add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49 | ||
323 | add r10, r10, r8, asl #5 @ | ||
324 | add r10, r10, r9, asl #3 @ | ||
325 | add r10, r10, r9, asl #5 @ | ||
326 | add r10, r10, r9, asl #6 @ | ||
327 | @ | ||
328 | mov r8, r8, asl #1 @ r8 = bu = Cb*258 | ||
329 | add r8, r8, r8, asl #7 @ | ||
330 | @ | ||
331 | add r9, r9, r9, asl #1 @ r9 = rv = Cr*408 | ||
332 | add r9, r9, r9, asl #4 @ | ||
333 | mov r9, r9, asl #3 @ | ||
334 | @ | ||
335 | @ compute R, G, and B | ||
336 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
337 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
338 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
339 | @ | ||
340 | @ r8 = bu, r9 = rv, r10 = guv | ||
341 | @ | ||
342 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256 | ||
343 | add r3, r12, r3, lsr #8 @ | ||
344 | @ | ||
345 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
346 | add r11, r12, r11, lsr #8 @ | ||
347 | @ | ||
348 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
349 | add r7, r12, r7, lsr #8 @ | ||
350 | @ | ||
351 | add r12, r14, #0x200 @ | ||
352 | @ | ||
353 | add r3, r3, r12 @ b = r3 + delta | ||
354 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
355 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
356 | @ | ||
357 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
358 | orr r12, r12, r7 @ ...at all | ||
359 | movs r12, r12, asr #15 @ | ||
360 | beq 15f @ no clamp @ | ||
361 | movs r12, r3, asr #15 @ clamp b | ||
362 | mvnne r3, r12, lsr #15 @ | ||
363 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
364 | movs r12, r11, asr #16 @ clamp r | ||
365 | mvnne r11, r12, lsr #16 @ | ||
366 | movs r12, r7, asr #15 @ clamp g | ||
367 | mvnne r7, r12, lsr #15 @ | ||
368 | 15: @ no clamp @ | ||
369 | @ | ||
370 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
371 | @ | ||
372 | and r11, r11, #0xf800 @ pack pixel | ||
373 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
374 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
375 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
376 | @ | ||
377 | mov r11, #LCD2_DATA_MASK @ store pixel | ||
378 | orr r7, r11, r3, lsr #8 @ | ||
379 | orr r11, r11, r3 @ | ||
380 | 20: @ | ||
381 | ldr r3, [r0] @ | ||
382 | tst r3, #LCD2_BUSY_MASK @ | ||
383 | bne 20b @ | ||
384 | str r7, [r0] @ | ||
385 | 20: @ | ||
386 | ldr r3, [r0] @ | ||
387 | tst r3, #LCD2_BUSY_MASK @ | ||
388 | bne 20b @ | ||
389 | str r11, [r0] @ | ||
390 | @ | ||
391 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
392 | add r12, r7, r7, asl #2 @ | ||
393 | add r12, r12, r12, asl #4 @ | ||
394 | add r7, r12, r7, asl #6 @ | ||
395 | @ compute R, G, and B | ||
396 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
397 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
398 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
399 | @ | ||
400 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256 | ||
401 | add r3, r12, r3, lsr #8 @ | ||
402 | @ | ||
403 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
404 | add r11, r12, r11, lsr #8 @ | ||
405 | @ | ||
406 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
407 | add r7, r12, r7, lsr #8 @ | ||
408 | @ | ||
409 | @ This element is zero - use r14 @ | ||
410 | @ | ||
411 | add r3, r3, r14 @ b = r3 + delta | ||
412 | add r11, r11, r14, lsl #1 @ r = r11 + delta*2 | ||
413 | add r7, r7, r14, lsr #1 @ g = r7 + delta/2 | ||
414 | @ | ||
415 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
416 | orr r12, r12, r7 @ ...at all | ||
417 | movs r12, r12, asr #15 @ | ||
418 | beq 15f @ no clamp @ | ||
419 | movs r12, r3, asr #15 @ clamp b | ||
420 | mvnne r3, r12, lsr #15 @ | ||
421 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
422 | movs r12, r11, asr #16 @ clamp r | ||
423 | mvnne r11, r12, lsr #16 @ | ||
424 | movs r12, r7, asr #15 @ clamp g | ||
425 | mvnne r7, r12, lsr #15 @ | ||
426 | 15: @ no clamp @ | ||
427 | @ | ||
428 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
429 | @ | ||
430 | and r11, r11, #0xf800 @ pack pixel | ||
431 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
432 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
433 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
434 | @ | ||
435 | mov r11, #LCD2_DATA_MASK @ store pixel | ||
436 | orr r7, r11, r3, lsr #8 @ | ||
437 | orr r11, r11, r3 @ | ||
438 | 20: @ | ||
439 | ldr r3, [r0] @ | ||
440 | tst r3, #LCD2_BUSY_MASK @ | ||
441 | bne 20b @ | ||
442 | str r7, [r0] @ | ||
443 | 20: @ | ||
444 | ldr r3, [r0] @ | ||
445 | tst r3, #LCD2_BUSY_MASK @ | ||
446 | bne 20b @ | ||
447 | str r11, [r0] @ | ||
448 | @ | ||
449 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
450 | add r12, r7, r7, asl #2 @ | ||
451 | add r12, r12, r12, asl #4 @ | ||
452 | add r7, r12, r7, asl #6 @ | ||
453 | @ compute R, G, and B | ||
454 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
455 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
456 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
457 | @ | ||
458 | @ r8 = bu, r9 = rv, r10 = guv | ||
459 | @ | ||
460 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256 | ||
461 | add r3, r12, r3, lsr #8 @ | ||
462 | @ | ||
463 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
464 | add r11, r12, r11, lsr #8 @ | ||
465 | @ | ||
466 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
467 | add r7, r12, r7, lsr #8 @ | ||
468 | @ | ||
469 | add r12, r14, #0x100 @ | ||
470 | @ | ||
471 | add r3, r3, r12 @ b = r3 + delta | ||
472 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
473 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
474 | @ | ||
475 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
476 | orr r12, r12, r7 @ ...at all | ||
477 | movs r12, r12, asr #15 @ | ||
478 | beq 15f @ no clamp @ | ||
479 | movs r12, r3, asr #15 @ clamp b | ||
480 | mvnne r3, r12, lsr #15 @ | ||
481 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
482 | movs r12, r11, asr #16 @ clamp r | ||
483 | mvnne r11, r12, lsr #16 @ | ||
484 | movs r12, r7, asr #15 @ clamp g | ||
485 | mvnne r7, r12, lsr #15 @ | ||
486 | 15: @ no clamp @ | ||
487 | @ | ||
488 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
489 | @ | ||
490 | and r11, r11, #0xf800 @ pack pixel | ||
491 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
492 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
493 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
494 | @ | ||
495 | mov r11, #LCD2_DATA_MASK @ store pixel | ||
496 | orr r7, r11, r3, lsr #8 @ | ||
497 | orr r11, r11, r3 @ | ||
498 | 20: @ | ||
499 | ldr r3, [r0] @ | ||
500 | tst r3, #LCD2_BUSY_MASK @ | ||
501 | bne 20b @ | ||
502 | str r7, [r0] @ | ||
503 | 20: @ | ||
504 | ldr r3, [r0] @ | ||
505 | tst r3, #LCD2_BUSY_MASK @ | ||
506 | bne 20b @ | ||
507 | str r11, [r0] @ | ||
508 | @ | ||
509 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
510 | add r12, r7, r7, asl #2 @ | ||
511 | add r12, r12, r12, asl #4 @ | ||
512 | add r7, r12, r7, asl #6 @ | ||
513 | @ compute R, G, and B | ||
514 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
515 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
516 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
517 | @ | ||
518 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256 | ||
519 | add r3, r12, r3, lsr #8 @ | ||
520 | @ | ||
521 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
522 | add r11, r12, r11, lsr #8 @ | ||
523 | @ | ||
524 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
525 | add r7, r12, r7, lsr #8 @ | ||
526 | @ | ||
527 | add r12, r14, #0x300 @ | ||
528 | @ | ||
529 | add r3, r3, r12 @ b = r3 + delta | ||
530 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
531 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
532 | @ | ||
533 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
534 | orr r12, r12, r7 @ ...at all | ||
535 | movs r12, r12, asr #15 @ | ||
536 | beq 15f @ no clamp @ | ||
537 | movs r12, r3, asr #15 @ clamp b | ||
538 | mvnne r3, r12, lsr #15 @ | ||
539 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
540 | movs r12, r11, asr #16 @ clamp r | ||
541 | mvnne r11, r12, lsr #16 @ | ||
542 | movs r12, r7, asr #15 @ clamp g | ||
543 | mvnne r7, r12, lsr #15 @ | ||
544 | 15: @ no clamp @ | ||
545 | @ | ||
546 | and r11, r11, #0xf800 @ pack pixel | ||
547 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
548 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
549 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
550 | @ | ||
551 | mov r11, #LCD2_DATA_MASK @ store pixel | ||
552 | orr r7, r11, r3, lsr #8 @ | ||
553 | orr r11, r11, r3 @ | ||
554 | 20: @ | ||
555 | ldr r3, [r0] @ | ||
556 | tst r3, #LCD2_BUSY_MASK @ | ||
557 | bne 20b @ | ||
558 | str r7, [r0] @ | ||
559 | 20: @ | ||
560 | ldr r3, [r0] @ | ||
561 | tst r3, #LCD2_BUSY_MASK @ | ||
562 | bne 20b @ | ||
563 | str r11, [r0] @ | ||
564 | @ | ||
565 | subs r1, r1, #2 @ subtract block from width | ||
566 | bgt 10b @ loop line @ | ||
567 | @ | ||
568 | ldmpc regs=r4-r11 @ restore registers and return | ||
569 | .ltorg @ dump constant pool | ||
570 | .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither | ||
diff --git a/firmware/target/arm/philips/hdd1630/lcd-hdd1630.c b/firmware/target/arm/philips/hdd1630/lcd-hdd1630.c index d9570600bc..c26c0bc963 100644 --- a/firmware/target/arm/philips/hdd1630/lcd-hdd1630.c +++ b/firmware/target/arm/philips/hdd1630/lcd-hdd1630.c | |||
@@ -81,6 +81,7 @@ | |||
81 | static bool lcd_enabled; | 81 | static bool lcd_enabled; |
82 | 82 | ||
83 | /* Display status */ | 83 | /* Display status */ |
84 | static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0; | ||
84 | static unsigned mad_ctrl = 0; | 85 | static unsigned mad_ctrl = 0; |
85 | 86 | ||
86 | /* wait for LCD */ | 87 | /* wait for LCD */ |
@@ -312,6 +313,86 @@ void lcd_set_flip(bool yesno) | |||
312 | lcd_send_data(mad_ctrl); | 313 | lcd_send_data(mad_ctrl); |
313 | } | 314 | } |
314 | 315 | ||
316 | void lcd_yuv_set_options(unsigned options) | ||
317 | { | ||
318 | lcd_yuv_options = options; | ||
319 | } | ||
320 | |||
321 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ | ||
322 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
323 | int width, int stride); | ||
324 | |||
325 | extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
326 | int width, int stride, | ||
327 | int x_screen, int y_screen); | ||
328 | |||
329 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
330 | void lcd_blit_yuv(unsigned char * const src[3], | ||
331 | int src_x, int src_y, int stride, | ||
332 | int x, int y, int width, int height) | ||
333 | { | ||
334 | unsigned char const * yuv_src[3]; | ||
335 | off_t z; | ||
336 | |||
337 | /* Sorry, but width and height must be >= 2 or else */ | ||
338 | width &= ~1; | ||
339 | height >>= 1; | ||
340 | |||
341 | z = stride*src_y; | ||
342 | yuv_src[0] = src[0] + z + src_x; | ||
343 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
344 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
345 | |||
346 | /* Set vertical address mode */ | ||
347 | lcd_send_cmd(MADCTR); | ||
348 | lcd_send_data(mad_ctrl | (1<<5)); | ||
349 | |||
350 | lcd_send_cmd(RASET); | ||
351 | lcd_send_data(x); | ||
352 | lcd_send_data(x + width - 1); | ||
353 | |||
354 | if (lcd_yuv_options & LCD_YUV_DITHER) | ||
355 | { | ||
356 | do | ||
357 | { | ||
358 | lcd_send_cmd(CASET); | ||
359 | lcd_send_data(y); | ||
360 | lcd_send_data(y + 1); | ||
361 | |||
362 | lcd_send_cmd(RAMWR); | ||
363 | |||
364 | lcd_write_yuv420_lines_odither(yuv_src, width, stride, x, y); | ||
365 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
366 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
367 | yuv_src[2] += stride >> 1; | ||
368 | y += 2; | ||
369 | } | ||
370 | while (--height > 0); | ||
371 | } | ||
372 | else | ||
373 | { | ||
374 | do | ||
375 | { | ||
376 | lcd_send_cmd(CASET); | ||
377 | lcd_send_data(y); | ||
378 | lcd_send_data(y + 1); | ||
379 | |||
380 | lcd_send_cmd(RAMWR); | ||
381 | |||
382 | lcd_write_yuv420_lines(yuv_src, width, stride); | ||
383 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
384 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
385 | yuv_src[2] += stride >> 1; | ||
386 | y += 2; | ||
387 | } | ||
388 | while (--height > 0); | ||
389 | } | ||
390 | |||
391 | /* Restore the address mode */ | ||
392 | lcd_send_cmd(MADCTR); | ||
393 | lcd_send_data(mad_ctrl); | ||
394 | } | ||
395 | |||
315 | /* Update the display. | 396 | /* Update the display. |
316 | This must be called after all other LCD functions that change the display. */ | 397 | This must be called after all other LCD functions that change the display. */ |
317 | void lcd_update(void) | 398 | void lcd_update(void) |
diff --git a/firmware/target/arm/philips/hdd6330/lcd-as-hdd6330.S b/firmware/target/arm/philips/hdd6330/lcd-as-hdd6330.S new file mode 100644 index 0000000000..c3a7992a2e --- /dev/null +++ b/firmware/target/arm/philips/hdd6330/lcd-as-hdd6330.S | |||
@@ -0,0 +1,140 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id:$ | ||
9 | * | ||
10 | * Copyright (C) 2010 by Szymon Dziok | ||
11 | * | ||
12 | * Philips Gogear HDD6330 LCD assembly routine | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | #include "config.h" | ||
25 | #include "cpu.h" | ||
26 | |||
27 | /**************************************************************************** | ||
28 | void lcd_yuv_write_inner_loop(unsigned char const * const ysrc, | ||
29 | unsigned char const * const usrc, | ||
30 | unsigned char const * const vsrc, | ||
31 | int width); | ||
32 | */ | ||
33 | .section .icode, "ax", %progbits | ||
34 | .align 2 | ||
35 | .global lcd_yuv_write_inner_loop | ||
36 | .type lcd_yuv_write_inner_loop, %function | ||
37 | lcd_yuv_write_inner_loop: | ||
38 | @ r0 = ysrc | ||
39 | @ r1 = usrc | ||
40 | @ r2 = vsrc | ||
41 | @ r3 = width | ||
42 | stmfd sp!, { r4-r11, lr } @ save regs | ||
43 | mov r4, #0x70000000 @ r4 = LCD2_BLOCK_CTRL - 0x20 | ||
44 | add r4, r4, #0x8a00 @ | ||
45 | add r5, r4, #0x100 @ r5 = LCD2_BLOCK_DATA | ||
46 | 10: @ loop | ||
47 | |||
48 | ldrb r7, [r1], #1 @ *usrc++ | ||
49 | ldrb r8, [r2], #1 @ *vsrc++ | ||
50 | |||
51 | sub r7, r7, #128 @ Cb -= 128 | ||
52 | sub r8, r8, #128 @ Cr -= 128 | ||
53 | |||
54 | add r10, r8, r8, asl #2 @ Cr*101 | ||
55 | add r10, r10, r8, asl #5 | ||
56 | add r10, r10, r8, asl #6 | ||
57 | |||
58 | add r11, r8, r8, asl #1 @ Cr*51 + Cb*24 | ||
59 | add r11, r11, r11, asl #4 | ||
60 | add r11, r11, r7, asl #3 | ||
61 | add r11, r11, r7, asl #4 | ||
62 | |||
63 | add r12, r7, #2 @ r12 = bu = (Cb*128 + 256) >> 9 | ||
64 | mov r12, r12, asr #2 | ||
65 | add r10, r10, #256 @ r10 = rv = (Cr*101 + 256) >> 9 | ||
66 | mov r10, r10, asr #9 | ||
67 | rsb r11, r11, #128 @ r11 = guv = (-r11 + 128) >> 8 | ||
68 | mov r11, r11, asr #8 | ||
69 | |||
70 | @ pixel_1 | ||
71 | ldrb r7, [r0], #1 @ *ysrc++ | ||
72 | sub r7, r7, #16 @ Y = (Y' - 16) * 37 | ||
73 | add r8, r7, r7, asl #2 | ||
74 | add r7, r8, r7, asl #5 | ||
75 | |||
76 | add r9, r10, r7, asr #8 @ R = (Y >> 8) + rv | ||
77 | add r8, r11, r7, asr #7 @ G = (Y >> 7) + guv | ||
78 | add r7, r12, r7, asr #8 @ B = (Y >> 8) + bu | ||
79 | |||
80 | cmp r9, #31 @ clamp R | ||
81 | mvnhi r9, r9, asr #31 | ||
82 | andhi r9, r9, #31 | ||
83 | |||
84 | cmp r8, #63 @ clamp G | ||
85 | mvnhi r8, r8, asr #31 | ||
86 | andhi r8, r8, #63 | ||
87 | |||
88 | cmp r7, #31 @ clamp B | ||
89 | mvnhi r7, r7, asr #31 | ||
90 | andhi r7, r7, #31 | ||
91 | |||
92 | orr r6, r7, r8, lsl #5 @ pack pixel | ||
93 | orr r6, r6, r9, lsl #11 | ||
94 | |||
95 | mov r7, r6, lsl #8 @ swap bytes | ||
96 | and r7, r7, #0xff00 | ||
97 | add r6, r7, r6, lsr #8 | ||
98 | |||
99 | @ pixel_2 | ||
100 | ldrb r7, [r0], #1 @ *ysrc++ | ||
101 | sub r7, r7, #16 @ Y = (Y' - 16) * 37 | ||
102 | add r8, r7, r7, asl #2 | ||
103 | add r7, r8, r7, asl #5 | ||
104 | |||
105 | add r9, r10, r7, asr #8 @ R = (Y >> 8) + rv | ||
106 | add r8, r11, r7, asr #7 @ G = (Y >> 7) + guv | ||
107 | add r7, r12, r7, asr #8 @ B = (Y >> 8) + bu | ||
108 | |||
109 | cmp r9, #31 @ clamp R | ||
110 | mvnhi r9, r9, asr #31 | ||
111 | andhi r9, r9, #31 | ||
112 | |||
113 | cmp r8, #63 @ clamp G | ||
114 | mvnhi r8, r8, asr #31 | ||
115 | andhi r8, r8, #63 | ||
116 | |||
117 | cmp r7, #31 @ clamp B | ||
118 | mvnhi r7, r7, asr #31 | ||
119 | andhi r7, r7, #31 | ||
120 | |||
121 | orr r7, r7, r8, lsl #5 @ pack pixel | ||
122 | orr r7, r7, r9, lsl #11 | ||
123 | |||
124 | orr r6, r6, r7, lsl #24 @ swap bytes and add pixels simultaneously | ||
125 | mov r7, r7, lsr #8 | ||
126 | orr r6, r6, r7, lsl #16 | ||
127 | |||
128 | 11: @ while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_TXOK)); | ||
129 | ldr r11, [r4, #0x20] @ | ||
130 | tst r11, #0x1000000 @ | ||
131 | beq 11b @ | ||
132 | |||
133 | str r6, [r5] @ send two pixels | ||
134 | |||
135 | subs r3, r3, #2 @ decrease width | ||
136 | bgt 10b @ loop | ||
137 | |||
138 | ldmpc regs=r4-r11 @ restore regs | ||
139 | .ltorg @ dump constant pool | ||
140 | .size lcd_yuv_write_inner_loop, .-lcd_yuv_write_inner_loop | ||
diff --git a/firmware/target/arm/philips/hdd6330/lcd-hdd6330.c b/firmware/target/arm/philips/hdd6330/lcd-hdd6330.c index 9d2fdc8519..cdd3064bba 100644 --- a/firmware/target/arm/philips/hdd6330/lcd-hdd6330.c +++ b/firmware/target/arm/philips/hdd6330/lcd-hdd6330.c | |||
@@ -37,6 +37,9 @@ | |||
37 | /* whether the lcd is currently enabled or not */ | 37 | /* whether the lcd is currently enabled or not */ |
38 | static bool lcd_enabled; | 38 | static bool lcd_enabled; |
39 | 39 | ||
40 | /* Display status */ | ||
41 | static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0; | ||
42 | |||
40 | /* Value used for flipping. Must be remembered when display is turned off. */ | 43 | /* Value used for flipping. Must be remembered when display is turned off. */ |
41 | static unsigned short flip; | 44 | static unsigned short flip; |
42 | 45 | ||
@@ -144,6 +147,101 @@ void lcd_set_flip(bool yesno) | |||
144 | lcd_send_data(0x08 | flip); | 147 | lcd_send_data(0x08 | flip); |
145 | } | 148 | } |
146 | 149 | ||
150 | void lcd_yuv_set_options(unsigned options) | ||
151 | { | ||
152 | lcd_yuv_options = options; | ||
153 | } | ||
154 | |||
155 | #define CSUB_X 2 | ||
156 | #define CSUB_Y 2 | ||
157 | |||
158 | /* YUV- > RGB565 conversion | ||
159 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
160 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
161 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
162 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
163 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
164 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
165 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
166 | */ | ||
167 | |||
168 | extern void lcd_yuv_write_inner_loop(unsigned char const * const ysrc, | ||
169 | unsigned char const * const usrc, | ||
170 | unsigned char const * const vsrc, | ||
171 | int width); | ||
172 | |||
173 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
174 | void lcd_blit_yuv(unsigned char * const src[3], | ||
175 | int src_x, int src_y, int stride, | ||
176 | int x, int y, int width, int height) | ||
177 | { | ||
178 | int h; | ||
179 | |||
180 | width = (width + 1) & ~1; | ||
181 | |||
182 | lcd_send_reg(LCD_REG_HORIZ_ADDR_START); | ||
183 | lcd_send_data(y); | ||
184 | |||
185 | lcd_send_reg(LCD_REG_HORIZ_ADDR_END); | ||
186 | lcd_send_data(y + height - 1); | ||
187 | |||
188 | lcd_send_reg(LCD_REG_VERT_ADDR_START); | ||
189 | lcd_send_data(x + x_offset); | ||
190 | |||
191 | lcd_send_reg(LCD_REG_VERT_ADDR_END); | ||
192 | lcd_send_data(x + width - 1 + x_offset); | ||
193 | |||
194 | lcd_send_reg(LCD_REG_WRITE_DATA_2_GRAM); | ||
195 | |||
196 | const int stride_div_csub_x = stride/CSUB_X; | ||
197 | |||
198 | h=0; | ||
199 | while (1) | ||
200 | { | ||
201 | /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ | ||
202 | const unsigned char *ysrc = src[0] + stride * src_y + src_x; | ||
203 | |||
204 | const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) + | ||
205 | (src_x/CSUB_X); | ||
206 | |||
207 | const unsigned char *usrc = src[1] + uvoffset; | ||
208 | const unsigned char *vsrc = src[2] + uvoffset; | ||
209 | |||
210 | int pixels_to_write; | ||
211 | |||
212 | if (h==0) | ||
213 | { | ||
214 | while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY)); | ||
215 | LCD2_BLOCK_CONFIG = 0; | ||
216 | |||
217 | if (height == 0) break; | ||
218 | |||
219 | pixels_to_write = (width * height) * 2; | ||
220 | h = height; | ||
221 | |||
222 | /* calculate how much we can do in one go */ | ||
223 | if (pixels_to_write > 0x10000) | ||
224 | { | ||
225 | h = (0x10000/2) / width; | ||
226 | pixels_to_write = (width * h) * 2; | ||
227 | } | ||
228 | |||
229 | height -= h; | ||
230 | LCD2_BLOCK_CTRL = 0x10000080; | ||
231 | LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1); | ||
232 | LCD2_BLOCK_CTRL = 0x34000000; | ||
233 | } | ||
234 | |||
235 | lcd_yuv_write_inner_loop(ysrc,usrc,vsrc,width); | ||
236 | |||
237 | src_y++; | ||
238 | h--; | ||
239 | } | ||
240 | |||
241 | while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY)); | ||
242 | LCD2_BLOCK_CONFIG = 0; | ||
243 | } | ||
244 | |||
147 | /* Update the display. | 245 | /* Update the display. |
148 | This must be called after all other LCD functions that change the display. */ | 246 | This must be called after all other LCD functions that change the display. */ |
149 | void lcd_update(void) | 247 | void lcd_update(void) |
diff --git a/firmware/target/arm/philips/sa9200/lcd-as-sa9200.S b/firmware/target/arm/philips/sa9200/lcd-as-sa9200.S new file mode 100644 index 0000000000..d99222b9df --- /dev/null +++ b/firmware/target/arm/philips/sa9200/lcd-as-sa9200.S | |||
@@ -0,0 +1,590 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007-2011 by Michael Sevakis | ||
11 | * | ||
12 | * Philips GoGear SA9200 LCD assembly routines | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | /* This code should work in general for a Renesas type LCD interface | ||
25 | * connected to the "mono" bridge. TODO: Share it where possible. | ||
26 | * | ||
27 | * Dither is already prepared to be built for upright and rotated | ||
28 | * orientations. */ | ||
29 | |||
30 | #include "config.h" | ||
31 | #include "cpu.h" | ||
32 | |||
33 | /**************************************************************************** | ||
34 | * void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
35 | * int width, | ||
36 | * int stride); | ||
37 | * | ||
38 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
39 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
40 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
41 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
42 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
43 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
44 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
45 | * | ||
46 | * Write four RGB565 pixels in the following order on each loop: | ||
47 | * 1 3 + > down | ||
48 | * 2 4 \/ left | ||
49 | */ | ||
50 | .section .icode, "ax", %progbits | ||
51 | .align 2 | ||
52 | .global lcd_write_yuv420_lines | ||
53 | .type lcd_write_yuv420_lines, %function | ||
54 | lcd_write_yuv420_lines: | ||
55 | @ r0 = yuv_src | ||
56 | @ r1 = width | ||
57 | @ r2 = stride | ||
58 | stmfd sp!, { r4-r10, lr } @ save non-scratch | ||
59 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
60 | @ r5 = yuv_src[1] = Cb_p | ||
61 | @ r6 = yuv_src[2] = Cr_p | ||
62 | @ | ||
63 | mov r0, #0x70000000 @ r0 = LCD1_BASE_ADDR = 0x70003000 | ||
64 | orr r0, r0, #0x3000 @ | ||
65 | @ | ||
66 | sub r2, r2, #1 @ Adjust stride because of increment | ||
67 | 10: @ loop line @ | ||
68 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
69 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
70 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
71 | @ | ||
72 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 | ||
73 | add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right | ||
74 | add r7, r12, r7, asl #5 @ by one less when adding - same for all | ||
75 | @ | ||
76 | sub r8, r8, #128 @ Cb -= 128 | ||
77 | sub r9, r9, #128 @ Cr -= 128 | ||
78 | @ | ||
79 | add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 | ||
80 | add r10, r10, r10, asl #4 @ | ||
81 | add r10, r10, r8, asl #3 @ | ||
82 | add r10, r10, r8, asl #4 @ | ||
83 | @ | ||
84 | add r14, r9, r9, asl #2 @ r9 = Cr*101 | ||
85 | add r14, r14, r9, asl #5 @ | ||
86 | add r9, r14, r9, asl #6 @ | ||
87 | @ | ||
88 | add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 | ||
89 | mov r8, r8, asr #2 @ | ||
90 | add r9, r9, #256 @ r9 = rv = (r8 + 256) >> 9 | ||
91 | mov r9, r9, asr #9 @ | ||
92 | rsb r10, r10, #128 @ r10 = guv = (-r9 + 128) >> 8 | ||
93 | mov r10, r10, asr #8 @ | ||
94 | @ compute R, G, and B | ||
95 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
96 | add r14, r9, r7, asr #8 @ r14 = r = (Y >> 9) + rv | ||
97 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
98 | @ | ||
99 | orr r12, r3, r14 @ check if clamping is needed... | ||
100 | orr r12, r12, r7, asr #1 @ ...at all | ||
101 | cmp r12, #31 @ | ||
102 | bls 15f @ no clamp @ | ||
103 | cmp r3, #31 @ clamp b | ||
104 | mvnhi r3, r3, asr #31 @ | ||
105 | andhi r3, r3, #31 @ | ||
106 | cmp r14, #31 @ clamp r | ||
107 | mvnhi r14, r14, asr #31 @ | ||
108 | andhi r14, r14, #31 @ | ||
109 | cmp r7, #63 @ clamp g | ||
110 | mvnhi r7, r7, asr #31 @ | ||
111 | andhi r7, r7, #63 @ | ||
112 | 15: @ no clamp @ | ||
113 | @ | ||
114 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
115 | @ | ||
116 | orr r7, r3, r7, lsl #5 @ r7 = |00000000|00000000|00000ggg|gggbbbbb| | ||
117 | orr r7, r7, r14, lsl #11 @ r7 = |00000000|00000000|rrrrrggg|gggbbbbb| | ||
118 | mov r14, r7, lsr #8 @ r14 = |00000000|00000000|00000000|rrrrrggg| | ||
119 | @ | ||
120 | 20: @ | ||
121 | ldr r3, [r0] @ | ||
122 | tst r3, #LCD1_BUSY_MASK @ | ||
123 | bne 20b @ | ||
124 | strb r14, [r0, #0x10] @ | ||
125 | 20: @ | ||
126 | ldr r3, [r0] @ | ||
127 | tst r3, #LCD1_BUSY_MASK @ | ||
128 | bne 20b @ | ||
129 | strb r7, [r0, #0x10] @ | ||
130 | @ | ||
131 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
132 | add r12, r7, r7, asl #2 @ | ||
133 | add r7, r12, r7, asl #5 @ | ||
134 | @ compute R, G, and B | ||
135 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
136 | add r14, r9, r7, asr #8 @ r14 = r = (Y >> 9) + rv | ||
137 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
138 | @ | ||
139 | orr r12, r3, r14 @ check if clamping is needed... | ||
140 | orr r12, r12, r7, asr #1 @ ...at all | ||
141 | cmp r12, #31 @ | ||
142 | bls 15f @ no clamp @ | ||
143 | cmp r3, #31 @ clamp b | ||
144 | mvnhi r3, r3, asr #31 @ | ||
145 | andhi r3, r3, #31 @ | ||
146 | cmp r14, #31 @ clamp r | ||
147 | mvnhi r14, r14, asr #31 @ | ||
148 | andhi r14, r14, #31 @ | ||
149 | cmp r7, #63 @ clamp g | ||
150 | mvnhi r7, r7, asr #31 @ | ||
151 | andhi r7, r7, #63 @ | ||
152 | 15: @ no clamp @ | ||
153 | @ | ||
154 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
155 | @ | ||
156 | orr r7, r3, r7, lsl #5 @ r7 = |00000000|00000000|00000ggg|gggbbbbb| | ||
157 | orr r7, r7, r14, lsl #11 @ r7 = |00000000|00000000|rrrrrggg|gggbbbbb| | ||
158 | mov r14, r7, lsr #8 @ r14 = |00000000|00000000|00000000|rrrrrggg| | ||
159 | 20: @ | ||
160 | ldr r3, [r0] @ | ||
161 | tst r3, #LCD1_BUSY_MASK @ | ||
162 | bne 20b @ | ||
163 | strb r14, [r0, #0x10] @ | ||
164 | 20: @ | ||
165 | ldr r3, [r0] @ | ||
166 | tst r3, #LCD1_BUSY_MASK @ | ||
167 | bne 20b @ | ||
168 | strb r7, [r0, #0x10] @ | ||
169 | @ | ||
170 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
171 | add r12, r7, r7, asl #2 @ | ||
172 | add r7, r12, r7, asl #5 @ | ||
173 | @ compute R, G, and B | ||
174 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
175 | add r14, r9, r7, asr #8 @ r14 = r = (Y >> 9) + rv | ||
176 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
177 | @ | ||
178 | orr r12, r3, r14 @ check if clamping is needed... | ||
179 | orr r12, r12, r7, asr #1 @ ...at all | ||
180 | cmp r12, #31 @ | ||
181 | bls 15f @ no clamp @ | ||
182 | cmp r3, #31 @ clamp b | ||
183 | mvnhi r3, r3, asr #31 @ | ||
184 | andhi r3, r3, #31 @ | ||
185 | cmp r14, #31 @ clamp r | ||
186 | mvnhi r14, r14, asr #31 @ | ||
187 | andhi r14, r14, #31 @ | ||
188 | cmp r7, #63 @ clamp g | ||
189 | mvnhi r7, r7, asr #31 @ | ||
190 | andhi r7, r7, #63 @ | ||
191 | 15: @ no clamp @ | ||
192 | @ | ||
193 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
194 | @ | ||
195 | orr r7, r3, r7, lsl #5 @ r7 = |00000000|00000000|00000ggg|gggbbbbb| | ||
196 | orr r7, r7, r14, lsl #11 @ r7 = |00000000|00000000|rrrrrggg|gggbbbbb| | ||
197 | mov r14, r7, lsr #8 @ r14 = |00000000|00000000|00000000|rrrrrggg| | ||
198 | 20: @ | ||
199 | ldr r3, [r0] @ | ||
200 | tst r3, #LCD1_BUSY_MASK @ | ||
201 | bne 20b @ | ||
202 | strb r14, [r0, #0x10] @ | ||
203 | 20: @ | ||
204 | ldr r3, [r0] @ | ||
205 | tst r3, #LCD1_BUSY_MASK @ | ||
206 | bne 20b @ | ||
207 | strb r7, [r0, #0x10] @ | ||
208 | @ | ||
209 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
210 | add r12, r7, r7, asl #2 @ | ||
211 | add r7, r12, r7, asl #5 @ | ||
212 | @ compute R, G, and B | ||
213 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
214 | add r14, r9, r7, asr #8 @ r14 = r = (Y >> 9) + rv | ||
215 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
216 | @ | ||
217 | orr r12, r3, r14 @ check if clamping is needed... | ||
218 | orr r12, r12, r7, asr #1 @ ...at all | ||
219 | cmp r12, #31 @ | ||
220 | bls 15f @ no clamp @ | ||
221 | cmp r3, #31 @ clamp b | ||
222 | mvnhi r3, r3, asr #31 @ | ||
223 | andhi r3, r3, #31 @ | ||
224 | cmp r14, #31 @ clamp r | ||
225 | mvnhi r14, r14, asr #31 @ | ||
226 | andhi r14, r14, #31 @ | ||
227 | cmp r7, #63 @ clamp g | ||
228 | mvnhi r7, r7, asr #31 @ | ||
229 | andhi r7, r7, #63 @ | ||
230 | 15: @ no clamp @ | ||
231 | @ | ||
232 | orr r7, r3, r7, lsl #5 @ r7 = |00000000|00000000|00000ggg|gggbbbbb| | ||
233 | orr r7, r7, r14, lsl #11 @ r7 = |00000000|00000000|rrrrrggg|gggbbbbb| | ||
234 | mov r14, r7, lsr #8 @ r14 = |00000000|00000000|00000000|rrrrrggg| | ||
235 | 20: @ | ||
236 | ldr r3, [r0] @ | ||
237 | tst r3, #LCD1_BUSY_MASK @ | ||
238 | bne 20b @ | ||
239 | strb r14, [r0, #0x10] @ | ||
240 | 20: @ | ||
241 | ldr r3, [r0] @ | ||
242 | tst r3, #LCD1_BUSY_MASK @ | ||
243 | bne 20b @ | ||
244 | strb r7, [r0, #0x10] @ | ||
245 | @ | ||
246 | subs r1, r1, #2 @ subtract block from width | ||
247 | bgt 10b @ loop line @ | ||
248 | @ | ||
249 | ldmpc regs=r4-r10 @ restore registers and return | ||
250 | .ltorg @ dump constant pool | ||
251 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
252 | |||
253 | |||
254 | /**************************************************************************** | ||
255 | * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
256 | * int width, | ||
257 | * int stride, | ||
258 | * int x_screen, | ||
259 | * int y_screen); | ||
260 | * | ||
261 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
262 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
263 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
264 | * Red scaled at twice g & b but at same precision to place it in correct | ||
265 | * bit position after multiply and leave instruction count lower. | ||
266 | * |R| |258 0 408| |Y' - 16| | ||
267 | * |G| = |149 -49 -104| |Cb - 128| | ||
268 | * |B| |149 258 0| |Cr - 128| | ||
269 | * | ||
270 | * Write four RGB565 pixels in the following order on each loop: | ||
271 | * 1 3 + > right/down | ||
272 | * 2 4 \/ down/left | ||
273 | * | ||
274 | * Kernel pattern for upright display: | ||
275 | * 5 3 4 2 +-> right | ||
276 | * 1 7 0 6 | down | ||
277 | * 4 2 5 3 \/ | ||
278 | * 0 6 1 7 | ||
279 | * | ||
280 | * Kernel pattern for clockwise rotated display: | ||
281 | * 2 6 3 7 +-> down | ||
282 | * 4 0 5 1 | left | ||
283 | * 3 7 2 6 \/ | ||
284 | * 5 1 4 0 | ||
285 | */ | ||
286 | .section .icode, "ax", %progbits | ||
287 | .align 2 | ||
288 | .global lcd_write_yuv420_lines_odither | ||
289 | .type lcd_write_yuv420_lines_odither, %function | ||
290 | lcd_write_yuv420_lines_odither: | ||
291 | @ r0 = yuv_src | ||
292 | @ r1 = width | ||
293 | @ r2 = strideS | ||
294 | @ r3 = x_screen | ||
295 | @ [sp] = y_screen | ||
296 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
297 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
298 | @ r5 = yuv_src[1] = Cb_p | ||
299 | @ r6 = yuv_src[2] = Cr_p | ||
300 | @ | ||
301 | ldr r0, [sp, #36] @ Line up pattern and kernel quadrant | ||
302 | eor r14, r3, r0 @ | ||
303 | and r14, r14, #0x2 @ | ||
304 | mov r14, r14, lsl #6 @ 0x00 or 0x80 | ||
305 | @ | ||
306 | mov r0, #0x70000000 @ r0 = LCD1_BASE_ADDR = 0x70003000 | ||
307 | orr r0, r0, #0x3000 @ | ||
308 | @ | ||
309 | sub r2, r2, #1 @ Adjust stride because of increment | ||
310 | 10: @ loop line @ | ||
311 | @ | ||
312 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
313 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
314 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
315 | @ | ||
316 | eor r14, r14, #0x80 @ flip pattern quadrant | ||
317 | @ | ||
318 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149 | ||
319 | add r12, r7, r7, asl #2 @ | ||
320 | add r12, r12, r12, asl #4 @ | ||
321 | add r7, r12, r7, asl #6 @ | ||
322 | @ | ||
323 | sub r8, r8, #128 @ Cb -= 128 | ||
324 | sub r9, r9, #128 @ Cr -= 128 | ||
325 | @ | ||
326 | add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49 | ||
327 | add r10, r10, r8, asl #5 @ | ||
328 | add r10, r10, r9, asl #3 @ | ||
329 | add r10, r10, r9, asl #5 @ | ||
330 | add r10, r10, r9, asl #6 @ | ||
331 | @ | ||
332 | mov r8, r8, asl #1 @ r8 = bu = Cb*258 | ||
333 | add r8, r8, r8, asl #7 @ | ||
334 | @ | ||
335 | add r9, r9, r9, asl #1 @ r9 = rv = Cr*408 | ||
336 | add r9, r9, r9, asl #4 @ | ||
337 | mov r9, r9, asl #3 @ | ||
338 | @ | ||
339 | @ compute R, G, and B | ||
340 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
341 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
342 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
343 | @ | ||
344 | @ r8 = bu, r9 = rv, r10 = guv | ||
345 | @ | ||
346 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256 | ||
347 | add r3, r12, r3, lsr #8 @ | ||
348 | @ | ||
349 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
350 | add r11, r12, r11, lsr #8 @ | ||
351 | @ | ||
352 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
353 | add r7, r12, r7, lsr #8 @ | ||
354 | @ | ||
355 | #if LCD_WIDTH >= LCD_HEIGHT | ||
356 | add r12, r14, #0x200 @ | ||
357 | #else | ||
358 | add r12, r14, #0x100 @ | ||
359 | #endif | ||
360 | @ | ||
361 | add r3, r3, r12 @ b = r3 + delta | ||
362 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
363 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
364 | @ | ||
365 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
366 | orr r12, r12, r7 @ ...at all | ||
367 | movs r12, r12, asr #15 @ | ||
368 | beq 15f @ no clamp @ | ||
369 | movs r12, r3, asr #15 @ clamp b | ||
370 | mvnne r3, r12, lsr #15 @ | ||
371 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
372 | movs r12, r11, asr #16 @ clamp r | ||
373 | mvnne r11, r12, lsr #16 @ | ||
374 | movs r12, r7, asr #15 @ clamp g | ||
375 | mvnne r7, r12, lsr #15 @ | ||
376 | 15: @ no clamp @ | ||
377 | @ | ||
378 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
379 | @ | ||
380 | and r11, r11, #0xf800 @ r11 = |00000000|00000000|rrrrrggg|gggbbbbb| | ||
381 | and r7, r7, #0x7e00 @ | ||
382 | orr r11, r11, r7, lsr #4 @ | ||
383 | orr r11, r11, r3, lsr #10 @ | ||
384 | mov r7, r11, lsr #8 @ r7 = |00000000|00000000|00000000|rrrrrggg| | ||
385 | @ | ||
386 | 20: @ | ||
387 | ldr r3, [r0] @ | ||
388 | tst r3, #LCD1_BUSY_MASK @ | ||
389 | bne 20b @ | ||
390 | strb r7, [r0, #0x10] @ | ||
391 | 20: @ | ||
392 | ldr r3, [r0] @ | ||
393 | tst r3, #LCD1_BUSY_MASK @ | ||
394 | bne 20b @ | ||
395 | strb r11, [r0, #0x10] @ | ||
396 | @ | ||
397 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
398 | add r12, r7, r7, asl #2 @ | ||
399 | add r12, r12, r12, asl #4 @ | ||
400 | add r7, r12, r7, asl #6 @ | ||
401 | @ compute R, G, and B | ||
402 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
403 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
404 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
405 | @ | ||
406 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256 | ||
407 | add r3, r12, r3, lsr #8 @ | ||
408 | @ | ||
409 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
410 | add r11, r12, r11, lsr #8 @ | ||
411 | @ | ||
412 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
413 | add r7, r12, r7, lsr #8 @ | ||
414 | @ | ||
415 | #if LCD_WIDTH >= LCD_HEIGHT | ||
416 | @ This element is zero - use r14 @ | ||
417 | @ | ||
418 | add r3, r3, r14 @ b = r3 + delta | ||
419 | add r11, r11, r14, lsl #1 @ r = r11 + delta*2 | ||
420 | add r7, r7, r14, lsr #1 @ g = r7 + delta/2 | ||
421 | #else | ||
422 | add r12, r14, #0x200 @ | ||
423 | @ | ||
424 | add r3, r3, r12 @ b = r3 + delta | ||
425 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
426 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
427 | #endif | ||
428 | @ | ||
429 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
430 | orr r12, r12, r7 @ ...at all | ||
431 | movs r12, r12, asr #15 @ | ||
432 | beq 15f @ no clamp @ | ||
433 | movs r12, r3, asr #15 @ clamp b | ||
434 | mvnne r3, r12, lsr #15 @ | ||
435 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
436 | movs r12, r11, asr #16 @ clamp r | ||
437 | mvnne r11, r12, lsr #16 @ | ||
438 | movs r12, r7, asr #15 @ clamp g | ||
439 | mvnne r7, r12, lsr #15 @ | ||
440 | 15: @ no clamp @ | ||
441 | @ | ||
442 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
443 | @ | ||
444 | and r11, r11, #0xf800 @ r11 = |00000000|00000000|rrrrrggg|gggbbbbb| | ||
445 | and r7, r7, #0x7e00 @ | ||
446 | orr r11, r11, r7, lsr #4 @ | ||
447 | orr r11, r11, r3, lsr #10 @ | ||
448 | mov r7, r11, lsr #8 @ r7 = |00000000|00000000|00000000|rrrrrggg| | ||
449 | @ | ||
450 | 20: @ | ||
451 | ldr r3, [r0] @ | ||
452 | tst r3, #LCD1_BUSY_MASK @ | ||
453 | bne 20b @ | ||
454 | strb r7, [r0, #0x10] @ | ||
455 | 20: @ | ||
456 | ldr r3, [r0] @ | ||
457 | tst r3, #LCD1_BUSY_MASK @ | ||
458 | bne 20b @ | ||
459 | strb r11, [r0, #0x10] @ | ||
460 | @ | ||
461 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
462 | add r12, r7, r7, asl #2 @ | ||
463 | add r12, r12, r12, asl #4 @ | ||
464 | add r7, r12, r7, asl #6 @ | ||
465 | @ compute R, G, and B | ||
466 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
467 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
468 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
469 | @ | ||
470 | @ r8 = bu, r9 = rv, r10 = guv | ||
471 | @ | ||
472 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256 | ||
473 | add r3, r12, r3, lsr #8 @ | ||
474 | @ | ||
475 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
476 | add r11, r12, r11, lsr #8 @ | ||
477 | @ | ||
478 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
479 | add r7, r12, r7, lsr #8 @ | ||
480 | @ | ||
481 | #if LCD_WIDTH >= LCD_HEIGHT | ||
482 | add r12, r14, #0x100 @ | ||
483 | #else | ||
484 | add r12, r14, #0x300 @ | ||
485 | #endif | ||
486 | @ | ||
487 | add r3, r3, r12 @ b = r3 + delta | ||
488 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
489 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
490 | @ | ||
491 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
492 | orr r12, r12, r7 @ ...at all | ||
493 | movs r12, r12, asr #15 @ | ||
494 | beq 15f @ no clamp @ | ||
495 | movs r12, r3, asr #15 @ clamp b | ||
496 | mvnne r3, r12, lsr #15 @ | ||
497 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
498 | movs r12, r11, asr #16 @ clamp r | ||
499 | mvnne r11, r12, lsr #16 @ | ||
500 | movs r12, r7, asr #15 @ clamp g | ||
501 | mvnne r7, r12, lsr #15 @ | ||
502 | 15: @ no clamp @ | ||
503 | @ | ||
504 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
505 | @ | ||
506 | and r11, r11, #0xf800 @ r11 = |00000000|00000000|rrrrrggg|gggbbbbb| | ||
507 | and r7, r7, #0x7e00 @ | ||
508 | orr r11, r11, r7, lsr #4 @ | ||
509 | orr r11, r11, r3, lsr #10 @ | ||
510 | mov r7, r11, lsr #8 @ r7 = |00000000|00000000|00000000|rrrrrggg| | ||
511 | @ | ||
512 | 20: @ | ||
513 | ldr r3, [r0] @ | ||
514 | tst r3, #LCD1_BUSY_MASK @ | ||
515 | bne 20b @ | ||
516 | strb r7, [r0, #0x10] @ | ||
517 | 20: @ | ||
518 | ldr r3, [r0] @ | ||
519 | tst r3, #LCD1_BUSY_MASK @ | ||
520 | bne 20b @ | ||
521 | strb r11, [r0, #0x10] @ | ||
522 | @ | ||
523 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
524 | add r12, r7, r7, asl #2 @ | ||
525 | add r12, r12, r12, asl #4 @ | ||
526 | add r7, r12, r7, asl #6 @ | ||
527 | @ compute R, G, and B | ||
528 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
529 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
530 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
531 | @ | ||
532 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256 | ||
533 | add r3, r12, r3, lsr #8 @ | ||
534 | @ | ||
535 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
536 | add r11, r12, r11, lsr #8 @ | ||
537 | @ | ||
538 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
539 | add r7, r12, r7, lsr #8 @ | ||
540 | @ | ||
541 | #if LCD_WIDTH >= LCD_HEIGHT | ||
542 | add r12, r14, #0x300 @ | ||
543 | @ | ||
544 | add r3, r3, r12 @ b = r3 + delta | ||
545 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
546 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
547 | #else | ||
548 | @ This element is zero - use r14 @ | ||
549 | @ | ||
550 | add r3, r3, r14 @ b = r3 + delta | ||
551 | add r11, r11, r14, lsl #1 @ r = r11 + delta*2 | ||
552 | add r7, r7, r14, lsr #1 @ g = r7 + delta/2 | ||
553 | #endif | ||
554 | @ | ||
555 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
556 | orr r12, r12, r7 @ ...at all | ||
557 | movs r12, r12, asr #15 @ | ||
558 | beq 15f @ no clamp @ | ||
559 | movs r12, r3, asr #15 @ clamp b | ||
560 | mvnne r3, r12, lsr #15 @ | ||
561 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
562 | movs r12, r11, asr #16 @ clamp r | ||
563 | mvnne r11, r12, lsr #16 @ | ||
564 | movs r12, r7, asr #15 @ clamp g | ||
565 | mvnne r7, r12, lsr #15 @ | ||
566 | 15: @ no clamp @ | ||
567 | @ | ||
568 | and r11, r11, #0xf800 @ r11 = |00000000|00000000|rrrrrggg|gggbbbbb| | ||
569 | and r7, r7, #0x7e00 @ | ||
570 | orr r11, r11, r7, lsr #4 @ | ||
571 | orr r11, r11, r3, lsr #10 @ | ||
572 | mov r7, r11, lsr #8 @ r7 = |00000000|00000000|00000000|rrrrrggg| | ||
573 | @ | ||
574 | 20: @ | ||
575 | ldr r3, [r0] @ | ||
576 | tst r3, #LCD1_BUSY_MASK @ | ||
577 | bne 20b @ | ||
578 | strb r7, [r0, #0x10] @ | ||
579 | 20: @ | ||
580 | ldr r3, [r0] @ | ||
581 | tst r3, #LCD1_BUSY_MASK @ | ||
582 | bne 20b @ | ||
583 | strb r11, [r0, #0x10] @ | ||
584 | @ | ||
585 | subs r1, r1, #2 @ subtract block from width | ||
586 | bgt 10b @ loop line @ | ||
587 | @ | ||
588 | ldmpc regs=r4-r11 @ restore registers and return | ||
589 | .ltorg @ dump constant pool | ||
590 | .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither | ||
diff --git a/firmware/target/arm/philips/sa9200/lcd-sa9200.c b/firmware/target/arm/philips/sa9200/lcd-sa9200.c index c6c297e6ca..e30a298045 100644 --- a/firmware/target/arm/philips/sa9200/lcd-sa9200.c +++ b/firmware/target/arm/philips/sa9200/lcd-sa9200.c | |||
@@ -75,6 +75,9 @@ static void lcd_display_off(void); | |||
75 | #define R_GATE_OUT_PERIOD_CTRL 0x71 | 75 | #define R_GATE_OUT_PERIOD_CTRL 0x71 |
76 | #define R_SOFTWARE_RESET 0x72 | 76 | #define R_SOFTWARE_RESET 0x72 |
77 | 77 | ||
78 | /* Display status */ | ||
79 | static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0; | ||
80 | |||
78 | /* wait for LCD */ | 81 | /* wait for LCD */ |
79 | static inline void lcd_wait_write(void) | 82 | static inline void lcd_wait_write(void) |
80 | { | 83 | { |
@@ -404,6 +407,85 @@ void lcd_set_flip(bool yesno) | |||
404 | lcd_write_reg(R_DRV_OUTPUT_CONTROL, flip ? 0x090c : 0x0a0c); | 407 | lcd_write_reg(R_DRV_OUTPUT_CONTROL, flip ? 0x090c : 0x0a0c); |
405 | } | 408 | } |
406 | 409 | ||
410 | void lcd_yuv_set_options(unsigned options) | ||
411 | { | ||
412 | lcd_yuv_options = options; | ||
413 | } | ||
414 | |||
415 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
416 | void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
417 | int width, | ||
418 | int stride); | ||
419 | void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
420 | int width, | ||
421 | int stride, | ||
422 | int x_screen, | ||
423 | int y_screen); | ||
424 | void lcd_blit_yuv(unsigned char * const src[3], | ||
425 | int src_x, int src_y, int stride, | ||
426 | int x, int y, int width, int height) | ||
427 | { | ||
428 | const unsigned char *yuv_src[3]; | ||
429 | const unsigned char *ysrc_max; | ||
430 | int options; | ||
431 | |||
432 | if (!display_on) | ||
433 | return; | ||
434 | |||
435 | width &= ~1; | ||
436 | height &= ~1; | ||
437 | |||
438 | /* calculate the drawing region */ | ||
439 | lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x); | ||
440 | |||
441 | /* convert YUV coordinates to screen coordinates */ | ||
442 | y = LCD_WIDTH - 1 - y; | ||
443 | |||
444 | /* 2px strip: cursor moves left, then down in gram */ | ||
445 | /* BGR=1, MDT1-0=00, I/D1-0=10, AM=0 */ | ||
446 | lcd_write_reg(R_ENTRY_MODE, 0x1020); | ||
447 | |||
448 | yuv_src[0] = src[0] + src_y * stride + src_x; | ||
449 | yuv_src[1] = src[1] + (src_y * stride >> 2) + (src_x >> 1); | ||
450 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
451 | ysrc_max = yuv_src[0] + height * stride; | ||
452 | |||
453 | /* cache options setting */ | ||
454 | options = lcd_yuv_options; | ||
455 | |||
456 | do | ||
457 | { | ||
458 | /* max horiz << 8 | start horiz */ | ||
459 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (y << 8) | (y - 1)); | ||
460 | |||
461 | /* position cursor (set AD0-AD15) */ | ||
462 | lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | y); | ||
463 | |||
464 | /* start drawing */ | ||
465 | lcd_send_command(R_WRITE_DATA_2_GRAM); | ||
466 | |||
467 | if (options & LCD_YUV_DITHER) | ||
468 | { | ||
469 | lcd_write_yuv420_lines_odither(yuv_src, width, stride, | ||
470 | y, x); | ||
471 | } | ||
472 | else | ||
473 | { | ||
474 | lcd_write_yuv420_lines(yuv_src, width, stride); | ||
475 | } | ||
476 | |||
477 | y -= 2; /* move strip by "down" 2 px */ | ||
478 | yuv_src[0] += stride << 1; | ||
479 | yuv_src[1] += stride >> 1; | ||
480 | yuv_src[2] += stride >> 1; | ||
481 | } | ||
482 | while (yuv_src[0] < ysrc_max); | ||
483 | |||
484 | /* back to normal right, then down cursor in gram */ | ||
485 | /* BGR=1, MDT1-0=00, I/D1-0=11, AM=0 */ | ||
486 | lcd_write_reg(R_ENTRY_MODE, 0x1030); | ||
487 | } | ||
488 | |||
407 | /* Update the display. | 489 | /* Update the display. |
408 | This must be called after all other LCD functions that change the display. */ | 490 | This must be called after all other LCD functions that change the display. */ |
409 | void lcd_update(void) | 491 | void lcd_update(void) |
diff --git a/firmware/target/arm/rk27xx/ihifi/lcd-ihifi.c b/firmware/target/arm/rk27xx/ihifi/lcd-ihifi.c index 9596dca98b..d5906b9dd5 100644 --- a/firmware/target/arm/rk27xx/ihifi/lcd-ihifi.c +++ b/firmware/target/arm/rk27xx/ihifi/lcd-ihifi.c | |||
@@ -207,3 +207,18 @@ bool lcd_active() | |||
207 | { | 207 | { |
208 | return display_on; | 208 | return display_on; |
209 | } | 209 | } |
210 | |||
211 | /* Blit a YUV bitmap directly to the LCD */ | ||
212 | void lcd_blit_yuv(unsigned char * const src[3], | ||
213 | int src_x, int src_y, int stride, | ||
214 | int x, int y, int width, int height) | ||
215 | { | ||
216 | (void)src; | ||
217 | (void)src_x; | ||
218 | (void)src_y; | ||
219 | (void)stride; | ||
220 | (void)x; | ||
221 | (void)y; | ||
222 | (void)width; | ||
223 | (void)height; | ||
224 | } | ||
diff --git a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c index cef0186de5..23505d9fa0 100644 --- a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c +++ b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c | |||
@@ -268,3 +268,18 @@ bool lcd_active() | |||
268 | { | 268 | { |
269 | return display_on; | 269 | return display_on; |
270 | } | 270 | } |
271 | |||
272 | /* Blit a YUV bitmap directly to the LCD */ | ||
273 | void lcd_blit_yuv(unsigned char * const src[3], | ||
274 | int src_x, int src_y, int stride, | ||
275 | int x, int y, int width, int height) | ||
276 | { | ||
277 | (void)src; | ||
278 | (void)src_x; | ||
279 | (void)src_y; | ||
280 | (void)stride; | ||
281 | (void)x; | ||
282 | (void)y; | ||
283 | (void)width; | ||
284 | (void)height; | ||
285 | } | ||
diff --git a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c index e2436e9b90..311b8057cb 100644 --- a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c +++ b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c | |||
@@ -231,3 +231,18 @@ bool lcd_active() | |||
231 | { | 231 | { |
232 | return display_on; | 232 | return display_on; |
233 | } | 233 | } |
234 | |||
235 | /* Blit a YUV bitmap directly to the LCD */ | ||
236 | void lcd_blit_yuv(unsigned char * const src[3], | ||
237 | int src_x, int src_y, int stride, | ||
238 | int x, int y, int width, int height) | ||
239 | { | ||
240 | (void)src; | ||
241 | (void)src_x; | ||
242 | (void)src_y; | ||
243 | (void)stride; | ||
244 | (void)x; | ||
245 | (void)y; | ||
246 | (void)width; | ||
247 | (void)height; | ||
248 | } | ||
diff --git a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c index 8520715650..821b52dcb6 100644 --- a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c +++ b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c | |||
@@ -211,3 +211,18 @@ bool lcd_active() | |||
211 | { | 211 | { |
212 | return display_on; | 212 | return display_on; |
213 | } | 213 | } |
214 | |||
215 | /* Blit a YUV bitmap directly to the LCD */ | ||
216 | void lcd_blit_yuv(unsigned char * const src[3], | ||
217 | int src_x, int src_y, int stride, | ||
218 | int x, int y, int width, int height) | ||
219 | { | ||
220 | (void)src; | ||
221 | (void)src_x; | ||
222 | (void)src_y; | ||
223 | (void)stride; | ||
224 | (void)x; | ||
225 | (void)y; | ||
226 | (void)width; | ||
227 | (void)height; | ||
228 | } | ||
diff --git a/firmware/target/arm/rk27xx/lcd-hifiman.c b/firmware/target/arm/rk27xx/lcd-hifiman.c index 95486b02e4..bde1d3546f 100644 --- a/firmware/target/arm/rk27xx/lcd-hifiman.c +++ b/firmware/target/arm/rk27xx/lcd-hifiman.c | |||
@@ -350,3 +350,22 @@ bool lcd_active() | |||
350 | { | 350 | { |
351 | return display_on; | 351 | return display_on; |
352 | } | 352 | } |
353 | |||
354 | /* Blit a YUV bitmap directly to the LCD | ||
355 | * provided by generic fallback in lcd-16bit-common.c | ||
356 | */ | ||
357 | #if 0 | ||
358 | void lcd_blit_yuv(unsigned char * const src[3], | ||
359 | int src_x, int src_y, int stride, | ||
360 | int x, int y, int width, int height) | ||
361 | { | ||
362 | (void)src; | ||
363 | (void)src_x; | ||
364 | (void)src_y; | ||
365 | (void)stride; | ||
366 | (void)x; | ||
367 | (void)y; | ||
368 | (void)width; | ||
369 | (void)height; | ||
370 | } | ||
371 | #endif | ||
diff --git a/firmware/target/arm/rk27xx/ma/lcd-ma.c b/firmware/target/arm/rk27xx/ma/lcd-ma.c index 8dfe874b44..fa3ccc5aa0 100644 --- a/firmware/target/arm/rk27xx/ma/lcd-ma.c +++ b/firmware/target/arm/rk27xx/ma/lcd-ma.c | |||
@@ -253,3 +253,18 @@ bool lcd_active() | |||
253 | { | 253 | { |
254 | return display_on; | 254 | return display_on; |
255 | } | 255 | } |
256 | |||
257 | /* Blit a YUV bitmap directly to the LCD */ | ||
258 | void lcd_blit_yuv(unsigned char * const src[3], | ||
259 | int src_x, int src_y, int stride, | ||
260 | int x, int y, int width, int height) | ||
261 | { | ||
262 | (void)src; | ||
263 | (void)src_x; | ||
264 | (void)src_y; | ||
265 | (void)stride; | ||
266 | (void)x; | ||
267 | (void)y; | ||
268 | (void)width; | ||
269 | (void)height; | ||
270 | } | ||
diff --git a/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c b/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c index e5cefd282d..b40f2860d7 100644 --- a/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c +++ b/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c | |||
@@ -178,3 +178,22 @@ void lcd_set_gram_area(int x_start, int y_start, | |||
178 | lcd_cmd(GRAM_WRITE); | 178 | lcd_cmd(GRAM_WRITE); |
179 | LCDC_CTRL &= ~RGB24B; | 179 | LCDC_CTRL &= ~RGB24B; |
180 | } | 180 | } |
181 | |||
182 | /* Blit a YUV bitmap directly to the LCD | ||
183 | * provided by generic fallback in lcd-16bit-common.c | ||
184 | */ | ||
185 | #if 0 | ||
186 | void lcd_blit_yuv(unsigned char * const src[3], | ||
187 | int src_x, int src_y, int stride, | ||
188 | int x, int y, int width, int height) | ||
189 | { | ||
190 | (void)src; | ||
191 | (void)src_x; | ||
192 | (void)src_y; | ||
193 | (void)stride; | ||
194 | (void)x; | ||
195 | (void)y; | ||
196 | (void)width; | ||
197 | (void)height; | ||
198 | } | ||
199 | #endif | ||
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/lcd-asm-nano2g.S b/firmware/target/arm/s5l8700/ipodnano2g/lcd-asm-nano2g.S index 50104a73e8..af338eef16 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/lcd-asm-nano2g.S +++ b/firmware/target/arm/s5l8700/ipodnano2g/lcd-asm-nano2g.S | |||
@@ -65,3 +65,231 @@ lcd_write_line: /* r2 = LCD_BASE */ | |||
65 | bgt .loop | 65 | bgt .loop |
66 | 66 | ||
67 | ldmpc regs=r4-r6 | 67 | ldmpc regs=r4-r6 |
68 | |||
69 | /**************************************************************************** | ||
70 | * extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
71 | * const unsigned LCD_BASE, | ||
72 | * int width, | ||
73 | * int stride); | ||
74 | * | ||
75 | * Conversion from Motion JPEG and MPEG Y'PbPr to RGB is: | ||
76 | * |R| |1.164 0.000 1.596| |Y' - 16| | ||
77 | * |G| = |1.164 -0.391 -0.813| |Pb - 128| | ||
78 | * |B| |1.164 2.018 0.000| |Pr - 128| | ||
79 | * | ||
80 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
81 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
82 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
83 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
84 | * | ||
85 | * Converts two lines from YUV to RGB565 and writes to LCD at once. First loop | ||
86 | * loads Cb/Cr, calculates the chroma offset and saves them to buffer. Within | ||
87 | * the second loop these chroma offset are reloaded from buffer. Within each | ||
88 | * loop two pixels are calculated and written to LCD. | ||
89 | */ | ||
90 | .align 2 | ||
91 | .global lcd_write_yuv420_lines | ||
92 | .type lcd_write_yuv420_lines, %function | ||
93 | lcd_write_yuv420_lines: | ||
94 | /* r0 = src = yuv_src */ | ||
95 | /* r1 = dst = LCD_BASE */ | ||
96 | /* r2 = width */ | ||
97 | /* r3 = stride */ | ||
98 | stmfd sp!, { r4-r10, lr } /* save non-scratch */ | ||
99 | ldmia r0, { r9, r10, r12 } /* r9 = yuv_src[0] = Y'_p */ | ||
100 | /* r10 = yuv_src[1] = Cb_p */ | ||
101 | /* r12 = yuv_src[2] = Cr_p */ | ||
102 | add r3, r9, r3 /* r3 = &ysrc[stride] */ | ||
103 | add r4, r2, r2, asr #1 /* chroma buffer lenght = width/2 *3 */ | ||
104 | mov r4, r4, asl #2 /* use words for str/ldm possibility */ | ||
105 | add r4, r4, #19 /* plus room for 4 additional words, */ | ||
106 | bic r4, r4, #3 /* rounded up to multiples of 4 byte */ | ||
107 | sub sp, sp, r4 /* and allocate on stack */ | ||
108 | stmia sp, {r1-r4} /* LCD_BASE, width, &ysrc[stride], stack_alloc */ | ||
109 | |||
110 | mov r7, r2 /* r7 = loop count */ | ||
111 | add r8, sp, #16 /* chroma buffer */ | ||
112 | add lr, r1, #0x40 /* LCD data port = LCD_BASE + 0x40 */ | ||
113 | |||
114 | /* 1st loop start */ | ||
115 | 10: /* loop start */ | ||
116 | |||
117 | ldrb r0, [r10], #1 /* r0 = *usrc++ = *Cb_p++ */ | ||
118 | ldrb r1, [r12], #1 /* r1 = *vsrc++ = *Cr_p++ */ | ||
119 | |||
120 | sub r0, r0, #128 /* r0 = Cb-128 */ | ||
121 | sub r1, r1, #128 /* r1 = Cr-128 */ | ||
122 | |||
123 | add r2, r1, r1, asl #1 /* r2 = Cr*51 + Cb*24 */ | ||
124 | add r2, r2, r2, asl #4 | ||
125 | add r2, r2, r0, asl #3 | ||
126 | add r2, r2, r0, asl #4 | ||
127 | |||
128 | add r4, r1, r1, asl #2 /* r1 = Cr*101 */ | ||
129 | add r4, r4, r1, asl #5 | ||
130 | add r1, r4, r1, asl #6 | ||
131 | |||
132 | add r1, r1, #256 /* r1 = rv = (r1 + 256) >> 9 */ | ||
133 | mov r1, r1, asr #9 | ||
134 | rsb r2, r2, #128 /* r2 = guv = (-r2 + 128) >> 8 */ | ||
135 | mov r2, r2, asr #8 | ||
136 | add r0, r0, #2 /* r0 = bu = (Cb*128 + 256) >> 9 */ | ||
137 | mov r0, r0, asr #2 | ||
138 | stmia r8!, {r0-r2} /* store r0, r1 and r2 to chroma buffer */ | ||
139 | |||
140 | /* 1st loop, first pixel */ | ||
141 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
142 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
143 | add r3, r5, r5, asl #2 | ||
144 | add r5, r3, r5, asl #5 | ||
145 | |||
146 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
147 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
148 | add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */ | ||
149 | |||
150 | orr r5, r6, r4 /* check if clamping is needed... */ | ||
151 | orr r5, r5, r3, asr #1 /* ...at all */ | ||
152 | cmp r5, #31 | ||
153 | bls 15f /* -> no clamp */ | ||
154 | cmp r6, #31 /* clamp r */ | ||
155 | mvnhi r6, r6, asr #31 | ||
156 | andhi r6, r6, #31 | ||
157 | cmp r3, #63 /* clamp g */ | ||
158 | mvnhi r3, r3, asr #31 | ||
159 | andhi r3, r3, #63 | ||
160 | cmp r4, #31 /* clamp b */ | ||
161 | mvnhi r4, r4, asr #31 | ||
162 | andhi r4, r4, #31 | ||
163 | 15: /* no clamp */ | ||
164 | |||
165 | /* calculate pixel_1 and save to r4 for later pixel packing */ | ||
166 | orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */ | ||
167 | orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */ | ||
168 | |||
169 | /* 1st loop, second pixel */ | ||
170 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
171 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
172 | add r3, r5, r5, asl #2 | ||
173 | add r5, r3, r5, asl #5 | ||
174 | |||
175 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
176 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
177 | add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */ | ||
178 | |||
179 | orr r0, r6, r5 /* check if clamping is needed... */ | ||
180 | orr r0, r0, r3, asr #1 /* ...at all */ | ||
181 | cmp r0, #31 | ||
182 | bls 15f /* -> no clamp */ | ||
183 | cmp r6, #31 /* clamp r */ | ||
184 | mvnhi r6, r6, asr #31 | ||
185 | andhi r6, r6, #31 | ||
186 | cmp r3, #63 /* clamp g */ | ||
187 | mvnhi r3, r3, asr #31 | ||
188 | andhi r3, r3, #63 | ||
189 | cmp r5, #31 /* clamp b */ | ||
190 | mvnhi r5, r5, asr #31 | ||
191 | andhi r5, r5, #31 | ||
192 | 15: /* no clamp */ | ||
193 | |||
194 | /* calculate pixel_2 and pack with pixel_1 before writing */ | ||
195 | orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ | ||
196 | orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */ | ||
197 | #ifdef FORCE_FIFO_WAIT | ||
198 | /* wait for FIFO half full */ | ||
199 | .fifo_wait1: | ||
200 | ldr r3, [lr, #-0x24] /* while (LCD_STATUS & 0x08); */ | ||
201 | tst r3, #0x8 | ||
202 | bgt .fifo_wait1 | ||
203 | #endif | ||
204 | stmia lr, {r4,r5} /* write pixel_1 and pixel_2 */ | ||
205 | |||
206 | subs r7, r7, #2 /* check for loop end */ | ||
207 | bgt 10b /* back to beginning */ | ||
208 | /* 1st loop end */ | ||
209 | |||
210 | /* Reload several registers for pointer rewinding for next loop */ | ||
211 | add r8, sp, #16 /* chroma buffer */ | ||
212 | ldmia sp, { r1, r7, r9} /* r1 = LCD_BASE */ | ||
213 | /* r7 = loop count */ | ||
214 | /* r9 = &ysrc[stride] */ | ||
215 | |||
216 | /* 2nd loop start */ | ||
217 | 20: /* loop start */ | ||
218 | /* restore r0 (bu), r1 (rv) and r2 (guv) from chroma buffer */ | ||
219 | ldmia r8!, {r0-r2} | ||
220 | |||
221 | /* 2nd loop, first pixel */ | ||
222 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
223 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
224 | add r3, r5, r5, asl #2 | ||
225 | add r5, r3, r5, asl #5 | ||
226 | |||
227 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
228 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
229 | add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */ | ||
230 | |||
231 | orr r5, r6, r4 /* check if clamping is needed... */ | ||
232 | orr r5, r5, r3, asr #1 /* ...at all */ | ||
233 | cmp r5, #31 | ||
234 | bls 15f /* -> no clamp */ | ||
235 | cmp r6, #31 /* clamp r */ | ||
236 | mvnhi r6, r6, asr #31 | ||
237 | andhi r6, r6, #31 | ||
238 | cmp r3, #63 /* clamp g */ | ||
239 | mvnhi r3, r3, asr #31 | ||
240 | andhi r3, r3, #63 | ||
241 | cmp r4, #31 /* clamp b */ | ||
242 | mvnhi r4, r4, asr #31 | ||
243 | andhi r4, r4, #31 | ||
244 | 15: /* no clamp */ | ||
245 | /* calculate pixel_1 and save to r4 for later pixel packing */ | ||
246 | orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */ | ||
247 | orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */ | ||
248 | |||
249 | /* 2nd loop, second pixel */ | ||
250 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
251 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
252 | add r3, r5, r5, asl #2 | ||
253 | add r5, r3, r5, asl #5 | ||
254 | |||
255 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
256 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
257 | add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */ | ||
258 | |||
259 | orr r0, r6, r5 /* check if clamping is needed... */ | ||
260 | orr r0, r0, r3, asr #1 /* ...at all */ | ||
261 | cmp r0, #31 | ||
262 | bls 15f /* -> no clamp */ | ||
263 | cmp r6, #31 /* clamp r */ | ||
264 | mvnhi r6, r6, asr #31 | ||
265 | andhi r6, r6, #31 | ||
266 | cmp r3, #63 /* clamp g */ | ||
267 | mvnhi r3, r3, asr #31 | ||
268 | andhi r3, r3, #63 | ||
269 | cmp r5, #31 /* clamp b */ | ||
270 | mvnhi r5, r5, asr #31 | ||
271 | andhi r5, r5, #31 | ||
272 | 15: /* no clamp */ | ||
273 | |||
274 | /* calculate pixel_2 and pack with pixel_1 before writing */ | ||
275 | orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ | ||
276 | orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */ | ||
277 | #ifdef FORCE_FIFO_WAIT | ||
278 | /* wait for FIFO half full */ | ||
279 | .fifo_wait2: | ||
280 | ldr r3, [lr, #-0x24] /* while (LCD_STATUS & 0x08); */ | ||
281 | tst r3, #0x8 | ||
282 | bgt .fifo_wait2 | ||
283 | #endif | ||
284 | stmia lr, {r4,r5} /* write pixel_1 and pixel_2 */ | ||
285 | |||
286 | subs r7, r7, #2 /* check for loop end */ | ||
287 | bgt 20b /* back to beginning */ | ||
288 | /* 2nd loop end */ | ||
289 | |||
290 | ldr r3, [sp, #12] | ||
291 | add sp, sp, r3 /* deallocate buffer */ | ||
292 | ldmpc regs=r4-r10 /* restore registers */ | ||
293 | |||
294 | .ltorg | ||
295 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c index 2d630886c9..13e5c5c1d4 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c +++ b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c | |||
@@ -406,3 +406,36 @@ void lcd_update_rect(int x, int y, int width, int height) | |||
406 | } while (--height > 0 ); | 406 | } while (--height > 0 ); |
407 | } | 407 | } |
408 | } | 408 | } |
409 | |||
410 | /* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */ | ||
411 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
412 | const unsigned int lcd_baseadress, | ||
413 | int width, | ||
414 | int stride); | ||
415 | |||
416 | /* Blit a YUV bitmap directly to the LCD */ | ||
417 | void lcd_blit_yuv(unsigned char * const src[3], | ||
418 | int src_x, int src_y, int stride, | ||
419 | int x, int y, int width, int height) | ||
420 | { | ||
421 | unsigned int z; | ||
422 | unsigned char const * yuv_src[3]; | ||
423 | |||
424 | width = (width + 1) & ~1; /* ensure width is even */ | ||
425 | |||
426 | lcd_setup_drawing_region(x, y, width, height); | ||
427 | |||
428 | z = stride * src_y; | ||
429 | yuv_src[0] = src[0] + z + src_x; | ||
430 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
431 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
432 | |||
433 | height >>= 1; | ||
434 | |||
435 | do { | ||
436 | lcd_write_yuv420_lines(yuv_src, LCD_BASE, width, stride); | ||
437 | yuv_src[0] += stride << 1; | ||
438 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
439 | yuv_src[2] += stride >> 1; | ||
440 | } while (--height > 0); | ||
441 | } | ||
diff --git a/firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c b/firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c index ced8925999..5ed6c752b7 100644 --- a/firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c +++ b/firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c | |||
@@ -311,3 +311,11 @@ void lcd_update_rect(int x, int y, int width, int height) | |||
311 | { | 311 | { |
312 | lcd_update(); | 312 | lcd_update(); |
313 | } | 313 | } |
314 | |||
315 | void lcd_blit_yuv(unsigned char * const src[3], | ||
316 | int src_x, int src_y, int stride, | ||
317 | int x, int y, int width, int height) | ||
318 | { | ||
319 | /* stub */ | ||
320 | } | ||
321 | |||
diff --git a/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c b/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c index bbbfccc11d..5e722d5a87 100644 --- a/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c +++ b/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c | |||
@@ -476,3 +476,19 @@ void lcd_update(void) | |||
476 | { | 476 | { |
477 | lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); | 477 | lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); |
478 | } | 478 | } |
479 | |||
480 | void lcd_blit_yuv(unsigned char * const src[3], | ||
481 | int src_x, int src_y, int stride, | ||
482 | int x, int y, int width, int height) | ||
483 | { | ||
484 | (void)src; | ||
485 | (void)src_x; | ||
486 | (void)src_y; | ||
487 | (void)stride; | ||
488 | (void)x; | ||
489 | (void)y; | ||
490 | (void)width; | ||
491 | (void)height; | ||
492 | /* TODO: not implemented yet */ | ||
493 | } | ||
494 | |||
diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-6g.c b/firmware/target/arm/s5l8702/ipod6g/lcd-6g.c index e1406549f4..14647a5697 100644 --- a/firmware/target/arm/s5l8702/ipod6g/lcd-6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/lcd-6g.c | |||
@@ -530,3 +530,49 @@ void lcd_update_rect(int x, int y, int width, int height) | |||
530 | 530 | ||
531 | displaylcd_dma(pixels); | 531 | displaylcd_dma(pixels); |
532 | } | 532 | } |
533 | |||
534 | /* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */ | ||
535 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
536 | uint16_t* outbuf, | ||
537 | int width, | ||
538 | int stride); | ||
539 | |||
540 | /* Blit a YUV bitmap directly to the LCD */ | ||
541 | void lcd_blit_yuv(unsigned char * const src[3], | ||
542 | int src_x, int src_y, int stride, | ||
543 | int x, int y, int width, int height) ICODE_ATTR; | ||
544 | void lcd_blit_yuv(unsigned char * const src[3], | ||
545 | int src_x, int src_y, int stride, | ||
546 | int x, int y, int width, int height) | ||
547 | { | ||
548 | unsigned int z; | ||
549 | unsigned char const * yuv_src[3]; | ||
550 | |||
551 | #ifdef HAVE_LCD_SLEEP | ||
552 | if (!lcd_active()) return; | ||
553 | #endif | ||
554 | |||
555 | width = (width + 1) & ~1; /* ensure width is even */ | ||
556 | |||
557 | int pixels = width * height; | ||
558 | uint16_t* out = lcd_dblbuf[0]; | ||
559 | |||
560 | z = stride * src_y; | ||
561 | yuv_src[0] = src[0] + z + src_x; | ||
562 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
563 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
564 | |||
565 | displaylcd_setup(x, y, width, height); | ||
566 | |||
567 | height >>= 1; | ||
568 | |||
569 | do { | ||
570 | lcd_write_yuv420_lines(yuv_src, out, width, stride); | ||
571 | yuv_src[0] += stride << 1; | ||
572 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
573 | yuv_src[2] += stride >> 1; | ||
574 | out += width << 1; | ||
575 | } while (--height); | ||
576 | |||
577 | displaylcd_dma(pixels); | ||
578 | } | ||
diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-asm-6g.S b/firmware/target/arm/s5l8702/ipod6g/lcd-asm-6g.S new file mode 100644 index 0000000000..1ed7c4e189 --- /dev/null +++ b/firmware/target/arm/s5l8702/ipod6g/lcd-asm-6g.S | |||
@@ -0,0 +1,1013 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: lcd-as-video.S 26756 2010-06-11 04:41:36Z funman $ | ||
9 | * | ||
10 | * Copyright (C) 2010 by Andree Buschmann | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | /* Version history: | ||
23 | * | ||
24 | * SVN: | ||
25 | * - initial SVN version. | ||
26 | * | ||
27 | * ARMv4: | ||
28 | * - use all available registers to calculate four pixels within each | ||
29 | * loop iteration. | ||
30 | * - avoid LDR interlocks. | ||
31 | * | ||
32 | * ARMv5TE: | ||
33 | * - use ARMv5TE+ 1-cycle multiply-accumulate instructions. | ||
34 | * | ||
35 | * ARMv5TE_WST: | ||
36 | * - use data tables (256 bytes) for RBG565 saturation. | ||
37 | * | ||
38 | * All versions are based on current SVN algorithm (round->scale->add) | ||
39 | * using the same coefficients, so output results are identical. | ||
40 | * | ||
41 | * TODO?: SVN coefficients are a very nice approximation for operations | ||
42 | * with shift+add instructions. When 16x16+32 MLA instructions are used, | ||
43 | * NBR and COEF_N could probably be adjusted to slighly increase accuracy. | ||
44 | */ | ||
45 | #define VERSION_SVN 0 | ||
46 | #define VERSION_ARMV4 1 | ||
47 | #define VERSION_ARMV5TE 2 | ||
48 | #define VERSION_ARMV5TE_WST 3 | ||
49 | |||
50 | #define YUV2RGB_VERSION VERSION_ARMV5TE_WST | ||
51 | |||
52 | |||
53 | #define ASM | ||
54 | #include "config.h" | ||
55 | #include "cpu.h" | ||
56 | |||
57 | #if (YUV2RGB_VERSION == VERSION_SVN) | ||
58 | .section .icode, "ax", %progbits | ||
59 | |||
60 | |||
61 | /**************************************************************************** | ||
62 | * extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
63 | * uint16_t* out, | ||
64 | * int width, | ||
65 | * int stride); | ||
66 | * | ||
67 | * Conversion from Motion JPEG and MPEG Y'PbPr to RGB is: | ||
68 | * |R| |1.164 0.000 1.596| |Y' - 16| | ||
69 | * |G| = |1.164 -0.391 -0.813| |Pb - 128| | ||
70 | * |B| |1.164 2.018 0.000| |Pr - 128| | ||
71 | * | ||
72 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
73 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
74 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
75 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
76 | * | ||
77 | * Converts two lines from YUV to RGB565 and writes to LCD at once. First loop | ||
78 | * loads Cb/Cr, calculates the chroma offset and saves them to buffer. Within | ||
79 | * the second loop these chroma offset are reloaded from buffer. Within each | ||
80 | * loop two pixels are calculated and written to LCD. | ||
81 | */ | ||
82 | .align 2 | ||
83 | .global lcd_write_yuv420_lines | ||
84 | .type lcd_write_yuv420_lines, %function | ||
85 | lcd_write_yuv420_lines: | ||
86 | /* r0 = src = yuv_src */ | ||
87 | /* r1 = dst = out */ | ||
88 | /* r2 = width */ | ||
89 | /* r3 = stride */ | ||
90 | stmfd sp!, { r4-r10, lr } /* save non-scratch */ | ||
91 | ldmia r0, { r9, r10, r12 } /* r9 = yuv_src[0] = Y'_p */ | ||
92 | /* r10 = yuv_src[1] = Cb_p */ | ||
93 | /* r12 = yuv_src[2] = Cr_p */ | ||
94 | add r3, r9, r3 /* r3 = &ysrc[stride] */ | ||
95 | add r4, r2, r2, asr #1 /* chroma buffer lenght = width/2 *3 */ | ||
96 | mov r4, r4, asl #2 /* use words for str/ldm possibility */ | ||
97 | add r4, r4, #15 /* plus room for 3 additional words, */ | ||
98 | bic r4, r4, #3 /* rounded up to multiples of 4 byte */ | ||
99 | sub sp, sp, r4 /* and allocate on stack */ | ||
100 | stmia sp, {r2-r4} /* width, &ysrc[stride], stack_alloc */ | ||
101 | |||
102 | mov r7, r2 /* r7 = loop count */ | ||
103 | add r8, sp, #12 /* chroma buffer */ | ||
104 | mov lr, r1 /* RGB565 data destination buffer */ | ||
105 | |||
106 | /* 1st loop start */ | ||
107 | 10: /* loop start */ | ||
108 | |||
109 | ldrb r0, [r10], #1 /* r0 = *usrc++ = *Cb_p++ */ | ||
110 | ldrb r1, [r12], #1 /* r1 = *vsrc++ = *Cr_p++ */ | ||
111 | |||
112 | sub r0, r0, #128 /* r0 = Cb-128 */ | ||
113 | sub r1, r1, #128 /* r1 = Cr-128 */ | ||
114 | |||
115 | add r2, r1, r1, asl #1 /* r2 = Cr*51 + Cb*24 */ | ||
116 | add r2, r2, r2, asl #4 | ||
117 | add r2, r2, r0, asl #3 | ||
118 | add r2, r2, r0, asl #4 | ||
119 | |||
120 | add r4, r1, r1, asl #2 /* r1 = Cr*101 */ | ||
121 | add r4, r4, r1, asl #5 | ||
122 | add r1, r4, r1, asl #6 | ||
123 | |||
124 | add r1, r1, #256 /* r1 = rv = (r1 + 256) >> 9 */ | ||
125 | mov r1, r1, asr #9 | ||
126 | rsb r2, r2, #128 /* r2 = guv = (-r2 + 128) >> 8 */ | ||
127 | mov r2, r2, asr #8 | ||
128 | add r0, r0, #2 /* r0 = bu = (Cb*128 + 256) >> 9 */ | ||
129 | mov r0, r0, asr #2 | ||
130 | stmia r8!, {r0-r2} /* store r0, r1 and r2 to chroma buffer */ | ||
131 | |||
132 | /* 1st loop, first pixel */ | ||
133 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
134 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
135 | add r3, r5, r5, asl #2 | ||
136 | add r5, r3, r5, asl #5 | ||
137 | |||
138 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
139 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
140 | add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */ | ||
141 | |||
142 | orr r5, r6, r4 /* check if clamping is needed... */ | ||
143 | orr r5, r5, r3, asr #1 /* ...at all */ | ||
144 | cmp r5, #31 | ||
145 | bls 15f /* -> no clamp */ | ||
146 | cmp r6, #31 /* clamp r */ | ||
147 | mvnhi r6, r6, asr #31 | ||
148 | andhi r6, r6, #31 | ||
149 | cmp r3, #63 /* clamp g */ | ||
150 | mvnhi r3, r3, asr #31 | ||
151 | andhi r3, r3, #63 | ||
152 | cmp r4, #31 /* clamp b */ | ||
153 | mvnhi r4, r4, asr #31 | ||
154 | andhi r4, r4, #31 | ||
155 | 15: /* no clamp */ | ||
156 | |||
157 | /* calculate pixel_1 and save to r4 for later pixel packing */ | ||
158 | orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */ | ||
159 | orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */ | ||
160 | |||
161 | /* 1st loop, second pixel */ | ||
162 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
163 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
164 | add r3, r5, r5, asl #2 | ||
165 | add r5, r3, r5, asl #5 | ||
166 | |||
167 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
168 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
169 | add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */ | ||
170 | |||
171 | orr r0, r6, r5 /* check if clamping is needed... */ | ||
172 | orr r0, r0, r3, asr #1 /* ...at all */ | ||
173 | cmp r0, #31 | ||
174 | bls 15f /* -> no clamp */ | ||
175 | cmp r6, #31 /* clamp r */ | ||
176 | mvnhi r6, r6, asr #31 | ||
177 | andhi r6, r6, #31 | ||
178 | cmp r3, #63 /* clamp g */ | ||
179 | mvnhi r3, r3, asr #31 | ||
180 | andhi r3, r3, #63 | ||
181 | cmp r5, #31 /* clamp b */ | ||
182 | mvnhi r5, r5, asr #31 | ||
183 | andhi r5, r5, #31 | ||
184 | 15: /* no clamp */ | ||
185 | |||
186 | /* calculate pixel_2 and pack with pixel_1 before writing */ | ||
187 | orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ | ||
188 | orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */ | ||
189 | orr r4, r4, r5, lsl #16 | ||
190 | str r4, [lr], #4 /* write pixel_1 and pixel_2 */ | ||
191 | |||
192 | subs r7, r7, #2 /* check for loop end */ | ||
193 | bgt 10b /* back to beginning */ | ||
194 | /* 1st loop end */ | ||
195 | |||
196 | /* Reload several registers for pointer rewinding for next loop */ | ||
197 | add r8, sp, #12 /* chroma buffer */ | ||
198 | ldmia sp, {r7, r9} /* r7 = loop count */ | ||
199 | /* r9 = &ysrc[stride] */ | ||
200 | |||
201 | /* 2nd loop start */ | ||
202 | 20: /* loop start */ | ||
203 | /* restore r0 (bu), r1 (rv) and r2 (guv) from chroma buffer */ | ||
204 | ldmia r8!, {r0-r2} | ||
205 | |||
206 | /* 2nd loop, first pixel */ | ||
207 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
208 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
209 | add r3, r5, r5, asl #2 | ||
210 | add r5, r3, r5, asl #5 | ||
211 | |||
212 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
213 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
214 | add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */ | ||
215 | |||
216 | orr r5, r6, r4 /* check if clamping is needed... */ | ||
217 | orr r5, r5, r3, asr #1 /* ...at all */ | ||
218 | cmp r5, #31 | ||
219 | bls 15f /* -> no clamp */ | ||
220 | cmp r6, #31 /* clamp r */ | ||
221 | mvnhi r6, r6, asr #31 | ||
222 | andhi r6, r6, #31 | ||
223 | cmp r3, #63 /* clamp g */ | ||
224 | mvnhi r3, r3, asr #31 | ||
225 | andhi r3, r3, #63 | ||
226 | cmp r4, #31 /* clamp b */ | ||
227 | mvnhi r4, r4, asr #31 | ||
228 | andhi r4, r4, #31 | ||
229 | 15: /* no clamp */ | ||
230 | /* calculate pixel_1 and save to r4 for later pixel packing */ | ||
231 | orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */ | ||
232 | orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */ | ||
233 | |||
234 | /* 2nd loop, second pixel */ | ||
235 | ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */ | ||
236 | sub r5, r5, #16 /* r5 = (Y'-16) * 74 */ | ||
237 | add r3, r5, r5, asl #2 | ||
238 | add r5, r3, r5, asl #5 | ||
239 | |||
240 | add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
241 | add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */ | ||
242 | add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */ | ||
243 | |||
244 | orr r0, r6, r5 /* check if clamping is needed... */ | ||
245 | orr r0, r0, r3, asr #1 /* ...at all */ | ||
246 | cmp r0, #31 | ||
247 | bls 15f /* -> no clamp */ | ||
248 | cmp r6, #31 /* clamp r */ | ||
249 | mvnhi r6, r6, asr #31 | ||
250 | andhi r6, r6, #31 | ||
251 | cmp r3, #63 /* clamp g */ | ||
252 | mvnhi r3, r3, asr #31 | ||
253 | andhi r3, r3, #63 | ||
254 | cmp r5, #31 /* clamp b */ | ||
255 | mvnhi r5, r5, asr #31 | ||
256 | andhi r5, r5, #31 | ||
257 | 15: /* no clamp */ | ||
258 | |||
259 | /* calculate pixel_2 and pack with pixel_1 before writing */ | ||
260 | orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ | ||
261 | orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */ | ||
262 | orr r4, r4, r5, lsl #16 | ||
263 | str r4, [lr], #4 /* write pixel_1 and pixel_2 */ | ||
264 | |||
265 | subs r7, r7, #2 /* check for loop end */ | ||
266 | bgt 20b /* back to beginning */ | ||
267 | /* 2nd loop end */ | ||
268 | |||
269 | ldr r3, [sp, #8] | ||
270 | add sp, sp, r3 /* deallocate buffer */ | ||
271 | ldmpc regs=r4-r10 /* restore registers */ | ||
272 | |||
273 | .ltorg | ||
274 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
275 | |||
276 | |||
277 | #elif (YUV2RGB_VERSION == VERSION_ARMV4) | ||
278 | /**************************************************************************** | ||
279 | * extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
280 | * uint16_t* out, | ||
281 | * int width, | ||
282 | * int stride); | ||
283 | * | ||
284 | * Conversion from Motion JPEG and MPEG Y'PbPr to RGB is: | ||
285 | * |R| |1.164 0.000 1.596| |Y' - 16| | ||
286 | * |G| = |1.164 -0.391 -0.813| |Pb - 128| | ||
287 | * |B| |1.164 2.018 0.000| |Pr - 128| | ||
288 | * | ||
289 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
290 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
291 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
292 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
293 | * | ||
294 | * Converts two lines from YUV420 to RGB565, within each iteration four | ||
295 | * pixels (2 per line) are calculated and written to destination buffer. | ||
296 | */ | ||
297 | .section .icode, "ax", %progbits | ||
298 | |||
299 | .align 2 | ||
300 | .global lcd_write_yuv420_lines | ||
301 | .type lcd_write_yuv420_lines, %function | ||
302 | |||
303 | lcd_write_yuv420_lines: | ||
304 | /* r0 = src = yuv_src */ | ||
305 | /* r1 = dst = out */ | ||
306 | /* r2 = width */ | ||
307 | /* r3 = stride */ | ||
308 | stmfd sp!, {r4-r11,lr} /* save non-scratch */ | ||
309 | ldmia r0, {r10-r12} /* r10 = yuv_src[0] = Y'_p */ | ||
310 | /* r11 = yuv_src[1] = Cb_p */ | ||
311 | /* r12 = yuv_src[2] = Cr_p */ | ||
312 | mov r9, r2, lsl #1 /* r9 = 2*width (loop count) */ | ||
313 | str r9, [sp, #-4]! /* [--sp] = 2*width (constant) */ | ||
314 | add r8, r10, r3 /* r8 = Y'_p + stride = Y'stride_p */ | ||
315 | mov lr, r1 /* RGB565 data destination buffer */ | ||
316 | |||
317 | 10: /* loop start */ | ||
318 | ldrb r0, [r11], #1 /* r0 = *Cb_p++ */ | ||
319 | ldrb r1, [r12], #1 /* r1 = *Cr_p++ */ | ||
320 | ldrb r3, [r8], #1 /* r3 = Y'3 */ | ||
321 | ldrb r4, [r8], #1 /* r4 = Y'4 */ | ||
322 | |||
323 | sub r0, r0, #128 /* r0 = Cb-128 */ | ||
324 | sub r1, r1, #128 /* r1 = Cr-128 */ | ||
325 | |||
326 | add r2, r1, r1, asl #1 /* r2 = Cr*51 + Cb*24 */ | ||
327 | add r2, r2, r2, asl #4 | ||
328 | add r2, r2, r0, asl #3 | ||
329 | add r2, r2, r0, asl #4 | ||
330 | |||
331 | add r5, r1, r1, asl #2 /* r1 = Cr*101 */ | ||
332 | add r5, r5, r1, asl #5 | ||
333 | add r1, r5, r1, asl #6 | ||
334 | |||
335 | add r1, r1, #256 /* r1 = rv = (r1 + 256) >> 9 */ | ||
336 | mov r1, r1, asr #9 | ||
337 | rsb r2, r2, #128 /* r2 = guv = (-r2 + 128) >> 8 */ | ||
338 | mov r2, r2, asr #8 | ||
339 | add r0, r0, #2 /* r0 = bu = (Cb*128 + 256) >> 9 */ | ||
340 | mov r0, r0, asr #2 | ||
341 | |||
342 | /* pixel_3 */ | ||
343 | sub r3, r3, #16 /* r3 = (Y'-16) * (74/2) */ | ||
344 | add r7, r3, r3, asl #2 | ||
345 | add r3, r7, r3, asl #5 | ||
346 | |||
347 | add r6, r1, r3, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
348 | add r7, r2, r3, asr #7 /* r7 = g = (Y >> 8) + guv */ | ||
349 | add r5, r0, r3, asr #8 /* r5 = b = (Y >> 9) + bu */ | ||
350 | |||
351 | orr r3, r6, r5 /* check if clamping is needed... */ | ||
352 | orr r3, r3, r7, asr #1 /* ...at all */ | ||
353 | cmp r3, #31 | ||
354 | bls 15f /* no clamp */ | ||
355 | cmp r6, #31 /* clamp r */ | ||
356 | mvnhi r6, r6, asr #31 | ||
357 | andhi r6, r6, #31 | ||
358 | cmp r7, #63 /* clamp g */ | ||
359 | mvnhi r7, r7, asr #31 | ||
360 | andhi r7, r7, #63 | ||
361 | cmp r5, #31 /* clamp b */ | ||
362 | mvnhi r5, r5, asr #31 | ||
363 | andhi r5, r5, #31 | ||
364 | 15: /* no clamp */ | ||
365 | |||
366 | /* calculate pixel_3 and save to r5 for later pixel packing */ | ||
367 | orr r5, r5, r7, lsl #5 /* pixel_3 = r<<11 | g<<5 | b */ | ||
368 | orr r5, r5, r6, lsl #11 /* r5 = pixel_3 */ | ||
369 | |||
370 | /* pixel_4 */ | ||
371 | sub r4, r4, #16 /* r4 = (Y'-16) * (74/2) */ | ||
372 | add r7, r4, r4, asl #2 | ||
373 | add r4, r7, r4, asl #5 | ||
374 | |||
375 | add r6, r1, r4, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
376 | add r7, r2, r4, asr #7 /* r7 = g = (Y >> 8) + guv */ | ||
377 | add r4, r0, r4, asr #8 /* r4 = b = (Y >> 9) + bu */ | ||
378 | |||
379 | orr r3, r6, r4 /* check if clamping is needed... */ | ||
380 | orr r3, r3, r7, asr #1 /* ...at all */ | ||
381 | cmp r3, #31 | ||
382 | bls 15f /* no clamp */ | ||
383 | cmp r6, #31 /* clamp r */ | ||
384 | mvnhi r6, r6, asr #31 | ||
385 | andhi r6, r6, #31 | ||
386 | cmp r7, #63 /* clamp g */ | ||
387 | mvnhi r7, r7, asr #31 | ||
388 | andhi r7, r7, #63 | ||
389 | cmp r4, #31 /* clamp b */ | ||
390 | mvnhi r4, r4, asr #31 | ||
391 | andhi r4, r4, #31 | ||
392 | 15: /* no clamp */ | ||
393 | |||
394 | /* calculate pixel_4 and pack with pixel_3 before writing */ | ||
395 | orr r4, r4, r7, lsl #5 /* pixel_4 = r<<11 | g<<5 | b */ | ||
396 | orr r4, r4, r6, lsl #11 /* r4 = pixel_4 */ | ||
397 | orr r5, r5, r4, lsl #16 /* r5 = pixel_4<<16 | pixel_3 */ | ||
398 | |||
399 | ldr r7, [sp] /* r7 = 2*width */ | ||
400 | ldrb r3, [r10], #1 /* r3 = Y'1 */ | ||
401 | ldrb r4, [r10], #1 /* r4 = Y'2 */ | ||
402 | |||
403 | str r5, [lr, r7] /* write pixel_3 and pixel_4 */ | ||
404 | |||
405 | /* pixel_1 */ | ||
406 | sub r3, r3, #16 /* r3 = (Y'-16) * (74/2) */ | ||
407 | add r7, r3, r3, asl #2 | ||
408 | add r3, r7, r3, asl #5 | ||
409 | |||
410 | add r6, r1, r3, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
411 | add r7, r2, r3, asr #7 /* r7 = g = (Y >> 8) + guv */ | ||
412 | add r5, r0, r3, asr #8 /* r5 = b = (Y >> 9) + bu */ | ||
413 | |||
414 | orr r3, r6, r5 /* check if clamping is needed... */ | ||
415 | orr r3, r3, r7, asr #1 /* ...at all */ | ||
416 | cmp r3, #31 | ||
417 | bls 15f /* no clamp */ | ||
418 | cmp r6, #31 /* clamp r */ | ||
419 | mvnhi r6, r6, asr #31 | ||
420 | andhi r6, r6, #31 | ||
421 | cmp r7, #63 /* clamp g */ | ||
422 | mvnhi r7, r7, asr #31 | ||
423 | andhi r7, r7, #63 | ||
424 | cmp r5, #31 /* clamp b */ | ||
425 | mvnhi r5, r5, asr #31 | ||
426 | andhi r5, r5, #31 | ||
427 | 15: /* no clamp */ | ||
428 | |||
429 | /* calculate pixel_1 and save to r5 for later pixel packing */ | ||
430 | orr r5, r5, r7, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */ | ||
431 | orr r5, r5, r6, lsl #11 /* r5 = pixel_1 */ | ||
432 | |||
433 | /* pixel_2 */ | ||
434 | sub r4, r4, #16 /* r4 = (Y'-16) * (74/2) */ | ||
435 | add r7, r4, r4, asl #2 | ||
436 | add r4, r7, r4, asl #5 | ||
437 | |||
438 | add r6, r1, r4, asr #8 /* r6 = r = (Y >> 9) + rv */ | ||
439 | add r7, r2, r4, asr #7 /* r7 = g = (Y >> 8) + guv */ | ||
440 | add r4, r0, r4, asr #8 /* r4 = b = (Y >> 9) + bu */ | ||
441 | |||
442 | orr r3, r6, r4 /* check if clamping is needed... */ | ||
443 | orr r3, r3, r7, asr #1 /* ...at all */ | ||
444 | cmp r3, #31 | ||
445 | bls 15f /* no clamp */ | ||
446 | cmp r6, #31 /* clamp r */ | ||
447 | mvnhi r6, r6, asr #31 | ||
448 | andhi r6, r6, #31 | ||
449 | cmp r7, #63 /* clamp g */ | ||
450 | mvnhi r7, r7, asr #31 | ||
451 | andhi r7, r7, #63 | ||
452 | cmp r4, #31 /* clamp b */ | ||
453 | mvnhi r4, r4, asr #31 | ||
454 | andhi r4, r4, #31 | ||
455 | 15: /* no clamp */ | ||
456 | |||
457 | /* calculate pixel_2 and pack with pixel_1 before writing */ | ||
458 | orr r4, r4, r7, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ | ||
459 | orr r4, r4, r6, lsl #11 /* r4 = pixel_2 */ | ||
460 | orr r5, r5, r4, lsl #16 /* r5 = pixel_2<<16 | pixel_1 */ | ||
461 | |||
462 | str r5, [lr], #4 /* write pixel_1 and pixel_2 */ | ||
463 | |||
464 | subs r9, r9, #4 /* check for loop end */ | ||
465 | bgt 10b /* back to beginning */ | ||
466 | |||
467 | /* loop end */ | ||
468 | add sp, sp, #4 /* deallocate stack */ | ||
469 | ldmpc regs=r4-r11 /* restore registers */ | ||
470 | |||
471 | .ltorg | ||
472 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
473 | |||
474 | |||
475 | #elif (YUV2RGB_VERSION == VERSION_ARMV5TE) | ||
476 | /**************************************************************************** | ||
477 | * How do I encode Y'CBCR components from R'G'B' in [0, +1]? (see ColorFAQ) | ||
478 | * |R| |0.00456621 0 0.00625893| |Y' - 16| | ||
479 | * |G| = |0.00456621 -0.00153632 -0.00318811| |Pb - 128| | ||
480 | * |B| |0.00456621 0.00791071 0 | |Pr - 128| | ||
481 | * | ||
482 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
483 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
484 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
485 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
486 | */ | ||
487 | #define NBR 14 /* 14-bit resolution (SVN) */ | ||
488 | #define COEF_C0 74 | ||
489 | #define COEF_C1 101 | ||
490 | #define COEF_C2 -24 | ||
491 | #define COEF_C3 -51 | ||
492 | #define COEF_C4 128 | ||
493 | #define C4_IS_POW2 | ||
494 | |||
495 | /* constant for rounding a NBR number before down-scaling it to RS bits */ | ||
496 | #define ROUND(RS) (1 << (NBR - RS - 1)) | ||
497 | |||
498 | /* packed 16-bit coefficients */ | ||
499 | #define COEF_C4_C1 ((COEF_C4 << 16) | (COEF_C1 & 0xffff)) | ||
500 | #define COEF_2C3_2C2 ((COEF_C3 << 17) | ((COEF_C2 << 1) & 0xffff)) | ||
501 | /* 32-bit MLA constants */ | ||
502 | #define CONST_MLA_Y (-16 * COEF_C0) | ||
503 | |||
504 | /**************************************************************************** | ||
505 | * extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
506 | * uint16_t* out, | ||
507 | * int width, | ||
508 | * int stride); | ||
509 | * | ||
510 | * Converts two lines from YUV420 to RGB565, within each iteration four | ||
511 | * pixels (2 per line) are calculated and written to destination buffer. | ||
512 | * | ||
513 | * - use ARMv5TE+ 1-cycle multiply+accumulator instructions. | ||
514 | */ | ||
515 | .section .icode, "ax", %progbits | ||
516 | |||
517 | .align 2 | ||
518 | .global lcd_write_yuv420_lines | ||
519 | .type lcd_write_yuv420_lines, %function | ||
520 | |||
521 | lcd_write_yuv420_lines: | ||
522 | @ r0 = src = yuv_src | ||
523 | @ r1 = out = dst_p | ||
524 | @ r2 = width | ||
525 | @ r3 = stride | ||
526 | stmfd sp!, {r4-r11,lr} @ save non-scratch | ||
527 | ldmia r0, {r10-r12} @ r10 = yuv_src[0] = Y'_p | ||
528 | @ r11 = yuv_src[1] = Cb_p | ||
529 | @ r12 = yuv_src[2] = Cr_p | ||
530 | adr r0, const_data @ load constants | ||
531 | ldmia r0, {r5-r8} @ r5 = COEF_C4_C1 | ||
532 | @ r6 = COEF_2C3_2C2 | ||
533 | @ r7 = COEF_C0 | ||
534 | @ r8 = CONST_MLA_Y | ||
535 | sub r4, r12, r11 @ r4 = Cr_p-Cb_p | ||
536 | mov r9, r2, asl #1 @ r9 = 2*width | ||
537 | stmfd sp!, {r4-r6,r9} @ SP -> Cr_p-Cb_p | ||
538 | @ COEF_C4_C1 | ||
539 | @ COEF_2C3_2C2 | ||
540 | @ 2*width | ||
541 | add r12, r10, r3 @ r12 = Y'_p + stride = Y'stride_p | ||
542 | mov lr, r1 @ RGB565 data destination buffer | ||
543 | orr r9, r7, r2, lsl #15 @ loop_count = width/2; | ||
544 | @ r9 = loop_count<<16 | COEF_C0 | ||
545 | sub r9, r9, #0x10000 @ loop_count-- | ||
546 | |||
547 | 10: @ loop_start | ||
548 | |||
549 | @ register usage: | ||
550 | @ r8 = CONST_MLA_Y | ||
551 | @ r9 = loop count<<16 | COEF_C0 | ||
552 | @ r10 = Y'_p | ||
553 | @ r11 = Cb_p | ||
554 | @ r12 = Y'stride_p | ||
555 | @ lr = dst_p | ||
556 | @ free: r0-r7 | ||
557 | |||
558 | ldmia sp, {r2-r4} @ r2 = Cr_p-Cb_p | ||
559 | @ r3 = COEF_C4_C1 | ||
560 | @ r4 = COEF_2C3_2C2 | ||
561 | mov r5, #ROUND(5) @ r5 = round constant | ||
562 | |||
563 | ldrb r6, [r12], #1 @ r6 = Y'3 | ||
564 | ldrb r7, [r12], #1 @ r7 = Y'4 | ||
565 | |||
566 | ldrb r1, [r11, r2] @ r1 = Cr = *Cr_p++ | ||
567 | ldrb r0, [r11], #1 @ r0 = Cb = *Cb_p++ | ||
568 | |||
569 | /* calculate Y3 and Y4 */ | ||
570 | smlabb r6, r6, r9, r8 @ r6 = Y3 = C0*Y'3 - C0*16 | ||
571 | smlabb r7, r7, r9, r8 @ r7 = Y4 = C0*Y'4 - C0*16 | ||
572 | |||
573 | /* calculate rv, guv, bu */ | ||
574 | sub r1, r1, #128 @ r1 = Cr" = Cr-128 | ||
575 | sub r0, r0, #128 @ r0 = Cb" = Cb-128 | ||
576 | |||
577 | smlabt r2, r1, r4, r5 @ r2 = guv" = Cr"*(2*C2) + | ||
578 | smlabb r2, r0, r4, r2 @ Cb"*(2*C3) + round | ||
579 | smlabb r1, r1, r3, r5 @ r1 = rv" = Cr"*C1 + round | ||
580 | #ifdef C4_IS_POW2 | ||
581 | add r0, r5, r0, asl #NBR-7 @ r0 = bu" = Cb"*C4 + round | ||
582 | #else | ||
583 | smlabt r0, r0, r3, r5 @ r0 = bu" = Cb"*C4 + round | ||
584 | #endif | ||
585 | |||
586 | /* scale rv",guv",bu" */ | ||
587 | mov r2, r2, asr #NBR-5 @ r2 = guv = guv" >> scale | ||
588 | mov r1, r1, asr #NBR-5 @ r1 = rv = rv" >> scale | ||
589 | mov r0, r0, asr #NBR-5 @ r0 = bu = bu" >> scale | ||
590 | |||
591 | @ register usage: | ||
592 | @ r8-r12,lr: pointers, counters | ||
593 | @ r0,r1,r2 = bu,rv,guv (rounded and scaled to RGB565) | ||
594 | @ r6,r7 = Y'3,Y'4 | ||
595 | @ free: r3-r5 | ||
596 | |||
597 | /* pixel_3 */ | ||
598 | add r5, r1, r6, asr #NBR-5 @ r5 = r = (Y3 >> scale) + rv | ||
599 | add r4, r2, r6, asr #NBR-6 @ r4 = g = (Y3 >> scale) + guv | ||
600 | add r3, r0, r6, asr #NBR-5 @ r3 = b = (Y3 >> scale) + bu | ||
601 | |||
602 | orr r6, r5, r3 @ check if clamping is needed... | ||
603 | orr r6, r6, r4, asr #1 @ ...at all | ||
604 | cmp r6, #31 | ||
605 | bls 15f @ no clamp | ||
606 | cmp r5, #31 @ clamp r | ||
607 | mvnhi r5, r5, asr #31 | ||
608 | andhi r5, r5, #31 | ||
609 | cmp r4, #63 @ clamp g | ||
610 | mvnhi r4, r4, asr #31 | ||
611 | andhi r4, r4, #63 | ||
612 | cmp r3, #31 @ clamp b | ||
613 | mvnhi r3, r3, asr #31 | ||
614 | andhi r3, r3, #31 | ||
615 | 15: @ no clamp | ||
616 | |||
617 | /* calculate pixel_3 and save to r3 for later pixel packing */ | ||
618 | orr r3, r3, r4, lsl #5 @ r3 = pixel_3 = r<<11 | g<<5 | b | ||
619 | orr r3, r3, r5, lsl #11 | ||
620 | |||
621 | /* pixel_4 */ | ||
622 | add r5, r1, r7, asr #NBR-5 @ r5 = r = (Y4 >> scale) + rv | ||
623 | add r4, r2, r7, asr #NBR-6 @ r4 = g = (Y4 >> scale) + guv | ||
624 | add r7, r0, r7, asr #NBR-5 @ r7 = b = (Y4 >> scale) + bu | ||
625 | |||
626 | orr r6, r5, r7 @ check if clamping is needed... | ||
627 | orr r6, r6, r4, asr #1 @ ...at all | ||
628 | cmp r6, #31 | ||
629 | bls 15f @ no clamp | ||
630 | cmp r5, #31 @ clamp r | ||
631 | mvnhi r5, r5, asr #31 | ||
632 | andhi r5, r5, #31 | ||
633 | cmp r4, #63 @ clamp g | ||
634 | mvnhi r4, r4, asr #31 | ||
635 | andhi r4, r4, #63 | ||
636 | cmp r7, #31 @ clamp b | ||
637 | mvnhi r7, r7, asr #31 | ||
638 | andhi r7, r7, #31 | ||
639 | 15: @ no clamp | ||
640 | |||
641 | /* calculate pixel_4 and pack with pixel_3 before writing */ | ||
642 | orr r7, r7, r4, lsl #5 @ r7 = pixel_4 = r<<11 | g<<5 | b | ||
643 | orr r7, r7, r5, lsl #11 | ||
644 | orr r3, r3, r7, lsl #16 @ r3 = pixel_4<<16 | pixel_3 | ||
645 | |||
646 | /* avoid interlocks when writing pixel_3 and pixel_4 */ | ||
647 | ldr r5, [sp, #12] @ r5 = 2*width | ||
648 | |||
649 | ldrb r6, [r10], #1 @ r6 = Y'1 | ||
650 | ldrb r7, [r10], #1 @ r7 = Y'2 | ||
651 | |||
652 | /* write pixel_3 and pixel_4 */ | ||
653 | str r3, [lr, r5] @ [dst_p + 2*width] = r3 | ||
654 | |||
655 | @ register usage: | ||
656 | @ r8-r12,lr: pointers, counters | ||
657 | @ r0,r1,r2 = bu,rv,guv (rounded and scaled to RGB565) | ||
658 | @ r6,r7 = Y'1,Y'2 | ||
659 | @ free: r3-r5 | ||
660 | |||
661 | /* calculate Y1 and Y2 */ | ||
662 | smlabb r6, r6, r9, r8 @ r6 = Y1 = C0*Y'1 - C0*16 | ||
663 | smlabb r7, r7, r9, r8 @ r7 = Y2 = C0*Y'2 - C0*16 | ||
664 | |||
665 | /* pixel_1 */ | ||
666 | add r5, r1, r6, asr #NBR-5 @ r5 = r = (Y1 >> scale) + rv | ||
667 | add r4, r2, r6, asr #NBR-6 @ r4 = g = (Y1 >> scale) + guv | ||
668 | add r3, r0, r6, asr #NBR-5 @ r3 = b = (Y1 >> scale) + bu | ||
669 | |||
670 | orr r6, r5, r3 @ check if clamping is needed... | ||
671 | orr r6, r6, r4, asr #1 @ ...at all | ||
672 | cmp r6, #31 | ||
673 | bls 15f @ no clamp | ||
674 | cmp r5, #31 @ clamp r | ||
675 | mvnhi r5, r5, asr #31 | ||
676 | andhi r5, r5, #31 | ||
677 | cmp r4, #63 @ clamp g | ||
678 | mvnhi r4, r4, asr #31 | ||
679 | andhi r4, r4, #63 | ||
680 | cmp r3, #31 @ clamp b | ||
681 | mvnhi r3, r3, asr #31 | ||
682 | andhi r3, r3, #31 | ||
683 | 15: @ no clamp | ||
684 | |||
685 | /* calculate pixel_1 and save to r3 for later pixel packing */ | ||
686 | orr r3, r3, r4, lsl #5 @ r3 = pixel_1 = r<<11 | g<<5 | b | ||
687 | orr r3, r3, r5, lsl #11 | ||
688 | |||
689 | /* pixel_2 */ | ||
690 | add r5, r1, r7, asr #NBR-5 @ r5 = r = (Y2 >> scale) + rv | ||
691 | add r4, r2, r7, asr #NBR-6 @ r4 = g = (Y2 >> scale) + guv | ||
692 | add r7, r0, r7, asr #NBR-5 @ r7 = b = (Y2 >> scale) + bu | ||
693 | |||
694 | orr r6, r5, r7 @ check if clamping is needed... | ||
695 | orr r6, r6, r4, asr #1 @ ...at all | ||
696 | cmp r6, #31 | ||
697 | bls 15f @ no clamp | ||
698 | cmp r5, #31 @ clamp r | ||
699 | mvnhi r5, r5, asr #31 | ||
700 | andhi r5, r5, #31 | ||
701 | cmp r4, #63 @ clamp g | ||
702 | mvnhi r4, r4, asr #31 | ||
703 | andhi r4, r4, #63 | ||
704 | cmp r7, #31 @ clamp b | ||
705 | mvnhi r7, r7, asr #31 | ||
706 | andhi r7, r7, #31 | ||
707 | 15: @ no clamp | ||
708 | |||
709 | /* calculate pixel_2 and pack with pixel_1 before writing */ | ||
710 | orr r7, r7, r4, lsl #5 @ r7 = pixel_2 = r<<11 | g<<5 | b | ||
711 | orr r7, r7, r5, lsl #11 | ||
712 | orr r3, r3, r7, lsl #16 @ r3 = pixel_2 << 16 | pixel_1 | ||
713 | |||
714 | str r3, [lr], #4 @ write pixel_1 and pixel_2 | ||
715 | |||
716 | /* check for loop end */ | ||
717 | subs r9, r9, #0x10000 @ loop_count-- | ||
718 | bge 10b @ back to beginning | ||
719 | |||
720 | /* bye */ | ||
721 | add sp, sp, #16 | ||
722 | ldmpc regs=r4-r11 @ restore registers | ||
723 | |||
724 | .ltorg | ||
725 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
726 | |||
727 | /* data */ | ||
728 | .align 2 | ||
729 | const_data: | ||
730 | .word COEF_C4_C1 | ||
731 | .word COEF_2C3_2C2 | ||
732 | .word COEF_C0 | ||
733 | .word CONST_MLA_Y | ||
734 | |||
735 | .size const_data, .-const_data | ||
736 | |||
737 | |||
738 | #else /* YUV2RGB_VERSION == VERSION_ARMV5TE_WST */ | ||
739 | /**************************************************************************** | ||
740 | * How do I encode Y'CBCR components from R'G'B' in [0, +1]? (see ColorFAQ) | ||
741 | * |R| |0.00456621 0 0.00625893| |Y' - 16| | ||
742 | * |G| = |0.00456621 -0.00153632 -0.00318811| |Pb - 128| | ||
743 | * |B| |0.00456621 0.00791071 0 | |Pr - 128| | ||
744 | * | ||
745 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
746 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
747 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
748 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
749 | */ | ||
750 | #define NBR 14 /* 14-bit resolution (SVN) */ | ||
751 | #define COEF_C0 74 | ||
752 | #define COEF_C1 101 | ||
753 | #define COEF_C2 -24 | ||
754 | #define COEF_C3 -51 | ||
755 | #define COEF_C4 128 | ||
756 | #define C4_IS_POW2 | ||
757 | |||
758 | /* packed 16-bit coefficients */ | ||
759 | #define COEF_C4_C1 ((COEF_C4 << 16) | (COEF_C1 & 0xffff)) | ||
760 | #define COEF_C3_C2 ((COEF_C3 << 16) | (COEF_C2 & 0xffff)) | ||
761 | |||
762 | /* constant for rounding an NBR number before down-scaling it to RS bits */ | ||
763 | #define ROUND(RS) (1 << (NBR - RS - 1)) | ||
764 | |||
765 | /* 32-bit MLA constants */ | ||
766 | #define CONST_MLA_Y (-16 * COEF_C0) | ||
767 | #define CONST_MLA_RV ((-128 * COEF_C1) + ROUND(5)) | ||
768 | #define CONST_MLA_BU ((-128 * COEF_C4) + ROUND(5)) | ||
769 | /* trick to save the register needed for table_sat6 reference: | ||
770 | add table_sat6-table_sat5 offset (conveniently scaled) to guv MLA */ | ||
771 | #define CONST_MLA_GUV (-128 * (COEF_C2 + COEF_C3) + ROUND(6) + \ | ||
772 | ((table_sat6 - table_sat5) << (NBR - 6))) | ||
773 | |||
774 | /**************************************************************************** | ||
775 | * extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
776 | * uint16_t* out, | ||
777 | * int width, | ||
778 | * int stride); | ||
779 | * | ||
780 | * Converts two lines from YUV420 to RGB565, within each iteration four | ||
781 | * pixels (2 per line) are calculated and written to destination buffer. | ||
782 | * | ||
783 | * - use ARMv5TE+ 1-cycle multiply+accumulator instructions. | ||
784 | * - use data tables (256 bytes) for RBG565 saturation. | ||
785 | */ | ||
786 | .section .icode, "ax", %progbits | ||
787 | |||
788 | .align 2 | ||
789 | .global lcd_write_yuv420_lines | ||
790 | .type lcd_write_yuv420_lines, %function | ||
791 | |||
792 | lcd_write_yuv420_lines: | ||
793 | @ r0 = src = yuv_src | ||
794 | @ r1 = out = dst1_p | ||
795 | @ r2 = width | ||
796 | @ r3 = stride | ||
797 | stmfd sp!, {r4-r11,lr} @ save non-scratch | ||
798 | ldmia r0, {r10-r12} @ r10 = yuv_src[0] = Y'_p | ||
799 | @ r11 = yuv_src[1] = Cb_p | ||
800 | @ r12 = yuv_src[2] = Cr_p | ||
801 | /* prepare data and fill stack */ | ||
802 | adr r0, const_data @ load constants | ||
803 | ldmia r0, {r4-r9,lr} @ r4 = COEF_C0 | ||
804 | @ r5 = CONST_MLA_GUV | ||
805 | @ r6 = COEF_C3_C2 | ||
806 | @ r7 = CONST_MLA_BU | ||
807 | @ r8 = COEF_C4_C1 | ||
808 | @ r9 = CONST_MLA_RV | ||
809 | @ lr = table_sat5 | ||
810 | sub r0, r12, r11 @ r0 = Cr_p-Cb_p | ||
811 | #define STACK_SZ 28 | ||
812 | stmfd sp!, {r0,r5-r9,lr} @ SP -> Cr_p-Cb_p | ||
813 | @ CONST_MLA_GUV | ||
814 | @ COEF_C3_C2 | ||
815 | @ CONST_MLA_BU | ||
816 | @ COEF_C4_C1 | ||
817 | @ CONST_MLA_RV | ||
818 | @ table_sat5 | ||
819 | mov r8, r4, lsl #4 @ | ||
820 | rsb r8, #0 @ r8 = -16*COEF_C0 = CONST_MLA_Y | ||
821 | mov lr, r1 @ RGB565 data destination buffer | ||
822 | add r9, lr, r2, asl #1 @ r9 = out + 2*width = dst2_p | ||
823 | add r12, r3, r10 @ r12 = Y'_p + stride | ||
824 | orr r7, r4, r2, lsl #15 @ loop_count = width/2; | ||
825 | @ r7 = loop_count<<16 | COEF_C0 | ||
826 | sub r7, r7, #0x10000 @ loop_count-- | ||
827 | |||
828 | /* align loop code to minimize occupied lines, execution | ||
829 | time per loop is optimized ~10% on ARM926EJ-S */ | ||
830 | .align CACHEALIGN_BITS | ||
831 | loop_start: | ||
832 | |||
833 | @ register usage: | ||
834 | @ r7 = loop count<<16 | COEF_C0 | ||
835 | @ r8 = CONST_MLA_Y | ||
836 | @ r9 = dst2_p | ||
837 | @ r10 = Y'_p | ||
838 | @ r11 = Cb_p | ||
839 | @ r12 = Y'stride_p | ||
840 | @ lr = dst1_p | ||
841 | @ free: r0-r6 | ||
842 | |||
843 | /* load constants from stack */ | ||
844 | ldmia sp, {r1-r3,r6} @ r1 = Cr_p-Cb_p | ||
845 | @ r2 = CONST_MLA_GUV | ||
846 | @ r3 = COEF_C3_C2 | ||
847 | @ r6 = CONST_MLA_BU | ||
848 | |||
849 | /* read Cr", Cb" */ | ||
850 | ldrb r1, [r11, r1] @ r1 = Cr = *Cr_p++ | ||
851 | ldrb r0, [r11], #1 @ r0 = Cb = *Cb_p++ | ||
852 | |||
853 | /* load more constants (avoids r1 interlock) */ | ||
854 | ldrd r4, [sp, #16] @ r4 = COEF_C4_C1 | ||
855 | @ r5 = CONST_MLA_RV | ||
856 | |||
857 | /* calculate rv", guv", bu" */ | ||
858 | smlabt r2, r1, r3, r2 @ r2 = guv" = Cr*C2 + Cb*C3 | ||
859 | smlabb r2, r0, r3, r2 @ + CONST_MLA_GUV | ||
860 | smlabb r1, r1, r4, r5 @ r1 = rv" = Cr*C1 + CONST_MLA_RV | ||
861 | #ifdef C4_IS_POW2 | ||
862 | add r0, r6, r0, asl #NBR-7 @ r0 = bu" = Cb*C4 + CONST_MLA_BU | ||
863 | #else | ||
864 | smlabt r0, r0, r4, r6 @ r0 = bu" = Cb*C4 + CONST_MLA_BU | ||
865 | #endif | ||
866 | |||
867 | ldr r4, [sp, #STACK_SZ-4] @ r4 = table_sat5 | ||
868 | |||
869 | /* read Y'1 and Y'2 */ | ||
870 | ldrb r5, [r10], #1 @ r5 = Y'1 = *Y'_p++ | ||
871 | ldrb r6, [r10], #1 @ r6 = Y'2 = *Y'_p++ | ||
872 | |||
873 | /* scale rv",guv",bu", adding sat5_p here saves instructions later */ | ||
874 | add r1, r4, r1, asr #NBR-5 @ r1 = rv' = sat5_p + rv">>scale | ||
875 | add r2, r4, r2, asr #NBR-6 @ r2 = guv' = sat5_p + guv">>scale | ||
876 | add r0, r4, r0, asr #NBR-5 @ r0 = bu' = sat5_p + bu">>scale | ||
877 | |||
878 | @ register usage: | ||
879 | @ r7-r12,lr: pointers, counters, tables | ||
880 | @ r0,r1,r2 = (bu,rv,guv) rounded and RGB565 scaled | ||
881 | @ r5,r6 = Y'1,Y'2 | ||
882 | @ free: r3,r4 | ||
883 | |||
884 | /* calculate Y1 and Y2 */ | ||
885 | smlabb r5, r5, r7, r8 @ r5 = Y1 = C0*Y'1 - 16*C0 | ||
886 | smlabb r6, r6, r7, r8 @ r6 = Y2 = C0*Y'2 - 16*C0 | ||
887 | |||
888 | /* pixel_1 */ | ||
889 | ldrb r3, [r0, r5, asr #NBR-5] @ r3 = b = sat5[Y1>>scale + bu'] | ||
890 | ldrb r4, [r2, r5, asr #NBR-6] @ r4 = g = sat6[Y1>>scale + guv'] | ||
891 | ldrb r5, [r1, r5, asr #NBR-5] @ r5 = r = sat5[Y1>>scale + rv'] | ||
892 | |||
893 | /* calculate pixel_1 */ | ||
894 | orr r3, r3, r4, lsl #5 @ r3 = pixel_1 = g<<5 | b | ||
895 | |||
896 | /* pixel_2 (avoid r5 interlock) */ | ||
897 | ldrb r4, [r0, r6, asr #NBR-5] @ r4 = b = sat5[Y2>>scale + bu'] | ||
898 | |||
899 | /* calculate pixel_1 and save to r3 for later pixel packing */ | ||
900 | orr r3, r3, r5, lsl #11 @ r3 = pixel_1 = r<<11 | g<<5 | b | ||
901 | |||
902 | /* pixel_2 */ | ||
903 | ldrb r5, [r2, r6, asr #NBR-6] @ r5 = g = sat6[Y2>>scale + guv'] | ||
904 | ldrb r6, [r1, r6, asr #NBR-5] @ r6 = r = sat5[Y2>>scale + rv'] | ||
905 | |||
906 | /* calculate pixel_2 and pack with pixel_1 before writing */ | ||
907 | orr r3, r3, r4, lsl #16 @ r3 = pixel_2<<16 | pixel_1 | ||
908 | orr r3, r3, r5, lsl #21 | ||
909 | orr r3, r3, r6, lsl #27 | ||
910 | |||
911 | /* read Y'3 and Y'4 */ | ||
912 | ldrb r5, [r12], #1 @ r5 = Y'3 = *Y'stride_p++ | ||
913 | ldrb r6, [r12], #1 @ r6 = Y'4 = *Y'stride_p++ | ||
914 | |||
915 | /* write pixel_1 and pixel_2 */ | ||
916 | str r3, [lr], #4 @ *dst2_p++ = r3 | ||
917 | |||
918 | @ register usage: | ||
919 | @ r7-r12,lr: pointers, counters, tables | ||
920 | @ r0,r1,r2 = (bu,rv,guv) rounded and RGB565 scaled | ||
921 | @ r5,r6 = Y'3,Y'4 | ||
922 | @ free: r3,r4 | ||
923 | |||
924 | /* calculate Y3 and Y4 */ | ||
925 | smlabb r5, r5, r7, r8 @ r5 = Y3 = C0*Y'3 - 16*C0 | ||
926 | smlabb r6, r6, r7, r8 @ r6 = Y4 = C0*Y'4 - 16*C0 | ||
927 | |||
928 | /* pixel_3 */ | ||
929 | ldrb r3, [r0, r5, asr #NBR-5] @ r3 = b = sat5[Y3>>scale + bu'] | ||
930 | ldrb r4, [r2, r5, asr #NBR-6] @ r4 = g = sat6[Y3>>scale + guv'] | ||
931 | ldrb r5, [r1, r5, asr #NBR-5] @ r5 = r = sat5[Y3>>scale + rv'] | ||
932 | |||
933 | /* calculate pixel_3 */ | ||
934 | orr r3, r3, r4, lsl #5 @ r3 = pixel_3 = g<<5 | b | ||
935 | |||
936 | /* pixel_4 (avoid r5 interlock) */ | ||
937 | ldrb r4, [r0, r6, asr #NBR-5] @ r4 = b = sat5[Y4>>scale + bu'] | ||
938 | |||
939 | /* calculate pixel_3 and save to r3 for later pixel packing */ | ||
940 | orr r3, r3, r5, lsl #11 @ r3 = pixel_3 = r<<11 | g<<5 | b | ||
941 | |||
942 | /* pixel_4 */ | ||
943 | ldrb r5, [r2, r6, asr #NBR-6] @ r5 = g = sat6[Y4>>scale + guv'] | ||
944 | ldrb r6, [r1, r6, asr #NBR-5] @ r6 = r = sat5[Y4>>scale + rv'] | ||
945 | |||
946 | /* calculate pixel_4 and pack with pixel_3 before writing */ | ||
947 | orr r3, r3, r4, lsl #16 @ r3 = pixel_4 << 16 | pixel_3 | ||
948 | orr r3, r3, r5, lsl #21 | ||
949 | orr r3, r3, r6, lsl #27 | ||
950 | |||
951 | /* write pixel_3 and pixel_4 */ | ||
952 | str r3, [r9], #4 @ *dst1_p++ = r3 | ||
953 | |||
954 | /* check for loop end */ | ||
955 | subs r7, r7, #0x10000 @ loop_count-- | ||
956 | bge loop_start @ back to beginning | ||
957 | |||
958 | /* bye */ | ||
959 | add sp, sp, #STACK_SZ @ deallocate stack | ||
960 | ldmpc regs=r4-r11 @ restore registers | ||
961 | |||
962 | .ltorg | ||
963 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
964 | |||
965 | /* data */ | ||
966 | .align 2 | ||
967 | const_data: | ||
968 | .word COEF_C0 | ||
969 | .word CONST_MLA_GUV | ||
970 | .word COEF_C3_C2 | ||
971 | .word CONST_MLA_BU | ||
972 | .word COEF_C4_C1 | ||
973 | .word CONST_MLA_RV | ||
974 | .word table_sat5 | ||
975 | |||
976 | .size const_data, .-const_data | ||
977 | |||
978 | /* saturation tables */ | ||
979 | /*.section .data*/ | ||
980 | /* aligned to cache line size to minimize cache usage */ | ||
981 | .align CACHEALIGN_BITS | ||
982 | |||
983 | saturation_tables: | ||
984 | /* 5-bit saturation table [-36..0..+67], size=104 */ | ||
985 | /* table_sat5[-36..-1] */ | ||
986 | .byte 0, 0, 0, 0 | ||
987 | .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
988 | .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
989 | table_sat5: | ||
990 | /* table_sat5[0..67] */ | ||
991 | .byte 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 | ||
992 | .byte 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 | ||
993 | .byte 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 | ||
994 | .byte 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 | ||
995 | .byte 31, 31, 31, 31 | ||
996 | |||
997 | /* 6-bit saturation table [-44..0..+107], size=152 */ | ||
998 | /* table_sat6[-44..-1] */ | ||
999 | .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
1000 | .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
1001 | .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
1002 | table_sat6: | ||
1003 | /* table_sat6[0..107] */ | ||
1004 | .byte 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 | ||
1005 | .byte 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 | ||
1006 | .byte 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47 | ||
1007 | .byte 48, 49, 50, 51, 52, 53 ,54, 55, 56, 57, 58, 59, 60, 61, 62, 63 | ||
1008 | .byte 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 | ||
1009 | .byte 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 | ||
1010 | .byte 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 | ||
1011 | |||
1012 | .size saturation_tables, .-saturation_tables | ||
1013 | #endif /* YUV2RGB_VERSION */ | ||
diff --git a/firmware/target/arm/samsung/yh820/lcd-as-yh820.S b/firmware/target/arm/samsung/yh820/lcd-as-yh820.S new file mode 100644 index 0000000000..542ceeeb36 --- /dev/null +++ b/firmware/target/arm/samsung/yh820/lcd-as-yh820.S | |||
@@ -0,0 +1,550 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Jens Arnold | ||
11 | * Heavily based on lcd-as-memframe.c by Michael Sevakis | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | |||
23 | #include "config.h" | ||
24 | #include "cpu.h" | ||
25 | |||
26 | /**************************************************************************** | ||
27 | * void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
28 | * int width, | ||
29 | * int stride); | ||
30 | * | ||
31 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
32 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
33 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
34 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
35 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
36 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
37 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
38 | * | ||
39 | * Write four RGB565 pixels in the following order on each loop: | ||
40 | * 1 3 + > down | ||
41 | * 2 4 \/ left | ||
42 | */ | ||
43 | .section .icode, "ax", %progbits | ||
44 | .align 2 | ||
45 | .global lcd_write_yuv420_lines | ||
46 | .type lcd_write_yuv420_lines, %function | ||
47 | lcd_write_yuv420_lines: | ||
48 | @ r0 = yuv_src | ||
49 | @ r1 = width | ||
50 | @ r2 = stride | ||
51 | stmfd sp!, { r4-r10, lr } @ save non-scratch | ||
52 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
53 | @ r5 = yuv_src[1] = Cb_p | ||
54 | @ r6 = yuv_src[2] = Cr_p | ||
55 | @ r0 = scratch | ||
56 | sub r2, r2, #1 @ | ||
57 | mov r3, #0x70000000 @ | ||
58 | orr r3, r3, #0x3000 @ r3 = LCD1_BASE | ||
59 | 10: @ loop line @ | ||
60 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
61 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
62 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
63 | @ | ||
64 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 | ||
65 | add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right | ||
66 | add r7, r12, r7, asl #5 @ by one less when adding - same for all | ||
67 | @ | ||
68 | sub r8, r8, #128 @ Cb -= 128 | ||
69 | sub r9, r9, #128 @ Cr -= 128 | ||
70 | @ | ||
71 | add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 | ||
72 | add r10, r10, r10, asl #4 @ | ||
73 | add r10, r10, r8, asl #3 @ | ||
74 | add r10, r10, r8, asl #4 @ | ||
75 | @ | ||
76 | add lr, r9, r9, asl #2 @ r9 = Cr*101 | ||
77 | add lr, lr, r9, asl #5 @ | ||
78 | add r9, lr, r9, asl #6 @ | ||
79 | @ | ||
80 | add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 | ||
81 | mov r8, r8, asr #2 @ | ||
82 | add r9, r9, #256 @ r9 = rv = (r9 + 256) >> 9 | ||
83 | mov r9, r9, asr #9 @ | ||
84 | rsb r10, r10, #128 @ r10 = guv = (-r10 + 128) >> 8 | ||
85 | mov r10, r10, asr #8 @ | ||
86 | @ compute R, G, and B | ||
87 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
88 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
89 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
90 | @ | ||
91 | orr r12, r0, lr @ check if clamping is needed... | ||
92 | orr r12, r12, r7, asr #1 @ ...at all | ||
93 | cmp r12, #31 @ | ||
94 | bls 15f @ no clamp @ | ||
95 | cmp r0, #31 @ clamp b | ||
96 | mvnhi r0, r0, asr #31 @ | ||
97 | andhi r0, r0, #31 @ | ||
98 | cmp lr, #31 @ clamp r | ||
99 | mvnhi lr, lr, asr #31 @ | ||
100 | andhi lr, lr, #31 @ | ||
101 | cmp r7, #63 @ clamp g | ||
102 | mvnhi r7, r7, asr #31 @ | ||
103 | andhi r7, r7, #63 @ | ||
104 | 15: @ no clamp @ | ||
105 | @ | ||
106 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
107 | @ | ||
108 | mov lr, lr, lsl #3 @ | ||
109 | orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3) | ||
110 | orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b | ||
111 | 1: @ busy @ | ||
112 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
113 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
114 | bne 1b @ | ||
115 | str lr, [r3, #0x10] @ send MSB | ||
116 | 1: @busy @ | ||
117 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
118 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
119 | bne 1b @ | ||
120 | str r0, [r3, #0x10] @ send LSB | ||
121 | @ | ||
122 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
123 | add r12, r7, r7, asl #2 @ | ||
124 | add r7, r12, r7, asl #5 @ | ||
125 | @ compute R, G, and B | ||
126 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
127 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
128 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
129 | @ | ||
130 | orr r12, r0, lr @ check if clamping is needed... | ||
131 | orr r12, r12, r7, asr #1 @ ...at all | ||
132 | cmp r12, #31 @ | ||
133 | bls 15f @ no clamp @ | ||
134 | cmp r0, #31 @ clamp b | ||
135 | mvnhi r0, r0, asr #31 @ | ||
136 | andhi r0, r0, #31 @ | ||
137 | cmp lr, #31 @ clamp r | ||
138 | mvnhi lr, lr, asr #31 @ | ||
139 | andhi lr, lr, #31 @ | ||
140 | cmp r7, #63 @ clamp g | ||
141 | mvnhi r7, r7, asr #31 @ | ||
142 | andhi r7, r7, #63 @ | ||
143 | 15: @ no clamp @ | ||
144 | @ | ||
145 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
146 | @ | ||
147 | mov lr, lr, lsl #3 @ | ||
148 | orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3) | ||
149 | orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b | ||
150 | 1: @ busy @ | ||
151 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
152 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
153 | bne 1b @ | ||
154 | str lr, [r3, #0x10] @ send MSB | ||
155 | 1: @ busy @ | ||
156 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
157 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
158 | bne 1b @ | ||
159 | str r0, [r3, #0x10] @ send LSB | ||
160 | @ | ||
161 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
162 | add r12, r7, r7, asl #2 @ | ||
163 | add r7, r12, r7, asl #5 @ | ||
164 | @ compute R, G, and B | ||
165 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
166 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
167 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
168 | @ | ||
169 | orr r12, r0, lr @ check if clamping is needed... | ||
170 | orr r12, r12, r7, asr #1 @ ...at all | ||
171 | cmp r12, #31 @ | ||
172 | bls 15f @ no clamp @ | ||
173 | cmp r0, #31 @ clamp b | ||
174 | mvnhi r0, r0, asr #31 @ | ||
175 | andhi r0, r0, #31 @ | ||
176 | cmp lr, #31 @ clamp r | ||
177 | mvnhi lr, lr, asr #31 @ | ||
178 | andhi lr, lr, #31 @ | ||
179 | cmp r7, #63 @ clamp g | ||
180 | mvnhi r7, r7, asr #31 @ | ||
181 | andhi r7, r7, #63 @ | ||
182 | 15: @ no clamp @ | ||
183 | @ | ||
184 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
185 | @ | ||
186 | @ | ||
187 | mov lr, lr, lsl #3 @ | ||
188 | orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3) | ||
189 | orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b | ||
190 | 1: @ busy @ | ||
191 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
192 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
193 | bne 1b @ | ||
194 | str lr, [r3, #0x10] @ send MSB | ||
195 | 1: @ busy @ | ||
196 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
197 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
198 | bne 1b @ | ||
199 | str r0, [r3, #0x10] @ send LSB | ||
200 | @ | ||
201 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
202 | add r12, r7, r7, asl #2 @ | ||
203 | add r7, r12, r7, asl #5 @ | ||
204 | @ compute R, G, and B | ||
205 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
206 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
207 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
208 | @ | ||
209 | orr r12, r0, lr @ check if clamping is needed... | ||
210 | orr r12, r12, r7, asr #1 @ ...at all | ||
211 | cmp r12, #31 @ | ||
212 | bls 15f @ no clamp @ | ||
213 | cmp r0, #31 @ clamp b | ||
214 | mvnhi r0, r0, asr #31 @ | ||
215 | andhi r0, r0, #31 @ | ||
216 | cmp lr, #31 @ clamp r | ||
217 | mvnhi lr, lr, asr #31 @ | ||
218 | andhi lr, lr, #31 @ | ||
219 | cmp r7, #63 @ clamp g | ||
220 | mvnhi r7, r7, asr #31 @ | ||
221 | andhi r7, r7, #63 @ | ||
222 | 15: @ no clamp @ | ||
223 | @ | ||
224 | mov lr, lr, lsl #3 @ | ||
225 | orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3) | ||
226 | orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b | ||
227 | 1: @ busy @ | ||
228 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
229 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
230 | bne 1b @ | ||
231 | str lr, [r3, #0x10] @ send MSB | ||
232 | 1: @ busy @ | ||
233 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
234 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
235 | bne 1b @ | ||
236 | str r0, [r3, #0x10] @ send LSB | ||
237 | @ | ||
238 | subs r1, r1, #2 @ subtract block from width | ||
239 | bgt 10b @ loop line @ | ||
240 | @ | ||
241 | ldmpc regs=r4-r10 @ restore registers and return | ||
242 | .ltorg @ dump constant pool | ||
243 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
244 | |||
245 | /**************************************************************************** | ||
246 | * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
247 | * int width, | ||
248 | * int stride, | ||
249 | * int x_screen, | ||
250 | * int y_screen); | ||
251 | * | ||
252 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
253 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
254 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
255 | * Red scaled at twice g & b but at same precision to place it in correct | ||
256 | * bit position after multiply and leave instruction count lower. | ||
257 | * |R| |258 0 408| |Y' - 16| | ||
258 | * |G| = |149 -49 -104| |Cb - 128| | ||
259 | * |B| |149 258 0| |Cr - 128| | ||
260 | * | ||
261 | * Write four RGB565 pixels in the following order on each loop: | ||
262 | * 1 3 + > down | ||
263 | * 2 4 \/ left | ||
264 | * | ||
265 | * Kernel pattern (raw|rotated|use order): | ||
266 | * 5 3 4 2 2 6 3 7 row0 row2 > down | ||
267 | * 1 7 0 6 | 4 0 5 1 | 2 4 6 0 3 5 7 1 col0 left | ||
268 | * 4 2 5 3 | 3 7 2 6 | 3 5 7 1 2 4 6 0 col2 \/ | ||
269 | * 0 6 1 7 5 1 4 0 | ||
270 | */ | ||
271 | .section .icode, "ax", %progbits | ||
272 | .align 2 | ||
273 | .global lcd_write_yuv420_lines_odither | ||
274 | .type lcd_write_yuv420_lines_odither, %function | ||
275 | lcd_write_yuv420_lines_odither: | ||
276 | @ r0 = yuv_src | ||
277 | @ r1 = width | ||
278 | @ r2 = stride | ||
279 | @ r3 = x_screen | ||
280 | @ [sp] = y_screen | ||
281 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
282 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
283 | @ r5 = yuv_src[1] = Cb_p | ||
284 | @ r6 = yuv_src[2] = Cr_p | ||
285 | @ | ||
286 | sub r2, r2, #1 @ | ||
287 | ldr r14, [sp, #36] @ Line up pattern and kernel quadrant | ||
288 | eor r14, r14, r3 @ | ||
289 | and r14, r14, #0x2 @ | ||
290 | mov r14, r14, lsl #6 @ 0x00 or 0x80 | ||
291 | mov r3, #0x70000000 @ | ||
292 | orr r3, r3, #0x3000 @ r3 = LCD1_BASE | ||
293 | 10: @ loop line @ | ||
294 | @ | ||
295 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
296 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
297 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
298 | @ | ||
299 | eor r14, r14, #0x80 @ flip pattern quadrant | ||
300 | @ | ||
301 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149 | ||
302 | add r12, r7, r7, asl #2 @ | ||
303 | add r12, r12, r12, asl #4 @ | ||
304 | add r7, r12, r7, asl #6 @ | ||
305 | @ | ||
306 | sub r8, r8, #128 @ Cb -= 128 | ||
307 | sub r9, r9, #128 @ Cr -= 128 | ||
308 | @ | ||
309 | add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49 | ||
310 | add r10, r10, r8, asl #5 @ | ||
311 | add r10, r10, r9, asl #3 @ | ||
312 | add r10, r10, r9, asl #5 @ | ||
313 | add r10, r10, r9, asl #6 @ | ||
314 | @ | ||
315 | mov r8, r8, asl #1 @ r8 = bu = Cb*258 | ||
316 | add r8, r8, r8, asl #7 @ | ||
317 | @ | ||
318 | add r9, r9, r9, asl #1 @ r9 = rv = Cr*408 | ||
319 | add r9, r9, r9, asl #4 @ | ||
320 | mov r9, r9, asl #3 @ | ||
321 | @ | ||
322 | @ compute R, G, and B | ||
323 | add r0, r8, r7 @ r0 = b' = Y + bu | ||
324 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
325 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
326 | @ | ||
327 | @ r8 = bu, r9 = rv, r10 = guv | ||
328 | @ | ||
329 | sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256 | ||
330 | add r0, r12, r0, lsr #8 @ | ||
331 | @ | ||
332 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
333 | add r11, r12, r11, lsr #8 @ | ||
334 | @ | ||
335 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
336 | add r7, r12, r7, lsr #8 @ | ||
337 | @ | ||
338 | add r12, r14, #0x100 @ | ||
339 | @ | ||
340 | add r0, r0, r12 @ b = r0 + delta | ||
341 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
342 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
343 | @ | ||
344 | orr r12, r0, r11, asr #1 @ check if clamping is needed... | ||
345 | orr r12, r12, r7 @ ...at all | ||
346 | movs r12, r12, asr #15 @ | ||
347 | beq 15f @ no clamp @ | ||
348 | movs r12, r0, asr #15 @ clamp b | ||
349 | mvnne r0, r12, lsr #15 @ | ||
350 | andne r0, r0, #0x7c00 @ mask b only if clamped | ||
351 | movs r12, r11, asr #16 @ clamp r | ||
352 | mvnne r11, r12, lsr #16 @ | ||
353 | movs r12, r7, asr #15 @ clamp g | ||
354 | mvnne r7, r12, lsr #15 @ | ||
355 | 15: @ no clamp @ | ||
356 | @ | ||
357 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
358 | @ | ||
359 | |||
360 | and r11, r11, #0xf800 @ pack pixel | ||
361 | mov r11, r11, lsr #8 | ||
362 | and r7, r7, #0x7e00 | ||
363 | orr r11, r11, r7, lsr #12 | ||
364 | mov r7, r7, lsr#4 | ||
365 | orr r0, r7, r0, lsr #10 | ||
366 | 1: @ busy @ | ||
367 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
368 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
369 | bne 1b @ | ||
370 | str r11, [r3, #0x10] @ send MSB | ||
371 | 1: @ busy @ | ||
372 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
373 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
374 | bne 1b @ | ||
375 | str r0, [r3, #0x10] @ send LSB | ||
376 | @ | ||
377 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
378 | add r12, r7, r7, asl #2 @ | ||
379 | add r12, r12, r12, asl #4 @ | ||
380 | add r7, r12, r7, asl #6 @ | ||
381 | @ compute R, G, and B | ||
382 | add r0, r8, r7 @ r0 = b' = Y + bu | ||
383 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
384 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
385 | @ | ||
386 | sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256 | ||
387 | add r0, r12, r0, lsr #8 @ | ||
388 | @ | ||
389 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
390 | add r11, r12, r11, lsr #8 @ | ||
391 | @ | ||
392 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
393 | add r7, r12, r7, lsr #8 @ | ||
394 | @ | ||
395 | add r12, r14, #0x200 @ | ||
396 | @ | ||
397 | add r0, r0, r12 @ b = r0 + delta | ||
398 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
399 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
400 | @ | ||
401 | orr r12, r0, r11, asr #1 @ check if clamping is needed... | ||
402 | orr r12, r12, r7 @ ...at all | ||
403 | movs r12, r12, asr #15 @ | ||
404 | beq 15f @ no clamp @ | ||
405 | movs r12, r0, asr #15 @ clamp b | ||
406 | mvnne r0, r12, lsr #15 @ | ||
407 | andne r0, r0, #0x7c00 @ mask b only if clamped | ||
408 | movs r12, r11, asr #16 @ clamp r | ||
409 | mvnne r11, r12, lsr #16 @ | ||
410 | movs r12, r7, asr #15 @ clamp g | ||
411 | mvnne r7, r12, lsr #15 @ | ||
412 | 15: @ no clamp @ | ||
413 | @ | ||
414 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
415 | |||
416 | and r11, r11, #0xf800 @ pack pixel | ||
417 | mov r11, r11, lsr #8 | ||
418 | and r7, r7, #0x7e00 | ||
419 | orr r11, r11, r7, lsr #12 | ||
420 | mov r7, r7, lsr#4 | ||
421 | orr r0, r7, r0, lsr #10 | ||
422 | 1: @ busy @ | ||
423 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
424 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
425 | bne 1b @ | ||
426 | str r11, [r3, #0x10] @ send MSB | ||
427 | 1: @ busy @ | ||
428 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
429 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
430 | bne 1b @ | ||
431 | str r0, [r3, #0x10] @ send LSB | ||
432 | |||
433 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
434 | add r12, r7, r7, asl #2 @ | ||
435 | add r12, r12, r12, asl #4 @ | ||
436 | add r7, r12, r7, asl #6 @ | ||
437 | @ compute R, G, and B | ||
438 | add r0, r8, r7 @ r0 = b' = Y + bu | ||
439 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
440 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
441 | @ | ||
442 | @ r8 = bu, r9 = rv, r10 = guv | ||
443 | @ | ||
444 | sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256 | ||
445 | add r0, r12, r0, lsr #8 @ | ||
446 | @ | ||
447 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
448 | add r11, r12, r11, lsr #8 @ | ||
449 | @ | ||
450 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
451 | add r7, r12, r7, lsr #8 @ | ||
452 | @ | ||
453 | add r12, r14, #0x300 @ | ||
454 | @ | ||
455 | add r0, r0, r12 @ b = r0 + delta | ||
456 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
457 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
458 | @ | ||
459 | orr r12, r0, r11, asr #1 @ check if clamping is needed... | ||
460 | orr r12, r12, r7 @ ...at all | ||
461 | movs r12, r12, asr #15 @ | ||
462 | beq 15f @ no clamp @ | ||
463 | movs r12, r0, asr #15 @ clamp b | ||
464 | mvnne r0, r12, lsr #15 @ | ||
465 | andne r0, r0, #0x7c00 @ mask b only if clamped | ||
466 | movs r12, r11, asr #16 @ clamp r | ||
467 | mvnne r11, r12, lsr #16 @ | ||
468 | movs r12, r7, asr #15 @ clamp g | ||
469 | mvnne r7, r12, lsr #15 @ | ||
470 | 15: @ no clamp @ | ||
471 | @ | ||
472 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
473 | |||
474 | and r11, r11, #0xf800 @ pack pixel | ||
475 | mov r11, r11, lsr #8 | ||
476 | and r7, r7, #0x7e00 | ||
477 | orr r11, r11, r7, lsr #12 | ||
478 | mov r7, r7, lsr#4 | ||
479 | orr r0, r7, r0, lsr #10 | ||
480 | 1: @ busy @ | ||
481 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
482 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
483 | bne 1b @ | ||
484 | str r11, [r3, #0x10] @ send MSB | ||
485 | 1: @ busy @ | ||
486 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
487 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
488 | bne 1b @ | ||
489 | str r0, [r3, #0x10] @ send LSB | ||
490 | |||
491 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
492 | add r12, r7, r7, asl #2 @ | ||
493 | add r12, r12, r12, asl #4 @ | ||
494 | add r7, r12, r7, asl #6 @ | ||
495 | @ compute R, G, and B | ||
496 | add r0, r8, r7 @ r0 = b' = Y + bu | ||
497 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
498 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
499 | @ | ||
500 | sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256 | ||
501 | add r0, r12, r0, lsr #8 @ | ||
502 | @ | ||
503 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
504 | add r11, r12, r11, lsr #8 @ | ||
505 | @ | ||
506 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
507 | add r7, r12, r7, lsr #8 @ | ||
508 | @ | ||
509 | @ This element is zero - use r14 @ | ||
510 | @ | ||
511 | add r0, r0, r14 @ b = r0 + delta | ||
512 | add r11, r11, r14, lsl #1 @ r = r11 + delta*2 | ||
513 | add r7, r7, r14, lsr #1 @ g = r7 + delta/2 | ||
514 | @ | ||
515 | orr r12, r0, r11, asr #1 @ check if clamping is needed... | ||
516 | orr r12, r12, r7 @ ...at all | ||
517 | movs r12, r12, asr #15 @ | ||
518 | beq 15f @ no clamp @ | ||
519 | movs r12, r0, asr #15 @ clamp b | ||
520 | mvnne r0, r12, lsr #15 @ | ||
521 | andne r0, r0, #0x7c00 @ mask b only if clamped | ||
522 | movs r12, r11, asr #16 @ clamp r | ||
523 | mvnne r11, r12, lsr #16 @ | ||
524 | movs r12, r7, asr #15 @ clamp g | ||
525 | mvnne r7, r12, lsr #15 @ | ||
526 | 15: @ no clamp @ | ||
527 | |||
528 | and r11, r11, #0xf800 @ pack pixel | ||
529 | mov r11, r11, lsr #8 | ||
530 | and r7, r7, #0x7e00 | ||
531 | orr r11, r11, r7, lsr #12 | ||
532 | mov r7, r7, lsr#4 | ||
533 | orr r0, r7, r0, lsr #10 | ||
534 | 1: @ busy @ | ||
535 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
536 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
537 | bne 1b @ | ||
538 | str r11, [r3, #0x10] @ send MSB | ||
539 | 1: @ busy @ | ||
540 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
541 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
542 | bne 1b @ | ||
543 | str r0, [r3, #0x10] @ send LSB | ||
544 | |||
545 | subs r1, r1, #2 @ subtract block from width | ||
546 | bgt 10b @ loop line @ | ||
547 | @ | ||
548 | ldmpc regs=r4-r11 @ restore registers and return | ||
549 | .ltorg @ dump constant pool | ||
550 | .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither | ||
diff --git a/firmware/target/arm/samsung/yh820/lcd-yh820.c b/firmware/target/arm/samsung/yh820/lcd-yh820.c index 25692eb8ac..f4b55ab917 100644 --- a/firmware/target/arm/samsung/yh820/lcd-yh820.c +++ b/firmware/target/arm/samsung/yh820/lcd-yh820.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | /* Display status */ | 32 | /* Display status */ |
33 | static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0; | ||
34 | |||
33 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | 35 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) |
34 | static bool is_lcd_enabled = true; | 36 | static bool is_lcd_enabled = true; |
35 | #endif | 37 | #endif |
@@ -289,6 +291,78 @@ void lcd_set_flip(bool yesno) | |||
289 | 291 | ||
290 | /*** update functions ***/ | 292 | /*** update functions ***/ |
291 | 293 | ||
294 | void lcd_yuv_set_options(unsigned options) | ||
295 | { | ||
296 | lcd_yuv_options = options; | ||
297 | } | ||
298 | |||
299 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ | ||
300 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
301 | int width, | ||
302 | int stride); | ||
303 | extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
304 | int width, | ||
305 | int stride, | ||
306 | int x_screen, /* To align dither pattern */ | ||
307 | int y_screen); | ||
308 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
309 | void lcd_blit_yuv(unsigned char * const src[3], | ||
310 | int src_x, int src_y, int stride, | ||
311 | int x, int y, int width, int height) | ||
312 | { | ||
313 | unsigned char const * yuv_src[3]; | ||
314 | off_t z; | ||
315 | |||
316 | /* Sorry, but width and height must be >= 2 or else */ | ||
317 | width &= ~1; | ||
318 | height >>= 1; | ||
319 | |||
320 | z = stride*src_y; | ||
321 | yuv_src[0] = src[0] + z + src_x; | ||
322 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
323 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
324 | |||
325 | lcd_send_command(R_ENTRY_MODE); | ||
326 | lcd_send_command(0x03); | ||
327 | |||
328 | lcd_send_command(R_Y_ADDR_AREA); | ||
329 | lcd_send_command(x + 4); | ||
330 | lcd_send_command(x + width - 1 + 4); | ||
331 | |||
332 | if (lcd_yuv_options & LCD_YUV_DITHER) | ||
333 | { | ||
334 | do | ||
335 | { | ||
336 | lcd_send_command(R_X_ADDR_AREA); | ||
337 | lcd_send_command(y); | ||
338 | lcd_send_command(y + 1); | ||
339 | |||
340 | lcd_write_yuv420_lines_odither(yuv_src, width, stride, x, y); | ||
341 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
342 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
343 | yuv_src[2] += stride >> 1; | ||
344 | y += 2; | ||
345 | } | ||
346 | while (--height > 0); | ||
347 | } | ||
348 | else | ||
349 | { | ||
350 | do | ||
351 | { | ||
352 | lcd_send_command(R_X_ADDR_AREA); | ||
353 | lcd_send_command(y); | ||
354 | lcd_send_command(y + 1); | ||
355 | |||
356 | lcd_write_yuv420_lines(yuv_src, width, stride); | ||
357 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
358 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
359 | yuv_src[2] += stride >> 1; | ||
360 | y += 2; | ||
361 | } | ||
362 | while (--height > 0); | ||
363 | } | ||
364 | } | ||
365 | |||
292 | /* Update the display. | 366 | /* Update the display. |
293 | This must be called after all other LCD functions that change the display. */ | 367 | This must be called after all other LCD functions that change the display. */ |
294 | void lcd_update(void) | 368 | void lcd_update(void) |
diff --git a/firmware/target/arm/samsung/yh925/lcd-as-yh925.S b/firmware/target/arm/samsung/yh925/lcd-as-yh925.S new file mode 100644 index 0000000000..8ac8b4289f --- /dev/null +++ b/firmware/target/arm/samsung/yh925/lcd-as-yh925.S | |||
@@ -0,0 +1,538 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007-2008 by Michael Sevakis | ||
11 | * | ||
12 | * H10 20GB LCD assembly routines | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | #include "config.h" | ||
25 | #include "cpu.h" | ||
26 | |||
27 | /**************************************************************************** | ||
28 | * void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
29 | * int width, | ||
30 | * int stride); | ||
31 | * | ||
32 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
33 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
34 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
35 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
36 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
37 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
38 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
39 | * | ||
40 | * Write four RGB565 pixels in the following order on each loop: | ||
41 | * 1 3 + > down | ||
42 | * 2 4 \/ left | ||
43 | */ | ||
44 | .section .icode, "ax", %progbits | ||
45 | .align 2 | ||
46 | .global lcd_write_yuv420_lines | ||
47 | .type lcd_write_yuv420_lines, %function | ||
48 | lcd_write_yuv420_lines: | ||
49 | @ r0 = yuv_src | ||
50 | @ r1 = width | ||
51 | @ r2 = stride | ||
52 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
53 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
54 | @ r5 = yuv_src[1] = Cb_p | ||
55 | @ r6 = yuv_src[2] = Cr_p | ||
56 | @ | ||
57 | mov r0, #0x7000000c @ r0 = &LCD2_PORT = 0x70008a0c | ||
58 | add r0, r0, #0x8a00 @ | ||
59 | mov r14, #LCD2_DATA_MASK @ | ||
60 | @ | ||
61 | sub r2, r2, #1 @ Adjust stride because of increment | ||
62 | 10: @ loop line @ | ||
63 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
64 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
65 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
66 | @ | ||
67 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 | ||
68 | add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right | ||
69 | add r7, r12, r7, asl #5 @ by one less when adding - same for all | ||
70 | @ | ||
71 | sub r8, r8, #128 @ Cb -= 128 | ||
72 | sub r9, r9, #128 @ Cr -= 128 | ||
73 | @ | ||
74 | add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 | ||
75 | add r10, r10, r10, asl #4 @ | ||
76 | add r10, r10, r8, asl #3 @ | ||
77 | add r10, r10, r8, asl #4 @ | ||
78 | @ | ||
79 | add r11, r9, r9, asl #2 @ r9 = Cr*101 | ||
80 | add r11, r11, r9, asl #5 @ | ||
81 | add r9, r11, r9, asl #6 @ | ||
82 | @ | ||
83 | add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 | ||
84 | mov r8, r8, asr #2 @ | ||
85 | add r9, r9, #256 @ r9 = rv = (r8 + 256) >> 9 | ||
86 | mov r9, r9, asr #9 @ | ||
87 | rsb r10, r10, #128 @ r10 = guv = (-r9 + 128) >> 8 | ||
88 | mov r10, r10, asr #8 @ | ||
89 | @ compute R, G, and B | ||
90 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
91 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
92 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
93 | @ | ||
94 | orr r12, r3, r11 @ check if clamping is needed... | ||
95 | orr r12, r12, r7, asr #1 @ ...at all | ||
96 | cmp r12, #31 @ | ||
97 | bls 15f @ no clamp @ | ||
98 | cmp r3, #31 @ clamp b | ||
99 | mvnhi r3, r3, asr #31 @ | ||
100 | andhi r3, r3, #31 @ | ||
101 | cmp r11, #31 @ clamp r | ||
102 | mvnhi r11, r11, asr #31 @ | ||
103 | andhi r11, r11, #31 @ | ||
104 | cmp r7, #63 @ clamp g | ||
105 | mvnhi r7, r7, asr #31 @ | ||
106 | andhi r7, r7, #63 @ | ||
107 | 15: @ no clamp @ | ||
108 | @ | ||
109 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
110 | @ | ||
111 | orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11) | ||
112 | orr r3, r3, r7, lsl #5 @ r3 |= (g << 5) | ||
113 | @ | ||
114 | orr r7, r14, r3, lsr #8 @ store pixel | ||
115 | orr r11, r14, r3 @ | ||
116 | 20: @ | ||
117 | ldr r3, [r0] @ | ||
118 | tst r3, #LCD2_BUSY_MASK @ | ||
119 | bne 20b @ | ||
120 | str r7, [r0] @ | ||
121 | str r11, [r0] @ | ||
122 | @ | ||
123 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
124 | add r12, r7, r7, asl #2 @ | ||
125 | add r7, r12, r7, asl #5 @ | ||
126 | @ compute R, G, and B | ||
127 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
128 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
129 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
130 | @ | ||
131 | orr r12, r3, r11 @ check if clamping is needed... | ||
132 | orr r12, r12, r7, asr #1 @ ...at all | ||
133 | cmp r12, #31 @ | ||
134 | bls 15f @ no clamp @ | ||
135 | cmp r3, #31 @ clamp b | ||
136 | mvnhi r3, r3, asr #31 @ | ||
137 | andhi r3, r3, #31 @ | ||
138 | cmp r11, #31 @ clamp r | ||
139 | mvnhi r11, r11, asr #31 @ | ||
140 | andhi r11, r11, #31 @ | ||
141 | cmp r7, #63 @ clamp g | ||
142 | mvnhi r7, r7, asr #31 @ | ||
143 | andhi r7, r7, #63 @ | ||
144 | 15: @ no clamp @ | ||
145 | @ | ||
146 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
147 | @ | ||
148 | orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11) | ||
149 | orr r3, r3, r7, lsl #5 @ r3 |= (g << 5) | ||
150 | @ | ||
151 | orr r7, r14, r3, lsr #8 @ store pixel | ||
152 | orr r11, r14, r3 @ | ||
153 | 20: @ | ||
154 | ldr r3, [r0] @ | ||
155 | tst r3, #LCD2_BUSY_MASK @ | ||
156 | bne 20b @ | ||
157 | str r7, [r0] @ | ||
158 | str r11, [r0] @ | ||
159 | @ | ||
160 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
161 | add r12, r7, r7, asl #2 @ | ||
162 | add r7, r12, r7, asl #5 @ | ||
163 | @ compute R, G, and B | ||
164 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
165 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
166 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
167 | @ | ||
168 | orr r12, r3, r11 @ check if clamping is needed... | ||
169 | orr r12, r12, r7, asr #1 @ ...at all | ||
170 | cmp r12, #31 @ | ||
171 | bls 15f @ no clamp @ | ||
172 | cmp r3, #31 @ clamp b | ||
173 | mvnhi r3, r3, asr #31 @ | ||
174 | andhi r3, r3, #31 @ | ||
175 | cmp r11, #31 @ clamp r | ||
176 | mvnhi r11, r11, asr #31 @ | ||
177 | andhi r11, r11, #31 @ | ||
178 | cmp r7, #63 @ clamp g | ||
179 | mvnhi r7, r7, asr #31 @ | ||
180 | andhi r7, r7, #63 @ | ||
181 | 15: @ no clamp @ | ||
182 | @ | ||
183 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
184 | @ | ||
185 | orr r3, r3, r7, lsl #5 @ r3 = b | (g << 5) | ||
186 | orr r3, r3, r11, lsl #11 @ r3 |= (r << 11) | ||
187 | @ | ||
188 | orr r7, r14, r3, lsr #8 @ store pixel | ||
189 | orr r11, r14, r3 @ | ||
190 | 20: @ | ||
191 | ldr r3, [r0] @ | ||
192 | tst r3, #LCD2_BUSY_MASK @ | ||
193 | bne 20b @ | ||
194 | str r7, [r0] @ | ||
195 | str r11, [r0] @ | ||
196 | @ | ||
197 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
198 | add r12, r7, r7, asl #2 @ | ||
199 | add r7, r12, r7, asl #5 @ | ||
200 | @ compute R, G, and B | ||
201 | add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu | ||
202 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
203 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
204 | @ | ||
205 | orr r12, r3, r11 @ check if clamping is needed... | ||
206 | orr r12, r12, r7, asr #1 @ ...at all | ||
207 | cmp r12, #31 @ | ||
208 | bls 15f @ no clamp @ | ||
209 | cmp r3, #31 @ clamp b | ||
210 | mvnhi r3, r3, asr #31 @ | ||
211 | andhi r3, r3, #31 @ | ||
212 | cmp r11, #31 @ clamp r | ||
213 | mvnhi r11, r11, asr #31 @ | ||
214 | andhi r11, r11, #31 @ | ||
215 | cmp r7, #63 @ clamp g | ||
216 | mvnhi r7, r7, asr #31 @ | ||
217 | andhi r7, r7, #63 @ | ||
218 | 15: @ no clamp @ | ||
219 | @ | ||
220 | orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11) | ||
221 | orr r3, r3, r7, lsl #5 @ r3 |= (g << 5) | ||
222 | @ | ||
223 | orr r7, r14, r3, lsr #8 @ store pixel | ||
224 | orr r11, r14, r3 @ | ||
225 | 20: @ | ||
226 | ldr r3, [r0] @ | ||
227 | tst r3, #LCD2_BUSY_MASK @ | ||
228 | bne 20b @ | ||
229 | str r7, [r0] @ | ||
230 | str r11, [r0] @ | ||
231 | @ | ||
232 | subs r1, r1, #2 @ subtract block from width | ||
233 | bgt 10b @ loop line @ | ||
234 | @ | ||
235 | ldmpc regs=r4-r11 @ restore registers and return | ||
236 | .ltorg @ dump constant pool | ||
237 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
238 | |||
239 | |||
240 | /**************************************************************************** | ||
241 | * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
242 | * int width, | ||
243 | * int stride, | ||
244 | * int x_screen, | ||
245 | * int y_screen); | ||
246 | * | ||
247 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
248 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
249 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
250 | * Red scaled at twice g & b but at same precision to place it in correct | ||
251 | * bit position after multiply and leave instruction count lower. | ||
252 | * |R| |258 0 408| |Y' - 16| | ||
253 | * |G| = |149 -49 -104| |Cb - 128| | ||
254 | * |B| |149 258 0| |Cr - 128| | ||
255 | * | ||
256 | * Write four RGB565 pixels in the following order on each loop: | ||
257 | * 1 3 + > down | ||
258 | * 2 4 \/ left | ||
259 | * | ||
260 | * Kernel pattern (raw|use order): | ||
261 | * 5 3 4 2 row0 row2 > down | ||
262 | * 1 7 0 6 | 5 1 3 7 4 0 2 6 col0 left | ||
263 | * 4 2 5 3 | 4 0 2 6 5 1 3 7 col2 \/ | ||
264 | * 0 6 1 7 | ||
265 | */ | ||
266 | .section .icode, "ax", %progbits | ||
267 | .align 2 | ||
268 | .global lcd_write_yuv420_lines_odither | ||
269 | .type lcd_write_yuv420_lines_odither, %function | ||
270 | lcd_write_yuv420_lines_odither: | ||
271 | @ r0 = yuv_src | ||
272 | @ r1 = width | ||
273 | @ r2 = stride | ||
274 | @ r3 = x_screen | ||
275 | @ [sp] = y_screen | ||
276 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
277 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
278 | @ r5 = yuv_src[1] = Cb_p | ||
279 | @ r6 = yuv_src[2] = Cr_p | ||
280 | @ | ||
281 | ldr r0, [sp, #36] @ Line up pattern and kernel quadrant | ||
282 | eor r14, r3, r0 @ | ||
283 | and r14, r14, #0x2 @ | ||
284 | mov r14, r14, lsl #6 @ 0x00 or 0x80 | ||
285 | @ | ||
286 | mov r0, #0x7000000c @ r0 = &LCD2_PORT = 0x70008a0c | ||
287 | add r0, r0, #0x8a00 @ | ||
288 | @ | ||
289 | sub r2, r2, #1 @ Adjust stride because of increment | ||
290 | 10: @ loop line @ | ||
291 | @ | ||
292 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
293 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
294 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
295 | @ | ||
296 | eor r14, r14, #0x80 @ flip pattern quadrant | ||
297 | @ | ||
298 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149 | ||
299 | add r12, r7, r7, asl #2 @ | ||
300 | add r12, r12, r12, asl #4 @ | ||
301 | add r7, r12, r7, asl #6 @ | ||
302 | @ | ||
303 | sub r8, r8, #128 @ Cb -= 128 | ||
304 | sub r9, r9, #128 @ Cr -= 128 | ||
305 | @ | ||
306 | add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49 | ||
307 | add r10, r10, r8, asl #5 @ | ||
308 | add r10, r10, r9, asl #3 @ | ||
309 | add r10, r10, r9, asl #5 @ | ||
310 | add r10, r10, r9, asl #6 @ | ||
311 | @ | ||
312 | mov r8, r8, asl #1 @ r8 = bu = Cb*258 | ||
313 | add r8, r8, r8, asl #7 @ | ||
314 | @ | ||
315 | add r9, r9, r9, asl #1 @ r9 = rv = Cr*408 | ||
316 | add r9, r9, r9, asl #4 @ | ||
317 | mov r9, r9, asl #3 @ | ||
318 | @ | ||
319 | @ compute R, G, and B | ||
320 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
321 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
322 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
323 | @ | ||
324 | @ r8 = bu, r9 = rv, r10 = guv | ||
325 | @ | ||
326 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256 | ||
327 | add r3, r12, r3, lsr #8 @ | ||
328 | @ | ||
329 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
330 | add r11, r12, r11, lsr #8 @ | ||
331 | @ | ||
332 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
333 | add r7, r12, r7, lsr #8 @ | ||
334 | @ | ||
335 | add r12, r14, #0x200 @ | ||
336 | @ | ||
337 | add r3, r3, r12 @ b = r3 + delta | ||
338 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
339 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
340 | @ | ||
341 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
342 | orr r12, r12, r7 @ ...at all | ||
343 | movs r12, r12, asr #15 @ | ||
344 | beq 15f @ no clamp @ | ||
345 | movs r12, r3, asr #15 @ clamp b | ||
346 | mvnne r3, r12, lsr #15 @ | ||
347 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
348 | movs r12, r11, asr #16 @ clamp r | ||
349 | mvnne r11, r12, lsr #16 @ | ||
350 | movs r12, r7, asr #15 @ clamp g | ||
351 | mvnne r7, r12, lsr #15 @ | ||
352 | 15: @ no clamp @ | ||
353 | @ | ||
354 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
355 | @ | ||
356 | and r11, r11, #0xf800 @ pack pixel | ||
357 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
358 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
359 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
360 | @ | ||
361 | mov r11, #LCD2_DATA_MASK @ store pixel | ||
362 | orr r7, r11, r3, lsr #8 @ | ||
363 | orr r11, r11, r3 @ | ||
364 | 20: @ | ||
365 | ldr r3, [r0] @ | ||
366 | tst r3, #LCD2_BUSY_MASK @ | ||
367 | bne 20b @ | ||
368 | str r7, [r0] @ | ||
369 | str r11, [r0] @ | ||
370 | @ | ||
371 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
372 | add r12, r7, r7, asl #2 @ | ||
373 | add r12, r12, r12, asl #4 @ | ||
374 | add r7, r12, r7, asl #6 @ | ||
375 | @ compute R, G, and B | ||
376 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
377 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
378 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
379 | @ | ||
380 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256 | ||
381 | add r3, r12, r3, lsr #8 @ | ||
382 | @ | ||
383 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
384 | add r11, r12, r11, lsr #8 @ | ||
385 | @ | ||
386 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
387 | add r7, r12, r7, lsr #8 @ | ||
388 | @ | ||
389 | @ This element is zero - use r14 @ | ||
390 | @ | ||
391 | add r3, r3, r14 @ b = r3 + delta | ||
392 | add r11, r11, r14, lsl #1 @ r = r11 + delta*2 | ||
393 | add r7, r7, r14, lsr #1 @ g = r7 + delta/2 | ||
394 | @ | ||
395 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
396 | orr r12, r12, r7 @ ...at all | ||
397 | movs r12, r12, asr #15 @ | ||
398 | beq 15f @ no clamp @ | ||
399 | movs r12, r3, asr #15 @ clamp b | ||
400 | mvnne r3, r12, lsr #15 @ | ||
401 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
402 | movs r12, r11, asr #16 @ clamp r | ||
403 | mvnne r11, r12, lsr #16 @ | ||
404 | movs r12, r7, asr #15 @ clamp g | ||
405 | mvnne r7, r12, lsr #15 @ | ||
406 | 15: @ no clamp @ | ||
407 | @ | ||
408 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
409 | @ | ||
410 | and r11, r11, #0xf800 @ pack pixel | ||
411 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
412 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
413 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
414 | @ | ||
415 | mov r11, #LCD2_DATA_MASK @ store pixel | ||
416 | orr r7, r11, r3, lsr #8 @ | ||
417 | orr r11, r11, r3 @ | ||
418 | 20: @ | ||
419 | ldr r3, [r0] @ | ||
420 | tst r3, #LCD2_BUSY_MASK @ | ||
421 | bne 20b @ | ||
422 | str r7, [r0] @ | ||
423 | str r11, [r0] @ | ||
424 | @ | ||
425 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
426 | add r12, r7, r7, asl #2 @ | ||
427 | add r12, r12, r12, asl #4 @ | ||
428 | add r7, r12, r7, asl #6 @ | ||
429 | @ compute R, G, and B | ||
430 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
431 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
432 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
433 | @ | ||
434 | @ r8 = bu, r9 = rv, r10 = guv | ||
435 | @ | ||
436 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256 | ||
437 | add r3, r12, r3, lsr #8 @ | ||
438 | @ | ||
439 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
440 | add r11, r12, r11, lsr #8 @ | ||
441 | @ | ||
442 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
443 | add r7, r12, r7, lsr #8 @ | ||
444 | @ | ||
445 | add r12, r14, #0x100 @ | ||
446 | @ | ||
447 | add r3, r3, r12 @ b = r3 + delta | ||
448 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
449 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
450 | @ | ||
451 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
452 | orr r12, r12, r7 @ ...at all | ||
453 | movs r12, r12, asr #15 @ | ||
454 | beq 15f @ no clamp @ | ||
455 | movs r12, r3, asr #15 @ clamp b | ||
456 | mvnne r3, r12, lsr #15 @ | ||
457 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
458 | movs r12, r11, asr #16 @ clamp r | ||
459 | mvnne r11, r12, lsr #16 @ | ||
460 | movs r12, r7, asr #15 @ clamp g | ||
461 | mvnne r7, r12, lsr #15 @ | ||
462 | 15: @ no clamp @ | ||
463 | @ | ||
464 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
465 | @ | ||
466 | and r11, r11, #0xf800 @ pack pixel | ||
467 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
468 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
469 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
470 | @ | ||
471 | mov r11, #LCD2_DATA_MASK @ store pixel | ||
472 | orr r7, r11, r3, lsr #8 @ | ||
473 | orr r11, r11, r3 @ | ||
474 | 20: @ | ||
475 | ldr r3, [r0] @ | ||
476 | tst r3, #LCD2_BUSY_MASK @ | ||
477 | bne 20b @ | ||
478 | str r7, [r0] @ | ||
479 | str r11, [r0] @ | ||
480 | @ | ||
481 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
482 | add r12, r7, r7, asl #2 @ | ||
483 | add r12, r12, r12, asl #4 @ | ||
484 | add r7, r12, r7, asl #6 @ | ||
485 | @ compute R, G, and B | ||
486 | add r3, r8, r7 @ r3 = b' = Y + bu | ||
487 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
488 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
489 | @ | ||
490 | sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256 | ||
491 | add r3, r12, r3, lsr #8 @ | ||
492 | @ | ||
493 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
494 | add r11, r12, r11, lsr #8 @ | ||
495 | @ | ||
496 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
497 | add r7, r12, r7, lsr #8 @ | ||
498 | @ | ||
499 | add r12, r14, #0x300 @ | ||
500 | @ | ||
501 | add r3, r3, r12 @ b = r3 + delta | ||
502 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
503 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
504 | @ | ||
505 | orr r12, r3, r11, asr #1 @ check if clamping is needed... | ||
506 | orr r12, r12, r7 @ ...at all | ||
507 | movs r12, r12, asr #15 @ | ||
508 | beq 15f @ no clamp @ | ||
509 | movs r12, r3, asr #15 @ clamp b | ||
510 | mvnne r3, r12, lsr #15 @ | ||
511 | andne r3, r3, #0x7c00 @ mask b only if clamped | ||
512 | movs r12, r11, asr #16 @ clamp r | ||
513 | mvnne r11, r12, lsr #16 @ | ||
514 | movs r12, r7, asr #15 @ clamp g | ||
515 | mvnne r7, r12, lsr #15 @ | ||
516 | 15: @ no clamp @ | ||
517 | @ | ||
518 | and r11, r11, #0xf800 @ pack pixel | ||
519 | and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) | | ||
520 | orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | | ||
521 | orr r3, r11, r3, lsr #10 @ (b >> 10) | ||
522 | @ | ||
523 | mov r11, #LCD2_DATA_MASK @ store pixel | ||
524 | orr r7, r11, r3, lsr #8 @ | ||
525 | orr r11, r11, r3 @ | ||
526 | 20: @ | ||
527 | ldr r3, [r0] @ | ||
528 | tst r3, #LCD2_BUSY_MASK @ | ||
529 | bne 20b @ | ||
530 | str r7, [r0] @ | ||
531 | str r11, [r0] @ | ||
532 | @ | ||
533 | subs r1, r1, #2 @ subtract block from width | ||
534 | bgt 10b @ loop line @ | ||
535 | @ | ||
536 | ldmpc regs=r4-r11 @ restore registers and return | ||
537 | .ltorg @ dump constant pool | ||
538 | .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither | ||
diff --git a/firmware/target/arm/samsung/yh925/lcd-yh925.c b/firmware/target/arm/samsung/yh925/lcd-yh925.c index e2b3ae3694..93bfb3a5f2 100644 --- a/firmware/target/arm/samsung/yh925/lcd-yh925.c +++ b/firmware/target/arm/samsung/yh925/lcd-yh925.c | |||
@@ -37,6 +37,8 @@ static unsigned short disp_control_rev; | |||
37 | /* Contrast setting << 8 */ | 37 | /* Contrast setting << 8 */ |
38 | static int lcd_contrast; | 38 | static int lcd_contrast; |
39 | 39 | ||
40 | static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0; | ||
41 | |||
40 | /* Forward declarations */ | 42 | /* Forward declarations */ |
41 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) | 43 | #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) |
42 | static void lcd_display_off(void); | 44 | static void lcd_display_off(void); |
@@ -508,6 +510,98 @@ bool lcd_active(void) | |||
508 | 510 | ||
509 | /*** update functions ***/ | 511 | /*** update functions ***/ |
510 | 512 | ||
513 | void lcd_yuv_set_options(unsigned options) | ||
514 | { | ||
515 | lcd_yuv_options = options; | ||
516 | } | ||
517 | |||
518 | /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ | ||
519 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
520 | int width, | ||
521 | int stride); | ||
522 | extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
523 | int width, | ||
524 | int stride, | ||
525 | int x_screen, /* To align dither pattern */ | ||
526 | int y_screen); | ||
527 | |||
528 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
529 | void lcd_blit_yuv(unsigned char * const src[3], | ||
530 | int src_x, int src_y, int stride, | ||
531 | int x, int y, int width, int height) | ||
532 | { | ||
533 | const unsigned char *yuv_src[3]; | ||
534 | const unsigned char *ysrc_max; | ||
535 | int y0; | ||
536 | int options; | ||
537 | |||
538 | /* NOT MODIFIED FOR THE YH-925 */ | ||
539 | |||
540 | if (!display_on) | ||
541 | return; | ||
542 | |||
543 | width &= ~1; | ||
544 | height &= ~1; | ||
545 | |||
546 | x += x_offset; | ||
547 | |||
548 | /* calculate the drawing region */ | ||
549 | |||
550 | /* The 20GB LCD is actually 128x160 but rotated 90 degrees so the origin | ||
551 | * is actually the bottom left and horizontal and vertical are swapped. | ||
552 | * Rockbox expects the origin to be the top left so we need to use | ||
553 | * 127 - y instead of just y */ | ||
554 | |||
555 | /* max vert << 8 | start vert */ | ||
556 | lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x); | ||
557 | |||
558 | y0 = LCD_HEIGHT - 1 - y + y_offset; | ||
559 | |||
560 | /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=0, LG2-0=000 */ | ||
561 | lcd_write_reg(R_ENTRY_MODE, 0x1020); | ||
562 | |||
563 | yuv_src[0] = src[0] + src_y * stride + src_x; | ||
564 | yuv_src[1] = src[1] + (src_y * stride >> 2) + (src_x >> 1); | ||
565 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
566 | ysrc_max = yuv_src[0] + height * stride; | ||
567 | |||
568 | options = lcd_yuv_options; | ||
569 | |||
570 | do | ||
571 | { | ||
572 | /* max horiz << 8 | start horiz */ | ||
573 | lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (y0 << 8) | (y0 - 1)); | ||
574 | |||
575 | /* position cursor (set AD0-AD15) */ | ||
576 | /* start vert << 8 | start horiz */ | ||
577 | lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | y0); | ||
578 | |||
579 | /* start drawing */ | ||
580 | lcd_send_cmd(R_WRITE_DATA_2_GRAM); | ||
581 | |||
582 | if (options & LCD_YUV_DITHER) | ||
583 | { | ||
584 | lcd_write_yuv420_lines_odither(yuv_src, width, stride, | ||
585 | x, y); | ||
586 | y -= 2; | ||
587 | } | ||
588 | else | ||
589 | { | ||
590 | lcd_write_yuv420_lines(yuv_src, width, stride); | ||
591 | } | ||
592 | |||
593 | y0 -= 2; | ||
594 | yuv_src[0] += stride << 1; | ||
595 | yuv_src[1] += stride >> 1; | ||
596 | yuv_src[2] += stride >> 1; | ||
597 | } | ||
598 | while (yuv_src[0] < ysrc_max); | ||
599 | |||
600 | /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=1, LG2-0=000 */ | ||
601 | lcd_write_reg(R_ENTRY_MODE, 0x1028); | ||
602 | } | ||
603 | |||
604 | |||
511 | /* Update a fraction of the display. */ | 605 | /* Update a fraction of the display. */ |
512 | void lcd_update_rect(int x0, int y0, int width, int height) | 606 | void lcd_update_rect(int x0, int y0, int width, int height) |
513 | { | 607 | { |
diff --git a/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S b/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S new file mode 100644 index 0000000000..542ceeeb36 --- /dev/null +++ b/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S | |||
@@ -0,0 +1,550 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Jens Arnold | ||
11 | * Heavily based on lcd-as-memframe.c by Michael Sevakis | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | |||
23 | #include "config.h" | ||
24 | #include "cpu.h" | ||
25 | |||
26 | /**************************************************************************** | ||
27 | * void lcd_write_yuv420_lines(unsigned char const * const src[3], | ||
28 | * int width, | ||
29 | * int stride); | ||
30 | * | ||
31 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
32 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
33 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
34 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
35 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
36 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
37 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
38 | * | ||
39 | * Write four RGB565 pixels in the following order on each loop: | ||
40 | * 1 3 + > down | ||
41 | * 2 4 \/ left | ||
42 | */ | ||
43 | .section .icode, "ax", %progbits | ||
44 | .align 2 | ||
45 | .global lcd_write_yuv420_lines | ||
46 | .type lcd_write_yuv420_lines, %function | ||
47 | lcd_write_yuv420_lines: | ||
48 | @ r0 = yuv_src | ||
49 | @ r1 = width | ||
50 | @ r2 = stride | ||
51 | stmfd sp!, { r4-r10, lr } @ save non-scratch | ||
52 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
53 | @ r5 = yuv_src[1] = Cb_p | ||
54 | @ r6 = yuv_src[2] = Cr_p | ||
55 | @ r0 = scratch | ||
56 | sub r2, r2, #1 @ | ||
57 | mov r3, #0x70000000 @ | ||
58 | orr r3, r3, #0x3000 @ r3 = LCD1_BASE | ||
59 | 10: @ loop line @ | ||
60 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
61 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
62 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
63 | @ | ||
64 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 | ||
65 | add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right | ||
66 | add r7, r12, r7, asl #5 @ by one less when adding - same for all | ||
67 | @ | ||
68 | sub r8, r8, #128 @ Cb -= 128 | ||
69 | sub r9, r9, #128 @ Cr -= 128 | ||
70 | @ | ||
71 | add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 | ||
72 | add r10, r10, r10, asl #4 @ | ||
73 | add r10, r10, r8, asl #3 @ | ||
74 | add r10, r10, r8, asl #4 @ | ||
75 | @ | ||
76 | add lr, r9, r9, asl #2 @ r9 = Cr*101 | ||
77 | add lr, lr, r9, asl #5 @ | ||
78 | add r9, lr, r9, asl #6 @ | ||
79 | @ | ||
80 | add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 | ||
81 | mov r8, r8, asr #2 @ | ||
82 | add r9, r9, #256 @ r9 = rv = (r9 + 256) >> 9 | ||
83 | mov r9, r9, asr #9 @ | ||
84 | rsb r10, r10, #128 @ r10 = guv = (-r10 + 128) >> 8 | ||
85 | mov r10, r10, asr #8 @ | ||
86 | @ compute R, G, and B | ||
87 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
88 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
89 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
90 | @ | ||
91 | orr r12, r0, lr @ check if clamping is needed... | ||
92 | orr r12, r12, r7, asr #1 @ ...at all | ||
93 | cmp r12, #31 @ | ||
94 | bls 15f @ no clamp @ | ||
95 | cmp r0, #31 @ clamp b | ||
96 | mvnhi r0, r0, asr #31 @ | ||
97 | andhi r0, r0, #31 @ | ||
98 | cmp lr, #31 @ clamp r | ||
99 | mvnhi lr, lr, asr #31 @ | ||
100 | andhi lr, lr, #31 @ | ||
101 | cmp r7, #63 @ clamp g | ||
102 | mvnhi r7, r7, asr #31 @ | ||
103 | andhi r7, r7, #63 @ | ||
104 | 15: @ no clamp @ | ||
105 | @ | ||
106 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
107 | @ | ||
108 | mov lr, lr, lsl #3 @ | ||
109 | orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3) | ||
110 | orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b | ||
111 | 1: @ busy @ | ||
112 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
113 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
114 | bne 1b @ | ||
115 | str lr, [r3, #0x10] @ send MSB | ||
116 | 1: @busy @ | ||
117 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
118 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
119 | bne 1b @ | ||
120 | str r0, [r3, #0x10] @ send LSB | ||
121 | @ | ||
122 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
123 | add r12, r7, r7, asl #2 @ | ||
124 | add r7, r12, r7, asl #5 @ | ||
125 | @ compute R, G, and B | ||
126 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
127 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
128 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
129 | @ | ||
130 | orr r12, r0, lr @ check if clamping is needed... | ||
131 | orr r12, r12, r7, asr #1 @ ...at all | ||
132 | cmp r12, #31 @ | ||
133 | bls 15f @ no clamp @ | ||
134 | cmp r0, #31 @ clamp b | ||
135 | mvnhi r0, r0, asr #31 @ | ||
136 | andhi r0, r0, #31 @ | ||
137 | cmp lr, #31 @ clamp r | ||
138 | mvnhi lr, lr, asr #31 @ | ||
139 | andhi lr, lr, #31 @ | ||
140 | cmp r7, #63 @ clamp g | ||
141 | mvnhi r7, r7, asr #31 @ | ||
142 | andhi r7, r7, #63 @ | ||
143 | 15: @ no clamp @ | ||
144 | @ | ||
145 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
146 | @ | ||
147 | mov lr, lr, lsl #3 @ | ||
148 | orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3) | ||
149 | orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b | ||
150 | 1: @ busy @ | ||
151 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
152 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
153 | bne 1b @ | ||
154 | str lr, [r3, #0x10] @ send MSB | ||
155 | 1: @ busy @ | ||
156 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
157 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
158 | bne 1b @ | ||
159 | str r0, [r3, #0x10] @ send LSB | ||
160 | @ | ||
161 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
162 | add r12, r7, r7, asl #2 @ | ||
163 | add r7, r12, r7, asl #5 @ | ||
164 | @ compute R, G, and B | ||
165 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
166 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
167 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
168 | @ | ||
169 | orr r12, r0, lr @ check if clamping is needed... | ||
170 | orr r12, r12, r7, asr #1 @ ...at all | ||
171 | cmp r12, #31 @ | ||
172 | bls 15f @ no clamp @ | ||
173 | cmp r0, #31 @ clamp b | ||
174 | mvnhi r0, r0, asr #31 @ | ||
175 | andhi r0, r0, #31 @ | ||
176 | cmp lr, #31 @ clamp r | ||
177 | mvnhi lr, lr, asr #31 @ | ||
178 | andhi lr, lr, #31 @ | ||
179 | cmp r7, #63 @ clamp g | ||
180 | mvnhi r7, r7, asr #31 @ | ||
181 | andhi r7, r7, #63 @ | ||
182 | 15: @ no clamp @ | ||
183 | @ | ||
184 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
185 | @ | ||
186 | @ | ||
187 | mov lr, lr, lsl #3 @ | ||
188 | orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3) | ||
189 | orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b | ||
190 | 1: @ busy @ | ||
191 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
192 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
193 | bne 1b @ | ||
194 | str lr, [r3, #0x10] @ send MSB | ||
195 | 1: @ busy @ | ||
196 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
197 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
198 | bne 1b @ | ||
199 | str r0, [r3, #0x10] @ send LSB | ||
200 | @ | ||
201 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
202 | add r12, r7, r7, asl #2 @ | ||
203 | add r7, r12, r7, asl #5 @ | ||
204 | @ compute R, G, and B | ||
205 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
206 | add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv | ||
207 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
208 | @ | ||
209 | orr r12, r0, lr @ check if clamping is needed... | ||
210 | orr r12, r12, r7, asr #1 @ ...at all | ||
211 | cmp r12, #31 @ | ||
212 | bls 15f @ no clamp @ | ||
213 | cmp r0, #31 @ clamp b | ||
214 | mvnhi r0, r0, asr #31 @ | ||
215 | andhi r0, r0, #31 @ | ||
216 | cmp lr, #31 @ clamp r | ||
217 | mvnhi lr, lr, asr #31 @ | ||
218 | andhi lr, lr, #31 @ | ||
219 | cmp r7, #63 @ clamp g | ||
220 | mvnhi r7, r7, asr #31 @ | ||
221 | andhi r7, r7, #63 @ | ||
222 | 15: @ no clamp @ | ||
223 | @ | ||
224 | mov lr, lr, lsl #3 @ | ||
225 | orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3) | ||
226 | orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b | ||
227 | 1: @ busy @ | ||
228 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
229 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
230 | bne 1b @ | ||
231 | str lr, [r3, #0x10] @ send MSB | ||
232 | 1: @ busy @ | ||
233 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
234 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
235 | bne 1b @ | ||
236 | str r0, [r3, #0x10] @ send LSB | ||
237 | @ | ||
238 | subs r1, r1, #2 @ subtract block from width | ||
239 | bgt 10b @ loop line @ | ||
240 | @ | ||
241 | ldmpc regs=r4-r10 @ restore registers and return | ||
242 | .ltorg @ dump constant pool | ||
243 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
244 | |||
245 | /**************************************************************************** | ||
246 | * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3], | ||
247 | * int width, | ||
248 | * int stride, | ||
249 | * int x_screen, | ||
250 | * int y_screen); | ||
251 | * | ||
252 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
253 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
254 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
255 | * Red scaled at twice g & b but at same precision to place it in correct | ||
256 | * bit position after multiply and leave instruction count lower. | ||
257 | * |R| |258 0 408| |Y' - 16| | ||
258 | * |G| = |149 -49 -104| |Cb - 128| | ||
259 | * |B| |149 258 0| |Cr - 128| | ||
260 | * | ||
261 | * Write four RGB565 pixels in the following order on each loop: | ||
262 | * 1 3 + > down | ||
263 | * 2 4 \/ left | ||
264 | * | ||
265 | * Kernel pattern (raw|rotated|use order): | ||
266 | * 5 3 4 2 2 6 3 7 row0 row2 > down | ||
267 | * 1 7 0 6 | 4 0 5 1 | 2 4 6 0 3 5 7 1 col0 left | ||
268 | * 4 2 5 3 | 3 7 2 6 | 3 5 7 1 2 4 6 0 col2 \/ | ||
269 | * 0 6 1 7 5 1 4 0 | ||
270 | */ | ||
271 | .section .icode, "ax", %progbits | ||
272 | .align 2 | ||
273 | .global lcd_write_yuv420_lines_odither | ||
274 | .type lcd_write_yuv420_lines_odither, %function | ||
275 | lcd_write_yuv420_lines_odither: | ||
276 | @ r0 = yuv_src | ||
277 | @ r1 = width | ||
278 | @ r2 = stride | ||
279 | @ r3 = x_screen | ||
280 | @ [sp] = y_screen | ||
281 | stmfd sp!, { r4-r11, lr } @ save non-scratch | ||
282 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
283 | @ r5 = yuv_src[1] = Cb_p | ||
284 | @ r6 = yuv_src[2] = Cr_p | ||
285 | @ | ||
286 | sub r2, r2, #1 @ | ||
287 | ldr r14, [sp, #36] @ Line up pattern and kernel quadrant | ||
288 | eor r14, r14, r3 @ | ||
289 | and r14, r14, #0x2 @ | ||
290 | mov r14, r14, lsl #6 @ 0x00 or 0x80 | ||
291 | mov r3, #0x70000000 @ | ||
292 | orr r3, r3, #0x3000 @ r3 = LCD1_BASE | ||
293 | 10: @ loop line @ | ||
294 | @ | ||
295 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
296 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
297 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
298 | @ | ||
299 | eor r14, r14, #0x80 @ flip pattern quadrant | ||
300 | @ | ||
301 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149 | ||
302 | add r12, r7, r7, asl #2 @ | ||
303 | add r12, r12, r12, asl #4 @ | ||
304 | add r7, r12, r7, asl #6 @ | ||
305 | @ | ||
306 | sub r8, r8, #128 @ Cb -= 128 | ||
307 | sub r9, r9, #128 @ Cr -= 128 | ||
308 | @ | ||
309 | add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49 | ||
310 | add r10, r10, r8, asl #5 @ | ||
311 | add r10, r10, r9, asl #3 @ | ||
312 | add r10, r10, r9, asl #5 @ | ||
313 | add r10, r10, r9, asl #6 @ | ||
314 | @ | ||
315 | mov r8, r8, asl #1 @ r8 = bu = Cb*258 | ||
316 | add r8, r8, r8, asl #7 @ | ||
317 | @ | ||
318 | add r9, r9, r9, asl #1 @ r9 = rv = Cr*408 | ||
319 | add r9, r9, r9, asl #4 @ | ||
320 | mov r9, r9, asl #3 @ | ||
321 | @ | ||
322 | @ compute R, G, and B | ||
323 | add r0, r8, r7 @ r0 = b' = Y + bu | ||
324 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
325 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
326 | @ | ||
327 | @ r8 = bu, r9 = rv, r10 = guv | ||
328 | @ | ||
329 | sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256 | ||
330 | add r0, r12, r0, lsr #8 @ | ||
331 | @ | ||
332 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
333 | add r11, r12, r11, lsr #8 @ | ||
334 | @ | ||
335 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
336 | add r7, r12, r7, lsr #8 @ | ||
337 | @ | ||
338 | add r12, r14, #0x100 @ | ||
339 | @ | ||
340 | add r0, r0, r12 @ b = r0 + delta | ||
341 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
342 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
343 | @ | ||
344 | orr r12, r0, r11, asr #1 @ check if clamping is needed... | ||
345 | orr r12, r12, r7 @ ...at all | ||
346 | movs r12, r12, asr #15 @ | ||
347 | beq 15f @ no clamp @ | ||
348 | movs r12, r0, asr #15 @ clamp b | ||
349 | mvnne r0, r12, lsr #15 @ | ||
350 | andne r0, r0, #0x7c00 @ mask b only if clamped | ||
351 | movs r12, r11, asr #16 @ clamp r | ||
352 | mvnne r11, r12, lsr #16 @ | ||
353 | movs r12, r7, asr #15 @ clamp g | ||
354 | mvnne r7, r12, lsr #15 @ | ||
355 | 15: @ no clamp @ | ||
356 | @ | ||
357 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
358 | @ | ||
359 | |||
360 | and r11, r11, #0xf800 @ pack pixel | ||
361 | mov r11, r11, lsr #8 | ||
362 | and r7, r7, #0x7e00 | ||
363 | orr r11, r11, r7, lsr #12 | ||
364 | mov r7, r7, lsr#4 | ||
365 | orr r0, r7, r0, lsr #10 | ||
366 | 1: @ busy @ | ||
367 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
368 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
369 | bne 1b @ | ||
370 | str r11, [r3, #0x10] @ send MSB | ||
371 | 1: @ busy @ | ||
372 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
373 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
374 | bne 1b @ | ||
375 | str r0, [r3, #0x10] @ send LSB | ||
376 | @ | ||
377 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
378 | add r12, r7, r7, asl #2 @ | ||
379 | add r12, r12, r12, asl #4 @ | ||
380 | add r7, r12, r7, asl #6 @ | ||
381 | @ compute R, G, and B | ||
382 | add r0, r8, r7 @ r0 = b' = Y + bu | ||
383 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
384 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
385 | @ | ||
386 | sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256 | ||
387 | add r0, r12, r0, lsr #8 @ | ||
388 | @ | ||
389 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
390 | add r11, r12, r11, lsr #8 @ | ||
391 | @ | ||
392 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
393 | add r7, r12, r7, lsr #8 @ | ||
394 | @ | ||
395 | add r12, r14, #0x200 @ | ||
396 | @ | ||
397 | add r0, r0, r12 @ b = r0 + delta | ||
398 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
399 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
400 | @ | ||
401 | orr r12, r0, r11, asr #1 @ check if clamping is needed... | ||
402 | orr r12, r12, r7 @ ...at all | ||
403 | movs r12, r12, asr #15 @ | ||
404 | beq 15f @ no clamp @ | ||
405 | movs r12, r0, asr #15 @ clamp b | ||
406 | mvnne r0, r12, lsr #15 @ | ||
407 | andne r0, r0, #0x7c00 @ mask b only if clamped | ||
408 | movs r12, r11, asr #16 @ clamp r | ||
409 | mvnne r11, r12, lsr #16 @ | ||
410 | movs r12, r7, asr #15 @ clamp g | ||
411 | mvnne r7, r12, lsr #15 @ | ||
412 | 15: @ no clamp @ | ||
413 | @ | ||
414 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
415 | |||
416 | and r11, r11, #0xf800 @ pack pixel | ||
417 | mov r11, r11, lsr #8 | ||
418 | and r7, r7, #0x7e00 | ||
419 | orr r11, r11, r7, lsr #12 | ||
420 | mov r7, r7, lsr#4 | ||
421 | orr r0, r7, r0, lsr #10 | ||
422 | 1: @ busy @ | ||
423 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
424 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
425 | bne 1b @ | ||
426 | str r11, [r3, #0x10] @ send MSB | ||
427 | 1: @ busy @ | ||
428 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
429 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
430 | bne 1b @ | ||
431 | str r0, [r3, #0x10] @ send LSB | ||
432 | |||
433 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
434 | add r12, r7, r7, asl #2 @ | ||
435 | add r12, r12, r12, asl #4 @ | ||
436 | add r7, r12, r7, asl #6 @ | ||
437 | @ compute R, G, and B | ||
438 | add r0, r8, r7 @ r0 = b' = Y + bu | ||
439 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
440 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
441 | @ | ||
442 | @ r8 = bu, r9 = rv, r10 = guv | ||
443 | @ | ||
444 | sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256 | ||
445 | add r0, r12, r0, lsr #8 @ | ||
446 | @ | ||
447 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256 | ||
448 | add r11, r12, r11, lsr #8 @ | ||
449 | @ | ||
450 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256 | ||
451 | add r7, r12, r7, lsr #8 @ | ||
452 | @ | ||
453 | add r12, r14, #0x300 @ | ||
454 | @ | ||
455 | add r0, r0, r12 @ b = r0 + delta | ||
456 | add r11, r11, r12, lsl #1 @ r = r11 + delta*2 | ||
457 | add r7, r7, r12, lsr #1 @ g = r7 + delta/2 | ||
458 | @ | ||
459 | orr r12, r0, r11, asr #1 @ check if clamping is needed... | ||
460 | orr r12, r12, r7 @ ...at all | ||
461 | movs r12, r12, asr #15 @ | ||
462 | beq 15f @ no clamp @ | ||
463 | movs r12, r0, asr #15 @ clamp b | ||
464 | mvnne r0, r12, lsr #15 @ | ||
465 | andne r0, r0, #0x7c00 @ mask b only if clamped | ||
466 | movs r12, r11, asr #16 @ clamp r | ||
467 | mvnne r11, r12, lsr #16 @ | ||
468 | movs r12, r7, asr #15 @ clamp g | ||
469 | mvnne r7, r12, lsr #15 @ | ||
470 | 15: @ no clamp @ | ||
471 | @ | ||
472 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
473 | |||
474 | and r11, r11, #0xf800 @ pack pixel | ||
475 | mov r11, r11, lsr #8 | ||
476 | and r7, r7, #0x7e00 | ||
477 | orr r11, r11, r7, lsr #12 | ||
478 | mov r7, r7, lsr#4 | ||
479 | orr r0, r7, r0, lsr #10 | ||
480 | 1: @ busy @ | ||
481 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
482 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
483 | bne 1b @ | ||
484 | str r11, [r3, #0x10] @ send MSB | ||
485 | 1: @ busy @ | ||
486 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
487 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
488 | bne 1b @ | ||
489 | str r0, [r3, #0x10] @ send LSB | ||
490 | |||
491 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149 | ||
492 | add r12, r7, r7, asl #2 @ | ||
493 | add r12, r12, r12, asl #4 @ | ||
494 | add r7, r12, r7, asl #6 @ | ||
495 | @ compute R, G, and B | ||
496 | add r0, r8, r7 @ r0 = b' = Y + bu | ||
497 | add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv | ||
498 | rsb r7, r10, r7 @ r7 = g' = Y + guv | ||
499 | @ | ||
500 | sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256 | ||
501 | add r0, r12, r0, lsr #8 @ | ||
502 | @ | ||
503 | sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256 | ||
504 | add r11, r12, r11, lsr #8 @ | ||
505 | @ | ||
506 | sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256 | ||
507 | add r7, r12, r7, lsr #8 @ | ||
508 | @ | ||
509 | @ This element is zero - use r14 @ | ||
510 | @ | ||
511 | add r0, r0, r14 @ b = r0 + delta | ||
512 | add r11, r11, r14, lsl #1 @ r = r11 + delta*2 | ||
513 | add r7, r7, r14, lsr #1 @ g = r7 + delta/2 | ||
514 | @ | ||
515 | orr r12, r0, r11, asr #1 @ check if clamping is needed... | ||
516 | orr r12, r12, r7 @ ...at all | ||
517 | movs r12, r12, asr #15 @ | ||
518 | beq 15f @ no clamp @ | ||
519 | movs r12, r0, asr #15 @ clamp b | ||
520 | mvnne r0, r12, lsr #15 @ | ||
521 | andne r0, r0, #0x7c00 @ mask b only if clamped | ||
522 | movs r12, r11, asr #16 @ clamp r | ||
523 | mvnne r11, r12, lsr #16 @ | ||
524 | movs r12, r7, asr #15 @ clamp g | ||
525 | mvnne r7, r12, lsr #15 @ | ||
526 | 15: @ no clamp @ | ||
527 | |||
528 | and r11, r11, #0xf800 @ pack pixel | ||
529 | mov r11, r11, lsr #8 | ||
530 | and r7, r7, #0x7e00 | ||
531 | orr r11, r11, r7, lsr #12 | ||
532 | mov r7, r7, lsr#4 | ||
533 | orr r0, r7, r0, lsr #10 | ||
534 | 1: @ busy @ | ||
535 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
536 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
537 | bne 1b @ | ||
538 | str r11, [r3, #0x10] @ send MSB | ||
539 | 1: @ busy @ | ||
540 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
541 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
542 | bne 1b @ | ||
543 | str r0, [r3, #0x10] @ send LSB | ||
544 | |||
545 | subs r1, r1, #2 @ subtract block from width | ||
546 | bgt 10b @ loop line @ | ||
547 | @ | ||
548 | ldmpc regs=r4-r11 @ restore registers and return | ||
549 | .ltorg @ dump constant pool | ||
550 | .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither | ||
diff --git a/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c b/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c index e851c421a6..8620c672e1 100644 --- a/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c +++ b/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c | |||
@@ -273,7 +273,15 @@ void lcd_init_device(void) | |||
273 | #if defined(HAVE_LCD_MODES) | 273 | #if defined(HAVE_LCD_MODES) |
274 | void lcd_set_mode(int mode) | 274 | void lcd_set_mode(int mode) |
275 | { | 275 | { |
276 | if(mode==LCD_MODE_RGB565) { | 276 | if(mode==LCD_MODE_YUV) { |
277 | /* Turn off the RGB buffer and enable the YUV buffer with zoom */ | ||
278 | IO_OSD_OSDWINMD0 |= 0x04; | ||
279 | IO_OSD_VIDWINMD |= 0x01; | ||
280 | #if LCD_NATIVE_WIDTH > 240 | ||
281 | IO_OSD_VIDWINMD |= (0x05<<2); /* This does a 2x zoom */ | ||
282 | #endif | ||
283 | memset16(FRAME2, 0x0080, LCD_NATIVE_HEIGHT*(LCD_NATIVE_WIDTH+LCD_FUDGE)); | ||
284 | } else if(mode==LCD_MODE_RGB565) { | ||
277 | /* Turn on the RGB window, set it to 16 bit and turn YUV window off */ | 285 | /* Turn on the RGB window, set it to 16 bit and turn YUV window off */ |
278 | IO_OSD_VIDWINMD &= ~(0x01); | 286 | IO_OSD_VIDWINMD &= ~(0x01); |
279 | IO_OSD_OSDWIN0OFST = LCD_NATIVE_WIDTH / 16; | 287 | IO_OSD_OSDWIN0OFST = LCD_NATIVE_WIDTH / 16; |
@@ -636,6 +644,82 @@ void lcd_pal256_update_pal(fb_data *palette) | |||
636 | } | 644 | } |
637 | #endif | 645 | #endif |
638 | 646 | ||
647 | /* Performance function to blit a YUV bitmap directly to the LCD */ | ||
648 | /* Show it rotated so the LCD_WIDTH is now the height */ | ||
649 | void lcd_blit_yuv(unsigned char * const src[3], | ||
650 | int src_x, int src_y, int stride, | ||
651 | int x, int y, int width, int height) | ||
652 | { | ||
653 | unsigned char const * yuv_src[3]; | ||
654 | |||
655 | if (!lcd_on) | ||
656 | return; | ||
657 | |||
658 | /* y has to be on a 16 pixel boundary */ | ||
659 | y &= ~0xF; | ||
660 | |||
661 | if( ((y | x | height | width ) < 0) | ||
662 | || y>LCD_NATIVE_HEIGHT || x>LCD_NATIVE_WIDTH ) | ||
663 | return; | ||
664 | |||
665 | if(y+height>LCD_NATIVE_WIDTH) | ||
666 | { | ||
667 | height=LCD_NATIVE_WIDTH-y; | ||
668 | } | ||
669 | if(x+width>LCD_NATIVE_HEIGHT) | ||
670 | { | ||
671 | width=LCD_NATIVE_HEIGHT-x; | ||
672 | } | ||
673 | |||
674 | /* Sorry, but width and height must be >= 2 or else */ | ||
675 | width &= ~1; | ||
676 | height>>=1; | ||
677 | |||
678 | fb_data * dst = FRAME2 | ||
679 | + ((LCD_NATIVE_WIDTH+LCD_FUDGE)*(LCD_NATIVE_HEIGHT-1)) | ||
680 | - (LCD_NATIVE_WIDTH+LCD_FUDGE)*x + y ; | ||
681 | |||
682 | /* Scope z */ | ||
683 | { | ||
684 | off_t z; | ||
685 | z = stride*src_y; | ||
686 | yuv_src[0] = src[0] + z + src_x; | ||
687 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
688 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
689 | } | ||
690 | |||
691 | int cbcr_remain=(stride>>1)-(width>>1); | ||
692 | int y_remain=(stride<<1)-width; | ||
693 | do | ||
694 | { | ||
695 | register int c_width=width; | ||
696 | register unsigned int *c_dst=(unsigned int*)dst; | ||
697 | do | ||
698 | { | ||
699 | register unsigned short Y=*((unsigned short*)yuv_src[0]); | ||
700 | register unsigned short Yst=*((unsigned short*)(yuv_src[0]+stride)); | ||
701 | yuv_src[0]+=2; | ||
702 | |||
703 | register unsigned char Cb=*yuv_src[1]++; | ||
704 | register unsigned char Cr=*yuv_src[2]++; | ||
705 | |||
706 | *c_dst = (Yst<<24) | (Cr << 16) | ((Y&0xFF)<<8) | Cb; | ||
707 | *(c_dst - (LCD_NATIVE_WIDTH+LCD_FUDGE)/2) = | ||
708 | ( (Yst&0xFF00)<<16) | (Cr << 16) | (Y&0xFF00) | Cb; | ||
709 | |||
710 | c_dst -= (LCD_NATIVE_WIDTH+LCD_FUDGE); | ||
711 | |||
712 | c_width -= 2; | ||
713 | } while (c_width); | ||
714 | |||
715 | yuv_src[0] += y_remain; /* Skip down two luma lines-width */ | ||
716 | yuv_src[1] += cbcr_remain; /* Skip down one chroma line-width/2 */ | ||
717 | yuv_src[2] += cbcr_remain; | ||
718 | |||
719 | dst+=2; | ||
720 | } while (--height); | ||
721 | } | ||
722 | |||
639 | void lcd_set_contrast(int val) { | 723 | void lcd_set_contrast(int val) { |
640 | (void) val; | 724 | (void) val; |
641 | // TODO: | 725 | // TODO: |