]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/trab/vfd.c
* Patches by David Müller, 31 Jan 2003:
[karo-tx-uboot.git] / board / trab / vfd.c
1 /*
2  * (C) Copyright 2001
3  * Wolfgang Denk, DENX Software Engineering -- wd@denx.de
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /************************************************************************/
25 /* ** DEBUG SETTINGS                                                    */
26 /************************************************************************/
27
28 /* #define DEBUG        */
29
30 /************************************************************************/
31 /* ** HEADER FILES                                                      */
32 /************************************************************************/
33
34 #include <config.h>
35 #include <common.h>
36 #include <version.h>
37 #include <stdarg.h>
38 #include <linux/types.h>
39 #include <devices.h>
40 #include <s3c2400.h>
41
42 #ifdef CONFIG_VFD
43
44 /************************************************************************/
45 /* ** CONFIG STUFF -- should be moved to board config file              */
46 /************************************************************************/
47
48 /************************************************************************/
49
50 #ifndef PAGE_SIZE
51 #define PAGE_SIZE       4096
52 #endif
53
54 #define ROT     0x09
55 #define BLAU    0x0C
56 #define VIOLETT 0X0D
57
58 ulong   frame_buf_size;
59 #define frame_buf_offs 4
60
61 /* Supported VFD Types */
62 #define VFD_TYPE_T119C          1       /* Noritake T119C VFD */
63 #define VFD_TYPE_MN11236        2
64
65 /* taken from armboot/common/vfd.c */
66 unsigned long adr_vfd_table[112][18][2][4][2];
67 unsigned char bit_vfd_table[112][18][2][4][2];
68
69 /*
70  * initialize the values for the VFD-grid-control in the framebuffer
71  */
72 void init_grid_ctrl(void)
73 {
74         DECLARE_GLOBAL_DATA_PTR;
75         ulong adr, grid_cycle;
76         unsigned int bit, display;
77         unsigned char temp, bit_nr;
78         ulong val;
79
80         /*
81          * clear frame buffer (logical clear => set to "black")
82          */
83         if (gd->vfd_inv_data == 0)
84                 val = 0;
85         else
86                 val = ~0;
87
88         for (adr = gd->fb_base; adr <= (gd->fb_base+7168); adr += 4) {
89                 (*(volatile ulong*)(adr)) = val;
90         }
91
92         switch (gd->vfd_type) {
93         case VFD_TYPE_T119C:
94             for (display=0; display<4; display++) {
95                 for(grid_cycle=0; grid_cycle<56; grid_cycle++) {
96                         bit = grid_cycle * 256  * 4 +
97                              (grid_cycle + 200) * 4 +
98                              frame_buf_offs + display;
99                         /* wrap arround if offset (see manual S3C2400) */
100                         if (bit>=frame_buf_size*8)
101                                 bit = bit - (frame_buf_size * 8);
102                         adr = gd->fb_base + (bit/32) * 4 + (3 - (bit%32) / 8);
103                         bit_nr = bit % 8;
104                         bit_nr = (bit_nr > 3) ? bit_nr-4 : bit_nr+4;
105                         temp=(*(volatile unsigned char*)(adr));
106                         if (gd->vfd_inv_data)
107                                 temp &= ~(1<<bit_nr);
108                         else
109                                 temp |=  (1<<bit_nr);
110                         (*(volatile unsigned char*)(adr))=temp;
111
112                         if(grid_cycle<55)
113                                 bit = grid_cycle*256*4+(grid_cycle+201)*4+frame_buf_offs+display;
114                         else
115                                 bit = grid_cycle*256*4+200*4+frame_buf_offs+display-4;  /* grid nr. 0 */
116                         /* wrap arround if offset (see manual S3C2400) */
117                         if (bit>=frame_buf_size*8)
118                                 bit = bit-(frame_buf_size*8);
119                         adr = gd->fb_base+(bit/32)*4+(3-(bit%32)/8);
120                         bit_nr = bit%8;
121                         bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
122                         temp=(*(volatile unsigned char*)(adr));
123                         if (gd->vfd_inv_data)
124                                 temp &= ~(1<<bit_nr);
125                         else
126                                 temp |=  (1<<bit_nr);
127                         (*(volatile unsigned char*)(adr))=temp;
128                 }
129             }
130             break;
131         case VFD_TYPE_MN11236:
132             for (display=0; display<4; display++) {
133                 for (grid_cycle=0; grid_cycle<38; grid_cycle++) {
134                         bit = grid_cycle * 256  * 4 +
135                              (253 - grid_cycle) * 4 +
136                              frame_buf_offs + display;
137                         /* wrap arround if offset (see manual S3C2400) */
138                         if (bit>=frame_buf_size*8)
139                                 bit = bit - (frame_buf_size * 8);
140                         adr = gd->fb_base + (bit/32) * 4 + (3 - (bit%32) / 8);
141                         bit_nr = bit % 8;
142                         bit_nr = (bit_nr > 3) ? bit_nr-4 : bit_nr+4;
143                         temp=(*(volatile unsigned char*)(adr));
144                         if (gd->vfd_inv_data)
145                                 temp &= ~(1<<bit_nr);
146                         else
147                                 temp |=  (1<<bit_nr);
148                         (*(volatile unsigned char*)(adr))=temp;
149
150                         if(grid_cycle<37)
151                                 bit = grid_cycle*256*4+(252-grid_cycle)*4+frame_buf_offs+display;
152
153                         /* wrap arround if offset (see manual S3C2400) */
154                         if (bit>=frame_buf_size*8)
155                                 bit = bit-(frame_buf_size*8);
156                         adr = gd->fb_base+(bit/32)*4+(3-(bit%32)/8);
157                         bit_nr = bit%8;
158                         bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
159                         temp=(*(volatile unsigned char*)(adr));
160                         if (gd->vfd_inv_data)
161                                 temp &= ~(1<<bit_nr);
162                         else
163                                 temp |=  (1<<bit_nr);
164                         (*(volatile unsigned char*)(adr))=temp;
165                 }
166             }
167             break;
168         default:
169             printf ("Warning: unknown display type\n");
170             break;
171         }
172 }
173
174 /*
175  *create translation table for getting easy the right position in the
176  *physical framebuffer for some x/y-coordinates of the VFDs
177  */
178 void create_vfd_table(void)
179 {
180         DECLARE_GLOBAL_DATA_PTR;
181         unsigned long vfd_table[112][18][2][4][2];
182         unsigned int x, y, color, display, entry, pixel;
183         unsigned int x_abcdef = 0;
184
185         switch (gd->vfd_type) {
186         case VFD_TYPE_T119C:
187             for(y=0; y<=17; y++) {      /* Line */
188                 for(x=0; x<=111; x++) { /* Column */
189                     for(display=0; display <=3; display++) {
190
191                             /* Display 0 blue pixels */
192                             vfd_table[x][y][0][display][0] =
193                                 (x==0) ? y*16+display
194                                        : (x%4)*4+y*16+((x-1)/2)*1024+display;
195                             /* Display 0 red pixels */
196                             vfd_table[x][y][1][display][0] =
197                                 (x==0) ? y*16+512+display
198                                        : (x%4)*4+y*16+((x-1)/2)*1024+512+display;
199                     }
200                 }
201             }
202             break;
203         case VFD_TYPE_MN11236:
204             for(y=0; y<=17; y++) {      /* Line */
205                 for(x=0; x<=111; x++) { /* Column */
206                     for(display=0; display <=3; display++) {
207
208                             vfd_table[x][y][0][display][0]=0;
209                             vfd_table[x][y][0][display][1]=0;
210                             vfd_table[x][y][1][display][0]=0;
211                             vfd_table[x][y][1][display][1]=0;
212
213                             switch (x%6) {
214                             case 0: x_abcdef=0; break; /* a -> a */
215                             case 1: x_abcdef=2; break; /* b -> c */
216                             case 2: x_abcdef=4; break; /* c -> e */
217                             case 3: x_abcdef=5; break; /* d -> f */
218                             case 4: x_abcdef=3; break; /* e -> d */
219                             case 5: x_abcdef=1; break; /* f -> b */
220                             }
221
222                             /* blue pixels */
223                             vfd_table[x][y][0][display][0] =
224                                 (x>1) ? x_abcdef*4+((x-1)/3)*1024+y*48+display
225                                       : x_abcdef*4+             0+y*48+display;
226                             /* blue pixels */
227                             if (x>1 && (x-1)%3)
228                                     vfd_table[x][y][0][display][1] = x_abcdef*4+((x-1)/3+1)*1024+y*48+display;
229
230                             /* red pixels */
231                             vfd_table[x][y][1][display][0] =
232                                 (x>1) ? x_abcdef*4+24+((x-1)/3)*1024+y*48+display
233                                       : x_abcdef*4+24+             0+y*48+display;
234                             /* red pixels */
235                             if (x>1 && (x-1)%3)
236                                     vfd_table[x][y][1][display][1] = x_abcdef*4+24+((x-1)/3+1)*1024+y*48+display;
237                     }
238                 }
239             }
240             break;
241         default:
242             /* do nothing */
243             return;
244         }
245
246         /*
247          * Create table with entries for physical byte adresses and
248          * bit-number within the byte
249          * from table with bit-numbers within the total framebuffer
250          */
251         for(y=0;y<18;y++) {
252             for(x=0;x<112;x++) {
253                 for(color=0;color<2;color++) {
254                     for(display=0;display<4;display++) {
255                         for(entry=0;entry<2;entry++) {
256                             unsigned long adr  = gd->fb_base;
257                             unsigned int bit_nr = 0;
258                             
259                             if (vfd_table[x][y][color][display][entry]) {
260
261                                 pixel  = vfd_table[x][y][color][display][entry] + frame_buf_offs;
262                                  /*
263                                   * wrap arround if offset
264                                   * (see manual S3C2400)
265                                   */
266                                 if (pixel>=frame_buf_size*8)
267                                         pixel = pixel-(frame_buf_size*8);
268                                 adr    = gd->fb_base+(pixel/32)*4+(3-(pixel%32)/8);
269                                 bit_nr = pixel%8;
270                                 bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
271                             }
272                             adr_vfd_table[x][y][color][display][entry] = adr;
273                             bit_vfd_table[x][y][color][display][entry] = bit_nr;
274                         }
275                     }
276                 }
277             }
278         }
279 }
280
281 /*
282  * Set/clear pixel of the VFDs
283  */
284 void set_vfd_pixel(unsigned char x, unsigned char y,
285                    unsigned char color, unsigned char display,
286                    unsigned char value)
287 {
288         DECLARE_GLOBAL_DATA_PTR;
289         ulong adr;
290         unsigned char bit_nr, temp;
291
292         if (! gd->vfd_type) {
293                 /* Unknown type. */
294                 return;
295         }
296
297         /* Pixel-Eintrag Nr. 1 */
298         adr = adr_vfd_table[x][y][color][display][0];
299         /* Pixel-Eintrag Nr. 1 */
300         bit_nr = bit_vfd_table[x][y][color][display][0];
301         temp=(*(volatile unsigned char*)(adr));
302
303         if (gd->vfd_inv_data) {
304                 if (value)
305                         temp &= ~(1<<bit_nr);
306                 else
307                         temp |=  (1<<bit_nr);
308         } else {
309                 if (value)
310                         temp |=  (1<<bit_nr);
311                 else
312                         temp &= ~(1<<bit_nr);
313         }
314         
315         (*(volatile unsigned char*)(adr))=temp;
316 }
317
318 /*
319  * transfer image from BMP-File
320  */
321 void transfer_pic(int display, unsigned char *adr, int height, int width)
322 {
323         int x, y;
324         unsigned char temp;
325
326         for (; height > 0; height -= 18)
327         {
328                 if (height > 18)
329                         y = 18;
330                 else
331                         y = height;
332                 for (; y > 0; y--)
333                 {
334                         for (x = 0; x < width; x += 2)
335                         {
336                                 temp = *adr++;
337                                 set_vfd_pixel(x, y-1, 0, display, 0);
338                                 set_vfd_pixel(x, y-1, 1, display, 0);
339                                 if ((temp >> 4) == BLAU)
340                                         set_vfd_pixel(x, y-1, 0, display, 1);
341                                 else if ((temp >> 4) == ROT)
342                                         set_vfd_pixel(x, y-1, 1, display, 1);
343                                 else if ((temp >> 4) == VIOLETT)
344                                 {
345                                         set_vfd_pixel(x, y-1, 0, display, 1);
346                                         set_vfd_pixel(x, y-1, 1, display, 1);
347                                 }
348                                 set_vfd_pixel(x+1, y-1, 0, display, 0);
349                                 set_vfd_pixel(x+1, y-1, 1, display, 0);
350                                 if ((temp & 0x0F) == BLAU)
351                                         set_vfd_pixel(x+1, y-1, 0, display, 1);
352                                 else if ((temp & 0x0F) == ROT)
353                                         set_vfd_pixel(x+1, y-1, 1, display, 1);
354                                 else if ((temp & 0x0F) == VIOLETT)
355                                 {
356                                         set_vfd_pixel(x+1, y-1, 0, display, 1);
357                                         set_vfd_pixel(x+1, y-1, 1, display, 1);
358                                 }
359                         }
360                 }
361                 display++;
362                 if (display > 3)
363                         display = 0;
364         }
365 }
366
367 /*
368  * This function initializes VFD clock that is needed for the CPLD that
369  * manages the keyboard.
370  */
371 int vfd_init_clocks(void)
372 {
373         /* Port-Pins als LCD-Ausgang */
374         rPCCON =   (rPCCON & 0xFFFFFF00)| 0x000000AA;
375         /* Port-Pins als LCD-Ausgang */
376         rPDCON =   (rPDCON & 0xFFFFFF03)| 0x000000A8;
377 #ifdef CFG_WITH_VFRAME
378         /* mit VFRAME zum Messen */
379         rPDCON =   (rPDCON & 0xFFFFFF00)| 0x000000AA;
380 #endif
381
382         rLCDCON2 = 0x000DC000;
383         rLCDCON3 = 0x0051000A;
384         rLCDCON4 = 0x00000001;
385         rLCDCON5 = 0x00000440;
386         rLCDCON1 = 0x00000B75;
387
388         return 0;
389 }
390
391 /*
392  * initialize LCD-Controller of the S3C2400 for using VFDs
393  *
394  * VFD detection depends on the board revision:
395  * starting from Rev. 200 a type code can be read from the data pins,
396  * driven by some pull-up resistors; all earlier systems must be
397  * manually configured. The type is set in the "vfd_type" environment
398  * variable.
399  */
400 int drv_vfd_init(void)
401 {
402         char *tmp;
403         ulong palette;
404         static int vfd_init_done = 0;
405         int vfd_id;
406
407         DECLARE_GLOBAL_DATA_PTR;
408
409         if (vfd_init_done != 0)
410                 return (0);
411         vfd_init_done = 1;
412
413         /* try to determine display type from the value
414          * defined by pull-ups
415          */
416         rPCUP  = (rPCUP & 0xFFF0);      /* activate  GPC0...GPC3 pullups */
417         rPCCON = (rPCCON & 0xFFFFFF00); /* configure GPC0...GPC3 as inputs */
418         udelay(10);                     /* allow signals to settle */
419
420         vfd_id = (~rPCDAT) & 0x000F;    /* read GPC0...GPC3 port pins */
421         debug("Detecting Revison of WA4-VFD: ID=0x%X\n", vfd_id);
422
423         switch (vfd_id) {
424         case 0:                 /* board revision < Rev.200 */
425                 if ((tmp = getenv ("vfd_type")) == NULL) {
426                         break;
427                 }
428                 if (strcmp(tmp, "T119C") == 0) {
429                         gd->vfd_type = VFD_TYPE_T119C;
430                 } else if (strcmp(tmp, "MN11236") == 0) {
431                         gd->vfd_type = VFD_TYPE_MN11236;
432                 } else {
433                         /* cannot use printf for a warning here */
434                         gd->vfd_type = 0;       /* unknown */
435                 }
436                 gd->vfd_inv_data = 0;
437
438                 break;
439         default:                /* default to MN11236, data inverted */
440                 gd->vfd_type = VFD_TYPE_MN11236;
441                 gd->vfd_inv_data = 1;
442                 setenv ("vfd_type", "MN11236");
443         }
444         debug ("VFD type: %s%s\n",
445                 (gd->vfd_type == VFD_TYPE_T119C)   ? "T119C" :
446                 (gd->vfd_type == VFD_TYPE_MN11236) ? "MN11236" :
447                 "unknown",
448                 gd->vfd_inv_data ? ", inverted data" : "");
449
450         gd->fb_base = gd->fb_base;
451         create_vfd_table();
452         init_grid_ctrl();
453
454         for (palette=0; palette < 16; palette++)
455                 (*(volatile unsigned int*)(PALETTE+(palette*4)))=palette;
456         for (palette=16; palette < 256; palette++)
457                 (*(volatile unsigned int*)(PALETTE+(palette*4)))=0x00;
458
459         /*
460          * Hinweis: Der Framebuffer ist um genau ein Nibble verschoben
461          * Das erste angezeigte Pixel wird aus dem zweiten Nibble geholt
462          * das letzte angezeigte Pixel wird aus dem ersten Nibble geholt
463          * (wrap around)
464          * see manual S3C2400
465          */
466         /* frame buffer startadr */
467         rLCDSADDR1 = gd->fb_base >> 1;
468         /* frame buffer endadr */
469         rLCDSADDR2 = (gd->fb_base + frame_buf_size) >> 1;
470         rLCDSADDR3 = ((256/4));
471
472         debug ("LCDSADDR1: %lX\n", rLCDSADDR1);
473         debug ("LCDSADDR2: %lX\n", rLCDSADDR2);
474         debug ("LCDSADDR3: %lX\n", rLCDSADDR3);
475
476         return 0;
477 }
478
479 /************************************************************************/
480 /* ** ROM capable initialization part - needed to reserve FB memory     */
481 /************************************************************************/
482
483 /*
484  * This is called early in the system initialization to grab memory
485  * for the VFD controller.
486  *
487  * Note that this is running from ROM, so no write access to global data.
488  */
489 ulong vfd_setmem (ulong addr)
490 {
491         ulong size;
492
493         /* MAGIC */
494         frame_buf_size = (256*4*56)/8;
495
496         /* Round up to nearest full page */
497         size = (frame_buf_size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
498
499         debug ("Reserving %ldk for VFD Framebuffer at: %08lx\n", size>>10, addr);
500
501         return (size);
502 }
503
504 #endif /* CONFIG_VFD */