/* * HP300 Topcat framebuffer support (derived from macfb of all things) * Phil Blundell 1998 * * Should this be moved to drivers/dio/video/ ? -- Peter Maydell * No! -- Jes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fbcon-mfb.h" #include "fbcon-cfb2.h" #include "fbcon-cfb4.h" #include "fbcon-cfb8.h" #define arraysize(x) (sizeof(x)/sizeof(*(x))) static struct display disp; static struct fb_info fb_info; unsigned long fb_start, fb_size = 1024*768, fb_line_length = 1024; unsigned long fb_regs; unsigned char fb_bitmask; #define TC_WEN 0x4088 #define TC_REN 0x408c #define TC_FBEN 0x4090 #define TC_NBLANK 0x4080 /* blitter regs */ #define BUSY 0x4044 #define WMRR 0x40ef #define SOURCE_X 0x40f2 #define SOURCE_Y 0x40f6 #define DEST_X 0x40fa #define DEST_Y 0x40fe #define WHEIGHT 0x4106 #define WWIDTH 0x4102 #define WMOVE 0x409c static struct fb_var_screeninfo hpfb_defined = { 0,0,0,0, /* W,H, W, H (virtual) load xres,xres_virtual*/ 0,0, /* virtual -> visible no offset */ 0, /* depth -> load bits_per_pixel */ 0, /* greyscale ? */ {0,2,0}, /* R */ {0,2,0}, /* G */ {0,2,0}, /* B */ {0,0,0}, /* transparency */ 0, /* standard pixel format */ FB_ACTIVATE_NOW, 274,195, /* 14" monitor */ FB_ACCEL_NONE, 0L,0L,0L,0L,0L, 0L,0L,0, /* No sync info */ FB_VMODE_NONINTERLACED, {0,0,0,0,0,0} }; struct hpfb_par { }; static int currcon = 0; struct hpfb_par current_par; static void hpfb_encode_var(struct fb_var_screeninfo *var, struct hpfb_par *par) { int i=0; var->xres=1024; var->yres=768; var->xres_virtual=1024; var->yres_virtual=768; var->xoffset=0; var->yoffset=0; var->bits_per_pixel = 1; var->grayscale=0; var->transp.offset=0; var->transp.length=0; var->transp.msb_right=0; var->nonstd=0; var->activate=0; var->height= -1; var->width= -1; var->vmode=FB_VMODE_NONINTERLACED; var->pixclock=0; var->sync=0; var->left_margin=0; var->right_margin=0; var->upper_margin=0; var->lower_margin=0; var->hsync_len=0; var->vsync_len=0; for(i=0;ireserved);i++) var->reserved[i]=0; } static void hpfb_get_par(struct hpfb_par *par) { *par=current_par; } static int fb_update_var(int con, struct fb_info *info) { return 0; } static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) { struct hpfb_par par; hpfb_get_par(&par); hpfb_encode_var(var, &par); return 0; } static int hpfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { return 0; } /* * Set the palette. This may not work on all boards but only experimentation will tell. * XXX Doesn't work at all. */ static int hpfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { unsigned int i; for (i = 0; i < cmap->len; i++) { while (readw(fb_regs + 0x6002) & 0x4) udelay(1); writew(0, fb_regs + 0x60f0); writew(cmap->start + i, fb_regs + 0x60b8); writew(cmap->red[i], fb_regs + 0x60b2); writew(cmap->green[i], fb_regs + 0x60b4); writew(cmap->blue[i], fb_regs + 0x60b6); writew(0xff, fb_regs + 0x60f0); udelay(100); } writew(0xffff, fb_regs + 0x60ba); return 0; } static int hpfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { struct hpfb_par par; if(con==-1) { hpfb_get_par(&par); hpfb_encode_var(var, &par); } else *var=fb_display[con].var; return 0; } static int hpfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { int err; if ((err=do_fb_set_var(var, 1))) return err; return 0; } static void hpfb_encode_fix(struct fb_fix_screeninfo *fix, struct hpfb_par *par) { memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "HP300 Topcat"); /* * X works, but screen wraps ... */ fix->smem_start=(char *)fb_start; fix->smem_len=fb_size; fix->type = FB_TYPE_PACKED_PIXELS; fix->visual = FB_VISUAL_PSEUDOCOLOR; fix->xpanstep=0; fix->ypanstep=0; fix->ywrapstep=0; fix->line_length=fb_line_length; } static int hpfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) { struct hpfb_par par; hpfb_get_par(&par); hpfb_encode_fix(fix, &par); return 0; } static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h) { while (readb(fb_regs + BUSY) & fb_bitmask); writeb(0x3, fb_regs + WMRR); writew(x0, fb_regs + SOURCE_X); writew(y0, fb_regs + SOURCE_Y); writew(x1, fb_regs + DEST_X); writew(y1, fb_regs + DEST_Y); writew(h, fb_regs + WHEIGHT); writew(w, fb_regs + WWIDTH); writeb(fb_bitmask, fb_regs + WMOVE); } static int hpfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, int con, struct fb_info *info) { return -EINVAL; } static int hpfb_switch(int con, struct fb_info *info) { do_fb_set_var(&fb_display[con].var,1); currcon=con; return 0; } /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ static void hpfb_blank(int blank, struct fb_info *info) { /* Not supported */ } static int hpfb_open(struct fb_info *info, int user) { /* * Nothing, only a usage count for the moment */ MOD_INC_USE_COUNT; return(0); } static void hpfb_set_disp(int con) { struct fb_fix_screeninfo fix; struct display *display; if (con >= 0) display = &fb_display[con]; else display = &disp; /* used during initialization */ hpfb_get_fix(&fix, con, 0); display->screen_base = fix.smem_start; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; display->ypanstep = fix.ypanstep; display->ywrapstep = fix.ywrapstep; display->line_length = fix.line_length; display->next_line = fix.line_length; display->can_soft_blank = 0; display->inverse = 0; display->dispsw = &fbcon_cfb8; } static int hpfb_release(struct fb_info *info, int user) { MOD_DEC_USE_COUNT; return(0); } static struct fb_ops hpfb_ops = { hpfb_open, hpfb_release, hpfb_get_fix, hpfb_get_var, hpfb_set_var, hpfb_get_cmap, hpfb_set_cmap, NULL, hpfb_ioctl }; #define TOPCAT_FBOMSB 0x5d #define TOPCAT_FBOLSB 0x5f __initfunc(int hpfb_init_one(unsigned long base)) { unsigned long fboff; fboff = (readb(base + TOPCAT_FBOMSB) << 8) | readb(base + TOPCAT_FBOLSB); fb_start = 0xf0000000 | (readb(base + fboff) << 16); fb_regs = base; #if 0 /* This is the magic incantation NetBSD uses to make Catseye boards work. */ writeb(0, base+0x4800); writeb(0, base+0x4510); writeb(0, base+0x4512); writeb(0, base+0x4514); writeb(0, base+0x4516); writeb(0x90, base+0x4206); #endif /* * Fill in the available video resolution */ hpfb_defined.xres = 1024; hpfb_defined.yres = 768; hpfb_defined.xres_virtual = 1024; hpfb_defined.yres_virtual = 768; hpfb_defined.bits_per_pixel = 8; /* * Give the hardware a bit of a prod and work out how many bits per * pixel are supported. */ writeb(0xff, base + TC_WEN); writeb(0xff, base + TC_FBEN); writeb(0xff, fb_start); fb_bitmask = readb(fb_start); /* * Enable reading/writing of all the planes. */ writeb(fb_bitmask, base + TC_WEN); writeb(fb_bitmask, base + TC_REN); writeb(fb_bitmask, base + TC_FBEN); writeb(0x1, base + TC_NBLANK); /* * Let there be consoles.. */ strcpy(fb_info.modename, "Topcat"); fb_info.changevar = NULL; fb_info.node = -1; fb_info.fbops = &hpfb_ops; fb_info.disp = &disp; fb_info.switch_con = &hpfb_switch; fb_info.updatevar = &fb_update_var; fb_info.blank = &hpfb_blank; do_fb_set_var(&hpfb_defined, 1); hpfb_get_var(&disp.var, -1, &fb_info); hpfb_set_disp(-1); if (register_framebuffer(&fb_info) < 0) return 1; return 0; } /* * Check that the secondary ID indicates that we have some hope of working with this * framebuffer. The catseye boards are pretty much like topcats and we can muddle through. */ #define topcat_sid_ok(x) (((x) == DIO_ID2_LRCATSEYE) || ((x) == DIO_ID2_HRCCATSEYE) \ || ((x) == DIO_ID2_HRMCATSEYE) || ((x) == DIO_ID2_TOPCAT)) /* * Initialise the framebuffer */ __initfunc(unsigned long hpfb_init(unsigned long mem_start)) { unsigned int sid; /* Topcats can be on the internal IO bus or real DIO devices. * The internal variant sits at 0xf0560000; it has primary * and secondary ID registers just like the DIO version. * So we merge the two detection routines. * * Perhaps this #define should be in a global header file: * I believe it's common to all internal fbs, not just topcat. */ #define INTFBADDR 0xf0560000 if (hwreg_present((void *)INTFBADDR) && (DIO_ID(INTFBADDR) == DIO_ID_FBUFFER) && topcat_sid_ok(sid = DIO_SECID(INTFBADDR))) { printk("Internal Topcat found (secondary id %02x)\n", sid); hpfb_init_one(INTFBADDR); } else { int sc = dio_find(DIO_ID_FBUFFER); if (sc) { unsigned long addr = (unsigned long)dio_scodetoviraddr(sc); unsigned int sid = DIO_SECID(addr); if (topcat_sid_ok(sid)) { printk("Topcat found at DIO select code %02x " "(secondary id %02x)\n", sc, sid); hpfb_init_one(addr); } } } return mem_start; } __initfunc(void hpfb_setup(char *options, int *ints)) { }