lcd-m6sp.c: remove \r
[kugel-rb.git] / firmware / target / arm / s5l8700 / meizu-m6sp / lcd-m6sp.c
blob6ab5c08a50fd059d76ec416f961ae3dc89fbfc5c
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;
59 static bool lcd_is_active = false;
61 /* simple and crude delay */
62 static void lcd_delay(int count)
64 volatile int i;
65 for (i = 0; i < count; i++);
68 /* write 'data_out' of length 'bits' over SPI and return received data */
69 static unsigned int lcd_spi_transfer(int bits, unsigned int data_out)
71 unsigned int data_in = 0;
73 /* SSn active */
74 PDAT7 &= ~LCD_SPI_SSn;
75 lcd_delay(10);
77 /* send and receive data */
78 while (bits--) {
79 /* CLK low */
80 PDAT3 &= ~LCD_SPI_SCLK;
82 /* set MOSI */
83 if (data_out & (1 << bits)) {
84 PDAT3 |= LCD_SPI_MOSI;
86 else {
87 PDAT3 &= ~LCD_SPI_MOSI;
90 /* delay */
91 lcd_delay(10);
93 /* sample MISO */
94 data_in <<= 1;
95 if (PDAT3 & LCD_SPI_MISO) {
96 data_in |= 1;
99 /* CLK high */
100 PDAT3 |= LCD_SPI_SCLK;
102 /* delay */
103 lcd_delay(10);
106 /* SSn inactive */
107 PDAT7 |= LCD_SPI_SSn;
108 lcd_delay(10);
110 return data_in;
113 /* initialize the lcd SPI port interface */
114 static void lcd_spi_init(void)
116 /* configure SSn (P7.1) as output */
117 PCON7 = (PCON7 & ~0x000000F0) | 0x00000010;
119 /* configure MISO (P3.2) input, MOSI (P3.6) output, SCLK (P3.7) output */
120 PCON3 = (PCON3 & ~0xFF000F00) | 0x11000000;
122 /* set all outputs high */
123 PDAT7 |= LCD_SPI_SSn;
124 PDAT3 |= (LCD_SPI_MOSI | LCD_SPI_SCLK);
127 /* read LCD identification word over SPI */
128 static unsigned int lcd_read_reg(unsigned reg)
130 unsigned int data;
132 lcd_spi_transfer(24, (LCD_SPI_INDEX_WRITE << 16) | reg);
133 data = lcd_spi_transfer(24, (LCD_SPI_DATA_READ << 16));
134 return data & 0xFFFF;
137 /* write LCD register over SPI */
138 static void lcd_write_reg(unsigned char reg, unsigned int data)
140 lcd_spi_transfer(24, (LCD_SPI_INDEX_WRITE << 16) | reg);
141 lcd_spi_transfer(24, (LCD_SPI_DATA_WRITE << 16) | data);
144 /* enable/disable clock signals towards the lcd */
145 static void lcd_controller_power(bool on)
147 if (on) {
148 LCDCON1 |= 0x80003;
150 else {
151 LCDCON1 &= ~0x80003;
155 /* lcd init configuration for lcd type 1 */
156 static void lcd_init1(void)
158 lcd_write_reg(0x07, 0x0000); /* display control */
159 lcd_write_reg(0x13, 0x0000); /* power control 3 */
160 lcd_delay(166670);
162 lcd_write_reg(0x11, 0x3304); /* power control 2 */
163 lcd_write_reg(0x14, 0x1300); /* power control 4 */
164 lcd_write_reg(0x10, 0x1A20); /* power control 1 */
165 lcd_write_reg(0x13, 0x0040); /* power control 3 */
166 lcd_delay(833350);
168 lcd_write_reg(0x13, 0x0060); /* power control 3 */
169 lcd_write_reg(0x13, 0x0070); /* power control 3 */
170 lcd_delay(3333400);
172 lcd_write_reg(0x01, 0x0127); /* driver output control */
173 lcd_write_reg(0x02, 0x0700); /* lcd driving waveform control */
174 lcd_write_reg(0x03, 0x1030); /* entry mode */
175 lcd_write_reg(0x08, 0x0208); /* blank period control 1 */
176 lcd_write_reg(0x0B, 0x0620); /* frame cycle control */
177 lcd_write_reg(0x0C, 0x0110); /* external interface control */
178 lcd_write_reg(0x30, 0x0120); /* gamma control 1 */
179 lcd_write_reg(0x31, 0x0117); /* gamma control 2 */
180 lcd_write_reg(0x32, 0x0000); /* gamma control 3 */
181 lcd_write_reg(0x33, 0x0305); /* gamma control 4 */
182 lcd_write_reg(0x34, 0x0717); /* gamma control 5 */
183 lcd_write_reg(0x35, 0x0124); /* gamma control 6 */
184 lcd_write_reg(0x36, 0x0706); /* gamma control 7 */
185 lcd_write_reg(0x37, 0x0503); /* gamma control 8 */
186 lcd_write_reg(0x38, 0x1F03); /* gamma control 9 */
187 lcd_write_reg(0x39, 0x0009); /* gamma control 10 */
188 lcd_write_reg(0x40, 0x0000); /* gate scan position */
189 lcd_write_reg(0x41, 0x0000); /* vertical scroll control */
190 lcd_write_reg(0x42, 0x013F); /* 1st screen driving position (end) */
191 lcd_write_reg(0x43, 0x0000); /* 1st screen driving position (start) */
192 lcd_write_reg(0x44, 0x013F); /* 2nd screen driving position (end) */
193 lcd_write_reg(0x45, 0x0000); /* 2nd screen driving position (start) */
194 lcd_write_reg(0x46, 0xEF00); /* horizontal window address */
195 lcd_write_reg(0x47, 0x013F); /* vertical window address (end) */
196 lcd_write_reg(0x48, 0x0000); /* vertical window address (start) */
198 lcd_write_reg(0x07, 0x0015); /* display control */
199 lcd_delay(500000);
200 lcd_write_reg(0x07, 0x0017); /* display control */
202 lcd_write_reg(0x20, 0x0000); /* RAM address set (low part) */
203 lcd_write_reg(0x21, 0x0000); /* RAM address set (high part) */
204 lcd_write_reg(0x22, 0x0000); /* write data to GRAM */
207 /* lcd init configuration for lcd type 2 */
208 static void lcd_init2(void)
210 lcd_write_reg(0x07, 0x0000);
211 lcd_write_reg(0x12, 0x0000);
212 lcd_delay(166670);
214 lcd_write_reg(0x11, 0x000C);
215 lcd_write_reg(0x12, 0x0A1C);
216 lcd_write_reg(0x13, 0x0022);
217 lcd_write_reg(0x14, 0x0000);
219 lcd_write_reg(0x10, 0x7404);
220 lcd_write_reg(0x11, 0x0738);
221 lcd_write_reg(0x10, 0x7404);
222 lcd_delay(833350);
224 lcd_write_reg(0x07, 0x0009);
225 lcd_write_reg(0x12, 0x065C);
226 lcd_delay(3333400);
228 lcd_write_reg(0x01, 0xE127);
229 lcd_write_reg(0x02, 0x0300);
230 lcd_write_reg(0x03, 0x1100);
231 lcd_write_reg(0x08, 0x0008);
232 lcd_write_reg(0x0B, 0x0000);
233 lcd_write_reg(0x0C, 0x0000);
234 lcd_write_reg(0x0D, 0x0007);
235 lcd_write_reg(0x15, 0x0003);
236 lcd_write_reg(0x16, 0x0014);
237 lcd_write_reg(0x17, 0x0000);
239 lcd_write_reg(0x30, 0x0503); /* gamma? */
240 lcd_write_reg(0x31, 0x0303);
241 lcd_write_reg(0x32, 0x0305);
242 lcd_write_reg(0x33, 0x0202);
243 lcd_write_reg(0x34, 0x0204);
244 lcd_write_reg(0x35, 0x0404);
245 lcd_write_reg(0x36, 0x0402);
246 lcd_write_reg(0x37, 0x0202);
247 lcd_write_reg(0x38, 0x1000);
248 lcd_write_reg(0x39, 0x1000);
250 lcd_write_reg(0x07, 0x0009);
251 lcd_delay(666680);
253 lcd_write_reg(0x07, 0x0109);
254 lcd_delay(666680);
256 lcd_write_reg(0x07, 0x010B);
259 /* lcd enable for lcd type 1 */
260 static void lcd_enable1(bool on)
262 if (on) {
263 lcd_write_reg(0x00, 0x0001); /* start oscillation */
264 lcd_delay(166670);
265 lcd_write_reg(0x10, 0x0000); /* power control 1 */
266 lcd_delay(166670);
268 lcd_write_reg(0x11, 0x3304); /* power control 2 */
269 lcd_write_reg(0x14, 0x1300); /* power control 4 */
270 lcd_write_reg(0x10, 0x1A20); /* power control 1 */
271 lcd_write_reg(0x07, 0x0015); /* display control */
272 lcd_delay(500000);
274 lcd_write_reg(0x20, 0x0000); /* RAM address set (low part) */
275 lcd_write_reg(0x21, 0x0000); /* RAM address set (high part) */
276 lcd_write_reg(0x22, 0x0000); /* write data to GRAM */
278 else {
279 lcd_write_reg(0x07, 0x0016); /* display control */
280 lcd_delay(166670 * 4);
281 lcd_write_reg(0x07, 0x0004); /* display control */
282 lcd_delay(166670 * 4);
284 lcd_write_reg(0x10, 0x1E21); /* power control 1 */
285 lcd_delay(166670);
289 /* lcd enable for lcd type 2 */
290 static void lcd_enable2(bool on)
292 if (on) {
293 lcd_write_reg(0x10, 0x0400);
294 lcd_delay(666680);
296 lcd_write_reg(0x07, 0x0000);
297 lcd_write_reg(0x12, 0x0000);
298 lcd_delay(166670);
300 lcd_write_reg(0x11, 0x000C);
301 lcd_write_reg(0x12, 0x0A1C);
302 lcd_write_reg(0x13, 0x0022);
303 lcd_write_reg(0x14, 0x0000);
304 lcd_write_reg(0x10, 0x7404);
305 lcd_write_reg(0x11, 0x0738);
306 lcd_write_reg(0x10, 0x7404);
307 lcd_delay(833350);
309 lcd_write_reg(0x07, 0x0009);
310 lcd_write_reg(0x12, 0x065C);
311 lcd_delay(3333400);
313 lcd_write_reg(0x0B, 0x0000);
314 lcd_write_reg(0x07, 0x0009);
315 lcd_delay(666680);
317 lcd_write_reg(0x07, 0x0109);
318 lcd_delay(666680);
320 lcd_write_reg(0x07, 0x010B);
322 else {
323 lcd_write_reg(0x0B, 0x0109);
324 lcd_write_reg(0x07, 0x0009);
325 lcd_delay(666680);
327 lcd_write_reg(0x07, 0x0008);
328 lcd_delay(666680);
330 lcd_write_reg(0x10, 0x0400);
331 lcd_write_reg(0x10, 0x0401);
332 lcd_delay(166670);
336 /* turn both the lcd controller and the lcd itself on or off */
337 void lcd_enable(bool on)
339 if (on) {
340 /* enable controller clock */
341 PWRCON &= ~(1 << 18);
343 lcd_controller_power(true);
344 lcd_delay(166670);
347 /* call type specific power function */
348 if (lcd_type == 1) {
349 lcd_enable1(on);
351 else {
352 lcd_enable2(on);
355 if (!on) {
356 lcd_controller_power(false);
358 /* disable controller clock */
359 PWRCON |= (1 << 18);
362 lcd_is_active = on;
365 bool lcd_active(void)
367 return lcd_is_active;
370 /* initialise the lcd controller inside the s5l8700 */
371 static void lcd_controller_init(void)
373 PWRCON &= ~(1 << 18);
375 LCDCON1 = (0 << 28) | /* BURSTLEN */
376 (0 << 19) | /* DIVEN */
377 (12 << 13) | /* CLKVAL */
378 (1 << 12) | /* CLKDIR, 1=divided clock */
379 (0 << 11) | /* CLKSEL, 0=HCLK, 1=PLL */
380 (5 << 6) | /* BPPMODEF, 5=rgb565, 7=raw24 */
381 (5 << 2) | /* BPPMODEB, 5=rgb565, 7=raw24 */
382 (0 << 0); /* ENVID */
383 LCDCON2 = (2 << 9) | /* PALFRM, 2=rgb565 palette */
384 (1 << 7) | /* IVCLK */
385 (1 << 6) | /* IHSYNC */
386 (1 << 5) | /* IVSYNC */
387 (1 << 3); /* IVDEN */
388 LCDTCON1 = (lcd_type == 1) ? 0x070103 : 0x030303;
389 LCDTCON2 = (lcd_type == 1) ? 0x070103 : 0x030703;
390 LCDTCON3 = ((LCD_HEIGHT - 1) << 11) | (LCD_WIDTH - 1);
391 LCDOSD1 = 0;
392 LCDOSD2 = 0;
393 LCDOSD3 = 0;
395 LCDB1SADDR1 = 0;
396 LCDB2SADDR1 = 0;
397 LCDF1SADDR1 = 0;
398 LCDF2SADDR1 = 0;
399 LCDB1SADDR2 = 0;
400 LCDB2SADDR2 = 0;
401 LCDF1SADDR2 = 0;
402 LCDF2SADDR2 = 0;
403 LCDB1SADDR3 = 0;
404 LCDB2SADDR3 = 0;
405 LCDF1SADDR3 = 0;
406 LCDF2SADDR3 = 0;
408 LCDKEYCON = 0;
409 LCDCOLVAL = 0;
410 LCDBGCON = 0;
411 LCDFGCON = 0;
412 LCDDITHMODE = 0;
414 LCDINTCON = 0;
417 void lcd_init_device(void)
419 unsigned int lcd_id;
420 uint32_t fb, fb_end, window;
422 /* configure LCD SPI pins */
423 lcd_spi_init();
425 /* identify display through SPI */
426 lcd_id = lcd_read_reg(0);
427 lcd_type = (lcd_id == LCD_TYPE1_ID) ? 1 : 2;
429 /* display specific init sequence */
430 if (lcd_type == 1) {
431 lcd_init1();
433 else {
434 lcd_init2();
437 /* init LCD controller */
438 lcd_controller_init();
440 /* set framebuffer addresses */
441 fb = (uint32_t) &lcd_framebuffer[0][0];
442 fb_end = (uint32_t) &lcd_framebuffer[LCD_HEIGHT][0];
443 window = 2 * LCD_WIDTH;
445 LCDB1SADDR1 = fb;
446 LCDB2SADDR1 = fb;
447 LCDF1SADDR1 = fb;
448 LCDF2SADDR1 = fb;
450 LCDB1SADDR2 = fb_end;
451 LCDB2SADDR2 = fb_end;
452 LCDF1SADDR2 = fb_end;
453 LCDF2SADDR2 = fb_end;
455 LCDB1SADDR3 = window;
456 LCDB2SADDR3 = window;
457 LCDF1SADDR3 = window;
458 LCDF2SADDR3 = window;
460 lcd_enable(true);
462 /* configure LCD pins */
463 PCON_ASRAM = 1;
466 void lcd_update_rect(int x, int y, int width, int height)
468 /* not implemented yet, LCD controller accesses framebuffer directly */
469 (void) x;
470 (void) y;
471 (void) width;
472 (void) height;
475 void lcd_update(void)
477 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
480 void lcd_blit_yuv(unsigned char * const src[3],
481 int src_x, int src_y, int stride,
482 int x, int y, int width, int height)
484 (void)src;
485 (void)src_x;
486 (void)src_y;
487 (void)stride;
488 (void)x;
489 (void)y;
490 (void)width;
491 (void)height;
492 /* TODO: not implemented yet */