1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 by Greg White
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
25 #include "lcd-target.h"
27 #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)])
29 static volatile bool lcd_on
= true;
30 volatile bool lcd_poweroff
= false;
31 static unsigned lcd_yuv_options
= 0;
33 ** This is imported from lcd-16bit.c
35 extern struct viewport
* current_vp
;
37 /* Copies a rectangle from one framebuffer to another. Can be used in
38 single transfer mode with width = num pixels, and height = 1 which
39 allows a full-width rectangle to be copied more efficiently. */
40 extern void lcd_copy_buffer_rect(fb_data
*dst
, const fb_data
*src
,
41 int width
, int height
);
48 unsigned int LCDBANK(unsigned int address
)
50 return ((address
>> 22) & 0xff);
53 unsigned int LCDBASEU(unsigned int address
)
55 return (address
& ((1 << 22)-1)) >> 1;
58 unsigned int LCDBASEL(unsigned int address
)
61 return (address
& ((1 << 22)-1)) >> 1;
64 inline void delay_cycles(volatile int delay
)
66 while(delay
>0) delay
--;
69 void LCD_CTRL_setup(void)
71 /* ENVID = 0, BPPMODE = 16 bpp, PNRMODE = TFT, MMODE = Each Frame, CLKVAL = 8 */
74 /* VCPW = 1, VFPD = 5, LINEVAL = 319, VBPD = 7 */
77 /* HFPD = 9, HOZVAL = 239, HBPD = 7 */
83 /* HWSWP = 1, INVVFRAM = 1, INVVLINE = 1, FRM565 = 1, All others = 0 */
86 LCDSADDR1
= (LCDBANK((unsigned)FRAME
) << 21) | (LCDBASEU((unsigned)FRAME
));
87 LCDSADDR2
= LCDBASEL((unsigned)FRAME
);
88 LCDSADDR3
= 0x000000F0;
91 void LCD_CTRL_clock(bool onoff
)
95 GPCCON
&= ~0xFFF000FC;
96 GPDCON
&= ~0xFFF0FFF0;
101 GPDCON
|= 0xAAA0AAA0;
104 s3c_regset(&CLKCON
, 0x20); /* enable LCD clock */
109 GPCCON
&= ~0xFFF000FC;
112 GPDCON
&= ~0xFFF0FFF0;
115 LCDCON1
&= ~1; /* Must diable first or bus may freeze */
116 s3c_regclr(&CLKCON
, 0x20); /* disable LCD clock */
120 void reset_LCD(bool reset
)
130 void LCD_SPI_send(const unsigned char *array
, int count
)
134 while ((SPSTA0
&0x01)==0){};
139 void LCD_SPI_SS(bool select
)
141 delay_cycles(0x4FFF);
152 void LCD_SPI_start(void)
154 s3c_regset(&CLKCON
, 0x40000); /* enable SPI clock */
163 void LCD_SPI_stop(void)
168 s3c_regclr(&CLKCON
, 0x40000); /* disable SPI clock */
171 void LCD_SPI_powerdown(void)
173 const unsigned char powerdncmd
[] =
180 LCD_SPI_send(powerdncmd
, sizeof(powerdncmd
));
184 reset_LCD(false); /* This makes a big difference on power */
185 LCD_CTRL_clock(false);
188 void LCD_SPI_powerup(void)
190 const unsigned char powerupcmd
[] =
195 LCD_CTRL_clock(true);
199 LCD_SPI_send(powerupcmd
, sizeof(powerupcmd
));
204 void LCD_SPI_init(void)
206 /* SPI data - Right now we are not sure what each of these SPI writes is
207 * actually telling the lcd. Many thanks to Alex Gerchanovsky for
210 * This looks like a register, data combination, 0 denoting a register
211 * address, 1 denoting data. Addr 0x04 is used more than once is
214 const unsigned char initbuf
[] =
243 LCD_CTRL_clock(true);
247 LCD_SPI_send(initbuf
, sizeof(initbuf
));
253 void lcd_init_device(void)
259 GPECON
|= 0x0A800000;
264 s3c_regset(&CLKCON
, 0x20); /* enable LCD clock */
270 void lcd_enable(bool state
)
290 /* Update a fraction of the display. */
291 void lcd_update_rect(int x
, int y
, int width
, int height
)
298 if (x
+ width
> LCD_WIDTH
)
299 width
= LCD_WIDTH
- x
; /* Clip right */
301 width
+= x
, x
= 0; /* Clip left */
303 return; /* nothing left to do */
305 if (y
+ height
> LCD_HEIGHT
)
306 height
= LCD_HEIGHT
- y
; /* Clip bottom */
308 height
+= y
, y
= 0; /* Clip top */
310 return; /* nothing left to do */
312 /* TODO: It may be faster to swap the addresses of lcd_driver_framebuffer
313 * and lcd_framebuffer */
314 dst
= (fb_data
*)FRAME
+ LCD_WIDTH
*y
+ x
;
315 src
= &lcd_framebuffer
[y
][x
];
317 /* Copy part of the Rockbox framebuffer to the second framebuffer */
318 if (width
< LCD_WIDTH
)
320 /* Not full width - do line-by-line */
321 lcd_copy_buffer_rect(dst
, src
, width
, height
);
325 /* Full width - copy as one line */
326 lcd_copy_buffer_rect(dst
, src
, LCD_WIDTH
*height
, 1);
330 /* Update the display.
331 This must be called after all other LCD functions that change the display. */
332 void lcd_update(void)
337 lcd_copy_buffer_rect((fb_data
*)FRAME
, &lcd_framebuffer
[0][0],
338 LCD_WIDTH
*LCD_HEIGHT
, 1);
341 void lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
, int src_y
,
342 int stride
, int x
, int y
, int width
,
348 if (x
+ width
> current_vp
->width
)
349 width
= current_vp
->width
- x
; /* Clip right */
351 width
+= x
, x
= 0; /* Clip left */
353 return; /* nothing left to do */
355 if (y
+ height
> current_vp
->height
)
356 height
= current_vp
->height
- y
; /* Clip bottom */
358 height
+= y
, y
= 0; /* Clip top */
360 return; /* nothing left to do */
362 src
+= stride
* src_y
+ src_x
; /* move starting point */
363 dst
= &lcd_framebuffer
[current_vp
->y
+y
][current_vp
->x
+x
];
367 "mov %[w], %[width] \r\n" /* Load width for inner loop */
369 "ldrh %[px], [%[s]], #2 \r\n" /* Load src pixel */
370 "add %[d], %[d], #2 \r\n" /* Uncoditionally increment dst */
371 "cmp %[px], %[fgcolor] \r\n" /* Compare to foreground color */
372 "streqh %[fgpat], [%[d], #-2] \r\n" /* Store foregroud if match */
373 "cmpne %[px], %[transcolor] \r\n" /* Compare to transparent color */
374 "strneh %[px], [%[d], #-2] \r\n" /* Store dst if not transparent */
375 "subs %[w], %[w], #1 \r\n" /* Width counter has run down? */
376 "bgt .nextpixel \r\n" /* More in this row? */
377 "add %[s], %[s], %[sstp], lsl #1 \r\n" /* Skip over to start of next line */
378 "add %[d], %[d], %[dstp], lsl #1 \r\n"
379 "subs %[h], %[h], #1 \r\n" /* Height counter has run down? */
380 "bgt .rowstart \r\n" /* More rows? */
381 : [w
]"=&r"(w
), [h
]"+&r"(height
), [px
]"=&r"(px
),
382 [s
]"+&r"(src
), [d
]"+&r"(dst
)
384 [sstp
]"r"(stride
- width
),
385 [dstp
]"r"(LCD_WIDTH
- width
),
386 [transcolor
]"r"(TRANSPARENT_COLOR
),
387 [fgcolor
]"r"(REPLACEWITHFG_COLOR
),
388 [fgpat
]"r"(current_vp
->fg_pattern
)
392 void lcd_yuv_set_options(unsigned options
)
394 lcd_yuv_options
= options
;
397 /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
398 extern void lcd_write_yuv420_lines(fb_data
*dst
,
399 unsigned char const * const src
[3],
402 extern void lcd_write_yuv420_lines_odither(fb_data
*dst
,
403 unsigned char const * const src
[3],
406 int x_screen
, /* To align dither pattern */
408 /* Performance function to blit a YUV bitmap directly to the LCD */
409 /* For the Gigabeat - show it rotated */
410 /* So the LCD_WIDTH is now the height */
411 void lcd_blit_yuv(unsigned char * const src
[3],
412 int src_x
, int src_y
, int stride
,
413 int x
, int y
, int width
, int height
)
415 /* Caches for chroma data so it only need be recaculated every other
417 unsigned char const * yuv_src
[3];
423 /* Sorry, but width and height must be >= 2 or else */
427 y
= LCD_WIDTH
- 1 - y
;
428 fb_data
*dst
= (fb_data
*)FRAME
+ x
* LCD_WIDTH
+ y
;
431 yuv_src
[0] = src
[0] + z
+ src_x
;
432 yuv_src
[1] = src
[1] + (z
>> 2) + (src_x
>> 1);
433 yuv_src
[2] = src
[2] + (yuv_src
[1] - src
[1]);
435 if (lcd_yuv_options
& LCD_YUV_DITHER
)
439 lcd_write_yuv420_lines_odither(dst
, yuv_src
, width
, stride
, y
, x
);
440 yuv_src
[0] += stride
<< 1; /* Skip down two luma lines */
441 yuv_src
[1] += stride
>> 1; /* Skip down one chroma line */
442 yuv_src
[2] += stride
>> 1;
446 while (--height
> 0);
452 lcd_write_yuv420_lines(dst
, yuv_src
, width
, stride
);
453 yuv_src
[0] += stride
<< 1; /* Skip down two luma lines */
454 yuv_src
[1] += stride
>> 1; /* Skip down one chroma line */
455 yuv_src
[2] += stride
>> 1;
458 while (--height
> 0);
462 void lcd_set_contrast(int val
) {
467 void lcd_set_invert_display(bool yesno
) {
472 void lcd_set_flip(bool yesno
) {