📄 ffb.c
字号:
/** * ffb_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 ffb_imageblit(struct fb_info *info, const struct fb_image *image){ struct ffb_par *par = (struct ffb_par *)info->par; struct ffb_fbc __iomem *fbc = par->fbc; const u8 *data = image->data; unsigned long flags; u32 fg, bg, xy; u64 fgbg; int i, width, stride; if (image->depth > 1) { cfb_imageblit(info, image); return; } fg = ((u32 *)info->pseudo_palette)[image->fg_color]; bg = ((u32 *)info->pseudo_palette)[image->bg_color]; fgbg = ((u64) fg << 32) | (u64) bg; xy = (image->dy << 16) | image->dx; width = image->width; stride = ((width + 7) >> 3); spin_lock_irqsave(&par->lock, flags); if (fgbg != *(u64 *)&par->fg_cache) { FFBFifo(par, 2); upa_writeq(fgbg, &fbc->fg); *(u64 *)&par->fg_cache = fgbg; } if (width >= 32) { FFBFifo(par, 1); upa_writel(32, &fbc->fontw); } while (width >= 32) { const u8 *next_data = data + 4; FFBFifo(par, 1); upa_writel(xy, &fbc->fontxy); xy += (32 << 0); for (i = 0; i < image->height; i++) { u32 val = (((u32)data[0] << 24) | ((u32)data[1] << 16) | ((u32)data[2] << 8) | ((u32)data[3] << 0)); FFBFifo(par, 1); upa_writel(val, &fbc->font); data += stride; } data = next_data; width -= 32; } if (width) { FFBFifo(par, 2); upa_writel(width, &fbc->fontw); upa_writel(xy, &fbc->fontxy); for (i = 0; i < image->height; i++) { u32 val = (((u32)data[0] << 24) | ((u32)data[1] << 16) | ((u32)data[2] << 8) | ((u32)data[3] << 0)); FFBFifo(par, 1); upa_writel(val, &fbc->font); data += stride; } } spin_unlock_irqrestore(&par->lock, flags);}static void ffb_fixup_var_rgb(struct fb_var_screeninfo *var){ var->red.offset = 0; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 16; var->blue.length = 8; var->transp.offset = 0; var->transp.length = 0;}/** * ffb_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 ffb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info){ u32 value; if (regno >= 16) return 1; red >>= 8; green >>= 8; blue >>= 8; value = (blue << 16) | (green << 8) | red; ((u32 *)info->pseudo_palette)[regno] = value; return 0;}/** * ffb_blank - Optional function. Blanks the display. * @blank_mode: the blank mode we want. * @info: frame buffer structure that represents a single frame buffer */static int ffb_blank(int blank, struct fb_info *info){ struct ffb_par *par = (struct ffb_par *)info->par; struct ffb_dac __iomem *dac = par->dac; unsigned long flags; u32 val; int i; spin_lock_irqsave(&par->lock, flags); FFBWait(par); upa_writel(FFB_DAC_TGEN, &dac->type); val = upa_readl(&dac->value); switch (blank) { case FB_BLANK_UNBLANK: /* Unblanking */ val |= FFB_DAC_TGEN_VIDE; par->flags &= ~FFB_FLAG_BLANKED; break; case FB_BLANK_NORMAL: /* Normal blanking */ case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ case FB_BLANK_POWERDOWN: /* Poweroff */ val &= ~FFB_DAC_TGEN_VIDE; par->flags |= FFB_FLAG_BLANKED; break; } upa_writel(FFB_DAC_TGEN, &dac->type); upa_writel(val, &dac->value); for (i = 0; i < 10; i++) { upa_writel(FFB_DAC_TGEN, &dac->type); upa_readl(&dac->value); } spin_unlock_irqrestore(&par->lock, flags); return 0;}static struct sbus_mmap_map ffb_mmap_map[] = { { .voff = FFB_SFB8R_VOFF, .poff = FFB_SFB8R_POFF, .size = 0x0400000 }, { .voff = FFB_SFB8G_VOFF, .poff = FFB_SFB8G_POFF, .size = 0x0400000 }, { .voff = FFB_SFB8B_VOFF, .poff = FFB_SFB8B_POFF, .size = 0x0400000 }, { .voff = FFB_SFB8X_VOFF, .poff = FFB_SFB8X_POFF, .size = 0x0400000 }, { .voff = FFB_SFB32_VOFF, .poff = FFB_SFB32_POFF, .size = 0x1000000 }, { .voff = FFB_SFB64_VOFF, .poff = FFB_SFB64_POFF, .size = 0x2000000 }, { .voff = FFB_FBC_REGS_VOFF, .poff = FFB_FBC_REGS_POFF, .size = 0x0002000 }, { .voff = FFB_BM_FBC_REGS_VOFF, .poff = FFB_BM_FBC_REGS_POFF, .size = 0x0002000 }, { .voff = FFB_DFB8R_VOFF, .poff = FFB_DFB8R_POFF, .size = 0x0400000 }, { .voff = FFB_DFB8G_VOFF, .poff = FFB_DFB8G_POFF, .size = 0x0400000 }, { .voff = FFB_DFB8B_VOFF, .poff = FFB_DFB8B_POFF, .size = 0x0400000 }, { .voff = FFB_DFB8X_VOFF, .poff = FFB_DFB8X_POFF, .size = 0x0400000 }, { .voff = FFB_DFB24_VOFF, .poff = FFB_DFB24_POFF, .size = 0x1000000 }, { .voff = FFB_DFB32_VOFF, .poff = FFB_DFB32_POFF, .size = 0x1000000 }, { .voff = FFB_FBC_KREGS_VOFF, .poff = FFB_FBC_KREGS_POFF, .size = 0x0002000 }, { .voff = FFB_DAC_VOFF, .poff = FFB_DAC_POFF, .size = 0x0002000 }, { .voff = FFB_PROM_VOFF, .poff = FFB_PROM_POFF, .size = 0x0010000 }, { .voff = FFB_EXP_VOFF, .poff = FFB_EXP_POFF, .size = 0x0002000 }, { .voff = FFB_DFB422A_VOFF, .poff = FFB_DFB422A_POFF, .size = 0x0800000 }, { .voff = FFB_DFB422AD_VOFF, .poff = FFB_DFB422AD_POFF, .size = 0x0800000 }, { .voff = FFB_DFB24B_VOFF, .poff = FFB_DFB24B_POFF, .size = 0x1000000 }, { .voff = FFB_DFB422B_VOFF, .poff = FFB_DFB422B_POFF, .size = 0x0800000 }, { .voff = FFB_DFB422BD_VOFF, .poff = FFB_DFB422BD_POFF, .size = 0x0800000 }, { .voff = FFB_SFB16Z_VOFF, .poff = FFB_SFB16Z_POFF, .size = 0x0800000 }, { .voff = FFB_SFB8Z_VOFF, .poff = FFB_SFB8Z_POFF, .size = 0x0800000 }, { .voff = FFB_SFB422_VOFF, .poff = FFB_SFB422_POFF, .size = 0x0800000 }, { .voff = FFB_SFB422D_VOFF, .poff = FFB_SFB422D_POFF, .size = 0x0800000 }, { .size = 0 }};static int ffb_mmap(struct fb_info *info, struct vm_area_struct *vma){ struct ffb_par *par = (struct ffb_par *)info->par; return sbusfb_mmap_helper(ffb_mmap_map, par->physbase, par->fbsize, 0, vma);}static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg){ struct ffb_par *par = (struct ffb_par *)info->par; return sbusfb_ioctl_helper(cmd, arg, info, FBTYPE_CREATOR, 24, par->fbsize);}/* * Initialisation */static void ffb_init_fix(struct fb_info *info){ struct ffb_par *par = (struct ffb_par *)info->par; const char *ffb_type_name; if (!(par->flags & FFB_FLAG_AFB)) { if ((par->board_type & 0x7) == 0x3) ffb_type_name = "Creator 3D"; else ffb_type_name = "Creator"; } else ffb_type_name = "Elite 3D"; strlcpy(info->fix.id, ffb_type_name, sizeof(info->fix.id)); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_TRUECOLOR; /* Framebuffer length is the same regardless of resolution. */ info->fix.line_length = 8192; info->fix.accel = FB_ACCEL_SUN_CREATOR;}static int __devinit ffb_probe(struct of_device *op, const struct of_device_id *match){ struct device_node *dp = op->node; struct ffb_fbc __iomem *fbc; struct ffb_dac __iomem *dac; struct fb_info *info; struct ffb_par *par; u32 dac_pnum, dac_rev, dac_mrev; int err; info = framebuffer_alloc(sizeof(struct ffb_par), &op->dev); err = -ENOMEM; if (!info) goto out_err; par = info->par; spin_lock_init(&par->lock); par->fbc = of_ioremap(&op->resource[2], 0, sizeof(struct ffb_fbc), "ffb fbc"); if (!par->fbc) goto out_release_fb; par->dac = of_ioremap(&op->resource[1], 0, sizeof(struct ffb_dac), "ffb dac"); if (!par->dac) goto out_unmap_fbc; par->rop_cache = FFB_ROP_NEW; par->physbase = op->resource[0].start; /* Don't mention copyarea, so SCROLL_REDRAW is always * used. It is the fastest on this chip. */ info->flags = (FBINFO_DEFAULT | /* FBINFO_HWACCEL_COPYAREA | */ FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_IMAGEBLIT); info->fbops = &ffb_ops; info->screen_base = (char *) par->physbase + FFB_DFB24_POFF; info->pseudo_palette = par->pseudo_palette; sbusfb_fill_var(&info->var, dp, 32); par->fbsize = PAGE_ALIGN(info->var.xres * info->var.yres * 4); ffb_fixup_var_rgb(&info->var); info->var.accel_flags = FB_ACCELF_TEXT; if (!strcmp(dp->name, "SUNW,afb")) par->flags |= FFB_FLAG_AFB; par->board_type = of_getintprop_default(dp, "board_type", 0); fbc = par->fbc; if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr); dac = par->dac; upa_writel(FFB_DAC_DID, &dac->type); dac_pnum = upa_readl(&dac->value); dac_rev = (dac_pnum & FFB_DAC_DID_REV) >> FFB_DAC_DID_REV_SHIFT; dac_pnum = (dac_pnum & FFB_DAC_DID_PNUM) >> FFB_DAC_DID_PNUM_SHIFT; upa_writel(FFB_DAC_UCTRL, &dac->type); dac_mrev = upa_readl(&dac->value); dac_mrev = (dac_mrev & FFB_DAC_UCTRL_MANREV) >> FFB_DAC_UCTRL_MANREV_SHIFT; /* Elite3D has different DAC revision numbering, and no DAC revisions * have the reversed meaning of cursor enable. Otherwise, Pacifica 1 * ramdacs with manufacturing revision less than 3 have inverted * cursor logic. We identify Pacifica 1 as not Pacifica 2, the * latter having a part number value of 0x236e. */ if ((par->flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) { par->flags &= ~FFB_FLAG_INVCURSOR; } else { if (dac_mrev < 3) par->flags |= FFB_FLAG_INVCURSOR; } ffb_switch_from_graph(par); /* Unblank it just to be sure. When there are multiple * FFB/AFB cards in the system, or it is not the OBP * chosen console, it will have video outputs off in * the DAC. */ ffb_blank(FB_BLANK_UNBLANK, info); if (fb_alloc_cmap(&info->cmap, 256, 0)) goto out_unmap_dac; ffb_init_fix(info); err = register_framebuffer(info); if (err < 0) goto out_dealloc_cmap; dev_set_drvdata(&op->dev, info); printk(KERN_INFO "%s: %s at %016lx, type %d, " "DAC pnum[%x] rev[%d] manuf_rev[%d]\n", dp->full_name, ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), par->physbase, par->board_type, dac_pnum, dac_rev, dac_mrev); return 0;out_dealloc_cmap: fb_dealloc_cmap(&info->cmap);out_unmap_dac: of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));out_unmap_fbc: of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));out_release_fb: framebuffer_release(info);out_err: return err;}static int __devexit ffb_remove(struct of_device *op){ struct fb_info *info = dev_get_drvdata(&op->dev); struct ffb_par *par = info->par; unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc)); of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac)); framebuffer_release(info); dev_set_drvdata(&op->dev, NULL); return 0;}static const struct of_device_id ffb_match[] = { { .name = "SUNW,ffb", }, { .name = "SUNW,afb", }, {},};MODULE_DEVICE_TABLE(of, ffb_match);static struct of_platform_driver ffb_driver = { .name = "ffb", .match_table = ffb_match, .probe = ffb_probe, .remove = __devexit_p(ffb_remove),};static int __init ffb_init(void){ if (fb_get_options("ffb", NULL)) return -ENODEV; return of_register_driver(&ffb_driver, &of_bus_type);}static void __exit ffb_exit(void){ of_unregister_driver(&ffb_driver);}module_init(ffb_init);module_exit(ffb_exit);MODULE_DESCRIPTION("framebuffer driver for Creator/Elite3D chipsets");MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");MODULE_VERSION("2.0");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -