1 /*
2 * linux/drivers/video/pmag-ba-fb.c
3 *
4 * PMAG-BA TurboChannel framebuffer card support ... derived from:
5 * "HP300 Topcat framebuffer support (derived from macfb of all things)
6 * Phil Blundell <philb@gnu.org> 1998", the original code can be
7 * found in the file hpfb.c in the same directory.
8 *
9 * Based on digital document:
10 * "PMAG-BA TURBOchannel Color Frame Buffer
11 * Functional Specification", Revision 1.2, August 27, 1990
12 *
13 * DECstation related code Copyright (C) 1999, 2000, 2001 by
14 * Michael Engel <engel@unix-ag.org>,
15 * Karsten Merker <merker@linuxtag.org> and
16 * Harald Koerfgen.
17 * This file is subject to the terms and conditions of the GNU General
18 * Public License. See the file COPYING in the main directory of this
19 * archive for more details.
20 *
21 */
22 #include <linux/module.h>
23 #include <linux/kernel.h>
24 #include <linux/sched.h>
25 #include <linux/errno.h>
26 #include <linux/string.h>
27 #include <linux/timer.h>
28 #include <linux/mm.h>
29 #include <linux/tty.h>
30 #include <linux/slab.h>
31 #include <linux/delay.h>
32 #include <linux/init.h>
33 #include <linux/fb.h>
34 #include <asm/bootinfo.h>
35 #include <asm/dec/machtype.h>
36 #include <asm/dec/tc.h>
37 #include "pmag-ba-fb.h"
38
39 #include <video/fbcon.h>
40 #include <video/fbcon-mfb.h>
41 #include <video/fbcon-cfb2.h>
42 #include <video/fbcon-cfb4.h>
43 #include <video/fbcon-cfb8.h>
44
45 #define arraysize(x) (sizeof(x)/sizeof(*(x)))
46
47 struct pmag_ba_ramdac_regs {
48 unsigned char addr_low;
49 unsigned char pad0[3];
50 unsigned char addr_hi;
51 unsigned char pad1[3];
52 unsigned char data;
53 unsigned char pad2[3];
54 unsigned char cmap;
55 };
56
57 struct pmag_ba_my_fb_info {
58 struct fb_info info;
59 struct pmag_ba_ramdac_regs *bt459_regs;
60 unsigned long pmagba_fb_start;
61 unsigned long pmagba_fb_size;
62 unsigned long pmagba_fb_line_length;
63 };
64
65 static struct display disp;
66 /*
67 * Max 3 TURBOchannel slots -> max 3 PMAG-BA :)
68 */
69 static struct pmag_ba_my_fb_info pmagba_fb_info[3];
70
71 static struct fb_var_screeninfo pmagbafb_defined = {
72 0, 0, 0, 0, /* W,H, W, H (virtual) load xres,xres_virtual */
73 0, 0, /* virtual -> visible no offset */
74 0, /* depth -> load bits_per_pixel */
75 0, /* greyscale ? */
76 {0, 0, 0}, /* R */
77 {0, 0, 0}, /* G */
78 {0, 0, 0}, /* B */
79 {0, 0, 0}, /* transparency */
80 0, /* standard pixel format */
81 FB_ACTIVATE_NOW,
82 274, 195, /* 14" monitor */
83 FB_ACCEL_NONE,
84 0L, 0L, 0L, 0L, 0L,
85 0L, 0L, 0, /* No sync info */
86 FB_VMODE_NONINTERLACED,
87 {0, 0, 0, 0, 0, 0}
88 };
89
90 struct pmagbafb_par {
91 };
92
93 static int currcon = 0;
94 static struct pmagbafb_par current_par;
95
pmagbafb_encode_var(struct fb_var_screeninfo * var,struct pmagbafb_par * par)96 static void pmagbafb_encode_var(struct fb_var_screeninfo *var,
97 struct pmagbafb_par *par)
98 {
99 int i = 0;
100 var->xres = 1024;
101 var->yres = 864;
102 var->xres_virtual = 1024;
103 var->yres_virtual = 864;
104 var->xoffset = 0;
105 var->yoffset = 0;
106 var->bits_per_pixel = 8;
107 var->grayscale = 0;
108 var->red.offset = 0;
109 var->red.length = 8;
110 var->red.msb_right = 0;
111 var->green.offset = 0;
112 var->green.length = 8;
113 var->green.msb_right = 0;
114 var->blue.offset = 0;
115 var->blue.length = 8;
116 var->blue.msb_right = 0;
117 var->transp.offset = 0;
118 var->transp.length = 0;
119 var->transp.msb_right = 0;
120 var->nonstd = 0;
121 var->activate = 1;
122 var->height = -1;
123 var->width = -1;
124 var->vmode = FB_VMODE_NONINTERLACED;
125 var->pixclock = 0;
126 var->sync = 0;
127 var->left_margin = 0;
128 var->right_margin = 0;
129 var->upper_margin = 0;
130 var->lower_margin = 0;
131 var->hsync_len = 0;
132 var->vsync_len = 0;
133 for (i = 0; i < arraysize(var->reserved); i++)
134 var->reserved[i] = 0;
135 }
136
pmagbafb_get_par(struct pmagbafb_par * par)137 static void pmagbafb_get_par(struct pmagbafb_par *par)
138 {
139 *par = current_par;
140 }
141
pmagba_fb_update_var(int con,struct fb_info * info)142 static int pmagba_fb_update_var(int con, struct fb_info *info)
143 {
144 return 0;
145 }
146
pmagba_do_fb_set_var(struct fb_var_screeninfo * var,int isactive)147 static int pmagba_do_fb_set_var(struct fb_var_screeninfo *var,
148 int isactive)
149 {
150 struct pmagbafb_par par;
151
152 pmagbafb_get_par(&par);
153 pmagbafb_encode_var(var, &par);
154 return 0;
155 }
156
157 /*
158 * Turn hardware cursor off
159 */
pmagbafb_erase_cursor(struct pmag_ba_my_fb_info * info)160 void pmagbafb_erase_cursor(struct pmag_ba_my_fb_info *info)
161 {
162 info->bt459_regs->addr_low = 0;
163 info->bt459_regs->addr_hi = 3;
164 info->bt459_regs->data = 0;
165 }
166
167 /*
168 * Write to a Bt459 color map register
169 */
pmag_ba_bt459_write_colormap(struct pmag_ba_my_fb_info * info,int reg,__u8 red,__u8 green,__u8 blue)170 void pmag_ba_bt459_write_colormap(struct pmag_ba_my_fb_info *info,
171 int reg, __u8 red, __u8 green, __u8 blue)
172 {
173 info->bt459_regs->addr_low = (__u8) reg;
174 info->bt459_regs->addr_hi = 0;
175 info->bt459_regs->cmap = red;
176 info->bt459_regs->cmap = green;
177 info->bt459_regs->cmap = blue;
178 }
179
180 /*
181 * Get the palette
182 */
183
pmagbafb_get_cmap(struct fb_cmap * cmap,int kspc,int con,struct fb_info * info)184 static int pmagbafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
185 struct fb_info *info)
186 {
187 unsigned int i;
188 unsigned int length;
189
190 if (((cmap->start) + (cmap->len)) >= 256) {
191 length = 256 - (cmap->start);
192 } else {
193 length = cmap->len;
194 }
195 for (i = 0; i < length; i++) {
196 /*
197 * TODO
198 */
199 }
200 return 0;
201 }
202
203 /*
204 * Set the palette.
205 */
pmagbafb_set_cmap(struct fb_cmap * cmap,int kspc,int con,struct fb_info * info)206 static int pmagbafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
207 struct fb_info *info)
208 {
209 unsigned int i;
210 __u8 cmap_red, cmap_green, cmap_blue;
211 unsigned int length;
212
213 if (((cmap->start) + (cmap->len)) >= 256)
214 length = 256 - (cmap->start);
215 else
216 length = cmap->len;
217
218 for (i = 0; i < length; i++) {
219 cmap_red = ((cmap->red[i]) >> 8); /* The cmap fields are 16 bits */
220 cmap_green = ((cmap->green[i]) >> 8); /* wide, but the harware colormap */
221 cmap_blue = ((cmap->blue[i]) >> 8); /* registers are only 8 bits wide */
222
223 pmag_ba_bt459_write_colormap((struct pmag_ba_my_fb_info *)
224 info, cmap->start + i,
225 cmap_red, cmap_green,
226 cmap_blue);
227 }
228 return 0;
229 }
230
pmagbafb_get_var(struct fb_var_screeninfo * var,int con,struct fb_info * info)231 static int pmagbafb_get_var(struct fb_var_screeninfo *var, int con,
232 struct fb_info *info)
233 {
234 struct pmagbafb_par par;
235 if (con == -1) {
236 pmagbafb_get_par(&par);
237 pmagbafb_encode_var(var, &par);
238 } else
239 *var = fb_display[con].var;
240 return 0;
241 }
242
243
pmagbafb_set_var(struct fb_var_screeninfo * var,int con,struct fb_info * info)244 static int pmagbafb_set_var(struct fb_var_screeninfo *var, int con,
245 struct fb_info *info)
246 {
247 int err;
248
249 if ((err = pmagba_do_fb_set_var(var, 1)))
250 return err;
251 return 0;
252 }
253
pmagbafb_encode_fix(struct fb_fix_screeninfo * fix,struct pmagbafb_par * par,struct pmag_ba_my_fb_info * info)254 static void pmagbafb_encode_fix(struct fb_fix_screeninfo *fix,
255 struct pmagbafb_par *par,
256 struct pmag_ba_my_fb_info *info)
257 {
258 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
259 strcpy(fix->id, "PMAG-BA");
260
261 fix->smem_start = info->pmagba_fb_start;
262 fix->smem_len = info->pmagba_fb_size;
263 fix->type = FB_TYPE_PACKED_PIXELS;
264 fix->visual = FB_VISUAL_PSEUDOCOLOR;
265 fix->xpanstep = 0;
266 fix->ypanstep = 0;
267 fix->ywrapstep = 0;
268 fix->line_length = info->pmagba_fb_line_length;
269 }
270
pmagbafb_get_fix(struct fb_fix_screeninfo * fix,int con,struct fb_info * info)271 static int pmagbafb_get_fix(struct fb_fix_screeninfo *fix, int con,
272 struct fb_info *info)
273 {
274 struct pmagbafb_par par;
275
276 pmagbafb_get_par(&par);
277 pmagbafb_encode_fix(fix, &par, (struct pmag_ba_my_fb_info *) info);
278
279 return 0;
280 }
281
282
pmagbafb_ioctl(struct inode * inode,struct file * file,unsigned int cmd,unsigned long arg,int con,struct fb_info * info)283 static int pmagbafb_ioctl(struct inode *inode, struct file *file,
284 unsigned int cmd, unsigned long arg, int con,
285 struct fb_info *info)
286 {
287 return -EINVAL;
288 }
289
pmagbafb_switch(int con,struct fb_info * info)290 static int pmagbafb_switch(int con, struct fb_info *info)
291 {
292 pmagba_do_fb_set_var(&fb_display[con].var, 1);
293 currcon = con;
294
295 return 0;
296 }
297
298 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
299
pmagbafb_blank(int blank,struct fb_info * info)300 static void pmagbafb_blank(int blank, struct fb_info *info)
301 {
302 /* Not supported */
303 }
304
pmagbafb_open(struct fb_info * info,int user)305 static int pmagbafb_open(struct fb_info *info, int user)
306 {
307 /*
308 * Nothing, only a usage count for the moment
309 */
310 MOD_INC_USE_COUNT;
311 return (0);
312 }
313
pmagbafb_set_disp(int con,struct pmag_ba_my_fb_info * info)314 static void pmagbafb_set_disp(int con, struct pmag_ba_my_fb_info *info)
315 {
316 struct fb_fix_screeninfo fix;
317 struct display *display;
318
319 if (con >= 0)
320 display = &fb_display[con];
321 else
322 display = &disp; /* used during initialization */
323
324 pmagbafb_get_fix(&fix, con, (struct fb_info *) info);
325
326 display->screen_base = (char *) fix.smem_start;
327 display->visual = fix.visual;
328 display->type = fix.type;
329 display->type_aux = fix.type_aux;
330 display->ypanstep = fix.ypanstep;
331 display->ywrapstep = fix.ywrapstep;
332 display->line_length = fix.line_length;
333 display->next_line = fix.line_length;
334 display->can_soft_blank = 0;
335 display->inverse = 0;
336 display->scrollmode = SCROLL_YREDRAW;
337 display->dispsw = &fbcon_cfb8;
338 }
339
pmagbafb_release(struct fb_info * info,int user)340 static int pmagbafb_release(struct fb_info *info, int user)
341 {
342 MOD_DEC_USE_COUNT;
343 return (0);
344 }
345
346 static struct fb_ops pmagbafb_ops = {
347 owner:THIS_MODULE,
348 fb_open:pmagbafb_open,
349 fb_release:pmagbafb_release,
350 fb_get_fix:pmagbafb_get_fix,
351 fb_get_var:pmagbafb_get_var,
352 fb_set_var:pmagbafb_set_var,
353 fb_get_cmap:pmagbafb_get_cmap,
354 fb_set_cmap:pmagbafb_set_cmap,
355 fb_ioctl:pmagbafb_ioctl,
356 fb_mmap:0,
357 fb_rasterimg:0
358 };
359
pmagbafb_init_one(int slot)360 int __init pmagbafb_init_one(int slot)
361 {
362 unsigned long base_addr = get_tc_base_addr(slot);
363 struct pmag_ba_my_fb_info *ip =
364 (struct pmag_ba_my_fb_info *) &pmagba_fb_info[slot];
365
366 printk("PMAG-BA framebuffer in slot %d\n", slot);
367
368 /*
369 * Framebuffer display memory base address and friends
370 */
371 ip->bt459_regs =
372 (struct pmag_ba_ramdac_regs *) (base_addr +
373 PMAG_BA_BT459_OFFSET);
374 ip->pmagba_fb_start = base_addr + PMAG_BA_ONBOARD_FBMEM_OFFSET;
375 ip->pmagba_fb_size = 1024 * 864;
376 ip->pmagba_fb_line_length = 1024;
377
378 /*
379 * Configure the Bt459 RAM DAC
380 */
381 pmagbafb_erase_cursor(ip);
382
383 /*
384 * Fill in the available video resolution
385 */
386
387 pmagbafb_defined.xres = 1024;
388 pmagbafb_defined.yres = 864;
389 pmagbafb_defined.xres_virtual = 1024;
390 pmagbafb_defined.yres_virtual = 864;
391 pmagbafb_defined.bits_per_pixel = 8;
392
393 /*
394 * Let there be consoles..
395 */
396 strcpy(ip->info.modename, "PMAG-BA");
397 ip->info.changevar = NULL;
398 ip->info.node = -1;
399 ip->info.fbops = &pmagbafb_ops;
400 ip->info.disp = &disp;
401 ip->info.switch_con = &pmagbafb_switch;
402 ip->info.updatevar = &pmagba_fb_update_var;
403 ip->info.blank = &pmagbafb_blank;
404 ip->info.flags = FBINFO_FLAG_DEFAULT;
405
406 pmagba_do_fb_set_var(&pmagbafb_defined, 1);
407 pmagbafb_get_var(&disp.var, -1, (struct fb_info *) ip);
408 pmagbafb_set_disp(-1, ip);
409
410 if (register_framebuffer((struct fb_info *) ip) < 0)
411 return 1;
412
413 return 0;
414 }
415
416 /*
417 * Initialise the framebuffer
418 */
419
pmagbafb_init(void)420 int __init pmagbafb_init(void)
421 {
422 int sid;
423 int found = 0;
424
425 if (TURBOCHANNEL) {
426 while ((sid = search_tc_card("PMAG-BA")) >= 0) {
427 found = 1;
428 claim_tc_card(sid);
429 pmagbafb_init_one(sid);
430 }
431 return found ? 0 : -ENODEV;
432 } else {
433 return -ENODEV;
434 }
435 }
436
437 MODULE_LICENSE("GPL");
438