blob: 7377b4df1a3fc2d6df72ec1ad8c5326df478d83e [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
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
58ulong vfdbase;
59ulong frame_buf_size;
60#define frame_buf_offs 4
61
62/* taken from armboot/common/vfd.c */
63ulong adr_vfd_table[112][18][2][4][2];
64unsigned char bit_vfd_table[112][18][2][4][2];
65
66/*
67 * initialize the values for the VFD-grid-control in the framebuffer
68 */
69void 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 */
114void 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 */
244void 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 */
290void 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 */
339int drv_vfd_init(void)
340{
341 ulong palette;
wdenk9dd2b882002-12-03 21:28:10 +0000342 static int vfd_init_done = 0;
wdenkc6097192002-11-03 00:24:07 +0000343
344 DECLARE_GLOBAL_DATA_PTR;
345
wdenk9dd2b882002-12-03 21:28:10 +0000346 if (vfd_init_done != 0)
347 return;
348 vfd_init_done = 1;
349
wdenkc6097192002-11-03 00:24:07 +0000350 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 */
404ulong 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 */