diff options
author | Michael Sparmann <theseven@rockbox.org> | 2011-03-01 01:52:12 +0000 |
---|---|---|
committer | Michael Sparmann <theseven@rockbox.org> | 2011-03-01 01:52:12 +0000 |
commit | 7a7c8f071dd37ad74a299c4b18706d99a67bd128 (patch) | |
tree | cdbfa66ee4bf88b0f9dc046d01380207da812754 /firmware | |
parent | 24a6f93aa88cd5dd6b3feef9509e0b32894ebe0b (diff) | |
download | rockbox-7a7c8f071dd37ad74a299c4b18706d99a67bd128.tar.gz rockbox-7a7c8f071dd37ad74a299c4b18706d99a67bd128.zip |
iPod Classic: Use DMA (and double buffering) for LCD updates
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29474 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S | 81 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c | 156 |
2 files changed, 103 insertions, 134 deletions
diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S b/firmware/target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S index 7d9e8274d5..ec8a24c4e5 100644 --- a/firmware/target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S +++ b/firmware/target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S | |||
@@ -19,57 +19,15 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #define FORCE_FIFO_WAIT | ||
23 | /**************************************************************************** | ||
24 | * #define FORCE_FIFO_WAIT | ||
25 | * | ||
26 | * This is not needed in YUV blitting when the LCD IF is fast enough. In this | ||
27 | * case YUV-to-RGB conversion per pixel needs longer than the transfer of a | ||
28 | * pixel via the LCD IF. For iPod nano 2G this is true if the LCD IF is | ||
29 | * configured to use LCD_PHTIME = 0x00 (see lcd-nano2g.c). | ||
30 | ****************************************************************************/ | ||
31 | 22 | ||
32 | #include "config.h" | 23 | #include "config.h" |
33 | 24 | ||
34 | .section .icode, "ax", %progbits | 25 | .section .icode, "ax", %progbits |
35 | 26 | ||
36 | /**************************************************************************** | ||
37 | * void lcd_write_line(const fb_data *addr, | ||
38 | * int pixelcount, | ||
39 | * const unsigned int lcd_base_addr); | ||
40 | * | ||
41 | * Writes pixelcount pixels from src-pointer (lcd_framebuffer) to LCD dataport. | ||
42 | */ | ||
43 | .align 2 | ||
44 | .global lcd_write_line | ||
45 | .type lcd_write_line, %function | ||
46 | /* r0 = addr, must be aligned */ | ||
47 | /* r1 = pixel count, must be even */ | ||
48 | lcd_write_line: /* r2 = LCD_BASE */ | ||
49 | stmfd sp!, {r4-r6, lr} /* save non-scratch registers */ | ||
50 | add r12, r2, #0x40 /* LCD_WDATA = LCD data port */ | ||
51 | |||
52 | .loop: | ||
53 | ldmia r0!, {r3, r5} /* read 2 pixel (=8 byte) */ | ||
54 | |||
55 | /* wait for FIFO half full */ | ||
56 | .fifo_wait: | ||
57 | ldr lr, [r2, #0x1C] /* while (LCD_STATUS & 0x08); */ | ||
58 | tst lr, #0x8 | ||
59 | bgt .fifo_wait | ||
60 | |||
61 | mov r4, r3, asr #16 /* r3 = 1st pixel, r4 = 2nd pixel */ | ||
62 | mov r6, r5, asr #16 /* r5 = 3rd pixel, r6 = 4th pixel */ | ||
63 | stmia r12, {r3-r6} /* write pixels (lowest 16 bit used) */ | ||
64 | |||
65 | subs r1, r1, #4 | ||
66 | bgt .loop | ||
67 | |||
68 | ldmpc regs=r4-r6 | ||
69 | 27 | ||
70 | /**************************************************************************** | 28 | /**************************************************************************** |
71 | * extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | 29 | * extern void lcd_write_yuv420_lines(unsigned char const * const src[3], |
72 | * const unsigned LCD_BASE, | 30 | * uint16_t* out, |
73 | * int width, | 31 | * int width, |
74 | * int stride); | 32 | * int stride); |
75 | * | 33 | * |
@@ -93,7 +51,7 @@ lcd_write_line: /* r2 = LCD_BASE */ | |||
93 | .type lcd_write_yuv420_lines, %function | 51 | .type lcd_write_yuv420_lines, %function |
94 | lcd_write_yuv420_lines: | 52 | lcd_write_yuv420_lines: |
95 | /* r0 = src = yuv_src */ | 53 | /* r0 = src = yuv_src */ |
96 | /* r1 = dst = LCD_BASE */ | 54 | /* r1 = dst = out */ |
97 | /* r2 = width */ | 55 | /* r2 = width */ |
98 | /* r3 = stride */ | 56 | /* r3 = stride */ |
99 | stmfd sp!, { r4-r10, lr } /* save non-scratch */ | 57 | stmfd sp!, { r4-r10, lr } /* save non-scratch */ |
@@ -103,14 +61,14 @@ lcd_write_yuv420_lines: | |||
103 | add r3, r9, r3 /* r3 = &ysrc[stride] */ | 61 | add r3, r9, r3 /* r3 = &ysrc[stride] */ |
104 | add r4, r2, r2, asr #1 /* chroma buffer lenght = width/2 *3 */ | 62 | add r4, r2, r2, asr #1 /* chroma buffer lenght = width/2 *3 */ |
105 | mov r4, r4, asl #2 /* use words for str/ldm possibility */ | 63 | mov r4, r4, asl #2 /* use words for str/ldm possibility */ |
106 | add r4, r4, #19 /* plus room for 4 additional words, */ | 64 | add r4, r4, #15 /* plus room for 3 additional words, */ |
107 | bic r4, r4, #3 /* rounded up to multiples of 4 byte */ | 65 | bic r4, r4, #3 /* rounded up to multiples of 4 byte */ |
108 | sub sp, sp, r4 /* and allocate on stack */ | 66 | sub sp, sp, r4 /* and allocate on stack */ |
109 | stmia sp, {r1-r4} /* LCD_BASE, width, &ysrc[stride], stack_alloc */ | 67 | stmia sp, {r2-r4} /* width, &ysrc[stride], stack_alloc */ |
110 | 68 | ||
111 | mov r7, r2 /* r7 = loop count */ | 69 | mov r7, r2 /* r7 = loop count */ |
112 | add r8, sp, #16 /* chroma buffer */ | 70 | add r8, sp, #12 /* chroma buffer */ |
113 | add lr, r1, #0x40 /* LCD data port = LCD_BASE + 0x40 */ | 71 | mov lr, r1 /* RGB565 data destination buffer */ |
114 | 72 | ||
115 | /* 1st loop start */ | 73 | /* 1st loop start */ |
116 | 10: /* loop start */ | 74 | 10: /* loop start */ |
@@ -195,23 +153,16 @@ lcd_write_yuv420_lines: | |||
195 | /* calculate pixel_2 and pack with pixel_1 before writing */ | 153 | /* calculate pixel_2 and pack with pixel_1 before writing */ |
196 | orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ | 154 | orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ |
197 | orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */ | 155 | orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */ |
198 | #ifdef FORCE_FIFO_WAIT | 156 | orr r4, r4, r5, lsl #16 |
199 | /* wait for FIFO half full */ | 157 | str r4, [lr], #4 /* write pixel_1 and pixel_2 */ |
200 | .fifo_wait1: | ||
201 | ldr r3, [lr, #-0x24] /* while (LCD_STATUS & 0x08); */ | ||
202 | tst r3, #0x8 | ||
203 | bgt .fifo_wait1 | ||
204 | #endif | ||
205 | stmia lr, {r4,r5} /* write pixel_1 and pixel_2 */ | ||
206 | 158 | ||
207 | subs r7, r7, #2 /* check for loop end */ | 159 | subs r7, r7, #2 /* check for loop end */ |
208 | bgt 10b /* back to beginning */ | 160 | bgt 10b /* back to beginning */ |
209 | /* 1st loop end */ | 161 | /* 1st loop end */ |
210 | 162 | ||
211 | /* Reload several registers for pointer rewinding for next loop */ | 163 | /* Reload several registers for pointer rewinding for next loop */ |
212 | add r8, sp, #16 /* chroma buffer */ | 164 | add r8, sp, #12 /* chroma buffer */ |
213 | ldmia sp, { r1, r7, r9} /* r1 = LCD_BASE */ | 165 | ldmia sp, {r7, r9} /* r7 = loop count */ |
214 | /* r7 = loop count */ | ||
215 | /* r9 = &ysrc[stride] */ | 166 | /* r9 = &ysrc[stride] */ |
216 | 167 | ||
217 | /* 2nd loop start */ | 168 | /* 2nd loop start */ |
@@ -275,20 +226,14 @@ lcd_write_yuv420_lines: | |||
275 | /* calculate pixel_2 and pack with pixel_1 before writing */ | 226 | /* calculate pixel_2 and pack with pixel_1 before writing */ |
276 | orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ | 227 | orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */ |
277 | orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */ | 228 | orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */ |
278 | #ifdef FORCE_FIFO_WAIT | 229 | orr r4, r4, r5, lsl #16 |
279 | /* wait for FIFO half full */ | 230 | str r4, [lr], #4 /* write pixel_1 and pixel_2 */ |
280 | .fifo_wait2: | ||
281 | ldr r3, [lr, #-0x24] /* while (LCD_STATUS & 0x08); */ | ||
282 | tst r3, #0x8 | ||
283 | bgt .fifo_wait2 | ||
284 | #endif | ||
285 | stmia lr, {r4,r5} /* write pixel_1 and pixel_2 */ | ||
286 | 231 | ||
287 | subs r7, r7, #2 /* check for loop end */ | 232 | subs r7, r7, #2 /* check for loop end */ |
288 | bgt 20b /* back to beginning */ | 233 | bgt 20b /* back to beginning */ |
289 | /* 2nd loop end */ | 234 | /* 2nd loop end */ |
290 | 235 | ||
291 | ldr r3, [sp, #12] | 236 | ldr r3, [sp, #8] |
292 | add sp, sp, r3 /* deallocate buffer */ | 237 | add sp, sp, r3 /* deallocate buffer */ |
293 | ldmpc regs=r4-r10 /* restore registers */ | 238 | ldmpc regs=r4-r10 /* restore registers */ |
294 | 239 | ||
diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c index 7b3e9319d7..de731a91b8 100644 --- a/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "cpu.h" | 27 | #include "cpu.h" |
28 | #include "pmu-target.h" | 28 | #include "pmu-target.h" |
29 | #include "power.h" | 29 | #include "power.h" |
30 | #include "string.h" | ||
30 | 31 | ||
31 | 32 | ||
32 | #define R_HORIZ_GRAM_ADDR_SET 0x200 | 33 | #define R_HORIZ_GRAM_ADDR_SET 0x200 |
@@ -48,6 +49,10 @@ | |||
48 | /** globals **/ | 49 | /** globals **/ |
49 | 50 | ||
50 | int lcd_type; /* also needed in debug-s5l8702.c */ | 51 | int lcd_type; /* also needed in debug-s5l8702.c */ |
52 | static struct dma_lli lcd_lli[(LCD_WIDTH * LCD_HEIGHT - 1) / 0xfff] CACHEALIGN_ATTR; | ||
53 | static struct wakeup lcd_wakeup; | ||
54 | static struct mutex lcd_mutex; | ||
55 | static uint16_t lcd_dblbuf[LCD_HEIGHT][LCD_WIDTH]; | ||
51 | 56 | ||
52 | 57 | ||
53 | static inline void s5l_lcd_write_cmd_data(int cmd, int data) | 58 | static inline void s5l_lcd_write_cmd_data(int cmd, int data) |
@@ -100,6 +105,7 @@ bool lcd_active(void) | |||
100 | 105 | ||
101 | void lcd_shutdown(void) | 106 | void lcd_shutdown(void) |
102 | { | 107 | { |
108 | mutex_lock(&lcd_mutex); | ||
103 | pmu_write(0x2b, 0); /* Kill the backlight, instantly. */ | 109 | pmu_write(0x2b, 0); /* Kill the backlight, instantly. */ |
104 | pmu_write(0x29, 0); | 110 | pmu_write(0x29, 0); |
105 | 111 | ||
@@ -131,6 +137,7 @@ void lcd_shutdown(void) | |||
131 | s5l_lcd_write_cmd(0x10); | 137 | s5l_lcd_write_cmd(0x10); |
132 | sleep(HZ / 20); | 138 | sleep(HZ / 20); |
133 | } | 139 | } |
140 | mutex_unlock(&lcd_mutex); | ||
134 | } | 141 | } |
135 | 142 | ||
136 | void lcd_sleep(void) | 143 | void lcd_sleep(void) |
@@ -142,6 +149,8 @@ void lcd_sleep(void) | |||
142 | void lcd_init_device(void) | 149 | void lcd_init_device(void) |
143 | { | 150 | { |
144 | /* Detect lcd type */ | 151 | /* Detect lcd type */ |
152 | wakeup_init(&lcd_wakeup); | ||
153 | mutex_init(&lcd_mutex); | ||
145 | lcd_type = (PDAT6 & 0x30) >> 4; | 154 | lcd_type = (PDAT6 & 0x30) >> 4; |
146 | } | 155 | } |
147 | 156 | ||
@@ -149,7 +158,9 @@ void lcd_init_device(void) | |||
149 | 158 | ||
150 | static inline void lcd_write_pixel(fb_data pixel) | 159 | static inline void lcd_write_pixel(fb_data pixel) |
151 | { | 160 | { |
161 | mutex_lock(&lcd_mutex); | ||
152 | LCD_WDATA = pixel; | 162 | LCD_WDATA = pixel; |
163 | mutex_unlock(&lcd_mutex); | ||
153 | } | 164 | } |
154 | 165 | ||
155 | /* Update the display. | 166 | /* Update the display. |
@@ -165,121 +176,134 @@ extern void lcd_write_line(const fb_data *addr, | |||
165 | int pixelcount, | 176 | int pixelcount, |
166 | const unsigned int lcd_base_addr); | 177 | const unsigned int lcd_base_addr); |
167 | 178 | ||
168 | /* Update a fraction of the display. */ | 179 | static void displaylcd_setup(int x, int y, int width, int height) ICODE_ATTR; |
169 | void lcd_update_rect(int, int, int, int) ICODE_ATTR; | 180 | static void displaylcd_setup(int x, int y, int width, int height) |
170 | void lcd_update_rect(int x, int y, int width, int height) | ||
171 | { | 181 | { |
172 | int y0, x0, y1, x1; | 182 | mutex_lock(&lcd_mutex); |
173 | fb_data* p; | 183 | while (DMAC0C4CONFIG & 1) wakeup_wait(&lcd_wakeup, HZ / 10); |
174 | |||
175 | /* Both x and width need to be preprocessed due to asm optimizations */ | ||
176 | x = x & ~1; /* ensure x is even */ | ||
177 | width = (width + 3) & ~3; /* ensure width is a multiple of 4 */ | ||
178 | 184 | ||
179 | x0 = x; /* start horiz */ | 185 | int xe = (x + width) - 1; /* max horiz */ |
180 | y0 = y; /* start vert */ | 186 | int ye = (y + height) - 1; /* max vert */ |
181 | x1 = (x + width) - 1; /* max horiz */ | ||
182 | y1 = (y + height) - 1; /* max vert */ | ||
183 | 187 | ||
184 | if (lcd_type & 2) { | 188 | if (lcd_type & 2) { |
185 | s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0); | 189 | s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x); |
186 | s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1); | 190 | s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, xe); |
187 | s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0); | 191 | s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y); |
188 | s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1); | 192 | s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, ye); |
189 | 193 | ||
190 | s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, x0); | 194 | s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, x); |
191 | s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, y0); | 195 | s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, y); |
192 | 196 | ||
193 | s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); | 197 | s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); |
194 | } else { | 198 | } else { |
195 | s5l_lcd_write_cmd(R_COLUMN_ADDR_SET); | 199 | s5l_lcd_write_cmd(R_COLUMN_ADDR_SET); |
196 | s5l_lcd_write_data(x0 >> 8); | 200 | s5l_lcd_write_data(x >> 8); |
197 | s5l_lcd_write_data(x0 & 0xff); | 201 | s5l_lcd_write_data(x & 0xff); |
198 | s5l_lcd_write_data(x1 >> 8); | 202 | s5l_lcd_write_data(xe >> 8); |
199 | s5l_lcd_write_data(x1 & 0xff); | 203 | s5l_lcd_write_data(xe & 0xff); |
200 | 204 | ||
201 | s5l_lcd_write_cmd(R_ROW_ADDR_SET); | 205 | s5l_lcd_write_cmd(R_ROW_ADDR_SET); |
202 | s5l_lcd_write_data(y0 >> 8); | 206 | s5l_lcd_write_data(y >> 8); |
203 | s5l_lcd_write_data(y0 & 0xff); | 207 | s5l_lcd_write_data(y & 0xff); |
204 | s5l_lcd_write_data(y1 >> 8); | 208 | s5l_lcd_write_data(ye >> 8); |
205 | s5l_lcd_write_data(y1 & 0xff); | 209 | s5l_lcd_write_data(ye & 0xff); |
206 | 210 | ||
207 | s5l_lcd_write_cmd(R_MEMORY_WRITE); | 211 | s5l_lcd_write_cmd(R_MEMORY_WRITE); |
208 | } | 212 | } |
213 | } | ||
214 | |||
215 | static void displaylcd_dma(int pixels) ICODE_ATTR; | ||
216 | static void displaylcd_dma(int pixels) | ||
217 | { | ||
218 | int i; | ||
219 | void* data = lcd_dblbuf; | ||
220 | for (i = -1; i < (int)ARRAYLEN(lcd_lli) && pixels > 0; i++, pixels -= 0xfff) | ||
221 | { | ||
222 | bool last = i + 1 >= (int)ARRAYLEN(lcd_lli) || pixels <= 0xfff; | ||
223 | struct dma_lli* lli = i < 0 ? (struct dma_lli*)((int)&DMAC0C4LLI) : &lcd_lli[i]; | ||
224 | lli->srcaddr = data; | ||
225 | lli->dstaddr = (void*)((int)&LCD_WDATA); | ||
226 | lli->nextlli = last ? NULL : &lcd_lli[i + 1]; | ||
227 | lli->control = 0x70240000 | (last ? pixels : 0xfff) | ||
228 | | (last ? 0x80000000 : 0) | 0x4000000; | ||
229 | data += 0x1ffe; | ||
230 | } | ||
231 | clean_dcache(); | ||
232 | DMAC0C4CONFIG = 0x88c1; | ||
233 | mutex_unlock(&lcd_mutex); | ||
234 | } | ||
235 | |||
236 | void INT_DMAC0C4(void) ICODE_ATTR; | ||
237 | void INT_DMAC0C4(void) | ||
238 | { | ||
239 | DMAC0INTTCCLR = 0x10; | ||
240 | wakeup_signal(&lcd_wakeup); | ||
241 | } | ||
242 | |||
243 | /* Update a fraction of the display. */ | ||
244 | void lcd_update_rect(int, int, int, int) ICODE_ATTR; | ||
245 | void lcd_update_rect(int x, int y, int width, int height) | ||
246 | { | ||
247 | int pixels = width * height; | ||
248 | fb_data* p = &lcd_framebuffer[y][x]; | ||
249 | uint16_t* out = lcd_dblbuf[0]; | ||
250 | |||
251 | displaylcd_setup(x, y, width, height); | ||
209 | 252 | ||
210 | /* Copy display bitmap to hardware */ | 253 | /* Copy display bitmap to hardware */ |
211 | p = &lcd_framebuffer[y0][x0]; | ||
212 | if (LCD_WIDTH == width) { | 254 | if (LCD_WIDTH == width) { |
213 | /* Write all lines at once */ | 255 | /* Write all lines at once */ |
214 | lcd_write_line(p, height*LCD_WIDTH, LCD_BASE); | 256 | memcpy(out, p, pixels * 2); |
215 | } else { | 257 | } else { |
216 | y1 = height; | ||
217 | do { | 258 | do { |
218 | /* Write a single line */ | 259 | /* Write a single line */ |
219 | lcd_write_line(p, width, LCD_BASE); | 260 | memcpy(out, p, width * 2); |
220 | p += LCD_WIDTH; | 261 | p += LCD_WIDTH; |
221 | } while (--y1 > 0 ); | 262 | out += width; |
263 | } while (--height); | ||
222 | } | 264 | } |
265 | |||
266 | displaylcd_dma(pixels); | ||
223 | } | 267 | } |
224 | 268 | ||
225 | /* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */ | 269 | /* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */ |
226 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], | 270 | extern void lcd_write_yuv420_lines(unsigned char const * const src[3], |
227 | const unsigned int lcd_baseadress, | 271 | uint16_t* outbuf, |
228 | int width, | 272 | int width, |
229 | int stride); | 273 | int stride); |
230 | 274 | ||
231 | /* Blit a YUV bitmap directly to the LCD */ | 275 | /* Blit a YUV bitmap directly to the LCD */ |
232 | void lcd_blit_yuv(unsigned char * const src[3], | 276 | void lcd_blit_yuv(unsigned char * const src[3], |
233 | int src_x, int src_y, int stride, | 277 | int src_x, int src_y, int stride, |
278 | int x, int y, int width, int height) ICODE_ATTR; | ||
279 | void lcd_blit_yuv(unsigned char * const src[3], | ||
280 | int src_x, int src_y, int stride, | ||
234 | int x, int y, int width, int height) | 281 | int x, int y, int width, int height) |
235 | { | 282 | { |
236 | unsigned int z, y0, x0, y1, x1;; | 283 | unsigned int z; |
237 | unsigned char const * yuv_src[3]; | 284 | unsigned char const * yuv_src[3]; |
238 | 285 | ||
239 | width = (width + 1) & ~1; /* ensure width is even */ | 286 | width = (width + 1) & ~1; /* ensure width is even */ |
240 | 287 | ||
241 | x0 = x; /* start horiz */ | 288 | int pixels = width * height; |
242 | y0 = y; /* start vert */ | 289 | uint16_t* out = lcd_dblbuf[0]; |
243 | x1 = (x + width) - 1; /* max horiz */ | ||
244 | y1 = (y + height) - 1; /* max vert */ | ||
245 | |||
246 | if (lcd_type & 2) { | ||
247 | s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0); | ||
248 | s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1); | ||
249 | s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0); | ||
250 | s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1); | ||
251 | |||
252 | s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, x0); | ||
253 | s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, y0); | ||
254 | |||
255 | s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); | ||
256 | } else { | ||
257 | s5l_lcd_write_cmd(R_COLUMN_ADDR_SET); | ||
258 | s5l_lcd_write_data(x0 >> 8); | ||
259 | s5l_lcd_write_data(x0 & 0xff); | ||
260 | s5l_lcd_write_data(x1 >> 8); | ||
261 | s5l_lcd_write_data(x1 & 0xff); | ||
262 | |||
263 | s5l_lcd_write_cmd(R_ROW_ADDR_SET); | ||
264 | s5l_lcd_write_data(y0 >> 8); | ||
265 | s5l_lcd_write_data(y0 & 0xff); | ||
266 | s5l_lcd_write_data(y1 >> 8); | ||
267 | s5l_lcd_write_data(y1 & 0xff); | ||
268 | |||
269 | s5l_lcd_write_cmd(R_MEMORY_WRITE); | ||
270 | } | ||
271 | 290 | ||
272 | z = stride * src_y; | 291 | z = stride * src_y; |
273 | yuv_src[0] = src[0] + z + src_x; | 292 | yuv_src[0] = src[0] + z + src_x; |
274 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); | 293 | yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); |
275 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); | 294 | yuv_src[2] = src[2] + (yuv_src[1] - src[1]); |
276 | 295 | ||
296 | displaylcd_setup(x, y, width, height); | ||
297 | |||
277 | height >>= 1; | 298 | height >>= 1; |
278 | 299 | ||
279 | do { | 300 | do { |
280 | lcd_write_yuv420_lines(yuv_src, LCD_BASE, width, stride); | 301 | lcd_write_yuv420_lines(yuv_src, out, width, stride); |
281 | yuv_src[0] += stride << 1; | 302 | yuv_src[0] += stride << 1; |
282 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ | 303 | yuv_src[1] += stride >> 1; /* Skip down one chroma line */ |
283 | yuv_src[2] += stride >> 1; | 304 | yuv_src[2] += stride >> 1; |
284 | } while (--height > 0); | 305 | out += width << 1; |
306 | } while (--height); | ||
307 | |||
308 | displaylcd_dma(pixels); | ||
285 | } | 309 | } |