summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2022-10-13 11:03:53 -0400
committerSolomon Peachy <pizza@shaftnet.org>2022-10-13 11:08:06 -0400
commit418169aff8faf2cf90124cd95dba0af821cea73d (patch)
tree4fc206af57c9a07fba6cbcb3517fa946a7b84668
parentf9ea1fc79d6aaff9949a5b11ae011b4e04e0e9d9 (diff)
downloadrockbox-418169aff8faf2cf90124cd95dba0af821cea73d.tar.gz
rockbox-418169aff8faf2cf90124cd95dba0af821cea73d.zip
Revert "Remove YUV blitting functions and LCD modes"
This reverts commit fe6aa21e9eb88f49005863efd2003d0982920048. Change-Id: I8bb1e5d6c52ed1478002d2140ef494ec5d62b8e3
-rw-r--r--apps/plugin.c9
-rw-r--r--apps/plugin.h11
-rw-r--r--apps/plugins/test_fps.c91
-rw-r--r--docs/PLUGIN_API19
-rw-r--r--firmware/SOURCES15
-rw-r--r--firmware/asm/arm/lcd-as-memframe.S591
-rw-r--r--firmware/asm/lcd-as-memframe.c168
-rw-r--r--firmware/drivers/lcd-color-common.c189
-rw-r--r--firmware/drivers/lcd-memframe.c98
-rw-r--r--firmware/export/config/mrobe500.h2
-rw-r--r--firmware/export/lcd.h11
-rw-r--r--firmware/target/arm/as3525/lcd-as-e200v2-fuze-fuzev2.S550
-rw-r--r--firmware/target/arm/as3525/lcd-fuze.c80
-rw-r--r--firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c98
-rw-r--r--firmware/target/arm/ipod/lcd-as-color-nano.S287
-rw-r--r--firmware/target/arm/ipod/lcd-color_nano.c56
-rw-r--r--firmware/target/arm/ipod/video/lcd-as-video.S237
-rw-r--r--firmware/target/arm/ipod/video/lcd-video.c47
-rw-r--r--firmware/target/arm/iriver/h10/lcd-as-h10.S538
-rw-r--r--firmware/target/arm/iriver/h10/lcd-h10_20gb.c90
-rw-r--r--firmware/target/arm/iriver/h10/lcd-h10_5gb.c162
-rw-r--r--firmware/target/arm/lcd-c200_c200v2.c77
-rw-r--r--firmware/target/arm/pbell/vibe500/lcd-as-vibe500.S556
-rw-r--r--firmware/target/arm/pbell/vibe500/lcd-vibe500.c75
-rw-r--r--firmware/target/arm/philips/hdd1630/lcd-as-hdd1630.S570
-rw-r--r--firmware/target/arm/philips/hdd1630/lcd-hdd1630.c81
-rw-r--r--firmware/target/arm/philips/hdd6330/lcd-as-hdd6330.S140
-rw-r--r--firmware/target/arm/philips/hdd6330/lcd-hdd6330.c98
-rw-r--r--firmware/target/arm/philips/sa9200/lcd-as-sa9200.S590
-rw-r--r--firmware/target/arm/philips/sa9200/lcd-sa9200.c82
-rw-r--r--firmware/target/arm/rk27xx/ihifi/lcd-ihifi.c15
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c15
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c15
-rw-r--r--firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c15
-rw-r--r--firmware/target/arm/rk27xx/lcd-hifiman.c19
-rw-r--r--firmware/target/arm/rk27xx/ma/lcd-ma.c15
-rw-r--r--firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c19
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/lcd-asm-nano2g.S228
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c33
-rw-r--r--firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c8
-rw-r--r--firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c16
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/lcd-6g.c46
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/lcd-asm-6g.S1013
-rw-r--r--firmware/target/arm/samsung/yh820/lcd-as-yh820.S550
-rw-r--r--firmware/target/arm/samsung/yh820/lcd-yh820.c74
-rw-r--r--firmware/target/arm/samsung/yh925/lcd-as-yh925.S538
-rw-r--r--firmware/target/arm/samsung/yh925/lcd-yh925.c94
-rw-r--r--firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S550
-rw-r--r--firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c86
-rw-r--r--firmware/target/coldfire/iaudio/x5/lcd-as-x5.S242
-rw-r--r--firmware/target/coldfire/iaudio/x5/lcd-x5.c63
-rw-r--r--firmware/target/coldfire/iriver/h300/lcd-as-h300.S246
-rw-r--r--firmware/target/coldfire/iriver/h300/lcd-h300.c61
-rw-r--r--firmware/target/mips/ingenic_jz47xx/lcd-jz4740.c62
54 files changed, 9638 insertions, 3 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index 2b3b58a654..888a9e109c 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -222,6 +222,15 @@ static const struct plugin_api rockbox_api = {
222#if LCD_DEPTH >= 16 222#if LCD_DEPTH >= 16
223 lcd_bitmap_transparent_part, 223 lcd_bitmap_transparent_part,
224 lcd_bitmap_transparent, 224 lcd_bitmap_transparent,
225#if MEMORYSIZE > 2
226 lcd_blit_yuv,
227#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200) \
228 || defined(IRIVER_H10) || defined(COWON_D2) || defined(PHILIPS_HDD1630) \
229 || defined(SANSA_FUZE) || defined(SANSA_E200V2) || defined(SANSA_FUZEV2) \
230 || defined(TOSHIBA_GIGABEAT_S) || defined(PHILIPS_SA9200)
231 lcd_yuv_set_options,
232#endif
233#endif /* MEMORYSIZE > 2 */
225#elif (LCD_DEPTH < 4) && (CONFIG_PLATFORM & PLATFORM_NATIVE) 234#elif (LCD_DEPTH < 4) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
226 lcd_blit_mono, 235 lcd_blit_mono,
227 lcd_blit_grey_phase, 236 lcd_blit_grey_phase,
diff --git a/apps/plugin.h b/apps/plugin.h
index 681200608c..2ac333a19f 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -242,6 +242,17 @@ struct plugin_api {
242 int x, int y, int width, int height); 242 int x, int y, int width, int height);
243 void (*lcd_bitmap_transparent)(const fb_data *src, int x, int y, 243 void (*lcd_bitmap_transparent)(const fb_data *src, int x, int y,
244 int width, int height); 244 int width, int height);
245#if MEMORYSIZE > 2
246 void (*lcd_blit_yuv)(unsigned char * const src[3],
247 int src_x, int src_y, int stride,
248 int x, int y, int width, int height);
249#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200) \
250 || defined(IRIVER_H10) || defined(COWON_D2) || defined(PHILIPS_HDD1630) \
251 || defined(SANSA_FUZE) || defined(SANSA_E200V2) || defined(SANSA_FUZEV2) \
252 || defined(TOSHIBA_GIGABEAT_S) || defined(PHILIPS_SA9200)
253 void (*lcd_yuv_set_options)(unsigned options);
254#endif
255#endif /* MEMORYSIZE > 2 */
245#elif (LCD_DEPTH < 4) && (CONFIG_PLATFORM & PLATFORM_NATIVE) 256#elif (LCD_DEPTH < 4) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
246 void (*lcd_blit_mono)(const unsigned char *data, int x, int by, int width, 257 void (*lcd_blit_mono)(const unsigned char *data, int x, int by, int width,
247 int bheight, int stride); 258 int bheight, int stride);
diff --git a/apps/plugins/test_fps.c b/apps/plugins/test_fps.c
index b2fc957dc1..ddf938ac25 100644
--- a/apps/plugins/test_fps.c
+++ b/apps/plugins/test_fps.c
@@ -123,6 +123,94 @@ static void time_main_update(void)
123 log_text(str); 123 log_text(str);
124} 124}
125 125
126#if defined(HAVE_LCD_COLOR) && (MEMORYSIZE > 2)
127
128#if LCD_WIDTH >= LCD_HEIGHT
129#define YUV_WIDTH LCD_WIDTH
130#define YUV_HEIGHT LCD_HEIGHT
131#else /* Assume the screen is rotated on portrait LCDs */
132#define YUV_WIDTH LCD_HEIGHT
133#define YUV_HEIGHT LCD_WIDTH
134#endif
135
136static unsigned char ydata[YUV_HEIGHT][YUV_WIDTH];
137static unsigned char udata[YUV_HEIGHT/2][YUV_WIDTH/2];
138static unsigned char vdata[YUV_HEIGHT/2][YUV_WIDTH/2];
139
140static unsigned char * const yuvbuf[3] = {
141 (void*)ydata,
142 (void*)udata,
143 (void*)vdata
144};
145
146static void make_gradient_rect(int width, int height)
147{
148 unsigned char vline[YUV_WIDTH/2];
149 int x, y;
150
151 width /= 2;
152 height /= 2;
153
154 for (x = 0; x < width; x++)
155 vline[x] = (x << 8) / width;
156 for (y = 0; y < height; y++)
157 {
158 rb->memset(udata[y], (y << 8) / height, width);
159 rb->memcpy(vdata[y], vline, width);
160 }
161}
162
163static void time_main_yuv(void)
164{
165 char str[32]; /* text buffer */
166 long time_start; /* start tickcount */
167 long time_end; /* end tickcount */
168 int frame_count;
169 int fps;
170
171 const int part14_x = YUV_WIDTH/4; /* x-offset for 1/4 update test */
172 const int part14_w = YUV_WIDTH/2; /* x-size for 1/4 update test */
173 const int part14_y = YUV_HEIGHT/4; /* y-offset for 1/4 update test */
174 const int part14_h = YUV_HEIGHT/2; /* y-size for 1/4 update test */
175
176 log_text("Main LCD YUV");
177
178 rb->memset(ydata, 128, sizeof(ydata)); /* medium grey */
179
180 /* Test 1: full LCD update */
181 make_gradient_rect(YUV_WIDTH, YUV_HEIGHT);
182
183 frame_count = 0;
184 rb->sleep(0); /* sync to tick */
185 time_start = *rb->current_tick;
186 while((time_end = *rb->current_tick) - time_start < DURATION)
187 {
188 rb->lcd_blit_yuv(yuvbuf, 0, 0, YUV_WIDTH,
189 0, 0, YUV_WIDTH, YUV_HEIGHT);
190 frame_count++;
191 }
192 fps = calc_tenth_fps(frame_count, time_end - time_start);
193 rb->snprintf(str, sizeof(str), "1/1: %d.%d fps", fps / 10, fps % 10);
194 log_text(str);
195
196 /* Test 2: quarter LCD update */
197 make_gradient_rect(YUV_WIDTH/2, YUV_HEIGHT/2);
198
199 frame_count = 0;
200 rb->sleep(0); /* sync to tick */
201 time_start = *rb->current_tick;
202 while((time_end = *rb->current_tick) - time_start < DURATION)
203 {
204 rb->lcd_blit_yuv(yuvbuf, 0, 0, YUV_WIDTH,
205 part14_x, part14_y, part14_w, part14_h);
206 frame_count++;
207 }
208 fps = calc_tenth_fps(frame_count, time_end - time_start);
209 rb->snprintf(str, sizeof(str), "1/4: %d.%d fps", fps / 10, fps % 10);
210 log_text(str);
211}
212#endif
213
126#ifdef HAVE_REMOTE_LCD 214#ifdef HAVE_REMOTE_LCD
127static void time_remote_update(void) 215static void time_remote_update(void)
128{ 216{
@@ -318,6 +406,9 @@ enum plugin_status plugin_start(const void* parameter)
318#endif 406#endif
319 time_main_update(); 407 time_main_update();
320 rb->sleep(HZ); 408 rb->sleep(HZ);
409#if defined(HAVE_LCD_COLOR) && (MEMORYSIZE > 2)
410 time_main_yuv();
411#endif
321#if LCD_DEPTH < 4 412#if LCD_DEPTH < 4
322 time_greyscale(); 413 time_greyscale();
323#endif 414#endif
diff --git a/docs/PLUGIN_API b/docs/PLUGIN_API
index 0a256ff147..834b3522be 100644
--- a/docs/PLUGIN_API
+++ b/docs/PLUGIN_API
@@ -832,6 +832,19 @@ void lcd_blit_mono(const unsigned char *data, int x, int by, int width, int bhei
832 \param stride 832 \param stride
833 \description 833 \description
834 834
835void lcd_blit_yuv(unsigned char * const src[3], int src_x, int src_y, int stride, int x, int y, int width, int height)
836 \group lcd
837 \conditions (LCD_DEPTH >= 16)
838 \param src[3]
839 \param src_x
840 \param src_y
841 \param stride
842 \param x
843 \param y
844 \param width
845 \param height
846 \description
847
835void lcd_clear_display(void) 848void lcd_clear_display(void)
836 \group lcd 849 \group lcd
837 \description Clears the LCD and the framebuffer 850 \description Clears the LCD and the framebuffer
@@ -1226,6 +1239,12 @@ void lcd_vline(int x, int y1, int y2)
1226 \param y2 Y end coordinate 1239 \param y2 Y end coordinate
1227 \description Draws a vertical line at (=x=, =y1=) -> (=x=, =y2=) within current drawing mode 1240 \description Draws a vertical line at (=x=, =y1=) -> (=x=, =y2=) within current drawing mode
1228 1241
1242void lcd_yuv_set_options(unsigned options)
1243 \group lcd
1244 \conditions (LCD_DEPTH >= 16) && (defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200) || defined(IRIVER_H10) || defined(COWON_D2))
1245 \param options
1246 \description
1247
1229void led(bool on) 1248void led(bool on)
1230 \param on 1249 \param on
1231 \description 1250 \description
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 9c273246be..abce59fe04 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -947,6 +947,7 @@ target/arm/sandisk/sansa-e200/powermgmt-e200.c
947#endif /* SANSA_E200 */ 947#endif /* SANSA_E200 */
948 948
949#ifdef SANSA_C200 949#ifdef SANSA_C200
950target/arm/sandisk/sansa-c200/lcd-as-c200.S
950target/arm/sandisk/sansa-c200/button-c200.c 951target/arm/sandisk/sansa-c200/button-c200.c
951target/arm/sandisk/sansa-c200/powermgmt-c200.c 952target/arm/sandisk/sansa-c200/powermgmt-c200.c
952#endif /* SANSA_C200 */ 953#endif /* SANSA_C200 */
@@ -971,6 +972,7 @@ target/arm/philips/piezo.c
971target/arm/philips/sa9200/backlight-sa9200.c 972target/arm/philips/sa9200/backlight-sa9200.c
972target/arm/philips/sa9200/button-sa9200.c 973target/arm/philips/sa9200/button-sa9200.c
973target/arm/philips/sa9200/lcd-sa9200.c 974target/arm/philips/sa9200/lcd-sa9200.c
975target/arm/philips/sa9200/lcd-as-sa9200.S
974target/arm/philips/sa9200/power-sa9200.c 976target/arm/philips/sa9200/power-sa9200.c
975target/arm/philips/sa9200/powermgmt-sa9200.c 977target/arm/philips/sa9200/powermgmt-sa9200.c
976#endif /* PHILIPS_SA9200 */ 978#endif /* PHILIPS_SA9200 */
@@ -988,6 +990,7 @@ target/arm/philips/fmradio_i2c-hdd.c
988target/arm/philips/hdd1630/backlight-hdd1630.c 990target/arm/philips/hdd1630/backlight-hdd1630.c
989target/arm/philips/hdd1630/button-hdd1630.c 991target/arm/philips/hdd1630/button-hdd1630.c
990target/arm/philips/hdd1630/lcd-hdd1630.c 992target/arm/philips/hdd1630/lcd-hdd1630.c
993target/arm/philips/hdd1630/lcd-as-hdd1630.S
991target/arm/philips/hdd1630/powermgmt-hdd1630.c 994target/arm/philips/hdd1630/powermgmt-hdd1630.c
992#endif /* PHILIPS_HDD1630 */ 995#endif /* PHILIPS_HDD1630 */
993 996
@@ -995,6 +998,7 @@ target/arm/philips/hdd1630/powermgmt-hdd1630.c
995target/arm/philips/hdd6330/backlight-hdd6330.c 998target/arm/philips/hdd6330/backlight-hdd6330.c
996target/arm/philips/hdd6330/button-hdd6330.c 999target/arm/philips/hdd6330/button-hdd6330.c
997target/arm/philips/hdd6330/lcd-hdd6330.c 1000target/arm/philips/hdd6330/lcd-hdd6330.c
1001target/arm/philips/hdd6330/lcd-as-hdd6330.S
998target/arm/philips/hdd6330/powermgmt-hdd6330.c 1002target/arm/philips/hdd6330/powermgmt-hdd6330.c
999#endif /* PHILIPS_HDD6330 */ 1003#endif /* PHILIPS_HDD6330 */
1000 1004
@@ -1073,6 +1077,7 @@ target/coldfire/iriver/h300/adc-h300.c
1073target/coldfire/iriver/h300/backlight-h300.c 1077target/coldfire/iriver/h300/backlight-h300.c
1074target/coldfire/iriver/h300/button-h300.c 1078target/coldfire/iriver/h300/button-h300.c
1075target/coldfire/iriver/h300/pcf50606-h300.c 1079target/coldfire/iriver/h300/pcf50606-h300.c
1080target/coldfire/iriver/h300/lcd-as-h300.S
1076target/coldfire/iriver/h300/lcd-h300.c 1081target/coldfire/iriver/h300/lcd-h300.c
1077target/coldfire/iriver/h300/power-h300.c 1082target/coldfire/iriver/h300/power-h300.c
1078target/coldfire/iriver/h300/powermgmt-h300.c 1083target/coldfire/iriver/h300/powermgmt-h300.c
@@ -1105,6 +1110,7 @@ target/arm/iriver/h10/powermgmt-h10.c
1105 1110
1106#ifdef IRIVER_H10 1111#ifdef IRIVER_H10
1107target/arm/iriver/h10/lcd-h10_20gb.c 1112target/arm/iriver/h10/lcd-h10_20gb.c
1113target/arm/iriver/h10/lcd-as-h10.S
1108#endif /* IRIVER_H10 */ 1114#endif /* IRIVER_H10 */
1109 1115
1110#ifdef IRIVER_H10_5GB 1116#ifdef IRIVER_H10_5GB
@@ -1308,11 +1314,13 @@ target/arm/ipod/button-clickwheel.c
1308#ifdef IPOD_COLOR 1314#ifdef IPOD_COLOR
1309target/arm/ipod/backlight-4g_color.c 1315target/arm/ipod/backlight-4g_color.c
1310target/arm/ipod/button-clickwheel.c 1316target/arm/ipod/button-clickwheel.c
1317target/arm/ipod/lcd-as-color-nano.S
1311#endif /* IPOD_COLOR */ 1318#endif /* IPOD_COLOR */
1312 1319
1313#ifdef IPOD_NANO 1320#ifdef IPOD_NANO
1314target/arm/ipod/backlight-nano_video.c 1321target/arm/ipod/backlight-nano_video.c
1315target/arm/ipod/button-clickwheel.c 1322target/arm/ipod/button-clickwheel.c
1323target/arm/ipod/lcd-as-color-nano.S
1316#endif /* IPOD_NANO */ 1324#endif /* IPOD_NANO */
1317 1325
1318#ifdef IPOD_VIDEO 1326#ifdef IPOD_VIDEO
@@ -1384,6 +1392,7 @@ target/arm/as3525/backlight-e200v2-fuze.c
1384target/arm/as3525/dbop-as3525.c 1392target/arm/as3525/dbop-as3525.c
1385#ifndef BOOTLOADER 1393#ifndef BOOTLOADER
1386target/arm/as3525/sansa-e200v2/powermgmt-e200v2.c 1394target/arm/as3525/sansa-e200v2/powermgmt-e200v2.c
1395target/arm/as3525/lcd-as-e200v2-fuze-fuzev2.S
1387#endif /* !BOOTLOADER */ 1396#endif /* !BOOTLOADER */
1388#endif /* SANSA_E200V2 */ 1397#endif /* SANSA_E200V2 */
1389 1398
@@ -1410,6 +1419,7 @@ target/arm/as3525/backlight-e200v2-fuze.c
1410target/arm/as3525/dbop-as3525.c 1419target/arm/as3525/dbop-as3525.c
1411#ifndef BOOTLOADER 1420#ifndef BOOTLOADER
1412target/arm/as3525/sansa-fuze/powermgmt-fuze.c 1421target/arm/as3525/sansa-fuze/powermgmt-fuze.c
1422target/arm/as3525/lcd-as-e200v2-fuze-fuzev2.S
1413#endif /* !BOOTLOADER */ 1423#endif /* !BOOTLOADER */
1414#endif /* SANSA_FUZE */ 1424#endif /* SANSA_FUZE */
1415 1425
@@ -1420,6 +1430,7 @@ target/arm/as3525/sansa-fuzev2/button-fuzev2.c
1420target/arm/as3525/dbop-as3525.c 1430target/arm/as3525/dbop-as3525.c
1421#ifndef BOOTLOADER 1431#ifndef BOOTLOADER
1422target/arm/as3525/sansa-fuzev2/powermgmt-fuzev2.c 1432target/arm/as3525/sansa-fuzev2/powermgmt-fuzev2.c
1433target/arm/as3525/lcd-as-e200v2-fuze-fuzev2.S
1423#endif /* !BOOTLOADER */ 1434#endif /* !BOOTLOADER */
1424#endif /* SANSA_FUZEV2 */ 1435#endif /* SANSA_FUZEV2 */
1425 1436
@@ -1540,6 +1551,7 @@ target/arm/s5l8702/pl080.c
1540target/arm/s5l8702/dma-s5l8702.c 1551target/arm/s5l8702/dma-s5l8702.c
1541target/arm/s5l8702/clocking-s5l8702.c 1552target/arm/s5l8702/clocking-s5l8702.c
1542target/arm/s5l8702/ipod6g/lcd-6g.c 1553target/arm/s5l8702/ipod6g/lcd-6g.c
1554target/arm/s5l8702/ipod6g/lcd-asm-6g.S
1543target/arm/s5l8702/ipod6g/piezo-6g.c 1555target/arm/s5l8702/ipod6g/piezo-6g.c
1544#if 0 //TODO 1556#if 0 //TODO
1545target/arm/s5l8702/postmortemstub.S 1557target/arm/s5l8702/postmortemstub.S
@@ -1756,6 +1768,7 @@ target/arm/samsung/power-yh82x_yh92x.c
1756#ifdef SAMSUNG_YH820 1768#ifdef SAMSUNG_YH820
1757target/arm/samsung/yh820/backlight-yh820.c 1769target/arm/samsung/yh820/backlight-yh820.c
1758target/arm/samsung/yh820/lcd-yh820.c 1770target/arm/samsung/yh820/lcd-yh820.c
1771target/arm/samsung/yh820/lcd-as-yh820.S
1759target/arm/samsung/yh820/powermgmt-yh820.c 1772target/arm/samsung/yh820/powermgmt-yh820.c
1760#endif /* SAMSUNG_YH820 */ 1773#endif /* SAMSUNG_YH820 */
1761 1774
@@ -1770,6 +1783,7 @@ target/arm/samsung/fmradio-yh92x.c
1770#ifdef SAMSUNG_YH925 1783#ifdef SAMSUNG_YH925
1771target/arm/samsung/yh925/backlight-yh925.c 1784target/arm/samsung/yh925/backlight-yh925.c
1772target/arm/samsung/yh925/lcd-yh925.c 1785target/arm/samsung/yh925/lcd-yh925.c
1786target/arm/samsung/yh925/lcd-as-yh925.S
1773target/arm/samsung/yh925/powermgmt-yh925.c 1787target/arm/samsung/yh925/powermgmt-yh925.c
1774#endif /* SAMSUNG_YH925 */ 1788#endif /* SAMSUNG_YH925 */
1775 1789
@@ -1788,6 +1802,7 @@ target/arm/pbell/vibe500/lcd-vibe500.c
1788target/arm/pbell/vibe500/button-vibe500.c 1802target/arm/pbell/vibe500/button-vibe500.c
1789target/arm/pbell/vibe500/power-vibe500.c 1803target/arm/pbell/vibe500/power-vibe500.c
1790target/arm/pbell/vibe500/backlight-vibe500.c 1804target/arm/pbell/vibe500/backlight-vibe500.c
1805target/arm/pbell/vibe500/lcd-as-vibe500.S
1791target/arm/pbell/vibe500/powermgmt-vibe500.c 1806target/arm/pbell/vibe500/powermgmt-vibe500.c
1792#endif 1807#endif
1793 1808
diff --git a/firmware/asm/arm/lcd-as-memframe.S b/firmware/asm/arm/lcd-as-memframe.S
index 4bbae6fc0a..52ab0447c2 100644
--- a/firmware/asm/arm/lcd-as-memframe.S
+++ b/firmware/asm/arm/lcd-as-memframe.S
@@ -99,3 +99,594 @@ lcd_copy_buffer_rect: @
99 bgt 10b @ copy line @ 99 bgt 10b @ copy line @
100 ldmpc regs=r4-r11 @ restore regs and return 100 ldmpc regs=r4-r11 @ restore regs and return
101 .size lcd_copy_buffer_rect, .-lcd_copy_buffer_rect 101 .size lcd_copy_buffer_rect, .-lcd_copy_buffer_rect
102
103
104/****************************************************************************
105 * void lcd_write_yuv420_lines(fb_data *dst,
106 * unsigned char const * const src[3],
107 * int width,
108 * int stride);
109 *
110 * |R| |1.000000 -0.000001 1.402000| |Y'|
111 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
112 * |B| |1.000000 1.772000 0.000000| |Pr|
113 * Scaled, normalized, rounded and tweaked to yield RGB 565:
114 * |R| |74 0 101| |Y' - 16| >> 9
115 * |G| = |74 -24 -51| |Cb - 128| >> 8
116 * |B| |74 128 0| |Cr - 128| >> 9
117 *
118 * Write four RGB565 pixels in the following order on each loop:
119 * 1 3 + > down
120 * 2 4 \/ left
121 */
122 .section .icode.lcd_write_yuv420_lines, "ax", %progbits
123 .align 2
124 .global lcd_write_yuv420_lines
125 .type lcd_write_yuv420_lines, %function
126lcd_write_yuv420_lines:
127 @ r0 = dst
128 @ r1 = yuv_src
129 @ r2 = width
130 @ r3 = stride
131 stmfd sp!, { r4-r10, lr } @ save non-scratch
132 ldmia r1, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
133 @ r5 = yuv_src[1] = Cb_p
134 @ r6 = yuv_src[2] = Cr_p
135 @ r1 = scratch
136 sub r3, r3, #1 @
13710: @ loop line @
138 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
139 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
140 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
141 @
142 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74
143 add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right
144 add r7, r12, r7, asl #5 @ by one less when adding - same for all
145 @
146 sub r8, r8, #128 @ Cb -= 128
147 sub r9, r9, #128 @ Cr -= 128
148 @
149 add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24
150 add r10, r10, r10, asl #4 @
151 add r10, r10, r8, asl #3 @
152 add r10, r10, r8, asl #4 @
153 @
154 add lr, r9, r9, asl #2 @ r9 = Cr*101
155 add lr, lr, r9, asl #5 @
156 add r9, lr, r9, asl #6 @
157 @
158 add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8
159 mov r8, r8, asr #2 @
160 add r9, r9, #256 @ r9 = rv = (r9 + 256) >> 9
161 mov r9, r9, asr #9 @
162 rsb r10, r10, #128 @ r10 = guv = (-r10 + 128) >> 8
163 mov r10, r10, asr #8 @
164 @ compute R, G, and B
165 add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu
166 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
167 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
168 @
169#if ARM_ARCH >= 6
170 usat r1, #5, r1 @ clamp b
171 usat lr, #5, lr @ clamp r
172 usat r7, #6, r7 @ clamp g
173#else
174 orr r12, r1, lr @ check if clamping is needed...
175 orr r12, r12, r7, asr #1 @ ...at all
176 cmp r12, #31 @
177 bls 15f @ no clamp @
178 cmp r1, #31 @ clamp b
179 mvnhi r1, r1, asr #31 @
180 andhi r1, r1, #31 @
181 cmp lr, #31 @ clamp r
182 mvnhi lr, lr, asr #31 @
183 andhi lr, lr, #31 @
184 cmp r7, #63 @ clamp g
185 mvnhi r7, r7, asr #31 @
186 andhi r7, r7, #63 @
18715: @ no clamp @
188#endif
189 @
190 ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride)
191 @
192 orr r1, r1, r7, lsl #5 @ r4 |= (g << 5)
193 orr r1, r1, lr, lsl #11 @ r4 = b | (r << 11)
194
195#if LCD_WIDTH >= LCD_HEIGHT
196 strh r1, [r0] @
197#elif LCD_WIDTH < 256
198 strh r1, [r0], #LCD_WIDTH @ store pixel
199#else
200 strh r1, [r0] @
201#endif
202 @
203 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
204 add r12, r7, r7, asl #2 @
205 add r7, r12, r7, asl #5 @
206 @ compute R, G, and B
207 add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu
208 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
209 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
210 @
211#if ARM_ARCH >= 6
212 usat r1, #5, r1 @ clamp b
213 usat lr, #5, lr @ clamp r
214 usat r7, #6, r7 @ clamp g
215#else
216 orr r12, r1, lr @ check if clamping is needed...
217 orr r12, r12, r7, asr #1 @ ...at all
218 cmp r12, #31 @
219 bls 15f @ no clamp @
220 cmp r1, #31 @ clamp b
221 mvnhi r1, r1, asr #31 @
222 andhi r1, r1, #31 @
223 cmp lr, #31 @ clamp r
224 mvnhi lr, lr, asr #31 @
225 andhi lr, lr, #31 @
226 cmp r7, #63 @ clamp g
227 mvnhi r7, r7, asr #31 @
228 andhi r7, r7, #63 @
22915: @ no clamp @
230#endif
231 @
232 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
233 @
234 orr r1, r1, lr, lsl #11 @ r1 = b | (r << 11)
235 orr r1, r1, r7, lsl #5 @ r1 |= (g << 5)
236
237#if LCD_WIDTH >= LCD_HEIGHT
238 add r0, r0, #2*LCD_WIDTH @
239 strh r1, [r0] @ store pixel
240 sub r0, r0, #2*LCD_WIDTH @
241#elif LCD_WIDTH < 256
242 strh r1, [r0, #-LCD_WIDTH-2] @ store pixel
243#else
244 strh r1, [r0, #-2] @
245 add r0, r0, #LCD_WIDTH @
246#endif
247 @
248 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
249 add r12, r7, r7, asl #2 @
250 add r7, r12, r7, asl #5 @
251 @ compute R, G, and B
252 add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu
253 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
254 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
255 @
256#if ARM_ARCH >= 6
257 usat r1, #5, r1 @ clamp b
258 usat lr, #5, lr @ clamp r
259 usat r7, #6, r7 @ clamp g
260#else
261 orr r12, r1, lr @ check if clamping is needed...
262 orr r12, r12, r7, asr #1 @ ...at all
263 cmp r12, #31 @
264 bls 15f @ no clamp @
265 cmp r1, #31 @ clamp b
266 mvnhi r1, r1, asr #31 @
267 andhi r1, r1, #31 @
268 cmp lr, #31 @ clamp r
269 mvnhi lr, lr, asr #31 @
270 andhi lr, lr, #31 @
271 cmp r7, #63 @ clamp g
272 mvnhi r7, r7, asr #31 @
273 andhi r7, r7, #63 @
27415: @ no clamp @
275#endif
276 @
277 ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride)
278 @
279 orr r1, r1, r7, lsl #5 @ r1 = b | (g << 5)
280 orr r1, r1, lr, lsl #11 @ r1 |= (r << 11)
281
282#if LCD_WIDTH >= LCD_HEIGHT
283 strh r1, [r0, #2]
284#elif LCD_WIDTH < 256
285 strh r1, [r0, #LCD_WIDTH]! @ store pixel
286#else
287 strh r1, [r0] @
288#endif
289 @
290 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
291 add r12, r7, r7, asl #2 @
292 add r7, r12, r7, asl #5 @
293 @ compute R, G, and B
294 add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu
295 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
296 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
297 @
298#if ARM_ARCH >= 6
299 usat r1, #5, r1 @ clamp b
300 usat lr, #5, lr @ clamp r
301 usat r7, #6, r7 @ clamp g
302#else
303 orr r12, r1, lr @ check if clamping is needed...
304 orr r12, r12, r7, asr #1 @ ...at all
305 cmp r12, #31 @
306 bls 15f @ no clamp @
307 cmp r1, #31 @ clamp b
308 mvnhi r1, r1, asr #31 @
309 andhi r1, r1, #31 @
310 cmp lr, #31 @ clamp r
311 mvnhi lr, lr, asr #31 @
312 andhi lr, lr, #31 @
313 cmp r7, #63 @ clamp g
314 mvnhi r7, r7, asr #31 @
315 andhi r7, r7, #63 @
31615: @ no clamp @
317#endif
318 @
319 orr r12, r1, lr, lsl #11 @ r12 = b | (r << 11)
320 orr r12, r12, r7, lsl #5 @ r12 |= (g << 5)
321
322#if LCD_WIDTH >= LCD_HEIGHT
323 add r0, r0, #2*LCD_WIDTH
324 strh r12, [r0, #2]
325#if LCD_WIDTH <= 512
326 sub r0, r0, #(2*LCD_WIDTH)-4
327#else
328 sub r0, r0, #(2*LCD_WIDTH)
329 add r0, r0, #4
330#endif
331#else
332 strh r12, [r0, #-2] @ store pixel
333#if LCD_WIDTH < 256
334 add r0, r0, #2*LCD_WIDTH @
335#else
336 add r0, r0, #LCD_WIDTH @
337#endif
338#endif
339 @
340 subs r2, r2, #2 @ subtract block from width
341 bgt 10b @ loop line @
342 @
343 ldmpc regs=r4-r10 @ restore registers and return
344 .ltorg @ dump constant pool
345 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
346
347
348/****************************************************************************
349 * void lcd_write_yuv420_lines_odither(fb_data *dst,
350 * unsigned char const * const src[3],
351 * int width,
352 * int stride,
353 * int x_screen,
354 * int y_screen);
355 *
356 * |R| |1.000000 -0.000001 1.402000| |Y'|
357 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
358 * |B| |1.000000 1.772000 0.000000| |Pr|
359 * Red scaled at twice g & b but at same precision to place it in correct
360 * bit position after multiply and leave instruction count lower.
361 * |R| |258 0 408| |Y' - 16|
362 * |G| = |149 -49 -104| |Cb - 128|
363 * |B| |149 258 0| |Cr - 128|
364 *
365 * Write four RGB565 pixels in the following order on each loop:
366 * 1 3 + > down
367 * 2 4 \/ left
368 *
369 * Kernel pattern (raw|rotated|use order):
370 * 5 3 4 2 2 6 3 7 row0 row2 > down
371 * 1 7 0 6 | 4 0 5 1 | 2 4 6 0 3 5 7 1 col0 left
372 * 4 2 5 3 | 3 7 2 6 | 3 5 7 1 2 4 6 0 col2 \/
373 * 0 6 1 7 5 1 4 0
374 */
375 .section .icode.lcd_write_yuv420_lines_odither, "ax", %progbits
376 .align 2
377 .global lcd_write_yuv420_lines_odither
378 .type lcd_write_yuv420_lines_odither, %function
379lcd_write_yuv420_lines_odither:
380 @ r0 = dst
381 @ r1 = yuv_src
382 @ r2 = width
383 @ r3 = stride
384 @ [sp] = x_screen
385 @ [sp+4] = y_screen
386 stmfd sp!, { r4-r11, lr } @ save non-scratch
387 ldmia r1, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
388 @ r5 = yuv_src[1] = Cb_p
389 @ r6 = yuv_src[2] = Cr_p
390 @
391 sub r3, r3, #1 @
392 add r1, sp, #36 @ Line up pattern and kernel quadrant
393 ldmia r1, { r12, r14 } @
394 eor r14, r14, r12 @
395 and r14, r14, #0x2 @
396 mov r14, r14, lsl #6 @ 0x00 or 0x80
39710: @ loop line @
398 @
399 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
400 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
401 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
402 @
403 eor r14, r14, #0x80 @ flip pattern quadrant
404 @
405 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149
406 add r12, r7, r7, asl #2 @
407 add r12, r12, r12, asl #4 @
408 add r7, r12, r7, asl #6 @
409 @
410 sub r8, r8, #128 @ Cb -= 128
411 sub r9, r9, #128 @ Cr -= 128
412 @
413 add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49
414 add r10, r10, r8, asl #5 @
415 add r10, r10, r9, asl #3 @
416 add r10, r10, r9, asl #5 @
417 add r10, r10, r9, asl #6 @
418 @
419 mov r8, r8, asl #1 @ r8 = bu = Cb*258
420 add r8, r8, r8, asl #7 @
421 @
422 add r9, r9, r9, asl #1 @ r9 = rv = Cr*408
423 add r9, r9, r9, asl #4 @
424 mov r9, r9, asl #3 @
425 @
426 @ compute R, G, and B
427 add r1, r8, r7 @ r1 = b' = Y + bu
428 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
429 rsb r7, r10, r7 @ r7 = g' = Y + guv
430 @
431 @ r8 = bu, r9 = rv, r10 = guv
432 @
433 sub r12, r1, r1, lsr #5 @ r1 = 31/32*b + b/256
434 add r1, r12, r1, lsr #8 @
435 @
436 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
437 add r11, r12, r11, lsr #8 @
438 @
439 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
440 add r7, r12, r7, lsr #8 @
441 @
442 add r12, r14, #0x100 @
443 @
444 add r1, r1, r12 @ b = r1 + delta
445 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
446 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
447 @
448#if ARM_ARCH >= 6
449 usat r11, #5, r11, asr #11 @ clamp r
450 usat r7, #6, r7, asr #9 @ clamp g
451 usat r1, #5, r1, asr #10 @ clamp b
452 @
453 ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride)
454 @
455 orr r1, r1, r11, lsl #11 @ r1 = b | (r << 11)
456 orr r1, r1, r7, lsl #5 @ r1 |= (g << 5)
457#else
458 orr r12, r1, r11, asr #1 @ check if clamping is needed...
459 orr r12, r12, r7 @ ...at all
460 movs r12, r12, asr #15 @
461 beq 15f @ no clamp @
462 movs r12, r1, asr #15 @ clamp b
463 mvnne r1, r12, lsr #15 @
464 andne r1, r1, #0x7c00 @ mask b only if clamped
465 movs r12, r11, asr #16 @ clamp r
466 mvnne r11, r12, lsr #16 @
467 movs r12, r7, asr #15 @ clamp g
468 mvnne r7, r12, lsr #15 @
46915: @ no clamp @
470 @
471 ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride)
472 @
473 and r11, r11, #0xf800 @ pack pixel
474 and r7, r7, #0x7e00 @ r1 = pixel = (r & 0xf800) |
475 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
476 orr r1, r11, r1, lsr #10 @ (b >> 10)
477#endif
478 @
479#if LCD_WIDTH >= LCD_HEIGHT
480 strh r1, [r0] @
481#elif LCD_WIDTH < 256
482 strh r1, [r0], #LCD_WIDTH @ store pixel
483#else
484 strh r1, [r0] @
485#endif
486 @
487 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
488 add r12, r7, r7, asl #2 @
489 add r12, r12, r12, asl #4 @
490 add r7, r12, r7, asl #6 @
491 @ compute R, G, and B
492 add r1, r8, r7 @ r1 = b' = Y + bu
493 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
494 rsb r7, r10, r7 @ r7 = g' = Y + guv
495 @
496 sub r12, r1, r1, lsr #5 @ r1 = 31/32*b' + b'/256
497 add r1, r12, r1, lsr #8 @
498 @
499 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
500 add r11, r12, r11, lsr #8 @
501 @
502 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
503 add r7, r12, r7, lsr #8 @
504 @
505 add r12, r14, #0x200 @
506 @
507 add r1, r1, r12 @ b = r1 + delta
508 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
509 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
510 @
511#if ARM_ARCH >= 6
512 usat r11, #5, r11, asr #11 @ clamp r
513 usat r7, #6, r7, asr #9 @ clamp g
514 usat r1, #5, r1, asr #10 @ clamp b
515 @
516 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
517 @
518 orr r1, r1, r11, lsl #11 @ r1 = b | (r << 11)
519 orr r1, r1, r7, lsl #5 @ r1 |= (g << 5)
520#else
521 orr r12, r1, r11, asr #1 @ check if clamping is needed...
522 orr r12, r12, r7 @ ...at all
523 movs r12, r12, asr #15 @
524 beq 15f @ no clamp @
525 movs r12, r1, asr #15 @ clamp b
526 mvnne r1, r12, lsr #15 @
527 andne r1, r1, #0x7c00 @ mask b only if clamped
528 movs r12, r11, asr #16 @ clamp r
529 mvnne r11, r12, lsr #16 @
530 movs r12, r7, asr #15 @ clamp g
531 mvnne r7, r12, lsr #15 @
53215: @ no clamp @
533 @
534 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
535 @
536 and r11, r11, #0xf800 @ pack pixel
537 and r7, r7, #0x7e00 @ r1 = pixel = (r & 0xf800) |
538 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
539 orr r1, r11, r1, lsr #10 @ (b >> 10)
540#endif
541 @
542#if LCD_WIDTH >= LCD_HEIGHT
543 add r0, r0, #2*LCD_WIDTH @
544 strh r1, [r0] @ store pixel
545 sub r0, r0, #2*LCD_WIDTH @
546#elif LCD_WIDTH < 256
547 strh r1, [r0, #-LCD_WIDTH-2] @ store pixel
548#else
549 strh r1, [r0, #-2] @ store pixel
550 add r0, r0, #LCD_WIDTH @
551#endif
552 @
553 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
554 add r12, r7, r7, asl #2 @
555 add r12, r12, r12, asl #4 @
556 add r7, r12, r7, asl #6 @
557 @ compute R, G, and B
558 add r1, r8, r7 @ r1 = b' = Y + bu
559 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
560 rsb r7, r10, r7 @ r7 = g' = Y + guv
561 @
562 @ r8 = bu, r9 = rv, r10 = guv
563 @
564 sub r12, r1, r1, lsr #5 @ r1 = 31/32*b' + b'/256
565 add r1, r12, r1, lsr #8 @
566 @
567 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
568 add r11, r12, r11, lsr #8 @
569 @
570 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
571 add r7, r12, r7, lsr #8 @
572 @
573 add r12, r14, #0x300 @
574 @
575 add r1, r1, r12 @ b = r1 + delta
576 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
577 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
578 @
579#if ARM_ARCH >= 6
580 usat r11, #5, r11, asr #11 @ clamp r
581 usat r7, #6, r7, asr #9 @ clamp g
582 usat r1, #5, r1, asr #10 @ clamp b
583 @
584 ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride)
585 @
586 orr r1, r1, r11, lsl #11 @ r1 = b | (r << 11)
587 orr r1, r1, r7, lsl #5 @ r1 |= (g << 5)
588#else
589 orr r12, r1, r11, asr #1 @ check if clamping is needed...
590 orr r12, r12, r7 @ ...at all
591 movs r12, r12, asr #15 @
592 beq 15f @ no clamp @
593 movs r12, r1, asr #15 @ clamp b
594 mvnne r1, r12, lsr #15 @
595 andne r1, r1, #0x7c00 @ mask b only if clamped
596 movs r12, r11, asr #16 @ clamp r
597 mvnne r11, r12, lsr #16 @
598 movs r12, r7, asr #15 @ clamp g
599 mvnne r7, r12, lsr #15 @
60015: @ no clamp @
601 @
602 ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride)
603 @
604 and r11, r11, #0xf800 @ pack pixel
605 and r7, r7, #0x7e00 @ r1 = pixel = (r & 0xf800) |
606 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
607 orr r1, r11, r1, lsr #10 @ (b >> 10)
608#endif
609 @
610#if LCD_WIDTH >= LCD_HEIGHT
611 strh r1, [r0, #2]
612#elif LCD_WIDTH < 256
613 strh r1, [r0, #LCD_WIDTH]! @ store pixel
614#else
615 strh r1, [r0] @
616#endif
617
618 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
619 add r12, r7, r7, asl #2 @
620 add r12, r12, r12, asl #4 @
621 add r7, r12, r7, asl #6 @
622 @ compute R, G, and B
623 add r1, r8, r7 @ r1 = b' = Y + bu
624 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
625 rsb r7, r10, r7 @ r7 = g' = Y + guv
626 @
627 sub r12, r1, r1, lsr #5 @ r1 = 31/32*b + b/256
628 add r1, r12, r1, lsr #8 @
629 @
630 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
631 add r11, r12, r11, lsr #8 @
632 @
633 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
634 add r7, r12, r7, lsr #8 @
635 @
636 @ This element is zero - use r14 @
637 @
638 add r1, r1, r14 @ b = r1 + delta
639 add r11, r11, r14, lsl #1 @ r = r11 + delta*2
640 add r7, r7, r14, lsr #1 @ g = r7 + delta/2
641 @
642#if ARM_ARCH >= 6
643 usat r11, #5, r11, asr #11 @ clamp r
644 usat r7, #6, r7, asr #9 @ clamp g
645 usat r1, #5, r1, asr #10 @ clamp b
646 @
647 orr r1, r1, r11, lsl #11 @ r1 = b | (r << 11)
648 orr r1, r1, r7, lsl #5 @ r1 |= (g << 5)
649#else
650 orr r12, r1, r11, asr #1 @ check if clamping is needed...
651 orr r12, r12, r7 @ ...at all
652 movs r12, r12, asr #15 @
653 beq 15f @ no clamp @
654 movs r12, r1, asr #15 @ clamp b
655 mvnne r1, r12, lsr #15 @
656 andne r1, r1, #0x7c00 @ mask b only if clamped
657 movs r12, r11, asr #16 @ clamp r
658 mvnne r11, r12, lsr #16 @
659 movs r12, r7, asr #15 @ clamp g
660 mvnne r7, r12, lsr #15 @
66115: @ no clamp @
662 @
663 and r11, r11, #0xf800 @ pack pixel
664 and r7, r7, #0x7e00 @ r1 = pixel = (r & 0xf800) |
665 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
666 orr r1, r11, r1, lsr #10 @ (b >> 10)
667#endif
668 @
669#if LCD_WIDTH >= LCD_HEIGHT
670 add r0, r0, #2*LCD_WIDTH
671 strh r1, [r0, #2] @ store pixel
672#if LCD_WIDTH <= 512
673 sub r0, r0, #(2*LCD_WIDTH)-4
674#else
675 sub r0, r0, #(2*LCD_WIDTH)
676 add r0, r0, #4
677#endif
678#else
679 strh r1, [r0, #-2] @ store pixel
680#if LCD_WIDTH < 256
681 add r0, r0, #2*LCD_WIDTH @
682#else
683 add r0, r0, #LCD_WIDTH @
684#endif
685#endif
686 @
687 subs r2, r2, #2 @ subtract block from width
688 bgt 10b @ loop line @
689 @
690 ldmpc regs=r4-r11 @ restore registers and return
691 .ltorg @ dump constant pool
692 .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither
diff --git a/firmware/asm/lcd-as-memframe.c b/firmware/asm/lcd-as-memframe.c
index f7f3473fad..fb31fa1953 100644
--- a/firmware/asm/lcd-as-memframe.c
+++ b/firmware/asm/lcd-as-memframe.c
@@ -9,3 +9,171 @@ void lcd_copy_buffer_rect(fb_data *dst, fb_data *src, int width, int height)
9 dst += LCD_WIDTH; 9 dst += LCD_WIDTH;
10 } while (--height); 10 } while (--height);
11} 11}
12
13#define YFAC (74)
14#define RVFAC (101)
15#define GUFAC (-24)
16#define GVFAC (-51)
17#define BUFAC (128)
18
19static inline int clamp(int val, int min, int max)
20{
21 if (val < min)
22 val = min;
23 else if (val > max)
24 val = max;
25 return val;
26}
27
28extern void lcd_write_yuv420_lines(fb_data *dst,
29 unsigned char const * const src[3],
30 int width,
31 int stride)
32{
33 /* Draw a partial YUV colour bitmap - similiar behavior to lcd_blit_yuv
34 in the core */
35 const unsigned char *ysrc, *usrc, *vsrc;
36 fb_data *row_end;
37
38 /* width and height must be >= 2 and an even number */
39 width &= ~1;
40
41#if LCD_WIDTH >= LCD_HEIGHT
42 row_end = dst + width;
43#else
44 row_end = dst + LCD_WIDTH * width;
45#endif
46
47 ysrc = src[0];
48 usrc = src[1];
49 vsrc = src[2];
50
51 /* stride => amount to jump from end of last row to start of next */
52 stride -= width;
53
54 /* upsampling, YUV->RGB conversion and reduction to RGB in one go */
55
56 do
57 {
58 int y, cb, cr, rv, guv, bu, r, g, b;
59
60 y = YFAC*(*ysrc++ - 16);
61 cb = *usrc++ - 128;
62 cr = *vsrc++ - 128;
63
64 rv = RVFAC*cr;
65 guv = GUFAC*cb + GVFAC*cr;
66 bu = BUFAC*cb;
67
68 r = y + rv;
69 g = y + guv;
70 b = y + bu;
71
72 if ((unsigned)(r | g | b) > 64*256-1)
73 {
74 r = clamp(r, 0, 64*256-1);
75 g = clamp(g, 0, 64*256-1);
76 b = clamp(b, 0, 64*256-1);
77 }
78
79 *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6);
80
81#if LCD_WIDTH >= LCD_HEIGHT
82 dst++;
83#else
84 dst += LCD_WIDTH;
85#endif
86
87 y = YFAC*(*ysrc++ - 16);
88 r = y + rv;
89 g = y + guv;
90 b = y + bu;
91
92 if ((unsigned)(r | g | b) > 64*256-1)
93 {
94 r = clamp(r, 0, 64*256-1);
95 g = clamp(g, 0, 64*256-1);
96 b = clamp(b, 0, 64*256-1);
97 }
98
99 *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6);
100
101#if LCD_WIDTH >= LCD_HEIGHT
102 dst++;
103#else
104 dst += LCD_WIDTH;
105#endif
106 }
107 while (dst < row_end);
108
109 ysrc += stride;
110 usrc -= width >> 1;
111 vsrc -= width >> 1;
112
113#if LCD_WIDTH >= LCD_HEIGHT
114 row_end += LCD_WIDTH;
115 dst += LCD_WIDTH - width;
116#else
117 row_end -= 1;
118 dst -= LCD_WIDTH*width + 1;
119#endif
120
121 do
122 {
123 int y, cb, cr, rv, guv, bu, r, g, b;
124
125 y = YFAC*(*ysrc++ - 16);
126 cb = *usrc++ - 128;
127 cr = *vsrc++ - 128;
128
129 rv = RVFAC*cr;
130 guv = GUFAC*cb + GVFAC*cr;
131 bu = BUFAC*cb;
132
133 r = y + rv;
134 g = y + guv;
135 b = y + bu;
136
137 if ((unsigned)(r | g | b) > 64*256-1)
138 {
139 r = clamp(r, 0, 64*256-1);
140 g = clamp(g, 0, 64*256-1);
141 b = clamp(b, 0, 64*256-1);
142 }
143
144 *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6);
145
146#if LCD_WIDTH >= LCD_HEIGHT
147 dst++;
148#else
149 dst += LCD_WIDTH;
150#endif
151
152 y = YFAC*(*ysrc++ - 16);
153 r = y + rv;
154 g = y + guv;
155 b = y + bu;
156
157 if ((unsigned)(r | g | b) > 64*256-1)
158 {
159 r = clamp(r, 0, 64*256-1);
160 g = clamp(g, 0, 64*256-1);
161 b = clamp(b, 0, 64*256-1);
162 }
163
164 *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6);
165
166#if LCD_WIDTH >= LCD_HEIGHT
167 dst++;
168#else
169 dst += LCD_WIDTH;
170#endif
171 }
172 while (dst < row_end);
173}
174
175void lcd_write_yuv420_lines_odither(fb_data *dst,
176 unsigned char const * const src[3],
177 int width, int stride,
178 int x_screen, int y_screen)
179__attribute__((alias("lcd_write_yuv420_lines")));
diff --git a/firmware/drivers/lcd-color-common.c b/firmware/drivers/lcd-color-common.c
index cce0bbbf4e..ae0fe519bc 100644
--- a/firmware/drivers/lcd-color-common.c
+++ b/firmware/drivers/lcd-color-common.c
@@ -220,6 +220,195 @@ static inline int clamp(int val, int min, int max)
220 return val; 220 return val;
221} 221}
222 222
223#ifndef _WIN32
224/*
225 * weak attribute doesn't work for win32 as of gcc 4.6.2 and binutils 2.21.52
226 * When building win32 simulators, we won't be using an optimized version of
227 * lcd_blit_yuv(), so just don't use the weak attribute.
228 */
229__attribute__((weak))
230#endif
231void lcd_yuv_set_options(unsigned options)
232{
233 (void)options;
234}
235
236/* Draw a partial YUV colour bitmap */
237#ifndef _WIN32
238__attribute__((weak))
239#endif
240void lcd_blit_yuv(unsigned char * const src[3],
241 int src_x, int src_y, int stride,
242 int x, int y, int width, int height)
243{
244 const unsigned char *ysrc, *usrc, *vsrc;
245 int linecounter;
246 fb_data *dst, *row_end;
247 long z;
248
249 /* width and height must be >= 2 and an even number */
250 width &= ~1;
251 linecounter = height >> 1;
252
253#if LCD_WIDTH >= LCD_HEIGHT
254 dst = FBADDR(x, y);
255 row_end = dst + width;
256#else
257 dst = FBADDR(LCD_WIDTH - y - 1, x);
258 row_end = dst + LCD_WIDTH * width;
259#endif
260
261 z = stride * src_y;
262 ysrc = src[0] + z + src_x;
263 usrc = src[1] + (z >> 2) + (src_x >> 1);
264 vsrc = src[2] + (usrc - src[1]);
265
266 /* stride => amount to jump from end of last row to start of next */
267 stride -= width;
268
269 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
270
271 do
272 {
273 do
274 {
275 int y, cb, cr, rv, guv, bu, r, g, b;
276
277 y = YFAC*(*ysrc++ - 16);
278 cb = *usrc++ - 128;
279 cr = *vsrc++ - 128;
280
281 rv = RVFAC*cr;
282 guv = GUFAC*cb + GVFAC*cr;
283 bu = BUFAC*cb;
284
285 r = y + rv;
286 g = y + guv;
287 b = y + bu;
288
289 if ((unsigned)(r | g | b) > 64*256-1)
290 {
291 r = clamp(r, 0, 64*256-1);
292 g = clamp(g, 0, 64*256-1);
293 b = clamp(b, 0, 64*256-1);
294 }
295
296 *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6);
297
298#if LCD_WIDTH >= LCD_HEIGHT
299 dst++;
300#else
301 dst += LCD_WIDTH;
302#endif
303
304 y = YFAC*(*ysrc++ - 16);
305 r = y + rv;
306 g = y + guv;
307 b = y + bu;
308
309 if ((unsigned)(r | g | b) > 64*256-1)
310 {
311 r = clamp(r, 0, 64*256-1);
312 g = clamp(g, 0, 64*256-1);
313 b = clamp(b, 0, 64*256-1);
314 }
315
316 *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6);
317
318#if LCD_WIDTH >= LCD_HEIGHT
319 dst++;
320#else
321 dst += LCD_WIDTH;
322#endif
323 }
324 while (dst < row_end);
325
326 ysrc += stride;
327 usrc -= width >> 1;
328 vsrc -= width >> 1;
329
330#if LCD_WIDTH >= LCD_HEIGHT
331 row_end += LCD_WIDTH;
332 dst += LCD_WIDTH - width;
333#else
334 row_end -= 1;
335 dst -= LCD_WIDTH*width + 1;
336#endif
337
338 do
339 {
340 int y, cb, cr, rv, guv, bu, r, g, b;
341
342 y = YFAC*(*ysrc++ - 16);
343 cb = *usrc++ - 128;
344 cr = *vsrc++ - 128;
345
346 rv = RVFAC*cr;
347 guv = GUFAC*cb + GVFAC*cr;
348 bu = BUFAC*cb;
349
350 r = y + rv;
351 g = y + guv;
352 b = y + bu;
353
354 if ((unsigned)(r | g | b) > 64*256-1)
355 {
356 r = clamp(r, 0, 64*256-1);
357 g = clamp(g, 0, 64*256-1);
358 b = clamp(b, 0, 64*256-1);
359 }
360
361 *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6);
362
363#if LCD_WIDTH >= LCD_HEIGHT
364 dst++;
365#else
366 dst += LCD_WIDTH;
367#endif
368
369 y = YFAC*(*ysrc++ - 16);
370 r = y + rv;
371 g = y + guv;
372 b = y + bu;
373
374 if ((unsigned)(r | g | b) > 64*256-1)
375 {
376 r = clamp(r, 0, 64*256-1);
377 g = clamp(g, 0, 64*256-1);
378 b = clamp(b, 0, 64*256-1);
379 }
380
381 *dst = FB_RGBPACK(r >> 6, g >> 6, b >> 6);
382
383#if LCD_WIDTH >= LCD_HEIGHT
384 dst++;
385#else
386 dst += LCD_WIDTH;
387#endif
388 }
389 while (dst < row_end);
390
391 ysrc += stride;
392 usrc += stride >> 1;
393 vsrc += stride >> 1;
394
395#if LCD_WIDTH >= LCD_HEIGHT
396 row_end += LCD_WIDTH;
397 dst += LCD_WIDTH - width;
398#else
399 row_end -= 1;
400 dst -= LCD_WIDTH*width + 1;
401#endif
402 }
403 while (--linecounter > 0);
404
405#if LCD_WIDTH >= LCD_HEIGHT
406 lcd_update_rect(x, y, width, height);
407#else
408 lcd_update_rect(LCD_WIDTH - y - height, x, height, width);
409#endif
410}
411
223/* Fill a rectangle with a gradient. This function draws only the partial 412/* Fill a rectangle with a gradient. This function draws only the partial
224 * gradient. It assumes the original gradient is src_height high and skips 413 * gradient. It assumes the original gradient is src_height high and skips
225 * the first few rows. This is useful for drawing only the bottom half of 414 * the first few rows. This is useful for drawing only the bottom half of
diff --git a/firmware/drivers/lcd-memframe.c b/firmware/drivers/lcd-memframe.c
index 357b4af32a..bb1682b074 100644
--- a/firmware/drivers/lcd-memframe.c
+++ b/firmware/drivers/lcd-memframe.c
@@ -110,3 +110,101 @@ void lcd_update_rect(int x, int y, int width, int height)
110 } 110 }
111} 111}
112#endif /* LCD_OPTIMIZED_UPDATE_RECT */ 112#endif /* LCD_OPTIMIZED_UPDATE_RECT */
113
114
115/*** YUV functions ***/
116static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
117
118
119/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
120extern void lcd_write_yuv420_lines(fb_data *dst,
121 unsigned char const * const src[3],
122 int width,
123 int stride);
124extern void lcd_write_yuv420_lines_odither(fb_data *dst,
125 unsigned char const * const src[3],
126 int width,
127 int stride,
128 int x_screen, /* To align dither pattern */
129 int y_screen);
130
131void lcd_yuv_set_options(unsigned options)
132{
133 lcd_yuv_options = options;
134}
135
136#ifndef LCD_OPTIMIZED_BLIT_YUV
137/* Performance function to blit a YUV bitmap directly to the LCD
138 * src_x, src_y, width and height should be even and within the LCD's
139 * boundaries.
140 *
141 * For portrait LCDs, show it rotated counterclockwise by 90 degrees
142 */
143void lcd_blit_yuv(unsigned char * const src[3],
144 int src_x, int src_y, int stride,
145 int x, int y, int width, int height)
146{
147 /* Macrofy the bits that change between orientations */
148#if CONFIG_ORIENTATION == SCREEN_PORTRAIT
149 #define LCD_FRAMEBUF_ADDR_ORIENTED(col, row) \
150 LCD_FRAMEBUF_ADDR(row, col)
151 #define lcd_write_yuv420_lines_odither_oriented(dst, src, w, s, col, row) \
152 lcd_write_yuv420_lines_odither(dst, src, w, s, row, col)
153 #define YUV_NEXTLINE() dst -= 2
154 #define YUV_DITHER_NEXTLINE() dst -= 2, y -= 2
155#else
156 #define LCD_FRAMEBUF_ADDR_ORIENTED(col, row) \
157 LCD_FRAMEBUF_ADDR(col, row)
158 #define lcd_write_yuv420_lines_odither_oriented(dst, src, w, s, col, row) \
159 lcd_write_yuv420_lines_odither(dst, src, w, s, col, row)
160 #define YUV_NEXTLINE() dst += 2*LCD_FBWIDTH
161 #define YUV_DITHER_NEXTLINE() dst += 2*LCD_FBWIDTH, y += 2
162#endif
163
164 if (!lcd_write_enabled())
165 return;
166
167 /* Sorry, but width and height must be >= 2 or else */
168 width &= ~1;
169 height >>= 1;
170
171#if CONFIG_ORIENTATION == SCREEN_PORTRAIT
172 /* Adjust portrait coordinates to make (0, 0) the upper right corner */
173 y = LCD_WIDTH - 1 - y;
174#endif
175
176 fb_data *dst = LCD_FRAMEBUF_ADDR_ORIENTED(x, y);
177 int z = stride*src_y;
178
179 unsigned char const * yuv_src[3];
180 yuv_src[0] = src[0] + z + src_x;
181 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
182 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
183
184 if (lcd_yuv_options & LCD_YUV_DITHER)
185 {
186 do
187 {
188 lcd_write_yuv420_lines_odither_oriented(dst, yuv_src, width,
189 stride, x, y);
190 yuv_src[0] += stride << 1; /* Skip down two luma lines */
191 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
192 yuv_src[2] += stride >> 1;
193 YUV_DITHER_NEXTLINE();
194 }
195 while (--height > 0);
196 }
197 else
198 {
199 do
200 {
201 lcd_write_yuv420_lines(dst, yuv_src, width, stride);
202 yuv_src[0] += stride << 1; /* Skip down two luma lines */
203 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
204 yuv_src[2] += stride >> 1;
205 YUV_NEXTLINE();
206 }
207 while (--height > 0);
208 }
209}
210#endif /* LCD_OPTIMIZED_BLIT_YUV */
diff --git a/firmware/export/config/mrobe500.h b/firmware/export/config/mrobe500.h
index 0ecec80e02..621c0b75ca 100644
--- a/firmware/export/config/mrobe500.h
+++ b/firmware/export/config/mrobe500.h
@@ -220,7 +220,7 @@
220#define HAVE_USB_HID_MOUSE 220#define HAVE_USB_HID_MOUSE
221 221
222/* Define this if hardware supports alternate blitting */ 222/* Define this if hardware supports alternate blitting */
223#define HAVE_LCD_MODES (LCD_MODE_RGB565 | LCD_MODE_PAL256) 223#define HAVE_LCD_MODES (LCD_MODE_RGB565 | LCD_MODE_YUV | LCD_MODE_PAL256)
224 224
225#define CONFIG_CPU DM320 225#define CONFIG_CPU DM320
226 226
diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h
index 29c34b698b..67b22190ad 100644
--- a/firmware/export/lcd.h
+++ b/firmware/export/lcd.h
@@ -145,6 +145,7 @@ struct scrollinfo;
145#if defined(HAVE_LCD_MODES) 145#if defined(HAVE_LCD_MODES)
146 void lcd_set_mode(int mode); 146 void lcd_set_mode(int mode);
147#define LCD_MODE_RGB565 0x00000001 147#define LCD_MODE_RGB565 0x00000001
148#define LCD_MODE_YUV 0x00000002
148#define LCD_MODE_PAL256 0x00000004 149#define LCD_MODE_PAL256 0x00000004
149 150
150#if HAVE_LCD_MODES & LCD_MODE_PAL256 151#if HAVE_LCD_MODES & LCD_MODE_PAL256
@@ -235,7 +236,15 @@ extern bool lcd_putsxy_scroll_func(int x, int y, const unsigned char *string,
235 void *data, int x_offset); 236 void *data, int x_offset);
236 237
237/* performance function */ 238/* performance function */
238#if !defined(HAVE_LCD_COLOR) 239#if defined(HAVE_LCD_COLOR)
240#if MEMORYSIZE > 2
241#define LCD_YUV_DITHER 0x1
242 extern void lcd_yuv_set_options(unsigned options);
243 extern void lcd_blit_yuv(unsigned char * const src[3],
244 int src_x, int src_y, int stride,
245 int x, int y, int width, int height);
246#endif /* MEMORYSIZE > 2 */
247#else
239 extern void lcd_blit_mono(const unsigned char *data, int x, int by, int width, 248 extern void lcd_blit_mono(const unsigned char *data, int x, int by, int width,
240 int bheight, int stride); 249 int bheight, int stride);
241 extern void lcd_blit_grey_phase(unsigned char *values, unsigned char *phases, 250 extern void lcd_blit_grey_phase(unsigned char *values, unsigned char *phases,
diff --git a/firmware/target/arm/as3525/lcd-as-e200v2-fuze-fuzev2.S b/firmware/target/arm/as3525/lcd-as-e200v2-fuze-fuzev2.S
new file mode 100644
index 0000000000..feffe6fb96
--- /dev/null
+++ b/firmware/target/arm/as3525/lcd-as-e200v2-fuze-fuzev2.S
@@ -0,0 +1,550 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 by Jens Arnold
11 * Heavily based on lcd-as-memframe.c by Michael Sevakis
12 * Adapted for Sansa Fuze/e200v2 by Rafaël Carré
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#include "config.h"
25#include "cpu.h"
26
27#define DBOP_BUSY (1<<10)
28
29/****************************************************************************
30 * void lcd_write_yuv420_lines(unsigned char const * const src[3],
31 * int width,
32 * int stride);
33 *
34 * |R| |1.000000 -0.000001 1.402000| |Y'|
35 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
36 * |B| |1.000000 1.772000 0.000000| |Pr|
37 * Scaled, normalized, rounded and tweaked to yield RGB 565:
38 * |R| |74 0 101| |Y' - 16| >> 9
39 * |G| = |74 -24 -51| |Cb - 128| >> 8
40 * |B| |74 128 0| |Cr - 128| >> 9
41 *
42 * Write four RGB565 pixels in the following order on each loop:
43 * 1 3 + > down
44 * 2 4 \/ left
45 */
46 .section .icode, "ax", %progbits
47 .align 2
48 .global lcd_write_yuv420_lines
49 .type lcd_write_yuv420_lines, %function
50lcd_write_yuv420_lines:
51 @ r0 = yuv_src
52 @ r1 = width
53 @ r2 = stride
54 stmfd sp!, { r4-r11, lr } @ save non-scratch
55
56 mov r3, #0xC8000000 @
57 orr r3, r3, #0x120000 @ r3 = DBOP_BASE
58
59 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
60 @ r5 = yuv_src[1] = Cb_p
61 @ r6 = yuv_src[2] = Cr_p
62 @ r0 = scratch
63 ldr r12, [r3, #8] @
64 sub r2, r2, #1 @ stride -= 1
65 orr r12, r12, #3<<13 @ DBOP_CTRL |= (1<<13|1<<14) (32bit mode)
66#ifdef SANSA_FUZEV2
67 bic r12, r12, #1<<13 @ DBOP_CTRL &= ~(1<<13),still 32bit mode
68#endif
69 str r12, [r3, #8] @
7010: @ loop line @
71 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
72 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
73 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
74 @
75 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74
76 add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right
77 add r7, r12, r7, asl #5 @ by one less when adding - same for all
78 @
79 sub r8, r8, #128 @ Cb -= 128
80 sub r9, r9, #128 @ Cr -= 128
81 @
82 add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24
83 add r10, r10, r10, asl #4 @
84 add r10, r10, r8, asl #3 @
85 add r10, r10, r8, asl #4 @
86 @
87 add lr, r9, r9, asl #2 @ r9 = Cr*101
88 add lr, lr, r9, asl #5 @
89 add r9, lr, r9, asl #6 @
90 @
91 add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8
92 mov r8, r8, asr #2 @
93 add r9, r9, #256 @ r9 = rv = (r9 + 256) >> 9
94 mov r9, r9, asr #9 @
95 rsb r10, r10, #128 @ r10 = guv = (-r10 + 128) >> 8
96 mov r10, r10, asr #8 @
97 @ compute R, G, and B
98 add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu
99 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
100 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
101 @
102 orr r12, r0, lr @ check if clamping is needed...
103 orr r12, r12, r7, asr #1 @ ...at all
104 cmp r12, #31 @
105 bls 15f @ no clamp @
106 cmp r0, #31 @ clamp b
107 mvnhi r0, r0, asr #31 @
108 andhi r0, r0, #31 @
109 cmp lr, #31 @ clamp r
110 mvnhi lr, lr, asr #31 @
111 andhi lr, lr, #31 @
112 cmp r7, #63 @ clamp g
113 mvnhi r7, r7, asr #31 @
114 andhi r7, r7, #63 @
11515: @ no clamp @
116 @
117 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
118 @
119 orr r0, r0, lr, lsl #11 @ r0 = (r << 11) | b
120 orr r11, r0, r7, lsl #5 @ r11 = (r << 11) | (g << 5) | b
121 orr r11, r0, r7, lsl #5 @ r11 = (r << 11) | (g << 5) | b
122#ifdef SANSA_FUZEV2
123 mov r0, r11, lsr #8 @
124 bic r11, r11, #0xff00 @
125 orr r11, r0, r11, lsl #8 @ swap bytes
126#endif
127 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
128 add r12, r7, r7, asl #2 @
129 add r7, r12, r7, asl #5 @
130 @ compute R, G, and B
131 add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu
132 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
133 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
134 @
135 orr r12, r0, lr @ check if clamping is needed...
136 orr r12, r12, r7, asr #1 @ ...at all
137 cmp r12, #31 @
138 bls 15f @ no clamp @
139 cmp r0, #31 @ clamp b
140 mvnhi r0, r0, asr #31 @
141 andhi r0, r0, #31 @
142 cmp lr, #31 @ clamp r
143 mvnhi lr, lr, asr #31 @
144 andhi lr, lr, #31 @
145 cmp r7, #63 @ clamp g
146 mvnhi r7, r7, asr #31 @
147 andhi r7, r7, #63 @
14815: @ no clamp @
149 @
150 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
151 @
152 orr r0, r0, lr, lsl #11 @ r0 = (r << 11) | b
153 orr r0, r0, r7, lsl #5 @ r0 = (r << 11) | (g << 5) | b
154
155#ifdef SANSA_FUZEV2
156 mov r7, r0, lsr #8 @
157 bic r7, r7, #0xff00 @
158 orr r0, r7, r0, lsl #8 @ swap bytes
159#endif
160
161 orr r0, r11, r0, lsl#16 @ pack with 2nd pixel
162 str r0, [r3, #0x10] @ write pixel
163 @
164 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
165 add r12, r7, r7, asl #2 @
166 add r7, r12, r7, asl #5 @
167 @ compute R, G, and B
168 add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu
169 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
170 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
171 @
172 orr r12, r0, lr @ check if clamping is needed...
173 orr r12, r12, r7, asr #1 @ ...at all
174 cmp r12, #31 @
175 bls 15f @ no clamp @
176 cmp r0, #31 @ clamp b
177 mvnhi r0, r0, asr #31 @
178 andhi r0, r0, #31 @
179 cmp lr, #31 @ clamp r
180 mvnhi lr, lr, asr #31 @
181 andhi lr, lr, #31 @
182 cmp r7, #63 @ clamp g
183 mvnhi r7, r7, asr #31 @
184 andhi r7, r7, #63 @
18515: @ no clamp @
186 @
187 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
188 @
189 @
190 orr r0, r0, lr, lsl #11 @ r0 = (r << 11) | b
191 orr r11, r0, r7, lsl #5 @ r0 = (r << 11) | (g << 5) | b
192
193#ifdef SANSA_FUZEV2
194 mov r0, r11, lsr #8 @
195 bic r11, r11, #0xff00 @
196 orr r11, r0, r11, lsl #8 @ swap byte
197#endif
198
199 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
200 add r12, r7, r7, asl #2 @
201 add r7, r12, r7, asl #5 @
202 @ compute R, G, and B
203 add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu
204 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
205 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
206 @
207 orr r12, r0, lr @ check if clamping is needed...
208 orr r12, r12, r7, asr #1 @ ...at all
209 cmp r12, #31 @
210 bls 15f @ no clamp @
211 cmp r0, #31 @ clamp b
212 mvnhi r0, r0, asr #31 @
213 andhi r0, r0, #31 @
214 cmp lr, #31 @ clamp r
215 mvnhi lr, lr, asr #31 @
216 andhi lr, lr, #31 @
217 cmp r7, #63 @ clamp g
218 mvnhi r7, r7, asr #31 @
219 andhi r7, r7, #63 @
22015: @ no clamp @
221 @
222 orr r0, r0, lr, lsl #11 @ r0 = (r << 11) | b
223 orr r0, r0, r7, lsl #5 @ r0 = (r << 11) | (g << 5) | b
224
225#ifdef SANSA_FUZEV2
226 mov r7, r0, lsr #8 @
227 bic r7, r7, #0xff00 @
228 orr r0, r7, r0, lsl #8 @ swap bytes
229#endif
230
231 orr r0, r11, r0, lsl#16 @ pack with 2nd pixel
232 str r0, [r3, #0x10] @ write pixel
233 @
234 subs r1, r1, #2 @ subtract block from width
235 bgt 10b @ loop line @
236 @
2371: @ busy
238 @ writing at max 110*32 (LCD_WIDTH/2), the fifo is bigger
239 @ so polling fifo empty only after each line is save
240 ldr r7, [r3,#0xc] @ r7 = DBOP_STATUS
241 tst r7, #DBOP_BUSY @ fifo not empty?
242 beq 1b @
243
244 ldmpc regs=r4-r11 @ restore registers and return
245 .ltorg @ dump constant pool
246 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
247
248/****************************************************************************
249 * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
250 * int width,
251 * int stride,
252 * int x_screen,
253 * int y_screen);
254 *
255 * |R| |1.000000 -0.000001 1.402000| |Y'|
256 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
257 * |B| |1.000000 1.772000 0.000000| |Pr|
258 * Red scaled at twice g & b but at same precision to place it in correct
259 * bit position after multiply and leave instruction count lower.
260 * |R| |258 0 408| |Y' - 16|
261 * |G| = |149 -49 -104| |Cb - 128|
262 * |B| |149 258 0| |Cr - 128|
263 *
264 * Write four RGB565 pixels in the following order on each loop:
265 * 1 3 + > down
266 * 2 4 \/ left
267 *
268 * Kernel pattern (raw|rotated|use order):
269 * 5 3 4 2 2 6 3 7 row0 row2 > down
270 * 1 7 0 6 | 4 0 5 1 | 2 4 6 0 3 5 7 1 col0 left
271 * 4 2 5 3 | 3 7 2 6 | 3 5 7 1 2 4 6 0 col2 \/
272 * 0 6 1 7 5 1 4 0
273 */
274 .section .icode, "ax", %progbits
275 .align 2
276 .global lcd_write_yuv420_lines_odither
277 .type lcd_write_yuv420_lines_odither, %function
278lcd_write_yuv420_lines_odither:
279 @ r0 = yuv_src
280 @ r1 = width
281 @ r2 = stride
282 @ r3 = x_screen
283 @ [sp] = y_screen
284 stmfd sp!, { r4-r11, lr } @ save non-scratch
285 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
286 @ r5 = yuv_src[1] = Cb_p
287 @ r6 = yuv_src[2] = Cr_p
288 @
289 ldr r14, [sp, #36] @ Line up pattern and kernel quadrant
290 sub r2, r2, #1 @ stride =- 1
291 eor r14, r14, r3 @
292 and r14, r14, #0x2 @
293 mov r14, r14, lsl #6 @ 0x00 or 0x80
294
295 mov r3, #0xC8000000 @
296 orr r3, r3, #0x120000 @ r3 = DBOP_BASE, need to be redone
297 @ due to lack of registers
298 ldr r12, [r3, #8] @
299 orr r12, r12, #3<<13 @ DBOP_CTRL |= (1<<13|1<<14)
300#ifdef SANSA_FUZEV2
301 bic r12, r12, #1<<13 @ DBOP_CTRL &= ~(1<<13), still 32bit mode
302#endif
303 str r12, [r3, #8] @ (32bit mode)
30410: @ loop line @
305 @
306 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
307 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
308 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
309 @
310 eor r14, r14, #0x80 @ flip pattern quadrant
311 @
312 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149
313 add r12, r7, r7, asl #2 @
314 add r12, r12, r12, asl #4 @
315 add r7, r12, r7, asl #6 @
316 @
317 sub r8, r8, #128 @ Cb -= 128
318 sub r9, r9, #128 @ Cr -= 128
319 @
320 add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49
321 add r10, r10, r8, asl #5 @
322 add r10, r10, r9, asl #3 @
323 add r10, r10, r9, asl #5 @
324 add r10, r10, r9, asl #6 @
325 @
326 mov r8, r8, asl #1 @ r8 = bu = Cb*258
327 add r8, r8, r8, asl #7 @
328 @
329 add r9, r9, r9, asl #1 @ r9 = rv = Cr*408
330 add r9, r9, r9, asl #4 @
331 mov r9, r9, asl #3 @
332 @
333 @ compute R, G, and B
334 add r0, r8, r7 @ r0 = b' = Y + bu
335 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
336 rsb r7, r10, r7 @ r7 = g' = Y + guv
337 @
338 @ r8 = bu, r9 = rv, r10 = guv
339 @
340 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256
341 add r0, r12, r0, lsr #8 @
342 @
343 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
344 add r11, r12, r11, lsr #8 @
345 @
346 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
347 add r7, r12, r7, lsr #8 @
348 @
349 add r12, r14, #0x100 @
350 @
351 add r0, r0, r12 @ b = r0 + delta
352 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
353 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
354 @
355 orr r12, r0, r11, asr #1 @ check if clamping is needed...
356 orr r12, r12, r7 @ ...at all
357 movs r12, r12, asr #15 @
358 beq 15f @ no clamp @
359 movs r12, r0, asr #15 @ clamp b
360 mvnne r0, r12, lsr #15 @
361 andne r0, r0, #0x7c00 @ mask b only if clamped
362 movs r12, r11, asr #16 @ clamp r
363 mvnne r11, r12, lsr #16 @
364 movs r12, r7, asr #15 @ clamp g
365 mvnne r7, r12, lsr #15 @
36615: @ no clamp @
367 @
368 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
369 @
370 and r11, r11, #0xf800 @ pack pixel
371 and r7, r7, #0x7e00 @ r0 = pixel = (r & 0xf800) |
372 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
373 orr r3, r11, r0, lsr #10 @ (b >> 10)
374#ifdef SANSA_FUZEV2
375 mov r7, r3, lsr #8 @
376 bic r3, r3, #0xff00 @
377 orr r3, r7, r3, lsl #8 @ swap pixel
378#endif
379 @ save pixel
380 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
381 add r12, r7, r7, asl #2 @
382 add r12, r12, r12, asl #4 @
383 add r7, r12, r7, asl #6 @
384 @ compute R, G, and B
385 add r0, r8, r7 @ r0 = b' = Y + bu
386 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
387 rsb r7, r10, r7 @ r7 = g' = Y + guv
388 @
389 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256
390 add r0, r12, r0, lsr #8 @
391 @
392 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
393 add r11, r12, r11, lsr #8 @
394 @
395 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
396 add r7, r12, r7, lsr #8 @
397 @
398 add r12, r14, #0x200 @
399 @
400 add r0, r0, r12 @ b = r0 + delta
401 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
402 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
403 @
404 orr r12, r0, r11, asr #1 @ check if clamping is needed...
405 orr r12, r12, r7 @ ...at all
406 movs r12, r12, asr #15 @
407 beq 15f @ no clamp @
408 movs r12, r0, asr #15 @ clamp b
409 mvnne r0, r12, lsr #15 @
410 andne r0, r0, #0x7c00 @ mask b only if clamped
411 movs r12, r11, asr #16 @ clamp r
412 mvnne r11, r12, lsr #16 @
413 movs r12, r7, asr #15 @ clamp g
414 mvnne r7, r12, lsr #15 @
41515: @ no clamp @
416 @
417 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
418
419 and r11, r11, #0xf800 @ pack pixel
420 and r7, r7, #0x7e00 @ r0 = pixel = (r & 0xf800) |
421 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
422 orr r0, r11, r0, lsr #10 @ (b >> 10)
423#ifdef SANSA_FUZEV2
424 mov r7, r0, lsr #8 @
425 bic r0, r0, #0xff00 @
426 orr r0, r7, r0, lsl #8 @ swap pixel
427#endif
428 orr r3, r3, r0, lsl#16 @ pack with 2nd pixel
429 mov r0, #0xC8000000 @
430 orr r0, r0, #0x120000 @ r3 = DBOP_BASE
431
432 str r3, [r0, #0x10] @ write pixel
433 @
434 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
435 add r12, r7, r7, asl #2 @
436 add r12, r12, r12, asl #4 @
437 add r7, r12, r7, asl #6 @
438 @ compute R, G, and B
439 add r0, r8, r7 @ r0 = b' = Y + bu
440 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
441 rsb r7, r10, r7 @ r7 = g' = Y + guv
442 @
443 @ r8 = bu, r9 = rv, r10 = guv
444 @
445 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256
446 add r0, r12, r0, lsr #8 @
447 @
448 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
449 add r11, r12, r11, lsr #8 @
450 @
451 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
452 add r7, r12, r7, lsr #8 @
453 @
454 add r12, r14, #0x300 @
455 @
456 add r0, r0, r12 @ b = r0 + delta
457 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
458 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
459 @
460 orr r12, r0, r11, asr #1 @ check if clamping is needed...
461 orr r12, r12, r7 @ ...at all
462 movs r12, r12, asr #15 @
463 beq 15f @ no clamp @
464 movs r12, r0, asr #15 @ clamp b
465 mvnne r0, r12, lsr #15 @
466 andne r0, r0, #0x7c00 @ mask b only if clamped
467 movs r12, r11, asr #16 @ clamp r
468 mvnne r11, r12, lsr #16 @
469 movs r12, r7, asr #15 @ clamp g
470 mvnne r7, r12, lsr #15 @
47115: @ no clamp @
472 @
473 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
474 @
475 and r11, r11, #0xf800 @ pack pixel
476 and r7, r7, #0x7e00 @ r0 = pixel = (r & 0xf800) |
477 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
478 orr r3, r11, r0, lsr #10 @ (b >> 10)
479#ifdef SANSA_FUZEV2
480 mov r7, r3, lsr #8 @
481 bic r3, r3, #0xff00 @
482 orr r3, r7, r3, lsl #8 @ swap pixel
483#endif
484 @ save pixel
485 @
486 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
487 add r12, r7, r7, asl #2 @
488 add r12, r12, r12, asl #4 @
489 add r7, r12, r7, asl #6 @
490 @ compute R, G, and B
491 add r0, r8, r7 @ r0 = b' = Y + bu
492 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
493 rsb r7, r10, r7 @ r7 = g' = Y + guv
494 @
495 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256
496 add r0, r12, r0, lsr #8 @
497 @
498 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
499 add r11, r12, r11, lsr #8 @
500 @
501 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
502 add r7, r12, r7, lsr #8 @
503 @
504 @ This element is zero - use r14 @
505 @
506 add r0, r0, r14 @ b = r0 + delta
507 add r11, r11, r14, lsl #1 @ r = r11 + delta*2
508 add r7, r7, r14, lsr #1 @ g = r7 + delta/2
509 @
510 orr r12, r0, r11, asr #1 @ check if clamping is needed...
511 orr r12, r12, r7 @ ...at all
512 movs r12, r12, asr #15 @
513 beq 15f @ no clamp @
514 movs r12, r0, asr #15 @ clamp b
515 mvnne r0, r12, lsr #15 @
516 andne r0, r0, #0x7c00 @ mask b only if clamped
517 movs r12, r11, asr #16 @ clamp r
518 mvnne r11, r12, lsr #16 @
519 movs r12, r7, asr #15 @ clamp g
520 mvnne r7, r12, lsr #15 @
52115: @ no clamp @
522 @
523 and r11, r11, #0xf800 @ pack pixel
524 and r7, r7, #0x7e00 @ r0 = pixel = (r & 0xf800) |
525 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
526 orr r0, r11, r0, lsr #10 @ (b >> 10)
527#ifdef SANSA_FUZEV2
528 mov r7, r0, lsr #8 @
529 bic r0, r0, #0xff00 @
530 orr r0, r7, r0, lsl #8 @ swap pixel
531#endif
532 orr r3, r3, r0, lsl#16 @ pack with 2nd pixel
533 mov r0, #0xC8000000 @
534 orr r0, r0, #0x120000 @ r3 = DBOP_BASE
535
536 str r3, [r0, #0x10] @ write pixel
537 @
538 subs r1, r1, #2 @ subtract block from width
539 bgt 10b @ loop line @
540 @
5411: @ busy @
542 @ writing at max 110*32 (LCD_WIDTH/2), the fifo is bigger (128*32)
543 @ so polling fifo empty only after each line is save
544 ldr r7, [r0,#0xc] @ r7 = DBOP_STATUS
545 tst r7, #DBOP_BUSY @ fifo not empty?
546 beq 1b @
547
548 ldmpc regs=r4-r11 @ restore registers and return
549 .ltorg @ dump constant pool
550 .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither
diff --git a/firmware/target/arm/as3525/lcd-fuze.c b/firmware/target/arm/as3525/lcd-fuze.c
index b1f62a1c95..a1ccea348d 100644
--- a/firmware/target/arm/as3525/lcd-fuze.c
+++ b/firmware/target/arm/as3525/lcd-fuze.c
@@ -197,6 +197,86 @@ static void lcd_window_y(int ymin, int ymax)
197 lcd_write_reg(R_RAM_ADDR_SET, ymin); 197 lcd_write_reg(R_RAM_ADDR_SET, ymin);
198} 198}
199 199
200static unsigned lcd_yuv_options = 0;
201
202void lcd_yuv_set_options(unsigned options)
203{
204 lcd_yuv_options = options;
205}
206
207
208#ifndef BOOTLOADER
209/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
210extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
211 int width,
212 int stride);
213extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
214 int width,
215 int stride,
216 int x_screen, /* To align dither pattern */
217 int y_screen);
218
219/* Performance function to blit a YUV bitmap directly to the LCD
220 * src_x, src_y, width and height should be even
221 * x, y, width and height have to be within LCD bounds
222 */
223void lcd_blit_yuv(unsigned char * const src[3],
224 int src_x, int src_y, int stride,
225 int x, int y, int width, int height)
226{
227 unsigned char const * yuv_src[3];
228 off_t z;
229
230 /* Sorry, but width and height must be >= 2 or else */
231 width &= ~1;
232 height >>= 1;
233
234 z = stride*src_y;
235 yuv_src[0] = src[0] + z + src_x;
236 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
237 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
238
239 lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_VIDEO);
240
241 lcd_window_x(x, x + width - 1);
242
243 if (lcd_yuv_options & LCD_YUV_DITHER)
244 {
245 do
246 {
247 lcd_window_y(y, y + 1);
248
249 lcd_write_cmd(R_WRITE_DATA_2_GRAM);
250
251 lcd_write_yuv420_lines_odither(yuv_src, width, stride, x, y);
252 yuv_src[0] += stride << 1; /* Skip down two luma lines */
253 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
254 yuv_src[2] += stride >> 1;
255 y += 2;
256 }
257 while (--height > 0);
258 }
259 else
260 {
261 do
262 {
263 lcd_window_y(y, y + 1);
264
265 lcd_write_cmd(R_WRITE_DATA_2_GRAM);
266
267 lcd_write_yuv420_lines(yuv_src, width, stride);
268 yuv_src[0] += stride << 1; /* Skip down two luma lines */
269 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
270 yuv_src[2] += stride >> 1;
271 y += 2;
272 }
273 while (--height > 0);
274 }
275}
276
277#endif
278
279
200/* Update the display. 280/* Update the display.
201 This must be called after all other LCD functions that change the display. */ 281 This must be called after all other LCD functions that change the display. */
202void lcd_update(void) 282void lcd_update(void)
diff --git a/firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c b/firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c
index 141340c003..f69ad48793 100644
--- a/firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c
+++ b/firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c
@@ -336,6 +336,104 @@ bool lcd_active(void)
336 336
337/*** update functions ***/ 337/*** update functions ***/
338 338
339static unsigned lcd_yuv_options = 0;
340
341void lcd_yuv_set_options(unsigned options)
342{
343 lcd_yuv_options = options;
344}
345
346
347#ifndef BOOTLOADER
348static void lcd_window_blit(int xmin, int ymin, int xmax, int ymax)
349{
350 if (!display_flipped)
351 {
352 lcd_write_reg(R_HORIZ_RAM_ADDR_POS,
353 ((LCD_WIDTH-1 - xmin) << 8) | (LCD_WIDTH-1 - xmax));
354 lcd_write_reg(R_VERT_RAM_ADDR_POS, (ymax << 8) | ymin);
355 lcd_write_reg(R_RAM_ADDR_SET,
356 (ymin << 8) | (LCD_WIDTH-1 - xmin));
357 }
358 else
359 {
360 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (xmax << 8) | xmin);
361 lcd_write_reg(R_VERT_RAM_ADDR_POS, (ymax << 8) | ymin);
362 lcd_write_reg(R_RAM_ADDR_SET, (ymax << 8) | xmin);
363 }
364}
365
366/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
367extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
368 int width,
369 int stride);
370extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
371 int width,
372 int stride,
373 int x_screen, /* To align dither pattern */
374 int y_screen);
375
376/* Performance function to blit a YUV bitmap directly to the LCD
377 * src_x, src_y, width and height should be even
378 * x, y, width and height have to be within LCD bounds
379 */
380void lcd_blit_yuv(unsigned char * const src[3],
381 int src_x, int src_y, int stride,
382 int x, int y, int width, int height)
383{
384 unsigned char const * yuv_src[3];
385 off_t z;
386
387 /* Sorry, but width and height must be >= 2 or else */
388 width &= ~1;
389 height >>= 1;
390
391 z = stride*src_y;
392 yuv_src[0] = src[0] + z + src_x;
393 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
394 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
395
396 lcd_write_reg(R_ENTRY_MODE,
397 display_flipped ? R_ENTRY_MODE_VIDEO_FLIPPED : R_ENTRY_MODE_VIDEO_NORMAL
398 );
399
400 if (lcd_yuv_options & LCD_YUV_DITHER)
401 {
402 do
403 {
404 lcd_window_blit(y, x, y+1, x+width-1);
405
406 lcd_write_cmd(R_WRITE_DATA_2_GRAM);
407
408 lcd_write_yuv420_lines_odither(yuv_src, width, stride, x, y);
409 yuv_src[0] += stride << 1; /* Skip down two luma lines */
410 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
411 yuv_src[2] += stride >> 1;
412 y += 2;
413 }
414 while (--height > 0);
415 }
416 else
417 {
418 do
419 {
420 lcd_window_blit(y, x, y+1, x+width-1);
421
422 lcd_write_cmd(R_WRITE_DATA_2_GRAM);
423
424 lcd_write_yuv420_lines(yuv_src, width, stride);
425 yuv_src[0] += stride << 1; /* Skip down two luma lines */
426 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
427 yuv_src[2] += stride >> 1;
428 y += 2;
429 }
430 while (--height > 0);
431 }
432}
433
434#endif
435
436
339/* Update the display. 437/* Update the display.
340 This must be called after all other LCD functions that change the display. */ 438 This must be called after all other LCD functions that change the display. */
341void lcd_update(void) 439void lcd_update(void)
diff --git a/firmware/target/arm/ipod/lcd-as-color-nano.S b/firmware/target/arm/ipod/lcd-as-color-nano.S
new file mode 100644
index 0000000000..f6f9cc5be3
--- /dev/null
+++ b/firmware/target/arm/ipod/lcd-as-color-nano.S
@@ -0,0 +1,287 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id:$
9 *
10 * Copyright (C) 2010-2011 by Andree Buschmann
11 *
12 * Generic asm helper function used by YUV blitting.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#include "config.h"
25#include "cpu.h"
26
27/****************************************************************************
28 * #define FORCE_FIFO_WAIT
29 *
30 * This is not needed in YUV blitting when the LCD IF is fast enough. In this
31 * case YUV-to-RGB conversion per pixel needs longer than the transfer of a
32 * pixel via the LCD IF.
33 ****************************************************************************/
34
35#include "config.h"
36
37/* Set FIFO wait for both iPod Color and iPod nano1G until we know for which
38 * devices we can switch this off. */
39#define FORCE_FIFO_WAIT
40
41 .section .icode, "ax", %progbits
42
43/****************************************************************************
44 * extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
45 * const unsigned LCD_BASE,
46 * int width,
47 * int stride);
48 *
49 * Conversion from Motion JPEG and MPEG Y'PbPr to RGB is:
50 * |R| |1.164 0.000 1.596| |Y' - 16|
51 * |G| = |1.164 -0.391 -0.813| |Pb - 128|
52 * |B| |1.164 2.018 0.000| |Pr - 128|
53 *
54 * Scaled, normalized, rounded and tweaked to yield RGB 565:
55 * |R| |74 0 101| |Y' - 16| >> 9
56 * |G| = |74 -24 -51| |Cb - 128| >> 8
57 * |B| |74 128 0| |Cr - 128| >> 9
58 *
59 * Converts two lines from YUV to RGB565 and writes to LCD at once. First loop
60 * loads Cb/Cr, calculates the chroma offset and saves them to buffer. Within
61 * the second loop these chroma offset are reloaded from buffer. Within each
62 * loop two pixels are calculated and written to LCD.
63 */
64 .align 2
65 .global lcd_write_yuv420_lines
66 .type lcd_write_yuv420_lines, %function
67lcd_write_yuv420_lines:
68 /* r0 = src = yuv_src */
69 /* r1 = dst = LCD_BASE */
70 /* r2 = width */
71 /* r3 = stride */
72 stmfd sp!, { r4-r10, lr } /* save non-scratch */
73 ldmia r0, { r9, r10, r12 } /* r9 = yuv_src[0] = Y'_p */
74 /* r10 = yuv_src[1] = Cb_p */
75 /* r12 = yuv_src[2] = Cr_p */
76 add r3, r9, r3 /* r3 = &ysrc[stride] */
77 add r4, r2, r2, asr #1 /* chroma buffer lenght = width/2 *3 */
78 mov r4, r4, asl #2 /* use words for str/ldm possibility */
79 add r4, r4, #19 /* plus room for 4 additional words, */
80 bic r4, r4, #3 /* rounded up to multiples of 4 byte */
81 sub sp, sp, r4 /* and allocate on stack */
82 stmia sp, {r1-r4} /* LCD_BASE, width, &ysrc[stride], stack_alloc */
83
84 mov r7, r2 /* r7 = loop count */
85 add r8, sp, #16 /* chroma buffer */
86 add lr, r1, #0x100 /* LCD data port = LCD2_BASE + 0x100 */
87
88 /* 1st loop start */
8910: /* loop start */
90
91 ldrb r0, [r10], #1 /* r0 = *usrc++ = *Cb_p++ */
92 ldrb r1, [r12], #1 /* r1 = *vsrc++ = *Cr_p++ */
93
94 sub r0, r0, #128 /* r0 = Cb-128 */
95 sub r1, r1, #128 /* r1 = Cr-128 */
96
97 add r2, r1, r1, asl #1 /* r2 = Cr*51 + Cb*24 */
98 add r2, r2, r2, asl #4
99 add r2, r2, r0, asl #3
100 add r2, r2, r0, asl #4
101
102 add r4, r1, r1, asl #2 /* r1 = Cr*101 */
103 add r4, r4, r1, asl #5
104 add r1, r4, r1, asl #6
105
106 add r1, r1, #256 /* r1 = rv = (r1 + 256) >> 9 */
107 mov r1, r1, asr #9
108 rsb r2, r2, #128 /* r2 = guv = (-r2 + 128) >> 8 */
109 mov r2, r2, asr #8
110 add r0, r0, #2 /* r0 = bu = (Cb*128 + 256) >> 9 */
111 mov r0, r0, asr #2
112 stmia r8!, {r0-r2} /* store r0, r1 and r2 to chroma buffer */
113
114 /* 1st loop, first pixel */
115 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
116 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
117 add r3, r5, r5, asl #2
118 add r5, r3, r5, asl #5
119
120 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
121 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
122 add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */
123
124 orr r5, r6, r4 /* check if clamping is needed... */
125 orr r5, r5, r3, asr #1 /* ...at all */
126 cmp r5, #31
127 bls 15f /* -> no clamp */
128 cmp r6, #31 /* clamp r */
129 mvnhi r6, r6, asr #31
130 andhi r6, r6, #31
131 cmp r3, #63 /* clamp g */
132 mvnhi r3, r3, asr #31
133 andhi r3, r3, #63
134 cmp r4, #31 /* clamp b */
135 mvnhi r4, r4, asr #31
136 andhi r4, r4, #31
13715: /* no clamp */
138
139 /* calculate pixel_1 and save to r4 for later pixel packing */
140 orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */
141 orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */
142
143 /* 1st loop, second pixel */
144 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
145 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
146 add r3, r5, r5, asl #2
147 add r5, r3, r5, asl #5
148
149 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
150 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
151 add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */
152
153 orr r0, r6, r5 /* check if clamping is needed... */
154 orr r0, r0, r3, asr #1 /* ...at all */
155 cmp r0, #31
156 bls 15f /* -> no clamp */
157 cmp r6, #31 /* clamp r */
158 mvnhi r6, r6, asr #31
159 andhi r6, r6, #31
160 cmp r3, #63 /* clamp g */
161 mvnhi r3, r3, asr #31
162 andhi r3, r3, #63
163 cmp r5, #31 /* clamp b */
164 mvnhi r5, r5, asr #31
165 andhi r5, r5, #31
16615: /* no clamp */
167
168 /* calculate pixel_2 and pack with pixel_1 before writing */
169 orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */
170 orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */
171#ifdef FORCE_FIFO_WAIT
172 /* wait for FIFO half full */
173.fifo_wait1:
174 ldr r3, [lr, #-0xE0] /* while !(LCD2_BLOCK_CTRL & 0x1000000); */
175 tst r3, #0x1000000
176 beq .fifo_wait1
177#endif
178
179 mov r3, r4, lsl #8 /* swap pixel_1 */
180 and r3, r3, #0xff00
181 add r4, r3, r4, lsr #8
182
183 orr r4, r4, r5, lsl #24 /* swap pixel_2 and pack with pixel_1 */
184 mov r5, r5, lsr #8
185 orr r4, r4, r5, lsl #16
186
187 str r4, [lr] /* write pixel_1 and pixel_2 */
188
189 subs r7, r7, #2 /* check for loop end */
190 bgt 10b /* back to beginning */
191 /* 1st loop end */
192
193 /* Reload several registers for pointer rewinding for next loop */
194 add r8, sp, #16 /* chroma buffer */
195 ldmia sp, { r1, r7, r9} /* r1 = LCD_BASE */
196 /* r7 = loop count */
197 /* r9 = &ysrc[stride] */
198
199 /* 2nd loop start */
20020: /* loop start */
201 /* restore r0 (bu), r1 (rv) and r2 (guv) from chroma buffer */
202 ldmia r8!, {r0-r2}
203
204 /* 2nd loop, first pixel */
205 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
206 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
207 add r3, r5, r5, asl #2
208 add r5, r3, r5, asl #5
209
210 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
211 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
212 add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */
213
214 orr r5, r6, r4 /* check if clamping is needed... */
215 orr r5, r5, r3, asr #1 /* ...at all */
216 cmp r5, #31
217 bls 15f /* -> no clamp */
218 cmp r6, #31 /* clamp r */
219 mvnhi r6, r6, asr #31
220 andhi r6, r6, #31
221 cmp r3, #63 /* clamp g */
222 mvnhi r3, r3, asr #31
223 andhi r3, r3, #63
224 cmp r4, #31 /* clamp b */
225 mvnhi r4, r4, asr #31
226 andhi r4, r4, #31
22715: /* no clamp */
228 /* calculate pixel_1 and save to r4 for later pixel packing */
229 orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */
230 orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */
231
232 /* 2nd loop, second pixel */
233 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
234 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
235 add r3, r5, r5, asl #2
236 add r5, r3, r5, asl #5
237
238 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
239 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
240 add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */
241
242 orr r0, r6, r5 /* check if clamping is needed... */
243 orr r0, r0, r3, asr #1 /* ...at all */
244 cmp r0, #31
245 bls 15f /* -> no clamp */
246 cmp r6, #31 /* clamp r */
247 mvnhi r6, r6, asr #31
248 andhi r6, r6, #31
249 cmp r3, #63 /* clamp g */
250 mvnhi r3, r3, asr #31
251 andhi r3, r3, #63
252 cmp r5, #31 /* clamp b */
253 mvnhi r5, r5, asr #31
254 andhi r5, r5, #31
25515: /* no clamp */
256
257 /* calculate pixel_2 and pack with pixel_1 before writing */
258 orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */
259 orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */
260#ifdef FORCE_FIFO_WAIT
261 /* wait for FIFO half full */
262.fifo_wait2:
263 ldr r3, [lr, #-0xE0] /* while !(LCD2_BLOCK_CTRL & 0x1000000); */
264 tst r3, #0x1000000
265 beq .fifo_wait2
266#endif
267
268 mov r3, r4, lsl #8 /* swap pixel_1 */
269 and r3, r3, #0xff00
270 add r4, r3, r4, lsr #8
271
272 orr r4, r4, r5, lsl #24 /* swap pixel_2 and pack with pixel_1 */
273 mov r5, r5, lsr #8
274 orr r4, r4, r5, lsl #16
275
276 str r4, [lr] /* write pixel_1 and pixel_2 */
277
278 subs r7, r7, #2 /* check for loop end */
279 bgt 20b /* back to beginning */
280 /* 2nd loop end */
281
282 ldr r3, [sp, #12]
283 add sp, sp, r3 /* deallocate buffer */
284 ldmpc regs=r4-r10 /* restore registers */
285
286 .ltorg
287 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
diff --git a/firmware/target/arm/ipod/lcd-color_nano.c b/firmware/target/arm/ipod/lcd-color_nano.c
index 71ae22cb23..67d26aa862 100644
--- a/firmware/target/arm/ipod/lcd-color_nano.c
+++ b/firmware/target/arm/ipod/lcd-color_nano.c
@@ -202,6 +202,62 @@ static void lcd_setup_drawing_region(int x, int y, int width, int height)
202 } 202 }
203} 203}
204 204
205/* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */
206extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
207 const unsigned int lcd_baseadress,
208 int width,
209 int stride);
210
211/* Performance function to blit a YUV bitmap directly to the LCD */
212void lcd_blit_yuv(unsigned char * const src[3],
213 int src_x, int src_y, int stride,
214 int x, int y, int width, int height)
215{
216 int z;
217 unsigned char const * yuv_src[3];
218
219 width = (width + 1) & ~1; /* ensure width is even */
220 height = (height + 1) & ~1; /* ensure height is even */
221
222 lcd_setup_drawing_region(x, y, width, height);
223
224 z = stride * src_y;
225 yuv_src[0] = src[0] + z + src_x;
226 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
227 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
228
229 while (height > 0) {
230 int r, h, pixels_to_write;
231
232 pixels_to_write = (width * height) * 2;
233 h = height;
234
235 /* calculate how much we can do in one go */
236 if (pixels_to_write > 0x10000) {
237 h = ((0x10000/2) / width) & ~1; /* ensure h is even */
238 pixels_to_write = (width * h) * 2;
239 }
240
241 LCD2_BLOCK_CTRL = 0x10000080;
242 LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1);
243 LCD2_BLOCK_CTRL = 0x34000000;
244
245 r = h>>1; /* lcd_write_yuv420_lines writes two lines at once */
246 do {
247 lcd_write_yuv420_lines(yuv_src, LCD2_BASE, width, stride);
248 yuv_src[0] += stride << 1;
249 yuv_src[1] += stride >> 1;
250 yuv_src[2] += stride >> 1;
251 } while (--r > 0);
252
253 /* transfer of pixels_to_write bytes finished */
254 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
255 LCD2_BLOCK_CONFIG = 0;
256
257 height -= h;
258 }
259}
260
205/* Helper function writes 'count' consecutive pixels from src to LCD IF */ 261/* Helper function writes 'count' consecutive pixels from src to LCD IF */
206static void lcd_write_line(int count, unsigned long *src) 262static void lcd_write_line(int count, unsigned long *src)
207{ 263{
diff --git a/firmware/target/arm/ipod/video/lcd-as-video.S b/firmware/target/arm/ipod/video/lcd-as-video.S
index 1b982c75ce..47155b8c75 100644
--- a/firmware/target/arm/ipod/video/lcd-as-video.S
+++ b/firmware/target/arm/ipod/video/lcd-as-video.S
@@ -63,3 +63,240 @@ lcd_write_data: /* r1 = pixel count, must be even */
63 strne r3, [lr] 63 strne r3, [lr]
64 64
65 ldmpc regs=r4 65 ldmpc regs=r4
66
67/****************************************************************************
68 * extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
69 * unsigned bcmaddr
70 * int width,
71 * int stride);
72 *
73 * Conversion from Motion JPEG and MPEG Y'PbPr to RGB is:
74 * |R| |1.164 0.000 1.596| |Y' - 16|
75 * |G| = |1.164 -0.391 -0.813| |Pb - 128|
76 * |B| |1.164 2.018 0.000| |Pr - 128|
77 *
78 * Scaled, normalized, rounded and tweaked to yield RGB 565:
79 * |R| |74 0 101| |Y' - 16| >> 9
80 * |G| = |74 -24 -51| |Cb - 128| >> 8
81 * |B| |74 128 0| |Cr - 128| >> 9
82 *
83 * Converts two lines from YUV to RGB565 and writes to BCM at once. First loop
84 * loads Cb/Cr, calculates the chroma offset and saves them to buffer. Within
85 * the second loop these chroma offset are reloaded from buffer.
86 * Within each loop two pixels are calculated and written to BCM. Before each
87 * loop the desired destination address is transmitted to BCM.
88 */
89 .align 2
90 .global lcd_write_yuv420_lines
91 .type lcd_write_yuv420_lines, %function
92lcd_write_yuv420_lines:
93 /* r0 = src = yuv_src */
94 /* r1 = dst = bcmaddr */
95 /* r2 = width */
96 /* r3 = stride */
97 stmfd sp!, { r4-r10, lr } /* save non-scratch */
98 ldmia r0, { r9, r10, r12 } /* r9 = yuv_src[0] = Y'_p */
99 /* r10 = yuv_src[1] = Cb_p */
100 /* r12 = yuv_src[2] = Cr_p */
101 add r3, r9, r3 /* r3 = &ysrc[stride] */
102 add r4, r2, r2, asr #1 /* chroma buffer lenght = width/2 *3 */
103 mov r4, r4, asl #2 /* use words for str/ldm possibility */
104 add r4, r4, #19 /* plus room for 4 additional words, */
105 bic r4, r4, #3 /* rounded up to multiples of 4 byte */
106 sub sp, sp, r4 /* and allocate on stack */
107 stmia sp, {r1-r4} /* bcmaddr, width, &ysrc[stride], stack_alloc */
108
109 mov r7, r2 /* r7 = loop count */
110 add r8, sp, #16 /* chroma buffer */
111 mov lr, #0x30000000 /* LCD data port */
112
113 /* The following writes dest address to BCM and waits for write ready */
114 orr r2, lr, #0x00010000 /* r2 = BCM_WR_ADDR32 */
115 orr r6, lr, #0x00030000 /* r6 = BCM_CONTROL */
116 str r1, [r2] /* BCM_WR_ADDR32 = bcmaddr */
117.busy_1:
118 ldrh r1, [r6] /* while (!(BCM_CONTROL & 0x2)) */
119 tst r1, #0x2
120 beq .busy_1
121
122 /* 1st loop start */
12310: /* loop start */
124
125 ldrb r0, [r10], #1 /* r0 = *usrc++ = *Cb_p++ */
126 ldrb r1, [r12], #1 /* r1 = *vsrc++ = *Cr_p++ */
127
128 sub r0, r0, #128 /* r0 = Cb-128 */
129 sub r1, r1, #128 /* r1 = Cr-128 */
130
131 add r2, r1, r1, asl #1 /* r2 = Cr*51 + Cb*24 */
132 add r2, r2, r2, asl #4
133 add r2, r2, r0, asl #3
134 add r2, r2, r0, asl #4
135
136 add r4, r1, r1, asl #2 /* r1 = Cr*101 */
137 add r4, r4, r1, asl #5
138 add r1, r4, r1, asl #6
139
140 add r1, r1, #256 /* r1 = rv = (r1 + 256) >> 9 */
141 mov r1, r1, asr #9
142 rsb r2, r2, #128 /* r2 = guv = (-r2 + 128) >> 8 */
143 mov r2, r2, asr #8
144 add r0, r0, #2 /* r0 = bu = (Cb*128 + 256) >> 9 */
145 mov r0, r0, asr #2
146 stmia r8!, {r0-r2} /* store r0, r1 and r2 to chroma buffer */
147
148 /* 1st loop, first pixel */
149 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
150 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
151 add r3, r5, r5, asl #2
152 add r5, r3, r5, asl #5
153
154 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
155 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
156 add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */
157
158 orr r5, r6, r4 /* check if clamping is needed... */
159 orr r5, r5, r3, asr #1 /* ...at all */
160 cmp r5, #31
161 bls 15f /* -> no clamp */
162 cmp r6, #31 /* clamp r */
163 mvnhi r6, r6, asr #31
164 andhi r6, r6, #31
165 cmp r3, #63 /* clamp g */
166 mvnhi r3, r3, asr #31
167 andhi r3, r3, #63
168 cmp r4, #31 /* clamp b */
169 mvnhi r4, r4, asr #31
170 andhi r4, r4, #31
17115: /* no clamp */
172
173 /* calculate pixel_1 and save to r5 for later pixel packing */
174 orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */
175 orr r5, r4, r6, lsl #11 /* r5 = pixel_1 */
176
177 /* 1st loop, second pixel */
178 ldrb r4, [r9], #1 /* r4 = *ysrc++ = *Y'_p++ */
179 sub r4, r4, #16 /* r4 = (Y'-16) * 74 */
180 add r3, r4, r4, asl #2
181 add r4, r3, r4, asl #5
182
183 add r6, r1, r4, asr #8 /* r6 = r = (Y >> 9) + rv */
184 add r3, r2, r4, asr #7 /* r3 = g = (Y >> 8) + guv */
185 add r4, r0, r4, asr #8 /* r4 = b = (Y >> 9) + bu */
186
187 orr r0, r6, r4 /* check if clamping is needed... */
188 orr r0, r0, r3, asr #1 /* ...at all */
189 cmp r0, #31
190 bls 15f /* -> no clamp */
191 cmp r6, #31 /* clamp r */
192 mvnhi r6, r6, asr #31
193 andhi r6, r6, #31
194 cmp r3, #63 /* clamp g */
195 mvnhi r3, r3, asr #31
196 andhi r3, r3, #63
197 cmp r4, #31 /* clamp b */
198 mvnhi r4, r4, asr #31
199 andhi r4, r4, #31
20015: /* no clamp */
201
202 /* calculate pixel_2 and pack with pixel_1 before writing */
203 orr r4, r4, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */
204 orr r4, r4, r6, lsl #11 /* r4 = pixel_2 */
205 orr r4, r5, r4, lsl #16 /* r4 = pixel_2<<16 | pixel_1 */
206 str r4, [lr] /* write packed pixels */
207
208 subs r7, r7, #2 /* check for loop end */
209 bgt 10b /* back to beginning */
210 /* 1st loop end */
211
212 /* Reload several registers for pointer rewinding for next loop */
213 add r8, sp, #16 /* chroma buffer */
214 ldmia sp, { r1, r7, r9} /* r1 = bcmaddr */
215 /* r7 = loop count */
216 /* r9 = &ysrc[stride] */
217
218 /* The following writes dest address to BCM and waits for write ready */
219 orr r2, lr, #0x00010000 /* r2 = BCM_WR_ADDR32 */
220 orr r6, lr, #0x00030000 /* r6 = BCM_CONTROL */
221 add r1, r1, #640 /* dst += (LCD_WIDTH*2) */
222 str r1, [r2] /* BCM_WR_ADDR32 = dst */
223.busy_2:
224 ldrh r1, [r6] /* while (!(BCM_CONTROL & 0x2)) */
225 tst r1, #0x2
226 beq .busy_2
227
228
229 /* 2nd loop start */
23020: /* loop start */
231 /* restore r0 (bu), r1 (rv) and r2 (guv) from chroma buffer */
232 ldmia r8!, {r0-r2}
233
234 /* 2nd loop, first pixel */
235 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
236 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
237 add r3, r5, r5, asl #2
238 add r5, r3, r5, asl #5
239
240 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
241 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
242 add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */
243
244 orr r5, r6, r4 /* check if clamping is needed... */
245 orr r5, r5, r3, asr #1 /* ...at all */
246 cmp r5, #31
247 bls 15f /* -> no clamp */
248 cmp r6, #31 /* clamp r */
249 mvnhi r6, r6, asr #31
250 andhi r6, r6, #31
251 cmp r3, #63 /* clamp g */
252 mvnhi r3, r3, asr #31
253 andhi r3, r3, #63
254 cmp r4, #31 /* clamp b */
255 mvnhi r4, r4, asr #31
256 andhi r4, r4, #31
25715: /* no clamp */
258 /* calculate pixel_1 and save to r5 for later pixel packing */
259 orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */
260 orr r5, r4, r6, lsl #11 /* r5 = pixel_1 */
261
262 /* 2nd loop, second pixel */
263 ldrb r4, [r9], #1 /* r4 = *ysrc++ = *Y'_p++ */
264 sub r4, r4, #16 /* r4 = (Y'-16) * 74 */
265 add r3, r4, r4, asl #2
266 add r4, r3, r4, asl #5
267
268 add r6, r1, r4, asr #8 /* r6 = r = (Y >> 9) + rv */
269 add r3, r2, r4, asr #7 /* r3 = g = (Y >> 8) + guv */
270 add r4, r0, r4, asr #8 /* r4 = b = (Y >> 9) + bu */
271
272 orr r0, r6, r4 /* check if clamping is needed... */
273 orr r0, r0, r3, asr #1 /* ...at all */
274 cmp r0, #31
275 bls 15f /* -> no clamp */
276 cmp r6, #31 /* clamp r */
277 mvnhi r6, r6, asr #31
278 andhi r6, r6, #31
279 cmp r3, #63 /* clamp g */
280 mvnhi r3, r3, asr #31
281 andhi r3, r3, #63
282 cmp r4, #31 /* clamp b */
283 mvnhi r4, r4, asr #31
284 andhi r4, r4, #31
28515: /* no clamp */
286
287 /* calculate pixel_2 and pack with pixel_1 before writing */
288 orr r4, r4, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */
289 orr r4, r4, r6, lsl #11 /* r4 = pixel_2 */
290 orr r4, r5, r4, lsl #16 /* r4 = pixel_2<<16 | pixel_1 */
291 str r4, [lr] /* write packed pixels */
292
293 subs r7, r7, #2 /* check for loop end */
294 bgt 20b /* back to beginning */
295 /* 2nd loop end */
296
297 ldr r3, [sp, #12]
298 add sp, sp, r3 /* deallocate buffer */
299 ldmpc regs=r4-r10 /* restore registers */
300
301 .ltorg
302 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
diff --git a/firmware/target/arm/ipod/video/lcd-video.c b/firmware/target/arm/ipod/video/lcd-video.c
index 494bec8429..27d889aafa 100644
--- a/firmware/target/arm/ipod/video/lcd-video.c
+++ b/firmware/target/arm/ipod/video/lcd-video.c
@@ -439,6 +439,53 @@ void lcd_update(void)
439 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); 439 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
440} 440}
441 441
442/* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */
443extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
444 unsigned bcmaddr,
445 int width,
446 int stride);
447
448/* Performance function to blit a YUV bitmap directly to the LCD */
449void lcd_blit_yuv(unsigned char * const src[3],
450 int src_x, int src_y, int stride,
451 int x, int y, int width, int height)
452{
453 unsigned bcmaddr;
454 off_t z;
455 unsigned char const * yuv_src[3];
456
457#ifdef HAVE_LCD_SLEEP
458 if (!lcd_state.display_on)
459 return;
460#endif
461
462 /* Sorry, but width and height must be >= 2 or else */
463 width &= ~1;
464
465 z = stride * src_y;
466 yuv_src[0] = src[0] + z + src_x;
467 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
468 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
469
470 /* Prevent the tick from triggering BCM updates while we're writing. */
471 lcd_block_tick();
472
473 bcmaddr = BCMA_CMDPARAM + (LCD_WIDTH*2) * y + (x << 1);
474 height >>= 1;
475
476 do
477 {
478 lcd_write_yuv420_lines(yuv_src, bcmaddr, width, stride);
479 bcmaddr += (LCD_WIDTH*4); /* Skip up two lines */
480 yuv_src[0] += stride << 1;
481 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
482 yuv_src[2] += stride >> 1;
483 }
484 while (--height > 0);
485
486 lcd_unblock_and_update();
487}
488
442#ifdef HAVE_LCD_SLEEP 489#ifdef HAVE_LCD_SLEEP
443/* Executes a BCM command immediately and waits for it to complete. 490/* Executes a BCM command immediately and waits for it to complete.
444 Other BCM commands (eg. LCD updates or lcd_tick) must not interfere. 491 Other BCM commands (eg. LCD updates or lcd_tick) must not interfere.
diff --git a/firmware/target/arm/iriver/h10/lcd-as-h10.S b/firmware/target/arm/iriver/h10/lcd-as-h10.S
new file mode 100644
index 0000000000..8ac8b4289f
--- /dev/null
+++ b/firmware/target/arm/iriver/h10/lcd-as-h10.S
@@ -0,0 +1,538 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007-2008 by Michael Sevakis
11 *
12 * H10 20GB LCD assembly routines
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#include "config.h"
25#include "cpu.h"
26
27/****************************************************************************
28 * void lcd_write_yuv420_lines(unsigned char const * const src[3],
29 * int width,
30 * int stride);
31 *
32 * |R| |1.000000 -0.000001 1.402000| |Y'|
33 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
34 * |B| |1.000000 1.772000 0.000000| |Pr|
35 * Scaled, normalized, rounded and tweaked to yield RGB 565:
36 * |R| |74 0 101| |Y' - 16| >> 9
37 * |G| = |74 -24 -51| |Cb - 128| >> 8
38 * |B| |74 128 0| |Cr - 128| >> 9
39 *
40 * Write four RGB565 pixels in the following order on each loop:
41 * 1 3 + > down
42 * 2 4 \/ left
43 */
44 .section .icode, "ax", %progbits
45 .align 2
46 .global lcd_write_yuv420_lines
47 .type lcd_write_yuv420_lines, %function
48lcd_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
6210: @ 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 @
10715: @ 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 @
11620: @
117 ldr r3, [r0] @
118 tst r3, #LCD2_BUSY_MASK @
119 bne 20b @
120 str r7, [r0] @
121 str r11, [r0] @
122 @
123 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
124 add r12, r7, r7, asl #2 @
125 add r7, r12, r7, asl #5 @
126 @ compute R, G, and B
127 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
128 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
129 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
130 @
131 orr r12, r3, r11 @ check if clamping is needed...
132 orr r12, r12, r7, asr #1 @ ...at all
133 cmp r12, #31 @
134 bls 15f @ no clamp @
135 cmp r3, #31 @ clamp b
136 mvnhi r3, r3, asr #31 @
137 andhi r3, r3, #31 @
138 cmp r11, #31 @ clamp r
139 mvnhi r11, r11, asr #31 @
140 andhi r11, r11, #31 @
141 cmp r7, #63 @ clamp g
142 mvnhi r7, r7, asr #31 @
143 andhi r7, r7, #63 @
14415: @ no clamp @
145 @
146 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
147 @
148 orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11)
149 orr r3, r3, r7, lsl #5 @ r3 |= (g << 5)
150 @
151 orr r7, r14, r3, lsr #8 @ store pixel
152 orr r11, r14, r3 @
15320: @
154 ldr r3, [r0] @
155 tst r3, #LCD2_BUSY_MASK @
156 bne 20b @
157 str r7, [r0] @
158 str r11, [r0] @
159 @
160 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
161 add r12, r7, r7, asl #2 @
162 add r7, r12, r7, asl #5 @
163 @ compute R, G, and B
164 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
165 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
166 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
167 @
168 orr r12, r3, r11 @ check if clamping is needed...
169 orr r12, r12, r7, asr #1 @ ...at all
170 cmp r12, #31 @
171 bls 15f @ no clamp @
172 cmp r3, #31 @ clamp b
173 mvnhi r3, r3, asr #31 @
174 andhi r3, r3, #31 @
175 cmp r11, #31 @ clamp r
176 mvnhi r11, r11, asr #31 @
177 andhi r11, r11, #31 @
178 cmp r7, #63 @ clamp g
179 mvnhi r7, r7, asr #31 @
180 andhi r7, r7, #63 @
18115: @ no clamp @
182 @
183 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
184 @
185 orr r3, r3, r7, lsl #5 @ r3 = b | (g << 5)
186 orr r3, r3, r11, lsl #11 @ r3 |= (r << 11)
187 @
188 orr r7, r14, r3, lsr #8 @ store pixel
189 orr r11, r14, r3 @
19020: @
191 ldr r3, [r0] @
192 tst r3, #LCD2_BUSY_MASK @
193 bne 20b @
194 str r7, [r0] @
195 str r11, [r0] @
196 @
197 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
198 add r12, r7, r7, asl #2 @
199 add r7, r12, r7, asl #5 @
200 @ compute R, G, and B
201 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
202 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
203 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
204 @
205 orr r12, r3, r11 @ check if clamping is needed...
206 orr r12, r12, r7, asr #1 @ ...at all
207 cmp r12, #31 @
208 bls 15f @ no clamp @
209 cmp r3, #31 @ clamp b
210 mvnhi r3, r3, asr #31 @
211 andhi r3, r3, #31 @
212 cmp r11, #31 @ clamp r
213 mvnhi r11, r11, asr #31 @
214 andhi r11, r11, #31 @
215 cmp r7, #63 @ clamp g
216 mvnhi r7, r7, asr #31 @
217 andhi r7, r7, #63 @
21815: @ no clamp @
219 @
220 orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11)
221 orr r3, r3, r7, lsl #5 @ r3 |= (g << 5)
222 @
223 orr r7, r14, r3, lsr #8 @ store pixel
224 orr r11, r14, r3 @
22520: @
226 ldr r3, [r0] @
227 tst r3, #LCD2_BUSY_MASK @
228 bne 20b @
229 str r7, [r0] @
230 str r11, [r0] @
231 @
232 subs r1, r1, #2 @ subtract block from width
233 bgt 10b @ loop line @
234 @
235 ldmpc regs=r4-r11 @ restore registers and return
236 .ltorg @ dump constant pool
237 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
238
239
240/****************************************************************************
241 * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
242 * int width,
243 * int stride,
244 * int x_screen,
245 * int y_screen);
246 *
247 * |R| |1.000000 -0.000001 1.402000| |Y'|
248 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
249 * |B| |1.000000 1.772000 0.000000| |Pr|
250 * Red scaled at twice g & b but at same precision to place it in correct
251 * bit position after multiply and leave instruction count lower.
252 * |R| |258 0 408| |Y' - 16|
253 * |G| = |149 -49 -104| |Cb - 128|
254 * |B| |149 258 0| |Cr - 128|
255 *
256 * Write four RGB565 pixels in the following order on each loop:
257 * 1 3 + > down
258 * 2 4 \/ left
259 *
260 * Kernel pattern (raw|use order):
261 * 5 3 4 2 row0 row2 > down
262 * 1 7 0 6 | 5 1 3 7 4 0 2 6 col0 left
263 * 4 2 5 3 | 4 0 2 6 5 1 3 7 col2 \/
264 * 0 6 1 7
265 */
266 .section .icode, "ax", %progbits
267 .align 2
268 .global lcd_write_yuv420_lines_odither
269 .type lcd_write_yuv420_lines_odither, %function
270lcd_write_yuv420_lines_odither:
271 @ r0 = yuv_src
272 @ r1 = width
273 @ r2 = stride
274 @ r3 = x_screen
275 @ [sp] = y_screen
276 stmfd sp!, { r4-r11, lr } @ save non-scratch
277 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
278 @ r5 = yuv_src[1] = Cb_p
279 @ r6 = yuv_src[2] = Cr_p
280 @
281 ldr r0, [sp, #36] @ Line up pattern and kernel quadrant
282 eor r14, r3, r0 @
283 and r14, r14, #0x2 @
284 mov r14, r14, lsl #6 @ 0x00 or 0x80
285 @
286 mov r0, #0x7000000c @ r0 = &LCD2_PORT = 0x70008a0c
287 add r0, r0, #0x8a00 @
288 @
289 sub r2, r2, #1 @ Adjust stride because of increment
29010: @ loop line @
291 @
292 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
293 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
294 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
295 @
296 eor r14, r14, #0x80 @ flip pattern quadrant
297 @
298 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149
299 add r12, r7, r7, asl #2 @
300 add r12, r12, r12, asl #4 @
301 add r7, r12, r7, asl #6 @
302 @
303 sub r8, r8, #128 @ Cb -= 128
304 sub r9, r9, #128 @ Cr -= 128
305 @
306 add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49
307 add r10, r10, r8, asl #5 @
308 add r10, r10, r9, asl #3 @
309 add r10, r10, r9, asl #5 @
310 add r10, r10, r9, asl #6 @
311 @
312 mov r8, r8, asl #1 @ r8 = bu = Cb*258
313 add r8, r8, r8, asl #7 @
314 @
315 add r9, r9, r9, asl #1 @ r9 = rv = Cr*408
316 add r9, r9, r9, asl #4 @
317 mov r9, r9, asl #3 @
318 @
319 @ compute R, G, and B
320 add r3, r8, r7 @ r3 = b' = Y + bu
321 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
322 rsb r7, r10, r7 @ r7 = g' = Y + guv
323 @
324 @ r8 = bu, r9 = rv, r10 = guv
325 @
326 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256
327 add r3, r12, r3, lsr #8 @
328 @
329 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
330 add r11, r12, r11, lsr #8 @
331 @
332 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
333 add r7, r12, r7, lsr #8 @
334 @
335 add r12, r14, #0x200 @
336 @
337 add r3, r3, r12 @ b = r3 + delta
338 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
339 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
340 @
341 orr r12, r3, r11, asr #1 @ check if clamping is needed...
342 orr r12, r12, r7 @ ...at all
343 movs r12, r12, asr #15 @
344 beq 15f @ no clamp @
345 movs r12, r3, asr #15 @ clamp b
346 mvnne r3, r12, lsr #15 @
347 andne r3, r3, #0x7c00 @ mask b only if clamped
348 movs r12, r11, asr #16 @ clamp r
349 mvnne r11, r12, lsr #16 @
350 movs r12, r7, asr #15 @ clamp g
351 mvnne r7, r12, lsr #15 @
35215: @ no clamp @
353 @
354 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
355 @
356 and r11, r11, #0xf800 @ pack pixel
357 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
358 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
359 orr r3, r11, r3, lsr #10 @ (b >> 10)
360 @
361 mov r11, #LCD2_DATA_MASK @ store pixel
362 orr r7, r11, r3, lsr #8 @
363 orr r11, r11, r3 @
36420: @
365 ldr r3, [r0] @
366 tst r3, #LCD2_BUSY_MASK @
367 bne 20b @
368 str r7, [r0] @
369 str r11, [r0] @
370 @
371 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
372 add r12, r7, r7, asl #2 @
373 add r12, r12, r12, asl #4 @
374 add r7, r12, r7, asl #6 @
375 @ compute R, G, and B
376 add r3, r8, r7 @ r3 = b' = Y + bu
377 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
378 rsb r7, r10, r7 @ r7 = g' = Y + guv
379 @
380 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256
381 add r3, r12, r3, lsr #8 @
382 @
383 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
384 add r11, r12, r11, lsr #8 @
385 @
386 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
387 add r7, r12, r7, lsr #8 @
388 @
389 @ This element is zero - use r14 @
390 @
391 add r3, r3, r14 @ b = r3 + delta
392 add r11, r11, r14, lsl #1 @ r = r11 + delta*2
393 add r7, r7, r14, lsr #1 @ g = r7 + delta/2
394 @
395 orr r12, r3, r11, asr #1 @ check if clamping is needed...
396 orr r12, r12, r7 @ ...at all
397 movs r12, r12, asr #15 @
398 beq 15f @ no clamp @
399 movs r12, r3, asr #15 @ clamp b
400 mvnne r3, r12, lsr #15 @
401 andne r3, r3, #0x7c00 @ mask b only if clamped
402 movs r12, r11, asr #16 @ clamp r
403 mvnne r11, r12, lsr #16 @
404 movs r12, r7, asr #15 @ clamp g
405 mvnne r7, r12, lsr #15 @
40615: @ no clamp @
407 @
408 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
409 @
410 and r11, r11, #0xf800 @ pack pixel
411 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
412 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
413 orr r3, r11, r3, lsr #10 @ (b >> 10)
414 @
415 mov r11, #LCD2_DATA_MASK @ store pixel
416 orr r7, r11, r3, lsr #8 @
417 orr r11, r11, r3 @
41820: @
419 ldr r3, [r0] @
420 tst r3, #LCD2_BUSY_MASK @
421 bne 20b @
422 str r7, [r0] @
423 str r11, [r0] @
424 @
425 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
426 add r12, r7, r7, asl #2 @
427 add r12, r12, r12, asl #4 @
428 add r7, r12, r7, asl #6 @
429 @ compute R, G, and B
430 add r3, r8, r7 @ r3 = b' = Y + bu
431 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
432 rsb r7, r10, r7 @ r7 = g' = Y + guv
433 @
434 @ r8 = bu, r9 = rv, r10 = guv
435 @
436 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256
437 add r3, r12, r3, lsr #8 @
438 @
439 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
440 add r11, r12, r11, lsr #8 @
441 @
442 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
443 add r7, r12, r7, lsr #8 @
444 @
445 add r12, r14, #0x100 @
446 @
447 add r3, r3, r12 @ b = r3 + delta
448 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
449 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
450 @
451 orr r12, r3, r11, asr #1 @ check if clamping is needed...
452 orr r12, r12, r7 @ ...at all
453 movs r12, r12, asr #15 @
454 beq 15f @ no clamp @
455 movs r12, r3, asr #15 @ clamp b
456 mvnne r3, r12, lsr #15 @
457 andne r3, r3, #0x7c00 @ mask b only if clamped
458 movs r12, r11, asr #16 @ clamp r
459 mvnne r11, r12, lsr #16 @
460 movs r12, r7, asr #15 @ clamp g
461 mvnne r7, r12, lsr #15 @
46215: @ no clamp @
463 @
464 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
465 @
466 and r11, r11, #0xf800 @ pack pixel
467 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
468 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
469 orr r3, r11, r3, lsr #10 @ (b >> 10)
470 @
471 mov r11, #LCD2_DATA_MASK @ store pixel
472 orr r7, r11, r3, lsr #8 @
473 orr r11, r11, r3 @
47420: @
475 ldr r3, [r0] @
476 tst r3, #LCD2_BUSY_MASK @
477 bne 20b @
478 str r7, [r0] @
479 str r11, [r0] @
480 @
481 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
482 add r12, r7, r7, asl #2 @
483 add r12, r12, r12, asl #4 @
484 add r7, r12, r7, asl #6 @
485 @ compute R, G, and B
486 add r3, r8, r7 @ r3 = b' = Y + bu
487 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
488 rsb r7, r10, r7 @ r7 = g' = Y + guv
489 @
490 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256
491 add r3, r12, r3, lsr #8 @
492 @
493 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
494 add r11, r12, r11, lsr #8 @
495 @
496 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
497 add r7, r12, r7, lsr #8 @
498 @
499 add r12, r14, #0x300 @
500 @
501 add r3, r3, r12 @ b = r3 + delta
502 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
503 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
504 @
505 orr r12, r3, r11, asr #1 @ check if clamping is needed...
506 orr r12, r12, r7 @ ...at all
507 movs r12, r12, asr #15 @
508 beq 15f @ no clamp @
509 movs r12, r3, asr #15 @ clamp b
510 mvnne r3, r12, lsr #15 @
511 andne r3, r3, #0x7c00 @ mask b only if clamped
512 movs r12, r11, asr #16 @ clamp r
513 mvnne r11, r12, lsr #16 @
514 movs r12, r7, asr #15 @ clamp g
515 mvnne r7, r12, lsr #15 @
51615: @ no clamp @
517 @
518 and r11, r11, #0xf800 @ pack pixel
519 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
520 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
521 orr r3, r11, r3, lsr #10 @ (b >> 10)
522 @
523 mov r11, #LCD2_DATA_MASK @ store pixel
524 orr r7, r11, r3, lsr #8 @
525 orr r11, r11, r3 @
52620: @
527 ldr r3, [r0] @
528 tst r3, #LCD2_BUSY_MASK @
529 bne 20b @
530 str r7, [r0] @
531 str r11, [r0] @
532 @
533 subs r1, r1, #2 @ subtract block from width
534 bgt 10b @ loop line @
535 @
536 ldmpc regs=r4-r11 @ restore registers and return
537 .ltorg @ dump constant pool
538 .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither
diff --git a/firmware/target/arm/iriver/h10/lcd-h10_20gb.c b/firmware/target/arm/iriver/h10/lcd-h10_20gb.c
index 403c1c19e0..c7e339295d 100644
--- a/firmware/target/arm/iriver/h10/lcd-h10_20gb.c
+++ b/firmware/target/arm/iriver/h10/lcd-h10_20gb.c
@@ -36,6 +36,8 @@ static unsigned short disp_control_rev;
36/* Contrast setting << 8 */ 36/* Contrast setting << 8 */
37static int lcd_contrast; 37static int lcd_contrast;
38 38
39static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
40
39/* Forward declarations */ 41/* Forward declarations */
40#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) 42#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
41static void lcd_display_off(void); 43static void lcd_display_off(void);
@@ -396,6 +398,94 @@ bool lcd_active(void)
396 398
397/*** update functions ***/ 399/*** update functions ***/
398 400
401void lcd_yuv_set_options(unsigned options)
402{
403 lcd_yuv_options = options;
404}
405
406/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
407extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
408 int width,
409 int stride);
410extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
411 int width,
412 int stride,
413 int x_screen, /* To align dither pattern */
414 int y_screen);
415
416/* Performance function to blit a YUV bitmap directly to the LCD */
417void lcd_blit_yuv(unsigned char * const src[3],
418 int src_x, int src_y, int stride,
419 int x, int y, int width, int height)
420{
421 const unsigned char *yuv_src[3];
422 const unsigned char *ysrc_max;
423 int y0;
424 int options;
425
426 if (!display_on)
427 return;
428
429 width &= ~1;
430 height &= ~1;
431
432 /* calculate the drawing region */
433
434 /* The 20GB LCD is actually 128x160 but rotated 90 degrees so the origin
435 * is actually the bottom left and horizontal and vertical are swapped.
436 * Rockbox expects the origin to be the top left so we need to use
437 * 127 - y instead of just y */
438
439 /* max vert << 8 | start vert */
440 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x);
441
442 y0 = LCD_HEIGHT - 1 - y + y_offset;
443
444 /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=0, LG2-0=000 */
445 lcd_write_reg(R_ENTRY_MODE, 0x1020);
446
447 yuv_src[0] = src[0] + src_y * stride + src_x;
448 yuv_src[1] = src[1] + (src_y * stride >> 2) + (src_x >> 1);
449 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
450 ysrc_max = yuv_src[0] + height * stride;
451
452 options = lcd_yuv_options;
453
454 do
455 {
456 /* max horiz << 8 | start horiz */
457 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (y0 << 8) | (y0 - 1));
458
459 /* position cursor (set AD0-AD15) */
460 /* start vert << 8 | start horiz */
461 lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | y0);
462
463 /* start drawing */
464 lcd_send_cmd(R_WRITE_DATA_2_GRAM);
465
466 if (options & LCD_YUV_DITHER)
467 {
468 lcd_write_yuv420_lines_odither(yuv_src, width, stride,
469 x, y);
470 y -= 2;
471 }
472 else
473 {
474 lcd_write_yuv420_lines(yuv_src, width, stride);
475 }
476
477 y0 -= 2;
478 yuv_src[0] += stride << 1;
479 yuv_src[1] += stride >> 1;
480 yuv_src[2] += stride >> 1;
481 }
482 while (yuv_src[0] < ysrc_max);
483
484 /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=1, LG2-0=000 */
485 lcd_write_reg(R_ENTRY_MODE, 0x1028);
486}
487
488
399/* Update a fraction of the display. */ 489/* Update a fraction of the display. */
400void lcd_update_rect(int x0, int y0, int width, int height) 490void lcd_update_rect(int x0, int y0, int width, int height)
401{ 491{
diff --git a/firmware/target/arm/iriver/h10/lcd-h10_5gb.c b/firmware/target/arm/iriver/h10/lcd-h10_5gb.c
index 4386e1670c..5e1ad9ce23 100644
--- a/firmware/target/arm/iriver/h10/lcd-h10_5gb.c
+++ b/firmware/target/arm/iriver/h10/lcd-h10_5gb.c
@@ -118,6 +118,168 @@ void lcd_init_device(void)
118 118
119/*** update functions ***/ 119/*** update functions ***/
120 120
121#define CSUB_X 2
122#define CSUB_Y 2
123
124#define RYFAC (31*257)
125#define GYFAC (31*257)
126#define BYFAC (31*257)
127#define RVFAC 11170 /* 31 * 257 * 1.402 */
128#define GVFAC (-5690) /* 31 * 257 * -0.714136 */
129#define GUFAC (-2742) /* 31 * 257 * -0.344136 */
130#define BUFAC 14118 /* 31 * 257 * 1.772 */
131
132#define ROUNDOFFS (127*257)
133#define ROUNDOFFSG (63*257)
134
135/* Performance function to blit a YUV bitmap directly to the LCD */
136void lcd_blit_yuv(unsigned char * const src[3],
137 int src_x, int src_y, int stride,
138 int x, int y, int width, int height)
139{
140 int y0, x0, y1, x1;
141 int ymax;
142
143 width = (width + 1) & ~1;
144
145 /* calculate the drawing region */
146 x0 = x;
147 x1 = x + width - 1;
148 y0 = y;
149 y1 = y + height - 1;
150
151 /* max horiz << 8 | start horiz */
152 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (x1 << 8) | x0);
153
154 /* max vert << 8 | start vert */
155 lcd_write_reg(R_VERT_RAM_ADDR_POS, (y1 << 8) | y0);
156
157 /* start vert << 8 | start horiz */
158 lcd_write_reg(R_RAM_ADDR_SET, (y0 << 8) | x0);
159
160 /* start drawing */
161 lcd_send_cmd(R_WRITE_DATA_2_GRAM);
162
163 ymax = y + height - 1 ;
164
165 const int stride_div_csub_x = stride/CSUB_X;
166
167 for (; y <= ymax ; y++)
168 {
169 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
170 const unsigned char *ysrc = src[0] + stride * src_y + src_x;
171
172 const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) +
173 (src_x/CSUB_X);
174
175 const unsigned char *usrc = src[1] + uvoffset;
176 const unsigned char *vsrc = src[2] + uvoffset;
177 const unsigned char *row_end = ysrc + width;
178
179 int y, u, v;
180 int red1, green1, blue1;
181 int red2, green2, blue2;
182 unsigned rbits, gbits, bbits;
183
184 int rc, gc, bc;
185
186 do
187 {
188 u = *usrc++ - 128;
189 v = *vsrc++ - 128;
190 rc = RVFAC * v + ROUNDOFFS;
191 gc = GVFAC * v + GUFAC * u + ROUNDOFFSG;
192 bc = BUFAC * u + ROUNDOFFS;
193
194 /* Pixel 1 */
195 y = *ysrc++;
196
197 red1 = RYFAC * y + rc;
198 green1 = GYFAC * y + gc;
199 blue1 = BYFAC * y + bc;
200
201 /* Pixel 2 */
202 y = *ysrc++;
203 red2 = RYFAC * y + rc;
204 green2 = GYFAC * y + gc;
205 blue2 = BYFAC * y + bc;
206
207 /* Since out of bounds errors are relatively rare, we check two
208 pixels at once to see if any components are out of bounds, and
209 then fix whichever is broken. This works due to high values and
210 negative values both becoming larger than the cutoff when
211 casted to unsigned. And ORing them together checks all of them
212 simultaneously. */
213 if (((unsigned)(red1 | green1 | blue1 |
214 red2 | green2 | blue2)) > (RYFAC*255+ROUNDOFFS)) {
215 if (((unsigned)(red1 | green1 | blue1)) >
216 (RYFAC*255+ROUNDOFFS)) {
217 if ((unsigned)red1 > (RYFAC*255+ROUNDOFFS))
218 {
219 if (red1 < 0)
220 red1 = 0;
221 else
222 red1 = (RYFAC*255+ROUNDOFFS);
223 }
224 if ((unsigned)green1 > (GYFAC*255+ROUNDOFFSG))
225 {
226 if (green1 < 0)
227 green1 = 0;
228 else
229 green1 = (GYFAC*255+ROUNDOFFSG);
230 }
231 if ((unsigned)blue1 > (BYFAC*255+ROUNDOFFS))
232 {
233 if (blue1 < 0)
234 blue1 = 0;
235 else
236 blue1 = (BYFAC*255+ROUNDOFFS);
237 }
238 }
239
240 if (((unsigned)(red2 | green2 | blue2)) >
241 (RYFAC*255+ROUNDOFFS)) {
242 if ((unsigned)red2 > (RYFAC*255+ROUNDOFFS))
243 {
244 if (red2 < 0)
245 red2 = 0;
246 else
247 red2 = (RYFAC*255+ROUNDOFFS);
248 }
249 if ((unsigned)green2 > (GYFAC*255+ROUNDOFFSG))
250 {
251 if (green2 < 0)
252 green2 = 0;
253 else
254 green2 = (GYFAC*255+ROUNDOFFSG);
255 }
256 if ((unsigned)blue2 > (BYFAC*255+ROUNDOFFS))
257 {
258 if (blue2 < 0)
259 blue2 = 0;
260 else
261 blue2 = (BYFAC*255+ROUNDOFFS);
262 }
263 }
264 }
265
266 rbits = red1 >> 16 ;
267 gbits = green1 >> 15 ;
268 bbits = blue1 >> 16 ;
269 lcd_send_data((rbits << 11) | (gbits << 5) | bbits);
270
271 rbits = red2 >> 16 ;
272 gbits = green2 >> 15 ;
273 bbits = blue2 >> 16 ;
274 lcd_send_data((rbits << 11) | (gbits << 5) | bbits);
275 }
276 while (ysrc < row_end);
277
278 src_y++;
279 }
280}
281
282
121/* Update a fraction of the display. */ 283/* Update a fraction of the display. */
122void lcd_update_rect(int x0, int y0, int width, int height) 284void lcd_update_rect(int x0, int y0, int width, int height)
123{ 285{
diff --git a/firmware/target/arm/lcd-c200_c200v2.c b/firmware/target/arm/lcd-c200_c200v2.c
index 665c82f292..38877ccac9 100644
--- a/firmware/target/arm/lcd-c200_c200v2.c
+++ b/firmware/target/arm/lcd-c200_c200v2.c
@@ -30,6 +30,9 @@
30#endif 30#endif
31 31
32/* Display status */ 32/* Display status */
33#if MEMORYSIZE > 2
34static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
35#endif
33static bool is_lcd_enabled = true; 36static bool is_lcd_enabled = true;
34 37
35/* LCD command set for Samsung S6B33B2 */ 38/* LCD command set for Samsung S6B33B2 */
@@ -298,6 +301,80 @@ void lcd_set_flip(bool yesno)
298 301
299/*** update functions ***/ 302/*** update functions ***/
300 303
304#if MEMORYSIZE > 2 /* not for C200V2 */
305void lcd_yuv_set_options(unsigned options)
306{
307 lcd_yuv_options = options;
308}
309
310/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
311extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
312 int width,
313 int stride);
314extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
315 int width,
316 int stride,
317 int x_screen, /* To align dither pattern */
318 int y_screen);
319/* Performance function to blit a YUV bitmap directly to the LCD */
320void lcd_blit_yuv(unsigned char * const src[3],
321 int src_x, int src_y, int stride,
322 int x, int y, int width, int height)
323{
324 unsigned char const * yuv_src[3];
325 off_t z;
326
327 /* Sorry, but width and height must be >= 2 or else */
328 width &= ~1;
329 height >>= 1;
330
331 y += 0x1a;
332
333 z = stride*src_y;
334 yuv_src[0] = src[0] + z + src_x;
335 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
336 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
337
338 lcd_send_command(R_ENTRY_MODE, 0x80);
339
340 lcd_send_command(R_X_ADDR_AREA, x);
341 lcd_send_command(x + width - 1, 0);
342
343 if (lcd_yuv_options & LCD_YUV_DITHER)
344 {
345 do
346 {
347 lcd_send_command(R_Y_ADDR_AREA, y);
348 lcd_send_command(y + 1, 0);
349
350 lcd_write_yuv420_lines_odither(yuv_src, width, stride, x, y);
351
352 yuv_src[0] += stride << 1; /* Skip down two luma lines */
353 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
354 yuv_src[2] += stride >> 1;
355 y += 2;
356 }
357 while (--height > 0);
358 }
359 else
360 {
361 do
362 {
363 lcd_send_command(R_Y_ADDR_AREA, y);
364 lcd_send_command(y + 1, 0);
365
366 lcd_write_yuv420_lines(yuv_src, width, stride);
367
368 yuv_src[0] += stride << 1; /* Skip down two luma lines */
369 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
370 yuv_src[2] += stride >> 1;
371 y += 2;
372 }
373 while (--height > 0);
374 }
375}
376#endif /* MEMORYSIZE > 2 */
377
301/* Update the display. 378/* Update the display.
302 This must be called after all other LCD functions that change the display. */ 379 This must be called after all other LCD functions that change the display. */
303void lcd_update(void) 380void lcd_update(void)
diff --git a/firmware/target/arm/pbell/vibe500/lcd-as-vibe500.S b/firmware/target/arm/pbell/vibe500/lcd-as-vibe500.S
new file mode 100644
index 0000000000..e03011c168
--- /dev/null
+++ b/firmware/target/arm/pbell/vibe500/lcd-as-vibe500.S
@@ -0,0 +1,556 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id:$
9 *
10 * Copyright (C) 2007-2008 by Michael Sevakis
11 * Adapted for the Packard Bell Vibe 500 by Szymon Dziok
12 *
13 * Packard Bell Vibe 500 LCD assembly routines
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include "config.h"
26#include "cpu.h"
27
28/****************************************************************************
29 * void lcd_write_yuv420_lines(unsigned char const * const src[3],
30 * int width,
31 * int stride);
32 *
33 * |R| |1.000000 -0.000001 1.402000| |Y'|
34 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
35 * |B| |1.000000 1.772000 0.000000| |Pr|
36 * Scaled, normalized, rounded and tweaked to yield RGB 565:
37 * |R| |74 0 101| |Y' - 16| >> 9
38 * |G| = |74 -24 -51| |Cb - 128| >> 8
39 * |B| |74 128 0| |Cr - 128| >> 9
40 *
41 * Write four RGB565 pixels in the following order on each loop:
42 * 1 3 + > down
43 * 2 4 \/ left
44 */
45 .section .icode, "ax", %progbits
46 .align 2
47 .global lcd_write_yuv420_lines
48 .type lcd_write_yuv420_lines, %function
49lcd_write_yuv420_lines:
50 @ r0 = yuv_src
51 @ r1 = width
52 @ r2 = stride
53 stmfd sp!, { r4-r11, lr } @ save non-scratch
54 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
55 @ r5 = yuv_src[1] = Cb_p
56 @ r6 = yuv_src[2] = Cr_p
57 @
58 ldr r0, =LCD1_BASE @
59 @
60 sub r2, r2, #1 @ Adjust stride because of increment
6110: @ loop line @
62 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
63 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
64 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
65 @
66 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74
67 add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right
68 add r7, r12, r7, asl #5 @ by one less when adding - same for all
69 @
70 sub r8, r8, #128 @ Cb -= 128
71 sub r9, r9, #128 @ Cr -= 128
72 @
73 add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24
74 add r10, r10, r10, asl #4 @
75 add r10, r10, r8, asl #3 @
76 add r10, r10, r8, asl #4 @
77 @
78 add r11, r9, r9, asl #2 @ r9 = Cr*101
79 add r11, r11, r9, asl #5 @
80 add r9, r11, r9, asl #6 @
81 @
82 add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8
83 mov r8, r8, asr #2 @
84 add r9, r9, #256 @ r9 = rv = (r8 + 256) >> 9
85 mov r9, r9, asr #9 @
86 rsb r10, r10, #128 @ r10 = guv = (-r9 + 128) >> 8
87 mov r10, r10, asr #8 @
88 @ compute R, G, and B
89 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
90 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
91 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
92 @
93 orr r12, r3, r11 @ check if clamping is needed...
94 orr r12, r12, r7, asr #1 @ ...at all
95 cmp r12, #31 @
96 bls 15f @ no clamp @
97 cmp r3, #31 @ clamp b
98 mvnhi r3, r3, asr #31 @
99 andhi r3, r3, #31 @
100 cmp r11, #31 @ clamp r
101 mvnhi r11, r11, asr #31 @
102 andhi r11, r11, #31 @
103 cmp r7, #63 @ clamp g
104 mvnhi r7, r7, asr #31 @
105 andhi r7, r7, #63 @
10615: @ no clamp @
107 @
108 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
109 @
110 orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11)
111 orr r3, r3, r7, lsl #5 @ r3 |= (g << 5)
112 @
113 movs r7, r3, lsr #8 @ store pixel
11420: @
115 ldr r11, [r0] @
116 tst r11, #LCD1_BUSY_MASK @
117 bne 20b @
118 str r7, [r0, #0x10] @
11925: @
120 ldr r11, [r0] @
121 tst r11, #LCD1_BUSY_MASK @
122 bne 25b @
123 str r3, [r0, #0x10] @
124 @
125 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
126 add r12, r7, r7, asl #2 @
127 add r7, r12, r7, asl #5 @
128 @ compute R, G, and B
129 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
130 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
131 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
132 @
133 orr r12, r3, r11 @ check if clamping is needed...
134 orr r12, r12, r7, asr #1 @ ...at all
135 cmp r12, #31 @
136 bls 15f @ no clamp @
137 cmp r3, #31 @ clamp b
138 mvnhi r3, r3, asr #31 @
139 andhi r3, r3, #31 @
140 cmp r11, #31 @ clamp r
141 mvnhi r11, r11, asr #31 @
142 andhi r11, r11, #31 @
143 cmp r7, #63 @ clamp g
144 mvnhi r7, r7, asr #31 @
145 andhi r7, r7, #63 @
14615: @ no clamp @
147 @
148 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
149 @
150 orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11)
151 orr r3, r3, r7, lsl #5 @ r3 |= (g << 5)
152 @
153 movs r7, r3, lsr #8 @ store pixel
15420: @
155 ldr r11, [r0] @
156 tst r11, #LCD1_BUSY_MASK @
157 bne 20b @
158 str r7, [r0, #0x10] @
15925: @
160 ldr r11, [r0] @
161 tst r11, #LCD1_BUSY_MASK @
162 bne 25b @
163 str r3, [r0, #0x10] @
164 @
165 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
166 add r12, r7, r7, asl #2 @
167 add r7, r12, r7, asl #5 @
168 @ compute R, G, and B
169 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
170 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
171 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
172 @
173 orr r12, r3, r11 @ check if clamping is needed...
174 orr r12, r12, r7, asr #1 @ ...at all
175 cmp r12, #31 @
176 bls 15f @ no clamp @
177 cmp r3, #31 @ clamp b
178 mvnhi r3, r3, asr #31 @
179 andhi r3, r3, #31 @
180 cmp r11, #31 @ clamp r
181 mvnhi r11, r11, asr #31 @
182 andhi r11, r11, #31 @
183 cmp r7, #63 @ clamp g
184 mvnhi r7, r7, asr #31 @
185 andhi r7, r7, #63 @
18615: @ no clamp @
187 @
188 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
189 @
190 orr r3, r3, r7, lsl #5 @ r3 = b | (g << 5)
191 orr r3, r3, r11, lsl #11 @ r3 |= (r << 11)
192 @
193 movs r7, r3, lsr #8 @ store pixel
19420: @
195 ldr r11, [r0] @
196 tst r11, #LCD1_BUSY_MASK @
197 bne 20b @
198 str r7, [r0, #0x10] @
19925: @
200 ldr r11, [r0] @
201 tst r11, #LCD1_BUSY_MASK @
202 bne 25b @
203 str r3, [r0, #0x10] @
204 @
205 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
206 add r12, r7, r7, asl #2 @
207 add r7, r12, r7, asl #5 @
208 @ compute R, G, and B
209 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
210 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
211 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
212 @
213 orr r12, r3, r11 @ check if clamping is needed...
214 orr r12, r12, r7, asr #1 @ ...at all
215 cmp r12, #31 @
216 bls 15f @ no clamp @
217 cmp r3, #31 @ clamp b
218 mvnhi r3, r3, asr #31 @
219 andhi r3, r3, #31 @
220 cmp r11, #31 @ clamp r
221 mvnhi r11, r11, asr #31 @
222 andhi r11, r11, #31 @
223 cmp r7, #63 @ clamp g
224 mvnhi r7, r7, asr #31 @
225 andhi r7, r7, #63 @
22615: @ no clamp @
227 @
228 orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11)
229 orr r3, r3, r7, lsl #5 @ r3 |= (g << 5)
230 @
231 movs r7, r3, lsr #8 @ store pixel
23220: @
233 ldr r11, [r0] @
234 tst r11, #LCD1_BUSY_MASK @
235 bne 20b @
236 str r7, [r0, #0x10] @
23725: @
238 ldr r11, [r0] @
239 tst r11, #LCD1_BUSY_MASK @
240 bne 25b @
241 str r3, [r0, #0x10] @
242 @
243 subs r1, r1, #2 @ subtract block from width
244 bgt 10b @ loop line @
245 @
246 ldmpc regs=r4-r11 @ restore registers and return
247 .ltorg @ dump constant pool
248 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
249
250
251/****************************************************************************
252 * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
253 * int width,
254 * int stride,
255 * int x_screen,
256 * int y_screen);
257 *
258 * |R| |1.000000 -0.000001 1.402000| |Y'|
259 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
260 * |B| |1.000000 1.772000 0.000000| |Pr|
261 * Red scaled at twice g & b but at same precision to place it in correct
262 * bit position after multiply and leave instruction count lower.
263 * |R| |258 0 408| |Y' - 16|
264 * |G| = |149 -49 -104| |Cb - 128|
265 * |B| |149 258 0| |Cr - 128|
266 *
267 * Write four RGB565 pixels in the following order on each loop:
268 * 1 3 + > down
269 * 2 4 \/ left
270 *
271 * Kernel pattern (raw|use order):
272 * 5 3 4 2 row0 row2 > down
273 * 1 7 0 6 | 5 1 3 7 4 0 2 6 col0 left
274 * 4 2 5 3 | 4 0 2 6 5 1 3 7 col2 \/
275 * 0 6 1 7
276 */
277 .section .icode, "ax", %progbits
278 .align 2
279 .global lcd_write_yuv420_lines_odither
280 .type lcd_write_yuv420_lines_odither, %function
281lcd_write_yuv420_lines_odither:
282 @ r0 = yuv_src
283 @ r1 = width
284 @ r2 = stride
285 @ r3 = x_screen
286 @ [sp] = y_screen
287 stmfd sp!, { r4-r11, lr } @ save non-scratch
288 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
289 @ r5 = yuv_src[1] = Cb_p
290 @ r6 = yuv_src[2] = Cr_p
291 @
292 ldr r0, [sp, #36] @ Line up pattern and kernel quadrant
293 eor r14, r3, r0 @
294 and r14, r14, #0x2 @
295 mov r14, r14, lsl #6 @ 0x00 or 0x80
296 @
297 ldr r0, =LCD1_BASE @
298 @
299 sub r2, r2, #1 @ Adjust stride because of increment
30010: @ loop line @
301 @
302 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
303 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
304 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
305 @
306 eor r14, r14, #0x80 @ flip pattern quadrant
307 @
308 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149
309 add r12, r7, r7, asl #2 @
310 add r12, r12, r12, asl #4 @
311 add r7, r12, r7, asl #6 @
312 @
313 sub r8, r8, #128 @ Cb -= 128
314 sub r9, r9, #128 @ Cr -= 128
315 @
316 add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49
317 add r10, r10, r8, asl #5 @
318 add r10, r10, r9, asl #3 @
319 add r10, r10, r9, asl #5 @
320 add r10, r10, r9, asl #6 @
321 @
322 mov r8, r8, asl #1 @ r8 = bu = Cb*258
323 add r8, r8, r8, asl #7 @
324 @
325 add r9, r9, r9, asl #1 @ r9 = rv = Cr*408
326 add r9, r9, r9, asl #4 @
327 mov r9, r9, asl #3 @
328 @
329 @ compute R, G, and B
330 add r3, r8, r7 @ r3 = b' = Y + bu
331 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
332 rsb r7, r10, r7 @ r7 = g' = Y + guv
333 @
334 @ r8 = bu, r9 = rv, r10 = guv
335 @
336 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256
337 add r3, r12, r3, lsr #8 @
338 @
339 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
340 add r11, r12, r11, lsr #8 @
341 @
342 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
343 add r7, r12, r7, lsr #8 @
344 @
345 add r12, r14, #0x200 @
346 @
347 add r3, r3, r12 @ b = r3 + delta
348 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
349 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
350 @
351 orr r12, r3, r11, asr #1 @ check if clamping is needed...
352 orr r12, r12, r7 @ ...at all
353 movs r12, r12, asr #15 @
354 beq 15f @ no clamp @
355 movs r12, r3, asr #15 @ clamp b
356 mvnne r3, r12, lsr #15 @
357 andne r3, r3, #0x7c00 @ mask b only if clamped
358 movs r12, r11, asr #16 @ clamp r
359 mvnne r11, r12, lsr #16 @
360 movs r12, r7, asr #15 @ clamp g
361 mvnne r7, r12, lsr #15 @
36215: @ no clamp @
363 @
364 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
365 @
366 and r11, r11, #0xf800 @ pack pixel
367 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
368 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
369 orr r3, r11, r3, lsr #10 @ (b >> 10)
370 @
371 movs r7, r3, lsr #8 @ store pixel
37220: @
373 ldr r11, [r0] @
374 tst r11, #LCD1_BUSY_MASK @
375 bne 20b @
376 str r7, [r0, #0x10] @
37725: @
378 ldr r11, [r0] @
379 tst r11, #LCD1_BUSY_MASK @
380 bne 25b @
381 str r3, [r0, #0x10] @
382 @
383 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
384 add r12, r7, r7, asl #2 @
385 add r12, r12, r12, asl #4 @
386 add r7, r12, r7, asl #6 @
387 @ compute R, G, and B
388 add r3, r8, r7 @ r3 = b' = Y + bu
389 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
390 rsb r7, r10, r7 @ r7 = g' = Y + guv
391 @
392 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256
393 add r3, r12, r3, lsr #8 @
394 @
395 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
396 add r11, r12, r11, lsr #8 @
397 @
398 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
399 add r7, r12, r7, lsr #8 @
400 @
401 @ This element is zero - use r14 @
402 @
403 add r3, r3, r14 @ b = r3 + delta
404 add r11, r11, r14, lsl #1 @ r = r11 + delta*2
405 add r7, r7, r14, lsr #1 @ g = r7 + delta/2
406 @
407 orr r12, r3, r11, asr #1 @ check if clamping is needed...
408 orr r12, r12, r7 @ ...at all
409 movs r12, r12, asr #15 @
410 beq 15f @ no clamp @
411 movs r12, r3, asr #15 @ clamp b
412 mvnne r3, r12, lsr #15 @
413 andne r3, r3, #0x7c00 @ mask b only if clamped
414 movs r12, r11, asr #16 @ clamp r
415 mvnne r11, r12, lsr #16 @
416 movs r12, r7, asr #15 @ clamp g
417 mvnne r7, r12, lsr #15 @
41815: @ no clamp @
419 @
420 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
421 @
422 and r11, r11, #0xf800 @ pack pixel
423 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
424 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
425 orr r3, r11, r3, lsr #10 @ (b >> 10)
426 @
427 movs r7, r3, lsr #8 @ store pixel
42820: @
429 ldr r11, [r0] @
430 tst r11, #LCD1_BUSY_MASK @
431 bne 20b @
432 str r7, [r0, #0x10] @
43325: @
434 ldr r11, [r0] @
435 tst r11, #LCD1_BUSY_MASK @
436 bne 25b @
437 str r3, [r0, #0x10] @
438 @
439 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
440 add r12, r7, r7, asl #2 @
441 add r12, r12, r12, asl #4 @
442 add r7, r12, r7, asl #6 @
443 @ compute R, G, and B
444 add r3, r8, r7 @ r3 = b' = Y + bu
445 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
446 rsb r7, r10, r7 @ r7 = g' = Y + guv
447 @
448 @ r8 = bu, r9 = rv, r10 = guv
449 @
450 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256
451 add r3, r12, r3, lsr #8 @
452 @
453 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
454 add r11, r12, r11, lsr #8 @
455 @
456 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
457 add r7, r12, r7, lsr #8 @
458 @
459 add r12, r14, #0x100 @
460 @
461 add r3, r3, r12 @ b = r3 + delta
462 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
463 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
464 @
465 orr r12, r3, r11, asr #1 @ check if clamping is needed...
466 orr r12, r12, r7 @ ...at all
467 movs r12, r12, asr #15 @
468 beq 15f @ no clamp @
469 movs r12, r3, asr #15 @ clamp b
470 mvnne r3, r12, lsr #15 @
471 andne r3, r3, #0x7c00 @ mask b only if clamped
472 movs r12, r11, asr #16 @ clamp r
473 mvnne r11, r12, lsr #16 @
474 movs r12, r7, asr #15 @ clamp g
475 mvnne r7, r12, lsr #15 @
47615: @ no clamp @
477 @
478 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
479 @
480 and r11, r11, #0xf800 @ pack pixel
481 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
482 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
483 orr r3, r11, r3, lsr #10 @ (b >> 10)
484 @
485 movs r7, r3, lsr #8 @ store pixel
48620: @
487 ldr r11, [r0] @
488 tst r11, #LCD1_BUSY_MASK @
489 bne 20b @
490 str r7, [r0, #0x10] @
49125: @
492 ldr r11, [r0] @
493 tst r11, #LCD1_BUSY_MASK @
494 bne 25b @
495 str r3, [r0, #0x10] @
496 @
497 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
498 add r12, r7, r7, asl #2 @
499 add r12, r12, r12, asl #4 @
500 add r7, r12, r7, asl #6 @
501 @ compute R, G, and B
502 add r3, r8, r7 @ r3 = b' = Y + bu
503 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
504 rsb r7, r10, r7 @ r7 = g' = Y + guv
505 @
506 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256
507 add r3, r12, r3, lsr #8 @
508 @
509 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
510 add r11, r12, r11, lsr #8 @
511 @
512 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
513 add r7, r12, r7, lsr #8 @
514 @
515 add r12, r14, #0x300 @
516 @
517 add r3, r3, r12 @ b = r3 + delta
518 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
519 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
520 @
521 orr r12, r3, r11, asr #1 @ check if clamping is needed...
522 orr r12, r12, r7 @ ...at all
523 movs r12, r12, asr #15 @
524 beq 15f @ no clamp @
525 movs r12, r3, asr #15 @ clamp b
526 mvnne r3, r12, lsr #15 @
527 andne r3, r3, #0x7c00 @ mask b only if clamped
528 movs r12, r11, asr #16 @ clamp r
529 mvnne r11, r12, lsr #16 @
530 movs r12, r7, asr #15 @ clamp g
531 mvnne r7, r12, lsr #15 @
53215: @ no clamp @
533 @
534 and r11, r11, #0xf800 @ pack pixel
535 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
536 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
537 orr r3, r11, r3, lsr #10 @ (b >> 10)
538 @
539 movs r7, r3, lsr #8 @ store pixel
54020: @
541 ldr r11, [r0] @
542 tst r11, #LCD1_BUSY_MASK @
543 bne 20b @
544 str r7, [r0, #0x10] @
54525: @
546 ldr r11, [r0] @
547 tst r11, #LCD1_BUSY_MASK @
548 bne 25b @
549 str r3, [r0, #0x10] @
550 @
551 subs r1, r1, #2 @ subtract block from width
552 bgt 10b @ loop line @
553 @
554 ldmpc regs=r4-r11 @ restore registers and return
555 .ltorg @ dump constant pool
556 .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither
diff --git a/firmware/target/arm/pbell/vibe500/lcd-vibe500.c b/firmware/target/arm/pbell/vibe500/lcd-vibe500.c
index 2daa5def74..047ef2bf53 100644
--- a/firmware/target/arm/pbell/vibe500/lcd-vibe500.c
+++ b/firmware/target/arm/pbell/vibe500/lcd-vibe500.c
@@ -35,6 +35,8 @@ static unsigned short disp_control_rev;
35/* Contrast setting << 8 */ 35/* Contrast setting << 8 */
36static int lcd_contrast; 36static int lcd_contrast;
37 37
38static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
39
38/* Forward declarations */ 40/* Forward declarations */
39#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) 41#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
40static void lcd_display_off(void); 42static void lcd_display_off(void);
@@ -375,6 +377,79 @@ bool lcd_active(void)
375 377
376/*** update functions ***/ 378/*** update functions ***/
377 379
380void lcd_yuv_set_options(unsigned options)
381{
382 lcd_yuv_options = options;
383}
384
385/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
386
387extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
388 int width,
389 int stride);
390extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
391 int width,
392 int stride,
393 int x_screen, /* To align dither pattern */
394 int y_screen);
395
396/* Performance function to blit a YUV bitmap directly to the LCD */
397void lcd_blit_yuv(unsigned char * const src[3],
398 int src_x, int src_y, int stride,
399 int x, int y, int width, int height)
400{
401 const unsigned char *yuv_src[3];
402 const unsigned char *ysrc_max;
403 int y0;
404 int options;
405
406 if (!display_on)
407 return;
408
409 width &= ~1;
410 height &= ~1;
411
412 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((LCD_WIDTH - 1 - x) << 8) |
413 ((LCD_WIDTH-1) - (x + width - 1)));
414
415 y0 = LCD_HEIGHT - 1 - y;
416
417 lcd_write_reg(R_ENTRY_MODE,0x1000);
418
419 yuv_src[0] = src[0] + src_y * stride + src_x;
420 yuv_src[1] = src[1] + (src_y * stride >> 2) + (src_x >> 1);
421 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
422 ysrc_max = yuv_src[0] + height * stride;
423
424 options = lcd_yuv_options;
425
426 do
427 {
428 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (y0 << 8) | (y0 - 1));
429 lcd_write_reg(R_RAM_ADDR_SET, ((LCD_WIDTH - 1 - x) << 8) | y0);
430
431 /* start drawing */
432 lcd_send_cmd(R_WRITE_DATA_2_GRAM);
433
434 if (options & LCD_YUV_DITHER)
435 {
436 lcd_write_yuv420_lines_odither(yuv_src, width, stride,x, y);
437 y -= 2;
438 }
439 else
440 {
441 lcd_write_yuv420_lines(yuv_src, width, stride);
442 }
443
444 y0 -= 2;
445 yuv_src[0] += stride << 1;
446 yuv_src[1] += stride >> 1;
447 yuv_src[2] += stride >> 1;
448 }
449 while (yuv_src[0] < ysrc_max);
450 lcd_write_reg(R_ENTRY_MODE,0x1008);
451}
452
378/* Update a fraction of the display. */ 453/* Update a fraction of the display. */
379void lcd_update_rect(int x0, int y0, int width, int height) 454void lcd_update_rect(int x0, int y0, int width, int height)
380{ 455{
diff --git a/firmware/target/arm/philips/hdd1630/lcd-as-hdd1630.S b/firmware/target/arm/philips/hdd1630/lcd-as-hdd1630.S
new file mode 100644
index 0000000000..3bb3530917
--- /dev/null
+++ b/firmware/target/arm/philips/hdd1630/lcd-as-hdd1630.S
@@ -0,0 +1,570 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007-2008 by Michael Sevakis
11 *
12 * H10 20GB LCD assembly routines
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#include "config.h"
25#include "cpu.h"
26
27/****************************************************************************
28 * void lcd_write_yuv420_lines(unsigned char const * const src[3],
29 * int width,
30 * int stride);
31 *
32 * |R| |1.000000 -0.000001 1.402000| |Y'|
33 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
34 * |B| |1.000000 1.772000 0.000000| |Pr|
35 * Scaled, normalized, rounded and tweaked to yield RGB 565:
36 * |R| |74 0 101| |Y' - 16| >> 9
37 * |G| = |74 -24 -51| |Cb - 128| >> 8
38 * |B| |74 128 0| |Cr - 128| >> 9
39 *
40 * Write four RGB565 pixels in the following order on each loop:
41 * 1 3 + > down
42 * 2 4 \/ left
43 */
44 .section .icode, "ax", %progbits
45 .align 2
46 .global lcd_write_yuv420_lines
47 .type lcd_write_yuv420_lines, %function
48lcd_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
6210: @ 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 @
10715: @ 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 @
11620: @
117 ldr r3, [r0] @
118 tst r3, #LCD2_BUSY_MASK @
119 bne 20b @
120 str r7, [r0] @
12120: @
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 @
14815: @ 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 @
15720: @
158 ldr r3, [r0] @
159 tst r3, #LCD2_BUSY_MASK @
160 bne 20b @
161 str r7, [r0] @
16220: @
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 @
18915: @ 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 @
19820: @
199 ldr r3, [r0] @
200 tst r3, #LCD2_BUSY_MASK @
201 bne 20b @
202 str r7, [r0] @
20320: @
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 @
23015: @ 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 @
23720: @
238 ldr r3, [r0] @
239 tst r3, #LCD2_BUSY_MASK @
240 bne 20b @
241 str r7, [r0] @
24220: @
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
286lcd_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
30610: @ 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 @
36815: @ 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 @
38020: @
381 ldr r3, [r0] @
382 tst r3, #LCD2_BUSY_MASK @
383 bne 20b @
384 str r7, [r0] @
38520: @
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 @
42615: @ 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 @
43820: @
439 ldr r3, [r0] @
440 tst r3, #LCD2_BUSY_MASK @
441 bne 20b @
442 str r7, [r0] @
44320: @
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 @
48615: @ 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 @
49820: @
499 ldr r3, [r0] @
500 tst r3, #LCD2_BUSY_MASK @
501 bne 20b @
502 str r7, [r0] @
50320: @
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 @
54415: @ 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 @
55420: @
555 ldr r3, [r0] @
556 tst r3, #LCD2_BUSY_MASK @
557 bne 20b @
558 str r7, [r0] @
55920: @
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 @@
81static bool lcd_enabled; 81static bool lcd_enabled;
82 82
83/* Display status */ 83/* Display status */
84static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
84static unsigned mad_ctrl = 0; 85static 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
316void 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. */
322extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
323 int width, int stride);
324
325extern 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 */
330void 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. */
317void lcd_update(void) 398void 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
37lcd_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
4610: @ 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
12811: @ 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 */
38static bool lcd_enabled; 38static bool lcd_enabled;
39 39
40/* Display status */
41static 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. */
41static unsigned short flip; 44static 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
150void 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
168extern 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 */
174void 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. */
149void lcd_update(void) 247void 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
54lcd_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
6710: @ 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 @
11215: @ 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 @
12020: @
121 ldr r3, [r0] @
122 tst r3, #LCD1_BUSY_MASK @
123 bne 20b @
124 strb r14, [r0, #0x10] @
12520: @
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 @
15215: @ 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|
15920: @
160 ldr r3, [r0] @
161 tst r3, #LCD1_BUSY_MASK @
162 bne 20b @
163 strb r14, [r0, #0x10] @
16420: @
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 @
19115: @ 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|
19820: @
199 ldr r3, [r0] @
200 tst r3, #LCD1_BUSY_MASK @
201 bne 20b @
202 strb r14, [r0, #0x10] @
20320: @
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 @
23015: @ 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|
23520: @
236 ldr r3, [r0] @
237 tst r3, #LCD1_BUSY_MASK @
238 bne 20b @
239 strb r14, [r0, #0x10] @
24020: @
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
290lcd_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
31010: @ 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 @
37615: @ 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 @
38620: @
387 ldr r3, [r0] @
388 tst r3, #LCD1_BUSY_MASK @
389 bne 20b @
390 strb r7, [r0, #0x10] @
39120: @
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 @
44015: @ 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 @
45020: @
451 ldr r3, [r0] @
452 tst r3, #LCD1_BUSY_MASK @
453 bne 20b @
454 strb r7, [r0, #0x10] @
45520: @
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 @
50215: @ 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 @
51220: @
513 ldr r3, [r0] @
514 tst r3, #LCD1_BUSY_MASK @
515 bne 20b @
516 strb r7, [r0, #0x10] @
51720: @
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 @
56615: @ 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 @
57420: @
575 ldr r3, [r0] @
576 tst r3, #LCD1_BUSY_MASK @
577 bne 20b @
578 strb r7, [r0, #0x10] @
57920: @
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 */
79static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
80
78/* wait for LCD */ 81/* wait for LCD */
79static inline void lcd_wait_write(void) 82static 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
410void 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 */
416void lcd_write_yuv420_lines(unsigned char const * const src[3],
417 int width,
418 int stride);
419void 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);
424void 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. */
409void lcd_update(void) 491void lcd_update(void)
diff --git a/firmware/target/arm/rk27xx/ihifi/lcd-ihifi.c b/firmware/target/arm/rk27xx/ihifi/lcd-ihifi.c
index 9596dca98b..d5906b9dd5 100644
--- a/firmware/target/arm/rk27xx/ihifi/lcd-ihifi.c
+++ b/firmware/target/arm/rk27xx/ihifi/lcd-ihifi.c
@@ -207,3 +207,18 @@ bool lcd_active()
207{ 207{
208 return display_on; 208 return display_on;
209} 209}
210
211/* Blit a YUV bitmap directly to the LCD */
212void lcd_blit_yuv(unsigned char * const src[3],
213 int src_x, int src_y, int stride,
214 int x, int y, int width, int height)
215{
216 (void)src;
217 (void)src_x;
218 (void)src_y;
219 (void)stride;
220 (void)x;
221 (void)y;
222 (void)width;
223 (void)height;
224}
diff --git a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c
index cef0186de5..23505d9fa0 100644
--- a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c
+++ b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770.c
@@ -268,3 +268,18 @@ bool lcd_active()
268{ 268{
269 return display_on; 269 return display_on;
270} 270}
271
272/* Blit a YUV bitmap directly to the LCD */
273void lcd_blit_yuv(unsigned char * const src[3],
274 int src_x, int src_y, int stride,
275 int x, int y, int width, int height)
276{
277 (void)src;
278 (void)src_x;
279 (void)src_y;
280 (void)stride;
281 (void)x;
282 (void)y;
283 (void)width;
284 (void)height;
285}
diff --git a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c
index e2436e9b90..311b8057cb 100644
--- a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c
+++ b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi770c.c
@@ -231,3 +231,18 @@ bool lcd_active()
231{ 231{
232 return display_on; 232 return display_on;
233} 233}
234
235/* Blit a YUV bitmap directly to the LCD */
236void lcd_blit_yuv(unsigned char * const src[3],
237 int src_x, int src_y, int stride,
238 int x, int y, int width, int height)
239{
240 (void)src;
241 (void)src_x;
242 (void)src_y;
243 (void)stride;
244 (void)x;
245 (void)y;
246 (void)width;
247 (void)height;
248}
diff --git a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c
index 8520715650..821b52dcb6 100644
--- a/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c
+++ b/firmware/target/arm/rk27xx/ihifi2/lcd-ihifi800.c
@@ -211,3 +211,18 @@ bool lcd_active()
211{ 211{
212 return display_on; 212 return display_on;
213} 213}
214
215/* Blit a YUV bitmap directly to the LCD */
216void lcd_blit_yuv(unsigned char * const src[3],
217 int src_x, int src_y, int stride,
218 int x, int y, int width, int height)
219{
220 (void)src;
221 (void)src_x;
222 (void)src_y;
223 (void)stride;
224 (void)x;
225 (void)y;
226 (void)width;
227 (void)height;
228}
diff --git a/firmware/target/arm/rk27xx/lcd-hifiman.c b/firmware/target/arm/rk27xx/lcd-hifiman.c
index 95486b02e4..bde1d3546f 100644
--- a/firmware/target/arm/rk27xx/lcd-hifiman.c
+++ b/firmware/target/arm/rk27xx/lcd-hifiman.c
@@ -350,3 +350,22 @@ bool lcd_active()
350{ 350{
351 return display_on; 351 return display_on;
352} 352}
353
354/* Blit a YUV bitmap directly to the LCD
355 * provided by generic fallback in lcd-16bit-common.c
356 */
357#if 0
358void lcd_blit_yuv(unsigned char * const src[3],
359 int src_x, int src_y, int stride,
360 int x, int y, int width, int height)
361{
362 (void)src;
363 (void)src_x;
364 (void)src_y;
365 (void)stride;
366 (void)x;
367 (void)y;
368 (void)width;
369 (void)height;
370}
371#endif
diff --git a/firmware/target/arm/rk27xx/ma/lcd-ma.c b/firmware/target/arm/rk27xx/ma/lcd-ma.c
index 8dfe874b44..fa3ccc5aa0 100644
--- a/firmware/target/arm/rk27xx/ma/lcd-ma.c
+++ b/firmware/target/arm/rk27xx/ma/lcd-ma.c
@@ -253,3 +253,18 @@ bool lcd_active()
253{ 253{
254 return display_on; 254 return display_on;
255} 255}
256
257/* Blit a YUV bitmap directly to the LCD */
258void lcd_blit_yuv(unsigned char * const src[3],
259 int src_x, int src_y, int stride,
260 int x, int y, int width, int height)
261{
262 (void)src;
263 (void)src_x;
264 (void)src_y;
265 (void)stride;
266 (void)x;
267 (void)y;
268 (void)width;
269 (void)height;
270}
diff --git a/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c b/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c
index e5cefd282d..b40f2860d7 100644
--- a/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c
+++ b/firmware/target/arm/rk27xx/rk27generic/lcd-rk27generic.c
@@ -178,3 +178,22 @@ void lcd_set_gram_area(int x_start, int y_start,
178 lcd_cmd(GRAM_WRITE); 178 lcd_cmd(GRAM_WRITE);
179 LCDC_CTRL &= ~RGB24B; 179 LCDC_CTRL &= ~RGB24B;
180} 180}
181
182/* Blit a YUV bitmap directly to the LCD
183 * provided by generic fallback in lcd-16bit-common.c
184 */
185#if 0
186void lcd_blit_yuv(unsigned char * const src[3],
187 int src_x, int src_y, int stride,
188 int x, int y, int width, int height)
189{
190 (void)src;
191 (void)src_x;
192 (void)src_y;
193 (void)stride;
194 (void)x;
195 (void)y;
196 (void)width;
197 (void)height;
198}
199#endif
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/lcd-asm-nano2g.S b/firmware/target/arm/s5l8700/ipodnano2g/lcd-asm-nano2g.S
index 50104a73e8..af338eef16 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/lcd-asm-nano2g.S
+++ b/firmware/target/arm/s5l8700/ipodnano2g/lcd-asm-nano2g.S
@@ -65,3 +65,231 @@ lcd_write_line: /* r2 = LCD_BASE */
65 bgt .loop 65 bgt .loop
66 66
67 ldmpc regs=r4-r6 67 ldmpc regs=r4-r6
68
69/****************************************************************************
70 * extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
71 * const unsigned LCD_BASE,
72 * int width,
73 * int stride);
74 *
75 * Conversion from Motion JPEG and MPEG Y'PbPr to RGB is:
76 * |R| |1.164 0.000 1.596| |Y' - 16|
77 * |G| = |1.164 -0.391 -0.813| |Pb - 128|
78 * |B| |1.164 2.018 0.000| |Pr - 128|
79 *
80 * Scaled, normalized, rounded and tweaked to yield RGB 565:
81 * |R| |74 0 101| |Y' - 16| >> 9
82 * |G| = |74 -24 -51| |Cb - 128| >> 8
83 * |B| |74 128 0| |Cr - 128| >> 9
84 *
85 * Converts two lines from YUV to RGB565 and writes to LCD at once. First loop
86 * loads Cb/Cr, calculates the chroma offset and saves them to buffer. Within
87 * the second loop these chroma offset are reloaded from buffer. Within each
88 * loop two pixels are calculated and written to LCD.
89 */
90 .align 2
91 .global lcd_write_yuv420_lines
92 .type lcd_write_yuv420_lines, %function
93lcd_write_yuv420_lines:
94 /* r0 = src = yuv_src */
95 /* r1 = dst = LCD_BASE */
96 /* r2 = width */
97 /* r3 = stride */
98 stmfd sp!, { r4-r10, lr } /* save non-scratch */
99 ldmia r0, { r9, r10, r12 } /* r9 = yuv_src[0] = Y'_p */
100 /* r10 = yuv_src[1] = Cb_p */
101 /* r12 = yuv_src[2] = Cr_p */
102 add r3, r9, r3 /* r3 = &ysrc[stride] */
103 add r4, r2, r2, asr #1 /* chroma buffer lenght = width/2 *3 */
104 mov r4, r4, asl #2 /* use words for str/ldm possibility */
105 add r4, r4, #19 /* plus room for 4 additional words, */
106 bic r4, r4, #3 /* rounded up to multiples of 4 byte */
107 sub sp, sp, r4 /* and allocate on stack */
108 stmia sp, {r1-r4} /* LCD_BASE, width, &ysrc[stride], stack_alloc */
109
110 mov r7, r2 /* r7 = loop count */
111 add r8, sp, #16 /* chroma buffer */
112 add lr, r1, #0x40 /* LCD data port = LCD_BASE + 0x40 */
113
114 /* 1st loop start */
11510: /* loop start */
116
117 ldrb r0, [r10], #1 /* r0 = *usrc++ = *Cb_p++ */
118 ldrb r1, [r12], #1 /* r1 = *vsrc++ = *Cr_p++ */
119
120 sub r0, r0, #128 /* r0 = Cb-128 */
121 sub r1, r1, #128 /* r1 = Cr-128 */
122
123 add r2, r1, r1, asl #1 /* r2 = Cr*51 + Cb*24 */
124 add r2, r2, r2, asl #4
125 add r2, r2, r0, asl #3
126 add r2, r2, r0, asl #4
127
128 add r4, r1, r1, asl #2 /* r1 = Cr*101 */
129 add r4, r4, r1, asl #5
130 add r1, r4, r1, asl #6
131
132 add r1, r1, #256 /* r1 = rv = (r1 + 256) >> 9 */
133 mov r1, r1, asr #9
134 rsb r2, r2, #128 /* r2 = guv = (-r2 + 128) >> 8 */
135 mov r2, r2, asr #8
136 add r0, r0, #2 /* r0 = bu = (Cb*128 + 256) >> 9 */
137 mov r0, r0, asr #2
138 stmia r8!, {r0-r2} /* store r0, r1 and r2 to chroma buffer */
139
140 /* 1st loop, first pixel */
141 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
142 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
143 add r3, r5, r5, asl #2
144 add r5, r3, r5, asl #5
145
146 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
147 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
148 add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */
149
150 orr r5, r6, r4 /* check if clamping is needed... */
151 orr r5, r5, r3, asr #1 /* ...at all */
152 cmp r5, #31
153 bls 15f /* -> no clamp */
154 cmp r6, #31 /* clamp r */
155 mvnhi r6, r6, asr #31
156 andhi r6, r6, #31
157 cmp r3, #63 /* clamp g */
158 mvnhi r3, r3, asr #31
159 andhi r3, r3, #63
160 cmp r4, #31 /* clamp b */
161 mvnhi r4, r4, asr #31
162 andhi r4, r4, #31
16315: /* no clamp */
164
165 /* calculate pixel_1 and save to r4 for later pixel packing */
166 orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */
167 orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */
168
169 /* 1st loop, second pixel */
170 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
171 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
172 add r3, r5, r5, asl #2
173 add r5, r3, r5, asl #5
174
175 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
176 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
177 add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */
178
179 orr r0, r6, r5 /* check if clamping is needed... */
180 orr r0, r0, r3, asr #1 /* ...at all */
181 cmp r0, #31
182 bls 15f /* -> no clamp */
183 cmp r6, #31 /* clamp r */
184 mvnhi r6, r6, asr #31
185 andhi r6, r6, #31
186 cmp r3, #63 /* clamp g */
187 mvnhi r3, r3, asr #31
188 andhi r3, r3, #63
189 cmp r5, #31 /* clamp b */
190 mvnhi r5, r5, asr #31
191 andhi r5, r5, #31
19215: /* no clamp */
193
194 /* calculate pixel_2 and pack with pixel_1 before writing */
195 orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */
196 orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */
197#ifdef FORCE_FIFO_WAIT
198 /* wait for FIFO half full */
199.fifo_wait1:
200 ldr r3, [lr, #-0x24] /* while (LCD_STATUS & 0x08); */
201 tst r3, #0x8
202 bgt .fifo_wait1
203#endif
204 stmia lr, {r4,r5} /* write pixel_1 and pixel_2 */
205
206 subs r7, r7, #2 /* check for loop end */
207 bgt 10b /* back to beginning */
208 /* 1st loop end */
209
210 /* Reload several registers for pointer rewinding for next loop */
211 add r8, sp, #16 /* chroma buffer */
212 ldmia sp, { r1, r7, r9} /* r1 = LCD_BASE */
213 /* r7 = loop count */
214 /* r9 = &ysrc[stride] */
215
216 /* 2nd loop start */
21720: /* loop start */
218 /* restore r0 (bu), r1 (rv) and r2 (guv) from chroma buffer */
219 ldmia r8!, {r0-r2}
220
221 /* 2nd loop, first pixel */
222 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
223 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
224 add r3, r5, r5, asl #2
225 add r5, r3, r5, asl #5
226
227 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
228 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
229 add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */
230
231 orr r5, r6, r4 /* check if clamping is needed... */
232 orr r5, r5, r3, asr #1 /* ...at all */
233 cmp r5, #31
234 bls 15f /* -> no clamp */
235 cmp r6, #31 /* clamp r */
236 mvnhi r6, r6, asr #31
237 andhi r6, r6, #31
238 cmp r3, #63 /* clamp g */
239 mvnhi r3, r3, asr #31
240 andhi r3, r3, #63
241 cmp r4, #31 /* clamp b */
242 mvnhi r4, r4, asr #31
243 andhi r4, r4, #31
24415: /* no clamp */
245 /* calculate pixel_1 and save to r4 for later pixel packing */
246 orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */
247 orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */
248
249 /* 2nd loop, second pixel */
250 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
251 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
252 add r3, r5, r5, asl #2
253 add r5, r3, r5, asl #5
254
255 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
256 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
257 add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */
258
259 orr r0, r6, r5 /* check if clamping is needed... */
260 orr r0, r0, r3, asr #1 /* ...at all */
261 cmp r0, #31
262 bls 15f /* -> no clamp */
263 cmp r6, #31 /* clamp r */
264 mvnhi r6, r6, asr #31
265 andhi r6, r6, #31
266 cmp r3, #63 /* clamp g */
267 mvnhi r3, r3, asr #31
268 andhi r3, r3, #63
269 cmp r5, #31 /* clamp b */
270 mvnhi r5, r5, asr #31
271 andhi r5, r5, #31
27215: /* no clamp */
273
274 /* calculate pixel_2 and pack with pixel_1 before writing */
275 orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */
276 orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */
277#ifdef FORCE_FIFO_WAIT
278 /* wait for FIFO half full */
279.fifo_wait2:
280 ldr r3, [lr, #-0x24] /* while (LCD_STATUS & 0x08); */
281 tst r3, #0x8
282 bgt .fifo_wait2
283#endif
284 stmia lr, {r4,r5} /* write pixel_1 and pixel_2 */
285
286 subs r7, r7, #2 /* check for loop end */
287 bgt 20b /* back to beginning */
288 /* 2nd loop end */
289
290 ldr r3, [sp, #12]
291 add sp, sp, r3 /* deallocate buffer */
292 ldmpc regs=r4-r10 /* restore registers */
293
294 .ltorg
295 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
index 2d630886c9..13e5c5c1d4 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
+++ b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
@@ -406,3 +406,36 @@ void lcd_update_rect(int x, int y, int width, int height)
406 } while (--height > 0 ); 406 } while (--height > 0 );
407 } 407 }
408} 408}
409
410/* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */
411extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
412 const unsigned int lcd_baseadress,
413 int width,
414 int stride);
415
416/* Blit a YUV bitmap directly to the LCD */
417void lcd_blit_yuv(unsigned char * const src[3],
418 int src_x, int src_y, int stride,
419 int x, int y, int width, int height)
420{
421 unsigned int z;
422 unsigned char const * yuv_src[3];
423
424 width = (width + 1) & ~1; /* ensure width is even */
425
426 lcd_setup_drawing_region(x, y, width, height);
427
428 z = stride * src_y;
429 yuv_src[0] = src[0] + z + src_x;
430 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
431 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
432
433 height >>= 1;
434
435 do {
436 lcd_write_yuv420_lines(yuv_src, LCD_BASE, width, stride);
437 yuv_src[0] += stride << 1;
438 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
439 yuv_src[2] += stride >> 1;
440 } while (--height > 0);
441}
diff --git a/firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c b/firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c
index ced8925999..5ed6c752b7 100644
--- a/firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c
+++ b/firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c
@@ -311,3 +311,11 @@ void lcd_update_rect(int x, int y, int width, int height)
311{ 311{
312 lcd_update(); 312 lcd_update();
313} 313}
314
315void lcd_blit_yuv(unsigned char * const src[3],
316 int src_x, int src_y, int stride,
317 int x, int y, int width, int height)
318{
319 /* stub */
320}
321
diff --git a/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c b/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c
index bbbfccc11d..5e722d5a87 100644
--- a/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c
+++ b/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c
@@ -476,3 +476,19 @@ void lcd_update(void)
476{ 476{
477 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); 477 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
478} 478}
479
480void lcd_blit_yuv(unsigned char * const src[3],
481 int src_x, int src_y, int stride,
482 int x, int y, int width, int height)
483{
484 (void)src;
485 (void)src_x;
486 (void)src_y;
487 (void)stride;
488 (void)x;
489 (void)y;
490 (void)width;
491 (void)height;
492 /* TODO: not implemented yet */
493}
494
diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-6g.c b/firmware/target/arm/s5l8702/ipod6g/lcd-6g.c
index e1406549f4..14647a5697 100644
--- a/firmware/target/arm/s5l8702/ipod6g/lcd-6g.c
+++ b/firmware/target/arm/s5l8702/ipod6g/lcd-6g.c
@@ -530,3 +530,49 @@ void lcd_update_rect(int x, int y, int width, int height)
530 530
531 displaylcd_dma(pixels); 531 displaylcd_dma(pixels);
532} 532}
533
534/* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */
535extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
536 uint16_t* outbuf,
537 int width,
538 int stride);
539
540/* Blit a YUV bitmap directly to the LCD */
541void lcd_blit_yuv(unsigned char * const src[3],
542 int src_x, int src_y, int stride,
543 int x, int y, int width, int height) ICODE_ATTR;
544void lcd_blit_yuv(unsigned char * const src[3],
545 int src_x, int src_y, int stride,
546 int x, int y, int width, int height)
547{
548 unsigned int z;
549 unsigned char const * yuv_src[3];
550
551#ifdef HAVE_LCD_SLEEP
552 if (!lcd_active()) return;
553#endif
554
555 width = (width + 1) & ~1; /* ensure width is even */
556
557 int pixels = width * height;
558 uint16_t* out = lcd_dblbuf[0];
559
560 z = stride * src_y;
561 yuv_src[0] = src[0] + z + src_x;
562 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
563 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
564
565 displaylcd_setup(x, y, width, height);
566
567 height >>= 1;
568
569 do {
570 lcd_write_yuv420_lines(yuv_src, out, width, stride);
571 yuv_src[0] += stride << 1;
572 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
573 yuv_src[2] += stride >> 1;
574 out += width << 1;
575 } while (--height);
576
577 displaylcd_dma(pixels);
578}
diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-asm-6g.S b/firmware/target/arm/s5l8702/ipod6g/lcd-asm-6g.S
new file mode 100644
index 0000000000..1ed7c4e189
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/lcd-asm-6g.S
@@ -0,0 +1,1013 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: lcd-as-video.S 26756 2010-06-11 04:41:36Z funman $
9 *
10 * Copyright (C) 2010 by Andree Buschmann
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/* Version history:
23 *
24 * SVN:
25 * - initial SVN version.
26 *
27 * ARMv4:
28 * - use all available registers to calculate four pixels within each
29 * loop iteration.
30 * - avoid LDR interlocks.
31 *
32 * ARMv5TE:
33 * - use ARMv5TE+ 1-cycle multiply-accumulate instructions.
34 *
35 * ARMv5TE_WST:
36 * - use data tables (256 bytes) for RBG565 saturation.
37 *
38 * All versions are based on current SVN algorithm (round->scale->add)
39 * using the same coefficients, so output results are identical.
40 *
41 * TODO?: SVN coefficients are a very nice approximation for operations
42 * with shift+add instructions. When 16x16+32 MLA instructions are used,
43 * NBR and COEF_N could probably be adjusted to slighly increase accuracy.
44 */
45#define VERSION_SVN 0
46#define VERSION_ARMV4 1
47#define VERSION_ARMV5TE 2
48#define VERSION_ARMV5TE_WST 3
49
50#define YUV2RGB_VERSION VERSION_ARMV5TE_WST
51
52
53#define ASM
54#include "config.h"
55#include "cpu.h"
56
57#if (YUV2RGB_VERSION == VERSION_SVN)
58 .section .icode, "ax", %progbits
59
60
61/****************************************************************************
62 * extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
63 * uint16_t* out,
64 * int width,
65 * int stride);
66 *
67 * Conversion from Motion JPEG and MPEG Y'PbPr to RGB is:
68 * |R| |1.164 0.000 1.596| |Y' - 16|
69 * |G| = |1.164 -0.391 -0.813| |Pb - 128|
70 * |B| |1.164 2.018 0.000| |Pr - 128|
71 *
72 * Scaled, normalized, rounded and tweaked to yield RGB 565:
73 * |R| |74 0 101| |Y' - 16| >> 9
74 * |G| = |74 -24 -51| |Cb - 128| >> 8
75 * |B| |74 128 0| |Cr - 128| >> 9
76 *
77 * Converts two lines from YUV to RGB565 and writes to LCD at once. First loop
78 * loads Cb/Cr, calculates the chroma offset and saves them to buffer. Within
79 * the second loop these chroma offset are reloaded from buffer. Within each
80 * loop two pixels are calculated and written to LCD.
81 */
82 .align 2
83 .global lcd_write_yuv420_lines
84 .type lcd_write_yuv420_lines, %function
85lcd_write_yuv420_lines:
86 /* r0 = src = yuv_src */
87 /* r1 = dst = out */
88 /* r2 = width */
89 /* r3 = stride */
90 stmfd sp!, { r4-r10, lr } /* save non-scratch */
91 ldmia r0, { r9, r10, r12 } /* r9 = yuv_src[0] = Y'_p */
92 /* r10 = yuv_src[1] = Cb_p */
93 /* r12 = yuv_src[2] = Cr_p */
94 add r3, r9, r3 /* r3 = &ysrc[stride] */
95 add r4, r2, r2, asr #1 /* chroma buffer lenght = width/2 *3 */
96 mov r4, r4, asl #2 /* use words for str/ldm possibility */
97 add r4, r4, #15 /* plus room for 3 additional words, */
98 bic r4, r4, #3 /* rounded up to multiples of 4 byte */
99 sub sp, sp, r4 /* and allocate on stack */
100 stmia sp, {r2-r4} /* width, &ysrc[stride], stack_alloc */
101
102 mov r7, r2 /* r7 = loop count */
103 add r8, sp, #12 /* chroma buffer */
104 mov lr, r1 /* RGB565 data destination buffer */
105
106 /* 1st loop start */
10710: /* loop start */
108
109 ldrb r0, [r10], #1 /* r0 = *usrc++ = *Cb_p++ */
110 ldrb r1, [r12], #1 /* r1 = *vsrc++ = *Cr_p++ */
111
112 sub r0, r0, #128 /* r0 = Cb-128 */
113 sub r1, r1, #128 /* r1 = Cr-128 */
114
115 add r2, r1, r1, asl #1 /* r2 = Cr*51 + Cb*24 */
116 add r2, r2, r2, asl #4
117 add r2, r2, r0, asl #3
118 add r2, r2, r0, asl #4
119
120 add r4, r1, r1, asl #2 /* r1 = Cr*101 */
121 add r4, r4, r1, asl #5
122 add r1, r4, r1, asl #6
123
124 add r1, r1, #256 /* r1 = rv = (r1 + 256) >> 9 */
125 mov r1, r1, asr #9
126 rsb r2, r2, #128 /* r2 = guv = (-r2 + 128) >> 8 */
127 mov r2, r2, asr #8
128 add r0, r0, #2 /* r0 = bu = (Cb*128 + 256) >> 9 */
129 mov r0, r0, asr #2
130 stmia r8!, {r0-r2} /* store r0, r1 and r2 to chroma buffer */
131
132 /* 1st loop, first pixel */
133 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
134 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
135 add r3, r5, r5, asl #2
136 add r5, r3, r5, asl #5
137
138 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
139 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
140 add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */
141
142 orr r5, r6, r4 /* check if clamping is needed... */
143 orr r5, r5, r3, asr #1 /* ...at all */
144 cmp r5, #31
145 bls 15f /* -> no clamp */
146 cmp r6, #31 /* clamp r */
147 mvnhi r6, r6, asr #31
148 andhi r6, r6, #31
149 cmp r3, #63 /* clamp g */
150 mvnhi r3, r3, asr #31
151 andhi r3, r3, #63
152 cmp r4, #31 /* clamp b */
153 mvnhi r4, r4, asr #31
154 andhi r4, r4, #31
15515: /* no clamp */
156
157 /* calculate pixel_1 and save to r4 for later pixel packing */
158 orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */
159 orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */
160
161 /* 1st loop, second pixel */
162 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
163 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
164 add r3, r5, r5, asl #2
165 add r5, r3, r5, asl #5
166
167 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
168 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
169 add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */
170
171 orr r0, r6, r5 /* check if clamping is needed... */
172 orr r0, r0, r3, asr #1 /* ...at all */
173 cmp r0, #31
174 bls 15f /* -> no clamp */
175 cmp r6, #31 /* clamp r */
176 mvnhi r6, r6, asr #31
177 andhi r6, r6, #31
178 cmp r3, #63 /* clamp g */
179 mvnhi r3, r3, asr #31
180 andhi r3, r3, #63
181 cmp r5, #31 /* clamp b */
182 mvnhi r5, r5, asr #31
183 andhi r5, r5, #31
18415: /* no clamp */
185
186 /* calculate pixel_2 and pack with pixel_1 before writing */
187 orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */
188 orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */
189 orr r4, r4, r5, lsl #16
190 str r4, [lr], #4 /* write pixel_1 and pixel_2 */
191
192 subs r7, r7, #2 /* check for loop end */
193 bgt 10b /* back to beginning */
194 /* 1st loop end */
195
196 /* Reload several registers for pointer rewinding for next loop */
197 add r8, sp, #12 /* chroma buffer */
198 ldmia sp, {r7, r9} /* r7 = loop count */
199 /* r9 = &ysrc[stride] */
200
201 /* 2nd loop start */
20220: /* loop start */
203 /* restore r0 (bu), r1 (rv) and r2 (guv) from chroma buffer */
204 ldmia r8!, {r0-r2}
205
206 /* 2nd loop, first pixel */
207 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
208 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
209 add r3, r5, r5, asl #2
210 add r5, r3, r5, asl #5
211
212 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
213 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
214 add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */
215
216 orr r5, r6, r4 /* check if clamping is needed... */
217 orr r5, r5, r3, asr #1 /* ...at all */
218 cmp r5, #31
219 bls 15f /* -> no clamp */
220 cmp r6, #31 /* clamp r */
221 mvnhi r6, r6, asr #31
222 andhi r6, r6, #31
223 cmp r3, #63 /* clamp g */
224 mvnhi r3, r3, asr #31
225 andhi r3, r3, #63
226 cmp r4, #31 /* clamp b */
227 mvnhi r4, r4, asr #31
228 andhi r4, r4, #31
22915: /* no clamp */
230 /* calculate pixel_1 and save to r4 for later pixel packing */
231 orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */
232 orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */
233
234 /* 2nd loop, second pixel */
235 ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
236 sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
237 add r3, r5, r5, asl #2
238 add r5, r3, r5, asl #5
239
240 add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
241 add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
242 add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */
243
244 orr r0, r6, r5 /* check if clamping is needed... */
245 orr r0, r0, r3, asr #1 /* ...at all */
246 cmp r0, #31
247 bls 15f /* -> no clamp */
248 cmp r6, #31 /* clamp r */
249 mvnhi r6, r6, asr #31
250 andhi r6, r6, #31
251 cmp r3, #63 /* clamp g */
252 mvnhi r3, r3, asr #31
253 andhi r3, r3, #63
254 cmp r5, #31 /* clamp b */
255 mvnhi r5, r5, asr #31
256 andhi r5, r5, #31
25715: /* no clamp */
258
259 /* calculate pixel_2 and pack with pixel_1 before writing */
260 orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */
261 orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */
262 orr r4, r4, r5, lsl #16
263 str r4, [lr], #4 /* write pixel_1 and pixel_2 */
264
265 subs r7, r7, #2 /* check for loop end */
266 bgt 20b /* back to beginning */
267 /* 2nd loop end */
268
269 ldr r3, [sp, #8]
270 add sp, sp, r3 /* deallocate buffer */
271 ldmpc regs=r4-r10 /* restore registers */
272
273 .ltorg
274 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
275
276
277#elif (YUV2RGB_VERSION == VERSION_ARMV4)
278/****************************************************************************
279 * extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
280 * uint16_t* out,
281 * int width,
282 * int stride);
283 *
284 * Conversion from Motion JPEG and MPEG Y'PbPr to RGB is:
285 * |R| |1.164 0.000 1.596| |Y' - 16|
286 * |G| = |1.164 -0.391 -0.813| |Pb - 128|
287 * |B| |1.164 2.018 0.000| |Pr - 128|
288 *
289 * Scaled, normalized, rounded and tweaked to yield RGB 565:
290 * |R| |74 0 101| |Y' - 16| >> 9
291 * |G| = |74 -24 -51| |Cb - 128| >> 8
292 * |B| |74 128 0| |Cr - 128| >> 9
293 *
294 * Converts two lines from YUV420 to RGB565, within each iteration four
295 * pixels (2 per line) are calculated and written to destination buffer.
296 */
297 .section .icode, "ax", %progbits
298
299 .align 2
300 .global lcd_write_yuv420_lines
301 .type lcd_write_yuv420_lines, %function
302
303lcd_write_yuv420_lines:
304 /* r0 = src = yuv_src */
305 /* r1 = dst = out */
306 /* r2 = width */
307 /* r3 = stride */
308 stmfd sp!, {r4-r11,lr} /* save non-scratch */
309 ldmia r0, {r10-r12} /* r10 = yuv_src[0] = Y'_p */
310 /* r11 = yuv_src[1] = Cb_p */
311 /* r12 = yuv_src[2] = Cr_p */
312 mov r9, r2, lsl #1 /* r9 = 2*width (loop count) */
313 str r9, [sp, #-4]! /* [--sp] = 2*width (constant) */
314 add r8, r10, r3 /* r8 = Y'_p + stride = Y'stride_p */
315 mov lr, r1 /* RGB565 data destination buffer */
316
31710: /* loop start */
318 ldrb r0, [r11], #1 /* r0 = *Cb_p++ */
319 ldrb r1, [r12], #1 /* r1 = *Cr_p++ */
320 ldrb r3, [r8], #1 /* r3 = Y'3 */
321 ldrb r4, [r8], #1 /* r4 = Y'4 */
322
323 sub r0, r0, #128 /* r0 = Cb-128 */
324 sub r1, r1, #128 /* r1 = Cr-128 */
325
326 add r2, r1, r1, asl #1 /* r2 = Cr*51 + Cb*24 */
327 add r2, r2, r2, asl #4
328 add r2, r2, r0, asl #3
329 add r2, r2, r0, asl #4
330
331 add r5, r1, r1, asl #2 /* r1 = Cr*101 */
332 add r5, r5, r1, asl #5
333 add r1, r5, r1, asl #6
334
335 add r1, r1, #256 /* r1 = rv = (r1 + 256) >> 9 */
336 mov r1, r1, asr #9
337 rsb r2, r2, #128 /* r2 = guv = (-r2 + 128) >> 8 */
338 mov r2, r2, asr #8
339 add r0, r0, #2 /* r0 = bu = (Cb*128 + 256) >> 9 */
340 mov r0, r0, asr #2
341
342 /* pixel_3 */
343 sub r3, r3, #16 /* r3 = (Y'-16) * (74/2) */
344 add r7, r3, r3, asl #2
345 add r3, r7, r3, asl #5
346
347 add r6, r1, r3, asr #8 /* r6 = r = (Y >> 9) + rv */
348 add r7, r2, r3, asr #7 /* r7 = g = (Y >> 8) + guv */
349 add r5, r0, r3, asr #8 /* r5 = b = (Y >> 9) + bu */
350
351 orr r3, r6, r5 /* check if clamping is needed... */
352 orr r3, r3, r7, asr #1 /* ...at all */
353 cmp r3, #31
354 bls 15f /* no clamp */
355 cmp r6, #31 /* clamp r */
356 mvnhi r6, r6, asr #31
357 andhi r6, r6, #31
358 cmp r7, #63 /* clamp g */
359 mvnhi r7, r7, asr #31
360 andhi r7, r7, #63
361 cmp r5, #31 /* clamp b */
362 mvnhi r5, r5, asr #31
363 andhi r5, r5, #31
36415: /* no clamp */
365
366 /* calculate pixel_3 and save to r5 for later pixel packing */
367 orr r5, r5, r7, lsl #5 /* pixel_3 = r<<11 | g<<5 | b */
368 orr r5, r5, r6, lsl #11 /* r5 = pixel_3 */
369
370 /* pixel_4 */
371 sub r4, r4, #16 /* r4 = (Y'-16) * (74/2) */
372 add r7, r4, r4, asl #2
373 add r4, r7, r4, asl #5
374
375 add r6, r1, r4, asr #8 /* r6 = r = (Y >> 9) + rv */
376 add r7, r2, r4, asr #7 /* r7 = g = (Y >> 8) + guv */
377 add r4, r0, r4, asr #8 /* r4 = b = (Y >> 9) + bu */
378
379 orr r3, r6, r4 /* check if clamping is needed... */
380 orr r3, r3, r7, asr #1 /* ...at all */
381 cmp r3, #31
382 bls 15f /* no clamp */
383 cmp r6, #31 /* clamp r */
384 mvnhi r6, r6, asr #31
385 andhi r6, r6, #31
386 cmp r7, #63 /* clamp g */
387 mvnhi r7, r7, asr #31
388 andhi r7, r7, #63
389 cmp r4, #31 /* clamp b */
390 mvnhi r4, r4, asr #31
391 andhi r4, r4, #31
39215: /* no clamp */
393
394 /* calculate pixel_4 and pack with pixel_3 before writing */
395 orr r4, r4, r7, lsl #5 /* pixel_4 = r<<11 | g<<5 | b */
396 orr r4, r4, r6, lsl #11 /* r4 = pixel_4 */
397 orr r5, r5, r4, lsl #16 /* r5 = pixel_4<<16 | pixel_3 */
398
399 ldr r7, [sp] /* r7 = 2*width */
400 ldrb r3, [r10], #1 /* r3 = Y'1 */
401 ldrb r4, [r10], #1 /* r4 = Y'2 */
402
403 str r5, [lr, r7] /* write pixel_3 and pixel_4 */
404
405 /* pixel_1 */
406 sub r3, r3, #16 /* r3 = (Y'-16) * (74/2) */
407 add r7, r3, r3, asl #2
408 add r3, r7, r3, asl #5
409
410 add r6, r1, r3, asr #8 /* r6 = r = (Y >> 9) + rv */
411 add r7, r2, r3, asr #7 /* r7 = g = (Y >> 8) + guv */
412 add r5, r0, r3, asr #8 /* r5 = b = (Y >> 9) + bu */
413
414 orr r3, r6, r5 /* check if clamping is needed... */
415 orr r3, r3, r7, asr #1 /* ...at all */
416 cmp r3, #31
417 bls 15f /* no clamp */
418 cmp r6, #31 /* clamp r */
419 mvnhi r6, r6, asr #31
420 andhi r6, r6, #31
421 cmp r7, #63 /* clamp g */
422 mvnhi r7, r7, asr #31
423 andhi r7, r7, #63
424 cmp r5, #31 /* clamp b */
425 mvnhi r5, r5, asr #31
426 andhi r5, r5, #31
42715: /* no clamp */
428
429 /* calculate pixel_1 and save to r5 for later pixel packing */
430 orr r5, r5, r7, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */
431 orr r5, r5, r6, lsl #11 /* r5 = pixel_1 */
432
433 /* pixel_2 */
434 sub r4, r4, #16 /* r4 = (Y'-16) * (74/2) */
435 add r7, r4, r4, asl #2
436 add r4, r7, r4, asl #5
437
438 add r6, r1, r4, asr #8 /* r6 = r = (Y >> 9) + rv */
439 add r7, r2, r4, asr #7 /* r7 = g = (Y >> 8) + guv */
440 add r4, r0, r4, asr #8 /* r4 = b = (Y >> 9) + bu */
441
442 orr r3, r6, r4 /* check if clamping is needed... */
443 orr r3, r3, r7, asr #1 /* ...at all */
444 cmp r3, #31
445 bls 15f /* no clamp */
446 cmp r6, #31 /* clamp r */
447 mvnhi r6, r6, asr #31
448 andhi r6, r6, #31
449 cmp r7, #63 /* clamp g */
450 mvnhi r7, r7, asr #31
451 andhi r7, r7, #63
452 cmp r4, #31 /* clamp b */
453 mvnhi r4, r4, asr #31
454 andhi r4, r4, #31
45515: /* no clamp */
456
457 /* calculate pixel_2 and pack with pixel_1 before writing */
458 orr r4, r4, r7, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */
459 orr r4, r4, r6, lsl #11 /* r4 = pixel_2 */
460 orr r5, r5, r4, lsl #16 /* r5 = pixel_2<<16 | pixel_1 */
461
462 str r5, [lr], #4 /* write pixel_1 and pixel_2 */
463
464 subs r9, r9, #4 /* check for loop end */
465 bgt 10b /* back to beginning */
466
467 /* loop end */
468 add sp, sp, #4 /* deallocate stack */
469 ldmpc regs=r4-r11 /* restore registers */
470
471 .ltorg
472 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
473
474
475#elif (YUV2RGB_VERSION == VERSION_ARMV5TE)
476/****************************************************************************
477 * How do I encode Y'CBCR components from R'G'B' in [0, +1]? (see ColorFAQ)
478 * |R| |0.00456621 0 0.00625893| |Y' - 16|
479 * |G| = |0.00456621 -0.00153632 -0.00318811| |Pb - 128|
480 * |B| |0.00456621 0.00791071 0 | |Pr - 128|
481 *
482 * Scaled, normalized, rounded and tweaked to yield RGB 565:
483 * |R| |74 0 101| |Y' - 16| >> 9
484 * |G| = |74 -24 -51| |Cb - 128| >> 8
485 * |B| |74 128 0| |Cr - 128| >> 9
486 */
487#define NBR 14 /* 14-bit resolution (SVN) */
488#define COEF_C0 74
489#define COEF_C1 101
490#define COEF_C2 -24
491#define COEF_C3 -51
492#define COEF_C4 128
493#define C4_IS_POW2
494
495/* constant for rounding a NBR number before down-scaling it to RS bits */
496#define ROUND(RS) (1 << (NBR - RS - 1))
497
498/* packed 16-bit coefficients */
499#define COEF_C4_C1 ((COEF_C4 << 16) | (COEF_C1 & 0xffff))
500#define COEF_2C3_2C2 ((COEF_C3 << 17) | ((COEF_C2 << 1) & 0xffff))
501/* 32-bit MLA constants */
502#define CONST_MLA_Y (-16 * COEF_C0)
503
504/****************************************************************************
505 * extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
506 * uint16_t* out,
507 * int width,
508 * int stride);
509 *
510 * Converts two lines from YUV420 to RGB565, within each iteration four
511 * pixels (2 per line) are calculated and written to destination buffer.
512 *
513 * - use ARMv5TE+ 1-cycle multiply+accumulator instructions.
514 */
515 .section .icode, "ax", %progbits
516
517 .align 2
518 .global lcd_write_yuv420_lines
519 .type lcd_write_yuv420_lines, %function
520
521lcd_write_yuv420_lines:
522 @ r0 = src = yuv_src
523 @ r1 = out = dst_p
524 @ r2 = width
525 @ r3 = stride
526 stmfd sp!, {r4-r11,lr} @ save non-scratch
527 ldmia r0, {r10-r12} @ r10 = yuv_src[0] = Y'_p
528 @ r11 = yuv_src[1] = Cb_p
529 @ r12 = yuv_src[2] = Cr_p
530 adr r0, const_data @ load constants
531 ldmia r0, {r5-r8} @ r5 = COEF_C4_C1
532 @ r6 = COEF_2C3_2C2
533 @ r7 = COEF_C0
534 @ r8 = CONST_MLA_Y
535 sub r4, r12, r11 @ r4 = Cr_p-Cb_p
536 mov r9, r2, asl #1 @ r9 = 2*width
537 stmfd sp!, {r4-r6,r9} @ SP -> Cr_p-Cb_p
538 @ COEF_C4_C1
539 @ COEF_2C3_2C2
540 @ 2*width
541 add r12, r10, r3 @ r12 = Y'_p + stride = Y'stride_p
542 mov lr, r1 @ RGB565 data destination buffer
543 orr r9, r7, r2, lsl #15 @ loop_count = width/2;
544 @ r9 = loop_count<<16 | COEF_C0
545 sub r9, r9, #0x10000 @ loop_count--
546
54710: @ loop_start
548
549 @ register usage:
550 @ r8 = CONST_MLA_Y
551 @ r9 = loop count<<16 | COEF_C0
552 @ r10 = Y'_p
553 @ r11 = Cb_p
554 @ r12 = Y'stride_p
555 @ lr = dst_p
556 @ free: r0-r7
557
558 ldmia sp, {r2-r4} @ r2 = Cr_p-Cb_p
559 @ r3 = COEF_C4_C1
560 @ r4 = COEF_2C3_2C2
561 mov r5, #ROUND(5) @ r5 = round constant
562
563 ldrb r6, [r12], #1 @ r6 = Y'3
564 ldrb r7, [r12], #1 @ r7 = Y'4
565
566 ldrb r1, [r11, r2] @ r1 = Cr = *Cr_p++
567 ldrb r0, [r11], #1 @ r0 = Cb = *Cb_p++
568
569 /* calculate Y3 and Y4 */
570 smlabb r6, r6, r9, r8 @ r6 = Y3 = C0*Y'3 - C0*16
571 smlabb r7, r7, r9, r8 @ r7 = Y4 = C0*Y'4 - C0*16
572
573 /* calculate rv, guv, bu */
574 sub r1, r1, #128 @ r1 = Cr" = Cr-128
575 sub r0, r0, #128 @ r0 = Cb" = Cb-128
576
577 smlabt r2, r1, r4, r5 @ r2 = guv" = Cr"*(2*C2) +
578 smlabb r2, r0, r4, r2 @ Cb"*(2*C3) + round
579 smlabb r1, r1, r3, r5 @ r1 = rv" = Cr"*C1 + round
580 #ifdef C4_IS_POW2
581 add r0, r5, r0, asl #NBR-7 @ r0 = bu" = Cb"*C4 + round
582 #else
583 smlabt r0, r0, r3, r5 @ r0 = bu" = Cb"*C4 + round
584 #endif
585
586 /* scale rv",guv",bu" */
587 mov r2, r2, asr #NBR-5 @ r2 = guv = guv" >> scale
588 mov r1, r1, asr #NBR-5 @ r1 = rv = rv" >> scale
589 mov r0, r0, asr #NBR-5 @ r0 = bu = bu" >> scale
590
591 @ register usage:
592 @ r8-r12,lr: pointers, counters
593 @ r0,r1,r2 = bu,rv,guv (rounded and scaled to RGB565)
594 @ r6,r7 = Y'3,Y'4
595 @ free: r3-r5
596
597 /* pixel_3 */
598 add r5, r1, r6, asr #NBR-5 @ r5 = r = (Y3 >> scale) + rv
599 add r4, r2, r6, asr #NBR-6 @ r4 = g = (Y3 >> scale) + guv
600 add r3, r0, r6, asr #NBR-5 @ r3 = b = (Y3 >> scale) + bu
601
602 orr r6, r5, r3 @ check if clamping is needed...
603 orr r6, r6, r4, asr #1 @ ...at all
604 cmp r6, #31
605 bls 15f @ no clamp
606 cmp r5, #31 @ clamp r
607 mvnhi r5, r5, asr #31
608 andhi r5, r5, #31
609 cmp r4, #63 @ clamp g
610 mvnhi r4, r4, asr #31
611 andhi r4, r4, #63
612 cmp r3, #31 @ clamp b
613 mvnhi r3, r3, asr #31
614 andhi r3, r3, #31
61515: @ no clamp
616
617 /* calculate pixel_3 and save to r3 for later pixel packing */
618 orr r3, r3, r4, lsl #5 @ r3 = pixel_3 = r<<11 | g<<5 | b
619 orr r3, r3, r5, lsl #11
620
621 /* pixel_4 */
622 add r5, r1, r7, asr #NBR-5 @ r5 = r = (Y4 >> scale) + rv
623 add r4, r2, r7, asr #NBR-6 @ r4 = g = (Y4 >> scale) + guv
624 add r7, r0, r7, asr #NBR-5 @ r7 = b = (Y4 >> scale) + bu
625
626 orr r6, r5, r7 @ check if clamping is needed...
627 orr r6, r6, r4, asr #1 @ ...at all
628 cmp r6, #31
629 bls 15f @ no clamp
630 cmp r5, #31 @ clamp r
631 mvnhi r5, r5, asr #31
632 andhi r5, r5, #31
633 cmp r4, #63 @ clamp g
634 mvnhi r4, r4, asr #31
635 andhi r4, r4, #63
636 cmp r7, #31 @ clamp b
637 mvnhi r7, r7, asr #31
638 andhi r7, r7, #31
63915: @ no clamp
640
641 /* calculate pixel_4 and pack with pixel_3 before writing */
642 orr r7, r7, r4, lsl #5 @ r7 = pixel_4 = r<<11 | g<<5 | b
643 orr r7, r7, r5, lsl #11
644 orr r3, r3, r7, lsl #16 @ r3 = pixel_4<<16 | pixel_3
645
646 /* avoid interlocks when writing pixel_3 and pixel_4 */
647 ldr r5, [sp, #12] @ r5 = 2*width
648
649 ldrb r6, [r10], #1 @ r6 = Y'1
650 ldrb r7, [r10], #1 @ r7 = Y'2
651
652 /* write pixel_3 and pixel_4 */
653 str r3, [lr, r5] @ [dst_p + 2*width] = r3
654
655 @ register usage:
656 @ r8-r12,lr: pointers, counters
657 @ r0,r1,r2 = bu,rv,guv (rounded and scaled to RGB565)
658 @ r6,r7 = Y'1,Y'2
659 @ free: r3-r5
660
661 /* calculate Y1 and Y2 */
662 smlabb r6, r6, r9, r8 @ r6 = Y1 = C0*Y'1 - C0*16
663 smlabb r7, r7, r9, r8 @ r7 = Y2 = C0*Y'2 - C0*16
664
665 /* pixel_1 */
666 add r5, r1, r6, asr #NBR-5 @ r5 = r = (Y1 >> scale) + rv
667 add r4, r2, r6, asr #NBR-6 @ r4 = g = (Y1 >> scale) + guv
668 add r3, r0, r6, asr #NBR-5 @ r3 = b = (Y1 >> scale) + bu
669
670 orr r6, r5, r3 @ check if clamping is needed...
671 orr r6, r6, r4, asr #1 @ ...at all
672 cmp r6, #31
673 bls 15f @ no clamp
674 cmp r5, #31 @ clamp r
675 mvnhi r5, r5, asr #31
676 andhi r5, r5, #31
677 cmp r4, #63 @ clamp g
678 mvnhi r4, r4, asr #31
679 andhi r4, r4, #63
680 cmp r3, #31 @ clamp b
681 mvnhi r3, r3, asr #31
682 andhi r3, r3, #31
68315: @ no clamp
684
685 /* calculate pixel_1 and save to r3 for later pixel packing */
686 orr r3, r3, r4, lsl #5 @ r3 = pixel_1 = r<<11 | g<<5 | b
687 orr r3, r3, r5, lsl #11
688
689 /* pixel_2 */
690 add r5, r1, r7, asr #NBR-5 @ r5 = r = (Y2 >> scale) + rv
691 add r4, r2, r7, asr #NBR-6 @ r4 = g = (Y2 >> scale) + guv
692 add r7, r0, r7, asr #NBR-5 @ r7 = b = (Y2 >> scale) + bu
693
694 orr r6, r5, r7 @ check if clamping is needed...
695 orr r6, r6, r4, asr #1 @ ...at all
696 cmp r6, #31
697 bls 15f @ no clamp
698 cmp r5, #31 @ clamp r
699 mvnhi r5, r5, asr #31
700 andhi r5, r5, #31
701 cmp r4, #63 @ clamp g
702 mvnhi r4, r4, asr #31
703 andhi r4, r4, #63
704 cmp r7, #31 @ clamp b
705 mvnhi r7, r7, asr #31
706 andhi r7, r7, #31
70715: @ no clamp
708
709 /* calculate pixel_2 and pack with pixel_1 before writing */
710 orr r7, r7, r4, lsl #5 @ r7 = pixel_2 = r<<11 | g<<5 | b
711 orr r7, r7, r5, lsl #11
712 orr r3, r3, r7, lsl #16 @ r3 = pixel_2 << 16 | pixel_1
713
714 str r3, [lr], #4 @ write pixel_1 and pixel_2
715
716 /* check for loop end */
717 subs r9, r9, #0x10000 @ loop_count--
718 bge 10b @ back to beginning
719
720 /* bye */
721 add sp, sp, #16
722 ldmpc regs=r4-r11 @ restore registers
723
724 .ltorg
725 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
726
727/* data */
728 .align 2
729const_data:
730 .word COEF_C4_C1
731 .word COEF_2C3_2C2
732 .word COEF_C0
733 .word CONST_MLA_Y
734
735 .size const_data, .-const_data
736
737
738#else /* YUV2RGB_VERSION == VERSION_ARMV5TE_WST */
739/****************************************************************************
740 * How do I encode Y'CBCR components from R'G'B' in [0, +1]? (see ColorFAQ)
741 * |R| |0.00456621 0 0.00625893| |Y' - 16|
742 * |G| = |0.00456621 -0.00153632 -0.00318811| |Pb - 128|
743 * |B| |0.00456621 0.00791071 0 | |Pr - 128|
744 *
745 * Scaled, normalized, rounded and tweaked to yield RGB 565:
746 * |R| |74 0 101| |Y' - 16| >> 9
747 * |G| = |74 -24 -51| |Cb - 128| >> 8
748 * |B| |74 128 0| |Cr - 128| >> 9
749 */
750#define NBR 14 /* 14-bit resolution (SVN) */
751#define COEF_C0 74
752#define COEF_C1 101
753#define COEF_C2 -24
754#define COEF_C3 -51
755#define COEF_C4 128
756#define C4_IS_POW2
757
758/* packed 16-bit coefficients */
759#define COEF_C4_C1 ((COEF_C4 << 16) | (COEF_C1 & 0xffff))
760#define COEF_C3_C2 ((COEF_C3 << 16) | (COEF_C2 & 0xffff))
761
762/* constant for rounding an NBR number before down-scaling it to RS bits */
763#define ROUND(RS) (1 << (NBR - RS - 1))
764
765/* 32-bit MLA constants */
766#define CONST_MLA_Y (-16 * COEF_C0)
767#define CONST_MLA_RV ((-128 * COEF_C1) + ROUND(5))
768#define CONST_MLA_BU ((-128 * COEF_C4) + ROUND(5))
769/* trick to save the register needed for table_sat6 reference:
770 add table_sat6-table_sat5 offset (conveniently scaled) to guv MLA */
771#define CONST_MLA_GUV (-128 * (COEF_C2 + COEF_C3) + ROUND(6) + \
772 ((table_sat6 - table_sat5) << (NBR - 6)))
773
774/****************************************************************************
775 * extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
776 * uint16_t* out,
777 * int width,
778 * int stride);
779 *
780 * Converts two lines from YUV420 to RGB565, within each iteration four
781 * pixels (2 per line) are calculated and written to destination buffer.
782 *
783 * - use ARMv5TE+ 1-cycle multiply+accumulator instructions.
784 * - use data tables (256 bytes) for RBG565 saturation.
785 */
786 .section .icode, "ax", %progbits
787
788 .align 2
789 .global lcd_write_yuv420_lines
790 .type lcd_write_yuv420_lines, %function
791
792lcd_write_yuv420_lines:
793 @ r0 = src = yuv_src
794 @ r1 = out = dst1_p
795 @ r2 = width
796 @ r3 = stride
797 stmfd sp!, {r4-r11,lr} @ save non-scratch
798 ldmia r0, {r10-r12} @ r10 = yuv_src[0] = Y'_p
799 @ r11 = yuv_src[1] = Cb_p
800 @ r12 = yuv_src[2] = Cr_p
801 /* prepare data and fill stack */
802 adr r0, const_data @ load constants
803 ldmia r0, {r4-r9,lr} @ r4 = COEF_C0
804 @ r5 = CONST_MLA_GUV
805 @ r6 = COEF_C3_C2
806 @ r7 = CONST_MLA_BU
807 @ r8 = COEF_C4_C1
808 @ r9 = CONST_MLA_RV
809 @ lr = table_sat5
810 sub r0, r12, r11 @ r0 = Cr_p-Cb_p
811 #define STACK_SZ 28
812 stmfd sp!, {r0,r5-r9,lr} @ SP -> Cr_p-Cb_p
813 @ CONST_MLA_GUV
814 @ COEF_C3_C2
815 @ CONST_MLA_BU
816 @ COEF_C4_C1
817 @ CONST_MLA_RV
818 @ table_sat5
819 mov r8, r4, lsl #4 @
820 rsb r8, #0 @ r8 = -16*COEF_C0 = CONST_MLA_Y
821 mov lr, r1 @ RGB565 data destination buffer
822 add r9, lr, r2, asl #1 @ r9 = out + 2*width = dst2_p
823 add r12, r3, r10 @ r12 = Y'_p + stride
824 orr r7, r4, r2, lsl #15 @ loop_count = width/2;
825 @ r7 = loop_count<<16 | COEF_C0
826 sub r7, r7, #0x10000 @ loop_count--
827
828 /* align loop code to minimize occupied lines, execution
829 time per loop is optimized ~10% on ARM926EJ-S */
830 .align CACHEALIGN_BITS
831loop_start:
832
833 @ register usage:
834 @ r7 = loop count<<16 | COEF_C0
835 @ r8 = CONST_MLA_Y
836 @ r9 = dst2_p
837 @ r10 = Y'_p
838 @ r11 = Cb_p
839 @ r12 = Y'stride_p
840 @ lr = dst1_p
841 @ free: r0-r6
842
843 /* load constants from stack */
844 ldmia sp, {r1-r3,r6} @ r1 = Cr_p-Cb_p
845 @ r2 = CONST_MLA_GUV
846 @ r3 = COEF_C3_C2
847 @ r6 = CONST_MLA_BU
848
849 /* read Cr", Cb" */
850 ldrb r1, [r11, r1] @ r1 = Cr = *Cr_p++
851 ldrb r0, [r11], #1 @ r0 = Cb = *Cb_p++
852
853 /* load more constants (avoids r1 interlock) */
854 ldrd r4, [sp, #16] @ r4 = COEF_C4_C1
855 @ r5 = CONST_MLA_RV
856
857 /* calculate rv", guv", bu" */
858 smlabt r2, r1, r3, r2 @ r2 = guv" = Cr*C2 + Cb*C3
859 smlabb r2, r0, r3, r2 @ + CONST_MLA_GUV
860 smlabb r1, r1, r4, r5 @ r1 = rv" = Cr*C1 + CONST_MLA_RV
861 #ifdef C4_IS_POW2
862 add r0, r6, r0, asl #NBR-7 @ r0 = bu" = Cb*C4 + CONST_MLA_BU
863 #else
864 smlabt r0, r0, r4, r6 @ r0 = bu" = Cb*C4 + CONST_MLA_BU
865 #endif
866
867 ldr r4, [sp, #STACK_SZ-4] @ r4 = table_sat5
868
869 /* read Y'1 and Y'2 */
870 ldrb r5, [r10], #1 @ r5 = Y'1 = *Y'_p++
871 ldrb r6, [r10], #1 @ r6 = Y'2 = *Y'_p++
872
873 /* scale rv",guv",bu", adding sat5_p here saves instructions later */
874 add r1, r4, r1, asr #NBR-5 @ r1 = rv' = sat5_p + rv">>scale
875 add r2, r4, r2, asr #NBR-6 @ r2 = guv' = sat5_p + guv">>scale
876 add r0, r4, r0, asr #NBR-5 @ r0 = bu' = sat5_p + bu">>scale
877
878 @ register usage:
879 @ r7-r12,lr: pointers, counters, tables
880 @ r0,r1,r2 = (bu,rv,guv) rounded and RGB565 scaled
881 @ r5,r6 = Y'1,Y'2
882 @ free: r3,r4
883
884 /* calculate Y1 and Y2 */
885 smlabb r5, r5, r7, r8 @ r5 = Y1 = C0*Y'1 - 16*C0
886 smlabb r6, r6, r7, r8 @ r6 = Y2 = C0*Y'2 - 16*C0
887
888 /* pixel_1 */
889 ldrb r3, [r0, r5, asr #NBR-5] @ r3 = b = sat5[Y1>>scale + bu']
890 ldrb r4, [r2, r5, asr #NBR-6] @ r4 = g = sat6[Y1>>scale + guv']
891 ldrb r5, [r1, r5, asr #NBR-5] @ r5 = r = sat5[Y1>>scale + rv']
892
893 /* calculate pixel_1 */
894 orr r3, r3, r4, lsl #5 @ r3 = pixel_1 = g<<5 | b
895
896 /* pixel_2 (avoid r5 interlock) */
897 ldrb r4, [r0, r6, asr #NBR-5] @ r4 = b = sat5[Y2>>scale + bu']
898
899 /* calculate pixel_1 and save to r3 for later pixel packing */
900 orr r3, r3, r5, lsl #11 @ r3 = pixel_1 = r<<11 | g<<5 | b
901
902 /* pixel_2 */
903 ldrb r5, [r2, r6, asr #NBR-6] @ r5 = g = sat6[Y2>>scale + guv']
904 ldrb r6, [r1, r6, asr #NBR-5] @ r6 = r = sat5[Y2>>scale + rv']
905
906 /* calculate pixel_2 and pack with pixel_1 before writing */
907 orr r3, r3, r4, lsl #16 @ r3 = pixel_2<<16 | pixel_1
908 orr r3, r3, r5, lsl #21
909 orr r3, r3, r6, lsl #27
910
911 /* read Y'3 and Y'4 */
912 ldrb r5, [r12], #1 @ r5 = Y'3 = *Y'stride_p++
913 ldrb r6, [r12], #1 @ r6 = Y'4 = *Y'stride_p++
914
915 /* write pixel_1 and pixel_2 */
916 str r3, [lr], #4 @ *dst2_p++ = r3
917
918 @ register usage:
919 @ r7-r12,lr: pointers, counters, tables
920 @ r0,r1,r2 = (bu,rv,guv) rounded and RGB565 scaled
921 @ r5,r6 = Y'3,Y'4
922 @ free: r3,r4
923
924 /* calculate Y3 and Y4 */
925 smlabb r5, r5, r7, r8 @ r5 = Y3 = C0*Y'3 - 16*C0
926 smlabb r6, r6, r7, r8 @ r6 = Y4 = C0*Y'4 - 16*C0
927
928 /* pixel_3 */
929 ldrb r3, [r0, r5, asr #NBR-5] @ r3 = b = sat5[Y3>>scale + bu']
930 ldrb r4, [r2, r5, asr #NBR-6] @ r4 = g = sat6[Y3>>scale + guv']
931 ldrb r5, [r1, r5, asr #NBR-5] @ r5 = r = sat5[Y3>>scale + rv']
932
933 /* calculate pixel_3 */
934 orr r3, r3, r4, lsl #5 @ r3 = pixel_3 = g<<5 | b
935
936 /* pixel_4 (avoid r5 interlock) */
937 ldrb r4, [r0, r6, asr #NBR-5] @ r4 = b = sat5[Y4>>scale + bu']
938
939 /* calculate pixel_3 and save to r3 for later pixel packing */
940 orr r3, r3, r5, lsl #11 @ r3 = pixel_3 = r<<11 | g<<5 | b
941
942 /* pixel_4 */
943 ldrb r5, [r2, r6, asr #NBR-6] @ r5 = g = sat6[Y4>>scale + guv']
944 ldrb r6, [r1, r6, asr #NBR-5] @ r6 = r = sat5[Y4>>scale + rv']
945
946 /* calculate pixel_4 and pack with pixel_3 before writing */
947 orr r3, r3, r4, lsl #16 @ r3 = pixel_4 << 16 | pixel_3
948 orr r3, r3, r5, lsl #21
949 orr r3, r3, r6, lsl #27
950
951 /* write pixel_3 and pixel_4 */
952 str r3, [r9], #4 @ *dst1_p++ = r3
953
954 /* check for loop end */
955 subs r7, r7, #0x10000 @ loop_count--
956 bge loop_start @ back to beginning
957
958 /* bye */
959 add sp, sp, #STACK_SZ @ deallocate stack
960 ldmpc regs=r4-r11 @ restore registers
961
962 .ltorg
963 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
964
965/* data */
966 .align 2
967const_data:
968 .word COEF_C0
969 .word CONST_MLA_GUV
970 .word COEF_C3_C2
971 .word CONST_MLA_BU
972 .word COEF_C4_C1
973 .word CONST_MLA_RV
974 .word table_sat5
975
976 .size const_data, .-const_data
977
978/* saturation tables */
979 /*.section .data*/
980 /* aligned to cache line size to minimize cache usage */
981 .align CACHEALIGN_BITS
982
983saturation_tables:
984 /* 5-bit saturation table [-36..0..+67], size=104 */
985 /* table_sat5[-36..-1] */
986 .byte 0, 0, 0, 0
987 .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
988 .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
989 table_sat5:
990 /* table_sat5[0..67] */
991 .byte 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
992 .byte 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
993 .byte 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31
994 .byte 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31
995 .byte 31, 31, 31, 31
996
997 /* 6-bit saturation table [-44..0..+107], size=152 */
998 /* table_sat6[-44..-1] */
999 .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1000 .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1001 .byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1002 table_sat6:
1003 /* table_sat6[0..107] */
1004 .byte 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
1005 .byte 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
1006 .byte 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47
1007 .byte 48, 49, 50, 51, 52, 53 ,54, 55, 56, 57, 58, 59, 60, 61, 62, 63
1008 .byte 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63
1009 .byte 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63
1010 .byte 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63
1011
1012 .size saturation_tables, .-saturation_tables
1013#endif /* YUV2RGB_VERSION */
diff --git a/firmware/target/arm/samsung/yh820/lcd-as-yh820.S b/firmware/target/arm/samsung/yh820/lcd-as-yh820.S
new file mode 100644
index 0000000000..542ceeeb36
--- /dev/null
+++ b/firmware/target/arm/samsung/yh820/lcd-as-yh820.S
@@ -0,0 +1,550 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 by Jens Arnold
11 * Heavily based on lcd-as-memframe.c by Michael Sevakis
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23#include "config.h"
24#include "cpu.h"
25
26/****************************************************************************
27 * void lcd_write_yuv420_lines(unsigned char const * const src[3],
28 * int width,
29 * int stride);
30 *
31 * |R| |1.000000 -0.000001 1.402000| |Y'|
32 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
33 * |B| |1.000000 1.772000 0.000000| |Pr|
34 * Scaled, normalized, rounded and tweaked to yield RGB 565:
35 * |R| |74 0 101| |Y' - 16| >> 9
36 * |G| = |74 -24 -51| |Cb - 128| >> 8
37 * |B| |74 128 0| |Cr - 128| >> 9
38 *
39 * Write four RGB565 pixels in the following order on each loop:
40 * 1 3 + > down
41 * 2 4 \/ left
42 */
43 .section .icode, "ax", %progbits
44 .align 2
45 .global lcd_write_yuv420_lines
46 .type lcd_write_yuv420_lines, %function
47lcd_write_yuv420_lines:
48 @ r0 = yuv_src
49 @ r1 = width
50 @ r2 = stride
51 stmfd sp!, { r4-r10, lr } @ save non-scratch
52 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
53 @ r5 = yuv_src[1] = Cb_p
54 @ r6 = yuv_src[2] = Cr_p
55 @ r0 = scratch
56 sub r2, r2, #1 @
57 mov r3, #0x70000000 @
58 orr r3, r3, #0x3000 @ r3 = LCD1_BASE
5910: @ loop line @
60 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
61 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
62 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
63 @
64 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74
65 add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right
66 add r7, r12, r7, asl #5 @ by one less when adding - same for all
67 @
68 sub r8, r8, #128 @ Cb -= 128
69 sub r9, r9, #128 @ Cr -= 128
70 @
71 add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24
72 add r10, r10, r10, asl #4 @
73 add r10, r10, r8, asl #3 @
74 add r10, r10, r8, asl #4 @
75 @
76 add lr, r9, r9, asl #2 @ r9 = Cr*101
77 add lr, lr, r9, asl #5 @
78 add r9, lr, r9, asl #6 @
79 @
80 add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8
81 mov r8, r8, asr #2 @
82 add r9, r9, #256 @ r9 = rv = (r9 + 256) >> 9
83 mov r9, r9, asr #9 @
84 rsb r10, r10, #128 @ r10 = guv = (-r10 + 128) >> 8
85 mov r10, r10, asr #8 @
86 @ compute R, G, and B
87 add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu
88 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
89 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
90 @
91 orr r12, r0, lr @ check if clamping is needed...
92 orr r12, r12, r7, asr #1 @ ...at all
93 cmp r12, #31 @
94 bls 15f @ no clamp @
95 cmp r0, #31 @ clamp b
96 mvnhi r0, r0, asr #31 @
97 andhi r0, r0, #31 @
98 cmp lr, #31 @ clamp r
99 mvnhi lr, lr, asr #31 @
100 andhi lr, lr, #31 @
101 cmp r7, #63 @ clamp g
102 mvnhi r7, r7, asr #31 @
103 andhi r7, r7, #63 @
10415: @ no clamp @
105 @
106 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
107 @
108 mov lr, lr, lsl #3 @
109 orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3)
110 orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b
1111: @ busy @
112 ldr r7, [r3] @ r7 = LCD1_BASE
113 tst r7, #LCD1_BUSY_MASK @ bridge busy?
114 bne 1b @
115 str lr, [r3, #0x10] @ send MSB
1161: @busy @
117 ldr r7, [r3] @ r7 = LCD1_BASE
118 tst r7, #LCD1_BUSY_MASK @ bridge busy?
119 bne 1b @
120 str r0, [r3, #0x10] @ send LSB
121 @
122 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
123 add r12, r7, r7, asl #2 @
124 add r7, r12, r7, asl #5 @
125 @ compute R, G, and B
126 add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu
127 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
128 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
129 @
130 orr r12, r0, lr @ check if clamping is needed...
131 orr r12, r12, r7, asr #1 @ ...at all
132 cmp r12, #31 @
133 bls 15f @ no clamp @
134 cmp r0, #31 @ clamp b
135 mvnhi r0, r0, asr #31 @
136 andhi r0, r0, #31 @
137 cmp lr, #31 @ clamp r
138 mvnhi lr, lr, asr #31 @
139 andhi lr, lr, #31 @
140 cmp r7, #63 @ clamp g
141 mvnhi r7, r7, asr #31 @
142 andhi r7, r7, #63 @
14315: @ no clamp @
144 @
145 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
146 @
147 mov lr, lr, lsl #3 @
148 orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3)
149 orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b
1501: @ busy @
151 ldr r7, [r3] @ r7 = LCD1_BASE
152 tst r7, #LCD1_BUSY_MASK @ bridge busy?
153 bne 1b @
154 str lr, [r3, #0x10] @ send MSB
1551: @ busy @
156 ldr r7, [r3] @ r7 = LCD1_BASE
157 tst r7, #LCD1_BUSY_MASK @ bridge busy?
158 bne 1b @
159 str r0, [r3, #0x10] @ send LSB
160 @
161 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
162 add r12, r7, r7, asl #2 @
163 add r7, r12, r7, asl #5 @
164 @ compute R, G, and B
165 add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu
166 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
167 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
168 @
169 orr r12, r0, lr @ check if clamping is needed...
170 orr r12, r12, r7, asr #1 @ ...at all
171 cmp r12, #31 @
172 bls 15f @ no clamp @
173 cmp r0, #31 @ clamp b
174 mvnhi r0, r0, asr #31 @
175 andhi r0, r0, #31 @
176 cmp lr, #31 @ clamp r
177 mvnhi lr, lr, asr #31 @
178 andhi lr, lr, #31 @
179 cmp r7, #63 @ clamp g
180 mvnhi r7, r7, asr #31 @
181 andhi r7, r7, #63 @
18215: @ no clamp @
183 @
184 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
185 @
186 @
187 mov lr, lr, lsl #3 @
188 orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3)
189 orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b
1901: @ busy @
191 ldr r7, [r3] @ r7 = LCD1_BASE
192 tst r7, #LCD1_BUSY_MASK @ bridge busy?
193 bne 1b @
194 str lr, [r3, #0x10] @ send MSB
1951: @ busy @
196 ldr r7, [r3] @ r7 = LCD1_BASE
197 tst r7, #LCD1_BUSY_MASK @ bridge busy?
198 bne 1b @
199 str r0, [r3, #0x10] @ send LSB
200 @
201 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
202 add r12, r7, r7, asl #2 @
203 add r7, r12, r7, asl #5 @
204 @ compute R, G, and B
205 add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu
206 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
207 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
208 @
209 orr r12, r0, lr @ check if clamping is needed...
210 orr r12, r12, r7, asr #1 @ ...at all
211 cmp r12, #31 @
212 bls 15f @ no clamp @
213 cmp r0, #31 @ clamp b
214 mvnhi r0, r0, asr #31 @
215 andhi r0, r0, #31 @
216 cmp lr, #31 @ clamp r
217 mvnhi lr, lr, asr #31 @
218 andhi lr, lr, #31 @
219 cmp r7, #63 @ clamp g
220 mvnhi r7, r7, asr #31 @
221 andhi r7, r7, #63 @
22215: @ no clamp @
223 @
224 mov lr, lr, lsl #3 @
225 orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3)
226 orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b
2271: @ busy @
228 ldr r7, [r3] @ r7 = LCD1_BASE
229 tst r7, #LCD1_BUSY_MASK @ bridge busy?
230 bne 1b @
231 str lr, [r3, #0x10] @ send MSB
2321: @ busy @
233 ldr r7, [r3] @ r7 = LCD1_BASE
234 tst r7, #LCD1_BUSY_MASK @ bridge busy?
235 bne 1b @
236 str r0, [r3, #0x10] @ send LSB
237 @
238 subs r1, r1, #2 @ subtract block from width
239 bgt 10b @ loop line @
240 @
241 ldmpc regs=r4-r10 @ restore registers and return
242 .ltorg @ dump constant pool
243 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
244
245/****************************************************************************
246 * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
247 * int width,
248 * int stride,
249 * int x_screen,
250 * int y_screen);
251 *
252 * |R| |1.000000 -0.000001 1.402000| |Y'|
253 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
254 * |B| |1.000000 1.772000 0.000000| |Pr|
255 * Red scaled at twice g & b but at same precision to place it in correct
256 * bit position after multiply and leave instruction count lower.
257 * |R| |258 0 408| |Y' - 16|
258 * |G| = |149 -49 -104| |Cb - 128|
259 * |B| |149 258 0| |Cr - 128|
260 *
261 * Write four RGB565 pixels in the following order on each loop:
262 * 1 3 + > down
263 * 2 4 \/ left
264 *
265 * Kernel pattern (raw|rotated|use order):
266 * 5 3 4 2 2 6 3 7 row0 row2 > down
267 * 1 7 0 6 | 4 0 5 1 | 2 4 6 0 3 5 7 1 col0 left
268 * 4 2 5 3 | 3 7 2 6 | 3 5 7 1 2 4 6 0 col2 \/
269 * 0 6 1 7 5 1 4 0
270 */
271 .section .icode, "ax", %progbits
272 .align 2
273 .global lcd_write_yuv420_lines_odither
274 .type lcd_write_yuv420_lines_odither, %function
275lcd_write_yuv420_lines_odither:
276 @ r0 = yuv_src
277 @ r1 = width
278 @ r2 = stride
279 @ r3 = x_screen
280 @ [sp] = y_screen
281 stmfd sp!, { r4-r11, lr } @ save non-scratch
282 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
283 @ r5 = yuv_src[1] = Cb_p
284 @ r6 = yuv_src[2] = Cr_p
285 @
286 sub r2, r2, #1 @
287 ldr r14, [sp, #36] @ Line up pattern and kernel quadrant
288 eor r14, r14, r3 @
289 and r14, r14, #0x2 @
290 mov r14, r14, lsl #6 @ 0x00 or 0x80
291 mov r3, #0x70000000 @
292 orr r3, r3, #0x3000 @ r3 = LCD1_BASE
29310: @ loop line @
294 @
295 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
296 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
297 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
298 @
299 eor r14, r14, #0x80 @ flip pattern quadrant
300 @
301 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149
302 add r12, r7, r7, asl #2 @
303 add r12, r12, r12, asl #4 @
304 add r7, r12, r7, asl #6 @
305 @
306 sub r8, r8, #128 @ Cb -= 128
307 sub r9, r9, #128 @ Cr -= 128
308 @
309 add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49
310 add r10, r10, r8, asl #5 @
311 add r10, r10, r9, asl #3 @
312 add r10, r10, r9, asl #5 @
313 add r10, r10, r9, asl #6 @
314 @
315 mov r8, r8, asl #1 @ r8 = bu = Cb*258
316 add r8, r8, r8, asl #7 @
317 @
318 add r9, r9, r9, asl #1 @ r9 = rv = Cr*408
319 add r9, r9, r9, asl #4 @
320 mov r9, r9, asl #3 @
321 @
322 @ compute R, G, and B
323 add r0, r8, r7 @ r0 = b' = Y + bu
324 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
325 rsb r7, r10, r7 @ r7 = g' = Y + guv
326 @
327 @ r8 = bu, r9 = rv, r10 = guv
328 @
329 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256
330 add r0, r12, r0, lsr #8 @
331 @
332 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
333 add r11, r12, r11, lsr #8 @
334 @
335 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
336 add r7, r12, r7, lsr #8 @
337 @
338 add r12, r14, #0x100 @
339 @
340 add r0, r0, r12 @ b = r0 + delta
341 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
342 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
343 @
344 orr r12, r0, r11, asr #1 @ check if clamping is needed...
345 orr r12, r12, r7 @ ...at all
346 movs r12, r12, asr #15 @
347 beq 15f @ no clamp @
348 movs r12, r0, asr #15 @ clamp b
349 mvnne r0, r12, lsr #15 @
350 andne r0, r0, #0x7c00 @ mask b only if clamped
351 movs r12, r11, asr #16 @ clamp r
352 mvnne r11, r12, lsr #16 @
353 movs r12, r7, asr #15 @ clamp g
354 mvnne r7, r12, lsr #15 @
35515: @ no clamp @
356 @
357 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
358 @
359
360 and r11, r11, #0xf800 @ pack pixel
361 mov r11, r11, lsr #8
362 and r7, r7, #0x7e00
363 orr r11, r11, r7, lsr #12
364 mov r7, r7, lsr#4
365 orr r0, r7, r0, lsr #10
3661: @ busy @
367 ldr r7, [r3] @ r7 = LCD1_BASE
368 tst r7, #LCD1_BUSY_MASK @ bridge busy?
369 bne 1b @
370 str r11, [r3, #0x10] @ send MSB
3711: @ busy @
372 ldr r7, [r3] @ r7 = LCD1_BASE
373 tst r7, #LCD1_BUSY_MASK @ bridge busy?
374 bne 1b @
375 str r0, [r3, #0x10] @ send LSB
376 @
377 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
378 add r12, r7, r7, asl #2 @
379 add r12, r12, r12, asl #4 @
380 add r7, r12, r7, asl #6 @
381 @ compute R, G, and B
382 add r0, r8, r7 @ r0 = b' = Y + bu
383 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
384 rsb r7, r10, r7 @ r7 = g' = Y + guv
385 @
386 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256
387 add r0, r12, r0, lsr #8 @
388 @
389 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
390 add r11, r12, r11, lsr #8 @
391 @
392 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
393 add r7, r12, r7, lsr #8 @
394 @
395 add r12, r14, #0x200 @
396 @
397 add r0, r0, r12 @ b = r0 + delta
398 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
399 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
400 @
401 orr r12, r0, r11, asr #1 @ check if clamping is needed...
402 orr r12, r12, r7 @ ...at all
403 movs r12, r12, asr #15 @
404 beq 15f @ no clamp @
405 movs r12, r0, asr #15 @ clamp b
406 mvnne r0, r12, lsr #15 @
407 andne r0, r0, #0x7c00 @ mask b only if clamped
408 movs r12, r11, asr #16 @ clamp r
409 mvnne r11, r12, lsr #16 @
410 movs r12, r7, asr #15 @ clamp g
411 mvnne r7, r12, lsr #15 @
41215: @ no clamp @
413 @
414 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
415
416 and r11, r11, #0xf800 @ pack pixel
417 mov r11, r11, lsr #8
418 and r7, r7, #0x7e00
419 orr r11, r11, r7, lsr #12
420 mov r7, r7, lsr#4
421 orr r0, r7, r0, lsr #10
4221: @ busy @
423 ldr r7, [r3] @ r7 = LCD1_BASE
424 tst r7, #LCD1_BUSY_MASK @ bridge busy?
425 bne 1b @
426 str r11, [r3, #0x10] @ send MSB
4271: @ busy @
428 ldr r7, [r3] @ r7 = LCD1_BASE
429 tst r7, #LCD1_BUSY_MASK @ bridge busy?
430 bne 1b @
431 str r0, [r3, #0x10] @ send LSB
432
433 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
434 add r12, r7, r7, asl #2 @
435 add r12, r12, r12, asl #4 @
436 add r7, r12, r7, asl #6 @
437 @ compute R, G, and B
438 add r0, r8, r7 @ r0 = b' = Y + bu
439 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
440 rsb r7, r10, r7 @ r7 = g' = Y + guv
441 @
442 @ r8 = bu, r9 = rv, r10 = guv
443 @
444 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256
445 add r0, r12, r0, lsr #8 @
446 @
447 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
448 add r11, r12, r11, lsr #8 @
449 @
450 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
451 add r7, r12, r7, lsr #8 @
452 @
453 add r12, r14, #0x300 @
454 @
455 add r0, r0, r12 @ b = r0 + delta
456 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
457 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
458 @
459 orr r12, r0, r11, asr #1 @ check if clamping is needed...
460 orr r12, r12, r7 @ ...at all
461 movs r12, r12, asr #15 @
462 beq 15f @ no clamp @
463 movs r12, r0, asr #15 @ clamp b
464 mvnne r0, r12, lsr #15 @
465 andne r0, r0, #0x7c00 @ mask b only if clamped
466 movs r12, r11, asr #16 @ clamp r
467 mvnne r11, r12, lsr #16 @
468 movs r12, r7, asr #15 @ clamp g
469 mvnne r7, r12, lsr #15 @
47015: @ no clamp @
471 @
472 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
473
474 and r11, r11, #0xf800 @ pack pixel
475 mov r11, r11, lsr #8
476 and r7, r7, #0x7e00
477 orr r11, r11, r7, lsr #12
478 mov r7, r7, lsr#4
479 orr r0, r7, r0, lsr #10
4801: @ busy @
481 ldr r7, [r3] @ r7 = LCD1_BASE
482 tst r7, #LCD1_BUSY_MASK @ bridge busy?
483 bne 1b @
484 str r11, [r3, #0x10] @ send MSB
4851: @ busy @
486 ldr r7, [r3] @ r7 = LCD1_BASE
487 tst r7, #LCD1_BUSY_MASK @ bridge busy?
488 bne 1b @
489 str r0, [r3, #0x10] @ send LSB
490
491 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
492 add r12, r7, r7, asl #2 @
493 add r12, r12, r12, asl #4 @
494 add r7, r12, r7, asl #6 @
495 @ compute R, G, and B
496 add r0, r8, r7 @ r0 = b' = Y + bu
497 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
498 rsb r7, r10, r7 @ r7 = g' = Y + guv
499 @
500 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256
501 add r0, r12, r0, lsr #8 @
502 @
503 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
504 add r11, r12, r11, lsr #8 @
505 @
506 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
507 add r7, r12, r7, lsr #8 @
508 @
509 @ This element is zero - use r14 @
510 @
511 add r0, r0, r14 @ b = r0 + delta
512 add r11, r11, r14, lsl #1 @ r = r11 + delta*2
513 add r7, r7, r14, lsr #1 @ g = r7 + delta/2
514 @
515 orr r12, r0, r11, asr #1 @ check if clamping is needed...
516 orr r12, r12, r7 @ ...at all
517 movs r12, r12, asr #15 @
518 beq 15f @ no clamp @
519 movs r12, r0, asr #15 @ clamp b
520 mvnne r0, r12, lsr #15 @
521 andne r0, r0, #0x7c00 @ mask b only if clamped
522 movs r12, r11, asr #16 @ clamp r
523 mvnne r11, r12, lsr #16 @
524 movs r12, r7, asr #15 @ clamp g
525 mvnne r7, r12, lsr #15 @
52615: @ no clamp @
527
528 and r11, r11, #0xf800 @ pack pixel
529 mov r11, r11, lsr #8
530 and r7, r7, #0x7e00
531 orr r11, r11, r7, lsr #12
532 mov r7, r7, lsr#4
533 orr r0, r7, r0, lsr #10
5341: @ busy @
535 ldr r7, [r3] @ r7 = LCD1_BASE
536 tst r7, #LCD1_BUSY_MASK @ bridge busy?
537 bne 1b @
538 str r11, [r3, #0x10] @ send MSB
5391: @ busy @
540 ldr r7, [r3] @ r7 = LCD1_BASE
541 tst r7, #LCD1_BUSY_MASK @ bridge busy?
542 bne 1b @
543 str r0, [r3, #0x10] @ send LSB
544
545 subs r1, r1, #2 @ subtract block from width
546 bgt 10b @ loop line @
547 @
548 ldmpc regs=r4-r11 @ restore registers and return
549 .ltorg @ dump constant pool
550 .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither
diff --git a/firmware/target/arm/samsung/yh820/lcd-yh820.c b/firmware/target/arm/samsung/yh820/lcd-yh820.c
index 25692eb8ac..f4b55ab917 100644
--- a/firmware/target/arm/samsung/yh820/lcd-yh820.c
+++ b/firmware/target/arm/samsung/yh820/lcd-yh820.c
@@ -30,6 +30,8 @@
30#endif 30#endif
31 31
32/* Display status */ 32/* Display status */
33static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
34
33#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) 35#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
34static bool is_lcd_enabled = true; 36static bool is_lcd_enabled = true;
35#endif 37#endif
@@ -289,6 +291,78 @@ void lcd_set_flip(bool yesno)
289 291
290/*** update functions ***/ 292/*** update functions ***/
291 293
294void lcd_yuv_set_options(unsigned options)
295{
296 lcd_yuv_options = options;
297}
298
299/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
300extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
301 int width,
302 int stride);
303extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
304 int width,
305 int stride,
306 int x_screen, /* To align dither pattern */
307 int y_screen);
308/* Performance function to blit a YUV bitmap directly to the LCD */
309void lcd_blit_yuv(unsigned char * const src[3],
310 int src_x, int src_y, int stride,
311 int x, int y, int width, int height)
312{
313 unsigned char const * yuv_src[3];
314 off_t z;
315
316 /* Sorry, but width and height must be >= 2 or else */
317 width &= ~1;
318 height >>= 1;
319
320 z = stride*src_y;
321 yuv_src[0] = src[0] + z + src_x;
322 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
323 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
324
325 lcd_send_command(R_ENTRY_MODE);
326 lcd_send_command(0x03);
327
328 lcd_send_command(R_Y_ADDR_AREA);
329 lcd_send_command(x + 4);
330 lcd_send_command(x + width - 1 + 4);
331
332 if (lcd_yuv_options & LCD_YUV_DITHER)
333 {
334 do
335 {
336 lcd_send_command(R_X_ADDR_AREA);
337 lcd_send_command(y);
338 lcd_send_command(y + 1);
339
340 lcd_write_yuv420_lines_odither(yuv_src, width, stride, x, y);
341 yuv_src[0] += stride << 1; /* Skip down two luma lines */
342 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
343 yuv_src[2] += stride >> 1;
344 y += 2;
345 }
346 while (--height > 0);
347 }
348 else
349 {
350 do
351 {
352 lcd_send_command(R_X_ADDR_AREA);
353 lcd_send_command(y);
354 lcd_send_command(y + 1);
355
356 lcd_write_yuv420_lines(yuv_src, width, stride);
357 yuv_src[0] += stride << 1; /* Skip down two luma lines */
358 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
359 yuv_src[2] += stride >> 1;
360 y += 2;
361 }
362 while (--height > 0);
363 }
364}
365
292/* Update the display. 366/* Update the display.
293 This must be called after all other LCD functions that change the display. */ 367 This must be called after all other LCD functions that change the display. */
294void lcd_update(void) 368void lcd_update(void)
diff --git a/firmware/target/arm/samsung/yh925/lcd-as-yh925.S b/firmware/target/arm/samsung/yh925/lcd-as-yh925.S
new file mode 100644
index 0000000000..8ac8b4289f
--- /dev/null
+++ b/firmware/target/arm/samsung/yh925/lcd-as-yh925.S
@@ -0,0 +1,538 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007-2008 by Michael Sevakis
11 *
12 * H10 20GB LCD assembly routines
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#include "config.h"
25#include "cpu.h"
26
27/****************************************************************************
28 * void lcd_write_yuv420_lines(unsigned char const * const src[3],
29 * int width,
30 * int stride);
31 *
32 * |R| |1.000000 -0.000001 1.402000| |Y'|
33 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
34 * |B| |1.000000 1.772000 0.000000| |Pr|
35 * Scaled, normalized, rounded and tweaked to yield RGB 565:
36 * |R| |74 0 101| |Y' - 16| >> 9
37 * |G| = |74 -24 -51| |Cb - 128| >> 8
38 * |B| |74 128 0| |Cr - 128| >> 9
39 *
40 * Write four RGB565 pixels in the following order on each loop:
41 * 1 3 + > down
42 * 2 4 \/ left
43 */
44 .section .icode, "ax", %progbits
45 .align 2
46 .global lcd_write_yuv420_lines
47 .type lcd_write_yuv420_lines, %function
48lcd_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
6210: @ 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 @
10715: @ 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 @
11620: @
117 ldr r3, [r0] @
118 tst r3, #LCD2_BUSY_MASK @
119 bne 20b @
120 str r7, [r0] @
121 str r11, [r0] @
122 @
123 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
124 add r12, r7, r7, asl #2 @
125 add r7, r12, r7, asl #5 @
126 @ compute R, G, and B
127 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
128 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
129 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
130 @
131 orr r12, r3, r11 @ check if clamping is needed...
132 orr r12, r12, r7, asr #1 @ ...at all
133 cmp r12, #31 @
134 bls 15f @ no clamp @
135 cmp r3, #31 @ clamp b
136 mvnhi r3, r3, asr #31 @
137 andhi r3, r3, #31 @
138 cmp r11, #31 @ clamp r
139 mvnhi r11, r11, asr #31 @
140 andhi r11, r11, #31 @
141 cmp r7, #63 @ clamp g
142 mvnhi r7, r7, asr #31 @
143 andhi r7, r7, #63 @
14415: @ no clamp @
145 @
146 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
147 @
148 orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11)
149 orr r3, r3, r7, lsl #5 @ r3 |= (g << 5)
150 @
151 orr r7, r14, r3, lsr #8 @ store pixel
152 orr r11, r14, r3 @
15320: @
154 ldr r3, [r0] @
155 tst r3, #LCD2_BUSY_MASK @
156 bne 20b @
157 str r7, [r0] @
158 str r11, [r0] @
159 @
160 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
161 add r12, r7, r7, asl #2 @
162 add r7, r12, r7, asl #5 @
163 @ compute R, G, and B
164 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
165 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
166 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
167 @
168 orr r12, r3, r11 @ check if clamping is needed...
169 orr r12, r12, r7, asr #1 @ ...at all
170 cmp r12, #31 @
171 bls 15f @ no clamp @
172 cmp r3, #31 @ clamp b
173 mvnhi r3, r3, asr #31 @
174 andhi r3, r3, #31 @
175 cmp r11, #31 @ clamp r
176 mvnhi r11, r11, asr #31 @
177 andhi r11, r11, #31 @
178 cmp r7, #63 @ clamp g
179 mvnhi r7, r7, asr #31 @
180 andhi r7, r7, #63 @
18115: @ no clamp @
182 @
183 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
184 @
185 orr r3, r3, r7, lsl #5 @ r3 = b | (g << 5)
186 orr r3, r3, r11, lsl #11 @ r3 |= (r << 11)
187 @
188 orr r7, r14, r3, lsr #8 @ store pixel
189 orr r11, r14, r3 @
19020: @
191 ldr r3, [r0] @
192 tst r3, #LCD2_BUSY_MASK @
193 bne 20b @
194 str r7, [r0] @
195 str r11, [r0] @
196 @
197 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
198 add r12, r7, r7, asl #2 @
199 add r7, r12, r7, asl #5 @
200 @ compute R, G, and B
201 add r3, r8, r7, asr #8 @ r3 = b = (Y >> 9) + bu
202 add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv
203 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
204 @
205 orr r12, r3, r11 @ check if clamping is needed...
206 orr r12, r12, r7, asr #1 @ ...at all
207 cmp r12, #31 @
208 bls 15f @ no clamp @
209 cmp r3, #31 @ clamp b
210 mvnhi r3, r3, asr #31 @
211 andhi r3, r3, #31 @
212 cmp r11, #31 @ clamp r
213 mvnhi r11, r11, asr #31 @
214 andhi r11, r11, #31 @
215 cmp r7, #63 @ clamp g
216 mvnhi r7, r7, asr #31 @
217 andhi r7, r7, #63 @
21815: @ no clamp @
219 @
220 orr r3, r3, r11, lsl #11 @ r3 = b | (r << 11)
221 orr r3, r3, r7, lsl #5 @ r3 |= (g << 5)
222 @
223 orr r7, r14, r3, lsr #8 @ store pixel
224 orr r11, r14, r3 @
22520: @
226 ldr r3, [r0] @
227 tst r3, #LCD2_BUSY_MASK @
228 bne 20b @
229 str r7, [r0] @
230 str r11, [r0] @
231 @
232 subs r1, r1, #2 @ subtract block from width
233 bgt 10b @ loop line @
234 @
235 ldmpc regs=r4-r11 @ restore registers and return
236 .ltorg @ dump constant pool
237 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
238
239
240/****************************************************************************
241 * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
242 * int width,
243 * int stride,
244 * int x_screen,
245 * int y_screen);
246 *
247 * |R| |1.000000 -0.000001 1.402000| |Y'|
248 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
249 * |B| |1.000000 1.772000 0.000000| |Pr|
250 * Red scaled at twice g & b but at same precision to place it in correct
251 * bit position after multiply and leave instruction count lower.
252 * |R| |258 0 408| |Y' - 16|
253 * |G| = |149 -49 -104| |Cb - 128|
254 * |B| |149 258 0| |Cr - 128|
255 *
256 * Write four RGB565 pixels in the following order on each loop:
257 * 1 3 + > down
258 * 2 4 \/ left
259 *
260 * Kernel pattern (raw|use order):
261 * 5 3 4 2 row0 row2 > down
262 * 1 7 0 6 | 5 1 3 7 4 0 2 6 col0 left
263 * 4 2 5 3 | 4 0 2 6 5 1 3 7 col2 \/
264 * 0 6 1 7
265 */
266 .section .icode, "ax", %progbits
267 .align 2
268 .global lcd_write_yuv420_lines_odither
269 .type lcd_write_yuv420_lines_odither, %function
270lcd_write_yuv420_lines_odither:
271 @ r0 = yuv_src
272 @ r1 = width
273 @ r2 = stride
274 @ r3 = x_screen
275 @ [sp] = y_screen
276 stmfd sp!, { r4-r11, lr } @ save non-scratch
277 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
278 @ r5 = yuv_src[1] = Cb_p
279 @ r6 = yuv_src[2] = Cr_p
280 @
281 ldr r0, [sp, #36] @ Line up pattern and kernel quadrant
282 eor r14, r3, r0 @
283 and r14, r14, #0x2 @
284 mov r14, r14, lsl #6 @ 0x00 or 0x80
285 @
286 mov r0, #0x7000000c @ r0 = &LCD2_PORT = 0x70008a0c
287 add r0, r0, #0x8a00 @
288 @
289 sub r2, r2, #1 @ Adjust stride because of increment
29010: @ loop line @
291 @
292 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
293 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
294 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
295 @
296 eor r14, r14, #0x80 @ flip pattern quadrant
297 @
298 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149
299 add r12, r7, r7, asl #2 @
300 add r12, r12, r12, asl #4 @
301 add r7, r12, r7, asl #6 @
302 @
303 sub r8, r8, #128 @ Cb -= 128
304 sub r9, r9, #128 @ Cr -= 128
305 @
306 add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49
307 add r10, r10, r8, asl #5 @
308 add r10, r10, r9, asl #3 @
309 add r10, r10, r9, asl #5 @
310 add r10, r10, r9, asl #6 @
311 @
312 mov r8, r8, asl #1 @ r8 = bu = Cb*258
313 add r8, r8, r8, asl #7 @
314 @
315 add r9, r9, r9, asl #1 @ r9 = rv = Cr*408
316 add r9, r9, r9, asl #4 @
317 mov r9, r9, asl #3 @
318 @
319 @ compute R, G, and B
320 add r3, r8, r7 @ r3 = b' = Y + bu
321 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
322 rsb r7, r10, r7 @ r7 = g' = Y + guv
323 @
324 @ r8 = bu, r9 = rv, r10 = guv
325 @
326 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256
327 add r3, r12, r3, lsr #8 @
328 @
329 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
330 add r11, r12, r11, lsr #8 @
331 @
332 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
333 add r7, r12, r7, lsr #8 @
334 @
335 add r12, r14, #0x200 @
336 @
337 add r3, r3, r12 @ b = r3 + delta
338 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
339 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
340 @
341 orr r12, r3, r11, asr #1 @ check if clamping is needed...
342 orr r12, r12, r7 @ ...at all
343 movs r12, r12, asr #15 @
344 beq 15f @ no clamp @
345 movs r12, r3, asr #15 @ clamp b
346 mvnne r3, r12, lsr #15 @
347 andne r3, r3, #0x7c00 @ mask b only if clamped
348 movs r12, r11, asr #16 @ clamp r
349 mvnne r11, r12, lsr #16 @
350 movs r12, r7, asr #15 @ clamp g
351 mvnne r7, r12, lsr #15 @
35215: @ no clamp @
353 @
354 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
355 @
356 and r11, r11, #0xf800 @ pack pixel
357 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
358 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
359 orr r3, r11, r3, lsr #10 @ (b >> 10)
360 @
361 mov r11, #LCD2_DATA_MASK @ store pixel
362 orr r7, r11, r3, lsr #8 @
363 orr r11, r11, r3 @
36420: @
365 ldr r3, [r0] @
366 tst r3, #LCD2_BUSY_MASK @
367 bne 20b @
368 str r7, [r0] @
369 str r11, [r0] @
370 @
371 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
372 add r12, r7, r7, asl #2 @
373 add r12, r12, r12, asl #4 @
374 add r7, r12, r7, asl #6 @
375 @ compute R, G, and B
376 add r3, r8, r7 @ r3 = b' = Y + bu
377 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
378 rsb r7, r10, r7 @ r7 = g' = Y + guv
379 @
380 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256
381 add r3, r12, r3, lsr #8 @
382 @
383 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
384 add r11, r12, r11, lsr #8 @
385 @
386 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
387 add r7, r12, r7, lsr #8 @
388 @
389 @ This element is zero - use r14 @
390 @
391 add r3, r3, r14 @ b = r3 + delta
392 add r11, r11, r14, lsl #1 @ r = r11 + delta*2
393 add r7, r7, r14, lsr #1 @ g = r7 + delta/2
394 @
395 orr r12, r3, r11, asr #1 @ check if clamping is needed...
396 orr r12, r12, r7 @ ...at all
397 movs r12, r12, asr #15 @
398 beq 15f @ no clamp @
399 movs r12, r3, asr #15 @ clamp b
400 mvnne r3, r12, lsr #15 @
401 andne r3, r3, #0x7c00 @ mask b only if clamped
402 movs r12, r11, asr #16 @ clamp r
403 mvnne r11, r12, lsr #16 @
404 movs r12, r7, asr #15 @ clamp g
405 mvnne r7, r12, lsr #15 @
40615: @ no clamp @
407 @
408 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
409 @
410 and r11, r11, #0xf800 @ pack pixel
411 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
412 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
413 orr r3, r11, r3, lsr #10 @ (b >> 10)
414 @
415 mov r11, #LCD2_DATA_MASK @ store pixel
416 orr r7, r11, r3, lsr #8 @
417 orr r11, r11, r3 @
41820: @
419 ldr r3, [r0] @
420 tst r3, #LCD2_BUSY_MASK @
421 bne 20b @
422 str r7, [r0] @
423 str r11, [r0] @
424 @
425 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
426 add r12, r7, r7, asl #2 @
427 add r12, r12, r12, asl #4 @
428 add r7, r12, r7, asl #6 @
429 @ compute R, G, and B
430 add r3, r8, r7 @ r3 = b' = Y + bu
431 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
432 rsb r7, r10, r7 @ r7 = g' = Y + guv
433 @
434 @ r8 = bu, r9 = rv, r10 = guv
435 @
436 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b' + b'/256
437 add r3, r12, r3, lsr #8 @
438 @
439 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
440 add r11, r12, r11, lsr #8 @
441 @
442 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
443 add r7, r12, r7, lsr #8 @
444 @
445 add r12, r14, #0x100 @
446 @
447 add r3, r3, r12 @ b = r3 + delta
448 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
449 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
450 @
451 orr r12, r3, r11, asr #1 @ check if clamping is needed...
452 orr r12, r12, r7 @ ...at all
453 movs r12, r12, asr #15 @
454 beq 15f @ no clamp @
455 movs r12, r3, asr #15 @ clamp b
456 mvnne r3, r12, lsr #15 @
457 andne r3, r3, #0x7c00 @ mask b only if clamped
458 movs r12, r11, asr #16 @ clamp r
459 mvnne r11, r12, lsr #16 @
460 movs r12, r7, asr #15 @ clamp g
461 mvnne r7, r12, lsr #15 @
46215: @ no clamp @
463 @
464 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
465 @
466 and r11, r11, #0xf800 @ pack pixel
467 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
468 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
469 orr r3, r11, r3, lsr #10 @ (b >> 10)
470 @
471 mov r11, #LCD2_DATA_MASK @ store pixel
472 orr r7, r11, r3, lsr #8 @
473 orr r11, r11, r3 @
47420: @
475 ldr r3, [r0] @
476 tst r3, #LCD2_BUSY_MASK @
477 bne 20b @
478 str r7, [r0] @
479 str r11, [r0] @
480 @
481 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
482 add r12, r7, r7, asl #2 @
483 add r12, r12, r12, asl #4 @
484 add r7, r12, r7, asl #6 @
485 @ compute R, G, and B
486 add r3, r8, r7 @ r3 = b' = Y + bu
487 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
488 rsb r7, r10, r7 @ r7 = g' = Y + guv
489 @
490 sub r12, r3, r3, lsr #5 @ r3 = 31/32*b + b/256
491 add r3, r12, r3, lsr #8 @
492 @
493 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
494 add r11, r12, r11, lsr #8 @
495 @
496 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
497 add r7, r12, r7, lsr #8 @
498 @
499 add r12, r14, #0x300 @
500 @
501 add r3, r3, r12 @ b = r3 + delta
502 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
503 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
504 @
505 orr r12, r3, r11, asr #1 @ check if clamping is needed...
506 orr r12, r12, r7 @ ...at all
507 movs r12, r12, asr #15 @
508 beq 15f @ no clamp @
509 movs r12, r3, asr #15 @ clamp b
510 mvnne r3, r12, lsr #15 @
511 andne r3, r3, #0x7c00 @ mask b only if clamped
512 movs r12, r11, asr #16 @ clamp r
513 mvnne r11, r12, lsr #16 @
514 movs r12, r7, asr #15 @ clamp g
515 mvnne r7, r12, lsr #15 @
51615: @ no clamp @
517 @
518 and r11, r11, #0xf800 @ pack pixel
519 and r7, r7, #0x7e00 @ r3 = pixel = (r & 0xf800) |
520 orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) |
521 orr r3, r11, r3, lsr #10 @ (b >> 10)
522 @
523 mov r11, #LCD2_DATA_MASK @ store pixel
524 orr r7, r11, r3, lsr #8 @
525 orr r11, r11, r3 @
52620: @
527 ldr r3, [r0] @
528 tst r3, #LCD2_BUSY_MASK @
529 bne 20b @
530 str r7, [r0] @
531 str r11, [r0] @
532 @
533 subs r1, r1, #2 @ subtract block from width
534 bgt 10b @ loop line @
535 @
536 ldmpc regs=r4-r11 @ restore registers and return
537 .ltorg @ dump constant pool
538 .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither
diff --git a/firmware/target/arm/samsung/yh925/lcd-yh925.c b/firmware/target/arm/samsung/yh925/lcd-yh925.c
index e2b3ae3694..93bfb3a5f2 100644
--- a/firmware/target/arm/samsung/yh925/lcd-yh925.c
+++ b/firmware/target/arm/samsung/yh925/lcd-yh925.c
@@ -37,6 +37,8 @@ static unsigned short disp_control_rev;
37/* Contrast setting << 8 */ 37/* Contrast setting << 8 */
38static int lcd_contrast; 38static int lcd_contrast;
39 39
40static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
41
40/* Forward declarations */ 42/* Forward declarations */
41#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP) 43#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
42static void lcd_display_off(void); 44static void lcd_display_off(void);
@@ -508,6 +510,98 @@ bool lcd_active(void)
508 510
509/*** update functions ***/ 511/*** update functions ***/
510 512
513void lcd_yuv_set_options(unsigned options)
514{
515 lcd_yuv_options = options;
516}
517
518/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
519extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
520 int width,
521 int stride);
522extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
523 int width,
524 int stride,
525 int x_screen, /* To align dither pattern */
526 int y_screen);
527
528/* Performance function to blit a YUV bitmap directly to the LCD */
529void lcd_blit_yuv(unsigned char * const src[3],
530 int src_x, int src_y, int stride,
531 int x, int y, int width, int height)
532{
533 const unsigned char *yuv_src[3];
534 const unsigned char *ysrc_max;
535 int y0;
536 int options;
537
538 /* NOT MODIFIED FOR THE YH-925 */
539
540 if (!display_on)
541 return;
542
543 width &= ~1;
544 height &= ~1;
545
546 x += x_offset;
547
548 /* calculate the drawing region */
549
550 /* The 20GB LCD is actually 128x160 but rotated 90 degrees so the origin
551 * is actually the bottom left and horizontal and vertical are swapped.
552 * Rockbox expects the origin to be the top left so we need to use
553 * 127 - y instead of just y */
554
555 /* max vert << 8 | start vert */
556 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((x + width - 1) << 8) | x);
557
558 y0 = LCD_HEIGHT - 1 - y + y_offset;
559
560 /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=0, LG2-0=000 */
561 lcd_write_reg(R_ENTRY_MODE, 0x1020);
562
563 yuv_src[0] = src[0] + src_y * stride + src_x;
564 yuv_src[1] = src[1] + (src_y * stride >> 2) + (src_x >> 1);
565 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
566 ysrc_max = yuv_src[0] + height * stride;
567
568 options = lcd_yuv_options;
569
570 do
571 {
572 /* max horiz << 8 | start horiz */
573 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (y0 << 8) | (y0 - 1));
574
575 /* position cursor (set AD0-AD15) */
576 /* start vert << 8 | start horiz */
577 lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | y0);
578
579 /* start drawing */
580 lcd_send_cmd(R_WRITE_DATA_2_GRAM);
581
582 if (options & LCD_YUV_DITHER)
583 {
584 lcd_write_yuv420_lines_odither(yuv_src, width, stride,
585 x, y);
586 y -= 2;
587 }
588 else
589 {
590 lcd_write_yuv420_lines(yuv_src, width, stride);
591 }
592
593 y0 -= 2;
594 yuv_src[0] += stride << 1;
595 yuv_src[1] += stride >> 1;
596 yuv_src[2] += stride >> 1;
597 }
598 while (yuv_src[0] < ysrc_max);
599
600 /* DIT=0, BGR=1, HWM=0, I/D1-0=10, AM=1, LG2-0=000 */
601 lcd_write_reg(R_ENTRY_MODE, 0x1028);
602}
603
604
511/* Update a fraction of the display. */ 605/* Update a fraction of the display. */
512void lcd_update_rect(int x0, int y0, int width, int height) 606void lcd_update_rect(int x0, int y0, int width, int height)
513{ 607{
diff --git a/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S b/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S
new file mode 100644
index 0000000000..542ceeeb36
--- /dev/null
+++ b/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S
@@ -0,0 +1,550 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 by Jens Arnold
11 * Heavily based on lcd-as-memframe.c by Michael Sevakis
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23#include "config.h"
24#include "cpu.h"
25
26/****************************************************************************
27 * void lcd_write_yuv420_lines(unsigned char const * const src[3],
28 * int width,
29 * int stride);
30 *
31 * |R| |1.000000 -0.000001 1.402000| |Y'|
32 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
33 * |B| |1.000000 1.772000 0.000000| |Pr|
34 * Scaled, normalized, rounded and tweaked to yield RGB 565:
35 * |R| |74 0 101| |Y' - 16| >> 9
36 * |G| = |74 -24 -51| |Cb - 128| >> 8
37 * |B| |74 128 0| |Cr - 128| >> 9
38 *
39 * Write four RGB565 pixels in the following order on each loop:
40 * 1 3 + > down
41 * 2 4 \/ left
42 */
43 .section .icode, "ax", %progbits
44 .align 2
45 .global lcd_write_yuv420_lines
46 .type lcd_write_yuv420_lines, %function
47lcd_write_yuv420_lines:
48 @ r0 = yuv_src
49 @ r1 = width
50 @ r2 = stride
51 stmfd sp!, { r4-r10, lr } @ save non-scratch
52 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
53 @ r5 = yuv_src[1] = Cb_p
54 @ r6 = yuv_src[2] = Cr_p
55 @ r0 = scratch
56 sub r2, r2, #1 @
57 mov r3, #0x70000000 @
58 orr r3, r3, #0x3000 @ r3 = LCD1_BASE
5910: @ loop line @
60 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
61 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
62 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
63 @
64 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74
65 add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right
66 add r7, r12, r7, asl #5 @ by one less when adding - same for all
67 @
68 sub r8, r8, #128 @ Cb -= 128
69 sub r9, r9, #128 @ Cr -= 128
70 @
71 add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24
72 add r10, r10, r10, asl #4 @
73 add r10, r10, r8, asl #3 @
74 add r10, r10, r8, asl #4 @
75 @
76 add lr, r9, r9, asl #2 @ r9 = Cr*101
77 add lr, lr, r9, asl #5 @
78 add r9, lr, r9, asl #6 @
79 @
80 add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8
81 mov r8, r8, asr #2 @
82 add r9, r9, #256 @ r9 = rv = (r9 + 256) >> 9
83 mov r9, r9, asr #9 @
84 rsb r10, r10, #128 @ r10 = guv = (-r10 + 128) >> 8
85 mov r10, r10, asr #8 @
86 @ compute R, G, and B
87 add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu
88 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
89 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
90 @
91 orr r12, r0, lr @ check if clamping is needed...
92 orr r12, r12, r7, asr #1 @ ...at all
93 cmp r12, #31 @
94 bls 15f @ no clamp @
95 cmp r0, #31 @ clamp b
96 mvnhi r0, r0, asr #31 @
97 andhi r0, r0, #31 @
98 cmp lr, #31 @ clamp r
99 mvnhi lr, lr, asr #31 @
100 andhi lr, lr, #31 @
101 cmp r7, #63 @ clamp g
102 mvnhi r7, r7, asr #31 @
103 andhi r7, r7, #63 @
10415: @ no clamp @
105 @
106 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
107 @
108 mov lr, lr, lsl #3 @
109 orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3)
110 orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b
1111: @ busy @
112 ldr r7, [r3] @ r7 = LCD1_BASE
113 tst r7, #LCD1_BUSY_MASK @ bridge busy?
114 bne 1b @
115 str lr, [r3, #0x10] @ send MSB
1161: @busy @
117 ldr r7, [r3] @ r7 = LCD1_BASE
118 tst r7, #LCD1_BUSY_MASK @ bridge busy?
119 bne 1b @
120 str r0, [r3, #0x10] @ send LSB
121 @
122 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
123 add r12, r7, r7, asl #2 @
124 add r7, r12, r7, asl #5 @
125 @ compute R, G, and B
126 add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu
127 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
128 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
129 @
130 orr r12, r0, lr @ check if clamping is needed...
131 orr r12, r12, r7, asr #1 @ ...at all
132 cmp r12, #31 @
133 bls 15f @ no clamp @
134 cmp r0, #31 @ clamp b
135 mvnhi r0, r0, asr #31 @
136 andhi r0, r0, #31 @
137 cmp lr, #31 @ clamp r
138 mvnhi lr, lr, asr #31 @
139 andhi lr, lr, #31 @
140 cmp r7, #63 @ clamp g
141 mvnhi r7, r7, asr #31 @
142 andhi r7, r7, #63 @
14315: @ no clamp @
144 @
145 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
146 @
147 mov lr, lr, lsl #3 @
148 orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3)
149 orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b
1501: @ busy @
151 ldr r7, [r3] @ r7 = LCD1_BASE
152 tst r7, #LCD1_BUSY_MASK @ bridge busy?
153 bne 1b @
154 str lr, [r3, #0x10] @ send MSB
1551: @ busy @
156 ldr r7, [r3] @ r7 = LCD1_BASE
157 tst r7, #LCD1_BUSY_MASK @ bridge busy?
158 bne 1b @
159 str r0, [r3, #0x10] @ send LSB
160 @
161 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
162 add r12, r7, r7, asl #2 @
163 add r7, r12, r7, asl #5 @
164 @ compute R, G, and B
165 add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu
166 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
167 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
168 @
169 orr r12, r0, lr @ check if clamping is needed...
170 orr r12, r12, r7, asr #1 @ ...at all
171 cmp r12, #31 @
172 bls 15f @ no clamp @
173 cmp r0, #31 @ clamp b
174 mvnhi r0, r0, asr #31 @
175 andhi r0, r0, #31 @
176 cmp lr, #31 @ clamp r
177 mvnhi lr, lr, asr #31 @
178 andhi lr, lr, #31 @
179 cmp r7, #63 @ clamp g
180 mvnhi r7, r7, asr #31 @
181 andhi r7, r7, #63 @
18215: @ no clamp @
183 @
184 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
185 @
186 @
187 mov lr, lr, lsl #3 @
188 orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3)
189 orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b
1901: @ busy @
191 ldr r7, [r3] @ r7 = LCD1_BASE
192 tst r7, #LCD1_BUSY_MASK @ bridge busy?
193 bne 1b @
194 str lr, [r3, #0x10] @ send MSB
1951: @ busy @
196 ldr r7, [r3] @ r7 = LCD1_BASE
197 tst r7, #LCD1_BUSY_MASK @ bridge busy?
198 bne 1b @
199 str r0, [r3, #0x10] @ send LSB
200 @
201 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74
202 add r12, r7, r7, asl #2 @
203 add r7, r12, r7, asl #5 @
204 @ compute R, G, and B
205 add r0, r8, r7, asr #8 @ r0 = b = (Y >> 9) + bu
206 add lr, r9, r7, asr #8 @ lr = r = (Y >> 9) + rv
207 add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv
208 @
209 orr r12, r0, lr @ check if clamping is needed...
210 orr r12, r12, r7, asr #1 @ ...at all
211 cmp r12, #31 @
212 bls 15f @ no clamp @
213 cmp r0, #31 @ clamp b
214 mvnhi r0, r0, asr #31 @
215 andhi r0, r0, #31 @
216 cmp lr, #31 @ clamp r
217 mvnhi lr, lr, asr #31 @
218 andhi lr, lr, #31 @
219 cmp r7, #63 @ clamp g
220 mvnhi r7, r7, asr #31 @
221 andhi r7, r7, #63 @
22215: @ no clamp @
223 @
224 mov lr, lr, lsl #3 @
225 orr lr, lr, r7, lsr #3 @ lr = (r << 3) | (g >> 3)
226 orr r0, r0, r7, lsl #5 @ r0 = (g << 5) | b
2271: @ busy @
228 ldr r7, [r3] @ r7 = LCD1_BASE
229 tst r7, #LCD1_BUSY_MASK @ bridge busy?
230 bne 1b @
231 str lr, [r3, #0x10] @ send MSB
2321: @ busy @
233 ldr r7, [r3] @ r7 = LCD1_BASE
234 tst r7, #LCD1_BUSY_MASK @ bridge busy?
235 bne 1b @
236 str r0, [r3, #0x10] @ send LSB
237 @
238 subs r1, r1, #2 @ subtract block from width
239 bgt 10b @ loop line @
240 @
241 ldmpc regs=r4-r10 @ restore registers and return
242 .ltorg @ dump constant pool
243 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
244
245/****************************************************************************
246 * void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
247 * int width,
248 * int stride,
249 * int x_screen,
250 * int y_screen);
251 *
252 * |R| |1.000000 -0.000001 1.402000| |Y'|
253 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
254 * |B| |1.000000 1.772000 0.000000| |Pr|
255 * Red scaled at twice g & b but at same precision to place it in correct
256 * bit position after multiply and leave instruction count lower.
257 * |R| |258 0 408| |Y' - 16|
258 * |G| = |149 -49 -104| |Cb - 128|
259 * |B| |149 258 0| |Cr - 128|
260 *
261 * Write four RGB565 pixels in the following order on each loop:
262 * 1 3 + > down
263 * 2 4 \/ left
264 *
265 * Kernel pattern (raw|rotated|use order):
266 * 5 3 4 2 2 6 3 7 row0 row2 > down
267 * 1 7 0 6 | 4 0 5 1 | 2 4 6 0 3 5 7 1 col0 left
268 * 4 2 5 3 | 3 7 2 6 | 3 5 7 1 2 4 6 0 col2 \/
269 * 0 6 1 7 5 1 4 0
270 */
271 .section .icode, "ax", %progbits
272 .align 2
273 .global lcd_write_yuv420_lines_odither
274 .type lcd_write_yuv420_lines_odither, %function
275lcd_write_yuv420_lines_odither:
276 @ r0 = yuv_src
277 @ r1 = width
278 @ r2 = stride
279 @ r3 = x_screen
280 @ [sp] = y_screen
281 stmfd sp!, { r4-r11, lr } @ save non-scratch
282 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
283 @ r5 = yuv_src[1] = Cb_p
284 @ r6 = yuv_src[2] = Cr_p
285 @
286 sub r2, r2, #1 @
287 ldr r14, [sp, #36] @ Line up pattern and kernel quadrant
288 eor r14, r14, r3 @
289 and r14, r14, #0x2 @
290 mov r14, r14, lsl #6 @ 0x00 or 0x80
291 mov r3, #0x70000000 @
292 orr r3, r3, #0x3000 @ r3 = LCD1_BASE
29310: @ loop line @
294 @
295 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
296 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
297 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
298 @
299 eor r14, r14, #0x80 @ flip pattern quadrant
300 @
301 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149
302 add r12, r7, r7, asl #2 @
303 add r12, r12, r12, asl #4 @
304 add r7, r12, r7, asl #6 @
305 @
306 sub r8, r8, #128 @ Cb -= 128
307 sub r9, r9, #128 @ Cr -= 128
308 @
309 add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49
310 add r10, r10, r8, asl #5 @
311 add r10, r10, r9, asl #3 @
312 add r10, r10, r9, asl #5 @
313 add r10, r10, r9, asl #6 @
314 @
315 mov r8, r8, asl #1 @ r8 = bu = Cb*258
316 add r8, r8, r8, asl #7 @
317 @
318 add r9, r9, r9, asl #1 @ r9 = rv = Cr*408
319 add r9, r9, r9, asl #4 @
320 mov r9, r9, asl #3 @
321 @
322 @ compute R, G, and B
323 add r0, r8, r7 @ r0 = b' = Y + bu
324 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
325 rsb r7, r10, r7 @ r7 = g' = Y + guv
326 @
327 @ r8 = bu, r9 = rv, r10 = guv
328 @
329 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256
330 add r0, r12, r0, lsr #8 @
331 @
332 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
333 add r11, r12, r11, lsr #8 @
334 @
335 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
336 add r7, r12, r7, lsr #8 @
337 @
338 add r12, r14, #0x100 @
339 @
340 add r0, r0, r12 @ b = r0 + delta
341 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
342 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
343 @
344 orr r12, r0, r11, asr #1 @ check if clamping is needed...
345 orr r12, r12, r7 @ ...at all
346 movs r12, r12, asr #15 @
347 beq 15f @ no clamp @
348 movs r12, r0, asr #15 @ clamp b
349 mvnne r0, r12, lsr #15 @
350 andne r0, r0, #0x7c00 @ mask b only if clamped
351 movs r12, r11, asr #16 @ clamp r
352 mvnne r11, r12, lsr #16 @
353 movs r12, r7, asr #15 @ clamp g
354 mvnne r7, r12, lsr #15 @
35515: @ no clamp @
356 @
357 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
358 @
359
360 and r11, r11, #0xf800 @ pack pixel
361 mov r11, r11, lsr #8
362 and r7, r7, #0x7e00
363 orr r11, r11, r7, lsr #12
364 mov r7, r7, lsr#4
365 orr r0, r7, r0, lsr #10
3661: @ busy @
367 ldr r7, [r3] @ r7 = LCD1_BASE
368 tst r7, #LCD1_BUSY_MASK @ bridge busy?
369 bne 1b @
370 str r11, [r3, #0x10] @ send MSB
3711: @ busy @
372 ldr r7, [r3] @ r7 = LCD1_BASE
373 tst r7, #LCD1_BUSY_MASK @ bridge busy?
374 bne 1b @
375 str r0, [r3, #0x10] @ send LSB
376 @
377 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
378 add r12, r7, r7, asl #2 @
379 add r12, r12, r12, asl #4 @
380 add r7, r12, r7, asl #6 @
381 @ compute R, G, and B
382 add r0, r8, r7 @ r0 = b' = Y + bu
383 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
384 rsb r7, r10, r7 @ r7 = g' = Y + guv
385 @
386 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256
387 add r0, r12, r0, lsr #8 @
388 @
389 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
390 add r11, r12, r11, lsr #8 @
391 @
392 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
393 add r7, r12, r7, lsr #8 @
394 @
395 add r12, r14, #0x200 @
396 @
397 add r0, r0, r12 @ b = r0 + delta
398 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
399 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
400 @
401 orr r12, r0, r11, asr #1 @ check if clamping is needed...
402 orr r12, r12, r7 @ ...at all
403 movs r12, r12, asr #15 @
404 beq 15f @ no clamp @
405 movs r12, r0, asr #15 @ clamp b
406 mvnne r0, r12, lsr #15 @
407 andne r0, r0, #0x7c00 @ mask b only if clamped
408 movs r12, r11, asr #16 @ clamp r
409 mvnne r11, r12, lsr #16 @
410 movs r12, r7, asr #15 @ clamp g
411 mvnne r7, r12, lsr #15 @
41215: @ no clamp @
413 @
414 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
415
416 and r11, r11, #0xf800 @ pack pixel
417 mov r11, r11, lsr #8
418 and r7, r7, #0x7e00
419 orr r11, r11, r7, lsr #12
420 mov r7, r7, lsr#4
421 orr r0, r7, r0, lsr #10
4221: @ busy @
423 ldr r7, [r3] @ r7 = LCD1_BASE
424 tst r7, #LCD1_BUSY_MASK @ bridge busy?
425 bne 1b @
426 str r11, [r3, #0x10] @ send MSB
4271: @ busy @
428 ldr r7, [r3] @ r7 = LCD1_BASE
429 tst r7, #LCD1_BUSY_MASK @ bridge busy?
430 bne 1b @
431 str r0, [r3, #0x10] @ send LSB
432
433 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
434 add r12, r7, r7, asl #2 @
435 add r12, r12, r12, asl #4 @
436 add r7, r12, r7, asl #6 @
437 @ compute R, G, and B
438 add r0, r8, r7 @ r0 = b' = Y + bu
439 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
440 rsb r7, r10, r7 @ r7 = g' = Y + guv
441 @
442 @ r8 = bu, r9 = rv, r10 = guv
443 @
444 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256
445 add r0, r12, r0, lsr #8 @
446 @
447 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
448 add r11, r12, r11, lsr #8 @
449 @
450 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
451 add r7, r12, r7, lsr #8 @
452 @
453 add r12, r14, #0x300 @
454 @
455 add r0, r0, r12 @ b = r0 + delta
456 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
457 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
458 @
459 orr r12, r0, r11, asr #1 @ check if clamping is needed...
460 orr r12, r12, r7 @ ...at all
461 movs r12, r12, asr #15 @
462 beq 15f @ no clamp @
463 movs r12, r0, asr #15 @ clamp b
464 mvnne r0, r12, lsr #15 @
465 andne r0, r0, #0x7c00 @ mask b only if clamped
466 movs r12, r11, asr #16 @ clamp r
467 mvnne r11, r12, lsr #16 @
468 movs r12, r7, asr #15 @ clamp g
469 mvnne r7, r12, lsr #15 @
47015: @ no clamp @
471 @
472 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
473
474 and r11, r11, #0xf800 @ pack pixel
475 mov r11, r11, lsr #8
476 and r7, r7, #0x7e00
477 orr r11, r11, r7, lsr #12
478 mov r7, r7, lsr#4
479 orr r0, r7, r0, lsr #10
4801: @ busy @
481 ldr r7, [r3] @ r7 = LCD1_BASE
482 tst r7, #LCD1_BUSY_MASK @ bridge busy?
483 bne 1b @
484 str r11, [r3, #0x10] @ send MSB
4851: @ busy @
486 ldr r7, [r3] @ r7 = LCD1_BASE
487 tst r7, #LCD1_BUSY_MASK @ bridge busy?
488 bne 1b @
489 str r0, [r3, #0x10] @ send LSB
490
491 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
492 add r12, r7, r7, asl #2 @
493 add r12, r12, r12, asl #4 @
494 add r7, r12, r7, asl #6 @
495 @ compute R, G, and B
496 add r0, r8, r7 @ r0 = b' = Y + bu
497 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
498 rsb r7, r10, r7 @ r7 = g' = Y + guv
499 @
500 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256
501 add r0, r12, r0, lsr #8 @
502 @
503 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
504 add r11, r12, r11, lsr #8 @
505 @
506 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
507 add r7, r12, r7, lsr #8 @
508 @
509 @ This element is zero - use r14 @
510 @
511 add r0, r0, r14 @ b = r0 + delta
512 add r11, r11, r14, lsl #1 @ r = r11 + delta*2
513 add r7, r7, r14, lsr #1 @ g = r7 + delta/2
514 @
515 orr r12, r0, r11, asr #1 @ check if clamping is needed...
516 orr r12, r12, r7 @ ...at all
517 movs r12, r12, asr #15 @
518 beq 15f @ no clamp @
519 movs r12, r0, asr #15 @ clamp b
520 mvnne r0, r12, lsr #15 @
521 andne r0, r0, #0x7c00 @ mask b only if clamped
522 movs r12, r11, asr #16 @ clamp r
523 mvnne r11, r12, lsr #16 @
524 movs r12, r7, asr #15 @ clamp g
525 mvnne r7, r12, lsr #15 @
52615: @ no clamp @
527
528 and r11, r11, #0xf800 @ pack pixel
529 mov r11, r11, lsr #8
530 and r7, r7, #0x7e00
531 orr r11, r11, r7, lsr #12
532 mov r7, r7, lsr#4
533 orr r0, r7, r0, lsr #10
5341: @ busy @
535 ldr r7, [r3] @ r7 = LCD1_BASE
536 tst r7, #LCD1_BUSY_MASK @ bridge busy?
537 bne 1b @
538 str r11, [r3, #0x10] @ send MSB
5391: @ busy @
540 ldr r7, [r3] @ r7 = LCD1_BASE
541 tst r7, #LCD1_BUSY_MASK @ bridge busy?
542 bne 1b @
543 str r0, [r3, #0x10] @ send LSB
544
545 subs r1, r1, #2 @ subtract block from width
546 bgt 10b @ loop line @
547 @
548 ldmpc regs=r4-r11 @ restore registers and return
549 .ltorg @ dump constant pool
550 .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither
diff --git a/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c b/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c
index e851c421a6..8620c672e1 100644
--- a/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c
+++ b/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c
@@ -273,7 +273,15 @@ void lcd_init_device(void)
273#if defined(HAVE_LCD_MODES) 273#if defined(HAVE_LCD_MODES)
274void lcd_set_mode(int mode) 274void lcd_set_mode(int mode)
275{ 275{
276 if(mode==LCD_MODE_RGB565) { 276 if(mode==LCD_MODE_YUV) {
277 /* Turn off the RGB buffer and enable the YUV buffer with zoom */
278 IO_OSD_OSDWINMD0 |= 0x04;
279 IO_OSD_VIDWINMD |= 0x01;
280#if LCD_NATIVE_WIDTH > 240
281 IO_OSD_VIDWINMD |= (0x05<<2); /* This does a 2x zoom */
282#endif
283 memset16(FRAME2, 0x0080, LCD_NATIVE_HEIGHT*(LCD_NATIVE_WIDTH+LCD_FUDGE));
284 } else if(mode==LCD_MODE_RGB565) {
277 /* Turn on the RGB window, set it to 16 bit and turn YUV window off */ 285 /* Turn on the RGB window, set it to 16 bit and turn YUV window off */
278 IO_OSD_VIDWINMD &= ~(0x01); 286 IO_OSD_VIDWINMD &= ~(0x01);
279 IO_OSD_OSDWIN0OFST = LCD_NATIVE_WIDTH / 16; 287 IO_OSD_OSDWIN0OFST = LCD_NATIVE_WIDTH / 16;
@@ -636,6 +644,82 @@ void lcd_pal256_update_pal(fb_data *palette)
636} 644}
637#endif 645#endif
638 646
647/* Performance function to blit a YUV bitmap directly to the LCD */
648/* Show it rotated so the LCD_WIDTH is now the height */
649void lcd_blit_yuv(unsigned char * const src[3],
650 int src_x, int src_y, int stride,
651 int x, int y, int width, int height)
652{
653 unsigned char const * yuv_src[3];
654
655 if (!lcd_on)
656 return;
657
658 /* y has to be on a 16 pixel boundary */
659 y &= ~0xF;
660
661 if( ((y | x | height | width ) < 0)
662 || y>LCD_NATIVE_HEIGHT || x>LCD_NATIVE_WIDTH )
663 return;
664
665 if(y+height>LCD_NATIVE_WIDTH)
666 {
667 height=LCD_NATIVE_WIDTH-y;
668 }
669 if(x+width>LCD_NATIVE_HEIGHT)
670 {
671 width=LCD_NATIVE_HEIGHT-x;
672 }
673
674 /* Sorry, but width and height must be >= 2 or else */
675 width &= ~1;
676 height>>=1;
677
678 fb_data * dst = FRAME2
679 + ((LCD_NATIVE_WIDTH+LCD_FUDGE)*(LCD_NATIVE_HEIGHT-1))
680 - (LCD_NATIVE_WIDTH+LCD_FUDGE)*x + y ;
681
682 /* Scope z */
683 {
684 off_t z;
685 z = stride*src_y;
686 yuv_src[0] = src[0] + z + src_x;
687 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
688 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
689 }
690
691 int cbcr_remain=(stride>>1)-(width>>1);
692 int y_remain=(stride<<1)-width;
693 do
694 {
695 register int c_width=width;
696 register unsigned int *c_dst=(unsigned int*)dst;
697 do
698 {
699 register unsigned short Y=*((unsigned short*)yuv_src[0]);
700 register unsigned short Yst=*((unsigned short*)(yuv_src[0]+stride));
701 yuv_src[0]+=2;
702
703 register unsigned char Cb=*yuv_src[1]++;
704 register unsigned char Cr=*yuv_src[2]++;
705
706 *c_dst = (Yst<<24) | (Cr << 16) | ((Y&0xFF)<<8) | Cb;
707 *(c_dst - (LCD_NATIVE_WIDTH+LCD_FUDGE)/2) =
708 ( (Yst&0xFF00)<<16) | (Cr << 16) | (Y&0xFF00) | Cb;
709
710 c_dst -= (LCD_NATIVE_WIDTH+LCD_FUDGE);
711
712 c_width -= 2;
713 } while (c_width);
714
715 yuv_src[0] += y_remain; /* Skip down two luma lines-width */
716 yuv_src[1] += cbcr_remain; /* Skip down one chroma line-width/2 */
717 yuv_src[2] += cbcr_remain;
718
719 dst+=2;
720 } while (--height);
721}
722
639void lcd_set_contrast(int val) { 723void lcd_set_contrast(int val) {
640 (void) val; 724 (void) val;
641 // TODO: 725 // TODO:
diff --git a/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S b/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S
index b319d745ca..e6621e1dea 100644
--- a/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S
+++ b/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S
@@ -25,6 +25,248 @@
25 25
26 .section .icode,"ax",@progbits 26 .section .icode,"ax",@progbits
27 27
28/* begin lcd_write_yuv420_lines
29 *
30 * See http://en.wikipedia.org/wiki/YCbCr
31 * ITU-R BT.601 (formerly CCIR 601):
32 * |Y'| | 0.299000 0.587000 0.114000| |R|
33 * |Pb| = |-0.168736 -0.331264 0.500000| |G| or 0.564334*(B - Y')
34 * |Pr| | 0.500000 -0.418688 0.081312| |B| or 0.713267*(R - Y')
35 * Scaled, normalized and rounded:
36 * |Y'| | 65 129 25| |R| + 16 : 16->235
37 * |Cb| = |-38 -74 112| |G| + 128 : 16->240
38 * |Cr| |112 -94 -18| |B| + 128 : 16->240
39 *
40 * The inverse:
41 * |R| |1.000000 -0.000001 1.402000| |Y'|
42 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
43 * |B| |1.000000 1.772000 0.000000| |Pr|
44 * Scaled, normalized, rounded and tweaked to yield RGB 666:
45 * |R| |19611723 0 26881894| |Y' - 16| >> 26
46 * |G| = |19611723 -6406711 -13692816| |Cb - 128| >> 26
47 * |B| |19611723 33976259 0| |Cr - 128| >> 26
48 *
49 * Needs EMAC set to saturated, signed integer mode.
50 *
51 * register usage:
52 * %a0 - LCD data port
53 * %a1 - Y pointer
54 * %a2 - C pointer
55 * %a3 - C width
56 * %a4 - Y end address
57 * %a5 - Y factor
58 * %a6 - BU factor
59 * %d0 - scratch
60 * %d1 - B, previous Y \ alternating
61 * %d2 - U / B, previous Y /
62 * %d3 - V / G
63 * %d4 - R / output pixel
64 * %d5 - GU factor
65 * %d6 - GV factor
66 * %d7 - RGB signed -> unsigned conversion mask
67 */
68 .align 2
69 .global lcd_write_yuv420_lines
70 .type lcd_write_yuv420_lines, @function
71
72lcd_write_yuv420_lines:
73 lea.l (-44, %sp), %sp /* free up some registers */
74 movem.l %d2-%d7/%a2-%a6, (%sp)
75
76 lea.l 0xf0008002, %a0 /* LCD data port */
77 movem.l (44+4, %sp), %a1-%a3 /* Y data, C data, C width */
78 lea.l (%a1, %a3*2), %a4 /* Y end address */
79
80 move.l #19611723, %a5 /* y factor */
81 move.l #33976259, %a6 /* bu factor */
82 move.l #-6406711, %d5 /* gu factor */
83 move.l #-13692816, %d6 /* gv factor */
84 move.l #0x01040820, %d7 /* bitmask for signed->unsigned conversion
85 * of R, G and B within RGGB6666 at once */
86
87 /* chroma for first 2x2 block */
88 clr.l %d3 /* load v component */
89 move.b (%a2, %a3), %d3
90 clr.l %d2 /* load u component */
91 move.b (%a2)+, %d2
92 moveq.l #-128, %d0
93 add.l %d0, %d2
94 add.l %d0, %d3
95
96 mac.l %a6, %d2, %acc0 /* bu */
97 mac.l %d5, %d2, %acc1 /* gu */
98 mac.l %d6, %d3, %acc1 /* gv */
99 move.l #26881894, %d0 /* rv factor */
100 mac.l %d0, %d3, %acc2 /* rv */
101
102 /* luma for very first pixel (top left) */
103 clr.l %d1
104 move.b (%a1, %a3*2), %d1
105 moveq.l #-126, %d0
106 add.l %d1, %d0 /* y' (-0.5 ... +0.5) */
107 mac.l %a5, %d0, %acc0
108 mac.l %a5, %d0, %acc1
109 mac.l %a5, %d0, %acc2
110
111 bra.b .yuv_line_entry
112
113.yuv_line_loop:
114 /* chroma for 2x2 pixel block */
115 clr.l %d3 /* load v component */
116 move.b (%a2, %a3), %d3
117 clr.l %d2 /* load u component */
118 move.b (%a2)+, %d2
119 moveq.l #-128, %d0
120 add.l %d0, %d2
121 add.l %d0, %d3
122
123 mac.l %a6, %d2, %acc0 /* bu */
124 mac.l %d5, %d2, %acc1 /* gu */
125 mac.l %d6, %d3, %acc1 /* gv */
126 move.l #26881894, %d0 /* rv factor */
127 mac.l %d0, %d3, %acc2 /* rv */
128
129 /* luma for first pixel (top left) */
130 clr.l %d1
131 move.b (%a1, %a3*2), %d1
132 moveq.l #-126, %d0
133 add.l %d1, %d0 /* y' (-0.5 ... +0.5) */
134 mac.l %a5, %d0, %acc0
135 mac.l %a5, %d0, %acc1
136 mac.l %a5, %d0, %acc2
137
138 move.w %d4, (%a0)
139 /* 2nd LCD write is delayed one pixel to use it for filling the EMAC latency */
140
141 /* convert to RGB666, pack and output */
142.yuv_line_entry:
143 moveq.l #26, %d0
144 move.l %acc0, %d4
145 move.l %acc1, %d3
146 move.l %acc2, %d2
147 lsr.l %d0, %d4
148 lsr.l %d0, %d3
149 lsr.l %d0, %d2
150
151 lsl.l #6, %d2
152 or.l %d3, %d2 /* |00000000|00000000|0000Rrrr|rrGggggg| */
153 lsl.l #7, %d2
154 or.l %d2, %d3 /* |00000000|00000Rrr|rrrGgggg|g0Gggggg| */
155 lsl.l #6, %d3
156 or.l %d3, %d4 /* |0000000R|rrrrrGgg|ggg0Gggg|ggBbbbbb| */
157 eor.l %d7, %d4 /* |0000000r|rrrrrggg|ggg0gggg|ggbbbbbb| */
158 swap %d4
159 move.w %d4, (%a0)
160 swap %d4
161
162 /* luma for second pixel (bottom left) as delta from the first */
163 clr.l %d2
164 move.b (%a1)+, %d2
165 move.l %d2, %d0
166 sub.l %d1, %d0
167 mac.l %a5, %d0, %acc0
168 mac.l %a5, %d0, %acc1
169 mac.l %a5, %d0, %acc2
170
171 move.w %d4, (%a0)
172 /* 2nd LCD write is delayed one pixel to use it for filling the EMAC latency */
173
174 /* convert to RGB666, pack and output */
175 moveq.l #26, %d0
176 move.l %acc0, %d4
177 move.l %acc1, %d3
178 move.l %acc2, %d1
179 lsr.l %d0, %d4
180 lsr.l %d0, %d3
181 lsr.l %d0, %d1
182
183 lsl.l #6, %d1
184 or.l %d3, %d1 /* |00000000|00000000|0000Rrrr|rrGggggg| */
185 lsl.l #7, %d1
186 or.l %d1, %d3 /* |00000000|00000Rrr|rrrGgggg|g0Gggggg| */
187 lsl.l #6, %d3
188 or.l %d3, %d4 /* |0000000R|rrrrrGgg|ggg0Gggg|ggBbbbbb| */
189 eor.l %d7, %d4 /* |0000000r|rrrrrggg|ggg0gggg|ggbbbbbb| */
190 swap %d4
191 move.w %d4, (%a0)
192 swap %d4
193
194 /* luma for third pixel (top right) as delta from the second */
195 clr.l %d1
196 move.b (%a1, %a3*2), %d1
197 move.l %d1, %d0
198 sub.l %d2, %d0
199 mac.l %a5, %d0, %acc0
200 mac.l %a5, %d0, %acc1
201 mac.l %a5, %d0, %acc2
202
203 move.w %d4, (%a0)
204 /* 2nd LCD write is delayed one pixel to use it for filling the EMAC latency */
205
206 /* convert to RGB666, pack and output */
207 moveq.l #26, %d0
208 move.l %acc0, %d4
209 move.l %acc1, %d3
210 move.l %acc2, %d2
211 lsr.l %d0, %d4
212 lsr.l %d0, %d3
213 lsr.l %d0, %d2
214
215 lsl.l #6, %d2
216 or.l %d3, %d2 /* |00000000|00000000|0000Rrrr|rrGggggg| */
217 lsl.l #7, %d2
218 or.l %d2, %d3 /* |00000000|00000Rrr|rrrGgggg|g0Gggggg| */
219 lsl.l #6, %d3
220 or.l %d3, %d4 /* |0000000R|rrrrrGgg|ggg0Gggg|ggBbbbbb| */
221 eor.l %d7, %d4 /* |0000000r|rrrrrggg|ggg0gggg|ggbbbbbb| */
222 swap %d4
223 move.w %d4, (%a0)
224 swap %d4
225
226 /* luma for fourth pixel (bottom right) as delta from the thrid */
227 clr.l %d2
228 move.b (%a1)+, %d2
229 move.l %d2, %d0
230 sub.l %d1, %d0
231 mac.l %a5, %d0, %acc0
232 mac.l %a5, %d0, %acc1
233 mac.l %a5, %d0, %acc2
234
235 move.w %d4, (%a0)
236 /* 2nd LCD write is delayed one pixel to use it for filling the EMAC latency */
237
238 /* convert to RGB666, pack and output */
239 moveq.l #26, %d0
240 movclr.l %acc0, %d4
241 movclr.l %acc1, %d3
242 movclr.l %acc2, %d1
243 lsr.l %d0, %d4
244 lsr.l %d0, %d3
245 lsr.l %d0, %d1
246
247 lsl.l #6, %d1
248 or.l %d3, %d1 /* |00000000|00000000|0000Rrrr|rrGggggg| */
249 lsl.l #7, %d1
250 or.l %d1, %d3 /* |00000000|00000Rrr|rrrGgggg|g0Gggggg| */
251 lsl.l #6, %d3
252 or.l %d3, %d4 /* |0000000R|rrrrrGgg|ggg0Gggg|ggBbbbbb| */
253 eor.l %d7, %d4 /* |0000000r|rrrrrggg|ggg0gggg|ggbbbbbb| */
254 swap %d4
255 move.w %d4, (%a0)
256 swap %d4
257
258 cmp.l %a1, %a4 /* run %a1 up to end of line */
259 bhi.w .yuv_line_loop
260
261 move.w %d4, (%a0) /* write (very) last 2nd word */
262
263 movem.l (%sp), %d2-%d7/%a2-%a6
264 lea.l (44, %sp), %sp /* restore registers */
265 rts
266.yuv_end:
267 .size lcd_write_yuv420_lines, .yuv_end - lcd_write_yuv420_lines
268
269
28/* begin lcd_write_data */ 270/* begin lcd_write_data */
29 .align 2 271 .align 2
30 .global lcd_write_data 272 .global lcd_write_data
diff --git a/firmware/target/coldfire/iaudio/x5/lcd-x5.c b/firmware/target/coldfire/iaudio/x5/lcd-x5.c
index a6a4fc0176..266a381c40 100644
--- a/firmware/target/coldfire/iaudio/x5/lcd-x5.c
+++ b/firmware/target/coldfire/iaudio/x5/lcd-x5.c
@@ -414,6 +414,69 @@ bool lcd_active(void)
414#endif 414#endif
415/*** update functions ***/ 415/*** update functions ***/
416 416
417/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420.
418 * y should have two lines of Y back to back, 2nd line first.
419 * c should contain the Cb and Cr data for the two lines of Y back to back.
420 * Needs EMAC set to saturated, signed integer mode.
421 */
422extern void lcd_write_yuv420_lines(const unsigned char *y,
423 const unsigned char *c, int width);
424
425/* Performance function to blit a YUV bitmap directly to the LCD
426 * src_x, src_y, width and height should be even and within the LCD's
427 * boundaries.
428 */
429void lcd_blit_yuv(unsigned char * const src[3],
430 int src_x, int src_y, int stride,
431 int x, int y, int width, int height)
432{
433 /* IRAM Y, Cb/bu, guv and Cb/rv buffers. */
434 unsigned char y_ibuf[LCD_WIDTH*2];
435 unsigned char c_ibuf[LCD_WIDTH];
436 const unsigned char *ysrc, *usrc, *vsrc;
437 const unsigned char *ysrc_max;
438
439 if (!display_on)
440 return;
441
442 width &= ~1; /* stay on the safe side */
443 height &= ~1;
444
445 lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_DIT_HORZ);
446 /* Set start position and window */
447 lcd_write_reg(R_VERT_RAM_ADDR_POS, (LCD_WIDTH-1) << 8);
448
449 ysrc = src[0] + src_y * stride + src_x;
450 usrc = src[1] + (src_y * stride >> 2) + (src_x >> 1);
451 vsrc = src[2] + (src_y * stride >> 2) + (src_x >> 1);
452 ysrc_max = ysrc + height * stride;
453
454 unsigned long macsr = coldfire_get_macsr();
455 coldfire_set_macsr(EMAC_SATURATE);
456
457 do
458 {
459 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, ((y + y_offset + 1) << 8) | (y + y_offset));
460 lcd_write_reg(R_RAM_ADDR_SET, (x << 8) | (y + y_offset));
461 lcd_begin_write_gram();
462
463 memcpy(y_ibuf + width, ysrc, width);
464 memcpy(y_ibuf, ysrc + stride, width);
465 memcpy(c_ibuf, usrc, width >> 1);
466 memcpy(c_ibuf + (width >> 1), vsrc, width >> 1);
467 lcd_write_yuv420_lines(y_ibuf, c_ibuf, width >> 1);
468
469 y += 2;
470 ysrc += 2 * stride;
471 usrc += stride >> 1;
472 vsrc += stride >> 1;
473 }
474 while (ysrc < ysrc_max);
475
476 coldfire_set_macsr(macsr);
477} /* lcd_yuv_blit */
478
479
417/* Update the display. 480/* Update the display.
418 This must be called after all other LCD functions that change the 481 This must be called after all other LCD functions that change the
419 lcd frame buffer. */ 482 lcd frame buffer. */
diff --git a/firmware/target/coldfire/iriver/h300/lcd-as-h300.S b/firmware/target/coldfire/iriver/h300/lcd-as-h300.S
new file mode 100644
index 0000000000..223c183860
--- /dev/null
+++ b/firmware/target/coldfire/iriver/h300/lcd-as-h300.S
@@ -0,0 +1,246 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Jens Arnold
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23#include "cpu.h"
24
25 .section .icode, "ax", @progbits
26
27/* lcd_write_yuv420_lines()
28 *
29 * See http://en.wikipedia.org/wiki/YCbCr
30 * ITU-R BT.601 (formerly CCIR 601):
31 * |Y'| | 0.299000 0.587000 0.114000| |R|
32 * |Pb| = |-0.168736 -0.331264 0.500000| |G| or 0.564334*(B - Y')
33 * |Pr| | 0.500000 -0.418688 0.081312| |B| or 0.713267*(R - Y')
34 * Scaled, normalized and rounded:
35 * |Y'| | 65 129 25| |R| + 16 : 16->235
36 * |Cb| = |-38 -74 112| |G| + 128 : 16->240
37 * |Cr| |112 -94 -18| |B| + 128 : 16->240
38 *
39 * The inverse:
40 * |R| |1.000000 0.000000 1.402000| |Y'|
41 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
42 * |B| |1.000000 1.772000 0.000000| |Pr|
43 * Scaled, normalized, rounded and tweaked to yield RGB565:
44 * |R| |19611723 0 26881894| |Y' - 16| >> 27
45 * |G| = |19611723 -6406711 -13692816| |Cb - 128| >> 26
46 * |B| |19611723 33976259 0| |Cr - 128| >> 27
47 *
48 * Needs EMAC set to saturated, signed integer mode.
49 *
50 * register usage:
51 * %a0 - LCD data port
52 * %a1 - Y pointer
53 * %a2 - C pointer
54 * %a3 - C width
55 * %a4 - Y end address
56 * %a5 - Y factor
57 * %a6 - BU factor
58 * %d0 - scratch
59 * %d1 - B, previous Y \ alternating
60 * %d2 - U / B, previous Y /
61 * %d3 - V / G
62 * %d4 - R / output pixel
63 * %d5 - GU factor
64 * %d6 - GV factor
65 * %d7 - RGB signed -> unsigned conversion mask
66 */
67 .align 2
68 .global lcd_write_yuv420_lines
69 .type lcd_write_yuv420_lines, @function
70
71lcd_write_yuv420_lines:
72 lea.l (-44, %sp), %sp /* free up some registers */
73 movem.l %d2-%d7/%a2-%a6, (%sp)
74
75 lea.l 0xf0000002, %a0 /* LCD data port */
76 movem.l (44+4, %sp), %a1-%a3 /* Y data, C data, C width */
77 lea.l (%a1, %a3*2), %a4 /* Y end address */
78
79 move.l #19611723, %a5 /* y factor */
80 move.l #33976259, %a6 /* bu factor */
81 move.l #-6406711, %d5 /* gu factor */
82 move.l #-13692816, %d6 /* gv factor */
83 move.l #0x8410, %d7 /* bitmask for signed->unsigned conversion
84 * of R, G and B within RGB565 at once */
85
86 /* chroma for first 2x2 pixel block */
87 clr.l %d3 /* load v component */
88 move.b (%a2, %a3), %d3
89 clr.l %d2 /* load u component */
90 move.b (%a2)+, %d2
91 moveq.l #-128, %d0
92 add.l %d0, %d2
93 add.l %d0, %d3
94
95 mac.l %a6, %d2, %acc0 /* bu */
96 mac.l %d5, %d2, %acc1 /* gu */
97 mac.l %d6, %d3, %acc1 /* gv */
98 move.l #26881894, %d0 /* rv factor */
99 mac.l %d0, %d3, %acc2 /* rv */
100
101 /* luma for very first pixel (top left) */
102 clr.l %d1
103 move.b (%a1, %a3*2), %d1
104 moveq.l #-126, %d0
105 add.l %d1, %d0 /* y' (-0.5 ... +0.5) */
106 mac.l %a5, %d0, %acc0
107 mac.l %a5, %d0, %acc1
108 mac.l %a5, %d0, %acc2
109
110 bra.b .yuv_line_entry
111
112.yuv_line_loop:
113 /* chroma for 2x2 pixel block */
114 clr.l %d3 /* load v component */
115 move.b (%a2, %a3), %d3
116 clr.l %d2 /* load u component */
117 move.b (%a2)+, %d2
118 moveq.l #-128, %d0
119 add.l %d0, %d2
120 add.l %d0, %d3
121
122 mac.l %a6, %d2, %acc0 /* bu */
123 mac.l %d5, %d2, %acc1 /* gu */
124 mac.l %d6, %d3, %acc1 /* gv */
125 move.l #26881894, %d0 /* rv factor */
126 mac.l %d0, %d3, %acc2 /* rv */
127
128 /* luma for first pixel (top left) */
129 clr.l %d1
130 move.b (%a1, %a3*2), %d1
131 moveq.l #-126, %d0
132 add.l %d1, %d0 /* y' (-0.5 ... +0.5) */
133 mac.l %a5, %d0, %acc0
134 mac.l %a5, %d0, %acc1
135 mac.l %a5, %d0, %acc2
136
137 move.w %d4, (%a0)
138 /* LCD write is delayed one pixel to use it for filling the EMAC latency */
139
140 /* convert to RGB565, pack and output */
141.yuv_line_entry:
142 moveq.l #27, %d0
143 move.l %acc0, %d2
144 move.l %acc1, %d3
145 move.l %acc2, %d4
146 lsr.l %d0, %d2
147 lsr.l %d0, %d4
148 moveq.l #26, %d0
149 lsr.l %d0, %d3
150 lsl.l #6, %d4
151 or.l %d3, %d4
152 lsl.l #5, %d4
153 or.l %d2, %d4
154 eor.l %d7, %d4
155
156 /* luma for second pixel (bottom left) as delta from the first */
157 clr.l %d2
158 move.b (%a1)+, %d2
159 move.l %d2, %d0
160 sub.l %d1, %d0
161 mac.l %a5, %d0, %acc0
162 mac.l %a5, %d0, %acc1
163 mac.l %a5, %d0, %acc2
164
165 move.w %d4, (%a0)
166 /* LCD write is delayed one pixel to use it for filling the EMAC latency */
167
168 /* convert to RGB565, pack and output */
169 moveq.l #27, %d0
170 move.l %acc0, %d1
171 move.l %acc1, %d3
172 move.l %acc2, %d4
173 lsr.l %d0, %d1
174 lsr.l %d0, %d4
175 moveq.l #26, %d0
176 lsr.l %d0, %d3
177 lsl.l #6, %d4
178 or.l %d3, %d4
179 lsl.l #5, %d4
180 or.l %d1, %d4
181 eor.l %d7, %d4
182
183 /* luma for third pixel (top right) as delta from the second */
184 clr.l %d1
185 move.b (%a1, %a3*2), %d1
186 move.l %d1, %d0
187 sub.l %d2, %d0
188 mac.l %a5, %d0, %acc0
189 mac.l %a5, %d0, %acc1
190 mac.l %a5, %d0, %acc2
191
192 move.w %d4, (%a0)
193 /* LCD write is delayed one pixel to use it for filling the EMAC latency */
194
195 /* convert to RGB565, pack and output */
196 moveq.l #27, %d0
197 move.l %acc0, %d2
198 move.l %acc1, %d3
199 move.l %acc2, %d4
200 lsr.l %d0, %d2
201 lsr.l %d0, %d4
202 moveq.l #26, %d0
203 lsr.l %d0, %d3
204 lsl.l #6, %d4
205 or.l %d3, %d4
206 lsl.l #5, %d4
207 or.l %d2, %d4
208 eor.l %d7, %d4
209
210 /* luma for fourth pixel (bottom right) as delta from the third */
211 clr.l %d2
212 move.b (%a1)+, %d2
213 move.l %d2, %d0
214 sub.l %d1, %d0
215 mac.l %a5, %d0, %acc0
216 mac.l %a5, %d0, %acc1
217 mac.l %a5, %d0, %acc2
218
219 move.w %d4, (%a0)
220 /* LCD write is delayed one pixel to use it for filling the EMAC latency */
221
222 /* convert to RGB565, pack and output */
223 moveq.l #27, %d0
224 movclr.l %acc0, %d1
225 movclr.l %acc1, %d3
226 movclr.l %acc2, %d4
227 lsr.l %d0, %d1
228 lsr.l %d0, %d4
229 moveq.l #26, %d0
230 lsr.l %d0, %d3
231 lsl.l #6, %d4
232 or.l %d3, %d4
233 lsl.l #5, %d4
234 or.l %d1, %d4
235 eor.l %d7, %d4
236
237 cmp.l %a1, %a4 /* run %a1 up to end of line */
238 bhi.w .yuv_line_loop
239
240 move.w %d4, (%a0) /* write (very) last pixel */
241
242 movem.l (%sp), %d2-%d7/%a2-%a6
243 lea.l (44, %sp), %sp /* restore registers */
244 rts
245.yuv_end:
246 .size lcd_write_yuv420_lines, .yuv_end - lcd_write_yuv420_lines
diff --git a/firmware/target/coldfire/iriver/h300/lcd-h300.c b/firmware/target/coldfire/iriver/h300/lcd-h300.c
index 8d5370cdcf..7e73ea3905 100644
--- a/firmware/target/coldfire/iriver/h300/lcd-h300.c
+++ b/firmware/target/coldfire/iriver/h300/lcd-h300.c
@@ -325,6 +325,67 @@ bool lcd_active(void)
325 325
326/*** update functions ***/ 326/*** update functions ***/
327 327
328/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420.
329 * y should have two lines of Y back to back, 2nd line first.
330 * c should contain the Cb and Cr data for the two lines of Y back to back.
331 * Needs EMAC set to saturated, signed integer mode.
332 */
333extern void lcd_write_yuv420_lines(const unsigned char *y,
334 const unsigned char *c, int cwidth);
335
336/* Performance function to blit a YUV bitmap directly to the LCD
337 * src_x, src_y, width and height should be even
338 * x, y, width and height have to be within LCD bounds
339 */
340void lcd_blit_yuv(unsigned char * const src[3],
341 int src_x, int src_y, int stride,
342 int x, int y, int width, int height)
343{
344 /* IRAM Y, Cb and Cb buffers. */
345 unsigned char y_ibuf[LCD_WIDTH*2];
346 unsigned char c_ibuf[LCD_WIDTH];
347 const unsigned char *ysrc, *usrc, *vsrc;
348 const unsigned char *ysrc_max;
349
350 if (!display_on)
351 return;
352
353 LCD_MUTEX_LOCK();
354 width &= ~1; /* stay on the safe side */
355 height &= ~1;
356
357 lcd_write_reg(R_ENTRY_MODE, R_ENTRY_MODE_HORZ);
358 /* Set start position and window */
359 lcd_write_reg(R_VERT_RAM_ADDR_POS, ((xoffset + 219) << 8) | xoffset);
360
361 ysrc = src[0] + src_y * stride + src_x;
362 usrc = src[1] + (src_y * stride >> 2) + (src_x >> 1);
363 vsrc = src[2] + (src_y * stride >> 2) + (src_x >> 1);
364 ysrc_max = ysrc + height * stride;
365
366 coldfire_set_macsr(EMAC_SATURATE);
367 do
368 {
369 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, ((y + 1) << 8) | y);
370 lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y);
371 lcd_begin_write_gram();
372
373 memcpy(y_ibuf + width, ysrc, width);
374 memcpy(y_ibuf, ysrc + stride, width);
375 memcpy(c_ibuf, usrc, width >> 1);
376 memcpy(c_ibuf + (width >> 1), vsrc, width >> 1);
377 lcd_write_yuv420_lines(y_ibuf, c_ibuf, width >> 1);
378
379 y += 2;
380 ysrc += 2 * stride;
381 usrc += stride >> 1;
382 vsrc += stride >> 1;
383 }
384 while (ysrc < ysrc_max)
385 ;;
386 LCD_MUTEX_UNLOCK();
387}
388
328#ifndef BOOTLOADER 389#ifndef BOOTLOADER
329/* LCD DMA ISR */ 390/* LCD DMA ISR */
330void DMA3(void) __attribute__ ((interrupt_handler, section(".icode"))); 391void DMA3(void) __attribute__ ((interrupt_handler, section(".icode")));
diff --git a/firmware/target/mips/ingenic_jz47xx/lcd-jz4740.c b/firmware/target/mips/ingenic_jz47xx/lcd-jz4740.c
index d2a1d759d0..a2d5b73ea8 100644
--- a/firmware/target/mips/ingenic_jz47xx/lcd-jz4740.c
+++ b/firmware/target/mips/ingenic_jz47xx/lcd-jz4740.c
@@ -158,3 +158,65 @@ void lcd_update(void)
158 158
159 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); 159 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
160} 160}
161
162/* (Mis)use LCD framebuffer as a temporary buffer */
163void lcd_blit_yuv(unsigned char * const src[3],
164 int src_x, int src_y, int stride,
165 int x, int y, int width, int height)
166{
167 unsigned char const * yuv_src[3];
168 register off_t z;
169
170 if(!lcd_is_on)
171 return;
172
173 z = stride * src_y;
174 yuv_src[0] = src[0] + z + src_x;
175 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
176 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
177
178 commit_discard_dcache(); // XXX range
179
180 __cpm_start_ipu();
181
182 IPU_STOP_IPU();
183 IPU_RESET_IPU();
184 IPU_CLEAR_END_FLAG();
185
186 IPU_DISABLE_RSIZE();
187 IPU_DISABLE_IRQ();
188
189 IPU_SET_INFMT(INFMT_YUV420);
190 IPU_SET_OUTFMT(OUTFMT_RGB565);
191
192 IPU_SET_IN_FM(width, height);
193 IPU_SET_Y_STRIDE(stride);
194 IPU_SET_UV_STRIDE(stride, stride);
195
196 IPU_SET_Y_ADDR(PHYSADDR((unsigned long)yuv_src[0]));
197 IPU_SET_U_ADDR(PHYSADDR((unsigned long)yuv_src[1]));
198 IPU_SET_V_ADDR(PHYSADDR((unsigned long)yuv_src[2]));
199 IPU_SET_OUT_ADDR(PHYSADDR((unsigned long)FBADDR(y,x)));
200
201 IPU_SET_OUT_FM(height, width);
202 IPU_SET_OUT_STRIDE(height);
203
204 IPU_SET_CSC_C0_COEF(YUV_CSC_C0);
205 IPU_SET_CSC_C1_COEF(YUV_CSC_C1);
206 IPU_SET_CSC_C2_COEF(YUV_CSC_C2);
207 IPU_SET_CSC_C3_COEF(YUV_CSC_C3);
208 IPU_SET_CSC_C4_COEF(YUV_CSC_C4);
209
210 IPU_RUN_IPU();
211
212 while(!(IPU_POLLING_END_FLAG()) && IPU_IS_ENABLED());
213
214 IPU_CLEAR_END_FLAG();
215 IPU_STOP_IPU();
216 IPU_RESET_IPU();
217
218 __cpm_stop_ipu();
219
220 /* YUV speed is limited by LCD speed */
221 lcd_update_rect(y, x, height, width);
222}