summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/iriver/h10/lcd-as-h10.S528
-rw-r--r--firmware/target/arm/iriver/h10/lcd-h10_20gb.c203
2 files changed, 586 insertions, 145 deletions
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..f4f7b9398e
--- /dev/null
+++ b/firmware/target/arm/iriver/h10/lcd-as-h10.S
@@ -0,0 +1,528 @@
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 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
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#include "config.h"
23#include "cpu.h"
24
25/****************************************************************************
26 * void lcd_write_yuv_420_lines(unsigned char const * const src[3],
27 * int width,
28 * int stride);
29 *
30 * |R| |1.000000 -0.000001 1.402000| |Y'|
31 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
32 * |B| |1.000000 1.772000 0.000000| |Pr|
33 * Scaled, normalized, rounded and tweaked to yield RGB 565:
34 * |R| |74 0 101| |Y' - 16| >> 9
35 * |G| = |74 -24 -51| |Cb - 128| >> 8
36 * |B| |74 128 0| |Cr - 128| >> 9
37 *
38 * Write four RGB565 pixels in the following order on each loop:
39 * 1 3 + > down
40 * 2 4 \/ left
41 */
42 .section .icode, "ax", %progbits
43 .align 2
44 .global lcd_write_yuv420_lines
45 .type lcd_write_yuv420_lines, %function
46lcd_write_yuv420_lines:
47 @ r0 = yuv_src
48 @ r1 = width
49 @ r2 = stride
50 stmfd sp!, { r4-r12, lr } @ save non-scratch
51 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
52 @ r5 = yuv_src[1] = Cb_p
53 @ r6 = yuv_src[2] = Cr_p
54 @
55 mov r0, #0x7000000c @ r0 = &LCD2_PORT = 0x70008a0c
56 add r0, r0, #0x8a00 @
57 mov r14, #LCD2_DATA_MASK @
58 @
59 sub r2, r2, #1 @ Adjust stride because of increment
6010: @ loop line @
61 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
62 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
63 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
64 @
65 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74
66 add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right
67 add r7, r12, r7, asl #5 @ by one less when adding - same for all
68 @
69 sub r8, r8, #128 @ Cb -= 128
70 sub r9, r9, #128 @ Cr -= 128
71 @
72 add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24
73 add r10, r10, r10, asl #4 @
74 add r10, r10, r8, asl #3 @
75 add r10, r10, r8, asl #4 @
76 @
77 add r11, r9, r9, asl #2 @ r9 = Cr*101
78 add r11, r11, r9, asl #5 @
79 add r9, r11, r9, asl #6 @
80 @
81 add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8
82 mov r8, r8, asr #2 @
83 add r9, r9, #256 @ r9 = rv = (r8 + 256) >> 9
84 mov r9, r9, asr #9 @
85 rsb r10, r10, #128 @ r10 = guv = (-r9 + 128) >> 8
86 mov r10, r10, asr #8 @
87 @ compute R, G, and B
88 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
89 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
90 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
91 @
92 orr r12, r3, r11 @ check if clamping is needed...
93 orr r12, r12, r7, asr #1 @ ...at all
94 cmp r12, #31 @
95 bls 15f @ no clamp @
96 cmp r3, #31 @ clamp b
97 mvnhi r3, r3, asr #31 @
98 andhi r3, r3, #31 @
99 cmp r11, #31 @ clamp r
100 mvnhi r11, r11, asr #31 @
101 andhi r11, r11, #31 @
102 cmp r7, #63 @ clamp g
103 mvnhi r7, r7, asr #31 @
104 andhi r7, r7, #63 @
10515: @ no clamp @
106 @
107 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
108 @
109 orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11)
110 orr r3, r3, r7, lsl #5 @ r3 |= (g << 5)
111 @
112 orr r7, r14, r3, lsr #8 @ store pixel
113 orr r11, r14, r3 @
11420: @
115 ldr r3, [r0] @
116 tst r3, #LCD2_BUSY_MASK @
117 bne 20b @
118 stmia r0, { r7, r11 } @
119 @
120 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
121 add r12, r7, r7, asl #2 @
122 add r7, r12, r7, asl #5 @
123 @ compute R, G, and B
124 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
125 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
126 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
127 @
128 orr r12, r3, r11 @ check if clamping is needed...
129 orr r12, r12, r7, asr #1 @ ...at all
130 cmp r12, #31 @
131 bls 15f @ no clamp @
132 cmp r3, #31 @ clamp b
133 mvnhi r3, r3, asr #31 @
134 andhi r3, r3, #31 @
135 cmp r11, #31 @ clamp r
136 mvnhi r11, r11, asr #31 @
137 andhi r11, r11, #31 @
138 cmp r7, #63 @ clamp g
139 mvnhi r7, r7, asr #31 @
140 andhi r7, r7, #63 @
14115: @ no clamp @
142 @
143 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
144 @
145 orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11)
146 orr r3, r3, r7, lsl #5 @ r3 |= (g << 5)
147 @
148 orr r7, r14, r3, lsr #8 @ store pixel
149 orr r11, r14, r3 @
15020: @
151 ldr r3, [r0] @
152 tst r3, #LCD2_BUSY_MASK @
153 bne 20b @
154 stmia r0, { r7, r11 } @
155 @
156 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
157 add r12, r7, r7, asl #2 @
158 add r7, r12, r7, asl #5 @
159 @ compute R, G, and B
160 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
161 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
162 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
163 @
164 orr r12, r3, r11 @ check if clamping is needed...
165 orr r12, r12, r7, asr #1 @ ...at all
166 cmp r12, #31 @
167 bls 15f @ no clamp @
168 cmp r3, #31 @ clamp b
169 mvnhi r3, r3, asr #31 @
170 andhi r3, r3, #31 @
171 cmp r11, #31 @ clamp r
172 mvnhi r11, r11, asr #31 @
173 andhi r11, r11, #31 @
174 cmp r7, #63 @ clamp g
175 mvnhi r7, r7, asr #31 @
176 andhi r7, r7, #63 @
17715: @ no clamp @
178 @
179 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
180 @
181 orr r3, r3, r7, lsl #5 @ r3 = b | (g << 5)
182 orr r3, r3, r11, lsl #11 @ r3 |= (r << 11)
183 @
184 orr r7, r14, r3, lsr #8 @ store pixel
185 orr r11, r14, r3 @
18620: @
187 ldr r3, [r0] @
188 tst r3, #LCD2_BUSY_MASK @
189 bne 20b @
190 stmia r0, { r7, r11 } @
191 @
192 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
193 add r12, r7, r7, asl #2 @
194 add r7, r12, r7, asl #5 @
195 @ compute R, G, and B
196 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
197 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
198 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
199 @
200 orr r12, r3, r11 @ check if clamping is needed...
201 orr r12, r12, r7, asr #1 @ ...at all
202 cmp r12, #31 @
203 bls 15f @ no clamp @
204 cmp r3, #31 @ clamp b
205 mvnhi r3, r3, asr #31 @
206 andhi r3, r3, #31 @
207 cmp r11, #31 @ clamp r
208 mvnhi r11, r11, asr #31 @
209 andhi r11, r11, #31 @
210 cmp r7, #63 @ clamp g
211 mvnhi r7, r7, asr #31 @
212 andhi r7, r7, #63 @
21315: @ no clamp @
214 @
215 orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11)
216 orr r3, r3, r7, lsl #5 @ r3 |= (g << 5)
217 @
218 orr r7, r14, r3, lsr #8 @ store pixel
219 orr r11, r14, r3 @
22020: @
221 ldr r3, [r0] @
222 tst r3, #LCD2_BUSY_MASK @
223 bne 20b @
224 stmia r0, { r7, r11 } @
225 @
226 subs r1, r1, #2 @ subtract block from width
227 bgt 10b @ loop line @
228 @
229 ldmfd sp!, { r4-r12, pc } @ restore registers and return
230 .ltorg @ dump constant pool
231 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
232
233
234/****************************************************************************
235 * void lcd_write_yuv_420_lines_odither(unsigned char const * const src[3],
236 * int width,
237 * int stride,
238 * int x_screen,
239 * int y_screen);
240 *
241 * |R| |1.000000 -0.000001 1.402000| |Y'|
242 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
243 * |B| |1.000000 1.772000 0.000000| |Pr|
244 * Red scaled at twice g & b but at same precision to place it in correct
245 * bit position after multiply and leave instruction count lower.
246 * |R| |258 0 408| |Y' - 16|
247 * |G| = |149 -49 -104| |Cb - 128|
248 * |B| |149 258 0| |Cr - 128|
249 *
250 * Write four RGB565 pixels in the following order on each loop:
251 * 1 3 + > down
252 * 2 4 \/ left
253 *
254 * Kernel pattern (raw|use order):
255 * 5 3 4 2 row0 row2 > down
256 * 1 7 0 6 | 5 1 3 7 4 0 2 6 col0 left
257 * 4 2 5 3 | 4 0 2 6 5 1 3 7 col2 \/
258 * 0 6 1 7
259 */
260 .section .icode, "ax", %progbits
261 .align 2
262 .global lcd_write_yuv420_lines_odither
263 .type lcd_write_yuv420_lines_odither, %function
264lcd_write_yuv420_lines_odither:
265 @ r0 = yuv_src
266 @ r1 = width
267 @ r2 = stride
268 @ r3 = x_screen
269 @ [sp] = y_screen
270 stmfd sp!, { r4-r12, lr } @ save non-scratch
271 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
272 @ r5 = yuv_src[1] = Cb_p
273 @ r6 = yuv_src[2] = Cr_p
274 @
275 ldr r0, [sp, #40] @ Line up pattern and kernel quadrant
276 eor r14, r3, r0 @
277 and r14, r14, #0x2 @
278 mov r14, r14, lsl #6 @ 0x00 or 0x80
279 @
280 mov r0, #0x7000000c @ r0 = &LCD2_PORT = 0x70008a0c
281 add r0, r0, #0x8a00 @
282 @
283 sub r2, r2, #1 @ Adjust stride because of increment
28410: @ loop line @
285 @
286 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
287 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
288 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
289 @
290 eor r14, r14, #0x80 @ flip pattern quadrant
291 @
292 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149
293 add r12, r7, r7, asl #2 @
294 add r12, r12, r12, asl #4 @
295 add r7, r12, r7, asl #6 @
296 @
297 sub r8, r8, #128 @ Cb -= 128
298 sub r9, r9, #128 @ Cr -= 128
299 @
300 add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49
301 add r10, r10, r8, asl #5 @
302 add r10, r10, r9, asl #3 @
303 add r10, r10, r9, asl #5 @
304 add r10, r10, r9, asl #6 @
305 @
306 mov r8, r8, asl #1 @ r8 = bu = Cb*258
307 add r8, r8, r8, asl #7 @
308 @
309 add r9, r9, r9, asl #1 @ r9 = rv = Cr*408
310 add r9, r9, r9, asl #4 @
311 mov r9, r9, asl #3 @
312 @
313 @ compute R, G, and B
314 add r3, r8, r7 @ r3 = b' = Y + bu
315 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
316 rsb r7, r10, r7 @ r7 = g' = Y + guv
317 @
318 @ r8 = bu, r9 = rv, r10 = guv
319 @
320 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256
321 add r3, r12, r3, lsr #8 @
322 @
323 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
324 add r11, r12, r11, lsr #8 @
325 @
326 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
327 add r7, r12, r7, lsr #8 @
328 @
329 add r12, r14, #0x200 @
330 @
331 add r3, r3, r12 @ b = r3 + delta
332 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
333 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
334 @
335 orr r12, r3, r11, asr #1 @ check if clamping is needed...
336 orr r12, r12, r7 @ ...at all
337 movs r12, r12, asr #15 @
338 beq 15f @ no clamp @
339 movs r12, r3, asr #15 @ clamp b
340 mvnne r3, r12, lsr #15 @
341 andne r3, r3, #0x7c00 @ mask b only if clamped
342 movs r12, r11, asr #16 @ clamp r
343 mvnne r11, r12, lsr #16 @
344 movs r12, r7, asr #15 @ clamp g
345 mvnne r7, r12, lsr #15 @
34615: @ no clamp @
347 @
348 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
349 @
350 and r11, r11, #0xf800 @ pack pixel
351 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
352 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
353 orr r3, r11, r3, lsr #10 @ (b >> 10)
354 @
355 mov r11, #LCD2_DATA_MASK @ store pixel
356 orr r7, r11, r3, lsr #8 @
357 orr r11, r11, r3 @
35820: @
359 ldr r3, [r0] @
360 tst r3, #LCD2_BUSY_MASK @
361 bne 20b @
362 stmia r0, { r7, r11 } @
363 @
364 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
365 add r12, r7, r7, asl #2 @
366 add r12, r12, r12, asl #4 @
367 add r7, r12, r7, asl #6 @
368 @ compute R, G, and B
369 add r3, r8, r7 @ r3 = b' = Y + bu
370 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
371 rsb r7, r10, r7 @ r7 = g' = Y + guv
372 @
373 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256
374 add r3, r12, r3, lsr #8 @
375 @
376 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
377 add r11, r12, r11, lsr #8 @
378 @
379 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
380 add r7, r12, r7, lsr #8 @
381 @
382 @ This element is zero - use r14 @
383 @
384 add r3, r3, r14 @ b = r3 + delta
385 add r11, r11, r14, lsl #1 @ r = r11 + delta*2
386 add r7, r7, r14, lsr #1 @ g = r7 + delta/2
387 @
388 orr r12, r3, r11, asr #1 @ check if clamping is needed...
389 orr r12, r12, r7 @ ...at all
390 movs r12, r12, asr #15 @
391 beq 15f @ no clamp @
392 movs r12, r3, asr #15 @ clamp b
393 mvnne r3, r12, lsr #15 @
394 andne r3, r3, #0x7c00 @ mask b only if clamped
395 movs r12, r11, asr #16 @ clamp r
396 mvnne r11, r12, lsr #16 @
397 movs r12, r7, asr #15 @ clamp g
398 mvnne r7, r12, lsr #15 @
39915: @ no clamp @
400 @
401 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
402 @
403 and r11, r11, #0xf800 @ pack pixel
404 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
405 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
406 orr r3, r11, r3, lsr #10 @ (b >> 10)
407 @
408 mov r11, #LCD2_DATA_MASK @ store pixel
409 orr r7, r11, r3, lsr #8 @
410 orr r11, r11, r3 @
41120: @
412 ldr r3, [r0] @
413 tst r3, #LCD2_BUSY_MASK @
414 bne 20b @
415 stmia r0, { r7, r11 } @
416 @
417 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
418 add r12, r7, r7, asl #2 @
419 add r12, r12, r12, asl #4 @
420 add r7, r12, r7, asl #6 @
421 @ compute R, G, and B
422 add r3, r8, r7 @ r3 = b' = Y + bu
423 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
424 rsb r7, r10, r7 @ r7 = g' = Y + guv
425 @
426 @ r8 = bu, r9 = rv, r10 = guv
427 @
428 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256
429 add r3, r12, r3, lsr #8 @
430 @
431 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
432 add r11, r12, r11, lsr #8 @
433 @
434 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
435 add r7, r12, r7, lsr #8 @
436 @
437 add r12, r14, #0x100 @
438 @
439 add r3, r3, r12 @ b = r3 + delta
440 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
441 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
442 @
443 orr r12, r3, r11, asr #1 @ check if clamping is needed...
444 orr r12, r12, r7 @ ...at all
445 movs r12, r12, asr #15 @
446 beq 15f @ no clamp @
447 movs r12, r3, asr #15 @ clamp b
448 mvnne r3, r12, lsr #15 @
449 andne r3, r3, #0x7c00 @ mask b only if clamped
450 movs r12, r11, asr #16 @ clamp r
451 mvnne r11, r12, lsr #16 @
452 movs r12, r7, asr #15 @ clamp g
453 mvnne r7, r12, lsr #15 @
45415: @ no clamp @
455 @
456 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
457 @
458 and r11, r11, #0xf800 @ pack pixel
459 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
460 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
461 orr r3, r11, r3, lsr #10 @ (b >> 10)
462 @
463 mov r11, #LCD2_DATA_MASK @ store pixel
464 orr r7, r11, r3, lsr #8 @
465 orr r11, r11, r3 @
46620: @
467 ldr r3, [r0] @
468 tst r3, #LCD2_BUSY_MASK @
469 bne 20b @
470 stmia r0, { r7, r11 } @
471 @
472 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
473 add r12, r7, r7, asl #2 @
474 add r12, r12, r12, asl #4 @
475 add r7, r12, r7, asl #6 @
476 @ compute R, G, and B
477 add r3, r8, r7 @ r3 = b' = Y + bu
478 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
479 rsb r7, r10, r7 @ r7 = g' = Y + guv
480 @
481 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256
482 add r3, r12, r3, lsr #8 @
483 @
484 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
485 add r11, r12, r11, lsr #8 @
486 @
487 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
488 add r7, r12, r7, lsr #8 @
489 @
490 add r12, r14, #0x300 @
491 @
492 add r3, r3, r12 @ b = r3 + delta
493 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
494 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
495 @
496 orr r12, r3, r11, asr #1 @ check if clamping is needed...
497 orr r12, r12, r7 @ ...at all
498 movs r12, r12, asr #15 @
499 beq 15f @ no clamp @
500 movs r12, r3, asr #15 @ clamp b
501 mvnne r3, r12, lsr #15 @
502 andne r3, r3, #0x7c00 @ mask b only if clamped
503 movs r12, r11, asr #16 @ clamp r
504 mvnne r11, r12, lsr #16 @
505 movs r12, r7, asr #15 @ clamp g
506 mvnne r7, r12, lsr #15 @
50715: @ no clamp @
508 @
509 and r11, r11, #0xf800 @ pack pixel
510 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
511 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
512 orr r3, r11, r3, lsr #10 @ (b >> 10)
513 @
514 mov r11, #LCD2_DATA_MASK @ store pixel
515 orr r7, r11, r3, lsr #8 @
516 orr r11, r11, r3 @
51720: @
518 ldr r3, [r0] @
519 tst r3, #LCD2_BUSY_MASK @
520 bne 20b @
521 stmia r0, { r7, r11 } @
522 @
523 subs r1, r1, #2 @ subtract block from width
524 bgt 10b @ loop line @
525 @
526 ldmfd sp!, { r4-r12, pc } @ restore registers and return
527 .ltorg @ dump constant pool
528 .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 2c527fa4d9..892adffea9 100644
--- a/firmware/target/arm/iriver/h10/lcd-h10_20gb.c
+++ b/firmware/target/arm/iriver/h10/lcd-h10_20gb.c
@@ -34,6 +34,8 @@ static unsigned short disp_control_rev;
34/* Contrast setting << 8 */ 34/* Contrast setting << 8 */
35static int lcd_contrast; 35static int lcd_contrast;
36 36
37static unsigned lcd_yuv_options NOCACHEBSS_ATTR = 0;
38
37/* Forward declarations */ 39/* Forward declarations */
38static void lcd_display_off(void); 40static void lcd_display_off(void);
39 41
@@ -166,8 +168,6 @@ void lcd_set_flip(bool yesno)
166 lcd_write_reg(R_GATE_SCAN_START_POS, yesno ? 0x0002 : 0x0000); 168 lcd_write_reg(R_GATE_SCAN_START_POS, yesno ? 0x0002 : 0x0000);
167 /* SM=0, GS=x, SS=x, NL4-0=10011 (G1-G160) */ 169 /* SM=0, GS=x, SS=x, NL4-0=10011 (G1-G160) */
168 lcd_write_reg(R_DRV_OUTPUT_CONTROL, yesno ? 0x0213 : 0x0113); 170 lcd_write_reg(R_DRV_OUTPUT_CONTROL, yesno ? 0x0213 : 0x0113);
169 /* HEA7-0=0xxx, HSA7-0=0xxx */
170 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, y_offset ? 0x8304 : 0x7f00);
171} 171}
172 172
173/* LCD init */ 173/* LCD init */
@@ -239,8 +239,8 @@ static void lcd_power_on(void)
239 lcd_write_reg(R_1ST_SCR_DRV_POS, 0x9f00); 239 lcd_write_reg(R_1ST_SCR_DRV_POS, 0x9f00);
240 /* SE27-20(End)=0x5c (92), SS27-20(Start)=0x00 */ 240 /* SE27-20(End)=0x5c (92), SS27-20(Start)=0x00 */
241 lcd_write_reg(R_2ND_SCR_DRV_POS, 0x5c00); 241 lcd_write_reg(R_2ND_SCR_DRV_POS, 0x5c00);
242 /* HEA7-0=0xxx, HSA7-0=0xxx */ 242 /* HEA7-0=7f, HSA7-0=00 */
243 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, y_offset ? 0x8304 : 0x7f00); 243 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, 0x7f00);
244 /* PKP12-10=0x0, PKP02-00=0x0 */ 244 /* PKP12-10=0x0, PKP02-00=0x0 */
245 lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0003); 245 lcd_write_reg(R_GAMMA_FINE_ADJ_POS1, 0x0003);
246 /* PKP32-30=0x4, PKP22-20=0x0 */ 246 /* PKP32-30=0x4, PKP22-20=0x0 */
@@ -395,177 +395,91 @@ void lcd_blit(const fb_data* data, int x, int by, int width,
395 (void)stride; 395 (void)stride;
396} 396}
397 397
398#define CSUB_X 2 398void lcd_yuv_set_options(unsigned options)
399#define CSUB_Y 2 399{
400 400 lcd_yuv_options = options;
401#define RYFAC (31*257) 401}
402#define GYFAC (31*257)
403#define BYFAC (31*257)
404#define RVFAC 11170 /* 31 * 257 * 1.402 */
405#define GVFAC (-5690) /* 31 * 257 * -0.714136 */
406#define GUFAC (-2742) /* 31 * 257 * -0.344136 */
407#define BUFAC 14118 /* 31 * 257 * 1.772 */
408 402
409#define ROUNDOFFS (127*257) 403/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
410#define ROUNDOFFSG (63*257) 404extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
405 int width,
406 int stride);
407extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
408 int width,
409 int stride,
410 int x_screen, /* To align dither pattern */
411 int y_screen);
411 412
412/* Performance function to blit a YUV bitmap directly to the LCD */ 413/* Performance function to blit a YUV bitmap directly to the LCD */
413void lcd_yuv_blit(unsigned char * const src[3], 414void lcd_yuv_blit(unsigned char * const src[3],
414 int src_x, int src_y, int stride, 415 int src_x, int src_y, int stride,
415 int x, int y, int width, int height) 416 int x, int y, int width, int height)
416{ 417{
417 int y0, x0, y1, x1; 418 const unsigned char *yuv_src[3];
418 int ymax; 419 const unsigned char *ysrc_max;
420 int y0;
421 int options;
419 422
420 if (!display_on) 423 if (!display_on)
421 return; 424 return;
422 425
423 width = (width + 1) & ~1; 426 width &= ~1;
427 height &= ~1;
424 428
425 /* calculate the drawing region */ 429 /* calculate the drawing region */
426 x0 = x;
427 x1 = x + width - 1;
428 y0 = y;
429 y1 = y + height - 1;
430 430
431 /* The 20GB LCD is actually 128x160 but rotated 90 degrees so the origin 431 /* The 20GB LCD is actually 128x160 but rotated 90 degrees so the origin
432 * is actually the bottom left and horizontal and vertical are swapped. 432 * is actually the bottom left and horizontal and vertical are swapped.
433 * Rockbox expects the origin to be the top left so we need to use 433 * Rockbox expects the origin to be the top left so we need to use
434 * 127 - y instead of just y */ 434 * 127 - y instead of just y */
435
436 /* max horiz << 8 | start horiz */
437 lcd_send_cmd(R_HORIZ_RAM_ADDR_POS);
438 lcd_send_data( (((LCD_HEIGHT-1)-y0+y_offset) << 8) | ((LCD_HEIGHT-1)-y1+y_offset) );
439 435
440 /* max vert << 8 | start vert */ 436 /* max vert << 8 | start vert */
441 lcd_send_cmd(R_VERT_RAM_ADDR_POS); 437 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x);
442 lcd_send_data((x1 << 8) | x0);
443
444 /* position cursor (set AD0-AD15) */
445 /* start vert << 8 | start horiz */
446 lcd_send_cmd(R_RAM_ADDR_SET);
447 lcd_send_data( (x0 << 8) | ((LCD_HEIGHT-1)-y0+y_offset) );
448
449 /* start drawing */
450 lcd_send_cmd(R_WRITE_DATA_2_GRAM);
451 438
452 ymax = y + height - 1 ; 439 y0 = LCD_HEIGHT - 1 - y + y_offset;
453 440
454 const int stride_div_csub_x = stride/CSUB_X; 441 /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=0, LG2-0=000 */
442 lcd_write_reg(R_ENTRY_MODE, 0x1020);
455 443
456 for (; y <= ymax ; y++) 444 yuv_src[0] = src[0] + src_y * stride + src_x;
457 { 445 yuv_src[1] = src[1] + (src_y * stride >> 2) + (src_x >> 1);
458 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ 446 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
459 const unsigned char *ysrc = src[0] + stride * src_y + src_x; 447 ysrc_max = yuv_src[0] + height * stride;
460 448
461 const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) + 449 options = lcd_yuv_options;
462 (src_x/CSUB_X);
463 450
464 const unsigned char *usrc = src[1] + uvoffset; 451 do
465 const unsigned char *vsrc = src[2] + uvoffset; 452 {
466 const unsigned char *row_end = ysrc + width; 453 /* max horiz << 8 | start horiz */
454 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (y0 << 8) | (y0 - 1));
467 455
468 int y, u, v; 456 /* position cursor (set AD0-AD15) */
469 int red1, green1, blue1; 457 /* start vert << 8 | start horiz */
470 int red2, green2, blue2; 458 lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | y0);
471 unsigned rbits, gbits, bbits;
472 459
473 int rc, gc, bc; 460 /* start drawing */
461 lcd_send_cmd(R_WRITE_DATA_2_GRAM);
474 462
475 do 463 if (options & LCD_YUV_DITHER)
464 {
465 lcd_write_yuv420_lines_odither(yuv_src, width, stride,
466 x, y);
467 y -= 2;
468 }
469 else
476 { 470 {
477 u = *usrc++ - 128; 471 lcd_write_yuv420_lines(yuv_src, width, stride);
478 v = *vsrc++ - 128;
479 rc = RVFAC * v + ROUNDOFFS;
480 gc = GVFAC * v + GUFAC * u + ROUNDOFFSG;
481 bc = BUFAC * u + ROUNDOFFS;
482
483 /* Pixel 1 */
484 y = *ysrc++;
485
486 red1 = RYFAC * y + rc;
487 green1 = GYFAC * y + gc;
488 blue1 = BYFAC * y + bc;
489
490 /* Pixel 2 */
491 y = *ysrc++;
492 red2 = RYFAC * y + rc;
493 green2 = GYFAC * y + gc;
494 blue2 = BYFAC * y + bc;
495
496 /* Since out of bounds errors are relatively rare, we check two
497 pixels at once to see if any components are out of bounds, and
498 then fix whichever is broken. This works due to high values and
499 negative values both becoming larger than the cutoff when
500 casted to unsigned. And ORing them together checks all of them
501 simultaneously. */
502 if (((unsigned)(red1 | green1 | blue1 |
503 red2 | green2 | blue2)) > (RYFAC*255+ROUNDOFFS)) {
504 if (((unsigned)(red1 | green1 | blue1)) >
505 (RYFAC*255+ROUNDOFFS)) {
506 if ((unsigned)red1 > (RYFAC*255+ROUNDOFFS))
507 {
508 if (red1 < 0)
509 red1 = 0;
510 else
511 red1 = (RYFAC*255+ROUNDOFFS);
512 }
513 if ((unsigned)green1 > (GYFAC*255+ROUNDOFFSG))
514 {
515 if (green1 < 0)
516 green1 = 0;
517 else
518 green1 = (GYFAC*255+ROUNDOFFSG);
519 }
520 if ((unsigned)blue1 > (BYFAC*255+ROUNDOFFS))
521 {
522 if (blue1 < 0)
523 blue1 = 0;
524 else
525 blue1 = (BYFAC*255+ROUNDOFFS);
526 }
527 }
528
529 if (((unsigned)(red2 | green2 | blue2)) >
530 (RYFAC*255+ROUNDOFFS)) {
531 if ((unsigned)red2 > (RYFAC*255+ROUNDOFFS))
532 {
533 if (red2 < 0)
534 red2 = 0;
535 else
536 red2 = (RYFAC*255+ROUNDOFFS);
537 }
538 if ((unsigned)green2 > (GYFAC*255+ROUNDOFFSG))
539 {
540 if (green2 < 0)
541 green2 = 0;
542 else
543 green2 = (GYFAC*255+ROUNDOFFSG);
544 }
545 if ((unsigned)blue2 > (BYFAC*255+ROUNDOFFS))
546 {
547 if (blue2 < 0)
548 blue2 = 0;
549 else
550 blue2 = (BYFAC*255+ROUNDOFFS);
551 }
552 }
553 }
554
555 rbits = red1 >> 16 ;
556 gbits = green1 >> 15 ;
557 bbits = blue1 >> 16 ;
558 lcd_send_data((rbits << 11) | (gbits << 5) | bbits);
559
560 rbits = red2 >> 16 ;
561 gbits = green2 >> 15 ;
562 bbits = blue2 >> 16 ;
563 lcd_send_data((rbits << 11) | (gbits << 5) | bbits);
564 } 472 }
565 while (ysrc < row_end);
566 473
567 src_y++; 474 y0 -= 2;
475 yuv_src[0] += stride << 1;
476 yuv_src[1] += stride >> 1;
477 yuv_src[2] += stride >> 1;
568 } 478 }
479 while (yuv_src[0] < ysrc_max);
480
481 /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=1, LG2-0=000 */
482 lcd_write_reg(R_ENTRY_MODE, 0x1028);
569} 483}
570 484
571 485
@@ -573,8 +487,7 @@ void lcd_yuv_blit(unsigned char * const src[3],
573void lcd_update_rect(int x0, int y0, int width, int height) 487void lcd_update_rect(int x0, int y0, int width, int height)
574{ 488{
575 int x1, y1; 489 int x1, y1;
576 490 unsigned short *addr;
577 unsigned short *addr = (unsigned short *)lcd_framebuffer;
578 491
579 if (!display_on) 492 if (!display_on)
580 return; 493 return;