summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBertrik Sikken <bertrik@sikken.nl>2009-08-24 17:37:53 +0000
committerBertrik Sikken <bertrik@sikken.nl>2009-08-24 17:37:53 +0000
commit400cd026f3267cff8b67d0bf0ab5f4645732cc5e (patch)
treeb1422baebf25c072d5308bba44995ba87ce62eb7
parent1747a33fcc9ceb8b78012d662086aeac51490812 (diff)
downloadrockbox-400cd026f3267cff8b67d0bf0ab5f4645732cc5e.tar.gz
rockbox-400cd026f3267cff8b67d0bf0ab5f4645732cc5e.zip
Meizu M6SP: initial LCD driver (compiles but is untested)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22500 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c514
1 files changed, 413 insertions, 101 deletions
diff --git a/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c b/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c
index 1affab3b01..b6330406f2 100644
--- a/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c
+++ b/firmware/target/arm/s5l8700/meizu-m6sp/lcd-m6sp.c
@@ -7,7 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2002 by Alan Korr 10 * Copyright (C) 2009 Bertrik Sikken
11 * 11 *
12 * This program is free software; you can redistribute it and/or 12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 13 * modify it under the terms of the GNU General Public License
@@ -18,118 +18,430 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "config.h" 21
22#include <inttypes.h>
23
24#include "config.h"
25#include "s5l8700.h"
26#include "lcd.h"
27
28/* LCD driver for the Meizu M6 SP using the CLCD controller in the S5L8700
22 29
23#include "hwcompat.h" 30 The Meizu M6 SP can have two different LCDs, the S6D0139 and another
24#include "kernel.h" 31 (yet unknown) type, the exact type is detected at run-time.
25#include "lcd.h"
26#include "system.h"
27#include "cpu.h"
28 32
29/*** definitions ***/ 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.
37
38 */
30 39
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 */
45
46#define LCD_TYPE1_ID 0x139 /* id for LCD type S6D0139 */
47
48static int lcd_type = 0;
31 49
32/** globals **/ 50/* local frame buffer, keeps pixels in 32-bit words in format 0x00RRGGBB */
33 51static uint32_t lcd_local_fb[LCD_HEIGHT][LCD_WIDTH];
34static int xoffset; /* needed for flip */ 52
35 53
36/*** hardware configuration ***/ 54/* simple and crude delay */
37 55static void lcd_delay(int count)
38int lcd_default_contrast(void) 56{
39{ 57 volatile int i;
40 return 0x1f; 58 for (i = 0; i < count; i++);
41} 59}
42 60
43void lcd_set_contrast(int val) 61/* write 'data_out' of length 'bits' over SPI and return received data */
44{ 62static unsigned int lcd_spi_transfer(int bits, unsigned int data_out)
45} 63{
46 64 unsigned int data_in = 0;
47void lcd_set_invert_display(bool yesno) 65
48{ 66 /* SSn active */
49} 67 PDAT7 &= ~LCD_SPI_SSn;
50 68 lcd_delay(10);
51/* turn the display upside down (call lcd_update() afterwards) */ 69
52void lcd_set_flip(bool yesno) 70 /* send and receive data */
53{ 71 while (bits--) {
54 /* TODO: flip mode isn't working. The commands in the else part of 72 /* CLK low */
55 this function are how the original firmware inits the LCD */ 73 PDAT3 &= ~LCD_SPI_SCLK;
56 74
57 if (yesno) 75 /* set MOSI */
58 { 76 if (data_out & (1 << bits)) {
59 xoffset = 132 - LCD_WIDTH; /* 132 colums minus the 128 we have */ 77 PDAT3 |= LCD_SPI_MOSI;
60 } 78 }
61 else 79 else {
62 { 80 PDAT3 &= ~LCD_SPI_MOSI;
63 xoffset = 0; 81 }
64 } 82
65} 83 /* delay */
66 84 lcd_delay(10);
67 85
68/* LCD init */ 86 /* sample MISO */
69void lcd_init_device(void) 87 data_in <<= 1;
88 if (PDAT3 & LCD_SPI_MISO) {
89 data_in |= 1;
90 }
91
92 /* CLK high */
93 PDAT3 |= LCD_SPI_SCLK;
94
95 /* delay */
96 lcd_delay(10);
97 }
98
99 /* SSn inactive */
100 PDAT7 |= LCD_SPI_SSn;
101 lcd_delay(10);
102
103 return data_in;
104}
105
106/* initialize the lcd SPI port interface */
107static void lcd_spi_init(void)
108{
109 /* configure SSn (P7.1) as output */
110 PCON7 = (PCON7 & ~0x000000F0) | 0x00000010;
111
112 /* configure MISO (P3.2) input, MOSI (P3.6) output, SCLK (P3.7) output */
113 PCON3 = (PCON3 & ~0xFF000F00) | 0x11000000;
114
115 /* set all outputs high */
116 PDAT7 |= LCD_SPI_SSn;
117 PDAT3 |= (LCD_SPI_MOSI | LCD_SPI_SCLK);
118}
119
120/* read LCD identification word over SPI */
121static unsigned int lcd_read_reg(unsigned reg)
122{
123 unsigned int data;
124
125 lcd_spi_transfer(24, (0x74 << 16) | reg); //0111.0100
126 data = lcd_spi_transfer(24, (0x77 << 16)); //0111.0111
127 return data & 0xFFFF;
128}
129
130/* write LCD register over SPI */
131static void lcd_write_reg(unsigned char reg, unsigned int data)
132{
133 lcd_spi_transfer(24, (0x74 << 16) | reg); //0111.0100
134 lcd_spi_transfer(24, (0x76 << 16) | data); //0111.0110
135}
136
137/* enable/disable clock signals towards the lcd */
138static void lcd_controller_power(bool on)
70{ 139{
71} 140 if (on) {
141 LCDCON1 |= 0x80003;
142 }
143 else {
144 LCDCON1 &= ~0x80003;
145 }
146}
147
148/* lcd init configuration for lcd type 1 */
149static void lcd_init1(void)
150{
151 lcd_write_reg(0x07, 0x0000); /* display control */
152 lcd_write_reg(0x13, 0x0000); /* power control 3 */
153 lcd_delay(166670);
154
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);
160
161 lcd_write_reg(0x13, 0x0060); /* power control 3 */
162 lcd_write_reg(0x13, 0x0070); /* power control 3 */
163 lcd_delay(3333400);
164
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) */
190
191 lcd_write_reg(0x07, 0x0015); /* display control */
192 lcd_delay(500000);
193 lcd_write_reg(0x07, 0x0017); /* display control */
194
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 */
198}
199
200/* lcd init configuration for lcd type 2 */
201static void lcd_init2(void)
202{
203 lcd_write_reg(0x07, 0x0000);
204 lcd_write_reg(0x12, 0x0000);
205 lcd_delay(166670);
206
207 lcd_write_reg(0x11, 0x000C);
208 lcd_write_reg(0x12, 0x0A1C);
209 lcd_write_reg(0x13, 0x0022);
210 lcd_write_reg(0x14, 0x0000);
211
212 lcd_write_reg(0x10, 0x7404);
213 lcd_write_reg(0x11, 0x0738);
214 lcd_write_reg(0x10, 0x7404);
215 lcd_delay(833350);
216
217 lcd_write_reg(0x07, 0x0009);
218 lcd_write_reg(0x12, 0x065C);
219 lcd_delay(3333400);
220
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);
229
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);
242
243 lcd_write_reg(0x07, 0x0009);
244 lcd_delay(666680);
245
246 lcd_write_reg(0x07, 0x0109);
247 lcd_delay(666680);
248
249 lcd_write_reg(0x07, 0x010B);
250}
251
252/* lcd enable for lcd type 1 */
253static void lcd_enable1(bool on)
254{
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);
260
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);
266
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 */
270 }
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);
276
277 lcd_write_reg(0x10, 0x1E21); /* power control 1 */
278 lcd_delay(166670);
279 }
280}
281
282/* lcd enable for lcd type 2 */
283static void lcd_enable2(bool on)
284{
285 if (on) {
286 lcd_write_reg(0x10, 0x0400);
287 lcd_delay(666680);
288
289 lcd_write_reg(0x07, 0x0000);
290 lcd_write_reg(0x12, 0x0000);
291 lcd_delay(166670);
292
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);
299
300 lcd_write_reg(0x07, 0x0009);
301 lcd_write_reg(0x12, 0x065C);
302 lcd_delay(3333400);
303
304 lcd_write_reg(0x0B, 0x0000);
305 lcd_write_reg(0x07, 0x0009);
306 lcd_delay(666680);
307
308 lcd_write_reg(0x07, 0x0109);
309 lcd_delay(666680);
310
311 lcd_write_reg(0x07, 0x010B);
312 }
313 else {
314 lcd_write_reg(0x0B, 0x0000);
315 lcd_write_reg(0x07, 0x0009);
316 lcd_delay(666680);
317
318 lcd_write_reg(0x07, 0x0008);
319 lcd_delay(666680);
320
321 lcd_write_reg(0x10, 0x0400);
322 lcd_write_reg(0x10, 0x0401);
323 lcd_delay(166670);
324 }
325}
326
327/* turn both the lcd controller and the lcd itself on or off */
328void lcd_enable(bool on)
329{
330 if (on) {
331 /* enable controller clock */
332 PWRCON &= ~(1 << 18);
333
334 lcd_controller_power(true);
335 lcd_delay(166670);
336 }
337
338 /* call type specific power function */
339 if (lcd_type == 1) {
340 lcd_enable1(on);
341 }
342 else {
343 lcd_enable2(on);
344 }
345
346 if (!on) {
347 lcd_controller_power(false);
348
349 /* disable controller clock */
350 PWRCON |= (1 << 18);
351 }
352}
72 353
73/*** Update functions ***/ 354/* initialise the lcd controller inside the s5l8700 */
355static void lcd_controller_init(void)
356{
357 PWRCON &= ~(1 << 18);
358
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;
384
385 LCDINTCON = 0;
386}
387
388void lcd_init_device(void)
389{
390 unsigned int lcd_id;
391
392 /* configure LCD SPI pins */
393 lcd_spi_init();
394
395 /* identify display through SPI */
396 lcd_id = lcd_read_reg(0);
397 lcd_type = (lcd_id == LCD_TYPE1_ID) ? 1 : 2;
398
399 /* configure LCD pins */
400 PCON_ASRAM = 1;
401
402 /* init LCD controller */
403 lcd_controller_init();
404
405 /* display specific init sequence */
406 if (lcd_type == 1) {
407 lcd_init1();
408 }
409 else {
410 lcd_init2();
411 }
412
413 /* set active background buffer */
414 LCDCON1 &= ~(1 << 21); /* clear BDBCON */
415
416 /* set background buffer address */
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}
74 422
75/* Performance function that works with an external buffer 423void lcd_update_rect(int x, int y, int width, int height)
76 note that by and bheight are in 8-pixel units! */
77void lcd_blit_mono(const unsigned char *data, int x, int by, int width,
78 int bheight, int stride)
79{ 424{
80 /* Copy display bitmap to hardware */ 425 fb_data *src;
81 while (bheight--) 426 uint32_t *dst;
82 { 427 fb_data pixel;
428 int h, w;
429
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++;
83 } 440 }
84} 441}
85 442
86
87/* Performance function that works with an external buffer
88 note that by and bheight are in 8-pixel units! */
89void lcd_blit_grey_phase_blit(unsigned char *values, unsigned char *phases,
90 int x, int by, int width, int bheight, int stride)
91{
92 (void)values;
93 (void)phases;
94 (void)x;
95 (void)by;
96 (void)width;
97 (void)bheight;
98 (void)stride;
99}
100
101/* Update the display.
102 This must be called after all other LCD functions that change the display. */
103void lcd_update(void) ICODE_ATTR;
104void lcd_update(void) 443void lcd_update(void)
105{ 444{
106 int y; 445 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
107
108 /* Copy display bitmap to hardware */
109 for (y = 0; y < LCD_FBHEIGHT; y++)
110 {
111 }
112} 446}
113 447
114/* Update a fraction of the display. */
115void lcd_update_rect(int, int, int, int) ICODE_ATTR;
116void lcd_update_rect(int x, int y, int width, int height)
117{
118 int ymax;
119
120 /* The Y coordinates have to work on even 8 pixel rows */
121 ymax = (y + height-1) >> 3;
122 y >>= 3;
123
124 if(x + width > LCD_WIDTH)
125 width = LCD_WIDTH - x;
126 if (width <= 0)
127 return; /* nothing left to do, 0 is harmful to lcd_write_data() */
128 if(ymax >= LCD_FBHEIGHT)
129 ymax = LCD_FBHEIGHT-1;
130
131 /* Copy specified rectange bitmap to hardware */
132 for (; y <= ymax; y++)
133 {
134 }
135}