diff options
Diffstat (limited to 'firmware/target/arm/s5l8700')
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c | 1693 |
1 files changed, 847 insertions, 846 deletions
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c index f2d0c3458f..0f7fbd2cc7 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c +++ b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c @@ -1,854 +1,855 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2009 by Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "config.h" - -#include "hwcompat.h" -#include "kernel.h" -#include "lcd.h" -#include "system.h" -#include "cpu.h" -#include "pmu-target.h" - - -/* The Nano 2G has two different LCD types. What we call "type 0" - appears to be similar to the ILI9320 and "type 1" is similar to the - LDS176. -*/ - -/* LCD type 0 register defines */ - -#define R_ENTRY_MODE 0x03 -#define R_DISPLAY_CONTROL_1 0x07 -#define R_POWER_CONTROL_1 0x10 -#define R_POWER_CONTROL_2 0x12 -#define R_POWER_CONTROL_3 0x13 -#define R_HORIZ_GRAM_ADDR_SET 0x20 -#define R_VERT_GRAM_ADDR_SET 0x21 -#define R_WRITE_DATA_TO_GRAM 0x22 -#define R_HORIZ_ADDR_START_POS 0x50 -#define R_HORIZ_ADDR_END_POS 0x51 -#define R_VERT_ADDR_START_POS 0x52 -#define R_VERT_ADDR_END_POS 0x53 - - -/* LCD type 1 register defines */ - -#define R_SLEEP_IN 0x10 -#define R_DISPLAY_OFF 0x28 -#define R_COLUMN_ADDR_SET 0x2a -#define R_ROW_ADDR_SET 0x2b -#define R_MEMORY_WRITE 0x2c - -/** globals **/ - -int lcd_type; /* also needed in debug-s5l8700.c */ -static int xoffset; /* needed for flip */ -static bool lcd_ispowered; - -#ifdef HAVE_LCD_SLEEP - -#define SLEEP 0 -#define CMD8 1 -#define CMD16 2 -#define DATA8 3 -#define DATA16 4 - -unsigned short lcd_init_sequence_0[] = { - CMD16, 0x00a4, - DATA16, 0x0001, - SLEEP, 0x0000, - CMD16, 0x0001, - DATA16, 0x0100, - CMD16, 0x0002, - DATA16, 0x0300, - CMD16, 0x0003, - DATA16, 0x1230, - CMD16, 0x0008, - DATA16, 0x0404, - CMD16, 0x0008, - DATA16, 0x0404, - CMD16, 0x000e, - DATA16, 0x0010, - CMD16, 0x0070, - DATA16, 0x1000, - CMD16, 0x0071, - DATA16, 0x0001, - CMD16, 0x0030, - DATA16, 0x0002, - CMD16, 0x0031, - DATA16, 0x0400, - CMD16, 0x0032, - DATA16, 0x0007, - CMD16, 0x0033, - DATA16, 0x0500, - CMD16, 0x0034, - DATA16, 0x0007, - CMD16, 0x0035, - DATA16, 0x0703, - CMD16, 0x0036, - DATA16, 0x0507, - CMD16, 0x0037, - DATA16, 0x0005, - CMD16, 0x0038, - DATA16, 0x0407, - CMD16, 0x0039, - DATA16, 0x000e, - CMD16, 0x0040, - DATA16, 0x0202, - CMD16, 0x0041, - DATA16, 0x0003, - CMD16, 0x0042, - DATA16, 0x0000, - CMD16, 0x0043, - DATA16, 0x0200, - CMD16, 0x0044, - DATA16, 0x0707, - CMD16, 0x0045, - DATA16, 0x0407, - CMD16, 0x0046, - DATA16, 0x0505, - CMD16, 0x0047, - DATA16, 0x0002, - CMD16, 0x0048, - DATA16, 0x0004, - CMD16, 0x0049, - DATA16, 0x0004, - CMD16, 0x0060, - DATA16, 0x0202, - CMD16, 0x0061, - DATA16, 0x0003, - CMD16, 0x0062, - DATA16, 0x0000, - CMD16, 0x0063, - DATA16, 0x0200, - CMD16, 0x0064, - DATA16, 0x0707, - CMD16, 0x0065, - DATA16, 0x0407, - CMD16, 0x0066, - DATA16, 0x0505, - CMD16, 0x0068, - DATA16, 0x0004, - CMD16, 0x0069, - DATA16, 0x0004, - CMD16, 0x0007, - DATA16, 0x0001, - CMD16, 0x0018, - DATA16, 0x0001, - CMD16, 0x0010, - DATA16, 0x1690, - CMD16, 0x0011, - DATA16, 0x0100, - CMD16, 0x0012, - DATA16, 0x0117, - CMD16, 0x0013, - DATA16, 0x0f80, - CMD16, 0x0012, - DATA16, 0x0137, - CMD16, 0x0020, - DATA16, 0x0000, - CMD16, 0x0021, - DATA16, 0x0000, - CMD16, 0x0050, - DATA16, 0x0000, - CMD16, 0x0051, - DATA16, 0x00af, - CMD16, 0x0052, - DATA16, 0x0000, - CMD16, 0x0053, - DATA16, 0x0083, - CMD16, 0x0090, - DATA16, 0x0003, - CMD16, 0x0091, - DATA16, 0x0000, - CMD16, 0x0092, - DATA16, 0x0101, - CMD16, 0x0098, - DATA16, 0x0400, - CMD16, 0x0099, - DATA16, 0x1302, - CMD16, 0x009a, - DATA16, 0x0202, - CMD16, 0x009b, - DATA16, 0x0200, - SLEEP, 0x0000, - CMD16, 0x0007, - DATA16, 0x0021, - CMD16, 0x0012, - DATA16, 0x0137, - SLEEP, 0x0000, - CMD16, 0x0007, - DATA16, 0x0021, - CMD16, 0x0012, - DATA16, 0x1137, - SLEEP, 0x0000, - CMD16, 0x0007, - DATA16, 0x0233, -}; - -unsigned short lcd_init_sequence_1[] = { - CMD8, 0x01, - DATA8, 0x00, - SLEEP, 0, - CMD8, 0xB1, - DATA8, 0x16, - DATA8, 0x03, - CMD8, 0xB2, - DATA8, 0x17, - DATA8, 0x03, - CMD8, 0xB4, - DATA8, 0x00, - CMD8, 0xB6, - DATA8, 0x01, - CMD8, 0xB7, - DATA8, 0x00, - DATA8, 0x00, - DATA8, 0x02, - DATA8, 0x00, - DATA8, 0x06, - DATA8, 0x26, - DATA8, 0x2D, - DATA8, 0x27, - DATA8, 0x55, - DATA8, 0x27, - CMD8, 0xB8, - DATA8, 0x10, - CMD8, 0xB9, - DATA8, 0x52, - DATA8, 0x12, - DATA8, 0x03, - CMD8, 0xC0, - DATA8, 0x0A, - DATA8, 0x10, - DATA8, 0x10, - CMD8, 0xC2, - DATA8, 0x14, - DATA8, 0x23, - CMD8, 0xC3, - DATA8, 0x12, - DATA8, 0x23, - CMD8, 0xC6, - DATA8, 0x48, - CMD8, 0xE0, - DATA8, 0x20, - DATA8, 0x71, - DATA8, 0x17, - DATA8, 0x09, - DATA8, 0x70, - DATA8, 0x0C, - DATA8, 0x13, - DATA8, 0x25, - CMD8, 0xE1, - DATA8, 0x37, - DATA8, 0x00, - DATA8, 0x63, - DATA8, 0x11, - DATA8, 0xD9, - DATA8, 0x00, - DATA8, 0x12, - DATA8, 0x01, - CMD8, 0xE2, - DATA8, 0x42, - DATA8, 0x42, - DATA8, 0x60, - DATA8, 0x08, - DATA8, 0xB4, - DATA8, 0x07, - DATA8, 0x0E, - DATA8, 0x90, - CMD8, 0xE3, - DATA8, 0x47, - DATA8, 0x60, - DATA8, 0x66, - DATA8, 0x09, - DATA8, 0x6A, - DATA8, 0x02, - DATA8, 0x0E, - DATA8, 0x09, - CMD8, 0xE4, - DATA8, 0x11, - DATA8, 0x40, - DATA8, 0x03, - DATA8, 0x0A, - DATA8, 0xC1, - DATA8, 0x0D, - DATA8, 0x17, - DATA8, 0x30, - CMD8, 0xE5, - DATA8, 0x00, - DATA8, 0x30, - DATA8, 0x77, - DATA8, 0x1C, - DATA8, 0xFB, - DATA8, 0x00, - DATA8, 0x13, - DATA8, 0x07, - CMD8, 0xE6, - DATA8, 0x01, - CMD8, 0x35, - DATA8, 0x00, - CMD8, 0x36, - DATA8, 0x00, - CMD8, 0xF2, - DATA8, 0x40, - CMD8, 0xF3, - DATA8, 0x50, - CMD8, 0xFB, - DATA8, 0x01, - CMD8, 0x11, - DATA8, 0x00, - SLEEP, 0, - CMD8, 0x3A, - DATA8, 0x65, - CMD8, 0x29, - DATA8, 0x00, -}; - -unsigned short lcd_init_sequence_2[] = { - CMD8, 0x01, - SLEEP, 0, - CMD8, 0x11, - SLEEP, 0, - CMD8, 0x3a, - DATA8, 0x65, - CMD8, 0xab, - CMD8, 0x35, - DATA8, 0x00, - CMD8, 0xf2, - DATA8, 0x01, - CMD8, 0xe0, - DATA8, 0x71, - DATA8, 0x76, - DATA8, 0x25, - DATA8, 0x01, - DATA8, 0xa5, - DATA8, 0x09, - DATA8, 0x15, - DATA8, 0x11, - CMD8, 0xe1, - DATA8, 0x40, - DATA8, 0x21, - DATA8, 0x64, - DATA8, 0x13, - DATA8, 0xf3, - DATA8, 0x0b, - DATA8, 0x00, - DATA8, 0x00, - CMD8, 0xe2, - DATA8, 0x71, - DATA8, 0x65, - DATA8, 0x24, - DATA8, 0x08, - DATA8, 0x97, - DATA8, 0x01, - DATA8, 0x15, - DATA8, 0x11, - CMD8, 0xe3, - DATA8, 0x51, - DATA8, 0x01, - DATA8, 0x62, - DATA8, 0x13, - DATA8, 0xf3, - DATA8, 0x0b, - DATA8, 0x00, - DATA8, 0x00, - CMD8, 0xe4, - DATA8, 0x71, - DATA8, 0x57, - DATA8, 0x31, - DATA8, 0x01, - DATA8, 0x82, - DATA8, 0x04, - DATA8, 0x1f, - DATA8, 0x11, - CMD8, 0xe5, - DATA8, 0x64, - DATA8, 0x41, - DATA8, 0x64, - DATA8, 0x19, - DATA8, 0xb3, - DATA8, 0x09, - DATA8, 0x00, - DATA8, 0x00, - CMD8, 0x29, -}; - -#endif /* HAVE_LCD_SLEEP */ - -static inline void s5l_lcd_write_cmd_data(int cmd, int data) -{ - while (LCD_STATUS & 0x10); - LCD_WCMD = cmd >> 8; - while (LCD_STATUS & 0x10); - LCD_WCMD = cmd & 0xff; - - while (LCD_STATUS & 0x10); - LCD_WDATA = data >> 8; - while (LCD_STATUS & 0x10); - LCD_WDATA = data & 0xff; -} - -static inline void s5l_lcd_write_cmd(unsigned short cmd) -{ - while (LCD_STATUS & 0x10); - LCD_WCMD = cmd; -} - -static inline void s5l_lcd_write_wcmd(unsigned short cmd) -{ - while (LCD_STATUS & 0x10); - LCD_WCMD = cmd >> 8; - while (LCD_STATUS & 0x10); - LCD_WCMD = cmd & 0xff; -} - -static inline void s5l_lcd_write_data(unsigned short data) -{ - while (LCD_STATUS & 0x10); - LCD_WDATA = data & 0xff; -} - -static inline void s5l_lcd_write_wdata(unsigned short data) -{ - while (LCD_STATUS & 0x10); - LCD_WDATA = data >> 8; - while (LCD_STATUS & 0x10); - LCD_WDATA = data & 0xff; -} - -/*** hardware configuration ***/ - -int lcd_default_contrast(void) -{ - return 0x1f; -} - -void lcd_set_contrast(int val) -{ - (void)val; -} - -void lcd_set_invert_display(bool yesno) -{ - (void)yesno; -} - -/* turn the display upside down (call lcd_update() afterwards) */ -void lcd_set_flip(bool yesno) -{ - /* TODO: flip mode isn't working. The commands in the else part of - this function are how the original firmware inits the LCD */ - - if (yesno) - { - xoffset = 132 - LCD_WIDTH; /* 132 colums minus the 128 we have */ - } - else - { - xoffset = 0; - } -} - -bool lcd_active(void) -{ - return lcd_ispowered; -} - -#ifdef HAVE_LCD_SLEEP - -void lcd_wakeup(void) -{ - unsigned short *lcd_init_sequence; - unsigned int lcd_init_sequence_length; - int type = lcd_type; - - pmu_ldo_set_voltage(2, 17); +/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2009 by Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+
+#include "hwcompat.h"
+#include "kernel.h"
+#include "lcd.h"
+#include "system.h"
+#include "cpu.h"
+#include "pmu-target.h"
+
+
+/* The Nano 2G has two different LCD types. What we call "type 0"
+ appears to be similar to the ILI9320 and "type 1" is similar to the
+ LDS176.
+*/
+
+/* LCD type 0 register defines */
+
+#define R_ENTRY_MODE 0x03
+#define R_DISPLAY_CONTROL_1 0x07
+#define R_POWER_CONTROL_1 0x10
+#define R_POWER_CONTROL_2 0x12
+#define R_POWER_CONTROL_3 0x13
+#define R_HORIZ_GRAM_ADDR_SET 0x20
+#define R_VERT_GRAM_ADDR_SET 0x21
+#define R_WRITE_DATA_TO_GRAM 0x22
+#define R_HORIZ_ADDR_START_POS 0x50
+#define R_HORIZ_ADDR_END_POS 0x51
+#define R_VERT_ADDR_START_POS 0x52
+#define R_VERT_ADDR_END_POS 0x53
+
+
+/* LCD type 1 register defines */
+
+#define R_SLEEP_IN 0x10
+#define R_DISPLAY_OFF 0x28
+#define R_COLUMN_ADDR_SET 0x2a
+#define R_ROW_ADDR_SET 0x2b
+#define R_MEMORY_WRITE 0x2c
+
+/** globals **/
+
+int lcd_type; /* also needed in debug-s5l8700.c */
+static int xoffset; /* needed for flip */
+static bool lcd_ispowered;
+
+#ifdef HAVE_LCD_SLEEP
+
+#define SLEEP 0
+#define CMD8 1
+#define CMD16 2
+#define DATA8 3
+#define DATA16 4
+
+unsigned short lcd_init_sequence_0[] = {
+ CMD16, 0x00a4,
+ DATA16, 0x0001,
+ SLEEP, 0x0000,
+ CMD16, 0x0001,
+ DATA16, 0x0100,
+ CMD16, 0x0002,
+ DATA16, 0x0300,
+ CMD16, 0x0003,
+ DATA16, 0x1230,
+ CMD16, 0x0008,
+ DATA16, 0x0404,
+ CMD16, 0x0008,
+ DATA16, 0x0404,
+ CMD16, 0x000e,
+ DATA16, 0x0010,
+ CMD16, 0x0070,
+ DATA16, 0x1000,
+ CMD16, 0x0071,
+ DATA16, 0x0001,
+ CMD16, 0x0030,
+ DATA16, 0x0002,
+ CMD16, 0x0031,
+ DATA16, 0x0400,
+ CMD16, 0x0032,
+ DATA16, 0x0007,
+ CMD16, 0x0033,
+ DATA16, 0x0500,
+ CMD16, 0x0034,
+ DATA16, 0x0007,
+ CMD16, 0x0035,
+ DATA16, 0x0703,
+ CMD16, 0x0036,
+ DATA16, 0x0507,
+ CMD16, 0x0037,
+ DATA16, 0x0005,
+ CMD16, 0x0038,
+ DATA16, 0x0407,
+ CMD16, 0x0039,
+ DATA16, 0x000e,
+ CMD16, 0x0040,
+ DATA16, 0x0202,
+ CMD16, 0x0041,
+ DATA16, 0x0003,
+ CMD16, 0x0042,
+ DATA16, 0x0000,
+ CMD16, 0x0043,
+ DATA16, 0x0200,
+ CMD16, 0x0044,
+ DATA16, 0x0707,
+ CMD16, 0x0045,
+ DATA16, 0x0407,
+ CMD16, 0x0046,
+ DATA16, 0x0505,
+ CMD16, 0x0047,
+ DATA16, 0x0002,
+ CMD16, 0x0048,
+ DATA16, 0x0004,
+ CMD16, 0x0049,
+ DATA16, 0x0004,
+ CMD16, 0x0060,
+ DATA16, 0x0202,
+ CMD16, 0x0061,
+ DATA16, 0x0003,
+ CMD16, 0x0062,
+ DATA16, 0x0000,
+ CMD16, 0x0063,
+ DATA16, 0x0200,
+ CMD16, 0x0064,
+ DATA16, 0x0707,
+ CMD16, 0x0065,
+ DATA16, 0x0407,
+ CMD16, 0x0066,
+ DATA16, 0x0505,
+ CMD16, 0x0068,
+ DATA16, 0x0004,
+ CMD16, 0x0069,
+ DATA16, 0x0004,
+ CMD16, 0x0007,
+ DATA16, 0x0001,
+ CMD16, 0x0018,
+ DATA16, 0x0001,
+ CMD16, 0x0010,
+ DATA16, 0x1690,
+ CMD16, 0x0011,
+ DATA16, 0x0100,
+ CMD16, 0x0012,
+ DATA16, 0x0117,
+ CMD16, 0x0013,
+ DATA16, 0x0f80,
+ CMD16, 0x0012,
+ DATA16, 0x0137,
+ CMD16, 0x0020,
+ DATA16, 0x0000,
+ CMD16, 0x0021,
+ DATA16, 0x0000,
+ CMD16, 0x0050,
+ DATA16, 0x0000,
+ CMD16, 0x0051,
+ DATA16, 0x00af,
+ CMD16, 0x0052,
+ DATA16, 0x0000,
+ CMD16, 0x0053,
+ DATA16, 0x0083,
+ CMD16, 0x0090,
+ DATA16, 0x0003,
+ CMD16, 0x0091,
+ DATA16, 0x0000,
+ CMD16, 0x0092,
+ DATA16, 0x0101,
+ CMD16, 0x0098,
+ DATA16, 0x0400,
+ CMD16, 0x0099,
+ DATA16, 0x1302,
+ CMD16, 0x009a,
+ DATA16, 0x0202,
+ CMD16, 0x009b,
+ DATA16, 0x0200,
+ SLEEP, 0x0000,
+ CMD16, 0x0007,
+ DATA16, 0x0021,
+ CMD16, 0x0012,
+ DATA16, 0x0137,
+ SLEEP, 0x0000,
+ CMD16, 0x0007,
+ DATA16, 0x0021,
+ CMD16, 0x0012,
+ DATA16, 0x1137,
+ SLEEP, 0x0000,
+ CMD16, 0x0007,
+ DATA16, 0x0233,
+};
+
+unsigned short lcd_init_sequence_1[] = {
+ CMD8, 0x01,
+ DATA8, 0x00,
+ SLEEP, 0,
+ CMD8, 0xB1,
+ DATA8, 0x16,
+ DATA8, 0x03,
+ CMD8, 0xB2,
+ DATA8, 0x17,
+ DATA8, 0x03,
+ CMD8, 0xB4,
+ DATA8, 0x00,
+ CMD8, 0xB6,
+ DATA8, 0x01,
+ CMD8, 0xB7,
+ DATA8, 0x00,
+ DATA8, 0x00,
+ DATA8, 0x02,
+ DATA8, 0x00,
+ DATA8, 0x06,
+ DATA8, 0x26,
+ DATA8, 0x2D,
+ DATA8, 0x27,
+ DATA8, 0x55,
+ DATA8, 0x27,
+ CMD8, 0xB8,
+ DATA8, 0x10,
+ CMD8, 0xB9,
+ DATA8, 0x52,
+ DATA8, 0x12,
+ DATA8, 0x03,
+ CMD8, 0xC0,
+ DATA8, 0x0A,
+ DATA8, 0x10,
+ DATA8, 0x10,
+ CMD8, 0xC2,
+ DATA8, 0x14,
+ DATA8, 0x23,
+ CMD8, 0xC3,
+ DATA8, 0x12,
+ DATA8, 0x23,
+ CMD8, 0xC6,
+ DATA8, 0x48,
+ CMD8, 0xE0,
+ DATA8, 0x20,
+ DATA8, 0x71,
+ DATA8, 0x17,
+ DATA8, 0x09,
+ DATA8, 0x70,
+ DATA8, 0x0C,
+ DATA8, 0x13,
+ DATA8, 0x25,
+ CMD8, 0xE1,
+ DATA8, 0x37,
+ DATA8, 0x00,
+ DATA8, 0x63,
+ DATA8, 0x11,
+ DATA8, 0xD9,
+ DATA8, 0x00,
+ DATA8, 0x12,
+ DATA8, 0x01,
+ CMD8, 0xE2,
+ DATA8, 0x42,
+ DATA8, 0x42,
+ DATA8, 0x60,
+ DATA8, 0x08,
+ DATA8, 0xB4,
+ DATA8, 0x07,
+ DATA8, 0x0E,
+ DATA8, 0x90,
+ CMD8, 0xE3,
+ DATA8, 0x47,
+ DATA8, 0x60,
+ DATA8, 0x66,
+ DATA8, 0x09,
+ DATA8, 0x6A,
+ DATA8, 0x02,
+ DATA8, 0x0E,
+ DATA8, 0x09,
+ CMD8, 0xE4,
+ DATA8, 0x11,
+ DATA8, 0x40,
+ DATA8, 0x03,
+ DATA8, 0x0A,
+ DATA8, 0xC1,
+ DATA8, 0x0D,
+ DATA8, 0x17,
+ DATA8, 0x30,
+ CMD8, 0xE5,
+ DATA8, 0x00,
+ DATA8, 0x30,
+ DATA8, 0x77,
+ DATA8, 0x1C,
+ DATA8, 0xFB,
+ DATA8, 0x00,
+ DATA8, 0x13,
+ DATA8, 0x07,
+ CMD8, 0xE6,
+ DATA8, 0x01,
+ CMD8, 0x35,
+ DATA8, 0x00,
+ CMD8, 0x36,
+ DATA8, 0x00,
+ CMD8, 0xF2,
+ DATA8, 0x40,
+ CMD8, 0xF3,
+ DATA8, 0x50,
+ CMD8, 0xFB,
+ DATA8, 0x01,
+ CMD8, 0x11,
+ DATA8, 0x00,
+ SLEEP, 0,
+ CMD8, 0x3A,
+ DATA8, 0x65,
+ CMD8, 0x29,
+ DATA8, 0x00,
+};
+
+unsigned short lcd_init_sequence_2[] = {
+ CMD8, 0x01,
+ SLEEP, 0,
+ CMD8, 0x11,
+ SLEEP, 0,
+ CMD8, 0x3a,
+ DATA8, 0x65,
+ CMD8, 0xab,
+ CMD8, 0x35,
+ DATA8, 0x00,
+ CMD8, 0xf2,
+ DATA8, 0x01,
+ CMD8, 0xe0,
+ DATA8, 0x71,
+ DATA8, 0x76,
+ DATA8, 0x25,
+ DATA8, 0x01,
+ DATA8, 0xa5,
+ DATA8, 0x09,
+ DATA8, 0x15,
+ DATA8, 0x11,
+ CMD8, 0xe1,
+ DATA8, 0x40,
+ DATA8, 0x21,
+ DATA8, 0x64,
+ DATA8, 0x13,
+ DATA8, 0xf3,
+ DATA8, 0x0b,
+ DATA8, 0x00,
+ DATA8, 0x00,
+ CMD8, 0xe2,
+ DATA8, 0x71,
+ DATA8, 0x65,
+ DATA8, 0x24,
+ DATA8, 0x08,
+ DATA8, 0x97,
+ DATA8, 0x01,
+ DATA8, 0x15,
+ DATA8, 0x11,
+ CMD8, 0xe3,
+ DATA8, 0x51,
+ DATA8, 0x01,
+ DATA8, 0x62,
+ DATA8, 0x13,
+ DATA8, 0xf3,
+ DATA8, 0x0b,
+ DATA8, 0x00,
+ DATA8, 0x00,
+ CMD8, 0xe4,
+ DATA8, 0x71,
+ DATA8, 0x57,
+ DATA8, 0x31,
+ DATA8, 0x01,
+ DATA8, 0x82,
+ DATA8, 0x04,
+ DATA8, 0x1f,
+ DATA8, 0x11,
+ CMD8, 0xe5,
+ DATA8, 0x64,
+ DATA8, 0x41,
+ DATA8, 0x64,
+ DATA8, 0x19,
+ DATA8, 0xb3,
+ DATA8, 0x09,
+ DATA8, 0x00,
+ DATA8, 0x00,
+ CMD8, 0x29,
+};
+
+#endif /* HAVE_LCD_SLEEP */
+
+static inline void s5l_lcd_write_cmd_data(int cmd, int data)
+{
+ while (LCD_STATUS & 0x10);
+ LCD_WCMD = cmd >> 8;
+ while (LCD_STATUS & 0x10);
+ LCD_WCMD = cmd & 0xff;
+
+ while (LCD_STATUS & 0x10);
+ LCD_WDATA = data >> 8;
+ while (LCD_STATUS & 0x10);
+ LCD_WDATA = data & 0xff;
+}
+
+static inline void s5l_lcd_write_cmd(unsigned short cmd)
+{
+ while (LCD_STATUS & 0x10);
+ LCD_WCMD = cmd;
+}
+
+static inline void s5l_lcd_write_wcmd(unsigned short cmd)
+{
+ while (LCD_STATUS & 0x10);
+ LCD_WCMD = cmd >> 8;
+ while (LCD_STATUS & 0x10);
+ LCD_WCMD = cmd & 0xff;
+}
+
+static inline void s5l_lcd_write_data(unsigned short data)
+{
+ while (LCD_STATUS & 0x10);
+ LCD_WDATA = data & 0xff;
+}
+
+static inline void s5l_lcd_write_wdata(unsigned short data)
+{
+ while (LCD_STATUS & 0x10);
+ LCD_WDATA = data >> 8;
+ while (LCD_STATUS & 0x10);
+ LCD_WDATA = data & 0xff;
+}
+
+/*** hardware configuration ***/
+
+int lcd_default_contrast(void)
+{
+ return 0x1f;
+}
+
+void lcd_set_contrast(int val)
+{
+ (void)val;
+}
+
+void lcd_set_invert_display(bool yesno)
+{
+ (void)yesno;
+}
+
+/* turn the display upside down (call lcd_update() afterwards) */
+void lcd_set_flip(bool yesno)
+{
+ /* TODO: flip mode isn't working. The commands in the else part of
+ this function are how the original firmware inits the LCD */
+
+ if (yesno)
+ {
+ xoffset = 132 - LCD_WIDTH; /* 132 colums minus the 128 we have */
+ }
+ else
+ {
+ xoffset = 0;
+ }
+}
+
+bool lcd_active(void)
+{
+ return lcd_ispowered;
+}
+
+#ifdef HAVE_LCD_SLEEP
+
+void lcd_wakeup(void)
+{
+ unsigned short *lcd_init_sequence;
+ unsigned int lcd_init_sequence_length;
+ int type = lcd_type;
+
+ pmu_ldo_set_voltage(2, 17);
PWRCONEXT &= ~0x80;
PCON2 = 0x33333333;
PCON3 = 0x11113333;
PCON4 = 0x33333333;
- PCON13 &= ~0xf; /* Set pin 0 to input */ - PCON14 &= ~0xf0; /* Set pin 1 to input */ - - if((((PDAT13 & 1) == 1) && ((PDAT14 & 2) == 2))|| - (((PDAT13 & 1) == 0) && ((PDAT14 & 2) == 0))) - { - type = 2; /* there is a third lcd type which behaves like type 7 (LDS176) but needs to be initialized differently */ - } - - if(type == 0) - { - lcd_init_sequence = lcd_init_sequence_0; - lcd_init_sequence_length = (sizeof(lcd_init_sequence_0) - 1)/sizeof(unsigned short); - } - else if(type == 1) - { - lcd_init_sequence = lcd_init_sequence_1; - lcd_init_sequence_length = (sizeof(lcd_init_sequence_1) - 1)/sizeof(unsigned short); - } - else - { - lcd_init_sequence = lcd_init_sequence_2; - lcd_init_sequence_length = (sizeof(lcd_init_sequence_2) - 1)/sizeof(unsigned short); - } - - /* reset the lcd chip */ - - LCD_RST_TIME = 0x7FFF; - LCD_DRV_RST = 0; - sleep(0); - LCD_DRV_RST = 1; - sleep(HZ / 100); - - for(unsigned int i=0;i<lcd_init_sequence_length;i+=2) - { - switch(lcd_init_sequence[i]) - { - case CMD8: - s5l_lcd_write_cmd(lcd_init_sequence[i+1]); - break; - case DATA8: - s5l_lcd_write_data(lcd_init_sequence[i+1]); - break; - case CMD16: - s5l_lcd_write_wcmd(lcd_init_sequence[i+1]); - break; - case DATA16: - s5l_lcd_write_wdata(lcd_init_sequence[i+1]); - break; - case SLEEP: - sleep(lcd_init_sequence[i+1]); - break; - default: - break; - } - } - lcd_ispowered = true; -} - -void lcd_awake(void) -{ - if(!lcd_active()) lcd_wakeup(); -} -#endif - -void lcd_shutdown(void) -{ - pmu_write(0x2b, 0); /* Kill the backlight, instantly. */ - pmu_write(0x29, 0); - - if (lcd_type == 0) - { - s5l_lcd_write_cmd_data(R_DISPLAY_CONTROL_1, 0x232); - s5l_lcd_write_cmd_data(R_POWER_CONTROL_3, 0x1137); - s5l_lcd_write_cmd_data(R_DISPLAY_CONTROL_1, 0x201); - s5l_lcd_write_cmd_data(R_POWER_CONTROL_3, 0x137); - s5l_lcd_write_cmd_data(R_DISPLAY_CONTROL_1, 0x200); - s5l_lcd_write_cmd_data(R_POWER_CONTROL_1, 0x680); - s5l_lcd_write_cmd_data(R_POWER_CONTROL_2, 0x160); - s5l_lcd_write_cmd_data(R_POWER_CONTROL_3, 0x127); - s5l_lcd_write_cmd_data(R_POWER_CONTROL_1, 0x600); - } - else - { - s5l_lcd_write_cmd(R_DISPLAY_OFF); - s5l_lcd_write_wdata(0); - s5l_lcd_write_wdata(0); - s5l_lcd_write_cmd(R_SLEEP_IN); - s5l_lcd_write_wdata(0); - s5l_lcd_write_wdata(0); - } - + PCON13 &= ~0xf; /* Set pin 0 to input */
+ PCON14 &= ~0xf0; /* Set pin 1 to input */
+
+ if((((PDAT13 & 1) == 1) && ((PDAT14 & 2) == 2))||
+ (((PDAT13 & 1) == 0) && ((PDAT14 & 2) == 0)))
+ {
+ type = 2; /* there is a third lcd type which behaves like type 7 (LDS176) but needs to be initialized differently */
+ }
+
+ if(type == 0)
+ {
+ lcd_init_sequence = lcd_init_sequence_0;
+ lcd_init_sequence_length = (sizeof(lcd_init_sequence_0) - 1)/sizeof(unsigned short);
+ }
+ else if(type == 1)
+ {
+ lcd_init_sequence = lcd_init_sequence_1;
+ lcd_init_sequence_length = (sizeof(lcd_init_sequence_1) - 1)/sizeof(unsigned short);
+ }
+ else
+ {
+ lcd_init_sequence = lcd_init_sequence_2;
+ lcd_init_sequence_length = (sizeof(lcd_init_sequence_2) - 1)/sizeof(unsigned short);
+ }
+
+ /* reset the lcd chip */
+
+ LCD_RST_TIME = 0x7FFF;
+ LCD_DRV_RST = 0;
+ sleep(0);
+ LCD_DRV_RST = 1;
+ sleep(HZ / 100);
+
+ for(unsigned int i=0;i<lcd_init_sequence_length;i+=2)
+ {
+ switch(lcd_init_sequence[i])
+ {
+ case CMD8:
+ s5l_lcd_write_cmd(lcd_init_sequence[i+1]);
+ break;
+ case DATA8:
+ s5l_lcd_write_data(lcd_init_sequence[i+1]);
+ break;
+ case CMD16:
+ s5l_lcd_write_wcmd(lcd_init_sequence[i+1]);
+ break;
+ case DATA16:
+ s5l_lcd_write_wdata(lcd_init_sequence[i+1]);
+ break;
+ case SLEEP:
+ sleep(lcd_init_sequence[i+1]);
+ break;
+ default:
+ break;
+ }
+ }
+ lcd_ispowered = true;
+ send_event(LCD_EVENT_ACTIVATION, NULL); +}
+
+void lcd_awake(void)
+{
+ if(!lcd_active()) lcd_wakeup();
+}
+#endif
+
+void lcd_shutdown(void)
+{
+ pmu_write(0x2b, 0); /* Kill the backlight, instantly. */
+ pmu_write(0x29, 0);
+
+ if (lcd_type == 0)
+ {
+ s5l_lcd_write_cmd_data(R_DISPLAY_CONTROL_1, 0x232);
+ s5l_lcd_write_cmd_data(R_POWER_CONTROL_3, 0x1137);
+ s5l_lcd_write_cmd_data(R_DISPLAY_CONTROL_1, 0x201);
+ s5l_lcd_write_cmd_data(R_POWER_CONTROL_3, 0x137);
+ s5l_lcd_write_cmd_data(R_DISPLAY_CONTROL_1, 0x200);
+ s5l_lcd_write_cmd_data(R_POWER_CONTROL_1, 0x680);
+ s5l_lcd_write_cmd_data(R_POWER_CONTROL_2, 0x160);
+ s5l_lcd_write_cmd_data(R_POWER_CONTROL_3, 0x127);
+ s5l_lcd_write_cmd_data(R_POWER_CONTROL_1, 0x600);
+ }
+ else
+ {
+ s5l_lcd_write_cmd(R_DISPLAY_OFF);
+ s5l_lcd_write_wdata(0);
+ s5l_lcd_write_wdata(0);
+ s5l_lcd_write_cmd(R_SLEEP_IN);
+ s5l_lcd_write_wdata(0);
+ s5l_lcd_write_wdata(0);
+ }
+
PCON2 = 0;
PCON3 = 0;
PCON4 = 0;
PWRCONEXT |= 0x80;
- sleep(HZ / 20); - pmu_ldo_set_voltage(2, 1); - - lcd_ispowered = false; -} - -void lcd_sleep(void) -{ - lcd_shutdown(); -} - -/* LCD init */ -void lcd_init_device(void) -{ - /* Detect lcd type */ - - PCON13 &= ~0xf; /* Set pin 0 to input */ - PCON14 &= ~0xf0; /* Set pin 1 to input */ - - if (((PDAT13 & 1) == 0) && ((PDAT14 & 2) == 2)) - lcd_type = 0; /* Similar to ILI9320 - aka "type 2" */ - else - lcd_type = 1; /* Similar to LDS176 - aka "type 7" */ - - lcd_ispowered = true; -} - -/*** Update functions ***/ - -static inline void lcd_write_pixel(fb_data pixel) -{ - while (LCD_STATUS & 0x10); - LCD_WDATA = (pixel & 0xff00) >> 8; - while (LCD_STATUS & 0x10); - LCD_WDATA = pixel & 0xff; -} - -/* Update the display. - This must be called after all other LCD functions that change the display. */ -void lcd_update(void) ICODE_ATTR; -void lcd_update(void) -{ - int x,y; - fb_data* p = &lcd_framebuffer[0][0]; - - if (lcd_type==0) { - s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, 0); - s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, LCD_WIDTH-1); - s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, 0); - s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, LCD_HEIGHT-1); - - s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, 0); - s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, 0); - - s5l_lcd_write_cmd(0); - s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); - } else { - s5l_lcd_write_cmd(R_COLUMN_ADDR_SET); - s5l_lcd_write_wdata(0); /* Start column */ - s5l_lcd_write_wdata(LCD_WIDTH-1); /* End column */ - - s5l_lcd_write_cmd(R_ROW_ADDR_SET); - s5l_lcd_write_wdata(0); /* Start row */ - s5l_lcd_write_wdata(LCD_HEIGHT-1); /* End row */ - - s5l_lcd_write_cmd(R_MEMORY_WRITE); - } - - - /* Copy display bitmap to hardware */ - for (y = 0; y < LCD_HEIGHT; y++) { - for (x = 0; x < LCD_WIDTH; x++) { - lcd_write_pixel(*(p++)); - } - } -} - -/* Update a fraction of the display. */ -void lcd_update_rect(int, int, int, int) ICODE_ATTR; -void lcd_update_rect(int x, int y, int width, int height) -{ - int xx,yy; - int y0, x0, y1, x1; - fb_data* p; - - x0 = x; /* start horiz */ - y0 = y; /* start vert */ - x1 = (x + width) - 1; /* max horiz */ - y1 = (y + height) - 1; /* max vert */ - - if (lcd_type==0) { - s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0); - s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1); - s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0); - s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1); - - s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, (x1 << 8) | x0); - s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, (y1 << 8) | y0); - - s5l_lcd_write_cmd(0); - s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); - } else { - s5l_lcd_write_cmd(R_COLUMN_ADDR_SET); - s5l_lcd_write_wdata(x0); /* Start column */ - s5l_lcd_write_wdata(x1); /* End column */ - - s5l_lcd_write_cmd(R_ROW_ADDR_SET); - s5l_lcd_write_wdata(y0); /* Start row */ - s5l_lcd_write_wdata(y1); /* End row */ - - s5l_lcd_write_cmd(R_MEMORY_WRITE); - } - - - /* Copy display bitmap to hardware */ - p = &lcd_framebuffer[y0][x0]; - yy = height; - for (yy = y0; yy <= y1; yy++) { - for (xx = x0; xx <= x1; xx++) { - lcd_write_pixel(*(p++)); - } - p += LCD_WIDTH - width; - } -} - -/*** update functions ***/ - -#define CSUB_X 2 -#define CSUB_Y 2 - -/* YUV- > RGB565 conversion - * |R| |1.000000 -0.000001 1.402000| |Y'| - * |G| = |1.000000 -0.334136 -0.714136| |Pb| - * |B| |1.000000 1.772000 0.000000| |Pr| - * Scaled, normalized, rounded and tweaked to yield RGB 565: - * |R| |74 0 101| |Y' - 16| >> 9 - * |G| = |74 -24 -51| |Cb - 128| >> 8 - * |B| |74 128 0| |Cr - 128| >> 9 -*/ - -#define RGBYFAC 74 /* 1.0 */ -#define RVFAC 101 /* 1.402 */ -#define GVFAC (-51) /* -0.714136 */ -#define GUFAC (-24) /* -0.334136 */ -#define BUFAC 128 /* 1.772 */ - -/* ROUNDOFFS contain constant for correct round-offs as well as - constant parts of the conversion matrix (e.g. (Y'-16)*RGBYFAC - -> constant part = -16*RGBYFAC). Through extraction of these - constant parts we save at leat 4 substractions in the conversion - loop */ -#define ROUNDOFFSR (256 - 16*RGBYFAC - 128*RVFAC) -#define ROUNDOFFSG (128 - 16*RGBYFAC - 128*GVFAC - 128*GUFAC) -#define ROUNDOFFSB (256 - 16*RGBYFAC - 128*BUFAC) - -#define MAX_5BIT 0x1f -#define MAX_6BIT 0x3f - -/* Performance function to blit a YUV bitmap directly to the LCD */ -void lcd_blit_yuv(unsigned char * const src[3], - int src_x, int src_y, int stride, - int x, int y, int width, int height) -{ - int h; - int y0, x0, y1, x1; - - width = (width + 1) & ~1; - - x0 = x; /* start horiz */ - y0 = y; /* start vert */ - x1 = (x + width) - 1; /* max horiz */ - y1 = (y + height) - 1; /* max vert */ - - if (lcd_type==0) { - s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0); - s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1); - s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0); - s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1); - - s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, (x1 << 8) | x0); - s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, (y1 << 8) | y0); - - s5l_lcd_write_cmd(0); - s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); - } else { - s5l_lcd_write_cmd(R_COLUMN_ADDR_SET); - s5l_lcd_write_wdata(x0); /* Start column */ - s5l_lcd_write_wdata(x1); /* End column */ - - s5l_lcd_write_cmd(R_ROW_ADDR_SET); - s5l_lcd_write_wdata(y0); /* Start row */ - s5l_lcd_write_wdata(y1); /* End row */ - - s5l_lcd_write_cmd(R_MEMORY_WRITE); - } - - const int stride_div_csub_x = stride/CSUB_X; - - h = height; - while (h > 0) { - /* 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 yp, up, vp; - int red1, green1, blue1; - int red2, green2, blue2; - - int rc, gc, bc; - - do - { - up = *usrc++; - vp = *vsrc++; - rc = RVFAC * vp + ROUNDOFFSR; - gc = GVFAC * vp + GUFAC * up + ROUNDOFFSG; - bc = BUFAC * up + ROUNDOFFSB; - - /* Pixel 1 -> RGB565 */ - yp = *ysrc++ * RGBYFAC; - red1 = (yp + rc) >> 9; - green1 = (yp + gc) >> 8; - blue1 = (yp + bc) >> 9; - - /* Pixel 2 -> RGB565 */ - yp = *ysrc++ * RGBYFAC; - red2 = (yp + rc) >> 9; - green2 = (yp + gc) >> 8; - blue2 = (yp + bc) >> 9; - - /* 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 being !=0 when bitmasking them. - We first check for red and blue components (5bit range). */ - if ((red1 | blue1 | red2 | blue2) & ~MAX_5BIT) - { - if (red1 & ~MAX_5BIT) - red1 = (red1 >> 31) ? 0 : MAX_5BIT; - if (blue1 & ~MAX_5BIT) - blue1 = (blue1 >> 31) ? 0 : MAX_5BIT; - if (red2 & ~MAX_5BIT) - red2 = (red2 >> 31) ? 0 : MAX_5BIT; - if (blue2 & ~MAX_5BIT) - blue2 = (blue2 >> 31) ? 0 : MAX_5BIT; - } - /* We second check for green component (6bit range) */ - if ((green1 | green2) & ~MAX_6BIT) - { - if (green1 & ~MAX_6BIT) - green1 = (green1 >> 31) ? 0 : MAX_6BIT; - if (green2 & ~MAX_6BIT) - green2 = (green2 >> 31) ? 0 : MAX_6BIT; - } - - /* output 2 pixels */ - lcd_write_pixel((red1 << 11) | (green1 << 5) | blue1); - lcd_write_pixel((red2 << 11) | (green2 << 5) | blue2); - } - while (ysrc < row_end); - - src_y++; - h--; - } -} + sleep(HZ / 20);
+ pmu_ldo_set_voltage(2, 1);
+
+ lcd_ispowered = false;
+}
+
+void lcd_sleep(void)
+{
+ lcd_shutdown();
+}
+
+/* LCD init */
+void lcd_init_device(void)
+{
+ /* Detect lcd type */
+
+ PCON13 &= ~0xf; /* Set pin 0 to input */
+ PCON14 &= ~0xf0; /* Set pin 1 to input */
+
+ if (((PDAT13 & 1) == 0) && ((PDAT14 & 2) == 2))
+ lcd_type = 0; /* Similar to ILI9320 - aka "type 2" */
+ else
+ lcd_type = 1; /* Similar to LDS176 - aka "type 7" */
+
+ lcd_ispowered = true;
+}
+
+/*** Update functions ***/
+
+static inline void lcd_write_pixel(fb_data pixel)
+{
+ while (LCD_STATUS & 0x10);
+ LCD_WDATA = (pixel & 0xff00) >> 8;
+ while (LCD_STATUS & 0x10);
+ LCD_WDATA = pixel & 0xff;
+}
+
+/* Update the display.
+ This must be called after all other LCD functions that change the display. */
+void lcd_update(void) ICODE_ATTR;
+void lcd_update(void)
+{
+ int x,y;
+ fb_data* p = &lcd_framebuffer[0][0];
+
+ if (lcd_type==0) {
+ s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, 0);
+ s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, LCD_WIDTH-1);
+ s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, 0);
+ s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, LCD_HEIGHT-1);
+
+ s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, 0);
+ s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, 0);
+
+ s5l_lcd_write_cmd(0);
+ s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM);
+ } else {
+ s5l_lcd_write_cmd(R_COLUMN_ADDR_SET);
+ s5l_lcd_write_wdata(0); /* Start column */
+ s5l_lcd_write_wdata(LCD_WIDTH-1); /* End column */
+
+ s5l_lcd_write_cmd(R_ROW_ADDR_SET);
+ s5l_lcd_write_wdata(0); /* Start row */
+ s5l_lcd_write_wdata(LCD_HEIGHT-1); /* End row */
+
+ s5l_lcd_write_cmd(R_MEMORY_WRITE);
+ }
+
+
+ /* Copy display bitmap to hardware */
+ for (y = 0; y < LCD_HEIGHT; y++) {
+ for (x = 0; x < LCD_WIDTH; x++) {
+ lcd_write_pixel(*(p++));
+ }
+ }
+}
+
+/* Update a fraction of the display. */
+void lcd_update_rect(int, int, int, int) ICODE_ATTR;
+void lcd_update_rect(int x, int y, int width, int height)
+{
+ int xx,yy;
+ int y0, x0, y1, x1;
+ fb_data* p;
+
+ x0 = x; /* start horiz */
+ y0 = y; /* start vert */
+ x1 = (x + width) - 1; /* max horiz */
+ y1 = (y + height) - 1; /* max vert */
+
+ if (lcd_type==0) {
+ s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0);
+ s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1);
+ s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0);
+ s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1);
+
+ s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, (x1 << 8) | x0);
+ s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, (y1 << 8) | y0);
+
+ s5l_lcd_write_cmd(0);
+ s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM);
+ } else {
+ s5l_lcd_write_cmd(R_COLUMN_ADDR_SET);
+ s5l_lcd_write_wdata(x0); /* Start column */
+ s5l_lcd_write_wdata(x1); /* End column */
+
+ s5l_lcd_write_cmd(R_ROW_ADDR_SET);
+ s5l_lcd_write_wdata(y0); /* Start row */
+ s5l_lcd_write_wdata(y1); /* End row */
+
+ s5l_lcd_write_cmd(R_MEMORY_WRITE);
+ }
+
+
+ /* Copy display bitmap to hardware */
+ p = &lcd_framebuffer[y0][x0];
+ yy = height;
+ for (yy = y0; yy <= y1; yy++) {
+ for (xx = x0; xx <= x1; xx++) {
+ lcd_write_pixel(*(p++));
+ }
+ p += LCD_WIDTH - width;
+ }
+}
+
+/*** update functions ***/
+
+#define CSUB_X 2
+#define CSUB_Y 2
+
+/* YUV- > RGB565 conversion
+ * |R| |1.000000 -0.000001 1.402000| |Y'|
+ * |G| = |1.000000 -0.334136 -0.714136| |Pb|
+ * |B| |1.000000 1.772000 0.000000| |Pr|
+ * Scaled, normalized, rounded and tweaked to yield RGB 565:
+ * |R| |74 0 101| |Y' - 16| >> 9
+ * |G| = |74 -24 -51| |Cb - 128| >> 8
+ * |B| |74 128 0| |Cr - 128| >> 9
+*/
+
+#define RGBYFAC 74 /* 1.0 */
+#define RVFAC 101 /* 1.402 */
+#define GVFAC (-51) /* -0.714136 */
+#define GUFAC (-24) /* -0.334136 */
+#define BUFAC 128 /* 1.772 */
+
+/* ROUNDOFFS contain constant for correct round-offs as well as
+ constant parts of the conversion matrix (e.g. (Y'-16)*RGBYFAC
+ -> constant part = -16*RGBYFAC). Through extraction of these
+ constant parts we save at leat 4 substractions in the conversion
+ loop */
+#define ROUNDOFFSR (256 - 16*RGBYFAC - 128*RVFAC)
+#define ROUNDOFFSG (128 - 16*RGBYFAC - 128*GVFAC - 128*GUFAC)
+#define ROUNDOFFSB (256 - 16*RGBYFAC - 128*BUFAC)
+
+#define MAX_5BIT 0x1f
+#define MAX_6BIT 0x3f
+
+/* Performance function to blit a YUV bitmap directly to the LCD */
+void lcd_blit_yuv(unsigned char * const src[3],
+ int src_x, int src_y, int stride,
+ int x, int y, int width, int height)
+{
+ int h;
+ int y0, x0, y1, x1;
+
+ width = (width + 1) & ~1;
+
+ x0 = x; /* start horiz */
+ y0 = y; /* start vert */
+ x1 = (x + width) - 1; /* max horiz */
+ y1 = (y + height) - 1; /* max vert */
+
+ if (lcd_type==0) {
+ s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0);
+ s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1);
+ s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0);
+ s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1);
+
+ s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, (x1 << 8) | x0);
+ s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, (y1 << 8) | y0);
+
+ s5l_lcd_write_cmd(0);
+ s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM);
+ } else {
+ s5l_lcd_write_cmd(R_COLUMN_ADDR_SET);
+ s5l_lcd_write_wdata(x0); /* Start column */
+ s5l_lcd_write_wdata(x1); /* End column */
+
+ s5l_lcd_write_cmd(R_ROW_ADDR_SET);
+ s5l_lcd_write_wdata(y0); /* Start row */
+ s5l_lcd_write_wdata(y1); /* End row */
+
+ s5l_lcd_write_cmd(R_MEMORY_WRITE);
+ }
+
+ const int stride_div_csub_x = stride/CSUB_X;
+
+ h = height;
+ while (h > 0) {
+ /* 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 yp, up, vp;
+ int red1, green1, blue1;
+ int red2, green2, blue2;
+
+ int rc, gc, bc;
+
+ do
+ {
+ up = *usrc++;
+ vp = *vsrc++;
+ rc = RVFAC * vp + ROUNDOFFSR;
+ gc = GVFAC * vp + GUFAC * up + ROUNDOFFSG;
+ bc = BUFAC * up + ROUNDOFFSB;
+
+ /* Pixel 1 -> RGB565 */
+ yp = *ysrc++ * RGBYFAC;
+ red1 = (yp + rc) >> 9;
+ green1 = (yp + gc) >> 8;
+ blue1 = (yp + bc) >> 9;
+
+ /* Pixel 2 -> RGB565 */
+ yp = *ysrc++ * RGBYFAC;
+ red2 = (yp + rc) >> 9;
+ green2 = (yp + gc) >> 8;
+ blue2 = (yp + bc) >> 9;
+
+ /* 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 being !=0 when bitmasking them.
+ We first check for red and blue components (5bit range). */
+ if ((red1 | blue1 | red2 | blue2) & ~MAX_5BIT)
+ {
+ if (red1 & ~MAX_5BIT)
+ red1 = (red1 >> 31) ? 0 : MAX_5BIT;
+ if (blue1 & ~MAX_5BIT)
+ blue1 = (blue1 >> 31) ? 0 : MAX_5BIT;
+ if (red2 & ~MAX_5BIT)
+ red2 = (red2 >> 31) ? 0 : MAX_5BIT;
+ if (blue2 & ~MAX_5BIT)
+ blue2 = (blue2 >> 31) ? 0 : MAX_5BIT;
+ }
+ /* We second check for green component (6bit range) */
+ if ((green1 | green2) & ~MAX_6BIT)
+ {
+ if (green1 & ~MAX_6BIT)
+ green1 = (green1 >> 31) ? 0 : MAX_6BIT;
+ if (green2 & ~MAX_6BIT)
+ green2 = (green2 >> 31) ? 0 : MAX_6BIT;
+ }
+
+ /* output 2 pixels */
+ lcd_write_pixel((red1 << 11) | (green1 << 5) | blue1);
+ lcd_write_pixel((red2 << 11) | (green2 << 5) | blue2);
+ }
+ while (ysrc < row_end);
+
+ src_y++;
+ h--;
+ }
+}
|