Meizu M6SP: fix incorrect readout of button on P1.3 (this is an output to the power...
[kugel-rb.git] / firmware / target / arm / s5l8700 / meizu-m6sp / lcd-m6sp.c
blobfa3d5aa7f2f5b9608589856566093e1dfed182a5
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2009 Bertrik Sikken
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <inttypes.h>
24 #include "config.h"
25 #include "s5l8700.h"
26 #include "lcd.h"
28 /* LCD driver for the Meizu M6 SP using the CLCD controller in the S5L8700
30 The Meizu M6 SP can have two different LCDs, the S6D0139 and another
31 (yet unknown) type, the exact type is detected at run-time.
33 Open issues:
34 * LCD is currently in portrait mode instead of landscape mode
35 * This LCD driver accesses the Rockbox framebuffer directly, so any changes
36 to the framebuffer as shown directly even before lcd_update is called.
37 * Sometimes part of the top of the screen appears at the bottom
38 * The Meizu seems to hang after LCD initialisation
39 * The driver for the S6D0139 LCD has not been tested yet
43 /* LCD SPI connections */
44 #define LCD_SPI_SSn (1<<1) /* on PDAT7 */
45 #define LCD_SPI_MISO (1<<2) /* on PDAT3 */
46 #define LCD_SPI_MOSI (1<<6) /* on PDAT3 */
47 #define LCD_SPI_SCLK (1<<7) /* on PDAT3 */
49 /* LCD SPI communication definitions */
50 #define LCD_SPI_DEVICE_ID (0x1D<<2)
51 #define LCD_SPI_INDEX_WRITE (LCD_SPI_DEVICE_ID|0)
52 #define LCD_SPI_STATUS_READ (LCD_SPI_DEVICE_ID|1)
53 #define LCD_SPI_DATA_WRITE (LCD_SPI_DEVICE_ID|2)
54 #define LCD_SPI_DATA_READ (LCD_SPI_DEVICE_ID|3)
56 #define LCD_TYPE1_ID 0x139 /* id for LCD type S6D0139 */
58 static int lcd_type = 0;
60 /* simple and crude delay */
61 static void lcd_delay(int count)
63 volatile int i;
64 for (i = 0; i < count; i++);
67 /* write 'data_out' of length 'bits' over SPI and return received data */
68 static unsigned int lcd_spi_transfer(int bits, unsigned int data_out)
70 unsigned int data_in = 0;
72 /* SSn active */
73 PDAT7 &= ~LCD_SPI_SSn;
74 lcd_delay(10);
76 /* send and receive data */
77 while (bits--) {
78 /* CLK low */
79 PDAT3 &= ~LCD_SPI_SCLK;
81 /* set MOSI */
82 if (data_out & (1 << bits)) {
83 PDAT3 |= LCD_SPI_MOSI;
85 else {
86 PDAT3 &= ~LCD_SPI_MOSI;
89 /* delay */
90 lcd_delay(10);
92 /* sample MISO */
93 data_in <<= 1;
94 if (PDAT3 & LCD_SPI_MISO) {
95 data_in |= 1;
98 /* CLK high */
99 PDAT3 |= LCD_SPI_SCLK;
101 /* delay */
102 lcd_delay(10);
105 /* SSn inactive */
106 PDAT7 |= LCD_SPI_SSn;
107 lcd_delay(10);
109 return data_in;
112 /* initialize the lcd SPI port interface */
113 static void lcd_spi_init(void)
115 /* configure SSn (P7.1) as output */
116 PCON7 = (PCON7 & ~0x000000F0) | 0x00000010;
118 /* configure MISO (P3.2) input, MOSI (P3.6) output, SCLK (P3.7) output */
119 PCON3 = (PCON3 & ~0xFF000F00) | 0x11000000;
121 /* set all outputs high */
122 PDAT7 |= LCD_SPI_SSn;
123 PDAT3 |= (LCD_SPI_MOSI | LCD_SPI_SCLK);
126 /* read LCD identification word over SPI */
127 static unsigned int lcd_read_reg(unsigned reg)
129 unsigned int data;
131 lcd_spi_transfer(24, (LCD_SPI_INDEX_WRITE << 16) | reg);
132 data = lcd_spi_transfer(24, (LCD_SPI_DATA_READ << 16));
133 return data & 0xFFFF;
136 /* write LCD register over SPI */
137 static void lcd_write_reg(unsigned char reg, unsigned int data)
139 lcd_spi_transfer(24, (LCD_SPI_INDEX_WRITE << 16) | reg);
140 lcd_spi_transfer(24, (LCD_SPI_DATA_WRITE << 16) | data);
143 /* enable/disable clock signals towards the lcd */
144 static void lcd_controller_power(bool on)
146 if (on) {
147 LCDCON1 |= 0x80003;
149 else {
150 LCDCON1 &= ~0x80003;
154 /* lcd init configuration for lcd type 1 */
155 static void lcd_init1(void)
157 lcd_write_reg(0x07, 0x0000); /* display control */
158 lcd_write_reg(0x13, 0x0000); /* power control 3 */
159 lcd_delay(166670);
161 lcd_write_reg(0x11, 0x3304); /* power control 2 */
162 lcd_write_reg(0x14, 0x1300); /* power control 4 */
163 lcd_write_reg(0x10, 0x1A20); /* power control 1 */
164 lcd_write_reg(0x13, 0x0040); /* power control 3 */
165 lcd_delay(833350);
167 lcd_write_reg(0x13, 0x0060); /* power control 3 */
168 lcd_write_reg(0x13, 0x0070); /* power control 3 */
169 lcd_delay(3333400);
171 lcd_write_reg(0x01, 0x0127); /* driver output control */
172 lcd_write_reg(0x02, 0x0700); /* lcd driving waveform control */
173 lcd_write_reg(0x03, 0x1030); /* entry mode */
174 lcd_write_reg(0x08, 0x0208); /* blank period control 1 */
175 lcd_write_reg(0x0B, 0x0620); /* frame cycle control */
176 lcd_write_reg(0x0C, 0x0110); /* external interface control */
177 lcd_write_reg(0x30, 0x0120); /* gamma control 1 */
178 lcd_write_reg(0x31, 0x0117); /* gamma control 2 */
179 lcd_write_reg(0x32, 0x0000); /* gamma control 3 */
180 lcd_write_reg(0x33, 0x0305); /* gamma control 4 */
181 lcd_write_reg(0x34, 0x0717); /* gamma control 5 */
182 lcd_write_reg(0x35, 0x0124); /* gamma control 6 */
183 lcd_write_reg(0x36, 0x0706); /* gamma control 7 */
184 lcd_write_reg(0x37, 0x0503); /* gamma control 8 */
185 lcd_write_reg(0x38, 0x1F03); /* gamma control 9 */
186 lcd_write_reg(0x39, 0x0009); /* gamma control 10 */
187 lcd_write_reg(0x40, 0x0000); /* gate scan position */
188 lcd_write_reg(0x41, 0x0000); /* vertical scroll control */
189 lcd_write_reg(0x42, 0x013F); /* 1st screen driving position (end) */
190 lcd_write_reg(0x43, 0x0000); /* 1st screen driving position (start) */
191 lcd_write_reg(0x44, 0x013F); /* 2nd screen driving position (end) */
192 lcd_write_reg(0x45, 0x0000); /* 2nd screen driving position (start) */
193 lcd_write_reg(0x46, 0xEF00); /* horizontal window address */
194 lcd_write_reg(0x47, 0x013F); /* vertical window address (end) */
195 lcd_write_reg(0x48, 0x0000); /* vertical window address (start) */
197 lcd_write_reg(0x07, 0x0015); /* display control */
198 lcd_delay(500000);
199 lcd_write_reg(0x07, 0x0017); /* display control */
201 lcd_write_reg(0x20, 0x0000); /* RAM address set (low part) */
202 lcd_write_reg(0x21, 0x0000); /* RAM address set (high part) */
203 lcd_write_reg(0x22, 0x0000); /* write data to GRAM */
206 /* lcd init configuration for lcd type 2 */
207 static void lcd_init2(void)
209 lcd_write_reg(0x07, 0x0000);
210 lcd_write_reg(0x12, 0x0000);
211 lcd_delay(166670);
213 lcd_write_reg(0x11, 0x000C);
214 lcd_write_reg(0x12, 0x0A1C);
215 lcd_write_reg(0x13, 0x0022);
216 lcd_write_reg(0x14, 0x0000);
218 lcd_write_reg(0x10, 0x7404);
219 lcd_write_reg(0x11, 0x0738);
220 lcd_write_reg(0x10, 0x7404);
221 lcd_delay(833350);
223 lcd_write_reg(0x07, 0x0009);
224 lcd_write_reg(0x12, 0x065C);
225 lcd_delay(3333400);
227 lcd_write_reg(0x01, 0xE127);
228 lcd_write_reg(0x02, 0x0300);
229 lcd_write_reg(0x03, 0x1100);
230 lcd_write_reg(0x08, 0x0008);
231 lcd_write_reg(0x0B, 0x0000);
232 lcd_write_reg(0x0C, 0x0000);
233 lcd_write_reg(0x0D, 0x0007);
234 lcd_write_reg(0x15, 0x0003);
235 lcd_write_reg(0x16, 0x0014);
236 lcd_write_reg(0x17, 0x0000);
238 lcd_write_reg(0x30, 0x0503); /* gamma? */
239 lcd_write_reg(0x31, 0x0303);
240 lcd_write_reg(0x32, 0x0305);
241 lcd_write_reg(0x33, 0x0202);
242 lcd_write_reg(0x34, 0x0204);
243 lcd_write_reg(0x35, 0x0404);
244 lcd_write_reg(0x36, 0x0402);
245 lcd_write_reg(0x37, 0x0202);
246 lcd_write_reg(0x38, 0x1000);
247 lcd_write_reg(0x39, 0x1000);
249 lcd_write_reg(0x07, 0x0009);
250 lcd_delay(666680);
252 lcd_write_reg(0x07, 0x0109);
253 lcd_delay(666680);
255 lcd_write_reg(0x07, 0x010B);
258 /* lcd enable for lcd type 1 */
259 static void lcd_enable1(bool on)
261 if (on) {
262 lcd_write_reg(0x00, 0x0001); /* start oscillation */
263 lcd_delay(166670);
264 lcd_write_reg(0x10, 0x0000); /* power control 1 */
265 lcd_delay(166670);
267 lcd_write_reg(0x11, 0x3304); /* power control 2 */
268 lcd_write_reg(0x14, 0x1300); /* power control 4 */
269 lcd_write_reg(0x10, 0x1A20); /* power control 1 */
270 lcd_write_reg(0x07, 0x0015); /* display control */
271 lcd_delay(500000);
273 lcd_write_reg(0x20, 0x0000); /* RAM address set (low part) */
274 lcd_write_reg(0x21, 0x0000); /* RAM address set (high part) */
275 lcd_write_reg(0x22, 0x0000); /* write data to GRAM */
277 else {
278 lcd_write_reg(0x07, 0x0016); /* display control */
279 lcd_delay(166670 * 4);
280 lcd_write_reg(0x07, 0x0004); /* display control */
281 lcd_delay(166670 * 4);
283 lcd_write_reg(0x10, 0x1E21); /* power control 1 */
284 lcd_delay(166670);
288 /* lcd enable for lcd type 2 */
289 static void lcd_enable2(bool on)
291 if (on) {
292 lcd_write_reg(0x10, 0x0400);
293 lcd_delay(666680);
295 lcd_write_reg(0x07, 0x0000);
296 lcd_write_reg(0x12, 0x0000);
297 lcd_delay(166670);
299 lcd_write_reg(0x11, 0x000C);
300 lcd_write_reg(0x12, 0x0A1C);
301 lcd_write_reg(0x13, 0x0022);
302 lcd_write_reg(0x14, 0x0000);
303 lcd_write_reg(0x10, 0x7404);
304 lcd_write_reg(0x11, 0x0738);
305 lcd_write_reg(0x10, 0x7404);
306 lcd_delay(833350);
308 lcd_write_reg(0x07, 0x0009);
309 lcd_write_reg(0x12, 0x065C);
310 lcd_delay(3333400);
312 lcd_write_reg(0x0B, 0x0000);
313 lcd_write_reg(0x07, 0x0009);
314 lcd_delay(666680);
316 lcd_write_reg(0x07, 0x0109);
317 lcd_delay(666680);
319 lcd_write_reg(0x07, 0x010B);
321 else {
322 lcd_write_reg(0x0B, 0x0109);
323 lcd_write_reg(0x07, 0x0009);
324 lcd_delay(666680);
326 lcd_write_reg(0x07, 0x0008);
327 lcd_delay(666680);
329 lcd_write_reg(0x10, 0x0400);
330 lcd_write_reg(0x10, 0x0401);
331 lcd_delay(166670);
335 /* turn both the lcd controller and the lcd itself on or off */
336 void lcd_enable(bool on)
338 if (on) {
339 /* enable controller clock */
340 PWRCON &= ~(1 << 18);
342 lcd_controller_power(true);
343 lcd_delay(166670);
346 /* call type specific power function */
347 if (lcd_type == 1) {
348 lcd_enable1(on);
350 else {
351 lcd_enable2(on);
354 if (!on) {
355 lcd_controller_power(false);
357 /* disable controller clock */
358 PWRCON |= (1 << 18);
362 /* initialise the lcd controller inside the s5l8700 */
363 static void lcd_controller_init(void)
365 PWRCON &= ~(1 << 18);
367 LCDCON1 = (0 << 28) | /* BURSTLEN */
368 (0 << 19) | /* DIVEN */
369 (12 << 13) | /* CLKVAL */
370 (1 << 12) | /* CLKDIR, 1=divided clock */
371 (0 << 11) | /* CLKSEL, 0=HCLK, 1=PLL */
372 (5 << 6) | /* BPPMODEF, 5=rgb565, 7=raw24 */
373 (5 << 2) | /* BPPMODEB, 5=rgb565, 7=raw24 */
374 (0 << 0); /* ENVID */
375 LCDCON2 = (2 << 9) | /* PALFRM, 2=rgb565 palette */
376 (1 << 7) | /* IVCLK */
377 (1 << 6) | /* IHSYNC */
378 (1 << 5) | /* IVSYNC */
379 (1 << 3); /* IVDEN */
380 LCDTCON1 = (lcd_type == 1) ? 0x070103 : 0x030303;
381 LCDTCON2 = (lcd_type == 1) ? 0x070103 : 0x030703;
382 LCDTCON3 = ((LCD_HEIGHT - 1) << 11) | (LCD_WIDTH - 1);
383 LCDOSD1 = 0;
384 LCDOSD2 = 0;
385 LCDOSD3 = 0;
387 LCDB1SADDR1 = 0;
388 LCDB2SADDR1 = 0;
389 LCDF1SADDR1 = 0;
390 LCDF2SADDR1 = 0;
391 LCDB1SADDR2 = 0;
392 LCDB2SADDR2 = 0;
393 LCDF1SADDR2 = 0;
394 LCDF2SADDR2 = 0;
395 LCDB1SADDR3 = 0;
396 LCDB2SADDR3 = 0;
397 LCDF1SADDR3 = 0;
398 LCDF2SADDR3 = 0;
400 LCDKEYCON = 0;
401 LCDCOLVAL = 0;
402 LCDBGCON = 0;
403 LCDFGCON = 0;
404 LCDDITHMODE = 0;
406 LCDINTCON = 0;
409 void lcd_init_device(void)
411 unsigned int lcd_id;
412 uint32_t fb, fb_end, window;
414 /* configure LCD SPI pins */
415 lcd_spi_init();
417 /* identify display through SPI */
418 lcd_id = lcd_read_reg(0);
419 lcd_type = (lcd_id == LCD_TYPE1_ID) ? 1 : 2;
421 /* display specific init sequence */
422 if (lcd_type == 1) {
423 lcd_init1();
425 else {
426 lcd_init2();
429 /* init LCD controller */
430 lcd_controller_init();
432 /* set framebuffer addresses */
433 fb = (uint32_t) &lcd_framebuffer[0][0];
434 fb_end = (uint32_t) &lcd_framebuffer[LCD_HEIGHT][0];
435 window = 2 * LCD_WIDTH;
437 LCDB1SADDR1 = fb;
438 LCDB2SADDR1 = fb;
439 LCDF1SADDR1 = fb;
440 LCDF2SADDR1 = fb;
442 LCDB1SADDR2 = fb_end;
443 LCDB2SADDR2 = fb_end;
444 LCDF1SADDR2 = fb_end; LCDF2SADDR2 = fb_end;
446 LCDB1SADDR3 = window;
447 LCDB2SADDR3 = window;
448 LCDF1SADDR3 = window;
449 LCDF2SADDR3 = window;
451 lcd_enable(true);
453 /* configure LCD pins */
454 PCON_ASRAM = 1;
457 void lcd_update_rect(int x, int y, int width, int height)
459 /* not implemented yet, LCD controller accesses framebuffer directly */
460 (void) x;
461 (void) y;
462 (void) width;
463 (void) height;
466 void lcd_update(void)
468 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);