X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fvideo%2Fpm2fb.c;h=a560a2223825ae74ba600b75f8853a6f5c8fb716;hb=refs%2Fheads%2Fvserver;hp=483b07062e6eca344d02c83a7dfc076d55f7a08a;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 483b07062..a560a2223 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -11,11 +11,11 @@ * and additional input from James Simmon's port of Hannu Mallat's tdfx * driver. * - * $Id$ - * - * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. - * I have no access to other pm2fb implementations, and cannot test - * on them. Therefore for now I am omitting Sparc and CVision code. + * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I + * have no access to other pm2fb implementations. Sparc (and thus + * hopefully other big-endian) devices now work, thanks to a lot of + * testing work by Ron Murray. I have no access to CVision hardware, + * and therefore for now I am omitting the CVision code. * * Multiple boards support has been on the TODO list for ages. * Don't expect this to change. @@ -27,13 +27,12 @@ * */ -#include #include +#include #include #include #include #include -#include #include #include #include @@ -47,10 +46,6 @@ #error "The endianness of the target host has not been defined." #endif -#if defined(__BIG_ENDIAN) && !defined(__sparc__) -#define PM2FB_BE_APERTURE -#endif - #if !defined(CONFIG_PCI) #error "Only generic PCI cards supported." #endif @@ -65,7 +60,7 @@ /* * Driver data */ -static char *mode __initdata = NULL; +static char *mode __devinitdata = NULL; /* * The XFree GLINT driver will (I think to implement hardware cursor @@ -76,8 +71,8 @@ static char *mode __initdata = NULL; * these flags allow the user to specify that requests for +ve sync * should be silently turned in -ve sync. */ -static int lowhsync __initdata = 0; -static int lowvsync __initdata = 0; +static int lowhsync; +static int lowvsync; /* * The hardware state of the graphics card that isn't part of the @@ -87,17 +82,21 @@ struct pm2fb_par { pm2type_t type; /* Board type */ u32 fb_size; /* framebuffer memory size */ - unsigned char* v_fb; /* virtual address of frame buffer */ - unsigned char* v_regs; /* virtual address of p_regs */ + unsigned char __iomem *v_fb; /* virtual address of frame buffer */ + unsigned char __iomem *v_regs;/* virtual address of p_regs */ u32 memclock; /* memclock */ u32 video; /* video flags before blanking */ + u32 mem_config; /* MemConfig reg at probe */ + u32 mem_control; /* MemControl reg at probe */ + u32 boot_address; /* BootAddress reg at probe */ + u32 palette[16]; }; /* * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo * if we don't use modedb. */ -static struct fb_fix_screeninfo pm2fb_fix __initdata = { +static struct fb_fix_screeninfo pm2fb_fix __devinitdata = { .id = "", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, @@ -108,10 +107,9 @@ static struct fb_fix_screeninfo pm2fb_fix __initdata = { }; /* - * Default video mode. In case the modedb doesn't work, or we're - * a module (in which case modedb doesn't really work). + * Default video mode. In case the modedb doesn't work. */ -static struct fb_var_screeninfo pm2fb_var __initdata = { +static struct fb_var_screeninfo pm2fb_var __devinitdata = { /* "640x480, 8 bpp @ 60 Hz */ .xres = 640, .yres = 480, @@ -139,27 +137,27 @@ static struct fb_var_screeninfo pm2fb_var __initdata = { * Utility functions */ -inline static u32 RD32(unsigned char* base, s32 off) +static inline u32 RD32(unsigned char __iomem *base, s32 off) { return fb_readl(base + off); } -inline static void WR32(unsigned char* base, s32 off, u32 v) +static inline void WR32(unsigned char __iomem *base, s32 off, u32 v) { fb_writel(v, base + off); } -inline static u32 pm2_RD(struct pm2fb_par* p, s32 off) +static inline u32 pm2_RD(struct pm2fb_par* p, s32 off) { return RD32(p->v_regs, off); } -inline static void pm2_WR(struct pm2fb_par* p, s32 off, u32 v) +static inline void pm2_WR(struct pm2fb_par* p, s32 off, u32 v) { WR32(p->v_regs, off, v); } -inline static u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx) +static inline u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx) { int index = PM2R_RD_INDEXED_DATA; switch (p->type) { @@ -175,7 +173,7 @@ inline static u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx) return pm2_RD(p, index); } -inline static void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) +static inline void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) { int index = PM2R_RD_INDEXED_DATA; switch (p->type) { @@ -191,14 +189,7 @@ inline static void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) pm2_WR(p, index, v); } -inline static u32 pm2v_RDAC_RD(struct pm2fb_par* p, s32 idx) -{ - pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); - mb(); - return pm2_RD(p, PM2VR_RD_INDEXED_DATA); -} - -inline static void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) +static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) { pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); mb(); @@ -208,7 +199,7 @@ inline static void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT #define WAIT_FIFO(p,a) #else -inline static void WAIT_FIFO(struct pm2fb_par* p, u32 a) +static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) { while( pm2_RD(p, PM2R_IN_FIFO_SPACE) < a ); mb(); @@ -340,16 +331,6 @@ static void clear_palette(struct pm2fb_par* p) { } } -#if 0 -/* - * FIXME: - * The 2.4 driver calls this at init time, where it also sets the - * initial mode. I don't think the driver should touch the chip - * until the console sets a video mode. So I was calling this - * at the start of setting a mode. However, certainly on 1280x1024 - * depth 16 this causes the display to smear slightly. - * I don't know why. Guesses to jim.hague@acm.org. - */ static void reset_card(struct pm2fb_par* p) { if (p->type == PM2_TYPE_PERMEDIA2V) @@ -364,8 +345,14 @@ static void reset_card(struct pm2fb_par* p) pm2_WR(p, PM2R_FIFO_DISCON, 1); mb(); #endif + + /* Restore stashed memory config information from probe */ + WAIT_FIFO(p, 3); + pm2_WR(p, PM2R_MEM_CONTROL, p->mem_control); + pm2_WR(p, PM2R_BOOT_ADDRESS, p->boot_address); + wmb(); + pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config); } -#endif static void reset_config(struct pm2fb_par* p) { @@ -425,27 +412,36 @@ static void reset_config(struct pm2fb_par* p) static void set_aperture(struct pm2fb_par* p, u32 depth) { + /* + * The hardware is little-endian. When used in big-endian + * hosts, the on-chip aperture settings are used where + * possible to translate from host to card byte order. + */ WAIT_FIFO(p, 4); #ifdef __LITTLE_ENDIAN - pm2_WR(p, PM2R_APERTURE_ONE, 0); - pm2_WR(p, PM2R_APERTURE_TWO, 0); + pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD); #else switch (depth) { - case 8: - case 24: - pm2_WR(p, PM2R_APERTURE_ONE, 0); - pm2_WR(p, PM2R_APERTURE_TWO, 1); + case 24: /* RGB->BGR */ + /* + * We can't use the aperture to translate host to + * card byte order here, so we switch to BGR mode + * in pm2fb_set_par(). + */ + case 8: /* B->B */ + pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD); break; - case 16: - pm2_WR(p, PM2R_APERTURE_ONE, 2); - pm2_WR(p, PM2R_APERTURE_TWO, 1); + case 16: /* HL->LH */ + pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_HALFWORDSWAP); break; - case 32: - pm2_WR(p, PM2R_APERTURE_ONE, 1); - pm2_WR(p, PM2R_APERTURE_TWO, 1); + case 32: /* RGBA->ABGR */ + pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_BYTESWAP); break; } #endif + + // We don't use aperture two, so this may be superflous + pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD); } static void set_color(struct pm2fb_par* p, unsigned char regno, @@ -461,6 +457,28 @@ static void set_color(struct pm2fb_par* p, unsigned char regno, pm2_WR(p, PM2R_RD_PALETTE_DATA, b); } +static void set_memclock(struct pm2fb_par* par, u32 clk) +{ + int i; + unsigned char m, n, p; + + pm2_mnp(clk, &m, &n, &p); + WAIT_FIFO(par, 10); + pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6); + wmb(); + pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m); + pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n); + wmb(); + pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p); + wmb(); + pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS); + rmb(); + for (i = 256; + i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED); + i--) + ; +} + static void set_pixclock(struct pm2fb_par* par, u32 clk) { int i; @@ -501,6 +519,8 @@ static void set_video(struct pm2fb_par* p, u32 video) { u32 vsync; vsync = video; + + DPRINTK("video = 0x%x\n", video); /* * The hardware cursor needs +vsync to recognise vert retrace. @@ -615,15 +635,23 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->blue.offset = 0; var->blue.length = 5; break; - case 24: + case 32: + var->transp.offset = 24; + var->transp.length = 8; var->red.offset = 16; var->green.offset = 8; var->blue.offset = 0; var->red.length = var->green.length = var->blue.length = 8; - case 32: + break; + case 24: +#ifdef __BIG_ENDIAN + var->red.offset = 0; + var->blue.offset = 16; +#else var->red.offset = 16; - var->green.offset = 8; var->blue.offset = 0; +#endif + var->green.offset = 8; var->red.length = var->green.length = var->blue.length = 8; break; } @@ -645,7 +673,7 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) */ static int pm2fb_set_par(struct fb_info *info) { - struct pm2fb_par *par = (struct pm2fb_par *) info->par; + struct pm2fb_par *par = info->par; u32 pixclock; u32 width, height, depth; u32 hsstart, hsend, hbend, htotal; @@ -653,15 +681,18 @@ static int pm2fb_set_par(struct fb_info *info) u32 stride; u32 base; u32 video = 0; - u32 clrmode = PM2F_RD_COLOR_MODE_RGB; + u32 clrmode = PM2F_RD_COLOR_MODE_RGB | PM2F_RD_GUI_ACTIVE; u32 txtmap = 0; u32 pixsize = 0; u32 clrformat = 0; u32 xres; int data64; + reset_card(par); reset_config(par); clear_palette(par); + if ( par->memclock ) + set_memclock(par, par->memclock); width = (info->var.xres_virtual + 7) & ~7; height = info->var.yres_virtual; @@ -715,14 +746,13 @@ static int pm2fb_set_par(struct fb_info *info) } if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE) video |= PM2F_LINE_DOUBLE; - if (info->var.activate==FB_ACTIVATE_NOW) + if ((info->var.activate & FB_ACTIVATE_MASK)==FB_ACTIVATE_NOW) video |= PM2F_VIDEO_ENABLE; par->video = video; info->fix.visual = (depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - info->fix.line_length = - info->var.xres * ((info->var.bits_per_pixel + 7) >> 3); + info->fix.line_length = info->var.xres * depth / 8; info->cmap.len = 256; /* @@ -746,24 +776,21 @@ static int pm2fb_set_par(struct fb_info *info) break; case 16: pm2_WR(par, PM2R_FB_READ_PIXEL, 1); - clrmode |= PM2F_RD_TRUECOLOR | 0x06; + clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB565; txtmap = PM2F_TEXTEL_SIZE_16; pixsize = 1; clrformat = 0x70; break; case 32: pm2_WR(par, PM2R_FB_READ_PIXEL, 2); - clrmode |= PM2F_RD_TRUECOLOR | 0x08; + clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGBA8888; txtmap = PM2F_TEXTEL_SIZE_32; pixsize = 2; clrformat = 0x20; break; case 24: pm2_WR(par, PM2R_FB_READ_PIXEL, 4); - clrmode |= PM2F_RD_TRUECOLOR | 0x09; -#ifndef PM2FB_BE_APERTURE - clrmode &= ~PM2F_RD_COLOR_MODE_RGB; -#endif + clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB888; txtmap = PM2F_TEXTEL_SIZE_24; pixsize = 4; clrformat = 0x20; @@ -794,8 +821,7 @@ static int pm2fb_set_par(struct fb_info *info) WAIT_FIFO(par, 4); switch (par->type) { case PM2_TYPE_PERMEDIA2: - pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, - PM2F_RD_COLOR_MODE_RGB | PM2F_RD_GUI_ACTIVE | clrmode); + pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode); break; case PM2_TYPE_PERMEDIA2V: pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize); @@ -803,6 +829,8 @@ static int pm2fb_set_par(struct fb_info *info) break; } set_pixclock(par, pixclock); + DPRINTK("Setting graphics mode at %dx%d depth %d\n", + info->var.xres, info->var.yres, info->var.bits_per_pixel); return 0; } @@ -825,7 +853,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - struct pm2fb_par *par = (struct pm2fb_par *) info->par; + struct pm2fb_par *par = info->par; if (regno >= info->cmap.len) /* no. of hw registers */ return 1; @@ -843,7 +871,8 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, * var->{color}.offset contains start of bitfield * var->{color}.length contains length of bitfield * {hardwarespecific} contains width of DAC - * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) + * cmap[X] is programmed to + * (X << red.offset) | (X << green.offset) | (X << blue.offset) * RAMDAC[X] is programmed to (red, green, blue) * * Pseudocolor: @@ -856,8 +885,9 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, * does not use RAMDAC (usually has 3 of them). * var->{color}.offset contains start of bitfield * var->{color}.length contains length of bitfield - * cmap is programmed to (red << red.offset) | (green << green.offset) | - * (blue << blue.offset) | (transp << transp.offset) + * cmap is programmed to + * (red << red.offset) | (green << green.offset) | + * (blue << blue.offset) | (transp << transp.offset) * RAMDAC does not exist */ #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) @@ -868,7 +898,6 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, green = CNVT_TOHW(green, info->var.green.length); blue = CNVT_TOHW(blue, info->var.blue.length); transp = CNVT_TOHW(transp, info->var.transp.length); - set_color(par, regno, red, green, blue); break; case FB_VISUAL_DIRECTCOLOR: /* example here assumes 8 bit DAC. Might be different @@ -895,20 +924,18 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, switch (info->var.bits_per_pixel) { case 8: - /* Yes some hand held devices have this. */ - ((u8*)(info->pseudo_palette))[regno] = v; break; case 16: - ((u16*)(info->pseudo_palette))[regno] = v; - break; case 24: case 32: - ((u32*)(info->pseudo_palette))[regno] = v; + par->palette[regno] = v; break; } return 0; } - /* ... */ + else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) + set_color(par, regno, red, green, blue); + return 0; } @@ -927,7 +954,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green, static int pm2fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { - struct pm2fb_par *p = (struct pm2fb_par *) info->par; + struct pm2fb_par *p = info->par; u32 base; u32 depth; u32 xres; @@ -959,24 +986,31 @@ static int pm2fb_pan_display(struct fb_var_screeninfo *var, */ static int pm2fb_blank(int blank_mode, struct fb_info *info) { - struct pm2fb_par *par = (struct pm2fb_par *) info->par; + struct pm2fb_par *par = info->par; u32 video = par->video; + DPRINTK("blank_mode %d\n", blank_mode); + switch (blank_mode) { - case 0: /* Screen: On; HSync: On, VSync: On */ + case FB_BLANK_UNBLANK: + /* Screen: On */ + video |= PM2F_VIDEO_ENABLE; break; - case 1: /* Screen: Off; HSync: On, VSync: On */ + case FB_BLANK_NORMAL: + /* Screen: Off */ video &= ~PM2F_VIDEO_ENABLE; break; - case 2: /* Screen: Off; HSync: On, VSync: Off */ - video &= ~(PM2F_VIDEO_ENABLE | PM2F_VSYNC_MASK | PM2F_BLANK_LOW ); + case FB_BLANK_VSYNC_SUSPEND: + /* VSync: Off */ + video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW ); break; - case 3: /* Screen: Off; HSync: Off, VSync: On */ - video &= ~(PM2F_VIDEO_ENABLE | PM2F_HSYNC_MASK | PM2F_BLANK_LOW ); + case FB_BLANK_HSYNC_SUSPEND: + /* HSync: Off */ + video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW ); break; - case 4: /* Screen: Off; HSync: Off, VSync: Off */ - video &= ~(PM2F_VIDEO_ENABLE | PM2F_VSYNC_MASK | PM2F_HSYNC_MASK| - PM2F_BLANK_LOW); + case FB_BLANK_POWERDOWN: + /* HSync: Off, VSync: Off */ + video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK| PM2F_BLANK_LOW); break; } set_video(par, video); @@ -999,7 +1033,6 @@ static struct fb_ops pm2fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; /* @@ -1020,9 +1053,7 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, { struct pm2fb_par *default_par; struct fb_info *info; - int size, err; - u32 pci_mem_config; - int err_retval = -ENXIO; + int err, err_retval = -ENXIO; err = pci_enable_device(pdev); if ( err ) { @@ -1030,15 +1061,11 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, return err; } - size = sizeof(struct fb_info) + sizeof(struct pm2fb_par) + 256 * sizeof(u32); - - info = framebuffer_alloc(size, &pdev->dev); + info = framebuffer_alloc(sizeof(struct pm2fb_par), &pdev->dev); if ( !info ) return -ENOMEM; - memset(info, 0, size); - default_par = info->par; - + switch (pdev->device) { case PCI_DEVICE_ID_TI_TVP4020: strcpy(pm2fb_fix.id, "TVP4020"); @@ -1057,9 +1084,15 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, pm2fb_fix.mmio_start = pci_resource_start(pdev, 0); pm2fb_fix.mmio_len = PM2_REGS_SIZE; -#ifdef PM2FB_BE_APERTURE +#if defined(__BIG_ENDIAN) + /* + * PM2 has a 64k register file, mapped twice in 128k. Lower + * map is little-endian, upper map is big-endian. + */ pm2fb_fix.mmio_start += PM2_REGS_SIZE; + DPRINTK("Adjusting register base for big-endian.\n"); #endif + DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start); /* Registers - request region and map it. */ if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len, @@ -1076,9 +1109,32 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, goto err_exit_neither; } + /* Stash away memory register info for use when we reset the board */ + default_par->mem_control = pm2_RD(default_par, PM2R_MEM_CONTROL); + default_par->boot_address = pm2_RD(default_par, PM2R_BOOT_ADDRESS); + default_par->mem_config = pm2_RD(default_par, PM2R_MEM_CONFIG); + DPRINTK("MemControl 0x%x BootAddress 0x%x MemConfig 0x%x\n", + default_par->mem_control, default_par->boot_address, + default_par->mem_config); + + if(default_par->mem_control == 0 && + default_par->boot_address == 0x31 && + default_par->mem_config == 0x259fffff && + pdev->subsystem_vendor == 0x1048 && + pdev->subsystem_device == 0x0a31) { + DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n", + pdev->subsystem_vendor, pdev->subsystem_device); + DPRINTK("We have not been initialized by VGA BIOS " + "and are running on an Elsa Winner 2000 Office\n"); + DPRINTK("Initializing card timings manually...\n"); + default_par->mem_control=0; + default_par->boot_address=0x20; + default_par->mem_config=0xe6002021; + default_par->memclock=100000; + } + /* Now work out how big lfb is going to be. */ - pci_mem_config = RD32(default_par->v_regs, PM2R_MEM_CONFIG); - switch(pci_mem_config & PM2F_MEM_CONFIG_RAM_MASK) { + switch(default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) { case PM2F_MEM_BANKS_1: default_par->fb_size=0x200000; break; @@ -1112,17 +1168,15 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, info->fbops = &pm2fb_ops; info->fix = pm2fb_fix; - info->par = default_par; - info->pseudo_palette = (void *)(default_par + 1); - info->flags = FBINFO_FLAG_DEFAULT; + info->pseudo_palette = default_par->palette; + info->flags = FBINFO_DEFAULT | + FBINFO_HWACCEL_YPAN; -#ifndef MODULE if (!mode) mode = "640x480@60"; err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8); if (!err || err == 4) -#endif info->var = pm2fb_var; if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) @@ -1144,10 +1198,10 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, err_exit_all: fb_dealloc_cmap(&info->cmap); err_exit_both: - iounmap((void*) pm2fb_fix.smem_start); + iounmap(info->screen_base); release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); err_exit_mmio: - iounmap((void*) pm2fb_fix.mmio_start); + iounmap(default_par->v_regs); release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); err_exit_neither: framebuffer_release(info); @@ -1165,12 +1219,13 @@ static void __devexit pm2fb_remove(struct pci_dev *pdev) { struct fb_info* info = pci_get_drvdata(pdev); struct fb_fix_screeninfo* fix = &info->fix; - + struct pm2fb_par *par = info->par; + unregister_framebuffer(info); - iounmap((void*) fix->smem_start); + iounmap(info->screen_base); release_mem_region(fix->smem_start, fix->smem_len); - iounmap((void*) fix->mmio_start); + iounmap(par->v_regs); release_mem_region(fix->mmio_start, fix->mmio_len); pci_set_drvdata(pdev, NULL); @@ -1200,34 +1255,13 @@ static struct pci_driver pm2fb_driver = { MODULE_DEVICE_TABLE(pci, pm2fb_id_table); -/* - * Initialization - */ - -int __init pm2fb_init(void) -{ - return pci_module_init(&pm2fb_driver); -} - -/* - * Cleanup - */ - -static void __exit pm2fb_exit(void) -{ - pci_unregister_driver(&pm2fb_driver); -} - -/* - * Setup - */ - +#ifndef MODULE /** * Parse user speficied options. * * This is, comma-separated options following `video=pm2fb:'. */ -int __init pm2fb_setup(char *options) +static int __init pm2fb_setup(char *options) { char* this_opt; @@ -1247,23 +1281,46 @@ int __init pm2fb_setup(char *options) } return 0; } +#endif -/* ------------------------------------------------------------------------- */ +static int __init pm2fb_init(void) +{ +#ifndef MODULE + char *option = NULL; -/* ------------------------------------------------------------------------- */ + if (fb_get_options("pm2fb", &option)) + return -ENODEV; + pm2fb_setup(option); +#endif + return pci_register_driver(&pm2fb_driver); +} +module_init(pm2fb_init); + +#ifdef MODULE +/* + * Cleanup + */ + +static void __exit pm2fb_exit(void) +{ + pci_unregister_driver(&pm2fb_driver); +} +#endif #ifdef MODULE -module_init(pm2fb_init); -#endif module_exit(pm2fb_exit); -MODULE_PARM(mode,"s"); -MODULE_PARM(lowhsync,"i"); -MODULE_PARM(lowvsync,"i"); +module_param(mode, charp, 0); +MODULE_PARM_DESC(mode, "Preferred video mode e.g. '648x480-8@60'"); +module_param(lowhsync, bool, 0); +MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode"); +module_param(lowvsync, bool, 0); +MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode"); MODULE_AUTHOR("Jim Hague "); MODULE_DESCRIPTION("Permedia2 framebuffer device driver"); MODULE_LICENSE("GPL"); +#endif