diff options
Diffstat (limited to 'firmware/target/arm/s5l8700')
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/backlight-nano2g.c | 11 | ||||
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/lcd-nano2g.c | 1512 |
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 |
30 | bool lcd_active(void); | ||
30 | void lcd_awake(void); | 31 | void lcd_awake(void); |
31 | void lcd_update(void); | 32 | void lcd_update(void); |
32 | #endif | 33 | #endif |
@@ -38,11 +39,13 @@ void _backlight_set_brightness(int brightness) | |||
38 | 39 | ||
39 | void _backlight_on(void) | 40 | void _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 **/ | |
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 | } | ||