Meizu M6SP: initial LCD driver (compiles but is untested)
[kugel-rb/myfork.git] / firmware / target / arm / s5l8700 / meizu-m6sp / lcd-m6sp.c
blobb6330406f251bc156e6646884621693f74db390d
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 * untested on actual hardware
35 * use 16-bit pixel format, currently pixels are converted to a 32-bit pixel
36 format in lcd_update_rect, that is not natively supported yet in Rockbox.
40 /* LCD SPI connections */
41 #define LCD_SPI_SSn (1<<1) /* on PDAT7 */
42 #define LCD_SPI_MISO (1<<2) /* on PDAT3 */
43 #define LCD_SPI_MOSI (1<<6) /* on PDAT3 */
44 #define LCD_SPI_SCLK (1<<7) /* on PDAT3 */
46 #define LCD_TYPE1_ID 0x139 /* id for LCD type S6D0139 */
48 static int lcd_type = 0;
50 /* local frame buffer, keeps pixels in 32-bit words in format 0x00RRGGBB */
51 static uint32_t lcd_local_fb[LCD_HEIGHT][LCD_WIDTH];
54 /* simple and crude delay */
55 static void lcd_delay(int count)
57 volatile int i;
58 for (i = 0; i < count; i++);
61 /* write 'data_out' of length 'bits' over SPI and return received data */
62 static unsigned int lcd_spi_transfer(int bits, unsigned int data_out)
64 unsigned int data_in = 0;
66 /* SSn active */
67 PDAT7 &= ~LCD_SPI_SSn;
68 lcd_delay(10);
70 /* send and receive data */
71 while (bits--) {
72 /* CLK low */
73 PDAT3 &= ~LCD_SPI_SCLK;
75 /* set MOSI */
76 if (data_out & (1 << bits)) {
77 PDAT3 |= LCD_SPI_MOSI;
79 else {
80 PDAT3 &= ~LCD_SPI_MOSI;
83 /* delay */
84 lcd_delay(10);
86 /* sample MISO */
87 data_in <<= 1;
88 if (PDAT3 & LCD_SPI_MISO) {
89 data_in |= 1;
92 /* CLK high */
93 PDAT3 |= LCD_SPI_SCLK;
95 /* delay */
96 lcd_delay(10);
99 /* SSn inactive */
100 PDAT7 |= LCD_SPI_SSn;
101 lcd_delay(10);
103 return data_in;
106 /* initialize the lcd SPI port interface */
107 static void lcd_spi_init(void)
109 /* configure SSn (P7.1) as output */
110 PCON7 = (PCON7 & ~0x000000F0) | 0x00000010;
112 /* configure MISO (P3.2) input, MOSI (P3.6) output, SCLK (P3.7) output */
113 PCON3 = (PCON3 & ~0xFF000F00) | 0x11000000;
115 /* set all outputs high */
116 PDAT7 |= LCD_SPI_SSn;
117 PDAT3 |= (LCD_SPI_MOSI | LCD_SPI_SCLK);
120 /* read LCD identification word over SPI */
121 static unsigned int lcd_read_reg(unsigned reg)
123 unsigned int data;
125 lcd_spi_transfer(24, (0x74 << 16) | reg); //0111.0100
126 data = lcd_spi_transfer(24, (0x77 << 16)); //0111.0111
127 return data & 0xFFFF;
130 /* write LCD register over SPI */
131 static void lcd_write_reg(unsigned char reg, unsigned int data)
133 lcd_spi_transfer(24, (0x74 << 16) | reg); //0111.0100
134 lcd_spi_transfer(24, (0x76 << 16) | data); //0111.0110
137 /* enable/disable clock signals towards the lcd */
138 static void lcd_controller_power(bool on)
140 if (on) {
141 LCDCON1 |= 0x80003;
143 else {
144 LCDCON1 &= ~0x80003;
148 /* lcd init configuration for lcd type 1 */
149 static void lcd_init1(void)
151 lcd_write_reg(0x07, 0x0000); /* display control */
152 lcd_write_reg(0x13, 0x0000); /* power control 3 */
153 lcd_delay(166670);
155 lcd_write_reg(0x11, 0x3304); /* power control 2 */
156 lcd_write_reg(0x14, 0x1300); /* power control 4 */
157 lcd_write_reg(0x10, 0x1A20); /* power control 1 */
158 lcd_write_reg(0x13, 0x0040); /* power control 3 */
159 lcd_delay(833350);
161 lcd_write_reg(0x13, 0x0060); /* power control 3 */
162 lcd_write_reg(0x13, 0x0070); /* power control 3 */
163 lcd_delay(3333400);
165 lcd_write_reg(0x01, 0x0127); /* driver output control */
166 lcd_write_reg(0x02, 0x0700); /* lcd driving waveform control */
167 lcd_write_reg(0x03, 0x1030); /* entry mode */
168 lcd_write_reg(0x08, 0x0208); /* blank period control 1 */
169 lcd_write_reg(0x0B, 0x0620); /* frame cycle control */
170 lcd_write_reg(0x0C, 0x0110); /* external interface control */
171 lcd_write_reg(0x30, 0x0120); /* gamma control 1 */
172 lcd_write_reg(0x31, 0x0117); /* gamma control 2 */
173 lcd_write_reg(0x32, 0x0000); /* gamma control 3 */
174 lcd_write_reg(0x33, 0x0305); /* gamma control 4 */
175 lcd_write_reg(0x34, 0x0717); /* gamma control 5 */
176 lcd_write_reg(0x35, 0x0124); /* gamma control 6 */
177 lcd_write_reg(0x36, 0x0706); /* gamma control 7 */
178 lcd_write_reg(0x37, 0x0503); /* gamma control 8 */
179 lcd_write_reg(0x38, 0x1F03); /* gamma control 9 */
180 lcd_write_reg(0x39, 0x0009); /* gamma control 10 */
181 lcd_write_reg(0x40, 0x0000); /* gate scan position */
182 lcd_write_reg(0x41, 0x0000); /* vertical scroll control */
183 lcd_write_reg(0x42, 0x013F); /* 1st screen driving position (end) */
184 lcd_write_reg(0x43, 0x0000); /* 1st screen driving position (start) */
185 lcd_write_reg(0x44, 0x013F); /* 2nd screen driving position (end) */
186 lcd_write_reg(0x45, 0x0000); /* 2nd screen driving position (start) */
187 lcd_write_reg(0x46, 0xEF00); /* horizontal window address */
188 lcd_write_reg(0x47, 0x013F); /* vertical window address (end) */
189 lcd_write_reg(0x48, 0x0000); /* vertical window address (start) */
191 lcd_write_reg(0x07, 0x0015); /* display control */
192 lcd_delay(500000);
193 lcd_write_reg(0x07, 0x0017); /* display control */
195 lcd_write_reg(0x20, 0x0000); /* RAM address set (low part) */
196 lcd_write_reg(0x21, 0x0000); /* RAM address set (high part) */
197 lcd_write_reg(0x22, 0x0000); /* write data to GRAM */
200 /* lcd init configuration for lcd type 2 */
201 static void lcd_init2(void)
203 lcd_write_reg(0x07, 0x0000);
204 lcd_write_reg(0x12, 0x0000);
205 lcd_delay(166670);
207 lcd_write_reg(0x11, 0x000C);
208 lcd_write_reg(0x12, 0x0A1C);
209 lcd_write_reg(0x13, 0x0022);
210 lcd_write_reg(0x14, 0x0000);
212 lcd_write_reg(0x10, 0x7404);
213 lcd_write_reg(0x11, 0x0738);
214 lcd_write_reg(0x10, 0x7404);
215 lcd_delay(833350);
217 lcd_write_reg(0x07, 0x0009);
218 lcd_write_reg(0x12, 0x065C);
219 lcd_delay(3333400);
221 lcd_write_reg(0x01, 0xE127);
222 lcd_write_reg(0x02, 0x0300);
223 lcd_write_reg(0x03, 0x1100);
224 lcd_write_reg(0x08, 0x0008);
225 lcd_write_reg(0x0B, 0x0000);
226 lcd_write_reg(0x0C, 0x0000);
227 lcd_write_reg(0x0D, 0x0007);
228 lcd_write_reg(0x15, 0x0003);
230 lcd_write_reg(0x16, 0x0014);
231 lcd_write_reg(0x17, 0x0000);
232 lcd_write_reg(0x30, 0x0503);
233 lcd_write_reg(0x31, 0x0303);
234 lcd_write_reg(0x32, 0x0305);
235 lcd_write_reg(0x33, 0x0202);
236 lcd_write_reg(0x34, 0x0204);
237 lcd_write_reg(0x35, 0x0404);
238 lcd_write_reg(0x36, 0x0402);
239 lcd_write_reg(0x37, 0x0202);
240 lcd_write_reg(0x38, 0x1000);
241 lcd_write_reg(0x39, 0x1000);
243 lcd_write_reg(0x07, 0x0009);
244 lcd_delay(666680);
246 lcd_write_reg(0x07, 0x0109);
247 lcd_delay(666680);
249 lcd_write_reg(0x07, 0x010B);
252 /* lcd enable for lcd type 1 */
253 static void lcd_enable1(bool on)
255 if (on) {
256 lcd_write_reg(0x00, 0x0001); /* start oscillation */
257 lcd_delay(166670);
258 lcd_write_reg(0x10, 0x0000); /* power control 1 */
259 lcd_delay(166670);
261 lcd_write_reg(0x11, 0x3304); /* power control 2 */
262 lcd_write_reg(0x14, 0x1300); /* power control 4 */
263 lcd_write_reg(0x10, 0x1A20); /* power control 1 */
264 lcd_write_reg(0x07, 0x0015); /* display control */
265 lcd_delay(500000);
267 lcd_write_reg(0x20, 0x0000); /* RAM address set (low part) */
268 lcd_write_reg(0x21, 0x0000); /* RAM address set (high part) */
269 lcd_write_reg(0x22, 0x0000); /* write data to GRAM */
271 else {
272 lcd_write_reg(0x07, 0x0016); /* display control */
273 lcd_delay(166670 * 4);
274 lcd_write_reg(0x07, 0x0004); /* display control */
275 lcd_delay(166670 * 4);
277 lcd_write_reg(0x10, 0x1E21); /* power control 1 */
278 lcd_delay(166670);
282 /* lcd enable for lcd type 2 */
283 static void lcd_enable2(bool on)
285 if (on) {
286 lcd_write_reg(0x10, 0x0400);
287 lcd_delay(666680);
289 lcd_write_reg(0x07, 0x0000);
290 lcd_write_reg(0x12, 0x0000);
291 lcd_delay(166670);
293 lcd_write_reg(0x11, 0x000C);
294 lcd_write_reg(0x12, 0x0A1C);
295 lcd_write_reg(0x13, 0x0022);
296 lcd_write_reg(0x14, 0x0000);
297 lcd_write_reg(0x10, 0x7404);
298 lcd_delay(833350);
300 lcd_write_reg(0x07, 0x0009);
301 lcd_write_reg(0x12, 0x065C);
302 lcd_delay(3333400);
304 lcd_write_reg(0x0B, 0x0000);
305 lcd_write_reg(0x07, 0x0009);
306 lcd_delay(666680);
308 lcd_write_reg(0x07, 0x0109);
309 lcd_delay(666680);
311 lcd_write_reg(0x07, 0x010B);
313 else {
314 lcd_write_reg(0x0B, 0x0000);
315 lcd_write_reg(0x07, 0x0009);
316 lcd_delay(666680);
318 lcd_write_reg(0x07, 0x0008);
319 lcd_delay(666680);
321 lcd_write_reg(0x10, 0x0400);
322 lcd_write_reg(0x10, 0x0401);
323 lcd_delay(166670);
327 /* turn both the lcd controller and the lcd itself on or off */
328 void lcd_enable(bool on)
330 if (on) {
331 /* enable controller clock */
332 PWRCON &= ~(1 << 18);
334 lcd_controller_power(true);
335 lcd_delay(166670);
338 /* call type specific power function */
339 if (lcd_type == 1) {
340 lcd_enable1(on);
342 else {
343 lcd_enable2(on);
346 if (!on) {
347 lcd_controller_power(false);
349 /* disable controller clock */
350 PWRCON |= (1 << 18);
354 /* initialise the lcd controller inside the s5l8700 */
355 static void lcd_controller_init(void)
357 PWRCON &= ~(1 << 18);
359 LCDCON1 = 0x991DC;
360 LCDCON2 = 0xE8;
361 LCDTCON1 = (lcd_type == 1) ? 0x70103 : 0x30303;
362 LCDTCON2 = (lcd_type == 1) ? 0x70103 : 0x30703;
363 LCDTCON3 = 0x9F8EF;
364 LCDOSD1 = 0;
365 LCDOSD2 = 0;
366 LCDOSD3 = 0;
367 LCDB1SADDR1 = 0;
368 LCDB2SADDR1 = 0;
369 LCDF1SADDR1 = 0;
370 LCDF2SADDR1 = 0;
371 LCDB1SADDR2 = 0;
372 LCDB2SADDR2 = 0;
373 LCDF1SADDR2 = 0;
374 LCDF2SADDR2 = 0;
375 LCDB1SADDR3 = 0;
376 LCDB2SADDR3 = 0;
377 LCDF1SADDR3 = 0;
378 LCDF2SADDR3 = 0;
379 LCDKEYCON = 0;
380 LCDCOLVAL = 0;
381 LCDBGCON = 0;
382 LCDFGCON = 0;
383 LCDDITHMODE = 0;
385 LCDINTCON = 0;
388 void lcd_init_device(void)
390 unsigned int lcd_id;
392 /* configure LCD SPI pins */
393 lcd_spi_init();
395 /* identify display through SPI */
396 lcd_id = lcd_read_reg(0);
397 lcd_type = (lcd_id == LCD_TYPE1_ID) ? 1 : 2;
399 /* configure LCD pins */
400 PCON_ASRAM = 1;
402 /* init LCD controller */
403 lcd_controller_init();
405 /* display specific init sequence */
406 if (lcd_type == 1) {
407 lcd_init1();
409 else {
410 lcd_init2();
413 /* set active background buffer */
414 LCDCON1 &= ~(1 << 21); /* clear BDBCON */
416 /* set background buffer address */
417 LCDB1SADDR1 = (uint32_t) &lcd_local_fb[0][0];
418 LCDB1SADDR2 = (uint32_t) &lcd_local_fb[LCD_HEIGHT][0];
420 lcd_enable(true);
423 void lcd_update_rect(int x, int y, int width, int height)
425 fb_data *src;
426 uint32_t *dst;
427 fb_data pixel;
428 int h, w;
430 for (h = 0; h < height; h++) {
431 src = &lcd_framebuffer[y][x];
432 dst = &lcd_local_fb[y][x];
433 for (w = 0; w < width; w++) {
434 pixel = src[w];
435 dst[w] = (RGB_UNPACK_RED(pixel) << 16) |
436 (RGB_UNPACK_GREEN(pixel) << 8) |
437 (RGB_UNPACK_BLUE(pixel) << 0);
439 y++;
443 void lcd_update(void)
445 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);