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