X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=drivers%2Fvideo%2Fcg6.c;h=549891d76ef5dba2728d905ff75217b95cf26f70;hb=8002cedc1adbf51e2d56091534ef7551b88329b4;hp=7aab91ead6818ee70d7484aedacc001a6ecd8739;hpb=cf41f8ac386e8d62122e7e394b4c6b3e3ab30ede;p=linux-2.6-omap-h63xx.git diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 7aab91ead68..549891d76ef 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -1,6 +1,6 @@ /* cg6.c: CGSIX (GX, GXplus, TGX) frame buffer driver * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) @@ -19,8 +19,7 @@ #include #include -#include -#include +#include #include #include "sbuslib.h" @@ -38,6 +37,7 @@ static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *); static int cg6_sync(struct fb_info *); static int cg6_mmap(struct fb_info *, struct vm_area_struct *); static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long); +static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area); /* * Frame buffer operations @@ -48,7 +48,7 @@ static struct fb_ops cg6_ops = { .fb_setcolreg = cg6_setcolreg, .fb_blank = cg6_blank, .fb_fillrect = cg6_fillrect, - .fb_copyarea = cfb_copyarea, + .fb_copyarea = cg6_copyarea, .fb_imageblit = cg6_imageblit, .fb_sync = cg6_sync, .fb_mmap = cg6_mmap, @@ -65,41 +65,41 @@ static struct fb_ops cg6_ops = { * The FBC could be the frame buffer control * The FHC could is the frame buffer hardware control. */ -#define CG6_ROM_OFFSET 0x0UL -#define CG6_BROOKTREE_OFFSET 0x200000UL -#define CG6_DHC_OFFSET 0x240000UL -#define CG6_ALT_OFFSET 0x280000UL -#define CG6_FHC_OFFSET 0x300000UL -#define CG6_THC_OFFSET 0x301000UL -#define CG6_FBC_OFFSET 0x700000UL -#define CG6_TEC_OFFSET 0x701000UL -#define CG6_RAM_OFFSET 0x800000UL +#define CG6_ROM_OFFSET 0x0UL +#define CG6_BROOKTREE_OFFSET 0x200000UL +#define CG6_DHC_OFFSET 0x240000UL +#define CG6_ALT_OFFSET 0x280000UL +#define CG6_FHC_OFFSET 0x300000UL +#define CG6_THC_OFFSET 0x301000UL +#define CG6_FBC_OFFSET 0x700000UL +#define CG6_TEC_OFFSET 0x701000UL +#define CG6_RAM_OFFSET 0x800000UL /* FHC definitions */ -#define CG6_FHC_FBID_SHIFT 24 -#define CG6_FHC_FBID_MASK 255 -#define CG6_FHC_REV_SHIFT 20 -#define CG6_FHC_REV_MASK 15 -#define CG6_FHC_FROP_DISABLE (1 << 19) -#define CG6_FHC_ROW_DISABLE (1 << 18) -#define CG6_FHC_SRC_DISABLE (1 << 17) -#define CG6_FHC_DST_DISABLE (1 << 16) -#define CG6_FHC_RESET (1 << 15) -#define CG6_FHC_LITTLE_ENDIAN (1 << 13) -#define CG6_FHC_RES_MASK (3 << 11) -#define CG6_FHC_1024 (0 << 11) -#define CG6_FHC_1152 (1 << 11) -#define CG6_FHC_1280 (2 << 11) -#define CG6_FHC_1600 (3 << 11) -#define CG6_FHC_CPU_MASK (3 << 9) -#define CG6_FHC_CPU_SPARC (0 << 9) -#define CG6_FHC_CPU_68020 (1 << 9) -#define CG6_FHC_CPU_386 (2 << 9) -#define CG6_FHC_TEST (1 << 8) -#define CG6_FHC_TEST_X_SHIFT 4 -#define CG6_FHC_TEST_X_MASK 15 -#define CG6_FHC_TEST_Y_SHIFT 0 -#define CG6_FHC_TEST_Y_MASK 15 +#define CG6_FHC_FBID_SHIFT 24 +#define CG6_FHC_FBID_MASK 255 +#define CG6_FHC_REV_SHIFT 20 +#define CG6_FHC_REV_MASK 15 +#define CG6_FHC_FROP_DISABLE (1 << 19) +#define CG6_FHC_ROW_DISABLE (1 << 18) +#define CG6_FHC_SRC_DISABLE (1 << 17) +#define CG6_FHC_DST_DISABLE (1 << 16) +#define CG6_FHC_RESET (1 << 15) +#define CG6_FHC_LITTLE_ENDIAN (1 << 13) +#define CG6_FHC_RES_MASK (3 << 11) +#define CG6_FHC_1024 (0 << 11) +#define CG6_FHC_1152 (1 << 11) +#define CG6_FHC_1280 (2 << 11) +#define CG6_FHC_1600 (3 << 11) +#define CG6_FHC_CPU_MASK (3 << 9) +#define CG6_FHC_CPU_SPARC (0 << 9) +#define CG6_FHC_CPU_68020 (1 << 9) +#define CG6_FHC_CPU_386 (2 << 9) +#define CG6_FHC_TEST (1 << 8) +#define CG6_FHC_TEST_X_SHIFT 4 +#define CG6_FHC_TEST_X_MASK 15 +#define CG6_FHC_TEST_Y_SHIFT 0 +#define CG6_FHC_TEST_Y_MASK 15 /* FBC mode definitions */ #define CG6_FBC_BLIT_IGNORE 0x00000000 @@ -150,103 +150,103 @@ static struct fb_ops cg6_ops = { #define CG6_FBC_INDEX_MASK 0x00000030 /* THC definitions */ -#define CG6_THC_MISC_REV_SHIFT 16 -#define CG6_THC_MISC_REV_MASK 15 -#define CG6_THC_MISC_RESET (1 << 12) -#define CG6_THC_MISC_VIDEO (1 << 10) -#define CG6_THC_MISC_SYNC (1 << 9) -#define CG6_THC_MISC_VSYNC (1 << 8) -#define CG6_THC_MISC_SYNC_ENAB (1 << 7) -#define CG6_THC_MISC_CURS_RES (1 << 6) -#define CG6_THC_MISC_INT_ENAB (1 << 5) -#define CG6_THC_MISC_INT (1 << 4) -#define CG6_THC_MISC_INIT 0x9f +#define CG6_THC_MISC_REV_SHIFT 16 +#define CG6_THC_MISC_REV_MASK 15 +#define CG6_THC_MISC_RESET (1 << 12) +#define CG6_THC_MISC_VIDEO (1 << 10) +#define CG6_THC_MISC_SYNC (1 << 9) +#define CG6_THC_MISC_VSYNC (1 << 8) +#define CG6_THC_MISC_SYNC_ENAB (1 << 7) +#define CG6_THC_MISC_CURS_RES (1 << 6) +#define CG6_THC_MISC_INT_ENAB (1 << 5) +#define CG6_THC_MISC_INT (1 << 4) +#define CG6_THC_MISC_INIT 0x9f /* The contents are unknown */ struct cg6_tec { - volatile int tec_matrix; - volatile int tec_clip; - volatile int tec_vdc; + int tec_matrix; + int tec_clip; + int tec_vdc; }; struct cg6_thc { - uint thc_pad0[512]; - volatile uint thc_hs; /* hsync timing */ - volatile uint thc_hsdvs; - volatile uint thc_hd; - volatile uint thc_vs; /* vsync timing */ - volatile uint thc_vd; - volatile uint thc_refresh; - volatile uint thc_misc; - uint thc_pad1[56]; - volatile uint thc_cursxy; /* cursor x,y position (16 bits each) */ - volatile uint thc_cursmask[32]; /* cursor mask bits */ - volatile uint thc_cursbits[32]; /* what to show where mask enabled */ + u32 thc_pad0[512]; + u32 thc_hs; /* hsync timing */ + u32 thc_hsdvs; + u32 thc_hd; + u32 thc_vs; /* vsync timing */ + u32 thc_vd; + u32 thc_refresh; + u32 thc_misc; + u32 thc_pad1[56]; + u32 thc_cursxy; /* cursor x,y position (16 bits each) */ + u32 thc_cursmask[32]; /* cursor mask bits */ + u32 thc_cursbits[32]; /* what to show where mask enabled */ }; struct cg6_fbc { - u32 xxx0[1]; - volatile u32 mode; - volatile u32 clip; - u32 xxx1[1]; - volatile u32 s; - volatile u32 draw; - volatile u32 blit; - volatile u32 font; - u32 xxx2[24]; - volatile u32 x0, y0, z0, color0; - volatile u32 x1, y1, z1, color1; - volatile u32 x2, y2, z2, color2; - volatile u32 x3, y3, z3, color3; - volatile u32 offx, offy; - u32 xxx3[2]; - volatile u32 incx, incy; - u32 xxx4[2]; - volatile u32 clipminx, clipminy; - u32 xxx5[2]; - volatile u32 clipmaxx, clipmaxy; - u32 xxx6[2]; - volatile u32 fg; - volatile u32 bg; - volatile u32 alu; - volatile u32 pm; - volatile u32 pixelm; - u32 xxx7[2]; - volatile u32 patalign; - volatile u32 pattern[8]; - u32 xxx8[432]; - volatile u32 apointx, apointy, apointz; - u32 xxx9[1]; - volatile u32 rpointx, rpointy, rpointz; - u32 xxx10[5]; - volatile u32 pointr, pointg, pointb, pointa; - volatile u32 alinex, aliney, alinez; - u32 xxx11[1]; - volatile u32 rlinex, rliney, rlinez; - u32 xxx12[5]; - volatile u32 liner, lineg, lineb, linea; - volatile u32 atrix, atriy, atriz; - u32 xxx13[1]; - volatile u32 rtrix, rtriy, rtriz; - u32 xxx14[5]; - volatile u32 trir, trig, trib, tria; - volatile u32 aquadx, aquady, aquadz; - u32 xxx15[1]; - volatile u32 rquadx, rquady, rquadz; - u32 xxx16[5]; - volatile u32 quadr, quadg, quadb, quada; - volatile u32 arectx, arecty, arectz; - u32 xxx17[1]; - volatile u32 rrectx, rrecty, rrectz; - u32 xxx18[5]; - volatile u32 rectr, rectg, rectb, recta; + u32 xxx0[1]; + u32 mode; + u32 clip; + u32 xxx1[1]; + u32 s; + u32 draw; + u32 blit; + u32 font; + u32 xxx2[24]; + u32 x0, y0, z0, color0; + u32 x1, y1, z1, color1; + u32 x2, y2, z2, color2; + u32 x3, y3, z3, color3; + u32 offx, offy; + u32 xxx3[2]; + u32 incx, incy; + u32 xxx4[2]; + u32 clipminx, clipminy; + u32 xxx5[2]; + u32 clipmaxx, clipmaxy; + u32 xxx6[2]; + u32 fg; + u32 bg; + u32 alu; + u32 pm; + u32 pixelm; + u32 xxx7[2]; + u32 patalign; + u32 pattern[8]; + u32 xxx8[432]; + u32 apointx, apointy, apointz; + u32 xxx9[1]; + u32 rpointx, rpointy, rpointz; + u32 xxx10[5]; + u32 pointr, pointg, pointb, pointa; + u32 alinex, aliney, alinez; + u32 xxx11[1]; + u32 rlinex, rliney, rlinez; + u32 xxx12[5]; + u32 liner, lineg, lineb, linea; + u32 atrix, atriy, atriz; + u32 xxx13[1]; + u32 rtrix, rtriy, rtriz; + u32 xxx14[5]; + u32 trir, trig, trib, tria; + u32 aquadx, aquady, aquadz; + u32 xxx15[1]; + u32 rquadx, rquady, rquadz; + u32 xxx16[5]; + u32 quadr, quadg, quadb, quada; + u32 arectx, arecty, arectz; + u32 xxx17[1]; + u32 rrectx, rrecty, rrectz; + u32 xxx18[5]; + u32 rectr, rectg, rectb, recta; }; struct bt_regs { - volatile u32 addr; - volatile u32 color_map; - volatile u32 control; - volatile u32 cursor; + u32 addr; + u32 color_map; + u32 control; + u32 cursor; }; struct cg6_par { @@ -255,20 +255,19 @@ struct cg6_par { struct cg6_fbc __iomem *fbc; struct cg6_thc __iomem *thc; struct cg6_tec __iomem *tec; - volatile u32 __iomem *fhc; + u32 __iomem *fhc; u32 flags; #define CG6_FLAG_BLANKED 0x00000001 unsigned long physbase; + unsigned long which_io; unsigned long fbsize; - - struct sbus_dev *sdev; }; static int cg6_sync(struct fb_info *info) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; struct cg6_fbc __iomem *fbc = par->fbc; int limit = 10000; @@ -282,24 +281,24 @@ static int cg6_sync(struct fb_info *info) } /** - * cg6_fillrect - REQUIRED function. Can use generic routines if - * non acclerated hardware and packed pixel based. - * Draws a rectangle on the screen. + * cg6_fillrect - Draws a rectangle on the screen. * - * @info: frame buffer structure that represents a single frame buffer - * @rect: structure defining the rectagle and operation. + * @info: frame buffer structure that represents a single frame buffer + * @rect: structure defining the rectagle and operation. */ static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; struct cg6_fbc __iomem *fbc = par->fbc; unsigned long flags; s32 val; - /* XXX doesn't handle ROP_XOR */ + /* CG6 doesn't handle ROP_XOR */ spin_lock_irqsave(&par->lock, flags); + cg6_sync(info); + sbus_writel(rect->color, &fbc->fg); sbus_writel(~(u32)0, &fbc->pixelm); sbus_writel(0xea80ff00, &fbc->alu); @@ -317,16 +316,56 @@ static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect) } /** - * cg6_imageblit - REQUIRED function. Can use generic routines if - * non acclerated hardware and packed pixel based. - * Copies a image from system memory to the screen. + * cg6_copyarea - Copies one area of the screen to another area. + * + * @info: frame buffer structure that represents a single frame buffer + * @area: Structure providing the data to copy the framebuffer contents + * from one region to another. * - * @info: frame buffer structure that represents a single frame buffer - * @image: structure defining the image. + * This drawing operation copies a rectangular area from one area of the + * screen to another area. + */ +static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct cg6_par *par = (struct cg6_par *)info->par; + struct cg6_fbc __iomem *fbc = par->fbc; + unsigned long flags; + int i; + + spin_lock_irqsave(&par->lock, flags); + + cg6_sync(info); + + sbus_writel(0xff, &fbc->fg); + sbus_writel(0x00, &fbc->bg); + sbus_writel(~0, &fbc->pixelm); + sbus_writel(0xe880cccc, &fbc->alu); + sbus_writel(0, &fbc->s); + sbus_writel(0, &fbc->clip); + + sbus_writel(area->sy, &fbc->y0); + sbus_writel(area->sx, &fbc->x0); + sbus_writel(area->sy + area->height - 1, &fbc->y1); + sbus_writel(area->sx + area->width - 1, &fbc->x1); + sbus_writel(area->dy, &fbc->y2); + sbus_writel(area->dx, &fbc->x2); + sbus_writel(area->dy + area->height - 1, &fbc->y3); + sbus_writel(area->dx + area->width - 1, &fbc->x3); + do { + i = sbus_readl(&fbc->blit); + } while (i < 0 && (i & 0x20000000)); + spin_unlock_irqrestore(&par->lock, flags); +} + +/** + * cg6_imageblit - Copies a image from system memory to the screen. + * + * @info: frame buffer structure that represents a single frame buffer + * @image: structure defining the image. */ static void cg6_imageblit(struct fb_info *info, const struct fb_image *image) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; struct cg6_fbc __iomem *fbc = par->fbc; const u8 *data = image->data; unsigned long flags; @@ -364,7 +403,7 @@ static void cg6_imageblit(struct fb_info *info, const struct fb_image *image) sbus_writel(y, &fbc->y0); sbus_writel(x, &fbc->x0); sbus_writel(x + 32 - 1, &fbc->x1); - + val = ((u32)data[0] << 24) | ((u32)data[1] << 16) | ((u32)data[2] << 8) | @@ -405,19 +444,20 @@ static void cg6_imageblit(struct fb_info *info, const struct fb_image *image) } /** - * cg6_setcolreg - Optional function. Sets a color register. - * @regno: boolean, 0 copy local, 1 get_user() function - * @red: frame buffer colormap structure - * @green: The green value which can be up to 16 bits wide - * @blue: The blue value which can be up to 16 bits wide. - * @transp: If supported the alpha value which can be up to 16 bits wide. - * @info: frame buffer info structure + * cg6_setcolreg - Sets a color register. + * + * @regno: boolean, 0 copy local, 1 get_user() function + * @red: frame buffer colormap structure + * @green: The green value which can be up to 16 bits wide + * @blue: The blue value which can be up to 16 bits wide. + * @transp: If supported the alpha value which can be up to 16 bits wide. + * @info: frame buffer info structure */ static int cg6_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; struct bt_regs __iomem *bt = par->bt; unsigned long flags; @@ -441,25 +481,24 @@ static int cg6_setcolreg(unsigned regno, } /** - * cg6_blank - Optional function. Blanks the display. - * @blank_mode: the blank mode we want. - * @info: frame buffer structure that represents a single frame buffer + * cg6_blank - Blanks the display. + * + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer */ -static int -cg6_blank(int blank, struct fb_info *info) +static int cg6_blank(int blank, struct fb_info *info) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; struct cg6_thc __iomem *thc = par->thc; unsigned long flags; u32 val; spin_lock_irqsave(&par->lock, flags); + val = sbus_readl(&thc->thc_misc); switch (blank) { case FB_BLANK_UNBLANK: /* Unblanking */ - val = sbus_readl(&thc->thc_misc); val |= CG6_THC_MISC_VIDEO; - sbus_writel(val, &thc->thc_misc); par->flags &= ~CG6_FLAG_BLANKED; break; @@ -467,13 +506,12 @@ cg6_blank(int blank, struct fb_info *info) case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ case FB_BLANK_POWERDOWN: /* Poweroff */ - val = sbus_readl(&thc->thc_misc); val &= ~CG6_THC_MISC_VIDEO; - sbus_writel(val, &thc->thc_misc); par->flags |= CG6_FLAG_BLANKED; break; } + sbus_writel(val, &thc->thc_misc); spin_unlock_irqrestore(&par->lock, flags); return 0; @@ -529,13 +567,12 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(cg6_mmap_map, par->physbase, par->fbsize, - par->sdev->reg_addrs[0].which_io, - vma); + par->which_io, vma); } static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; return sbusfb_ioctl_helper(cmd, arg, info, FBTYPE_SUNFAST_COLOR, 8, par->fbsize); @@ -545,15 +582,14 @@ static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) * Initialisation */ -static void -cg6_init_fix(struct fb_info *info, int linebytes) +static void __devinit cg6_init_fix(struct fb_info *info, int linebytes) { struct cg6_par *par = (struct cg6_par *)info->par; const char *cg6_cpu_name, *cg6_card_name; u32 conf; conf = sbus_readl(par->fhc); - switch(conf & CG6_FHC_CPU_MASK) { + switch (conf & CG6_FHC_CPU_MASK) { case CG6_FHC_CPU_SPARC: cg6_cpu_name = "sparc"; break; @@ -565,21 +601,19 @@ cg6_init_fix(struct fb_info *info, int linebytes) break; }; if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) { - if (par->fbsize <= 0x100000) { + if (par->fbsize <= 0x100000) cg6_card_name = "TGX"; - } else { + else cg6_card_name = "TGX+"; - } } else { - if (par->fbsize <= 0x100000) { + if (par->fbsize <= 0x100000) cg6_card_name = "GX"; - } else { + else cg6_card_name = "GX+"; - } } sprintf(info->fix.id, "%s %s", cg6_card_name, cg6_cpu_name); - info->fix.id[sizeof(info->fix.id)-1] = 0; + info->fix.id[sizeof(info->fix.id) - 1] = 0; info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_PSEUDOCOLOR; @@ -590,28 +624,28 @@ cg6_init_fix(struct fb_info *info, int linebytes) } /* Initialize Brooktree DAC */ -static void cg6_bt_init(struct cg6_par *par) +static void __devinit cg6_bt_init(struct cg6_par *par) { struct bt_regs __iomem *bt = par->bt; - sbus_writel(0x04 << 24, &bt->addr); /* color planes */ + sbus_writel(0x04 << 24, &bt->addr); /* color planes */ sbus_writel(0xff << 24, &bt->control); sbus_writel(0x05 << 24, &bt->addr); sbus_writel(0x00 << 24, &bt->control); - sbus_writel(0x06 << 24, &bt->addr); /* overlay plane */ + sbus_writel(0x06 << 24, &bt->addr); /* overlay plane */ sbus_writel(0x73 << 24, &bt->control); sbus_writel(0x07 << 24, &bt->addr); sbus_writel(0x00 << 24, &bt->control); } -static void cg6_chip_init(struct fb_info *info) +static void __devinit cg6_chip_init(struct fb_info *info) { - struct cg6_par *par = (struct cg6_par *) info->par; + struct cg6_par *par = (struct cg6_par *)info->par; struct cg6_tec __iomem *tec = par->tec; struct cg6_fbc __iomem *fbc = par->fbc; u32 rev, conf, mode; int i; - + /* Turn off stuff in the Transform Engine. */ sbus_writel(0, &tec->tec_matrix); sbus_writel(0, &tec->tec_clip); @@ -637,13 +671,13 @@ static void cg6_chip_init(struct fb_info *info) i = sbus_readl(&fbc->s); } while (i & 0x10000000); mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK | - CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK | - CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK | - CG6_FBC_BDISP_MASK); + CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK | + CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK | + CG6_FBC_BDISP_MASK); mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 | - CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE | - CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 | - CG6_FBC_BDISP_0); + CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE | + CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 | + CG6_FBC_BDISP_0); sbus_writel(mode, &fbc->mode); sbus_writel(0, &fbc->clip); @@ -655,140 +689,166 @@ static void cg6_chip_init(struct fb_info *info) sbus_writel(info->var.yres - 1, &fbc->clipmaxy); } -struct all_info { - struct fb_info info; - struct cg6_par par; - struct list_head list; -}; -static LIST_HEAD(cg6_list); +static void cg6_unmap_regs(struct of_device *op, struct fb_info *info, + struct cg6_par *par) +{ + if (par->fbc) + of_iounmap(&op->resource[0], par->fbc, 4096); + if (par->tec) + of_iounmap(&op->resource[0], par->tec, sizeof(struct cg6_tec)); + if (par->thc) + of_iounmap(&op->resource[0], par->thc, sizeof(struct cg6_thc)); + if (par->bt) + of_iounmap(&op->resource[0], par->bt, sizeof(struct bt_regs)); + if (par->fhc) + of_iounmap(&op->resource[0], par->fhc, sizeof(u32)); + + if (info->screen_base) + of_iounmap(&op->resource[0], info->screen_base, par->fbsize); +} -static void cg6_init_one(struct sbus_dev *sdev) +static int __devinit cg6_probe(struct of_device *op, + const struct of_device_id *match) { - struct all_info *all; - int linebytes; + struct device_node *dp = op->node; + struct fb_info *info; + struct cg6_par *par; + int linebytes, err; + int dblbuf; - all = kmalloc(sizeof(*all), GFP_KERNEL); - if (!all) { - printk(KERN_ERR "cg6: Cannot allocate memory.\n"); - return; - } - memset(all, 0, sizeof(*all)); - - INIT_LIST_HEAD(&all->list); - - spin_lock_init(&all->par.lock); - all->par.sdev = sdev; - - all->par.physbase = sdev->reg_addrs[0].phys_addr; - - sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); - all->info.var.red.length = 8; - all->info.var.green.length = 8; - all->info.var.blue.length = 8; - - linebytes = prom_getintdefault(sdev->prom_node, "linebytes", - all->info.var.xres); - all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - if (prom_getbool(sdev->prom_node, "dblbuf")) - all->par.fbsize *= 4; - - all->par.fbc = sbus_ioremap(&sdev->resource[0], CG6_FBC_OFFSET, - 4096, "cgsix fbc"); - all->par.tec = sbus_ioremap(&sdev->resource[0], CG6_TEC_OFFSET, - sizeof(struct cg6_tec), "cgsix tec"); - all->par.thc = sbus_ioremap(&sdev->resource[0], CG6_THC_OFFSET, - sizeof(struct cg6_thc), "cgsix thc"); - all->par.bt = sbus_ioremap(&sdev->resource[0], CG6_BROOKTREE_OFFSET, - sizeof(struct bt_regs), "cgsix dac"); - all->par.fhc = sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET, - sizeof(u32), "cgsix fhc"); - - all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT | - FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; - all->info.fbops = &cg6_ops; -#ifdef CONFIG_SPARC32 - all->info.screen_base = (char __iomem *) - prom_getintdefault(sdev->prom_node, "address", 0); -#endif - if (!all->info.screen_base) - all->info.screen_base = - sbus_ioremap(&sdev->resource[0], CG6_RAM_OFFSET, - all->par.fbsize, "cgsix ram"); - all->info.par = &all->par; + info = framebuffer_alloc(sizeof(struct cg6_par), &op->dev); - all->info.var.accel_flags = FB_ACCELF_TEXT; + err = -ENOMEM; + if (!info) + goto out_err; + par = info->par; - cg6_bt_init(&all->par); - cg6_chip_init(&all->info); - cg6_blank(0, &all->info); + spin_lock_init(&par->lock); - if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - printk(KERN_ERR "cg6: Could not allocate color map.\n"); - kfree(all); - return; - } + par->physbase = op->resource[0].start; + par->which_io = op->resource[0].flags & IORESOURCE_BITS; - fb_set_cmap(&all->info.cmap, &all->info); - cg6_init_fix(&all->info, linebytes); + sbusfb_fill_var(&info->var, dp->node, 8); + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; - if (register_framebuffer(&all->info) < 0) { - printk(KERN_ERR "cg6: Could not register framebuffer.\n"); - fb_dealloc_cmap(&all->info.cmap); - kfree(all); - return; - } + linebytes = of_getintprop_default(dp, "linebytes", + info->var.xres); + par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); + + dblbuf = of_getintprop_default(dp, "dblbuf", 0); + if (dblbuf) + par->fbsize *= 4; + + par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET, + 4096, "cgsix fbc"); + par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET, + sizeof(struct cg6_tec), "cgsix tec"); + par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET, + sizeof(struct cg6_thc), "cgsix thc"); + par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET, + sizeof(struct bt_regs), "cgsix dac"); + par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET, + sizeof(u32), "cgsix fhc"); + + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT | + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | + FBINFO_READS_FAST; + info->fbops = &cg6_ops; + + info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, + par->fbsize, "cgsix ram"); + if (!par->fbc || !par->tec || !par->thc || + !par->bt || !par->fhc || !info->screen_base) + goto out_unmap_regs; + + info->var.accel_flags = FB_ACCELF_TEXT; + + cg6_bt_init(par); + cg6_chip_init(info); + cg6_blank(0, info); + + if (fb_alloc_cmap(&info->cmap, 256, 0)) + goto out_unmap_regs; + + fb_set_cmap(&info->cmap, info); + cg6_init_fix(info, linebytes); + + err = register_framebuffer(info); + if (err < 0) + goto out_dealloc_cmap; + + dev_set_drvdata(&op->dev, info); + + printk("%s: CGsix [%s] at %lx:%lx\n", + dp->full_name, info->fix.id, + par->which_io, par->physbase); + + return 0; + +out_dealloc_cmap: + fb_dealloc_cmap(&info->cmap); - list_add(&all->list, &cg6_list); +out_unmap_regs: + cg6_unmap_regs(op, info, par); - printk("cg6: CGsix [%s] at %lx:%lx\n", - all->info.fix.id, - (long) sdev->reg_addrs[0].which_io, - (long) sdev->reg_addrs[0].phys_addr); +out_err: + return err; } -int __init cg6_init(void) +static int __devexit cg6_remove(struct of_device *op) { - struct sbus_bus *sbus; - struct sbus_dev *sdev; + struct fb_info *info = dev_get_drvdata(&op->dev); + struct cg6_par *par = info->par; - if (fb_get_options("cg6fb", NULL)) - return -ENODEV; + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); - for_all_sbusdev(sdev, sbus) { - if (!strcmp(sdev->prom_name, "cgsix") || - !strcmp(sdev->prom_name, "cgthree+")) - cg6_init_one(sdev); - } + cg6_unmap_regs(op, info, par); + + framebuffer_release(info); + + dev_set_drvdata(&op->dev, NULL); return 0; } -void __exit cg6_exit(void) -{ - struct list_head *pos, *tmp; +static struct of_device_id cg6_match[] = { + { + .name = "cgsix", + }, + { + .name = "cgthree+", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, cg6_match); - list_for_each_safe(pos, tmp, &cg6_list) { - struct all_info *all = list_entry(pos, typeof(*all), list); +static struct of_platform_driver cg6_driver = { + .name = "cg6", + .match_table = cg6_match, + .probe = cg6_probe, + .remove = __devexit_p(cg6_remove), +}; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); - kfree(all); - } +static int __init cg6_init(void) +{ + if (fb_get_options("cg6fb", NULL)) + return -ENODEV; + + return of_register_driver(&cg6_driver, &of_bus_type); } -int __init -cg6_setup(char *arg) +static void __exit cg6_exit(void) { - /* No cmdline options yet... */ - return 0; + of_unregister_driver(&cg6_driver); } module_init(cg6_init); - -#ifdef MODULE module_exit(cg6_exit); -#endif MODULE_DESCRIPTION("framebuffer driver for CGsix chipsets"); -MODULE_AUTHOR("David S. Miller "); +MODULE_AUTHOR("David S. Miller "); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL");