diff options
author | Michael Sparmann <theseven@rockbox.org> | 2010-11-14 20:39:18 +0000 |
---|---|---|
committer | Michael Sparmann <theseven@rockbox.org> | 2010-11-14 20:39:18 +0000 |
commit | 6574040b186c65c7d9539f7b1fd254ddb6ee850c (patch) | |
tree | 956e3383f3efa2d3a355f12ef30f075e1c53633b /firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c | |
parent | ba64cf697edfcfb826d54dd86ab40c13c75e0796 (diff) | |
download | rockbox-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
Diffstat (limited to 'firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c')
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c | 1512 |
1 files changed, 658 insertions, 854 deletions
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 **/ | |
62 | int lcd_type; /* also needed in debug-s5l8700.c */ | 62 | |
63 | static int xoffset; /* needed for flip */ | 63 | int lcd_type; /* also needed in debug-s5l8700.c */ |
64 | static bool lcd_ispowered; | 64 | static int xoffset; /* needed for flip */ |
65 | 65 | static 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 | |
74 | unsigned short lcd_init_sequence_0[] = { | 74 | |
75 | CMD16, 0x00a4, | 75 | unsigned 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 | }; | |
207 | unsigned short lcd_init_sequence_1[] = { | 207 | |
208 | CMD8, 0x01, | 208 | unsigned 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, | 219 | static 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, | 232 | static 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, | 238 | static 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, | 246 | static 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, | 252 | static 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, | 262 | int 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, | 267 | void 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, | 272 | void 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, | 278 | void 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, | 293 | bool 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, | 300 | void 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 | |
325 | unsigned 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 | |||
396 | static 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 | |||
409 | static inline void s5l_lcd_write_cmd(unsigned short cmd) | ||
410 | { | ||
411 | while (LCD_STATUS & 0x10); | ||
412 | LCD_WCMD = cmd; | ||
413 | } | ||
414 | |||
415 | static 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 | |||
423 | static inline void s5l_lcd_write_data(unsigned short data) | ||
424 | { | ||
425 | while (LCD_STATUS & 0x10); | ||
426 | LCD_WDATA = data & 0xff; | ||
427 | } | ||
428 | |||
429 | static 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 | |||
439 | int lcd_default_contrast(void) | ||
440 | { | ||
441 | return 0x1f; | ||
442 | } | ||
443 | |||
444 | void lcd_set_contrast(int val) | ||
445 | { | ||
446 | (void)val; | ||
447 | } | ||
448 | |||
449 | void lcd_set_invert_display(bool yesno) | ||
450 | { | ||
451 | (void)yesno; | ||
452 | } | ||
453 | |||
454 | /* turn the display upside down (call lcd_update() afterwards) */ | ||
455 | void 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 | |||
470 | bool lcd_active(void) | ||
471 | { | ||
472 | return lcd_ispowered; | ||
473 | } | ||
474 | |||
475 | #ifdef HAVE_LCD_SLEEP | ||
476 | |||
477 | void 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 | ||
548 | void lcd_awake(void) | 357 | void 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 | ||
554 | void lcd_shutdown(void) | 363 | void 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); | 395 | void lcd_sleep(void) |
587 | 396 | { | |
588 | lcd_ispowered = false; | 397 | lcd_shutdown(); |
589 | } | 398 | } |
590 | 399 | ||
591 | void lcd_sleep(void) | 400 | /* LCD init */ |
592 | { | 401 | void 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 */ |
597 | void 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; | 418 | static 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); | |
614 | static 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; | 428 | void lcd_update(void) ICODE_ATTR; |
620 | } | 429 | void 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]; |
624 | void lcd_update(void) ICODE_ATTR; | 433 | |
625 | void 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 | } | 467 | void lcd_update_rect(int, int, int, int) ICODE_ATTR; |
659 | } | 468 | void 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; |
663 | void lcd_update_rect(int, int, int, int) ICODE_ATTR; | 472 | fb_data* p; |
664 | void 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 | 548 | void 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; |
744 | void 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 | } | ||