From cdbaa09fb73ce9ff04876c5f8464fc5f692b9e3f Mon Sep 17 00:00:00 2001 From: Michael Sparmann Date: Sun, 14 Nov 2010 15:46:17 +0000 Subject: iPod Nano 2G LCD sleep: Send LCD_EVENT_ACTIVATION event git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28593 a1c6a512-1295-4272-9138-f99709370657 --- .../target/arm/s5l8700/ipodnano2g/lcd-nano2g.c | 1693 ++++++++++---------- 1 file 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> 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--; + } +} -- cgit v1.2.3