summaryrefslogtreecommitdiff
path: root/firmware/target/arm/iriver/h10/lcd-h10_5gb.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/iriver/h10/lcd-h10_5gb.c')
-rw-r--r--firmware/target/arm/iriver/h10/lcd-h10_5gb.c390
1 files changed, 390 insertions, 0 deletions
diff --git a/firmware/target/arm/iriver/h10/lcd-h10_5gb.c b/firmware/target/arm/iriver/h10/lcd-h10_5gb.c
new file mode 100644
index 0000000000..01f4130efb
--- /dev/null
+++ b/firmware/target/arm/iriver/h10/lcd-h10_5gb.c
@@ -0,0 +1,390 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Barry Wardell
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "config.h"
20#include "cpu.h"
21#include "lcd.h"
22#include "kernel.h"
23#include "system.h"
24
25/* check if number of useconds has past */
26static inline bool timer_check(int clock_start, int usecs)
27{
28 return ((int)(USEC_TIMER - clock_start)) >= usecs;
29}
30
31/* Hardware address of LCD. Bits are:
32 * 31 - set to write, poll for completion.
33 * 24 - 0 for command, 1 for data
34 * 7..0 - command/data to send
35 * Commands/Data are always sent in 16-bits, msb first.
36 */
37#define LCD_BASE *(volatile unsigned int *)0x70008a0c
38#define LCD_BUSY_MASK 0x80000000
39#define LCD_CMD 0x80000000
40#define LCD_DATA 0x81000000
41
42/* register defines for TL1771 */
43#define R_START_OSC 0x00
44#define R_DEVICE_CODE_READ 0x00
45#define R_DRV_OUTPUT_CONTROL 0x01
46#define R_DRV_AC_CONTROL 0x02
47#define R_ENTRY_MODE 0x03
48#define R_DISP_CONTROL1 0x07
49#define R_DISP_CONTROL2 0x08
50#define R_FRAME_CYCLE_CONTROL 0x0b
51#define R_POWER_CONTROL1 0x10
52#define R_POWER_CONTROL2 0x11
53#define R_POWER_CONTROL3 0x12
54#define R_POWER_CONTROL4 0x13
55#define R_POWER_CONTROL5 0x14
56#define R_RAM_ADDR_SET 0x21
57#define R_WRITE_DATA_2_GRAM 0x22
58#define R_GAMMA_FINE_ADJ_POS1 0x30
59#define R_GAMMA_FINE_ADJ_POS2 0x31
60#define R_GAMMA_FINE_ADJ_POS3 0x32
61#define R_GAMMA_GRAD_ADJ_POS 0x33
62#define R_GAMMA_FINE_ADJ_NEG1 0x34
63#define R_GAMMA_FINE_ADJ_NEG2 0x35
64#define R_GAMMA_FINE_ADJ_NEG3 0x36
65#define R_GAMMA_GRAD_ADJ_NEG 0x37
66#define R_POWER_CONTROL6 0x38
67#define R_GATE_SCAN_START_POS 0x40
68#define R_1ST_SCR_DRV_POS 0x42
69#define R_2ND_SCR_DRV_POS 0x43
70#define R_HORIZ_RAM_ADDR_POS 0x44
71#define R_VERT_RAM_ADDR_POS 0x45
72
73static inline void lcd_wait_write(void)
74{
75 if ((LCD_BASE & LCD_BUSY_MASK) != 0) {
76 int start = USEC_TIMER;
77
78 do {
79 if ((LCD_BASE & LCD_BUSY_MASK) == 0) break;
80 } while (timer_check(start, 1000) == 0);
81 }
82}
83
84/* Send command */
85static inline void lcd_send_cmd(int v)
86{
87 lcd_wait_write();
88 LCD_BASE = 0x00000000 | LCD_CMD;
89 LCD_BASE = v | LCD_CMD;
90}
91
92/* Send 16-bit data */
93static inline void lcd_send_data(int v)
94{
95 lcd_wait_write();
96 LCD_BASE = ( v & 0xff) | LCD_DATA; /* Send MSB first */
97 LCD_BASE = ((v>>8) & 0xff) | LCD_DATA;
98}
99
100/* Send two 16-bit data */
101static inline void lcd_send_data2(int v)
102{
103 unsigned int vsr = v;
104 lcd_send_data(vsr);
105 vsr = v >> 16;
106 lcd_send_data(vsr);
107}
108
109
110/*** hardware configuration ***/
111
112void lcd_set_contrast(int val)
113{
114 /* TODO: Implement lcd_set_contrast() */
115 (void)val;
116}
117
118void lcd_set_invert_display(bool yesno)
119{
120 /* TODO: Implement lcd_set_invert_display() */
121 (void)yesno;
122}
123
124/* turn the display upside down (call lcd_update() afterwards) */
125void lcd_set_flip(bool yesno)
126{
127 /* TODO: Implement lcd_set_flip() */
128 (void)yesno;
129}
130
131/* LCD init */
132void lcd_init_device(void)
133{
134 /* H10 LCD is initialised by the bootloader */
135}
136
137/*** update functions ***/
138
139/* Performance function that works with an external buffer
140 note that by and bheight are in 4-pixel units! */
141void lcd_blit(const fb_data* data, int x, int by, int width,
142 int bheight, int stride)
143{
144 /* TODO: Implement lcd_blit() */
145 (void)data;
146 (void)x;
147 (void)by;
148 (void)width;
149 (void)bheight;
150 (void)stride;
151}
152
153#define CSUB_X 2
154#define CSUB_Y 2
155
156#define RYFAC (31*257)
157#define GYFAC (31*257)
158#define BYFAC (31*257)
159#define RVFAC 11170 /* 31 * 257 * 1.402 */
160#define GVFAC (-5690) /* 31 * 257 * -0.714136 */
161#define GUFAC (-2742) /* 31 * 257 * -0.344136 */
162#define BUFAC 14118 /* 31 * 257 * 1.772 */
163
164#define ROUNDOFFS (127*257)
165#define ROUNDOFFSG (63*257)
166
167/* Performance function to blit a YUV bitmap directly to the LCD */
168void lcd_yuv_blit(unsigned char * const src[3],
169 int src_x, int src_y, int stride,
170 int x, int y, int width, int height)
171{
172 int y0, x0, y1, x1;
173 int ymax;
174
175 width = (width + 1) & ~1;
176
177 /* calculate the drawing region */
178 x0 = x;
179 x1 = x + width - 1;
180 y0 = y;
181 y1 = y + height - 1;
182
183 /* start horiz << 8 | max horiz */
184 lcd_send_cmd(R_HORIZ_RAM_ADDR_POS);
185 lcd_send_data((x0 << 8) | x1);
186
187 /* start vert << 8 | max vert */
188 lcd_send_cmd(R_VERT_RAM_ADDR_POS);
189 lcd_send_data((y0 << 8) | y1);
190
191 /* start horiz << 8 | start vert */
192 lcd_send_cmd(R_RAM_ADDR_SET);
193 lcd_send_data(((x0 << 8) | y0));
194
195 /* start drawing */
196 lcd_send_cmd(R_WRITE_DATA_2_GRAM);
197
198 ymax = y + height - 1 ;
199
200 const int stride_div_csub_x = stride/CSUB_X;
201
202 for (; y <= ymax ; y++)
203 {
204 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
205 const unsigned char *ysrc = src[0] + stride * src_y + src_x;
206
207 const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) +
208 (src_x/CSUB_X);
209
210 const unsigned char *usrc = src[1] + uvoffset;
211 const unsigned char *vsrc = src[2] + uvoffset;
212 const unsigned char *row_end = ysrc + width;
213
214 int y, u, v;
215 int red1, green1, blue1;
216 int red2, green2, blue2;
217 unsigned rbits, gbits, bbits;
218
219 int rc, gc, bc;
220
221 do
222 {
223 u = *usrc++ - 128;
224 v = *vsrc++ - 128;
225 rc = RVFAC * v + ROUNDOFFS;
226 gc = GVFAC * v + GUFAC * u + ROUNDOFFSG;
227 bc = BUFAC * u + ROUNDOFFS;
228
229 /* Pixel 1 */
230 y = *ysrc++;
231
232 red1 = RYFAC * y + rc;
233 green1 = GYFAC * y + gc;
234 blue1 = BYFAC * y + bc;
235
236 /* Pixel 2 */
237 y = *ysrc++;
238 red2 = RYFAC * y + rc;
239 green2 = GYFAC * y + gc;
240 blue2 = BYFAC * y + bc;
241
242 /* Since out of bounds errors are relatively rare, we check two
243 pixels at once to see if any components are out of bounds, and
244 then fix whichever is broken. This works due to high values and
245 negative values both becoming larger than the cutoff when
246 casted to unsigned. And ORing them together checks all of them
247 simultaneously. */
248 if (((unsigned)(red1 | green1 | blue1 |
249 red2 | green2 | blue2)) > (RYFAC*255+ROUNDOFFS)) {
250 if (((unsigned)(red1 | green1 | blue1)) >
251 (RYFAC*255+ROUNDOFFS)) {
252 if ((unsigned)red1 > (RYFAC*255+ROUNDOFFS))
253 {
254 if (red1 < 0)
255 red1 = 0;
256 else
257 red1 = (RYFAC*255+ROUNDOFFS);
258 }
259 if ((unsigned)green1 > (GYFAC*255+ROUNDOFFSG))
260 {
261 if (green1 < 0)
262 green1 = 0;
263 else
264 green1 = (GYFAC*255+ROUNDOFFSG);
265 }
266 if ((unsigned)blue1 > (BYFAC*255+ROUNDOFFS))
267 {
268 if (blue1 < 0)
269 blue1 = 0;
270 else
271 blue1 = (BYFAC*255+ROUNDOFFS);
272 }
273 }
274
275 if (((unsigned)(red2 | green2 | blue2)) >
276 (RYFAC*255+ROUNDOFFS)) {
277 if ((unsigned)red2 > (RYFAC*255+ROUNDOFFS))
278 {
279 if (red2 < 0)
280 red2 = 0;
281 else
282 red2 = (RYFAC*255+ROUNDOFFS);
283 }
284 if ((unsigned)green2 > (GYFAC*255+ROUNDOFFSG))
285 {
286 if (green2 < 0)
287 green2 = 0;
288 else
289 green2 = (GYFAC*255+ROUNDOFFSG);
290 }
291 if ((unsigned)blue2 > (BYFAC*255+ROUNDOFFS))
292 {
293 if (blue2 < 0)
294 blue2 = 0;
295 else
296 blue2 = (BYFAC*255+ROUNDOFFS);
297 }
298 }
299 }
300
301 rbits = red1 >> 16 ;
302 gbits = green1 >> 15 ;
303 bbits = blue1 >> 16 ;
304 lcd_send_data(swap16((rbits << 11) | (gbits << 5) | bbits));
305
306 rbits = red2 >> 16 ;
307 gbits = green2 >> 15 ;
308 bbits = blue2 >> 16 ;
309 lcd_send_data(swap16((rbits << 11) | (gbits << 5) | bbits));
310 }
311 while (ysrc < row_end);
312
313 src_y++;
314 }
315}
316
317
318/* Update a fraction of the display. */
319void lcd_update_rect(int x0, int y0, int width, int height)
320{
321 int x1, y1;
322 int newx,newwidth;
323
324 unsigned long *addr = (unsigned long *)lcd_framebuffer;
325
326 /* Ensure x and width are both even - so we can read 32-bit aligned
327 data from lcd_framebuffer */
328 newx=x0&~1;
329 newwidth=width&~1;
330 if (newx+newwidth < x0+width) { newwidth+=2; }
331 x0=newx; width=newwidth;
332
333 /* calculate the drawing region */
334 y1 = (y0 + height) - 1; /* max vert */
335 x1 = (x0 + width) - 1; /* max horiz */
336
337
338 /* swap max horiz < start horiz */
339 if (y1 < y0) {
340 int t;
341 t = y0;
342 y0 = y1;
343 y1 = t;
344 }
345
346 /* swap max vert < start vert */
347 if (x1 < x0) {
348 int t;
349 t = x0;
350 x0 = x1;
351 x1 = t;
352 }
353
354 /* start horiz << 8 | max horiz */
355 lcd_send_cmd(R_HORIZ_RAM_ADDR_POS);
356 lcd_send_data((x0 << 8) | x1);
357
358 /* start vert << 8 | max vert */
359 lcd_send_cmd(R_VERT_RAM_ADDR_POS);
360 lcd_send_data((y0 << 8) | y1);
361
362 /* start horiz << 8 | start vert */
363 lcd_send_cmd(R_RAM_ADDR_SET);
364 lcd_send_data(((x0 << 8) | y0));
365
366 /* start drawing */
367 lcd_send_cmd(R_WRITE_DATA_2_GRAM);
368
369 addr = (unsigned long*)&lcd_framebuffer[y0][x0];
370
371 int c, r;
372
373 /* for each row */
374 for (r = 0; r < height; r++) {
375 /* for each column */
376 for (c = 0; c < width; c += 2) {
377 /* output 2 pixels */
378 lcd_send_data2(*(addr++));
379 }
380
381 addr += (LCD_WIDTH - width)/2;
382 }
383}
384
385/* Update the display.
386 This must be called after all other LCD functions that change the display. */
387void lcd_update(void)
388{
389 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
390}