freemyipod r513 - Code Review

Jump to: navigation, search
Repository:freemyipod
Revision:r512‎ | r513 | r514 >
Date:19:08, 4 February 2011
Author:theseven
Status:new
Tags:
Comment:
emCORE: Assembler-optimized dithering on iPod Classic (10% performance gain)
Modified paths:
  • /emcore/trunk/target/ipodnano3g/lcd.c (modified) (history)

Diff [purge]

Index: emcore/trunk/target/ipodnano3g/lcd.c
@@ -1,323 +1,378 @@
2 -//
3 -//
4 -// Copyright 2010 TheSeven
5 -//
6 -//
7 -// This file is part of emCORE.
8 -//
9 -// emCORE is free software: you can redistribute it and/or
10 -// modify it under the terms of the GNU General Public License as
11 -// published by the Free Software Foundation, either version 2 of the
12 -// License, or (at your option) any later version.
13 -//
14 -// emCORE is distributed in the hope that it will be useful,
15 -// but WITHOUT ANY WARRANTY; without even the implied warranty of
16 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 -// See the GNU General Public License for more details.
18 -//
19 -// You should have received a copy of the GNU General Public License along
20 -// with emCORE. If not, see <http://www.gnu.org/licenses/>.
21 -//
22 -//
23 -
24 -
25 -#include "global.h"
26 -#include "thread.h"
27 -#include "s5l8702.h"
28 -#include "util.h"
29 -
30 -
31 -static struct dma_lli lcd_lli[(LCD_WIDTH * LCD_HEIGHT - 1) / 0xfff]
32 - IDATA_ATTR __attribute__((aligned(16)));
33 -
34 -static uint16_t lcd_color IDATA_ATTR;
35 -
36 -static struct mutex lcd_mutex;
37 -
38 -
39 -void lcd_init()
40 -{
41 -}
42 -
43 -int lcd_get_width()
44 -{
45 - return LCD_WIDTH;
46 -}
47 -
48 -int lcd_get_height()
49 -{
50 - return LCD_HEIGHT;
51 -}
52 -
53 -int lcd_get_bytes_per_pixel()
54 -{
55 - return LCD_BYTESPERPIXEL;
56 -}
57 -
58 -int lcd_get_format()
59 -{
60 - return LCD_FORMAT;
61 -}
62 -
63 -static void lcd_send_cmd(uint16_t cmd) ICODE_ATTR __attribute__((noinline));
64 -static void lcd_send_cmd(uint16_t cmd)
65 -{
66 - while (LCDSTATUS & 0x10);
67 - LCDWCMD = cmd;
68 -}
69 -
70 -static void lcd_send_data(uint16_t data) ICODE_ATTR __attribute__((noinline));
71 -static void lcd_send_data(uint16_t data)
72 -{
73 - while (LCDSTATUS & 0x10);
74 - LCDWDATA = (data & 0xff) | ((data & 0x7f00) << 1);
75 -}
76 -
77 -static uint32_t lcd_detect() ICODE_ATTR;
78 -static uint32_t lcd_detect()
79 -{
80 - return (PDAT6 & 0x30) >> 4;
81 -}
82 -
83 -bool displaylcd_busy() ICODE_ATTR;
84 -bool displaylcd_busy()
85 -{
86 - return DMAC0C4CONFIG & 1;
87 -}
88 -
89 -bool displaylcd_safe()
90 -{
91 - return !(DMAC0C4CONFIG & 1);
92 -}
93 -
94 -void displaylcd_sync() ICODE_ATTR;
95 -void displaylcd_sync()
96 -{
97 - mutex_lock(&lcd_mutex, TIMEOUT_BLOCK);
98 - while (displaylcd_busy()) sleep(100);
99 - mutex_unlock(&lcd_mutex);
100 -}
101 -
102 -void displaylcd_setup(unsigned int startx, unsigned int endx,
103 - unsigned int starty, unsigned int endy) ICODE_ATTR;
104 -void displaylcd_setup(unsigned int startx, unsigned int endx,
105 - unsigned int starty, unsigned int endy)
106 -{
107 - mutex_lock(&lcd_mutex, TIMEOUT_BLOCK);
108 - displaylcd_sync();
109 - if (lcd_detect() & 2)
110 - {
111 - lcd_send_cmd(0x210);
112 - lcd_send_data(startx);
113 - lcd_send_cmd(0x211);
114 - lcd_send_data(endx);
115 - lcd_send_cmd(0x212);
116 - lcd_send_data(starty);
117 - lcd_send_cmd(0x213);
118 - lcd_send_data(endy);
119 - lcd_send_cmd(0x200);
120 - lcd_send_data(startx);
121 - lcd_send_cmd(0x201);
122 - lcd_send_data(starty);
123 - lcd_send_cmd(0x202);
124 - }
125 - else
126 - {
127 - lcd_send_cmd(0x2a);
128 - lcd_send_data(startx >> 8);
129 - lcd_send_data(startx & 0xff);
130 - lcd_send_data(endx >> 8);
131 - lcd_send_data(endx & 0xff);
132 - lcd_send_cmd(0x2b);
133 - lcd_send_data(starty >> 8);
134 - lcd_send_data(starty & 0xff);
135 - lcd_send_data(endy >> 8);
136 - lcd_send_data(endy & 0xff);
137 - lcd_send_cmd(0x2c);
138 - }
139 -}
140 -
141 -static void displaylcd_dma(void* data, int pixels, bool solid) ICODE_ATTR;
142 -static void displaylcd_dma(void* data, int pixels, bool solid)
143 -{
144 - int i;
145 - for (i = -1; i < (int)ARRAYLEN(lcd_lli) && pixels > 0; i++, pixels -= 0xfff)
146 - {
147 - bool last = i + 1 >= ARRAYLEN(lcd_lli) || pixels <= 0xfff;
148 - struct dma_lli* lli = i < 0 ? (struct dma_lli*)((int)&DMAC0C4LLI) : &lcd_lli[i];
149 - lli->srcaddr = data;
150 - lli->dstaddr = (void*)((int)&LCDWDATA);
151 - lli->nextlli = last ? NULL : &lcd_lli[i + 1];
152 - lli->control = 0x70240000 | (last ? pixels : 0xfff)
153 - | (last ? 0x80000000 : 0) | (solid ? 0 : 0x4000000);
154 - data = (void*)(((uint32_t)data) + 0x1ffe);
155 - }
156 - clean_dcache();
157 - DMAC0C4CONFIG = 0x88c1;
158 -}
159 -
160 -void displaylcd_native(unsigned int startx, unsigned int endx,
161 - unsigned int starty, unsigned int endy, void* data)
162 -{
163 - int pixels = (endx - startx + 1) * (endy - starty + 1);
164 - if (pixels <= 0) return;
165 - displaylcd_setup(startx, endx, starty, endy);
166 - displaylcd_dma(data, pixels, false);
167 - mutex_unlock(&lcd_mutex);
168 -}
169 -
170 -void filllcd_native(unsigned int startx, unsigned int endx,
171 - unsigned int starty, unsigned int endy, int color)
172 -{
173 - int pixels = (endx - startx + 1) * (endy - starty + 1);
174 - if (pixels <= 0) return;
175 - displaylcd_setup(startx, endx, starty, endy);
176 - lcd_color = color;
177 - displaylcd_dma(&lcd_color, pixels, true);
178 - mutex_unlock(&lcd_mutex);
179 -}
180 -
181 -void displaylcd_dither(unsigned int x, unsigned int y, unsigned int width,
182 - unsigned int height, void* data, unsigned int datax,
183 - unsigned int datay, unsigned int stride, bool solid) ICODE_ATTR;
184 -void displaylcd_dither(unsigned int x, unsigned int y, unsigned int width,
185 - unsigned int height, void* data, unsigned int datax,
186 - unsigned int datay, unsigned int stride, bool solid)
187 -{
188 - int pixels = width * height;
189 - if (pixels <= 0) return;
190 - displaylcd_setup(x, x + width - 1, y, y + height - 1);
191 - int corrsize = width * 3;
192 - signed char* corr = (signed char*)malloc(corrsize);
193 - if (!corr)
194 - {
195 - mutex_unlock(&lcd_mutex);
196 - return;
197 - }
198 - memset(corr, 0, corrsize);
199 - unsigned char* in = (unsigned char*)data + (stride * datay + datax) * 3;
200 - for (y = 0; y < height; y++)
201 - {
202 - int i;
203 - signed char* corrptr = corr;
204 - signed char lastcorr[3] = {0};
205 - for (x = 0; x < width; x++)
206 - {
207 - unsigned int pixel = 0;
208 - signed char* lastcorrptr = lastcorr;
209 - int orig = *in++ + *corrptr + *lastcorrptr;
210 - orig = MAX(0, MIN(255, orig));
211 - unsigned int real = orig >> 3;
212 - pixel |= real << 11;
213 - int err = orig - ((real << 3) | (real >> 2));
214 - *corrptr++ = (*lastcorrptr >> 1) + err >> 2;
215 - *lastcorrptr++ = err >> 1;
216 - orig = *in++ + *corrptr + *lastcorrptr;
217 - orig = MAX(0, MIN(255, orig));
218 - real = orig >> 2;
219 - pixel |= real << 5;
220 - err = orig - ((real << 2) | (real >> 4));
221 - *corrptr++ = (*lastcorrptr >> 1) + err >> 2;
222 - *lastcorrptr++ = err >> 1;
223 - orig = *in++ + *corrptr + *lastcorrptr;
224 - orig = MAX(0, MIN(255, orig));
225 - real = orig >> 3;
226 - pixel |= real;
227 - err = orig - ((real << 3) | (real >> 2));
228 - *corrptr++ = (*lastcorrptr >> 1) + err >> 2;
229 - *lastcorrptr++ = err >> 1;
230 - while (LCDSTATUS & 0x10);
231 - LCDWDATA = pixel;
232 - if (solid) in -= 3;
233 - }
234 - if (solid) in += stride * 3;
235 - else in += (stride - width) * 3;
236 - }
237 - free(corr);
238 - mutex_unlock(&lcd_mutex);
239 -}
240 -
241 -void displaylcd(unsigned int x, unsigned int y, unsigned int width, unsigned int height,
242 - void* data, unsigned int datax, unsigned int datay, unsigned int stride)
243 -{
244 - displaylcd_dither(x, y, width, height, data, datax, datay, stride, false);
245 -}
246 -
247 -void filllcd(unsigned int x, unsigned int y, unsigned int width, unsigned int height, int color)
248 -{
249 - if (width * height <= 0) return;
250 - mutex_lock(&lcd_mutex, TIMEOUT_BLOCK);
251 - lcd_color = color;
252 - displaylcd_dither(x, y, width, height, &lcd_color, 0, 0, 0, true);
253 - mutex_unlock(&lcd_mutex);
254 -}
255 -
256 -void lcd_shutdown()
257 -{
258 - displaylcd_sync();
259 - uint32_t type = lcd_detect();
260 - if (type & 2)
261 - {
262 - lcd_send_cmd(0x7);
263 - lcd_send_data(0x172);
264 - lcd_send_cmd(0x30);
265 - lcd_send_data(0x3ff);
266 - sleep(90000);
267 - lcd_send_cmd(0x7);
268 - lcd_send_data(0x120);
269 - lcd_send_cmd(0x30);
270 - lcd_send_data(0x0);
271 - lcd_send_cmd(0x100);
272 - lcd_send_data(0x780);
273 - lcd_send_cmd(0x7);
274 - lcd_send_data(0x0);
275 - lcd_send_cmd(0x101);
276 - lcd_send_data(0x260);
277 - lcd_send_cmd(0x102);
278 - lcd_send_data(0xa9);
279 - sleep(30000);
280 - lcd_send_cmd(0x100);
281 - lcd_send_data(0x700);
282 - lcd_send_cmd(0x100);
283 - lcd_send_data(0x704);
284 - }
285 - else if (type == 1)
286 - {
287 - lcd_send_cmd(0x28);
288 - lcd_send_cmd(0x10);
289 - sleep(100000);
290 - }
291 - else
292 - {
293 - lcd_send_cmd(0x28);
294 - sleep(50000);
295 - lcd_send_cmd(0x10);
296 - sleep(50000);
297 - }
298 -}
299 -
300 -void INT_DMAC0C4()
301 -{
302 - DMAC0INTTCCLR = 0x10;
303 - lcdconsole_callback();
304 -}
305 -
306 -int lcd_translate_color(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue)
307 - ICODE_ATTR __attribute__((naked, noinline));
308 -int lcd_translate_color(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue)
309 -{
310 - asm volatile(
311 - "cmp r0, #0xff \n\t"
312 - "moveq r0, #-1 \n\t"
313 - "moveq pc, lr \n\t"
314 - "cmp r0, #0 \n\t"
315 - "movne r0, #0xff000000 \n\t"
316 - "orrne r0, r0, #0xff0000 \n\t"
317 - "mov r2, r2,lsr#2 \n\t"
318 - "orr r0, r0, r3,lsr#3 \n\t"
319 - "mov r1, r1,lsr#3 \n\t"
320 - "orr r0, r0, r2,lsl#5 \n\t"
321 - "orr r0, r0, r1,lsl#11 \n\t"
322 - "mov pc, lr \n\t"
323 - );
324 -}
 2+//
 3+//
 4+// Copyright 2010 TheSeven
 5+//
 6+//
 7+// This file is part of emCORE.
 8+//
 9+// emCORE is free software: you can redistribute it and/or
 10+// modify it under the terms of the GNU General Public License as
 11+// published by the Free Software Foundation, either version 2 of the
 12+// License, or (at your option) any later version.
 13+//
 14+// emCORE is distributed in the hope that it will be useful,
 15+// but WITHOUT ANY WARRANTY; without even the implied warranty of
 16+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 17+// See the GNU General Public License for more details.
 18+//
 19+// You should have received a copy of the GNU General Public License along
 20+// with emCORE. If not, see <http://www.gnu.org/licenses/>.
 21+//
 22+//
 23+
 24+
 25+#include "global.h"
 26+#include "thread.h"
 27+#include "s5l8702.h"
 28+#include "util.h"
 29+
 30+
 31+static struct dma_lli lcd_lli[(LCD_WIDTH * LCD_HEIGHT - 1) / 0xfff]
 32+ IDATA_ATTR __attribute__((aligned(16)));
 33+
 34+static uint16_t lcd_color IDATA_ATTR;
 35+
 36+static struct mutex lcd_mutex;
 37+
 38+
 39+void lcd_init()
 40+{
 41+}
 42+
 43+int lcd_get_width()
 44+{
 45+ return LCD_WIDTH;
 46+}
 47+
 48+int lcd_get_height()
 49+{
 50+ return LCD_HEIGHT;
 51+}
 52+
 53+int lcd_get_bytes_per_pixel()
 54+{
 55+ return LCD_BYTESPERPIXEL;
 56+}
 57+
 58+int lcd_get_format()
 59+{
 60+ return LCD_FORMAT;
 61+}
 62+
 63+static void lcd_send_cmd(uint16_t cmd) ICODE_ATTR __attribute__((noinline));
 64+static void lcd_send_cmd(uint16_t cmd)
 65+{
 66+ while (LCDSTATUS & 0x10);
 67+ LCDWCMD = cmd;
 68+}
 69+
 70+static void lcd_send_data(uint16_t data) ICODE_ATTR __attribute__((noinline));
 71+static void lcd_send_data(uint16_t data)
 72+{
 73+ while (LCDSTATUS & 0x10);
 74+ LCDWDATA = (data & 0xff) | ((data & 0x7f00) << 1);
 75+}
 76+
 77+static uint32_t lcd_detect() ICODE_ATTR;
 78+static uint32_t lcd_detect()
 79+{
 80+ return (PDAT6 & 0x30) >> 4;
 81+}
 82+
 83+bool displaylcd_busy() ICODE_ATTR;
 84+bool displaylcd_busy()
 85+{
 86+ return DMAC0C4CONFIG & 1;
 87+}
 88+
 89+bool displaylcd_safe()
 90+{
 91+ return !(DMAC0C4CONFIG & 1);
 92+}
 93+
 94+void displaylcd_sync() ICODE_ATTR;
 95+void displaylcd_sync()
 96+{
 97+ mutex_lock(&lcd_mutex, TIMEOUT_BLOCK);
 98+ while (displaylcd_busy()) sleep(100);
 99+ mutex_unlock(&lcd_mutex);
 100+}
 101+
 102+void displaylcd_setup(unsigned int startx, unsigned int endx,
 103+ unsigned int starty, unsigned int endy) ICODE_ATTR;
 104+void displaylcd_setup(unsigned int startx, unsigned int endx,
 105+ unsigned int starty, unsigned int endy)
 106+{
 107+ mutex_lock(&lcd_mutex, TIMEOUT_BLOCK);
 108+ displaylcd_sync();
 109+ if (lcd_detect() & 2)
 110+ {
 111+ lcd_send_cmd(0x210);
 112+ lcd_send_data(startx);
 113+ lcd_send_cmd(0x211);
 114+ lcd_send_data(endx);
 115+ lcd_send_cmd(0x212);
 116+ lcd_send_data(starty);
 117+ lcd_send_cmd(0x213);
 118+ lcd_send_data(endy);
 119+ lcd_send_cmd(0x200);
 120+ lcd_send_data(startx);
 121+ lcd_send_cmd(0x201);
 122+ lcd_send_data(starty);
 123+ lcd_send_cmd(0x202);
 124+ }
 125+ else
 126+ {
 127+ lcd_send_cmd(0x2a);
 128+ lcd_send_data(startx >> 8);
 129+ lcd_send_data(startx & 0xff);
 130+ lcd_send_data(endx >> 8);
 131+ lcd_send_data(endx & 0xff);
 132+ lcd_send_cmd(0x2b);
 133+ lcd_send_data(starty >> 8);
 134+ lcd_send_data(starty & 0xff);
 135+ lcd_send_data(endy >> 8);
 136+ lcd_send_data(endy & 0xff);
 137+ lcd_send_cmd(0x2c);
 138+ }
 139+}
 140+
 141+static void displaylcd_dma(void* data, int pixels, bool solid) ICODE_ATTR;
 142+static void displaylcd_dma(void* data, int pixels, bool solid)
 143+{
 144+ int i;
 145+ for (i = -1; i < (int)ARRAYLEN(lcd_lli) && pixels > 0; i++, pixels -= 0xfff)
 146+ {
 147+ bool last = i + 1 >= ARRAYLEN(lcd_lli) || pixels <= 0xfff;
 148+ struct dma_lli* lli = i < 0 ? (struct dma_lli*)((int)&DMAC0C4LLI) : &lcd_lli[i];
 149+ lli->srcaddr = data;
 150+ lli->dstaddr = (void*)((int)&LCDWDATA);
 151+ lli->nextlli = last ? NULL : &lcd_lli[i + 1];
 152+ lli->control = 0x70240000 | (last ? pixels : 0xfff)
 153+ | (last ? 0x80000000 : 0) | (solid ? 0 : 0x4000000);
 154+ data = (void*)(((uint32_t)data) + 0x1ffe);
 155+ }
 156+ clean_dcache();
 157+ DMAC0C4CONFIG = 0x88c1;
 158+}
 159+
 160+void displaylcd_native(unsigned int startx, unsigned int endx,
 161+ unsigned int starty, unsigned int endy, void* data)
 162+{
 163+ int pixels = (endx - startx + 1) * (endy - starty + 1);
 164+ if (pixels <= 0) return;
 165+ displaylcd_setup(startx, endx, starty, endy);
 166+ displaylcd_dma(data, pixels, false);
 167+ mutex_unlock(&lcd_mutex);
 168+}
 169+
 170+void filllcd_native(unsigned int startx, unsigned int endx,
 171+ unsigned int starty, unsigned int endy, int color)
 172+{
 173+ int pixels = (endx - startx + 1) * (endy - starty + 1);
 174+ if (pixels <= 0) return;
 175+ displaylcd_setup(startx, endx, starty, endy);
 176+ lcd_color = color;
 177+ displaylcd_dma(&lcd_color, pixels, true);
 178+ mutex_unlock(&lcd_mutex);
 179+}
 180+
 181+void displaylcd_dither(unsigned int x, unsigned int y, unsigned int width,
 182+ unsigned int height, void* data, unsigned int datax,
 183+ unsigned int datay, unsigned int stride, bool solid)
 184+ ICODE_ATTR __attribute__((naked,noinline));
 185+void displaylcd_dither(unsigned int x, unsigned int y, unsigned int width,
 186+ unsigned int height, void* data, unsigned int datax,
 187+ unsigned int datay, unsigned int stride, bool solid)
 188+{
 189+ __asm__ volatile(" muls r12, r2, r3 \n");
 190+ __asm__ volatile(" bxeq lr \n");
 191+ __asm__ volatile(" stmfd sp!, {r2-r11,lr} \n");
 192+ __asm__ volatile(" mov r12, r2 \n");
 193+ __asm__ volatile(" add r8, r2, r2,lsl#1 \n");
 194+ __asm__ volatile(" add r3, r1, r3 \n");
 195+ __asm__ volatile(" sub r3, r3, #1 \n");
 196+ __asm__ volatile(" mov r2, r1 \n");
 197+ __asm__ volatile(" add r1, r0, r12 \n");
 198+ __asm__ volatile(" sub r1, r1, #1 \n");
 199+ __asm__ volatile(" bl displaylcd_setup \n");
 200+ __asm__ volatile(" mov r0, r8 \n");
 201+ __asm__ volatile(" bl malloc \n");
 202+ __asm__ volatile(" cmp r0, #0 \n");
 203+ __asm__ volatile(" beq displaylcd_dither_unlock \n");
 204+ __asm__ volatile(" mov r2, r8 \n");
 205+ __asm__ volatile(" mov r1, #0 \n");
 206+ __asm__ volatile(" mov r8, r0 \n");
 207+ __asm__ volatile(" bl memset \n");
 208+ __asm__ volatile(" ldr r0, [sp,#0x30] \n");
 209+ __asm__ volatile(" ldr r1, [sp,#0x34] \n");
 210+ __asm__ volatile(" ldr r11, [sp,#0x38] \n");
 211+ __asm__ volatile(" ldr r3, [sp,#0x2c] \n");
 212+ __asm__ volatile(" mla r0, r1, r11, r0 \n");
 213+ __asm__ volatile(" ldr r12, [sp,#0x04] \n");
 214+ __asm__ volatile(" ldr r2, [sp,#0x3c] \n");
 215+ __asm__ volatile(" add r3, r3, r0,lsl#1 \n");
 216+ __asm__ volatile(" cmp r2, #0 \n");
 217+ __asm__ volatile(" ldreq r1, [sp] \n");
 218+ __asm__ volatile(" add r3, r3, r0 \n");
 219+ __asm__ volatile(" subeq r11, r11, r1 \n");
 220+ __asm__ volatile(" add r11, r11, r11,lsl#1 \n");
 221+ __asm__ volatile(" movne r10, #3 \n");
 222+ __asm__ volatile(" moveq r10, #0 \n");
 223+ __asm__ volatile(" ldr r9, =0x38300040 \n");
 224+ __asm__ volatile("displaylcd_dither_y: \n");
 225+ __asm__ volatile(" ldr lr, [sp] \n");
 226+ __asm__ volatile(" mov r4, #0 \n");
 227+ __asm__ volatile(" mov r5, #0 \n");
 228+ __asm__ volatile(" mov r6, #0 \n");
 229+ __asm__ volatile(" mov r7, r8 \n");
 230+ __asm__ volatile("displaylcd_dither_x: \n");
 231+ __asm__ volatile(" mov r2, #0 \n");
 232+ __asm__ volatile(" ldrb r1, [r3], #1 \n");
 233+ __asm__ volatile(" ldrsb r0, [r7] \n");
 234+ __asm__ volatile(" add r1, r1, r4 \n");
 235+ __asm__ volatile(" add r1, r1, r0 \n");
 236+ __asm__ volatile(" cmp r1, #0 \n");
 237+ __asm__ volatile(" movlt r1, #0 \n");
 238+ __asm__ volatile(" cmp r1, #0xff \n");
 239+ __asm__ volatile(" movgt r1, #0xff \n");
 240+ __asm__ volatile(" mov r0, r1,lsr#3 \n");
 241+ __asm__ volatile(" orr r2, r0,lsl#11 \n");
 242+ __asm__ volatile(" sub r1, r1, r0,lsl#3 \n");
 243+ __asm__ volatile(" sub r1, r1, r0,lsr#2 \n");
 244+ __asm__ volatile(" mov r4, r4,lsr#1 \n");
 245+ __asm__ volatile(" add r4, r4, r1,lsr#2 \n");
 246+ __asm__ volatile(" strb r4, [r7], #1 \n");
 247+ __asm__ volatile(" mov r4, r1,asr#1 \n");
 248+ __asm__ volatile(" ldrb r1, [r3], #1 \n");
 249+ __asm__ volatile(" ldrsb r0, [r7] \n");
 250+ __asm__ volatile(" add r1, r1, r5 \n");
 251+ __asm__ volatile(" add r1, r1, r0 \n");
 252+ __asm__ volatile(" cmp r1, #0 \n");
 253+ __asm__ volatile(" movlt r1, #0 \n");
 254+ __asm__ volatile(" cmp r1, #0xff \n");
 255+ __asm__ volatile(" movgt r1, #0xff \n");
 256+ __asm__ volatile(" mov r0, r1,lsr#2 \n");
 257+ __asm__ volatile(" orr r2, r0,lsl#5 \n");
 258+ __asm__ volatile(" sub r1, r1, r0,lsl#2 \n");
 259+ __asm__ volatile(" sub r1, r1, r0,lsr#4 \n");
 260+ __asm__ volatile(" mov r5, r5,lsr#1 \n");
 261+ __asm__ volatile(" add r5, r5, r1,lsr#2 \n");
 262+ __asm__ volatile(" strb r5, [r7], #1 \n");
 263+ __asm__ volatile(" mov r5, r1,asr#1 \n");
 264+ __asm__ volatile(" ldrb r1, [r3], #1 \n");
 265+ __asm__ volatile(" ldrsb r0, [r7] \n");
 266+ __asm__ volatile(" add r1, r1, r6 \n");
 267+ __asm__ volatile(" add r1, r1, r0 \n");
 268+ __asm__ volatile(" cmp r1, #0 \n");
 269+ __asm__ volatile(" movlt r1, #0 \n");
 270+ __asm__ volatile(" cmp r1, #0xff \n");
 271+ __asm__ volatile(" movgt r1, #0xff \n");
 272+ __asm__ volatile(" mov r0, r1,lsr#3 \n");
 273+ __asm__ volatile(" orr r2, r0 \n");
 274+ __asm__ volatile(" sub r1, r1, r0,lsl#3 \n");
 275+ __asm__ volatile(" sub r1, r1, r0,lsr#2 \n");
 276+ __asm__ volatile(" mov r6, r6,lsr#1 \n");
 277+ __asm__ volatile(" add r6, r6, r1,lsr#2 \n");
 278+ __asm__ volatile(" strb r6, [r7], #1 \n");
 279+ __asm__ volatile(" mov r6, r1,asr#1 \n");
 280+ __asm__ volatile(" str r2, [r9] \n");
 281+ __asm__ volatile(" sub r3, r3, r10 \n");
 282+ __asm__ volatile(" subs lr, lr, #1 \n");
 283+ __asm__ volatile(" bne displaylcd_dither_x \n");
 284+ __asm__ volatile(" add r3, r3, r11 \n");
 285+ __asm__ volatile(" subs r12, r12, #1 \n");
 286+ __asm__ volatile(" bne displaylcd_dither_y \n");
 287+ __asm__ volatile("displaylcd_dither_free: \n");
 288+ __asm__ volatile(" mov r0, r8 \n");
 289+ __asm__ volatile(" bl free \n");
 290+ __asm__ volatile("displaylcd_dither_unlock: \n");
 291+ __asm__ volatile(" ldr r0, =lcd_mutex \n");
 292+ __asm__ volatile(" bl mutex_unlock \n");
 293+ __asm__ volatile(" ldmfd sp!, {r2-r11,pc} \n");
 294+}
 295+
 296+void displaylcd(unsigned int x, unsigned int y, unsigned int width, unsigned int height,
 297+ void* data, unsigned int datax, unsigned int datay, unsigned int stride)
 298+{
 299+ displaylcd_dither(x, y, width, height, data, datax, datay, stride, false);
 300+}
 301+
 302+void filllcd(unsigned int x, unsigned int y, unsigned int width, unsigned int height, int color)
 303+{
 304+ if (width * height <= 0) return;
 305+ mutex_lock(&lcd_mutex, TIMEOUT_BLOCK);
 306+ lcd_color = color;
 307+ displaylcd_dither(x, y, width, height, &lcd_color, 0, 0, 0, true);
 308+ mutex_unlock(&lcd_mutex);
 309+}
 310+
 311+void lcd_shutdown()
 312+{
 313+ displaylcd_sync();
 314+ uint32_t type = lcd_detect();
 315+ if (type & 2)
 316+ {
 317+ lcd_send_cmd(0x7);
 318+ lcd_send_data(0x172);
 319+ lcd_send_cmd(0x30);
 320+ lcd_send_data(0x3ff);
 321+ sleep(90000);
 322+ lcd_send_cmd(0x7);
 323+ lcd_send_data(0x120);
 324+ lcd_send_cmd(0x30);
 325+ lcd_send_data(0x0);
 326+ lcd_send_cmd(0x100);
 327+ lcd_send_data(0x780);
 328+ lcd_send_cmd(0x7);
 329+ lcd_send_data(0x0);
 330+ lcd_send_cmd(0x101);
 331+ lcd_send_data(0x260);
 332+ lcd_send_cmd(0x102);
 333+ lcd_send_data(0xa9);
 334+ sleep(30000);
 335+ lcd_send_cmd(0x100);
 336+ lcd_send_data(0x700);
 337+ lcd_send_cmd(0x100);
 338+ lcd_send_data(0x704);
 339+ }
 340+ else if (type == 1)
 341+ {
 342+ lcd_send_cmd(0x28);
 343+ lcd_send_cmd(0x10);
 344+ sleep(100000);
 345+ }
 346+ else
 347+ {
 348+ lcd_send_cmd(0x28);
 349+ sleep(50000);
 350+ lcd_send_cmd(0x10);
 351+ sleep(50000);
 352+ }
 353+}
 354+
 355+void INT_DMAC0C4()
 356+{
 357+ DMAC0INTTCCLR = 0x10;
 358+ lcdconsole_callback();
 359+}
 360+
 361+int lcd_translate_color(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue)
 362+ ICODE_ATTR __attribute__((naked, noinline));
 363+int lcd_translate_color(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue)
 364+{
 365+ asm volatile(
 366+ "cmp r0, #0xff \n\t"
 367+ "moveq r0, #-1 \n\t"
 368+ "moveq pc, lr \n\t"
 369+ "cmp r0, #0 \n\t"
 370+ "movne r0, #0xff000000 \n\t"
 371+ "orrne r0, r0, #0xff0000 \n\t"
 372+ "mov r2, r2,lsr#2 \n\t"
 373+ "orr r0, r0, r3,lsr#3 \n\t"
 374+ "mov r1, r1,lsr#3 \n\t"
 375+ "orr r0, r0, r2,lsl#5 \n\t"
 376+ "orr r0, r0, r1,lsl#11 \n\t"
 377+ "mov pc, lr \n\t"
 378+ );
 379+}