diff options
-rw-r--r-- | firmware/export/config/ipod6g.h | 4 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/backlight-ipod6g.c | 10 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c | 267 |
3 files changed, 235 insertions, 46 deletions
diff --git a/firmware/export/config/ipod6g.h b/firmware/export/config/ipod6g.h index 16e114bf9b..1941074d57 100644 --- a/firmware/export/config/ipod6g.h +++ b/firmware/export/config/ipod6g.h | |||
@@ -93,8 +93,8 @@ | |||
93 | /* Define this if your LCD can be put to sleep. HAVE_LCD_ENABLE | 93 | /* Define this if your LCD can be put to sleep. HAVE_LCD_ENABLE |
94 | should be defined as well. */ | 94 | should be defined as well. */ |
95 | #ifndef BOOTLOADER | 95 | #ifndef BOOTLOADER |
96 | //TODO: #define HAVE_LCD_SLEEP | 96 | #define HAVE_LCD_SLEEP |
97 | //TODO: #define HAVE_LCD_SLEEP_SETTING | 97 | #define HAVE_LCD_SLEEP_SETTING |
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | #define CONFIG_KEYPAD IPOD_4G_PAD | 100 | #define CONFIG_KEYPAD IPOD_4G_PAD |
diff --git a/firmware/target/arm/s5l8702/ipod6g/backlight-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/backlight-ipod6g.c index dc21d161de..481a2643bb 100644 --- a/firmware/target/arm/s5l8702/ipod6g/backlight-ipod6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/backlight-ipod6g.c | |||
@@ -44,7 +44,7 @@ void _backlight_on(void) | |||
44 | { | 44 | { |
45 | lcd_awake(); | 45 | lcd_awake(); |
46 | lcd_update(); | 46 | lcd_update(); |
47 | sleep(HZ/8); | 47 | sleep(HZ/20); |
48 | } | 48 | } |
49 | #endif | 49 | #endif |
50 | pmu_write(0x29, 1); | 50 | pmu_write(0x29, 1); |
@@ -57,9 +57,11 @@ void _backlight_off(void) | |||
57 | 57 | ||
58 | bool _backlight_init(void) | 58 | bool _backlight_init(void) |
59 | { | 59 | { |
60 | pmu_write(0x2a, 6); | 60 | /* LEDCTL: overvoltage protection enabled, OCP limit is 500mA */ |
61 | pmu_write(0x28, 0x20); | 61 | pmu_write(0x2a, 0x05); |
62 | pmu_write(0x2b, 20); | 62 | |
63 | pmu_write(0x2b, 0x14); /* T_dimstep = 16 * value / 32768 */ | ||
64 | _backlight_set_brightness(DEFAULT_BRIGHTNESS_SETTING); | ||
63 | 65 | ||
64 | _backlight_on(); | 66 | _backlight_on(); |
65 | 67 | ||
diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c index e7a9cf4141..c1071e31b1 100644 --- a/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c | |||
@@ -53,15 +53,159 @@ static struct dma_lli lcd_lli[(LCD_WIDTH * LCD_HEIGHT - 1) / 0xfff] CACHEALIGN_A | |||
53 | static struct semaphore lcd_wakeup; | 53 | static struct semaphore lcd_wakeup; |
54 | static struct mutex lcd_mutex; | 54 | static struct mutex lcd_mutex; |
55 | static uint16_t lcd_dblbuf[LCD_HEIGHT][LCD_WIDTH]; | 55 | static uint16_t lcd_dblbuf[LCD_HEIGHT][LCD_WIDTH]; |
56 | static bool lcd_ispowered; | ||
56 | 57 | ||
58 | #define SLEEP 0 | ||
59 | #define CMD16 1 | ||
60 | #define DATA16 2 | ||
61 | #define REG15 3 | ||
62 | #define END 0xff | ||
57 | 63 | ||
58 | static inline void s5l_lcd_write_cmd_data(int cmd, int data) | 64 | /* powersave sequences */ |
65 | |||
66 | unsigned short lcd_sleep_sequence_01[] = | ||
67 | { | ||
68 | CMD16, 0x028, /* Display Off */ | ||
69 | SLEEP, 0x005, /* 50 ms */ | ||
70 | CMD16, 0x010, /* Sleep In Mode */ | ||
71 | SLEEP, 0x005, /* 50 ms */ | ||
72 | END | ||
73 | }; | ||
74 | |||
75 | unsigned short lcd_deep_stby_sequence_23[] = | ||
76 | { | ||
77 | /* Display Off */ | ||
78 | REG15, 0x007, 0x0172, | ||
79 | REG15, 0x030, 0x03ff, | ||
80 | SLEEP, 0x00a, | ||
81 | REG15, 0x007, 0x0120, | ||
82 | REG15, 0x030, 0x0000, | ||
83 | REG15, 0x100, 0x0780, | ||
84 | REG15, 0x007, 0x0000, | ||
85 | REG15, 0x101, 0x0260, | ||
86 | REG15, 0x102, 0x00a9, | ||
87 | SLEEP, 0x003, | ||
88 | REG15, 0x100, 0x0700, | ||
89 | |||
90 | /* Deep Standby Mode */ | ||
91 | REG15, 0x100, 0x0704, | ||
92 | SLEEP, 0x005, | ||
93 | END | ||
94 | }; | ||
95 | |||
96 | #ifdef HAVE_LCD_SLEEP | ||
97 | /* init sequences */ | ||
98 | |||
99 | unsigned short lcd_init_sequence_01[] = | ||
100 | { | ||
101 | CMD16, 0x011, /* Sleep Out Mode */ | ||
102 | SLEEP, 0x006, /* 60 ms */ | ||
103 | CMD16, 0x029, /* Display On */ | ||
104 | END | ||
105 | }; | ||
106 | |||
107 | unsigned short lcd_init_sequence_23[] = | ||
108 | { | ||
109 | /* Display settings */ | ||
110 | REG15, 0x008, 0x0808, | ||
111 | REG15, 0x010, 0x0013, | ||
112 | REG15, 0x011, 0x0300, | ||
113 | REG15, 0x012, 0x0101, | ||
114 | REG15, 0x013, 0x0a03, | ||
115 | REG15, 0x014, 0x0a0e, | ||
116 | REG15, 0x015, 0x0a19, | ||
117 | REG15, 0x016, 0x2402, | ||
118 | REG15, 0x018, 0x0001, | ||
119 | REG15, 0x090, 0x0021, | ||
120 | |||
121 | /* Gamma settings */ | ||
122 | REG15, 0x300, 0x0307, | ||
123 | REG15, 0x301, 0x0003, | ||
124 | REG15, 0x302, 0x0402, | ||
125 | REG15, 0x303, 0x0303, | ||
126 | REG15, 0x304, 0x0300, | ||
127 | REG15, 0x305, 0x0407, | ||
128 | REG15, 0x306, 0x1c04, | ||
129 | REG15, 0x307, 0x0307, | ||
130 | REG15, 0x308, 0x0003, | ||
131 | REG15, 0x309, 0x0402, | ||
132 | REG15, 0x30a, 0x0303, | ||
133 | REG15, 0x30b, 0x0300, | ||
134 | REG15, 0x30c, 0x0407, | ||
135 | REG15, 0x30d, 0x1c04, | ||
136 | |||
137 | REG15, 0x310, 0x0707, | ||
138 | REG15, 0x311, 0x0407, | ||
139 | REG15, 0x312, 0x0306, | ||
140 | REG15, 0x313, 0x0303, | ||
141 | REG15, 0x314, 0x0300, | ||
142 | REG15, 0x315, 0x0407, | ||
143 | REG15, 0x316, 0x1c01, | ||
144 | REG15, 0x317, 0x0707, | ||
145 | REG15, 0x318, 0x0407, | ||
146 | REG15, 0x319, 0x0306, | ||
147 | REG15, 0x31a, 0x0303, | ||
148 | REG15, 0x31b, 0x0300, | ||
149 | REG15, 0x31c, 0x0407, | ||
150 | REG15, 0x31d, 0x1c01, | ||
151 | |||
152 | REG15, 0x320, 0x0206, | ||
153 | REG15, 0x321, 0x0102, | ||
154 | REG15, 0x322, 0x0404, | ||
155 | REG15, 0x323, 0x0303, | ||
156 | REG15, 0x324, 0x0300, | ||
157 | REG15, 0x325, 0x0407, | ||
158 | REG15, 0x326, 0x1c1f, | ||
159 | REG15, 0x327, 0x0206, | ||
160 | REG15, 0x328, 0x0102, | ||
161 | REG15, 0x329, 0x0404, | ||
162 | REG15, 0x32a, 0x0303, | ||
163 | REG15, 0x32b, 0x0300, | ||
164 | REG15, 0x32c, 0x0407, | ||
165 | REG15, 0x32d, 0x1c1f, | ||
166 | |||
167 | /* GRAM and Base Imagen settings (ili9326ds) */ | ||
168 | REG15, 0x400, 0x001d, | ||
169 | REG15, 0x401, 0x0001, | ||
170 | REG15, 0x205, 0x0060, | ||
171 | |||
172 | /* Power settings */ | ||
173 | REG15, 0x007, 0x0001, | ||
174 | REG15, 0x031, 0x0071, | ||
175 | REG15, 0x110, 0x0001, | ||
176 | REG15, 0x100, 0x17b0, | ||
177 | REG15, 0x101, 0x0220, | ||
178 | REG15, 0x102, 0x00bd, | ||
179 | REG15, 0x103, 0x1500, | ||
180 | REG15, 0x105, 0x0103, | ||
181 | REG15, 0x106, 0x0105, | ||
182 | |||
183 | /* Display On */ | ||
184 | REG15, 0x007, 0x0021, | ||
185 | REG15, 0x001, 0x0110, | ||
186 | REG15, 0x003, 0x0230, | ||
187 | REG15, 0x002, 0x0500, | ||
188 | REG15, 0x007, 0x0031, | ||
189 | REG15, 0x030, 0x0007, | ||
190 | SLEEP, 0x003, | ||
191 | REG15, 0x030, 0x03ff, | ||
192 | SLEEP, 0x006, | ||
193 | REG15, 0x007, 0x0072, | ||
194 | SLEEP, 0x00f, | ||
195 | REG15, 0x007, 0x0173, | ||
196 | END | ||
197 | }; | ||
198 | #endif | ||
199 | |||
200 | static inline void s5l_lcd_write_reg(int cmd, unsigned int data) | ||
59 | { | 201 | { |
60 | while (LCD_STATUS & 0x10); | 202 | while (LCD_STATUS & 0x10); |
61 | LCD_WCMD = cmd; | 203 | LCD_WCMD = cmd; |
62 | 204 | ||
63 | while (LCD_STATUS & 0x10); | 205 | while (LCD_STATUS & 0x10); |
64 | LCD_WDATA = (data & 0xff) | ((data & 0x7f00) << 1); | 206 | /* 16-bit/1-transfer data format (ili9320ds s7.2.2) */ |
207 | LCD_WDATA = (data & 0x78ff) | | ||
208 | ((data & 0x0300) << 1) | ((data & 0x0400) << 5); | ||
65 | } | 209 | } |
66 | 210 | ||
67 | static inline void s5l_lcd_write_cmd(unsigned short cmd) | 211 | static inline void s5l_lcd_write_cmd(unsigned short cmd) |
@@ -76,6 +220,32 @@ static inline void s5l_lcd_write_data(unsigned short data) | |||
76 | LCD_WDATA = data; | 220 | LCD_WDATA = data; |
77 | } | 221 | } |
78 | 222 | ||
223 | static void lcd_run_sequence(unsigned short *seq) | ||
224 | { | ||
225 | unsigned short tmp; | ||
226 | |||
227 | while (1) switch (*seq++) | ||
228 | { | ||
229 | case SLEEP: | ||
230 | sleep(*seq++); | ||
231 | break; | ||
232 | case CMD16: | ||
233 | s5l_lcd_write_cmd(*seq++); | ||
234 | break; | ||
235 | case DATA16: | ||
236 | s5l_lcd_write_data(*seq++); | ||
237 | break; | ||
238 | case REG15: | ||
239 | tmp = *seq++; /* avoid compiler warning */ | ||
240 | s5l_lcd_write_reg(tmp, *seq++); | ||
241 | break; | ||
242 | case END: | ||
243 | default: | ||
244 | /* bye */ | ||
245 | return; | ||
246 | } | ||
247 | } | ||
248 | |||
79 | /*** hardware configuration ***/ | 249 | /*** hardware configuration ***/ |
80 | 250 | ||
81 | int lcd_default_contrast(void) | 251 | int lcd_default_contrast(void) |
@@ -100,50 +270,57 @@ void lcd_set_flip(bool yesno) | |||
100 | 270 | ||
101 | bool lcd_active(void) | 271 | bool lcd_active(void) |
102 | { | 272 | { |
103 | return true; | 273 | return lcd_ispowered; |
104 | } | 274 | } |
105 | 275 | ||
106 | void lcd_shutdown(void) | 276 | void lcd_shutdown(void) |
107 | { | 277 | { |
108 | mutex_lock(&lcd_mutex); | ||
109 | pmu_write(0x2b, 0); /* Kill the backlight, instantly. */ | 278 | pmu_write(0x2b, 0); /* Kill the backlight, instantly. */ |
110 | pmu_write(0x29, 0); | 279 | pmu_write(0x29, 0); |
111 | 280 | ||
112 | if (lcd_type & 2) | 281 | lcd_sleep(); |
113 | { | 282 | } |
114 | s5l_lcd_write_cmd_data(0x7, 0x172); | 283 | |
115 | s5l_lcd_write_cmd_data(0x30, 0x3ff); | 284 | void lcd_sleep(void) |
116 | sleep(HZ / 10); | 285 | { |
117 | s5l_lcd_write_cmd_data(0x7, 0x120); | 286 | mutex_lock(&lcd_mutex); |
118 | s5l_lcd_write_cmd_data(0x30, 0x0); | 287 | |
119 | s5l_lcd_write_cmd_data(0x100, 0x780); | 288 | lcd_run_sequence((lcd_type & 2) ? lcd_deep_stby_sequence_23 |
120 | s5l_lcd_write_cmd_data(0x7, 0x0); | 289 | : lcd_sleep_sequence_01); |
121 | s5l_lcd_write_cmd_data(0x101, 0x260); | 290 | |
122 | s5l_lcd_write_cmd_data(0x102, 0xa9); | 291 | /* mask lcd controller clock gate */ |
123 | sleep(HZ / 30); | 292 | PWRCON(0) |= (1 << 1); |
124 | s5l_lcd_write_cmd_data(0x100, 0x700); | 293 | |
125 | s5l_lcd_write_cmd_data(0x100, 0x704); | 294 | lcd_ispowered = false; |
126 | } | 295 | |
127 | else if (lcd_type == 1) | ||
128 | { | ||
129 | s5l_lcd_write_cmd(0x28); | ||
130 | s5l_lcd_write_cmd(0x10); | ||
131 | sleep(HZ / 10); | ||
132 | } | ||
133 | else | ||
134 | { | ||
135 | s5l_lcd_write_cmd(0x28); | ||
136 | sleep(HZ / 20); | ||
137 | s5l_lcd_write_cmd(0x10); | ||
138 | sleep(HZ / 20); | ||
139 | } | ||
140 | mutex_unlock(&lcd_mutex); | 296 | mutex_unlock(&lcd_mutex); |
141 | } | 297 | } |
142 | 298 | ||
143 | #ifdef HAVE_LCD_SLEEP | 299 | #ifdef HAVE_LCD_SLEEP |
144 | void lcd_sleep(void) | 300 | void lcd_awake(void) |
145 | { | 301 | { |
146 | lcd_shutdown(); | 302 | mutex_lock(&lcd_mutex); |
303 | |||
304 | /* unmask lcd controller clock gate */ | ||
305 | PWRCON(0) &= ~(1 << 1); | ||
306 | |||
307 | if (lcd_type & 2) { | ||
308 | /* release from deep standby mode (ili9320ds s12.3) */ | ||
309 | for (int i = 0; i < 6; i++) { | ||
310 | s5l_lcd_write_cmd(0x000); | ||
311 | udelay(1000); | ||
312 | } | ||
313 | |||
314 | lcd_run_sequence(lcd_init_sequence_23); | ||
315 | } | ||
316 | else | ||
317 | lcd_run_sequence(lcd_init_sequence_01); | ||
318 | |||
319 | lcd_ispowered = true; | ||
320 | |||
321 | mutex_unlock(&lcd_mutex); | ||
322 | |||
323 | send_event(LCD_EVENT_ACTIVATION, NULL); | ||
147 | } | 324 | } |
148 | #endif | 325 | #endif |
149 | 326 | ||
@@ -156,6 +333,8 @@ void lcd_init_device(void) | |||
156 | lcd_type = (PDAT6 & 0x30) >> 4; | 333 | lcd_type = (PDAT6 & 0x30) >> 4; |
157 | while (!(LCD_STATUS & 0x2)); | 334 | while (!(LCD_STATUS & 0x2)); |
158 | LCD_CONFIG = 0x80100db0; | 335 | LCD_CONFIG = 0x80100db0; |
336 | |||
337 | lcd_ispowered = true; | ||
159 | } | 338 | } |
160 | 339 | ||
161 | /*** Update functions ***/ | 340 | /*** Update functions ***/ |
@@ -190,13 +369,13 @@ static void displaylcd_setup(int x, int y, int width, int height) | |||
190 | int ye = (y + height) - 1; /* max vert */ | 369 | int ye = (y + height) - 1; /* max vert */ |
191 | 370 | ||
192 | if (lcd_type & 2) { | 371 | if (lcd_type & 2) { |
193 | s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x); | 372 | s5l_lcd_write_reg(R_HORIZ_ADDR_START_POS, x); |
194 | s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, xe); | 373 | s5l_lcd_write_reg(R_HORIZ_ADDR_END_POS, xe); |
195 | s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y); | 374 | s5l_lcd_write_reg(R_VERT_ADDR_START_POS, y); |
196 | s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, ye); | 375 | s5l_lcd_write_reg(R_VERT_ADDR_END_POS, ye); |
197 | 376 | ||
198 | s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, x); | 377 | s5l_lcd_write_reg(R_HORIZ_GRAM_ADDR_SET, x); |
199 | s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, y); | 378 | s5l_lcd_write_reg(R_VERT_GRAM_ADDR_SET, y); |
200 | 379 | ||
201 | s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); | 380 | s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM); |
202 | } else { | 381 | } else { |
@@ -252,6 +431,10 @@ void lcd_update_rect(int x, int y, int width, int height) | |||
252 | fb_data* p = &lcd_framebuffer[y][x]; | 431 | fb_data* p = &lcd_framebuffer[y][x]; |
253 | uint16_t* out = lcd_dblbuf[0]; | 432 | uint16_t* out = lcd_dblbuf[0]; |
254 | 433 | ||
434 | #ifdef HAVE_LCD_SLEEP | ||
435 | if (!lcd_active()) return; | ||
436 | #endif | ||
437 | |||
255 | displaylcd_setup(x, y, width, height); | 438 | displaylcd_setup(x, y, width, height); |
256 | 439 | ||
257 | /* Copy display bitmap to hardware */ | 440 | /* Copy display bitmap to hardware */ |
@@ -287,6 +470,10 @@ void lcd_blit_yuv(unsigned char * const src[3], | |||
287 | unsigned int z; | 470 | unsigned int z; |
288 | unsigned char const * yuv_src[3]; | 471 | unsigned char const * yuv_src[3]; |
289 | 472 | ||
473 | #ifdef HAVE_LCD_SLEEP | ||
474 | if (!lcd_active()) return; | ||
475 | #endif | ||
476 | |||
290 | width = (width + 1) & ~1; /* ensure width is even */ | 477 | width = (width + 1) & ~1; /* ensure width is even */ |
291 | 478 | ||
292 | int pixels = width * height; | 479 | int pixels = width * height; |