diff options
Diffstat (limited to 'firmware/target/arm/sandisk/sansa-c200')
-rw-r--r-- | firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S | 243 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/sansa-c200/lcd-c200.c | 49 |
2 files changed, 284 insertions, 8 deletions
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..9b0cd75bae --- /dev/null +++ b/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S | |||
@@ -0,0 +1,243 @@ | |||
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 | * All files in this archive are subject to the GNU General Public License. | ||
14 | * See the file COPYING in the source tree root for full license agreement. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | #include "config.h" | ||
22 | #include "cpu.h" | ||
23 | |||
24 | /**************************************************************************** | ||
25 | * void lcd_write_yuv_420_lines(unsigned char const * const src[3], | ||
26 | * int width, | ||
27 | * int stride); | ||
28 | * | ||
29 | * |R| |1.000000 -0.000001 1.402000| |Y'| | ||
30 | * |G| = |1.000000 -0.334136 -0.714136| |Pb| | ||
31 | * |B| |1.000000 1.772000 0.000000| |Pr| | ||
32 | * Scaled, normalized, rounded and tweaked to yield RGB 565: | ||
33 | * |R| |74 0 101| |Y' - 16| >> 9 | ||
34 | * |G| = |74 -24 -51| |Cb - 128| >> 8 | ||
35 | * |B| |74 128 0| |Cr - 128| >> 9 | ||
36 | * | ||
37 | * Write four RGB565 pixels in the following order on each loop: | ||
38 | * 1 3 + > down | ||
39 | * 2 4 \/ left | ||
40 | */ | ||
41 | .section .icode, "ax", %progbits | ||
42 | .align 2 | ||
43 | .global lcd_write_yuv420_lines | ||
44 | .type lcd_write_yuv420_lines, %function | ||
45 | lcd_write_yuv420_lines: | ||
46 | @ r0 = yuv_src | ||
47 | @ r1 = width | ||
48 | @ r2 = stride | ||
49 | stmfd sp!, { r4-r12 } @ save non-scratch | ||
50 | ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p | ||
51 | @ r5 = yuv_src[1] = Cb_p | ||
52 | @ r6 = yuv_src[2] = Cr_p | ||
53 | @ r0 = scratch | ||
54 | sub r2, r2, #1 @ | ||
55 | mov r3, #0x70000000 @ | ||
56 | orr r3, r3, #0x3000 @ r3 = LCD1_BASE | ||
57 | 10: @ loop line @ | ||
58 | ldrb r7, [r4], #1 @ r7 = *Y'_p++; | ||
59 | ldrb r8, [r5], #1 @ r8 = *Cb_p++; | ||
60 | ldrb r9, [r6], #1 @ r9 = *Cr_p++; | ||
61 | @ | ||
62 | sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 | ||
63 | add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right | ||
64 | add r7, r12, r7, asl #5 @ by one less when adding - same for all | ||
65 | @ | ||
66 | sub r8, r8, #128 @ Cb -= 128 | ||
67 | sub r9, r9, #128 @ Cr -= 128 | ||
68 | @ | ||
69 | add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 | ||
70 | add r10, r10, r10, asl #4 @ | ||
71 | add r10, r10, r8, asl #3 @ | ||
72 | add r10, r10, r8, asl #4 @ | ||
73 | @ | ||
74 | add r11, r9, r9, asl #2 @ r9 = Cr*101 | ||
75 | add r11, r11, r9, asl #5 @ | ||
76 | add r9, r11, r9, asl #6 @ | ||
77 | @ | ||
78 | add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 | ||
79 | mov r8, r8, asr #2 @ | ||
80 | add r9, r9, #256 @ r9 = rv = (r9 + 256) >> 9 | ||
81 | mov r9, r9, asr #9 @ | ||
82 | rsb r10, r10, #128 @ r10 = guv = (-r10 + 128) >> 8 | ||
83 | mov r10, r10, asr #8 @ | ||
84 | @ compute R, G, and B | ||
85 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
86 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
87 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
88 | @ | ||
89 | orr r12, r0, r11 @ check if clamping is needed... | ||
90 | orr r12, r12, r7, asr #1 @ ...at all | ||
91 | cmp r12, #31 @ | ||
92 | bls 15f @ no clamp @ | ||
93 | cmp r0, #31 @ clamp b | ||
94 | mvnhi r0, r0, asr #31 @ | ||
95 | andhi r0, r0, #31 @ | ||
96 | cmp r11, #31 @ clamp r | ||
97 | mvnhi r11, r11, asr #31 @ | ||
98 | andhi r11, r11, #31 @ | ||
99 | cmp r7, #63 @ clamp g | ||
100 | mvnhi r7, r7, asr #31 @ | ||
101 | andhi r7, r7, #63 @ | ||
102 | 15: @ no clamp @ | ||
103 | @ | ||
104 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
105 | @ | ||
106 | mov r11, r11, lsl #3 @ | ||
107 | orr r11, r11, r7, lsr #3 @ r11 = (r << 3) | (g >> 3) | ||
108 | orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b | ||
109 | 1: @ busy @ | ||
110 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
111 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
112 | bne 1b @ | ||
113 | str r11, [r3, #0x10] @ send MSB | ||
114 | 1: @busy @ | ||
115 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
116 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
117 | bne 1b @ | ||
118 | str r0, [r3, #0x10] @ send LSB | ||
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 r0, r8, r7, asr #8 @ r0 = 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, r0, 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 r0, #31 @ clamp b | ||
133 | mvnhi r0, r0, asr #31 @ | ||
134 | andhi r0, r0, #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 @ | ||
141 | 15: @ no clamp @ | ||
142 | @ | ||
143 | ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) | ||
144 | @ | ||
145 | mov r11, r11, lsl #3 @ | ||
146 | orr r11, r11, r7, lsr #3 @ r11 = (r << 3) | (g >> 3) | ||
147 | orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b | ||
148 | 1: @ busy @ | ||
149 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
150 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
151 | bne 1b @ | ||
152 | str r11, [r3, #0x10] @ send MSB | ||
153 | 1: @ busy @ | ||
154 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
155 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
156 | bne 1b @ | ||
157 | str r0, [r3, #0x10] @ send LSB | ||
158 | @ | ||
159 | sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 | ||
160 | add r12, r7, r7, asl #2 @ | ||
161 | add r7, r12, r7, asl #5 @ | ||
162 | @ compute R, G, and B | ||
163 | add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu | ||
164 | add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
165 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
166 | @ | ||
167 | orr r12, r0, r11 @ check if clamping is needed... | ||
168 | orr r12, r12, r7, asr #1 @ ...at all | ||
169 | cmp r12, #31 @ | ||
170 | bls 15f @ no clamp @ | ||
171 | cmp r0, #31 @ clamp b | ||
172 | mvnhi r0, r0, asr #31 @ | ||
173 | andhi r0, r0, #31 @ | ||
174 | cmp r11, #31 @ clamp r | ||
175 | mvnhi r11, r11, asr #31 @ | ||
176 | andhi r11, r11, #31 @ | ||
177 | cmp r7, #63 @ clamp g | ||
178 | mvnhi r7, r7, asr #31 @ | ||
179 | andhi r7, r7, #63 @ | ||
180 | 15: @ no clamp @ | ||
181 | @ | ||
182 | ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride) | ||
183 | @ | ||
184 | @ | ||
185 | mov r11, r11, lsl #3 @ | ||
186 | orr r11, r11, r7, lsr #3 @ r11 = (r << 3) | (g >> 3) | ||
187 | orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b | ||
188 | 1: @ busy @ | ||
189 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
190 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
191 | bne 1b @ | ||
192 | str r11, [r3, #0x10] @ send MSB | ||
193 | 1: @ busy @ | ||
194 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
195 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
196 | bne 1b @ | ||
197 | str r0, [r3, #0x10] @ send LSB | ||
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 r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv | ||
205 | add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv | ||
206 | @ | ||
207 | orr r12, r0, r11 @ 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 r11, #31 @ clamp r | ||
215 | mvnhi r11, r11, asr #31 @ | ||
216 | andhi r11, r11, #31 @ | ||
217 | cmp r7, #63 @ clamp g | ||
218 | mvnhi r7, r7, asr #31 @ | ||
219 | andhi r7, r7, #63 @ | ||
220 | 15: @ no clamp @ | ||
221 | @ | ||
222 | mov r11, r11, lsl #3 @ | ||
223 | orr r11, r11, r7, lsr #3 @ r11 = (r << 3) | (g >> 3) | ||
224 | orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b | ||
225 | 1: @ busy @ | ||
226 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
227 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
228 | bne 1b @ | ||
229 | str r11, [r3, #0x10] @ send MSB | ||
230 | 1: @ busy @ | ||
231 | ldr r7, [r3] @ r7 = LCD1_BASE | ||
232 | tst r7, #LCD1_BUSY_MASK @ bridge busy? | ||
233 | bne 1b @ | ||
234 | str r0, [r3, #0x10] @ send LSB | ||
235 | @ | ||
236 | subs r1, r1, #2 @ subtract block from width | ||
237 | bgt 10b @ loop line @ | ||
238 | @ | ||
239 | ldmfd sp!, { r4-r12 } @ restore registers and return | ||
240 | bx lr @ | ||
241 | .ltorg @ dump constant pool | ||
242 | .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines | ||
243 | |||
diff --git a/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c b/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c index ef336b46c0..d503fd2c9b 100644 --- a/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c +++ b/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c | |||
@@ -206,19 +206,49 @@ void lcd_blit(const fb_data* data, int x, int by, int width, | |||
206 | (void)stride; | 206 | (void)stride; |
207 | } | 207 | } |
208 | 208 | ||
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); | ||
209 | /* Performance function to blit a YUV bitmap directly to the LCD */ | 213 | /* Performance function to blit a YUV bitmap directly to the LCD */ |
210 | void lcd_yuv_blit(unsigned char * const src[3], | 214 | void lcd_yuv_blit(unsigned char * const src[3], |
211 | int src_x, int src_y, int stride, | 215 | int src_x, int src_y, int stride, |
212 | int x, int y, int width, int height) | 216 | int x, int y, int width, int height) |
213 | { | 217 | { |
214 | (void)src; | 218 | unsigned char const * yuv_src[3]; |
215 | (void)src_x; | 219 | off_t z; |
216 | (void)src_y; | 220 | |
217 | (void)stride; | 221 | /* Sorry, but width and height must be >= 2 or else */ |
218 | (void)x; | 222 | width &= ~1; |
219 | (void)y; | 223 | height >>= 1; |
220 | (void)width; | 224 | |
221 | (void)height; | 225 | y += 0x1a; |
226 | |||
227 | z = stride*src_y; | ||
228 | yuv_src[0] = src[0] + z + src_x; | ||
229 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | ||
230 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | ||
231 | |||
232 | lcd_send_command(R_ENTRY_MODE); | ||
233 | lcd_send_command(0x80); | ||
234 | |||
235 | lcd_send_command(R_X_ADDR_AREA); | ||
236 | lcd_send_command(x); | ||
237 | lcd_send_command(x + width - 1); | ||
238 | |||
239 | do | ||
240 | { | ||
241 | lcd_send_command(R_Y_ADDR_AREA); | ||
242 | lcd_send_command(y); | ||
243 | lcd_send_command(y + 1); | ||
244 | |||
245 | lcd_write_yuv420_lines(yuv_src, width, stride); | ||
246 | yuv_src[0] += stride << 1; /* Skip down two luma lines */ | ||
247 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | ||
248 | yuv_src[2] += stride >> 1; | ||
249 | y += 2; | ||
250 | } | ||
251 | while (--height > 0); | ||
222 | } | 252 | } |
223 | 253 | ||
224 | /* Update the display. | 254 | /* Update the display. |
@@ -239,6 +269,9 @@ void lcd_update_rect(int x0, int y0, int width, int height) | |||
239 | if ((x1 <= 0) || (y1 <= 0)) | 269 | if ((x1 <= 0) || (y1 <= 0)) |
240 | return; | 270 | return; |
241 | 271 | ||
272 | lcd_send_command(R_ENTRY_MODE); | ||
273 | lcd_send_command(0x82); | ||
274 | |||
242 | if(y1 >= LCD_HEIGHT) | 275 | if(y1 >= LCD_HEIGHT) |
243 | y1 = LCD_HEIGHT - 1; | 276 | y1 = LCD_HEIGHT - 1; |
244 | 277 | ||