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