diff options
Diffstat (limited to 'firmware/target/arm/philips')
-rw-r--r-- | firmware/target/arm/philips/hdd1630/lcd-as-hdd1630.S | 570 | ||||
-rw-r--r-- | firmware/target/arm/philips/hdd1630/lcd-hdd1630.c | 81 | ||||
-rw-r--r-- | firmware/target/arm/philips/hdd6330/lcd-as-hdd6330.S | 140 | ||||
-rw-r--r-- | firmware/target/arm/philips/hdd6330/lcd-hdd6330.c | 98 | ||||
-rw-r--r-- | firmware/target/arm/philips/sa9200/lcd-as-sa9200.S | 590 | ||||
-rw-r--r-- | firmware/target/arm/philips/sa9200/lcd-sa9200.c | 82 |
6 files changed, 1561 insertions, 0 deletions
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) |