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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006 by Barry Wardell
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+#include "cpu.h"
+#include "lcd.h"
+#include "kernel.h"
+#include "system.h"
+
+/* check if number of useconds has past */
+static inline bool timer_check(int clock_start, int usecs)
+{
+ return ((int)(USEC_TIMER - clock_start)) >= usecs;
+}
+
+/* Hardware address of LCD. Bits are:
+ * 31 - set to write, poll for completion.
+ * 24 - 0 for command, 1 for data
+ * 7..0 - command/data to send
+ * Commands/Data are always sent in 16-bits, msb first.
+ */
+#define LCD_BASE *(volatile unsigned int *)0x70008a0c
+#define LCD_BUSY_MASK 0x80000000
+#define LCD_CMD 0x80000000
+#define LCD_DATA 0x81000000
+
+/* register defines for TL1771 */
+#define R_START_OSC 0x00
+#define R_DEVICE_CODE_READ 0x00
+#define R_DRV_OUTPUT_CONTROL 0x01
+#define R_DRV_AC_CONTROL 0x02
+#define R_ENTRY_MODE 0x03
+#define R_DISP_CONTROL1 0x07
+#define R_DISP_CONTROL2 0x08
+#define R_FRAME_CYCLE_CONTROL 0x0b
+#define R_POWER_CONTROL1 0x10
+#define R_POWER_CONTROL2 0x11
+#define R_POWER_CONTROL3 0x12
+#define R_POWER_CONTROL4 0x13
+#define R_POWER_CONTROL5 0x14
+#define R_RAM_ADDR_SET 0x21
+#define R_WRITE_DATA_2_GRAM 0x22
+#define R_GAMMA_FINE_ADJ_POS1 0x30
+#define R_GAMMA_FINE_ADJ_POS2 0x31
+#define R_GAMMA_FINE_ADJ_POS3 0x32
+#define R_GAMMA_GRAD_ADJ_POS 0x33
+#define R_GAMMA_FINE_ADJ_NEG1 0x34
+#define R_GAMMA_FINE_ADJ_NEG2 0x35
+#define R_GAMMA_FINE_ADJ_NEG3 0x36
+#define R_GAMMA_GRAD_ADJ_NEG 0x37
+#define R_POWER_CONTROL6 0x38
+#define R_GATE_SCAN_START_POS 0x40
+#define R_1ST_SCR_DRV_POS 0x42
+#define R_2ND_SCR_DRV_POS 0x43
+#define R_HORIZ_RAM_ADDR_POS 0x44
+#define R_VERT_RAM_ADDR_POS 0x45
+
+static inline void lcd_wait_write(void)
+{
+ if ((LCD_BASE & LCD_BUSY_MASK) != 0) {
+ int start = USEC_TIMER;
+
+ do {
+ if ((LCD_BASE & LCD_BUSY_MASK) == 0) break;
+ } while (timer_check(start, 1000) == 0);
+ }
+}
+
+/* Send command */
+static inline void lcd_send_cmd(int v)
+{
+ lcd_wait_write();
+ LCD_BASE = 0x00000000 | LCD_CMD;
+ LCD_BASE = v | LCD_CMD;
+}
+
+/* Send 16-bit data */
+static inline void lcd_send_data(int v)
+{
+ lcd_wait_write();
+ LCD_BASE = ( v & 0xff) | LCD_DATA; /* Send MSB first */
+ LCD_BASE = ((v>>8) & 0xff) | LCD_DATA;
+}
+
+/* Send two 16-bit data */
+static inline void lcd_send_data2(int v)
+{
+ unsigned int vsr = v;
+ lcd_send_data(vsr);
+ vsr = v >> 16;
+ lcd_send_data(vsr);
+}
+
+
+/*** hardware configuration ***/
+
+void lcd_set_contrast(int val)
+{
+ /* TODO: Implement lcd_set_contrast() */
+ (void)val;
+}
+
+void lcd_set_invert_display(bool yesno)
+{
+ /* TODO: Implement lcd_set_invert_display() */
+ (void)yesno;
+}
+
+/* turn the display upside down (call lcd_update() afterwards) */
+void lcd_set_flip(bool yesno)
+{
+ /* TODO: Implement lcd_set_flip() */
+ (void)yesno;
+}
+
+/* LCD init */
+void lcd_init_device(void)
+{
+ /* H10 LCD is initialised by the bootloader */
+}
+
+/*** update functions ***/
+
+/* Performance function that works with an external buffer
+ note that by and bheight are in 4-pixel units! */
+void lcd_blit(const fb_data* data, int x, int by, int width,
+ int bheight, int stride)
+{
+ /* TODO: Implement lcd_blit() */
+ (void)data;
+ (void)x;
+ (void)by;
+ (void)width;
+ (void)bheight;
+ (void)stride;
+}
+
+#define CSUB_X 2
+#define CSUB_Y 2
+
+#define RYFAC (31*257)
+#define GYFAC (31*257)
+#define BYFAC (31*257)
+#define RVFAC 11170 /* 31 * 257 * 1.402 */
+#define GVFAC (-5690) /* 31 * 257 * -0.714136 */
+#define GUFAC (-2742) /* 31 * 257 * -0.344136 */
+#define BUFAC 14118 /* 31 * 257 * 1.772 */
+
+#define ROUNDOFFS (127*257)
+#define ROUNDOFFSG (63*257)
+
+/* Performance function to blit a YUV bitmap directly to the LCD */
+void lcd_yuv_blit(unsigned char * const src[3],
+ int src_x, int src_y, int stride,
+ int x, int y, int width, int height)
+{
+ int y0, x0, y1, x1;
+ int ymax;
+
+ width = (width + 1) & ~1;
+
+ /* calculate the drawing region */
+ x0 = x;
+ x1 = x + width - 1;
+ y0 = y;
+ y1 = y + height - 1;
+
+ /* start horiz << 8 | max horiz */
+ lcd_send_cmd(R_HORIZ_RAM_ADDR_POS);
+ lcd_send_data((x0 << 8) | x1);
+
+ /* start vert << 8 | max vert */
+ lcd_send_cmd(R_VERT_RAM_ADDR_POS);
+ lcd_send_data((y0 << 8) | y1);
+
+ /* start horiz << 8 | start vert */
+ lcd_send_cmd(R_RAM_ADDR_SET);
+ lcd_send_data(((x0 << 8) | y0));
+
+ /* start drawing */
+ lcd_send_cmd(R_WRITE_DATA_2_GRAM);
+
+ ymax = y + height - 1 ;
+
+ const int stride_div_csub_x = stride/CSUB_X;
+
+ for (; y <= ymax ; y++)
+ {
+ /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
+ const unsigned char *ysrc = src[0] + stride * src_y + src_x;
+
+ const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) +
+ (src_x/CSUB_X);
+
+ const unsigned char *usrc = src[1] + uvoffset;
+ const unsigned char *vsrc = src[2] + uvoffset;
+ const unsigned char *row_end = ysrc + width;
+
+ int y, u, v;
+ int red1, green1, blue1;
+ int red2, green2, blue2;
+ unsigned rbits, gbits, bbits;
+
+ int rc, gc, bc;
+
+ do
+ {
+ u = *usrc++ - 128;
+ v = *vsrc++ - 128;
+ rc = RVFAC * v + ROUNDOFFS;
+ gc = GVFAC * v + GUFAC * u + ROUNDOFFSG;
+ bc = BUFAC * u + ROUNDOFFS;
+
+ /* Pixel 1 */
+ y = *ysrc++;
+
+ red1 = RYFAC * y + rc;
+ green1 = GYFAC * y + gc;
+ blue1 = BYFAC * y + bc;
+
+ /* Pixel 2 */
+ y = *ysrc++;
+ red2 = RYFAC * y + rc;
+ green2 = GYFAC * y + gc;
+ blue2 = BYFAC * y + bc;
+
+ /* Since out of bounds errors are relatively rare, we check two
+ pixels at once to see if any components are out of bounds, and
+ then fix whichever is broken. This works due to high values and
+ negative values both becoming larger than the cutoff when
+ casted to unsigned. And ORing them together checks all of them
+ simultaneously. */
+ if (((unsigned)(red1 | green1 | blue1 |
+ red2 | green2 | blue2)) > (RYFAC*255+ROUNDOFFS)) {
+ if (((unsigned)(red1 | green1 | blue1)) >
+ (RYFAC*255+ROUNDOFFS)) {
+ if ((unsigned)red1 > (RYFAC*255+ROUNDOFFS))
+ {
+ if (red1 < 0)
+ red1 = 0;
+ else
+ red1 = (RYFAC*255+ROUNDOFFS);
+ }
+ if ((unsigned)green1 > (GYFAC*255+ROUNDOFFSG))
+ {
+ if (green1 < 0)
+ green1 = 0;
+ else
+ green1 = (GYFAC*255+ROUNDOFFSG);
+ }
+ if ((unsigned)blue1 > (BYFAC*255+ROUNDOFFS))
+ {
+ if (blue1 < 0)
+ blue1 = 0;
+ else
+ blue1 = (BYFAC*255+ROUNDOFFS);
+ }
+ }
+
+ if (((unsigned)(red2 | green2 | blue2)) >
+ (RYFAC*255+ROUNDOFFS)) {
+ if ((unsigned)red2 > (RYFAC*255+ROUNDOFFS))
+ {
+ if (red2 < 0)
+ red2 = 0;
+ else
+ red2 = (RYFAC*255+ROUNDOFFS);
+ }
+ if ((unsigned)green2 > (GYFAC*255+ROUNDOFFSG))
+ {
+ if (green2 < 0)
+ green2 = 0;
+ else
+ green2 = (GYFAC*255+ROUNDOFFSG);
+ }
+ if ((unsigned)blue2 > (BYFAC*255+ROUNDOFFS))
+ {
+ if (blue2 < 0)
+ blue2 = 0;
+ else
+ blue2 = (BYFAC*255+ROUNDOFFS);
+ }
+ }
+ }
+
+ rbits = red1 >> 16 ;
+ gbits = green1 >> 15 ;
+ bbits = blue1 >> 16 ;
+ lcd_send_data(swap16((rbits << 11) | (gbits << 5) | bbits));
+
+ rbits = red2 >> 16 ;
+ gbits = green2 >> 15 ;
+ bbits = blue2 >> 16 ;
+ lcd_send_data(swap16((rbits << 11) | (gbits << 5) | bbits));
+ }
+ while (ysrc < row_end);
+
+ src_y++;
+ }
+}
+
+
+/* Update a fraction of the display. */
+void lcd_update_rect(int x0, int y0, int width, int height)
+{
+ int x1, y1;
+ int newx,newwidth;
+
+ unsigned long *addr = (unsigned long *)lcd_framebuffer;
+
+ /* Ensure x and width are both even - so we can read 32-bit aligned
+ data from lcd_framebuffer */
+ newx=x0&~1;
+ newwidth=width&~1;
+ if (newx+newwidth < x0+width) { newwidth+=2; }
+ x0=newx; width=newwidth;
+
+ /* calculate the drawing region */
+ y1 = (y0 + height) - 1; /* max vert */
+ x1 = (x0 + width) - 1; /* max horiz */
+
+
+ /* swap max horiz < start horiz */
+ if (y1 < y0) {
+ int t;
+ t = y0;
+ y0 = y1;
+ y1 = t;
+ }
+
+ /* swap max vert < start vert */
+ if (x1 < x0) {
+ int t;
+ t = x0;
+ x0 = x1;
+ x1 = t;
+ }
+
+ /* start horiz << 8 | max horiz */
+ lcd_send_cmd(R_HORIZ_RAM_ADDR_POS);
+ lcd_send_data((x0 << 8) | x1);
+
+ /* start vert << 8 | max vert */
+ lcd_send_cmd(R_VERT_RAM_ADDR_POS);
+ lcd_send_data((y0 << 8) | y1);
+
+ /* start horiz << 8 | start vert */
+ lcd_send_cmd(R_RAM_ADDR_SET);
+ lcd_send_data(((x0 << 8) | y0));
+
+ /* start drawing */
+ lcd_send_cmd(R_WRITE_DATA_2_GRAM);
+
+ addr = (unsigned long*)&lcd_framebuffer[y0][x0];
+
+ int c, r;
+
+ /* for each row */
+ for (r = 0; r < height; r++) {
+ /* for each column */
+ for (c = 0; c < width; c += 2) {
+ /* output 2 pixels */
+ lcd_send_data2(*(addr++));
+ }
+
+ addr += (LCD_WIDTH - width)/2;
+ }
+}
+
+/* Update the display.
+ This must be called after all other LCD functions that change the display. */
+void lcd_update(void)
+{
+ lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
+}