| 268 |
theseven |
1 |
//
|
|
|
2 |
//
|
|
|
3 |
// Copyright 2010 TheSeven
|
|
|
4 |
//
|
|
|
5 |
//
|
| 427 |
farthen |
6 |
// This file is part of emCORE.
|
| 268 |
theseven |
7 |
//
|
| 427 |
farthen |
8 |
// emCORE is free software: you can redistribute it and/or
|
| 268 |
theseven |
9 |
// modify it under the terms of the GNU General Public License as
|
|
|
10 |
// published by the Free Software Foundation, either version 2 of the
|
|
|
11 |
// License, or (at your option) any later version.
|
|
|
12 |
//
|
| 427 |
farthen |
13 |
// emCORE is distributed in the hope that it will be useful,
|
| 268 |
theseven |
14 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
15 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
16 |
// See the GNU General Public License for more details.
|
|
|
17 |
//
|
|
|
18 |
// You should have received a copy of the GNU General Public License along
|
| 427 |
farthen |
19 |
// with emCORE. If not, see <http://www.gnu.org/licenses/>.
|
| 268 |
theseven |
20 |
//
|
|
|
21 |
//
|
|
|
22 |
|
|
|
23 |
|
|
|
24 |
#include "global.h"
|
|
|
25 |
#include "thread.h"
|
|
|
26 |
#include "s5l8720.h"
|
|
|
27 |
#include "util.h"
|
|
|
28 |
|
|
|
29 |
|
| 278 |
theseven |
30 |
static struct dma_lli lcd_lli[(LCD_WIDTH * LCD_HEIGHT - 1) / 0xfff]
|
|
|
31 |
IDATA_ATTR __attribute__((aligned(16)));
|
| 268 |
theseven |
32 |
|
|
|
33 |
static uint16_t lcd_color IDATA_ATTR;
|
|
|
34 |
|
| 492 |
theseven |
35 |
static struct mutex lcd_mutex;
|
| 268 |
theseven |
36 |
|
| 492 |
theseven |
37 |
|
| 268 |
theseven |
38 |
void lcd_init()
|
|
|
39 |
{
|
|
|
40 |
}
|
|
|
41 |
|
|
|
42 |
int lcd_get_width()
|
|
|
43 |
{
|
|
|
44 |
return LCD_WIDTH;
|
|
|
45 |
}
|
|
|
46 |
|
|
|
47 |
int lcd_get_height()
|
|
|
48 |
{
|
|
|
49 |
return LCD_HEIGHT;
|
|
|
50 |
}
|
|
|
51 |
|
|
|
52 |
int lcd_get_bytes_per_pixel()
|
|
|
53 |
{
|
|
|
54 |
return LCD_BYTESPERPIXEL;
|
|
|
55 |
}
|
|
|
56 |
|
| 489 |
theseven |
57 |
int lcd_get_format()
|
|
|
58 |
{
|
|
|
59 |
return LCD_FORMAT;
|
|
|
60 |
}
|
|
|
61 |
|
| 492 |
theseven |
62 |
static void lcd_send_cmd(uint16_t cmd) ICODE_ATTR __attribute__((noinline));
|
| 268 |
theseven |
63 |
static void lcd_send_cmd(uint16_t cmd)
|
|
|
64 |
{
|
|
|
65 |
while (LCDSTATUS & 0x10);
|
|
|
66 |
LCDWCMD = cmd;
|
|
|
67 |
}
|
|
|
68 |
|
| 492 |
theseven |
69 |
static void lcd_send_data(uint16_t data) ICODE_ATTR __attribute__((noinline));
|
| 268 |
theseven |
70 |
static void lcd_send_data(uint16_t data)
|
|
|
71 |
{
|
|
|
72 |
while (LCDSTATUS & 0x10);
|
| 492 |
theseven |
73 |
LCDWDATA = (data & 0xff) | ((data & 0x7f00) << 1);
|
| 268 |
theseven |
74 |
}
|
|
|
75 |
|
|
|
76 |
void lcd_shutdown()
|
|
|
77 |
{
|
|
|
78 |
}
|
|
|
79 |
|
|
|
80 |
bool displaylcd_busy()
|
|
|
81 |
{
|
| 492 |
theseven |
82 |
return DMAC0C4CONFIG & 1;
|
| 268 |
theseven |
83 |
}
|
|
|
84 |
|
|
|
85 |
bool displaylcd_safe()
|
|
|
86 |
{
|
| 492 |
theseven |
87 |
return !(DMAC0C4CONFIG & 1);
|
| 268 |
theseven |
88 |
}
|
|
|
89 |
|
| 492 |
theseven |
90 |
void displaylcd_sync() ICODE_ATTR;
|
| 268 |
theseven |
91 |
void displaylcd_sync()
|
|
|
92 |
{
|
| 492 |
theseven |
93 |
mutex_lock(&lcd_mutex, TIMEOUT_BLOCK);
|
| 268 |
theseven |
94 |
while (displaylcd_busy()) sleep(100);
|
| 492 |
theseven |
95 |
mutex_unlock(&lcd_mutex);
|
| 268 |
theseven |
96 |
}
|
|
|
97 |
|
| 492 |
theseven |
98 |
void displaylcd_setup(unsigned int startx, unsigned int endx,
|
|
|
99 |
unsigned int starty, unsigned int endy) ICODE_ATTR;
|
|
|
100 |
void displaylcd_setup(unsigned int startx, unsigned int endx,
|
|
|
101 |
unsigned int starty, unsigned int endy)
|
| 268 |
theseven |
102 |
{
|
| 492 |
theseven |
103 |
mutex_lock(&lcd_mutex, TIMEOUT_BLOCK);
|
| 268 |
theseven |
104 |
displaylcd_sync();
|
|
|
105 |
lcd_send_cmd(0x2a);
|
| 492 |
theseven |
106 |
lcd_send_data(startx);
|
|
|
107 |
lcd_send_data(endx);
|
| 268 |
theseven |
108 |
lcd_send_cmd(0x2b);
|
| 492 |
theseven |
109 |
lcd_send_data(starty);
|
|
|
110 |
lcd_send_data(endy);
|
| 268 |
theseven |
111 |
lcd_send_cmd(0x2c);
|
| 492 |
theseven |
112 |
}
|
|
|
113 |
|
|
|
114 |
static void displaylcd_dma(void* data, int pixels, bool solid) ICODE_ATTR;
|
|
|
115 |
static void displaylcd_dma(void* data, int pixels, bool solid)
|
|
|
116 |
{
|
| 268 |
theseven |
117 |
int i;
|
| 278 |
theseven |
118 |
for (i = -1; i < (int)ARRAYLEN(lcd_lli) && pixels > 0; i++, pixels -= 0xfff)
|
| 268 |
theseven |
119 |
{
|
| 278 |
theseven |
120 |
bool last = i + 1 >= ARRAYLEN(lcd_lli) || pixels <= 0xfff;
|
| 492 |
theseven |
121 |
struct dma_lli* lli = i < 0 ? (struct dma_lli*)((int)&DMAC0C4LLI) : &lcd_lli[i];
|
|
|
122 |
lli->srcaddr = data;
|
| 278 |
theseven |
123 |
lli->dstaddr = (void*)((int)&LCDWDATA);
|
|
|
124 |
lli->nextlli = last ? NULL : &lcd_lli[i + 1];
|
|
|
125 |
lli->control = 0x70240000 | (last ? pixels : 0xfff)
|
|
|
126 |
| (last ? 0x80000000 : 0) | (solid ? 0 : 0x4000000);
|
| 268 |
theseven |
127 |
data = (void*)(((uint32_t)data) + 0x1ffe);
|
|
|
128 |
}
|
|
|
129 |
clean_dcache();
|
| 492 |
theseven |
130 |
DMAC0C4CONFIG = 0x88c1;
|
| 268 |
theseven |
131 |
}
|
|
|
132 |
|
| 492 |
theseven |
133 |
void displaylcd_native(unsigned int startx, unsigned int endx,
|
|
|
134 |
unsigned int starty, unsigned int endy, void* data)
|
| 268 |
theseven |
135 |
{
|
| 492 |
theseven |
136 |
int pixels = (endx - startx + 1) * (endy - starty + 1);
|
|
|
137 |
if (pixels <= 0) return;
|
|
|
138 |
displaylcd_setup(startx, endx, starty, endy);
|
|
|
139 |
displaylcd_dma(data, pixels, false);
|
|
|
140 |
mutex_unlock(&lcd_mutex);
|
|
|
141 |
}
|
|
|
142 |
|
|
|
143 |
void filllcd_native(unsigned int startx, unsigned int endx,
|
|
|
144 |
unsigned int starty, unsigned int endy, int color)
|
|
|
145 |
{
|
|
|
146 |
int pixels = (endx - startx + 1) * (endy - starty + 1);
|
|
|
147 |
if (pixels <= 0) return;
|
|
|
148 |
displaylcd_setup(startx, endx, starty, endy);
|
|
|
149 |
lcd_color = color;
|
|
|
150 |
displaylcd_dma(&lcd_color, pixels, true);
|
|
|
151 |
mutex_unlock(&lcd_mutex);
|
|
|
152 |
}
|
|
|
153 |
|
|
|
154 |
void displaylcd_dither(unsigned int x, unsigned int y, unsigned int width,
|
|
|
155 |
unsigned int height, void* data, unsigned int datax,
|
|
|
156 |
unsigned int datay, unsigned int stride, bool solid) ICODE_ATTR;
|
|
|
157 |
void displaylcd_dither(unsigned int x, unsigned int y, unsigned int width,
|
|
|
158 |
unsigned int height, void* data, unsigned int datax,
|
|
|
159 |
unsigned int datay, unsigned int stride, bool solid)
|
|
|
160 |
{
|
|
|
161 |
int pixels = width * height;
|
|
|
162 |
if (pixels <= 0) return;
|
|
|
163 |
displaylcd_setup(x, x + width - 1, y, y + height - 1);
|
|
|
164 |
int corrsize = width * 3;
|
|
|
165 |
signed char* corr = (signed char*)malloc(corrsize);
|
|
|
166 |
if (!corr)
|
|
|
167 |
{
|
|
|
168 |
mutex_unlock(&lcd_mutex);
|
|
|
169 |
return;
|
|
|
170 |
}
|
|
|
171 |
memset(corr, 0, corrsize);
|
|
|
172 |
unsigned char* in = (unsigned char*)data + (stride * datay + datax) * 3;
|
|
|
173 |
for (y = 0; y < height; y++)
|
|
|
174 |
{
|
|
|
175 |
int i;
|
|
|
176 |
signed char* corrptr = corr;
|
|
|
177 |
signed char lastcorr[3] = {0};
|
|
|
178 |
for (x = 0; x < width; x++)
|
|
|
179 |
{
|
|
|
180 |
unsigned int pixel = 0;
|
|
|
181 |
signed char* lastcorrptr = lastcorr;
|
|
|
182 |
int orig = *in++ + *corrptr + *lastcorrptr;
|
|
|
183 |
orig = MAX(0, MIN(255, orig));
|
|
|
184 |
unsigned int real = orig >> 3;
|
|
|
185 |
pixel |= real << 11;
|
|
|
186 |
int err = orig - ((real << 3) | (real >> 2));
|
|
|
187 |
*corrptr++ = (*lastcorrptr >> 1) + err >> 2;
|
|
|
188 |
*lastcorrptr++ = err >> 1;
|
|
|
189 |
orig = *in++ + *corrptr + *lastcorrptr;
|
|
|
190 |
orig = MAX(0, MIN(255, orig));
|
|
|
191 |
real = orig >> 2;
|
|
|
192 |
pixel |= real << 5;
|
|
|
193 |
err = orig - ((real << 2) | (real >> 4));
|
|
|
194 |
*corrptr++ = (*lastcorrptr >> 1) + err >> 2;
|
|
|
195 |
*lastcorrptr++ = err >> 1;
|
|
|
196 |
orig = *in++ + *corrptr + *lastcorrptr;
|
|
|
197 |
orig = MAX(0, MIN(255, orig));
|
|
|
198 |
real = orig >> 3;
|
|
|
199 |
pixel |= real;
|
|
|
200 |
err = orig - ((real << 3) | (real >> 2));
|
|
|
201 |
*corrptr++ = (*lastcorrptr >> 1) + err >> 2;
|
|
|
202 |
*lastcorrptr++ = err >> 1;
|
|
|
203 |
while (LCDSTATUS & 0x10);
|
|
|
204 |
LCDWDATA = pixel;
|
|
|
205 |
if (solid) in -= 3;
|
|
|
206 |
}
|
|
|
207 |
if (solid) in += stride * 3;
|
|
|
208 |
else in += (stride - width) * 3;
|
|
|
209 |
}
|
|
|
210 |
free(corr);
|
|
|
211 |
mutex_unlock(&lcd_mutex);
|
|
|
212 |
}
|
|
|
213 |
|
|
|
214 |
void displaylcd(unsigned int x, unsigned int y, unsigned int width, unsigned int height,
|
|
|
215 |
void* data, unsigned int datax, unsigned int datay, unsigned int stride)
|
|
|
216 |
{
|
|
|
217 |
displaylcd_dither(x, y, width, height, data, datax, datay, stride, false);
|
|
|
218 |
}
|
|
|
219 |
|
|
|
220 |
void filllcd(unsigned int x, unsigned int y, unsigned int width, unsigned int height, int color)
|
|
|
221 |
{
|
|
|
222 |
if (width * height <= 0) return;
|
|
|
223 |
mutex_lock(&lcd_mutex, TIMEOUT_BLOCK);
|
|
|
224 |
lcd_color = color;
|
|
|
225 |
displaylcd_dither(x, y, width, height, &lcd_color, 0, 0, 0, true);
|
|
|
226 |
mutex_unlock(&lcd_mutex);
|
|
|
227 |
}
|
|
|
228 |
|
|
|
229 |
void INT_DMAC0C4()
|
|
|
230 |
{
|
|
|
231 |
DMAC0INTTCCLR = 0x10;
|
| 268 |
theseven |
232 |
lcdconsole_callback();
|
|
|
233 |
}
|
|
|
234 |
|
|
|
235 |
int lcd_translate_color(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue)
|
|
|
236 |
ICODE_ATTR __attribute__((naked, noinline));
|
|
|
237 |
int lcd_translate_color(uint8_t alpha, uint8_t red, uint8_t green, uint8_t blue)
|
|
|
238 |
{
|
|
|
239 |
asm volatile(
|
|
|
240 |
"cmp r0, #0xff \n\t"
|
|
|
241 |
"moveq r0, #-1 \n\t"
|
|
|
242 |
"moveq pc, lr \n\t"
|
|
|
243 |
"cmp r0, #0 \n\t"
|
|
|
244 |
"movne r0, #0xff000000 \n\t"
|
|
|
245 |
"orrne r0, r0, #0xff0000 \n\t"
|
|
|
246 |
"mov r2, r2,lsr#2 \n\t"
|
|
|
247 |
"orr r0, r0, r3,lsr#3 \n\t"
|
|
|
248 |
"mov r1, r1,lsr#3 \n\t"
|
|
|
249 |
"orr r0, r0, r2,lsl#5 \n\t"
|
|
|
250 |
"orr r0, r0, r1,lsl#11 \n\t"
|
|
|
251 |
"mov pc, lr \n\t"
|
|
|
252 |
);
|
|
|
253 |
}
|