URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [video/] [hpfb.c] - Rev 1275
Go to most recent revision | Compare with Previous | Blame | View Log
/* * HP300 Topcat framebuffer support (derived from macfb of all things) * Phil Blundell <philb@gnu.org> 1998 * * Should this be moved to drivers/dio/video/ ? -- Peter Maydell * No! -- Jes */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/tty.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/fb.h> #include <linux/dio.h> #include <asm/io.h> #include <asm/blinken.h> #include <asm/hwtest.h> #include <video/fbcon.h> #include <video/fbcon-mfb.h> #include <video/fbcon-cfb2.h> #include <video/fbcon-cfb4.h> #include <video/fbcon-cfb8.h> 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;i<ARRAY_SIZE(var->reserved);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 (in_be16(fb_regs + 0x6002) & 0x4) udelay(1); out_be16(fb_regs + 0x60f0, 0); out_be16(fb_regs + 0x60b8, cmap->start + i); out_be16(fb_regs + 0x60b2, cmap->red[i]); out_be16(fb_regs + 0x60b4, cmap->green[i]); out_be16(fb_regs + 0x60b6, cmap->blue[i]); out_be16(fb_regs + 0x60f0, 0xff); udelay(100); } out_be16(fb_regs + 0x60ba, 0xffff); 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=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 (in_8(fb_regs + BUSY) & fb_bitmask); out_8(fb_regs + WMRR, 0x3); out_be16(fb_regs + SOURCE_X, x0); out_be16(fb_regs + SOURCE_Y, y0); out_be16(fb_regs + DEST_X, x1); out_be16(fb_regs + DEST_Y, y1); out_be16(fb_regs + WHEIGHT, h); out_be16(fb_regs + WWIDTH, w); out_8(fb_regs + WMOVE, fb_bitmask); } 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 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 = (char *)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; #ifdef FBCON_HAS_CFB8 display->dispsw = &fbcon_cfb8; #else display->dispsw = &fbcon_dummy; #endif } static struct fb_ops hpfb_ops = { owner: THIS_MODULE, fb_get_fix: hpfb_get_fix, fb_get_var: hpfb_get_var, fb_set_var: hpfb_set_var, fb_get_cmap: hpfb_get_cmap, fb_set_cmap: hpfb_set_cmap, }; #define TOPCAT_FBOMSB 0x5d #define TOPCAT_FBOLSB 0x5f int __init hpfb_init_one(unsigned long base) { unsigned long fboff; fboff = (in_8(base + TOPCAT_FBOMSB) << 8) | in_8(base + TOPCAT_FBOLSB); fb_start = 0xf0000000 | (in_8(base + fboff) << 16); fb_regs = base; #if 0 /* This is the magic incantation NetBSD uses to make Catseye boards work. */ out_8(base+0x4800, 0); out_8(base+0x4510, 0); out_8(base+0x4512, 0); out_8(base+0x4514, 0); out_8(base+0x4516, 0); out_8(base+0x4206, 0x90); #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. */ out_8(base + TC_WEN, 0xff); out_8(base + TC_FBEN, 0xff); out_8(fb_start, 0xff); fb_bitmask = in_8(fb_start); /* * Enable reading/writing of all the planes. */ out_8(base + TC_WEN, fb_bitmask); out_8(base + TC_REN, fb_bitmask); out_8(base + TC_FBEN, fb_bitmask); out_8(base + TC_NBLANK, 0x1); /* * 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; fb_info.flags = FBINFO_FLAG_DEFAULT; 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 */ int __init hpfb_init(void) { 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 0; } MODULE_LICENSE("GPL");
Go to most recent revision | Compare with Previous | Blame | View Log