]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/trab/vfd.c
* Patch by Hans-Joerg Frieden, 06 Dec 2002
[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 /* taken from armboot/common/vfd.c */
63 ulong         adr_vfd_table[112][18][2][4][2];
64 unsigned char bit_vfd_table[112][18][2][4][2];
65
66 /*
67  * initialize the values for the VFD-grid-control in the framebuffer
68  */
69 void init_grid_ctrl(void)
70 {
71         ulong adr, grid_cycle;
72         unsigned int bit, display;
73         unsigned char temp, bit_nr;
74
75         for (adr=vfdbase; adr<=(vfdbase+7168); adr+=4) /*clear frame buffer */
76                 (*(volatile ulong*)(adr))=0;
77
78         for(display=0;display<=3;display++)
79         {
80                 for(grid_cycle=0;grid_cycle<=55;grid_cycle++)
81                 {
82                         bit = grid_cycle*256*4+(grid_cycle+200)*4+frame_buf_offs+display;
83                         /* wrap arround if offset (see manual S3C2400) */
84                         if (bit>=frame_buf_size*8)
85                                 bit = bit-(frame_buf_size*8);
86                         adr = vfdbase+(bit/32)*4+(3-(bit%32)/8);
87                         bit_nr = bit%8;
88                         bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
89                         temp=(*(volatile unsigned char*)(adr));
90                         temp|=(1<<bit_nr);
91                         (*(volatile unsigned char*)(adr))=temp;
92
93                         if(grid_cycle<55)
94                                 bit = grid_cycle*256*4+(grid_cycle+201)*4+frame_buf_offs+display;
95                         else
96                                 bit = grid_cycle*256*4+200*4+frame_buf_offs+display-4;  /* grid nr. 0 */
97                         /* wrap arround if offset (see manual S3C2400) */
98                         if (bit>=frame_buf_size*8)
99                                 bit = bit-(frame_buf_size*8);
100                         adr = vfdbase+(bit/32)*4+(3-(bit%32)/8);
101                         bit_nr = bit%8;
102                         bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
103                         temp=(*(volatile unsigned char*)(adr));
104                         temp|=(1<<bit_nr);
105                         (*(volatile unsigned char*)(adr))=temp;
106                 }
107         }
108 }
109
110 /*
111  *create translation table for getting easy the right position in the
112  *physical framebuffer for some x/y-coordinates of the VFDs
113  */
114 void create_vfd_table(void)
115 {
116         unsigned int vfd_table[112][18][2][4][2];
117         ulong adr;
118         unsigned int x, y, color, display, entry, pixel, bit_nr;
119
120         /*
121          * Create translation table for Noritake-T119C-VFD-specific
122          * organized frame-buffer.
123          * Created is the number of the bit in the framebuffer (the
124          * first transferred pixel of each frame is bit 0).
125          */
126         for(y=0;y<=17;y++)   /* Zeile */
127         {
128                 for(x=0;x<=111;x++)  /* Spalten */
129                 {
130                         /*Display 0 blaue Pixel Eintrag 1 */
131                         vfd_table[x][y][0][0][0]=((x%4)*4+y*16+(x/4)*2048);
132                         /*Display 0 rote Pixel Eintrag 1 */
133                         vfd_table[x][y][1][0][0]=((x%4)*4+y*16+(x/4)*2048+512);
134                         if(x<=1)
135                         {
136                                 /*Display 0 blaue Pixel Eintrag 2 */
137                                 vfd_table[x][y][0][0][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+1024);
138                                 /*Display 0 rote Pixel Eintrag 2 */
139                                 vfd_table[x][y][1][0][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+512+1024);
140                         }
141                         else
142                         {
143                                 /*Display 0 blaue Pixel Eintrag 2 */
144                                 vfd_table[x][y][0][0][1]=((x%4)*4+y*16+((x-2)/4)*2048+1024);
145                                 /*Display 0 rote Pixel Eintrag 2 */
146                                 vfd_table[x][y][1][0][1]=((x%4)*4+y*16+((x-2)/4)*2048+512+1024);
147                         }
148                         /*Display 1 blaue Pixel Eintrag 1 */
149                         vfd_table[x][y][0][1][0]=((x%4)*4+y*16+(x/4)*2048+1);
150                         /*Display 1 rote Pixel Eintrag 1 */
151                         vfd_table[x][y][1][1][0]=((x%4)*4+y*16+(x/4)*2048+512+1);
152                         if(x<=1)
153                         {
154                                 /*Display 1 blaue Pixel Eintrag 2 */
155                                 vfd_table[x][y][0][1][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+1+1024);
156                                 /*Display 1 rote Pixel Eintrag 2 */
157                                 vfd_table[x][y][1][1][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+512+1+1024);
158                         }
159                         else
160                         {
161                                 /*Display 1 blaue Pixel Eintrag 2 */
162                                 vfd_table[x][y][0][1][1]=((x%4)*4+y*16+((x-2)/4)*2048+1+1024);
163                                 /*Display 1 rote Pixel Eintrag 2 */
164                                 vfd_table[x][y][1][1][1]=((x%4)*4+y*16+((x-2)/4)*2048+512+1+1024);
165                         }
166                         /*Display 2 blaue Pixel Eintrag 1 */
167                         vfd_table[x][y][0][2][0]=((x%4)*4+y*16+(x/4)*2048+2);
168                         /*Display 2 rote Pixel Eintrag 1 */
169                         vfd_table[x][y][1][2][0]=((x%4)*4+y*16+(x/4)*2048+512+2);
170                         if(x<=1)
171                         {
172                                 /*Display 2 blaue Pixel Eintrag 2 */
173                                 vfd_table[x][y][0][2][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+2+1024);
174                                 /*Display 2 rote Pixel Eintrag 2 */
175                                 vfd_table[x][y][1][2][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+512+2+1024);
176                         }
177                         else
178                         {
179                                 /*Display 2 blaue Pixel Eintrag 2 */
180                                 vfd_table[x][y][0][2][1]=((x%4)*4+y*16+((x-2)/4)*2048+2+1024);
181                                 /*Display 2 rote Pixel Eintrag 2 */
182                                 vfd_table[x][y][1][2][1]=((x%4)*4+y*16+((x-2)/4)*2048+512+2+1024);
183                         }
184                         /*Display 3 blaue Pixel Eintrag 1 */
185                         vfd_table[x][y][0][3][0]=((x%4)*4+y*16+(x/4)*2048+3);
186                         /*Display 3 rote Pixel Eintrag 1 */
187                         vfd_table[x][y][1][3][0]=((x%4)*4+y*16+(x/4)*2048+512+3);
188                         if(x<=1)
189                         {
190                                 /*Display 3 blaue Pixel Eintrag 2 */
191                                 vfd_table[x][y][0][3][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+3+1024);
192                                 /*Display 3 rote Pixel Eintrag 2 */
193                                 vfd_table[x][y][1][3][1]=(((x+112)%4)*4+y*16+((x+110)/4)*2048+512+3+1024);
194                         }
195                         else
196                         {
197                                 /*Display 3 blaue Pixel Eintrag 2 */
198                                 vfd_table[x][y][0][3][1]=((x%4)*4+y*16+((x-2)/4)*2048+3+1024);
199                                 /*Display 3 rote Pixel Eintrag 2 */
200                                 vfd_table[x][y][1][3][1]=((x%4)*4+y*16+((x-2)/4)*2048+512+3+1024);
201                         }
202                 }
203         }
204
205         /*
206          * Create translation table for Noritake-T119C-VFD-specific
207          * organized frame-buffer
208          * Create table with entries for physical byte adresses and
209          * bit-number within the byte
210          * from table with bit-numbers within the total framebuffer
211          */
212         for(y=0;y<=17;y++)
213         {
214                 for(x=0;x<=111;x++)
215                 {
216                         for(color=0;color<=1;color++)
217                         {
218                                 for(display=0;display<=3;display++)
219                                 {
220                                         for(entry=0;entry<=1;entry++)
221                                         {
222                                                 pixel  = vfd_table[x][y][color][display][entry] + frame_buf_offs;
223                                                  /*
224                                                   * wrap arround if offset
225                                                   * (see manual S3C2400)
226                                                   */
227                                                 if (pixel>=frame_buf_size*8)
228                                                         pixel = pixel-(frame_buf_size*8);
229                                                 adr    = vfdbase+(pixel/32)*4+(3-(pixel%32)/8);
230                                                 bit_nr = pixel%8;
231                                                 bit_nr = (bit_nr>3)?bit_nr-4:bit_nr+4;
232                                                 adr_vfd_table[x][y][color][display][entry] = adr;
233                                                 bit_vfd_table[x][y][color][display][entry] = bit_nr;
234                                         }
235                                 }
236                         }
237                 }
238         }
239 }
240
241 /*
242  * Set/clear pixel of the VFDs
243  */
244 void set_vfd_pixel(unsigned char x, unsigned char y, unsigned char color, unsigned char display, unsigned char value)
245 {
246         ulong adr;
247         unsigned char bit_nr, temp;
248
249         if (value!=0)
250         {
251                 /* Pixel-Eintrag Nr. 1 */
252                 adr = adr_vfd_table[x][y][color][display][0];
253                 /* Pixel-Eintrag Nr. 1 */
254                 bit_nr = bit_vfd_table[x][y][color][display][0];
255                 temp=(*(volatile unsigned char*)(adr));
256                 temp|=1<<bit_nr;
257                 (*(volatile unsigned char*)(adr))=temp;
258
259                 /* Pixel-Eintrag Nr. 2 */
260                 adr = adr_vfd_table[x][y][color][display][1];
261                 /* Pixel-Eintrag Nr. 2 */
262                 bit_nr = bit_vfd_table[x][y][color][display][1];
263                 temp=(*(volatile unsigned char*)(adr));
264                 temp|=1<<bit_nr;
265                 (*(volatile unsigned char*)(adr))=temp;
266         }
267         else
268         {
269                 /* Pixel-Eintrag Nr. 1 */
270                 adr = adr_vfd_table[x][y][color][display][0];
271                 /* Pixel-Eintrag Nr. 1 */
272                 bit_nr = bit_vfd_table[x][y][color][display][0];
273                 temp=(*(volatile unsigned char*)(adr));
274                 temp&=~(1<<bit_nr);
275                 (*(volatile unsigned char*)(adr))=temp;
276
277                 /* Pixel-Eintrag Nr. 2 */
278                 adr = adr_vfd_table[x][y][color][display][1];
279                 /* Pixel-Eintrag Nr. 2 */
280                 bit_nr = bit_vfd_table[x][y][color][display][1];
281                 temp=(*(volatile unsigned char*)(adr));
282                 temp&=~(1<<bit_nr);
283                 (*(volatile unsigned char*)(adr))=temp;
284         }
285 }
286
287 /*
288  * transfer image from BMP-File
289  */
290 void transfer_pic(int display, unsigned char *adr, int height, int width)
291 {
292         int x, y;
293         unsigned char temp;
294
295         for (; height > 0; height -= 18)
296         {
297                 if (height > 18)
298                         y = 18;
299                 else
300                         y = height;
301                 for (; y > 0; y--)
302                 {
303                         for (x = 0; x < width; x += 2)
304                         {
305                                 temp = *adr++;
306                                 set_vfd_pixel(x, y-1, 0, display, 0);
307                                 set_vfd_pixel(x, y-1, 1, display, 0);
308                                 if ((temp >> 4) == BLAU)
309                                         set_vfd_pixel(x, y-1, 0, display, 1);
310                                 else if ((temp >> 4) == ROT)
311                                         set_vfd_pixel(x, y-1, 1, display, 1);
312                                 else if ((temp >> 4) == VIOLETT)
313                                 {
314                                         set_vfd_pixel(x, y-1, 0, display, 1);
315                                         set_vfd_pixel(x, y-1, 1, display, 1);
316                                 }
317                                 set_vfd_pixel(x+1, y-1, 0, display, 0);
318                                 set_vfd_pixel(x+1, y-1, 1, display, 0);
319                                 if ((temp & 0x0F) == BLAU)
320                                         set_vfd_pixel(x+1, y-1, 0, display, 1);
321                                 else if ((temp & 0x0F) == ROT)
322                                         set_vfd_pixel(x+1, y-1, 1, display, 1);
323                                 else if ((temp & 0x0F) == VIOLETT)
324                                 {
325                                         set_vfd_pixel(x+1, y-1, 0, display, 1);
326                                         set_vfd_pixel(x+1, y-1, 1, display, 1);
327                                 }
328                         }
329                 }
330                 display++;
331                 if (display > 3)
332                         display = 0;
333         }
334 }
335
336 /*
337  * initialize LCD-Controller of the S3C2400 for using VFDs
338  */
339 int drv_vfd_init(void)
340 {
341         ulong palette;
342         static int vfd_init_done = 0;
343
344         DECLARE_GLOBAL_DATA_PTR;
345
346         if (vfd_init_done != 0)
347                 return (0);
348         vfd_init_done = 1;
349
350         vfdbase = gd->fb_base;
351         create_vfd_table();
352         init_grid_ctrl();
353
354         /*
355          * Hinweis: Der Framebuffer ist um genau ein Nibble verschoben
356          * Das erste angezeigte Pixel wird aus dem zweiten Nibble geholt
357          * das letzte angezeigte Pixel wird aus dem ersten Nibble geholt
358          * (wrap around)
359          * see manual S3C2400
360          */
361         /* frame buffer startadr */
362         rLCDSADDR1 = vfdbase >> 1;
363         /* frame buffer endadr */
364         rLCDSADDR2 = (vfdbase + frame_buf_size) >> 1;
365         rLCDSADDR3 = ((256/4));
366
367         /* Port-Pins als LCD-Ausgang */
368         rPCCON =   (rPCCON & 0xFFFFFF00)| 0x000000AA;
369         /* Port-Pins als LCD-Ausgang */
370         rPDCON =   (rPDCON & 0xFFFFFF03)| 0x000000A8;
371 #ifdef WITH_VFRAME
372         /* mit VFRAME zum Messen */
373         rPDCON =   (rPDCON & 0xFFFFFF00)| 0x000000AA;
374 #endif
375
376         rLCDCON2 = 0x000DC000;
377         rLCDCON3 = 0x0051000A;
378         rLCDCON4 = 0x00000001;
379         rLCDCON5 = 0x00000440;
380         rLCDCON1 = 0x00000B75;
381
382         debug ("LCDSADDR1: %lX\n", rLCDSADDR1);
383         debug ("LCDSADDR2: %lX\n", rLCDSADDR2);
384         debug ("LCDSADDR3: %lX\n", rLCDSADDR3);
385
386         for(palette=0;palette<=15;palette++)
387                 (*(volatile unsigned int*)(PALETTE+(palette*4)))=palette;
388         for(palette=16;palette<=255;palette++)
389                 (*(volatile unsigned int*)(PALETTE+(palette*4)))=0x00;
390
391         return 0;
392 }
393
394 /************************************************************************/
395 /* ** ROM capable initialization part - needed to reserve FB memory     */
396 /************************************************************************/
397
398 /*
399  * This is called early in the system initialization to grab memory
400  * for the VFD controller.
401  *
402  * Note that this is running from ROM, so no write access to global data.
403  */
404 ulong vfd_setmem (ulong addr)
405 {
406         ulong size;
407
408         /* MAGIC */
409         frame_buf_size = (256*4*56)/8;
410
411         /* Round up to nearest full page */
412         size = (frame_buf_size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
413
414         debug ("Reserving %ldk for VFD Framebuffer at: %08lx\n", size>>10, addr);
415
416         return (size);
417 }
418
419 #endif /* CONFIG_VFD */