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