summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sparmann <theseven@rockbox.org>2010-11-14 20:39:18 +0000
committerMichael Sparmann <theseven@rockbox.org>2010-11-14 20:39:18 +0000
commit6574040b186c65c7d9539f7b1fd254ddb6ee850c (patch)
tree956e3383f3efa2d3a355f12ef30f075e1c53633b
parentba64cf697edfcfb826d54dd86ab40c13c75e0796 (diff)
downloadrockbox-6574040b186c65c7d9539f7b1fd254ddb6ee850c.tar.gz
rockbox-6574040b186c65c7d9539f7b1fd254ddb6ee850c.zip
iPod Nano 2G LCD sleep: Powering down LDO2 also affects USB, so we can't do that to shut off the LCD. Leave it on for now, and use the lightweight approach for waking up the Leadis LCD.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28601 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/backlight-nano2g.c11
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c1512
2 files changed, 665 insertions, 858 deletions
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/backlight-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/backlight-nano2g.c
index 060dcccae4..3e0e7460c4 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/backlight-nano2g.c
+++ b/firmware/target/arm/s5l8700/ipodnano2g/backlight-nano2g.c
@@ -27,6 +27,7 @@
27#include "pmu-target.h" 27#include "pmu-target.h"
28 28
29#ifdef HAVE_LCD_SLEEP 29#ifdef HAVE_LCD_SLEEP
30bool lcd_active(void);
30void lcd_awake(void); 31void lcd_awake(void);
31void lcd_update(void); 32void lcd_update(void);
32#endif 33#endif
@@ -38,11 +39,13 @@ void _backlight_set_brightness(int brightness)
38 39
39void _backlight_on(void) 40void _backlight_on(void)
40{ 41{
41 if(pmu_read(0x29) == 1) return;
42#ifdef HAVE_LCD_SLEEP 42#ifdef HAVE_LCD_SLEEP
43 lcd_awake(); 43 if (!lcd_active())
44 lcd_update(); 44 {
45 sleep(HZ/10); 45 lcd_awake();
46 lcd_update();
47 sleep(HZ/8);
48 }
46#endif 49#endif
47 pmu_write(0x29, 1); 50 pmu_write(0x29, 1);
48} 51}
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
index 0f7fbd2cc7..eb1fd3e4c0 100644
--- a/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
+++ b/firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c
@@ -1,855 +1,659 @@
1/*************************************************************************** 1/***************************************************************************
2 * __________ __ ___. 2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2009 by Dave Chapman 10 * Copyright (C) 2009 by Dave Chapman
11 * 11 *
12 * This program is free software; you can redistribute it and/or 12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2 14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version. 15 * of the License, or (at your option) any later version.
16 * 16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "config.h" 21#include "config.h"
22 22
23#include "hwcompat.h" 23#include "hwcompat.h"
24#include "kernel.h" 24#include "kernel.h"
25#include "lcd.h" 25#include "lcd.h"
26#include "system.h" 26#include "system.h"
27#include "cpu.h" 27#include "cpu.h"
28#include "pmu-target.h" 28#include "pmu-target.h"
29 29#include "power.h"
30 30
31/* The Nano 2G has two different LCD types. What we call "type 0" 31
32 appears to be similar to the ILI9320 and "type 1" is similar to the 32/* The Nano 2G has two different LCD types. What we call "type 0"
33 LDS176. 33 appears to be similar to the ILI9320 and "type 1" is similar to the
34*/ 34 LDS176.
35 35*/
36/* LCD type 0 register defines */ 36
37 37/* LCD type 0 register defines */
38#define R_ENTRY_MODE 0x03 38
39#define R_DISPLAY_CONTROL_1 0x07 39#define R_ENTRY_MODE 0x03
40#define R_POWER_CONTROL_1 0x10 40#define R_DISPLAY_CONTROL_1 0x07
41#define R_POWER_CONTROL_2 0x12 41#define R_POWER_CONTROL_1 0x10
42#define R_POWER_CONTROL_3 0x13 42#define R_POWER_CONTROL_2 0x12
43#define R_HORIZ_GRAM_ADDR_SET 0x20 43#define R_POWER_CONTROL_3 0x13
44#define R_VERT_GRAM_ADDR_SET 0x21 44#define R_HORIZ_GRAM_ADDR_SET 0x20
45#define R_WRITE_DATA_TO_GRAM 0x22 45#define R_VERT_GRAM_ADDR_SET 0x21
46#define R_HORIZ_ADDR_START_POS 0x50 46#define R_WRITE_DATA_TO_GRAM 0x22
47#define R_HORIZ_ADDR_END_POS 0x51 47#define R_HORIZ_ADDR_START_POS 0x50
48#define R_VERT_ADDR_START_POS 0x52 48#define R_HORIZ_ADDR_END_POS 0x51
49#define R_VERT_ADDR_END_POS 0x53 49#define R_VERT_ADDR_START_POS 0x52
50 50#define R_VERT_ADDR_END_POS 0x53
51 51
52/* LCD type 1 register defines */ 52
53 53/* LCD type 1 register defines */
54#define R_SLEEP_IN 0x10 54
55#define R_DISPLAY_OFF 0x28 55#define R_SLEEP_IN 0x10
56#define R_COLUMN_ADDR_SET 0x2a 56#define R_DISPLAY_OFF 0x28
57#define R_ROW_ADDR_SET 0x2b 57#define R_COLUMN_ADDR_SET 0x2a
58#define R_MEMORY_WRITE 0x2c 58#define R_ROW_ADDR_SET 0x2b
59 59#define R_MEMORY_WRITE 0x2c
60/** globals **/ 60
61 61/** globals **/
62int lcd_type; /* also needed in debug-s5l8700.c */ 62
63static int xoffset; /* needed for flip */ 63int lcd_type; /* also needed in debug-s5l8700.c */
64static bool lcd_ispowered; 64static int xoffset; /* needed for flip */
65 65static bool lcd_ispowered;
66#ifdef HAVE_LCD_SLEEP 66
67 67#ifdef HAVE_LCD_SLEEP
68#define SLEEP 0 68
69#define CMD8 1 69#define SLEEP 0
70#define CMD16 2 70#define CMD8 1
71#define DATA8 3 71#define CMD16 2
72#define DATA16 4 72#define DATA8 3
73 73#define DATA16 4
74unsigned short lcd_init_sequence_0[] = { 74
75 CMD16, 0x00a4, 75unsigned short lcd_init_sequence_0[] = {
76 DATA16, 0x0001, 76 CMD16, 0x00a4,
77 SLEEP, 0x0000, 77 DATA16, 0x0001,
78 CMD16, 0x0001, 78 SLEEP, 0x0000,
79 DATA16, 0x0100, 79 CMD16, 0x0001,
80 CMD16, 0x0002, 80 DATA16, 0x0100,
81 DATA16, 0x0300, 81 CMD16, 0x0002,
82 CMD16, 0x0003, 82 DATA16, 0x0300,
83 DATA16, 0x1230, 83 CMD16, 0x0003,
84 CMD16, 0x0008, 84 DATA16, 0x1230,
85 DATA16, 0x0404, 85 CMD16, 0x0008,
86 CMD16, 0x0008, 86 DATA16, 0x0404,
87 DATA16, 0x0404, 87 CMD16, 0x0008,
88 CMD16, 0x000e, 88 DATA16, 0x0404,
89 DATA16, 0x0010, 89 CMD16, 0x000e,
90 CMD16, 0x0070, 90 DATA16, 0x0010,
91 DATA16, 0x1000, 91 CMD16, 0x0070,
92 CMD16, 0x0071, 92 DATA16, 0x1000,
93 DATA16, 0x0001, 93 CMD16, 0x0071,
94 CMD16, 0x0030, 94 DATA16, 0x0001,
95 DATA16, 0x0002, 95 CMD16, 0x0030,
96 CMD16, 0x0031, 96 DATA16, 0x0002,
97 DATA16, 0x0400, 97 CMD16, 0x0031,
98 CMD16, 0x0032, 98 DATA16, 0x0400,
99 DATA16, 0x0007, 99 CMD16, 0x0032,
100 CMD16, 0x0033, 100 DATA16, 0x0007,
101 DATA16, 0x0500, 101 CMD16, 0x0033,
102 CMD16, 0x0034, 102 DATA16, 0x0500,
103 DATA16, 0x0007, 103 CMD16, 0x0034,
104 CMD16, 0x0035, 104 DATA16, 0x0007,
105 DATA16, 0x0703, 105 CMD16, 0x0035,
106 CMD16, 0x0036, 106 DATA16, 0x0703,
107 DATA16, 0x0507, 107 CMD16, 0x0036,
108 CMD16, 0x0037, 108 DATA16, 0x0507,
109 DATA16, 0x0005, 109 CMD16, 0x0037,
110 CMD16, 0x0038, 110 DATA16, 0x0005,
111 DATA16, 0x0407, 111 CMD16, 0x0038,
112 CMD16, 0x0039, 112 DATA16, 0x0407,
113 DATA16, 0x000e, 113 CMD16, 0x0039,
114 CMD16, 0x0040, 114 DATA16, 0x000e,
115 DATA16, 0x0202, 115 CMD16, 0x0040,
116 CMD16, 0x0041, 116 DATA16, 0x0202,
117 DATA16, 0x0003, 117 CMD16, 0x0041,
118 CMD16, 0x0042, 118 DATA16, 0x0003,
119 DATA16, 0x0000, 119 CMD16, 0x0042,
120 CMD16, 0x0043, 120 DATA16, 0x0000,
121 DATA16, 0x0200, 121 CMD16, 0x0043,
122 CMD16, 0x0044, 122 DATA16, 0x0200,
123 DATA16, 0x0707, 123 CMD16, 0x0044,
124 CMD16, 0x0045, 124 DATA16, 0x0707,
125 DATA16, 0x0407, 125 CMD16, 0x0045,
126 CMD16, 0x0046, 126 DATA16, 0x0407,
127 DATA16, 0x0505, 127 CMD16, 0x0046,
128 CMD16, 0x0047, 128 DATA16, 0x0505,
129 DATA16, 0x0002, 129 CMD16, 0x0047,
130 CMD16, 0x0048, 130 DATA16, 0x0002,
131 DATA16, 0x0004, 131 CMD16, 0x0048,
132 CMD16, 0x0049, 132 DATA16, 0x0004,
133 DATA16, 0x0004, 133 CMD16, 0x0049,
134 CMD16, 0x0060, 134 DATA16, 0x0004,
135 DATA16, 0x0202, 135 CMD16, 0x0060,
136 CMD16, 0x0061, 136 DATA16, 0x0202,
137 DATA16, 0x0003, 137 CMD16, 0x0061,
138 CMD16, 0x0062, 138 DATA16, 0x0003,
139 DATA16, 0x0000, 139 CMD16, 0x0062,
140 CMD16, 0x0063, 140 DATA16, 0x0000,
141 DATA16, 0x0200, 141 CMD16, 0x0063,
142 CMD16, 0x0064, 142 DATA16, 0x0200,
143 DATA16, 0x0707, 143 CMD16, 0x0064,
144 CMD16, 0x0065, 144 DATA16, 0x0707,
145 DATA16, 0x0407, 145 CMD16, 0x0065,
146 CMD16, 0x0066, 146 DATA16, 0x0407,
147 DATA16, 0x0505, 147 CMD16, 0x0066,
148 CMD16, 0x0068, 148 DATA16, 0x0505,
149 DATA16, 0x0004, 149 CMD16, 0x0068,
150 CMD16, 0x0069, 150 DATA16, 0x0004,
151 DATA16, 0x0004, 151 CMD16, 0x0069,
152 CMD16, 0x0007, 152 DATA16, 0x0004,
153 DATA16, 0x0001, 153 CMD16, 0x0007,
154 CMD16, 0x0018, 154 DATA16, 0x0001,
155 DATA16, 0x0001, 155 CMD16, 0x0018,
156 CMD16, 0x0010, 156 DATA16, 0x0001,
157 DATA16, 0x1690, 157 CMD16, 0x0010,
158 CMD16, 0x0011, 158 DATA16, 0x1690,
159 DATA16, 0x0100, 159 CMD16, 0x0011,
160 CMD16, 0x0012, 160 DATA16, 0x0100,
161 DATA16, 0x0117, 161 CMD16, 0x0012,
162 CMD16, 0x0013, 162 DATA16, 0x0117,
163 DATA16, 0x0f80, 163 CMD16, 0x0013,
164 CMD16, 0x0012, 164 DATA16, 0x0f80,
165 DATA16, 0x0137, 165 CMD16, 0x0012,
166 CMD16, 0x0020, 166 DATA16, 0x0137,
167 DATA16, 0x0000, 167 CMD16, 0x0020,
168 CMD16, 0x0021, 168 DATA16, 0x0000,
169 DATA16, 0x0000, 169 CMD16, 0x0021,
170 CMD16, 0x0050, 170 DATA16, 0x0000,
171 DATA16, 0x0000, 171 CMD16, 0x0050,
172 CMD16, 0x0051, 172 DATA16, 0x0000,
173 DATA16, 0x00af, 173 CMD16, 0x0051,
174 CMD16, 0x0052, 174 DATA16, 0x00af,
175 DATA16, 0x0000, 175 CMD16, 0x0052,
176 CMD16, 0x0053, 176 DATA16, 0x0000,
177 DATA16, 0x0083, 177 CMD16, 0x0053,
178 CMD16, 0x0090, 178 DATA16, 0x0083,
179 DATA16, 0x0003, 179 CMD16, 0x0090,
180 CMD16, 0x0091, 180 DATA16, 0x0003,
181 DATA16, 0x0000, 181 CMD16, 0x0091,
182 CMD16, 0x0092, 182 DATA16, 0x0000,
183 DATA16, 0x0101, 183 CMD16, 0x0092,
184 CMD16, 0x0098, 184 DATA16, 0x0101,
185 DATA16, 0x0400, 185 CMD16, 0x0098,
186 CMD16, 0x0099, 186 DATA16, 0x0400,
187 DATA16, 0x1302, 187 CMD16, 0x0099,
188 CMD16, 0x009a, 188 DATA16, 0x1302,
189 DATA16, 0x0202, 189 CMD16, 0x009a,
190 CMD16, 0x009b, 190 DATA16, 0x0202,
191 DATA16, 0x0200, 191 CMD16, 0x009b,
192 SLEEP, 0x0000, 192 DATA16, 0x0200,
193 CMD16, 0x0007, 193 SLEEP, 0x0000,
194 DATA16, 0x0021, 194 CMD16, 0x0007,
195 CMD16, 0x0012, 195 DATA16, 0x0021,
196 DATA16, 0x0137, 196 CMD16, 0x0012,
197 SLEEP, 0x0000, 197 DATA16, 0x0137,
198 CMD16, 0x0007, 198 SLEEP, 0x0000,
199 DATA16, 0x0021, 199 CMD16, 0x0007,
200 CMD16, 0x0012, 200 DATA16, 0x0021,
201 DATA16, 0x1137, 201 CMD16, 0x0012,
202 SLEEP, 0x0000, 202 DATA16, 0x1137,
203 CMD16, 0x0007, 203 SLEEP, 0x0000,
204 DATA16, 0x0233, 204 CMD16, 0x0007,
205}; 205 DATA16, 0x0233,
206 206};
207unsigned short lcd_init_sequence_1[] = { 207
208 CMD8, 0x01, 208unsigned short lcd_init_sequence_1[] = {
209 DATA8, 0x00, 209 CMD8, 0x11,
210 SLEEP, 0, 210 DATA16, 0x00,
211 CMD8, 0xB1, 211 CMD8, 0x29,
212 DATA8, 0x16, 212 DATA16, 0x00,
213 DATA8, 0x03, 213};
214 CMD8, 0xB2, 214
215 DATA8, 0x17, 215
216 DATA8, 0x03, 216
217 CMD8, 0xB4, 217#endif /* HAVE_LCD_SLEEP */
218 DATA8, 0x00, 218
219 CMD8, 0xB6, 219static inline void s5l_lcd_write_cmd_data(int cmd, int data)
220 DATA8, 0x01, 220{
221 CMD8, 0xB7, 221 while (LCD_STATUS & 0x10);
222 DATA8, 0x00, 222 LCD_WCMD = cmd >> 8;
223 DATA8, 0x00, 223 while (LCD_STATUS & 0x10);
224 DATA8, 0x02, 224 LCD_WCMD = cmd & 0xff;
225 DATA8, 0x00, 225
226 DATA8, 0x06, 226 while (LCD_STATUS & 0x10);
227 DATA8, 0x26, 227 LCD_WDATA = data >> 8;
228 DATA8, 0x2D, 228 while (LCD_STATUS & 0x10);
229 DATA8, 0x27, 229 LCD_WDATA = data & 0xff;
230 DATA8, 0x55, 230}
231 DATA8, 0x27, 231
232 CMD8, 0xB8, 232static inline void s5l_lcd_write_cmd(unsigned short cmd)
233 DATA8, 0x10, 233{
234 CMD8, 0xB9, 234 while (LCD_STATUS & 0x10);
235 DATA8, 0x52, 235 LCD_WCMD = cmd;
236 DATA8, 0x12, 236}
237 DATA8, 0x03, 237
238 CMD8, 0xC0, 238static inline void s5l_lcd_write_wcmd(unsigned short cmd)
239 DATA8, 0x0A, 239{
240 DATA8, 0x10, 240 while (LCD_STATUS & 0x10);
241 DATA8, 0x10, 241 LCD_WCMD = cmd >> 8;
242 CMD8, 0xC2, 242 while (LCD_STATUS & 0x10);
243 DATA8, 0x14, 243 LCD_WCMD = cmd & 0xff;
244 DATA8, 0x23, 244}
245 CMD8, 0xC3, 245
246 DATA8, 0x12, 246static inline void s5l_lcd_write_data(unsigned short data)
247 DATA8, 0x23, 247{
248 CMD8, 0xC6, 248 while (LCD_STATUS & 0x10);
249 DATA8, 0x48, 249 LCD_WDATA = data & 0xff;
250 CMD8, 0xE0, 250}
251 DATA8, 0x20, 251
252 DATA8, 0x71, 252static inline void s5l_lcd_write_wdata(unsigned short data)
253 DATA8, 0x17, 253{
254 DATA8, 0x09, 254 while (LCD_STATUS & 0x10);
255 DATA8, 0x70, 255 LCD_WDATA = data >> 8;
256 DATA8, 0x0C, 256 while (LCD_STATUS & 0x10);
257 DATA8, 0x13, 257 LCD_WDATA = data & 0xff;
258 DATA8, 0x25, 258}
259 CMD8, 0xE1, 259
260 DATA8, 0x37, 260/*** hardware configuration ***/
261 DATA8, 0x00, 261
262 DATA8, 0x63, 262int lcd_default_contrast(void)
263 DATA8, 0x11, 263{
264 DATA8, 0xD9, 264 return 0x1f;
265 DATA8, 0x00, 265}
266 DATA8, 0x12, 266
267 DATA8, 0x01, 267void lcd_set_contrast(int val)
268 CMD8, 0xE2, 268{
269 DATA8, 0x42, 269 (void)val;
270 DATA8, 0x42, 270}
271 DATA8, 0x60, 271
272 DATA8, 0x08, 272void lcd_set_invert_display(bool yesno)
273 DATA8, 0xB4, 273{
274 DATA8, 0x07, 274 (void)yesno;
275 DATA8, 0x0E, 275}
276 DATA8, 0x90, 276
277 CMD8, 0xE3, 277/* turn the display upside down (call lcd_update() afterwards) */
278 DATA8, 0x47, 278void lcd_set_flip(bool yesno)
279 DATA8, 0x60, 279{
280 DATA8, 0x66, 280 /* TODO: flip mode isn't working. The commands in the else part of
281 DATA8, 0x09, 281 this function are how the original firmware inits the LCD */
282 DATA8, 0x6A, 282
283 DATA8, 0x02, 283 if (yesno)
284 DATA8, 0x0E, 284 {
285 DATA8, 0x09, 285 xoffset = 132 - LCD_WIDTH; /* 132 colums minus the 128 we have */
286 CMD8, 0xE4, 286 }
287 DATA8, 0x11, 287 else
288 DATA8, 0x40, 288 {
289 DATA8, 0x03, 289 xoffset = 0;
290 DATA8, 0x0A, 290 }
291 DATA8, 0xC1, 291}
292 DATA8, 0x0D, 292
293 DATA8, 0x17, 293bool lcd_active(void)
294 DATA8, 0x30, 294{
295 CMD8, 0xE5, 295 return lcd_ispowered;
296 DATA8, 0x00, 296}
297 DATA8, 0x30, 297
298 DATA8, 0x77, 298#ifdef HAVE_LCD_SLEEP
299 DATA8, 0x1C, 299
300 DATA8, 0xFB, 300void lcd_wakeup(void)
301 DATA8, 0x00, 301{
302 DATA8, 0x13, 302 unsigned short *lcd_init_sequence;
303 DATA8, 0x07, 303 unsigned int lcd_init_sequence_length;
304 CMD8, 0xE6, 304
305 DATA8, 0x01, 305 PWRCONEXT &= ~0x80;
306 CMD8, 0x35, 306 PCON13 &= ~0xf; /* Set pin 0 to input */
307 DATA8, 0x00, 307 PCON14 &= ~0xf0; /* Set pin 1 to input */
308 CMD8, 0x36, 308
309 DATA8, 0x00, 309 pmu_write(0x2b, 1);
310 CMD8, 0xF2, 310
311 DATA8, 0x40, 311 if (lcd_type == 0)
312 CMD8, 0xF3, 312 {
313 DATA8, 0x50, 313 /* reset the lcd chip */
314 CMD8, 0xFB, 314
315 DATA8, 0x01, 315 LCD_RST_TIME = 0x7FFF;
316 CMD8, 0x11, 316 LCD_DRV_RST = 0;
317 DATA8, 0x00, 317 sleep(0);
318 SLEEP, 0, 318 LCD_DRV_RST = 1;
319 CMD8, 0x3A, 319 sleep(HZ / 100);
320 DATA8, 0x65, 320
321 CMD8, 0x29, 321 lcd_init_sequence = lcd_init_sequence_0;
322 DATA8, 0x00, 322 lcd_init_sequence_length = (sizeof(lcd_init_sequence_0) - 1)/sizeof(unsigned short);
323}; 323 }
324 324 else
325unsigned short lcd_init_sequence_2[] = { 325 {
326 CMD8, 0x01, 326 lcd_init_sequence = lcd_init_sequence_1;
327 SLEEP, 0, 327 lcd_init_sequence_length = (sizeof(lcd_init_sequence_1) - 1)/sizeof(unsigned short);
328 CMD8, 0x11, 328 }
329 SLEEP, 0, 329
330 CMD8, 0x3a, 330 for(unsigned int i=0;i<lcd_init_sequence_length;i+=2)
331 DATA8, 0x65, 331 {
332 CMD8, 0xab, 332 switch(lcd_init_sequence[i])
333 CMD8, 0x35, 333 {
334 DATA8, 0x00, 334 case CMD8:
335 CMD8, 0xf2, 335 s5l_lcd_write_cmd(lcd_init_sequence[i+1]);
336 DATA8, 0x01, 336 break;
337 CMD8, 0xe0, 337 case DATA8:
338 DATA8, 0x71, 338 s5l_lcd_write_data(lcd_init_sequence[i+1]);
339 DATA8, 0x76, 339 break;
340 DATA8, 0x25, 340 case CMD16:
341 DATA8, 0x01, 341 s5l_lcd_write_wcmd(lcd_init_sequence[i+1]);
342 DATA8, 0xa5, 342 break;
343 DATA8, 0x09, 343 case DATA16:
344 DATA8, 0x15, 344 s5l_lcd_write_wdata(lcd_init_sequence[i+1]);
345 DATA8, 0x11, 345 break;
346 CMD8, 0xe1, 346 case SLEEP:
347 DATA8, 0x40, 347 sleep(lcd_init_sequence[i+1]);
348 DATA8, 0x21, 348 break;
349 DATA8, 0x64, 349 default:
350 DATA8, 0x13, 350 break;
351 DATA8, 0xf3, 351 }
352 DATA8, 0x0b, 352 }
353 DATA8, 0x00, 353 lcd_ispowered = true;
354 DATA8, 0x00,
355 CMD8, 0xe2,
356 DATA8, 0x71,
357 DATA8, 0x65,
358 DATA8, 0x24,
359 DATA8, 0x08,
360 DATA8, 0x97,
361 DATA8, 0x01,
362 DATA8, 0x15,
363 DATA8, 0x11,
364 CMD8, 0xe3,
365 DATA8, 0x51,
366 DATA8, 0x01,
367 DATA8, 0x62,
368 DATA8, 0x13,
369 DATA8, 0xf3,
370 DATA8, 0x0b,
371 DATA8, 0x00,
372 DATA8, 0x00,
373 CMD8, 0xe4,
374 DATA8, 0x71,
375 DATA8, 0x57,
376 DATA8, 0x31,
377 DATA8, 0x01,
378 DATA8, 0x82,
379 DATA8, 0x04,
380 DATA8, 0x1f,
381 DATA8, 0x11,
382 CMD8, 0xe5,
383 DATA8, 0x64,
384 DATA8, 0x41,
385 DATA8, 0x64,
386 DATA8, 0x19,
387 DATA8, 0xb3,
388 DATA8, 0x09,
389 DATA8, 0x00,
390 DATA8, 0x00,
391 CMD8, 0x29,
392};
393
394#endif /* HAVE_LCD_SLEEP */
395
396static inline void s5l_lcd_write_cmd_data(int cmd, int data)
397{
398 while (LCD_STATUS & 0x10);
399 LCD_WCMD = cmd >> 8;
400 while (LCD_STATUS & 0x10);
401 LCD_WCMD = cmd & 0xff;
402
403 while (LCD_STATUS & 0x10);
404 LCD_WDATA = data >> 8;
405 while (LCD_STATUS & 0x10);
406 LCD_WDATA = data & 0xff;
407}
408
409static inline void s5l_lcd_write_cmd(unsigned short cmd)
410{
411 while (LCD_STATUS & 0x10);
412 LCD_WCMD = cmd;
413}
414
415static inline void s5l_lcd_write_wcmd(unsigned short cmd)
416{
417 while (LCD_STATUS & 0x10);
418 LCD_WCMD = cmd >> 8;
419 while (LCD_STATUS & 0x10);
420 LCD_WCMD = cmd & 0xff;
421}
422
423static inline void s5l_lcd_write_data(unsigned short data)
424{
425 while (LCD_STATUS & 0x10);
426 LCD_WDATA = data & 0xff;
427}
428
429static inline void s5l_lcd_write_wdata(unsigned short data)
430{
431 while (LCD_STATUS & 0x10);
432 LCD_WDATA = data >> 8;
433 while (LCD_STATUS & 0x10);
434 LCD_WDATA = data & 0xff;
435}
436
437/*** hardware configuration ***/
438
439int lcd_default_contrast(void)
440{
441 return 0x1f;
442}
443
444void lcd_set_contrast(int val)
445{
446 (void)val;
447}
448
449void lcd_set_invert_display(bool yesno)
450{
451 (void)yesno;
452}
453
454/* turn the display upside down (call lcd_update() afterwards) */
455void lcd_set_flip(bool yesno)
456{
457 /* TODO: flip mode isn't working. The commands in the else part of
458 this function are how the original firmware inits the LCD */
459
460 if (yesno)
461 {
462 xoffset = 132 - LCD_WIDTH; /* 132 colums minus the 128 we have */
463 }
464 else
465 {
466 xoffset = 0;
467 }
468}
469
470bool lcd_active(void)
471{
472 return lcd_ispowered;
473}
474
475#ifdef HAVE_LCD_SLEEP
476
477void lcd_wakeup(void)
478{
479 unsigned short *lcd_init_sequence;
480 unsigned int lcd_init_sequence_length;
481 int type = lcd_type;
482
483 pmu_ldo_set_voltage(2, 17);
484 PWRCONEXT &= ~0x80;
485 PCON2 = 0x33333333;
486 PCON3 = 0x11113333;
487 PCON4 = 0x33333333;
488 PCON13 &= ~0xf; /* Set pin 0 to input */
489 PCON14 &= ~0xf0; /* Set pin 1 to input */
490
491 if((((PDAT13 & 1) == 1) && ((PDAT14 & 2) == 2))||
492 (((PDAT13 & 1) == 0) && ((PDAT14 & 2) == 0)))
493 {
494 type = 2; /* there is a third lcd type which behaves like type 7 (LDS176) but needs to be initialized differently */
495 }
496
497 if(type == 0)
498 {
499 lcd_init_sequence = lcd_init_sequence_0;
500 lcd_init_sequence_length = (sizeof(lcd_init_sequence_0) - 1)/sizeof(unsigned short);
501 }
502 else if(type == 1)
503 {
504 lcd_init_sequence = lcd_init_sequence_1;
505 lcd_init_sequence_length = (sizeof(lcd_init_sequence_1) - 1)/sizeof(unsigned short);
506 }
507 else
508 {
509 lcd_init_sequence = lcd_init_sequence_2;
510 lcd_init_sequence_length = (sizeof(lcd_init_sequence_2) - 1)/sizeof(unsigned short);
511 }
512
513 /* reset the lcd chip */
514
515 LCD_RST_TIME = 0x7FFF;
516 LCD_DRV_RST = 0;
517 sleep(0);
518 LCD_DRV_RST = 1;
519 sleep(HZ / 100);
520
521 for(unsigned int i=0;i<lcd_init_sequence_length;i+=2)
522 {
523 switch(lcd_init_sequence[i])
524 {
525 case CMD8:
526 s5l_lcd_write_cmd(lcd_init_sequence[i+1]);
527 break;
528 case DATA8:
529 s5l_lcd_write_data(lcd_init_sequence[i+1]);
530 break;
531 case CMD16:
532 s5l_lcd_write_wcmd(lcd_init_sequence[i+1]);
533 break;
534 case DATA16:
535 s5l_lcd_write_wdata(lcd_init_sequence[i+1]);
536 break;
537 case SLEEP:
538 sleep(lcd_init_sequence[i+1]);
539 break;
540 default:
541 break;
542 }
543 }
544 lcd_ispowered = true;
545 send_event(LCD_EVENT_ACTIVATION, NULL); 354 send_event(LCD_EVENT_ACTIVATION, NULL);
546} 355}
547 356
548void lcd_awake(void) 357void lcd_awake(void)
549{ 358{
550 if(!lcd_active()) lcd_wakeup(); 359 if(!lcd_active()) lcd_wakeup();
551} 360}
552#endif 361#endif
553 362
554void lcd_shutdown(void) 363void lcd_shutdown(void)
555{ 364{
556 pmu_write(0x2b, 0); /* Kill the backlight, instantly. */ 365 pmu_write(0x2b, 0); /* Kill the backlight, instantly. */
557 pmu_write(0x29, 0); 366 pmu_write(0x29, 0);
558 367
559 if (lcd_type == 0) 368 if (lcd_type == 0)
560 { 369 {
561 s5l_lcd_write_cmd_data(R_DISPLAY_CONTROL_1, 0x232); 370 s5l_lcd_write_cmd_data(R_DISPLAY_CONTROL_1, 0x232);
562 s5l_lcd_write_cmd_data(R_POWER_CONTROL_3, 0x1137); 371 s5l_lcd_write_cmd_data(R_POWER_CONTROL_3, 0x1137);
563 s5l_lcd_write_cmd_data(R_DISPLAY_CONTROL_1, 0x201); 372 s5l_lcd_write_cmd_data(R_DISPLAY_CONTROL_1, 0x201);
564 s5l_lcd_write_cmd_data(R_POWER_CONTROL_3, 0x137); 373 s5l_lcd_write_cmd_data(R_POWER_CONTROL_3, 0x137);
565 s5l_lcd_write_cmd_data(R_DISPLAY_CONTROL_1, 0x200); 374 s5l_lcd_write_cmd_data(R_DISPLAY_CONTROL_1, 0x200);
566 s5l_lcd_write_cmd_data(R_POWER_CONTROL_1, 0x680); 375 s5l_lcd_write_cmd_data(R_POWER_CONTROL_1, 0x680);
567 s5l_lcd_write_cmd_data(R_POWER_CONTROL_2, 0x160); 376 s5l_lcd_write_cmd_data(R_POWER_CONTROL_2, 0x160);
568 s5l_lcd_write_cmd_data(R_POWER_CONTROL_3, 0x127); 377 s5l_lcd_write_cmd_data(R_POWER_CONTROL_3, 0x127);
569 s5l_lcd_write_cmd_data(R_POWER_CONTROL_1, 0x600); 378 s5l_lcd_write_cmd_data(R_POWER_CONTROL_1, 0x600);
570 } 379 }
571 else 380 else
572 { 381 {
573 s5l_lcd_write_cmd(R_DISPLAY_OFF); 382 s5l_lcd_write_cmd(R_DISPLAY_OFF);
574 s5l_lcd_write_wdata(0); 383 s5l_lcd_write_wdata(0);
575 s5l_lcd_write_wdata(0); 384 s5l_lcd_write_wdata(0);
576 s5l_lcd_write_cmd(R_SLEEP_IN); 385 s5l_lcd_write_cmd(R_SLEEP_IN);
577 s5l_lcd_write_wdata(0); 386 s5l_lcd_write_wdata(0);
578 s5l_lcd_write_wdata(0); 387 s5l_lcd_write_wdata(0);
579 } 388 }
580 389
581 PCON2 = 0; 390 PWRCONEXT |= 0x80;
582 PCON3 = 0; 391
583 PCON4 = 0; 392 lcd_ispowered = false;
584 PWRCONEXT |= 0x80; 393}
585 sleep(HZ / 20); 394
586 pmu_ldo_set_voltage(2, 1); 395void lcd_sleep(void)
587 396{
588 lcd_ispowered = false; 397 lcd_shutdown();
589} 398}
590 399
591void lcd_sleep(void) 400/* LCD init */
592{ 401void lcd_init_device(void)
593 lcd_shutdown(); 402{
594} 403 /* Detect lcd type */
595 404
596/* LCD init */ 405 PCON13 &= ~0xf; /* Set pin 0 to input */
597void lcd_init_device(void) 406 PCON14 &= ~0xf0; /* Set pin 1 to input */
598{ 407
599 /* Detect lcd type */ 408 if (((PDAT13 & 1) == 0) && ((PDAT14 & 2) == 2))
600 409 lcd_type = 0; /* Similar to ILI9320 - aka "type 2" */
601 PCON13 &= ~0xf; /* Set pin 0 to input */ 410 else
602 PCON14 &= ~0xf0; /* Set pin 1 to input */ 411 lcd_type = 1; /* Similar to LDS176 - aka "type 7" */
603 412
604 if (((PDAT13 & 1) == 0) && ((PDAT14 & 2) == 2)) 413 lcd_ispowered = true;
605 lcd_type = 0; /* Similar to ILI9320 - aka "type 2" */ 414}
606 else 415
607 lcd_type = 1; /* Similar to LDS176 - aka "type 7" */ 416/*** Update functions ***/
608 417
609 lcd_ispowered = true; 418static inline void lcd_write_pixel(fb_data pixel)
610} 419{
611 420 while (LCD_STATUS & 0x10);
612/*** Update functions ***/ 421 LCD_WDATA = (pixel & 0xff00) >> 8;
613 422 while (LCD_STATUS & 0x10);
614static inline void lcd_write_pixel(fb_data pixel) 423 LCD_WDATA = pixel & 0xff;
615{ 424}
616 while (LCD_STATUS & 0x10); 425
617 LCD_WDATA = (pixel & 0xff00) >> 8; 426/* Update the display.
618 while (LCD_STATUS & 0x10); 427 This must be called after all other LCD functions that change the display. */
619 LCD_WDATA = pixel & 0xff; 428void lcd_update(void) ICODE_ATTR;
620} 429void lcd_update(void)
621 430{
622/* Update the display. 431 int x,y;
623 This must be called after all other LCD functions that change the display. */ 432 fb_data* p = &lcd_framebuffer[0][0];
624void lcd_update(void) ICODE_ATTR; 433
625void lcd_update(void) 434 if (lcd_type==0) {
626{ 435 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, 0);
627 int x,y; 436 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, LCD_WIDTH-1);
628 fb_data* p = &lcd_framebuffer[0][0]; 437 s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, 0);
629 438 s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, LCD_HEIGHT-1);
630 if (lcd_type==0) { 439
631 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, 0); 440 s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, 0);
632 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, LCD_WIDTH-1); 441 s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, 0);
633 s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, 0); 442
634 s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, LCD_HEIGHT-1); 443 s5l_lcd_write_cmd(0);
635 444 s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM);
636 s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, 0); 445 } else {
637 s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, 0); 446 s5l_lcd_write_cmd(R_COLUMN_ADDR_SET);
638 447 s5l_lcd_write_wdata(0); /* Start column */
639 s5l_lcd_write_cmd(0); 448 s5l_lcd_write_wdata(LCD_WIDTH-1); /* End column */
640 s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); 449
641 } else { 450 s5l_lcd_write_cmd(R_ROW_ADDR_SET);
642 s5l_lcd_write_cmd(R_COLUMN_ADDR_SET); 451 s5l_lcd_write_wdata(0); /* Start row */
643 s5l_lcd_write_wdata(0); /* Start column */ 452 s5l_lcd_write_wdata(LCD_HEIGHT-1); /* End row */
644 s5l_lcd_write_wdata(LCD_WIDTH-1); /* End column */ 453
645 454 s5l_lcd_write_cmd(R_MEMORY_WRITE);
646 s5l_lcd_write_cmd(R_ROW_ADDR_SET); 455 }
647 s5l_lcd_write_wdata(0); /* Start row */ 456
648 s5l_lcd_write_wdata(LCD_HEIGHT-1); /* End row */ 457
649 458 /* Copy display bitmap to hardware */
650 s5l_lcd_write_cmd(R_MEMORY_WRITE); 459 for (y = 0; y < LCD_HEIGHT; y++) {
651 } 460 for (x = 0; x < LCD_WIDTH; x++) {
652 461 lcd_write_pixel(*(p++));
653 462 }
654 /* Copy display bitmap to hardware */ 463 }
655 for (y = 0; y < LCD_HEIGHT; y++) { 464}
656 for (x = 0; x < LCD_WIDTH; x++) { 465
657 lcd_write_pixel(*(p++)); 466/* Update a fraction of the display. */
658 } 467void lcd_update_rect(int, int, int, int) ICODE_ATTR;
659 } 468void lcd_update_rect(int x, int y, int width, int height)
660} 469{
661 470 int xx,yy;
662/* Update a fraction of the display. */ 471 int y0, x0, y1, x1;
663void lcd_update_rect(int, int, int, int) ICODE_ATTR; 472 fb_data* p;
664void lcd_update_rect(int x, int y, int width, int height) 473
665{ 474 x0 = x; /* start horiz */
666 int xx,yy; 475 y0 = y; /* start vert */
667 int y0, x0, y1, x1; 476 x1 = (x + width) - 1; /* max horiz */
668 fb_data* p; 477 y1 = (y + height) - 1; /* max vert */
669 478
670 x0 = x; /* start horiz */ 479 if (lcd_type==0) {
671 y0 = y; /* start vert */ 480 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0);
672 x1 = (x + width) - 1; /* max horiz */ 481 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1);
673 y1 = (y + height) - 1; /* max vert */ 482 s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0);
674 483 s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1);
675 if (lcd_type==0) { 484
676 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0); 485 s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, (x1 << 8) | x0);
677 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1); 486 s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, (y1 << 8) | y0);
678 s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0); 487
679 s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1); 488 s5l_lcd_write_cmd(0);
680 489 s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM);
681 s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, (x1 << 8) | x0); 490 } else {
682 s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, (y1 << 8) | y0); 491 s5l_lcd_write_cmd(R_COLUMN_ADDR_SET);
683 492 s5l_lcd_write_wdata(x0); /* Start column */
684 s5l_lcd_write_cmd(0); 493 s5l_lcd_write_wdata(x1); /* End column */
685 s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); 494
686 } else { 495 s5l_lcd_write_cmd(R_ROW_ADDR_SET);
687 s5l_lcd_write_cmd(R_COLUMN_ADDR_SET); 496 s5l_lcd_write_wdata(y0); /* Start row */
688 s5l_lcd_write_wdata(x0); /* Start column */ 497 s5l_lcd_write_wdata(y1); /* End row */
689 s5l_lcd_write_wdata(x1); /* End column */ 498
690 499 s5l_lcd_write_cmd(R_MEMORY_WRITE);
691 s5l_lcd_write_cmd(R_ROW_ADDR_SET); 500 }
692 s5l_lcd_write_wdata(y0); /* Start row */ 501
693 s5l_lcd_write_wdata(y1); /* End row */ 502
694 503 /* Copy display bitmap to hardware */
695 s5l_lcd_write_cmd(R_MEMORY_WRITE); 504 p = &lcd_framebuffer[y0][x0];
696 } 505 yy = height;
697 506 for (yy = y0; yy <= y1; yy++) {
698 507 for (xx = x0; xx <= x1; xx++) {
699 /* Copy display bitmap to hardware */ 508 lcd_write_pixel(*(p++));
700 p = &lcd_framebuffer[y0][x0]; 509 }
701 yy = height; 510 p += LCD_WIDTH - width;
702 for (yy = y0; yy <= y1; yy++) { 511 }
703 for (xx = x0; xx <= x1; xx++) { 512}
704 lcd_write_pixel(*(p++)); 513
705 } 514/*** update functions ***/
706 p += LCD_WIDTH - width; 515
707 } 516#define CSUB_X 2
708} 517#define CSUB_Y 2
709 518
710/*** update functions ***/ 519/* YUV- > RGB565 conversion
711 520 * |R| |1.000000 -0.000001 1.402000| |Y'|
712#define CSUB_X 2 521 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
713#define CSUB_Y 2 522 * |B| |1.000000 1.772000 0.000000| |Pr|
714 523 * Scaled, normalized, rounded and tweaked to yield RGB 565:
715/* YUV- > RGB565 conversion 524 * |R| |74 0 101| |Y' - 16| >> 9
716 * |R| |1.000000 -0.000001 1.402000| |Y'| 525 * |G| = |74 -24 -51| |Cb - 128| >> 8
717 * |G| = |1.000000 -0.334136 -0.714136| |Pb| 526 * |B| |74 128 0| |Cr - 128| >> 9
718 * |B| |1.000000 1.772000 0.000000| |Pr| 527*/
719 * Scaled, normalized, rounded and tweaked to yield RGB 565: 528
720 * |R| |74 0 101| |Y' - 16| >> 9 529#define RGBYFAC 74 /* 1.0 */
721 * |G| = |74 -24 -51| |Cb - 128| >> 8 530#define RVFAC 101 /* 1.402 */
722 * |B| |74 128 0| |Cr - 128| >> 9 531#define GVFAC (-51) /* -0.714136 */
723*/ 532#define GUFAC (-24) /* -0.334136 */
724 533#define BUFAC 128 /* 1.772 */
725#define RGBYFAC 74 /* 1.0 */ 534
726#define RVFAC 101 /* 1.402 */ 535/* ROUNDOFFS contain constant for correct round-offs as well as
727#define GVFAC (-51) /* -0.714136 */ 536 constant parts of the conversion matrix (e.g. (Y'-16)*RGBYFAC
728#define GUFAC (-24) /* -0.334136 */ 537 -> constant part = -16*RGBYFAC). Through extraction of these
729#define BUFAC 128 /* 1.772 */ 538 constant parts we save at leat 4 substractions in the conversion
730 539 loop */
731/* ROUNDOFFS contain constant for correct round-offs as well as 540#define ROUNDOFFSR (256 - 16*RGBYFAC - 128*RVFAC)
732 constant parts of the conversion matrix (e.g. (Y'-16)*RGBYFAC 541#define ROUNDOFFSG (128 - 16*RGBYFAC - 128*GVFAC - 128*GUFAC)
733 -> constant part = -16*RGBYFAC). Through extraction of these 542#define ROUNDOFFSB (256 - 16*RGBYFAC - 128*BUFAC)
734 constant parts we save at leat 4 substractions in the conversion 543
735 loop */ 544#define MAX_5BIT 0x1f
736#define ROUNDOFFSR (256 - 16*RGBYFAC - 128*RVFAC) 545#define MAX_6BIT 0x3f
737#define ROUNDOFFSG (128 - 16*RGBYFAC - 128*GVFAC - 128*GUFAC) 546
738#define ROUNDOFFSB (256 - 16*RGBYFAC - 128*BUFAC) 547/* Performance function to blit a YUV bitmap directly to the LCD */
739 548void lcd_blit_yuv(unsigned char * const src[3],
740#define MAX_5BIT 0x1f 549 int src_x, int src_y, int stride,
741#define MAX_6BIT 0x3f 550 int x, int y, int width, int height)
742 551{
743/* Performance function to blit a YUV bitmap directly to the LCD */ 552 int h;
744void lcd_blit_yuv(unsigned char * const src[3], 553 int y0, x0, y1, x1;
745 int src_x, int src_y, int stride, 554
746 int x, int y, int width, int height) 555 width = (width + 1) & ~1;
747{ 556
748 int h; 557 x0 = x; /* start horiz */
749 int y0, x0, y1, x1; 558 y0 = y; /* start vert */
750 559 x1 = (x + width) - 1; /* max horiz */
751 width = (width + 1) & ~1; 560 y1 = (y + height) - 1; /* max vert */
752 561
753 x0 = x; /* start horiz */ 562 if (lcd_type==0) {
754 y0 = y; /* start vert */ 563 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0);
755 x1 = (x + width) - 1; /* max horiz */ 564 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1);
756 y1 = (y + height) - 1; /* max vert */ 565 s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0);
757 566 s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1);
758 if (lcd_type==0) { 567
759 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0); 568 s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, (x1 << 8) | x0);
760 s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1); 569 s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, (y1 << 8) | y0);
761 s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0); 570
762 s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1); 571 s5l_lcd_write_cmd(0);
763 572 s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM);
764 s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, (x1 << 8) | x0); 573 } else {
765 s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, (y1 << 8) | y0); 574 s5l_lcd_write_cmd(R_COLUMN_ADDR_SET);
766 575 s5l_lcd_write_wdata(x0); /* Start column */
767 s5l_lcd_write_cmd(0); 576 s5l_lcd_write_wdata(x1); /* End column */
768 s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); 577
769 } else { 578 s5l_lcd_write_cmd(R_ROW_ADDR_SET);
770 s5l_lcd_write_cmd(R_COLUMN_ADDR_SET); 579 s5l_lcd_write_wdata(y0); /* Start row */
771 s5l_lcd_write_wdata(x0); /* Start column */ 580 s5l_lcd_write_wdata(y1); /* End row */
772 s5l_lcd_write_wdata(x1); /* End column */ 581
773 582 s5l_lcd_write_cmd(R_MEMORY_WRITE);
774 s5l_lcd_write_cmd(R_ROW_ADDR_SET); 583 }
775 s5l_lcd_write_wdata(y0); /* Start row */ 584
776 s5l_lcd_write_wdata(y1); /* End row */ 585 const int stride_div_csub_x = stride/CSUB_X;
777 586
778 s5l_lcd_write_cmd(R_MEMORY_WRITE); 587 h = height;
779 } 588 while (h > 0) {
780 589 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
781 const int stride_div_csub_x = stride/CSUB_X; 590 const unsigned char *ysrc = src[0] + stride * src_y + src_x;
782 591
783 h = height; 592 const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) +
784 while (h > 0) { 593 (src_x/CSUB_X);
785 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ 594
786 const unsigned char *ysrc = src[0] + stride * src_y + src_x; 595 const unsigned char *usrc = src[1] + uvoffset;
787 596 const unsigned char *vsrc = src[2] + uvoffset;
788 const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) + 597 const unsigned char *row_end = ysrc + width;
789 (src_x/CSUB_X); 598
790 599 int yp, up, vp;
791 const unsigned char *usrc = src[1] + uvoffset; 600 int red1, green1, blue1;
792 const unsigned char *vsrc = src[2] + uvoffset; 601 int red2, green2, blue2;
793 const unsigned char *row_end = ysrc + width; 602
794 603 int rc, gc, bc;
795 int yp, up, vp; 604
796 int red1, green1, blue1; 605 do
797 int red2, green2, blue2; 606 {
798 607 up = *usrc++;
799 int rc, gc, bc; 608 vp = *vsrc++;
800 609 rc = RVFAC * vp + ROUNDOFFSR;
801 do 610 gc = GVFAC * vp + GUFAC * up + ROUNDOFFSG;
802 { 611 bc = BUFAC * up + ROUNDOFFSB;
803 up = *usrc++; 612
804 vp = *vsrc++; 613 /* Pixel 1 -> RGB565 */
805 rc = RVFAC * vp + ROUNDOFFSR; 614 yp = *ysrc++ * RGBYFAC;
806 gc = GVFAC * vp + GUFAC * up + ROUNDOFFSG; 615 red1 = (yp + rc) >> 9;
807 bc = BUFAC * up + ROUNDOFFSB; 616 green1 = (yp + gc) >> 8;
808 617 blue1 = (yp + bc) >> 9;
809 /* Pixel 1 -> RGB565 */ 618
810 yp = *ysrc++ * RGBYFAC; 619 /* Pixel 2 -> RGB565 */
811 red1 = (yp + rc) >> 9; 620 yp = *ysrc++ * RGBYFAC;
812 green1 = (yp + gc) >> 8; 621 red2 = (yp + rc) >> 9;
813 blue1 = (yp + bc) >> 9; 622 green2 = (yp + gc) >> 8;
814 623 blue2 = (yp + bc) >> 9;
815 /* Pixel 2 -> RGB565 */ 624
816 yp = *ysrc++ * RGBYFAC; 625 /* Since out of bounds errors are relatively rare, we check two
817 red2 = (yp + rc) >> 9; 626 pixels at once to see if any components are out of bounds, and
818 green2 = (yp + gc) >> 8; 627 then fix whichever is broken. This works due to high values and
819 blue2 = (yp + bc) >> 9; 628 negative values both being !=0 when bitmasking them.
820 629 We first check for red and blue components (5bit range). */
821 /* Since out of bounds errors are relatively rare, we check two 630 if ((red1 | blue1 | red2 | blue2) & ~MAX_5BIT)
822 pixels at once to see if any components are out of bounds, and 631 {
823 then fix whichever is broken. This works due to high values and 632 if (red1 & ~MAX_5BIT)
824 negative values both being !=0 when bitmasking them. 633 red1 = (red1 >> 31) ? 0 : MAX_5BIT;
825 We first check for red and blue components (5bit range). */ 634 if (blue1 & ~MAX_5BIT)
826 if ((red1 | blue1 | red2 | blue2) & ~MAX_5BIT) 635 blue1 = (blue1 >> 31) ? 0 : MAX_5BIT;
827 { 636 if (red2 & ~MAX_5BIT)
828 if (red1 & ~MAX_5BIT) 637 red2 = (red2 >> 31) ? 0 : MAX_5BIT;
829 red1 = (red1 >> 31) ? 0 : MAX_5BIT; 638 if (blue2 & ~MAX_5BIT)
830 if (blue1 & ~MAX_5BIT) 639 blue2 = (blue2 >> 31) ? 0 : MAX_5BIT;
831 blue1 = (blue1 >> 31) ? 0 : MAX_5BIT; 640 }
832 if (red2 & ~MAX_5BIT) 641 /* We second check for green component (6bit range) */
833 red2 = (red2 >> 31) ? 0 : MAX_5BIT; 642 if ((green1 | green2) & ~MAX_6BIT)
834 if (blue2 & ~MAX_5BIT) 643 {
835 blue2 = (blue2 >> 31) ? 0 : MAX_5BIT; 644 if (green1 & ~MAX_6BIT)
836 } 645 green1 = (green1 >> 31) ? 0 : MAX_6BIT;
837 /* We second check for green component (6bit range) */ 646 if (green2 & ~MAX_6BIT)
838 if ((green1 | green2) & ~MAX_6BIT) 647 green2 = (green2 >> 31) ? 0 : MAX_6BIT;
839 { 648 }
840 if (green1 & ~MAX_6BIT) 649
841 green1 = (green1 >> 31) ? 0 : MAX_6BIT; 650 /* output 2 pixels */
842 if (green2 & ~MAX_6BIT) 651 lcd_write_pixel((red1 << 11) | (green1 << 5) | blue1);
843 green2 = (green2 >> 31) ? 0 : MAX_6BIT; 652 lcd_write_pixel((red2 << 11) | (green2 << 5) | blue2);
844 } 653 }
845 654 while (ysrc < row_end);
846 /* output 2 pixels */ 655
847 lcd_write_pixel((red1 << 11) | (green1 << 5) | blue1); 656 src_y++;
848 lcd_write_pixel((red2 << 11) | (green2 << 5) | blue2); 657 h--;
849 } 658 }
850 while (ysrc < row_end); 659}
851
852 src_y++;
853 h--;
854 }
855}