diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c | 157 |
1 files changed, 90 insertions, 67 deletions
diff --git a/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c b/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c index b6330406f2..9a24480bfa 100644 --- a/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c +++ b/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c | |||
@@ -31,26 +31,32 @@ | |||
31 | (yet unknown) type, the exact type is detected at run-time. | 31 | (yet unknown) type, the exact type is detected at run-time. |
32 | 32 | ||
33 | Open issues: | 33 | Open issues: |
34 | * untested on actual hardware | 34 | * LCD is currently in portrait mode instead of landscape mode |
35 | * use 16-bit pixel format, currently pixels are converted to a 32-bit pixel | 35 | * This LCD driver accesses the Rockbox framebuffer directly, so any changes |
36 | format in lcd_update_rect, that is not natively supported yet in Rockbox. | 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 | ||
37 | 40 | ||
38 | */ | 41 | */ |
39 | 42 | ||
40 | /* LCD SPI connections */ | 43 | /* LCD SPI connections */ |
41 | #define LCD_SPI_SSn (1<<1) /* on PDAT7 */ | 44 | #define LCD_SPI_SSn (1<<1) /* on PDAT7 */ |
42 | #define LCD_SPI_MISO (1<<2) /* on PDAT3 */ | 45 | #define LCD_SPI_MISO (1<<2) /* on PDAT3 */ |
43 | #define LCD_SPI_MOSI (1<<6) /* on PDAT3 */ | 46 | #define LCD_SPI_MOSI (1<<6) /* on PDAT3 */ |
44 | #define LCD_SPI_SCLK (1<<7) /* on PDAT3 */ | 47 | #define LCD_SPI_SCLK (1<<7) /* on PDAT3 */ |
45 | 48 | ||
46 | #define LCD_TYPE1_ID 0x139 /* id for LCD type S6D0139 */ | 49 | /* LCD SPI communication definitions */ |
47 | 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) | ||
55 | |||
56 | #define LCD_TYPE1_ID 0x139 /* id for LCD type S6D0139 */ | ||
57 | |||
48 | static int lcd_type = 0; | 58 | static int lcd_type = 0; |
49 | 59 | ||
50 | /* local frame buffer, keeps pixels in 32-bit words in format 0x00RRGGBB */ | ||
51 | static uint32_t lcd_local_fb[LCD_HEIGHT][LCD_WIDTH]; | ||
52 | |||
53 | |||
54 | /* simple and crude delay */ | 60 | /* simple and crude delay */ |
55 | static void lcd_delay(int count) | 61 | static void lcd_delay(int count) |
56 | { | 62 | { |
@@ -111,7 +117,7 @@ static void lcd_spi_init(void) | |||
111 | 117 | ||
112 | /* configure MISO (P3.2) input, MOSI (P3.6) output, SCLK (P3.7) output */ | 118 | /* configure MISO (P3.2) input, MOSI (P3.6) output, SCLK (P3.7) output */ |
113 | PCON3 = (PCON3 & ~0xFF000F00) | 0x11000000; | 119 | PCON3 = (PCON3 & ~0xFF000F00) | 0x11000000; |
114 | 120 | ||
115 | /* set all outputs high */ | 121 | /* set all outputs high */ |
116 | PDAT7 |= LCD_SPI_SSn; | 122 | PDAT7 |= LCD_SPI_SSn; |
117 | PDAT3 |= (LCD_SPI_MOSI | LCD_SPI_SCLK); | 123 | PDAT3 |= (LCD_SPI_MOSI | LCD_SPI_SCLK); |
@@ -121,17 +127,17 @@ static void lcd_spi_init(void) | |||
121 | static unsigned int lcd_read_reg(unsigned reg) | 127 | static unsigned int lcd_read_reg(unsigned reg) |
122 | { | 128 | { |
123 | unsigned int data; | 129 | unsigned int data; |
124 | 130 | ||
125 | lcd_spi_transfer(24, (0x74 << 16) | reg); //0111.0100 | 131 | lcd_spi_transfer(24, (LCD_SPI_INDEX_WRITE << 16) | reg); |
126 | data = lcd_spi_transfer(24, (0x77 << 16)); //0111.0111 | 132 | data = lcd_spi_transfer(24, (LCD_SPI_DATA_READ << 16)); |
127 | return data & 0xFFFF; | 133 | return data & 0xFFFF; |
128 | } | 134 | } |
129 | 135 | ||
130 | /* write LCD register over SPI */ | 136 | /* write LCD register over SPI */ |
131 | static void lcd_write_reg(unsigned char reg, unsigned int data) | 137 | static void lcd_write_reg(unsigned char reg, unsigned int data) |
132 | { | 138 | { |
133 | lcd_spi_transfer(24, (0x74 << 16) | reg); //0111.0100 | 139 | lcd_spi_transfer(24, (LCD_SPI_INDEX_WRITE << 16) | reg); |
134 | lcd_spi_transfer(24, (0x76 << 16) | data); //0111.0110 | 140 | lcd_spi_transfer(24, (LCD_SPI_DATA_WRITE << 16) | data); |
135 | } | 141 | } |
136 | 142 | ||
137 | /* enable/disable clock signals towards the lcd */ | 143 | /* enable/disable clock signals towards the lcd */ |
@@ -226,10 +232,10 @@ static void lcd_init2(void) | |||
226 | lcd_write_reg(0x0C, 0x0000); | 232 | lcd_write_reg(0x0C, 0x0000); |
227 | lcd_write_reg(0x0D, 0x0007); | 233 | lcd_write_reg(0x0D, 0x0007); |
228 | lcd_write_reg(0x15, 0x0003); | 234 | lcd_write_reg(0x15, 0x0003); |
229 | |||
230 | lcd_write_reg(0x16, 0x0014); | 235 | lcd_write_reg(0x16, 0x0014); |
231 | lcd_write_reg(0x17, 0x0000); | 236 | lcd_write_reg(0x17, 0x0000); |
232 | lcd_write_reg(0x30, 0x0503); | 237 | |
238 | lcd_write_reg(0x30, 0x0503); /* gamma? */ | ||
233 | lcd_write_reg(0x31, 0x0303); | 239 | lcd_write_reg(0x31, 0x0303); |
234 | lcd_write_reg(0x32, 0x0305); | 240 | lcd_write_reg(0x32, 0x0305); |
235 | lcd_write_reg(0x33, 0x0202); | 241 | lcd_write_reg(0x33, 0x0202); |
@@ -295,6 +301,8 @@ static void lcd_enable2(bool on) | |||
295 | lcd_write_reg(0x13, 0x0022); | 301 | lcd_write_reg(0x13, 0x0022); |
296 | lcd_write_reg(0x14, 0x0000); | 302 | lcd_write_reg(0x14, 0x0000); |
297 | lcd_write_reg(0x10, 0x7404); | 303 | lcd_write_reg(0x10, 0x7404); |
304 | lcd_write_reg(0x11, 0x0738); | ||
305 | lcd_write_reg(0x10, 0x7404); | ||
298 | lcd_delay(833350); | 306 | lcd_delay(833350); |
299 | 307 | ||
300 | lcd_write_reg(0x07, 0x0009); | 308 | lcd_write_reg(0x07, 0x0009); |
@@ -311,7 +319,7 @@ static void lcd_enable2(bool on) | |||
311 | lcd_write_reg(0x07, 0x010B); | 319 | lcd_write_reg(0x07, 0x010B); |
312 | } | 320 | } |
313 | else { | 321 | else { |
314 | lcd_write_reg(0x0B, 0x0000); | 322 | lcd_write_reg(0x0B, 0x0109); |
315 | lcd_write_reg(0x07, 0x0009); | 323 | lcd_write_reg(0x07, 0x0009); |
316 | lcd_delay(666680); | 324 | lcd_delay(666680); |
317 | 325 | ||
@@ -326,7 +334,7 @@ static void lcd_enable2(bool on) | |||
326 | 334 | ||
327 | /* turn both the lcd controller and the lcd itself on or off */ | 335 | /* turn both the lcd controller and the lcd itself on or off */ |
328 | void lcd_enable(bool on) | 336 | void lcd_enable(bool on) |
329 | { | 337 | { |
330 | if (on) { | 338 | if (on) { |
331 | /* enable controller clock */ | 339 | /* enable controller clock */ |
332 | PWRCON &= ~(1 << 18); | 340 | PWRCON &= ~(1 << 18); |
@@ -354,16 +362,28 @@ void lcd_enable(bool on) | |||
354 | /* initialise the lcd controller inside the s5l8700 */ | 362 | /* initialise the lcd controller inside the s5l8700 */ |
355 | static void lcd_controller_init(void) | 363 | static void lcd_controller_init(void) |
356 | { | 364 | { |
357 | PWRCON &= ~(1 << 18); | 365 | PWRCON &= ~(1 << 18); |
358 | 366 | ||
359 | LCDCON1 = 0x991DC; | 367 | LCDCON1 = (0 << 28) | /* BURSTLEN */ |
360 | LCDCON2 = 0xE8; | 368 | (0 << 19) | /* DIVEN */ |
361 | LCDTCON1 = (lcd_type == 1) ? 0x70103 : 0x30303; | 369 | (12 << 13) | /* CLKVAL */ |
362 | LCDTCON2 = (lcd_type == 1) ? 0x70103 : 0x30703; | 370 | (1 << 12) | /* CLKDIR, 1=divided clock */ |
363 | LCDTCON3 = 0x9F8EF; | 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); | ||
364 | LCDOSD1 = 0; | 383 | LCDOSD1 = 0; |
365 | LCDOSD2 = 0; | 384 | LCDOSD2 = 0; |
366 | LCDOSD3 = 0; | 385 | LCDOSD3 = 0; |
386 | |||
367 | LCDB1SADDR1 = 0; | 387 | LCDB1SADDR1 = 0; |
368 | LCDB2SADDR1 = 0; | 388 | LCDB2SADDR1 = 0; |
369 | LCDF1SADDR1 = 0; | 389 | LCDF1SADDR1 = 0; |
@@ -376,6 +396,7 @@ static void lcd_controller_init(void) | |||
376 | LCDB2SADDR3 = 0; | 396 | LCDB2SADDR3 = 0; |
377 | LCDF1SADDR3 = 0; | 397 | LCDF1SADDR3 = 0; |
378 | LCDF2SADDR3 = 0; | 398 | LCDF2SADDR3 = 0; |
399 | |||
379 | LCDKEYCON = 0; | 400 | LCDKEYCON = 0; |
380 | LCDCOLVAL = 0; | 401 | LCDCOLVAL = 0; |
381 | LCDBGCON = 0; | 402 | LCDBGCON = 0; |
@@ -387,21 +408,16 @@ static void lcd_controller_init(void) | |||
387 | 408 | ||
388 | void lcd_init_device(void) | 409 | void lcd_init_device(void) |
389 | { | 410 | { |
390 | unsigned int lcd_id; | 411 | unsigned int lcd_id; |
391 | 412 | uint32_t fb, fb_end, window; | |
413 | |||
392 | /* configure LCD SPI pins */ | 414 | /* configure LCD SPI pins */ |
393 | lcd_spi_init(); | 415 | lcd_spi_init(); |
394 | 416 | ||
395 | /* identify display through SPI */ | 417 | /* identify display through SPI */ |
396 | lcd_id = lcd_read_reg(0); | 418 | lcd_id = lcd_read_reg(0); |
397 | lcd_type = (lcd_id == LCD_TYPE1_ID) ? 1 : 2; | 419 | lcd_type = (lcd_id == LCD_TYPE1_ID) ? 1 : 2; |
398 | |||
399 | /* configure LCD pins */ | ||
400 | PCON_ASRAM = 1; | ||
401 | 420 | ||
402 | /* init LCD controller */ | ||
403 | lcd_controller_init(); | ||
404 | |||
405 | /* display specific init sequence */ | 421 | /* display specific init sequence */ |
406 | if (lcd_type == 1) { | 422 | if (lcd_type == 1) { |
407 | lcd_init1(); | 423 | lcd_init1(); |
@@ -409,35 +425,42 @@ void lcd_init_device(void) | |||
409 | else { | 425 | else { |
410 | lcd_init2(); | 426 | lcd_init2(); |
411 | } | 427 | } |
428 | |||
429 | /* init LCD controller */ | ||
430 | lcd_controller_init(); | ||
431 | |||
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; | ||
436 | |||
437 | LCDB1SADDR1 = fb; | ||
438 | LCDB2SADDR1 = fb; | ||
439 | LCDF1SADDR1 = fb; | ||
440 | LCDF2SADDR1 = fb; | ||
441 | |||
442 | LCDB1SADDR2 = fb_end; | ||
443 | LCDB2SADDR2 = fb_end; | ||
444 | LCDF1SADDR2 = fb_end; LCDF2SADDR2 = fb_end; | ||
445 | |||
446 | LCDB1SADDR3 = window; | ||
447 | LCDB2SADDR3 = window; | ||
448 | LCDF1SADDR3 = window; | ||
449 | LCDF2SADDR3 = window; | ||
412 | 450 | ||
413 | /* set active background buffer */ | 451 | lcd_enable(true); |
414 | LCDCON1 &= ~(1 << 21); /* clear BDBCON */ | 452 | |
415 | 453 | /* configure LCD pins */ | |
416 | /* set background buffer address */ | 454 | PCON_ASRAM = 1; |
417 | LCDB1SADDR1 = (uint32_t) &lcd_local_fb[0][0]; | ||
418 | LCDB1SADDR2 = (uint32_t) &lcd_local_fb[LCD_HEIGHT][0]; | ||
419 | |||
420 | lcd_enable(true); | ||
421 | } | 455 | } |
422 | 456 | ||
423 | void lcd_update_rect(int x, int y, int width, int height) | 457 | void lcd_update_rect(int x, int y, int width, int height) |
424 | { | 458 | { |
425 | fb_data *src; | 459 | /* not implemented yet, LCD controller accesses framebuffer directly */ |
426 | uint32_t *dst; | 460 | (void) x; |
427 | fb_data pixel; | 461 | (void) y; |
428 | int h, w; | 462 | (void) width; |
429 | 463 | (void) height; | |
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); | ||
438 | } | ||
439 | y++; | ||
440 | } | ||
441 | } | 464 | } |
442 | 465 | ||
443 | void lcd_update(void) | 466 | void lcd_update(void) |