1 //==========================================================================
5 // Cirrus EDB7xxx eval board LCD support code
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
44 // Contributors: gthomas
46 // Description: Functions to drive LCD display
47 //####DESCRIPTIONEND####
49 // 8x8 Font - from Helios
51 #define FIRST_CHAR 0x20
52 #define LAST_CHAR 0x7E
55 #define CURSOR_ON 0x5F
56 #define CURSOR_OFF 0x20
57 static char font_table[LAST_CHAR-FIRST_CHAR+1][8] =
59 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* */
60 { 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00 }, /* ! */
61 { 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* " */
62 { 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00 }, /* # */
63 { 0x30, 0xFC, 0x16, 0x7C, 0xD0, 0x7E, 0x18, 0x00 }, /* $ */
64 { 0x06, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x60, 0x00 }, /* % */
65 { 0x1C, 0x36, 0x36, 0x1C, 0xB6, 0x66, 0xDC, 0x00 }, /* & */
66 { 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* ' */
67 { 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00 }, /* ( */
68 { 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00 }, /* ) */
69 { 0x00, 0x18, 0x7E, 0x3C, 0x7E, 0x18, 0x00, 0x00 }, /* * */
70 { 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00 }, /* + */
71 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C }, /* , */
72 { 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00 }, /* - */
73 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00 }, /* . */
74 { 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00 }, /* / */
75 { 0x3C, 0x66, 0x76, 0x7E, 0x6E, 0x66, 0x3C, 0x00 }, /* 0 */
76 { 0x18, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00 }, /* 1 */
77 { 0x3C, 0x66, 0x60, 0x30, 0x18, 0x0C, 0x7E, 0x00 }, /* 2 */
78 { 0x3C, 0x66, 0x60, 0x38, 0x60, 0x66, 0x3C, 0x00 }, /* 3 */
79 { 0x30, 0x38, 0x3C, 0x36, 0x7E, 0x30, 0x30, 0x00 }, /* 4 */
80 { 0x7E, 0x06, 0x3E, 0x60, 0x60, 0x66, 0x3C, 0x00 }, /* 5 */
81 { 0x38, 0x0C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00 }, /* 6 */
82 { 0x7E, 0x60, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00 }, /* 7 */
83 { 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00 }, /* 8 */
84 { 0x3C, 0x66, 0x66, 0x7C, 0x60, 0x30, 0x1C, 0x00 }, /* 9 */
85 { 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00 }, /* : */
86 { 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x0C }, /* ; */
87 { 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00 }, /* < */
88 { 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00 }, /* = */
89 { 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00 }, /* > */
90 { 0x3C, 0x66, 0x30, 0x18, 0x18, 0x00, 0x18, 0x00 }, /* ? */
91 { 0x3C, 0x66, 0x76, 0x56, 0x76, 0x06, 0x3C, 0x00 }, /* @ */
92 { 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00 }, /* A */
93 { 0x3E, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00 }, /* B */
94 { 0x3C, 0x66, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00 }, /* C */
95 { 0x1E, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1E, 0x00 }, /* D */
96 { 0x7E, 0x06, 0x06, 0x3E, 0x06, 0x06, 0x7E, 0x00 }, /* E */
97 { 0x7E, 0x06, 0x06, 0x3E, 0x06, 0x06, 0x06, 0x00 }, /* F */
98 { 0x3C, 0x66, 0x06, 0x76, 0x66, 0x66, 0x3C, 0x00 }, /* G */
99 { 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00 }, /* H */
100 { 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00 }, /* I */
101 { 0x7C, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00 }, /* J */
102 { 0x66, 0x36, 0x1E, 0x0E, 0x1E, 0x36, 0x66, 0x00 }, /* K */
103 { 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00 }, /* L */
104 { 0xC6, 0xEE, 0xFE, 0xD6, 0xD6, 0xC6, 0xC6, 0x00 }, /* M */
105 { 0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00 }, /* N */
106 { 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00 }, /* O */
107 { 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00 }, /* P */
108 { 0x3C, 0x66, 0x66, 0x66, 0x56, 0x36, 0x6C, 0x00 }, /* Q */
109 { 0x3E, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x66, 0x00 }, /* R */
110 { 0x3C, 0x66, 0x06, 0x3C, 0x60, 0x66, 0x3C, 0x00 }, /* S */
111 { 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00 }, /* T */
112 { 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00 }, /* U */
113 { 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00 }, /* V */
114 { 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00 }, /* W */
115 { 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00 }, /* X */
116 { 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00 }, /* Y */
117 { 0x7E, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00 }, /* Z */
118 { 0x3E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3E, 0x00 }, /* [ */
119 { 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00 }, /* \ */
120 { 0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7C, 0x00 }, /* ] */
121 { 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* ^ */
122 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }, /* _ */
123 { 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* ` */
124 { 0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00 }, /* a */
125 { 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00 }, /* b */
126 { 0x00, 0x00, 0x3C, 0x66, 0x06, 0x66, 0x3C, 0x00 }, /* c */
127 { 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00 }, /* d */
128 { 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00 }, /* e */
129 { 0x38, 0x0C, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00 }, /* f */
130 { 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x3C }, /* g */
131 { 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00 }, /* h */
132 { 0x18, 0x00, 0x1C, 0x18, 0x18, 0x18, 0x3C, 0x00 }, /* i */
133 { 0x18, 0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x0E }, /* j */
134 { 0x06, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x00 }, /* k */
135 { 0x1C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00 }, /* l */
136 { 0x00, 0x00, 0x6C, 0xFE, 0xD6, 0xD6, 0xC6, 0x00 }, /* m */
137 { 0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00 }, /* n */
138 { 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00 }, /* o */
139 { 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06 }, /* p */
140 { 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0xE0 }, /* q */
141 { 0x00, 0x00, 0x36, 0x6E, 0x06, 0x06, 0x06, 0x00 }, /* r */
142 { 0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00 }, /* s */
143 { 0x0C, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x38, 0x00 }, /* t */
144 { 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00 }, /* u */
145 { 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00 }, /* v */
146 { 0x00, 0x00, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00 }, /* w */
147 { 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00 }, /* x */
148 { 0x00, 0x00, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x3C }, /* y */
149 { 0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00 }, /* z */
150 { 0x30, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x30, 0x00 }, /* { */
151 { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00 }, /* | */
152 { 0x0C, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0C, 0x00 }, /* } */
153 { 0x8C, 0xD6, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00 } /* ~ */
158 #define LCD_WIDTH 640
159 #define LCD_HEIGHT 240
161 #define LCD_WIDTH 320
162 #define LCD_HEIGHT 240
164 // This can be 1 or 2
165 #define SCREEN_SCALE 2
166 #define NIBBLES_PER_PIXEL (1*SCREEN_SCALE)
167 #define PIXELS_PER_BYTE (2/NIBBLES_PER_PIXEL)
168 #define PIXEL_MASK ((1<<PIXELS_PER_BYTE)-1)
170 // Physical screen info
171 static int lcd_depth; // Should be 1, 2, or 4
172 static int lcd_width = LCD_WIDTH;
173 static int lcd_height = LCD_HEIGHT;
174 static cyg_uint8 *lcd_base = (cyg_uint8 *)0xC0000000;
176 // Virtual screen info
177 static int curX = 0; // Last used position
179 static int width = LCD_WIDTH / (FONT_WIDTH*NIBBLES_PER_PIXEL);
180 static int height = LCD_HEIGHT / (FONT_HEIGHT*SCREEN_SCALE);
181 static int fg = 0x0F;
182 static int bg = 0x00;
185 static void lcd_drawc(cyg_int8 c, int x, int y);
190 cyg_int32 ctl_word = 0;
194 *(volatile cyg_int32 *)PALLSW = 0xF0F0F0F0;
195 *(volatile cyg_int32 *)PALMSW = 0xF0F0F0F0;
199 *(volatile cyg_int32 *)PALLSW = 0xFA50FA50;
200 *(volatile cyg_int32 *)PALMSW = 0xFA50FA50;
201 ctl_word = LCDCON_GSEN;
204 *(volatile cyg_int32 *)PALLSW = 0x76543210;
205 *(volatile cyg_int32 *)PALMSW = 0xFEDCBA98;
206 ctl_word = LCDCON_GSEN | LCDCON_GSMD;
210 ctl_word |= ((lcd_width * lcd_height * lcd_depth) / 128 - 1) << LCDCON_BUFSIZ_S;
212 ctl_word |= ((lcd_width / 16) - 1) << LCDCON_LINE_LENGTH_S;
214 ctl_word |= ((526628 / (lcd_height * lcd_width)) - 1) << LCDCON_PIX_PRESCALE_S;
216 ctl_word |= 0 << LCDCON_AC_PRESCALE_S;
217 *(volatile cyg_int32 *)LCDCON = ctl_word;
218 diag_printf("Depth: %d, ctl: %x\n", depth, ctl_word);
221 #define LCD_DCDC 0x02
222 #define LCD_ENABLE 0x04
223 #define LCD_BACKLIGHT 0x08
224 #define LCD_INIT (LCD_DCDC|LCD_ENABLE|LCD_BACKLIGHT)
225 *(volatile cyg_uint8 *)PDDDR = 0x40; // 1's are inputs (backwards from A/B/E)
226 *(volatile cyg_uint8 *)PDDR = LCD_INIT; // Enable video + backlight + DC-DC converter
229 *(volatile cyg_uint8 *)PDDR = 0x20; // Enable video
230 *(volatile cyg_uint8 *)PEDDR = 0x0F; // Register E data direction
231 *(volatile cyg_uint8 *)PEDR |= 0x01; // Enable PE2
233 *(volatile cyg_uint32 *)PMPCON = 0x500; // Enable DC-to-DC pump #1
237 *(volatile cyg_uint8 *)FRBADDR = 0x0C; // Highest order nibble of LCD frame address
239 *(volatile cyg_uint32 *)SYSCON1 |= SYSCON1_LCDEN;
246 cyg_int8 *ptr = lcd_base;
248 for (i = 0; i < (lcd_width*lcd_height*lcd_depth)/8; i++) {
252 lcd_drawc(CURSOR_ON, curX, curY);
257 lcd_moveto(int X, int Y)
259 lcd_drawc(CURSOR_OFF, curX, curY);
261 if (X >= width) X = width-1;
264 if (Y >= height) Y = height-1;
266 lcd_drawc(CURSOR_ON, curX, curY);
269 // Render a character at position (X,Y) with current background/foreground
271 lcd_drawc(cyg_int8 c, int x, int y)
273 // Note: this only works for fonts which are a multiple of 8 bits wide!
274 cyg_uint8 *bufptr, bits;
278 bufptr = lcd_base + ((y * FONT_HEIGHT * (lcd_width*lcd_depth)) + (x * FONT_WIDTH)) / 8;
279 for (l = 0; l < FONT_HEIGHT; l++) {
280 *bufptr = font_table[c][l];
281 bufptr += (lcd_width*lcd_depth)/8;
285 diag_printf("Depth 2 not implemented\n");
288 bufptr = lcd_base + ((y * (FONT_HEIGHT*SCREEN_SCALE) * (lcd_width*lcd_depth))
289 + (x * (FONT_WIDTH*SCREEN_SCALE) * lcd_depth)) / 8;
290 for (l = 0; l < FONT_HEIGHT; l++) {
291 for (w = 0; w < SCREEN_SCALE; w++) {
292 bits = font_table[c-FIRST_CHAR][l];
293 for (p = 0; p < 8; p += PIXELS_PER_BYTE) {
294 switch (bits & PIXEL_MASK) {
296 *bufptr++ = (bg << 4) | bg;
299 #if SCREEN_SCALE == 1
300 *bufptr++ = (bg << 4) | fg;
302 *bufptr++ = (fg << 4) | fg;
305 #if SCREEN_SCALE == 1
307 *bufptr++ = (fg << 4) | bg;
310 *bufptr++ = (fg << 4) | fg;
314 bits >>= PIXELS_PER_BYTE;
316 bufptr += (lcd_width*lcd_depth)/8 - (8/PIXELS_PER_BYTE);
323 // Draw one character at the current position
327 lcd_drawc(CURSOR_OFF, curX, curY);
339 if (curY < 0) curY = 0;
344 lcd_drawc(c, curX, curY);
351 lcd_drawc(CURSOR_ON, curX, curY);
354 // Basic LCD 'printf()' support
363 #define is_digit(c) ((c >= '0') && (c <= '9'))
366 _cvt(unsigned long val, char *buf, long radix, char *digits)
376 *cp++ = digits[val % radix];
389 lcd_vprintf(void (*putc)(cyg_int8), const char *fmt0, va_list ap)
392 int left_prec, right_prec, zero_fill, length, pad, pad_on_right;
395 while ((c = *fmt0++)) {
400 left_prec = right_prec = pad_on_right = 0;
411 while (is_digit(c)) {
412 left_prec = (left_prec * 10) + (c - '0');
418 while (is_digit(c)) {
419 right_prec = (right_prec * 10) + (c - '0');
423 right_prec = left_prec;
430 val = va_arg(ap, long);
437 length = _cvt(val, buf, 10, "0123456789");
440 length = _cvt(val, buf, 16, "0123456789abcdef");
443 length = _cvt(val, buf, 16, "0123456789ABCDEF");
448 cp = va_arg(ap, char *);
452 c = va_arg(ap, long /*char*/);
458 pad = left_prec - length;
479 while (length-- > 0) {
500 lcd_printf(char const *fmt, ...)
506 ret = lcd_vprintf(lcd_putc, fmt, ap);