📄 platinumfb.c
字号:
default_vmode = VMODE_640_480_60;#ifdef CONFIG_NVRAM if (default_cmode == CMODE_NVRAM) default_cmode = nvram_read_byte(NV_CMODE);#endif if (default_cmode < CMODE_8 || default_cmode > CMODE_32) default_cmode = CMODE_8; /* * Reduce the pixel size if we don't have enough VRAM. */ while(default_cmode > CMODE_8 && platinum_vram_reqd(default_vmode, default_cmode) > pinfo->total_vram) default_cmode--; printk("platinumfb: Using video mode %d and color mode %d.\n", default_vmode, default_cmode); /* Setup default var */ if (mac_vmode_to_var(default_vmode, default_cmode, &var) < 0) { /* This shouldn't happen! */ printk("mac_vmode_to_var(%d, %d,) failed\n", default_vmode, default_cmode);try_again: default_vmode = VMODE_640_480_60; default_cmode = CMODE_8; if (mac_vmode_to_var(default_vmode, default_cmode, &var) < 0) { printk(KERN_ERR "platinumfb: mac_vmode_to_var() failed\n"); return -ENXIO; } } /* Initialize info structure */ platinum_init_info(info, pinfo); /* Apply default var */ info->var = var; var.activate = FB_ACTIVATE_NOW; rc = fb_set_var(info, &var); if (rc && (default_vmode != VMODE_640_480_60 || default_cmode != CMODE_8)) goto try_again; /* Register with fbdev layer */ rc = register_framebuffer(info); if (rc < 0) return rc; printk(KERN_INFO "fb%d: Apple Platinum frame buffer device\n", info->node); return 0;}/* * Get the monitor sense value. * Note that this can be called before calibrate_delay, * so we can't use udelay. */static int read_platinum_sense(struct fb_info_platinum *info){ volatile struct platinum_regs __iomem *platinum_regs = info->platinum_regs; int sense; out_be32(&platinum_regs->reg[23].r, 7); /* turn off drivers */ __delay(2000); sense = (~in_be32(&platinum_regs->reg[23].r) & 7) << 8; /* drive each sense line low in turn and collect the other 2 */ out_be32(&platinum_regs->reg[23].r, 3); /* drive A low */ __delay(2000); sense |= (~in_be32(&platinum_regs->reg[23].r) & 3) << 4; out_be32(&platinum_regs->reg[23].r, 5); /* drive B low */ __delay(2000); sense |= (~in_be32(&platinum_regs->reg[23].r) & 4) << 1; sense |= (~in_be32(&platinum_regs->reg[23].r) & 1) << 2; out_be32(&platinum_regs->reg[23].r, 6); /* drive C low */ __delay(2000); sense |= (~in_be32(&platinum_regs->reg[23].r) & 6) >> 1; out_be32(&platinum_regs->reg[23].r, 7); /* turn off drivers */ return sense;}/* * This routine takes a user-supplied var, and picks the best vmode/cmode from it. * It also updates the var structure to the actual mode data obtained */static int platinum_var_to_par(struct fb_var_screeninfo *var, struct fb_info_platinum *pinfo, int check_only){ int vmode, cmode; if (mac_var_to_vmode(var, &vmode, &cmode) != 0) { printk(KERN_ERR "platinum_var_to_par: mac_var_to_vmode unsuccessful.\n"); printk(KERN_ERR "platinum_var_to_par: var->xres = %d\n", var->xres); printk(KERN_ERR "platinum_var_to_par: var->yres = %d\n", var->yres); printk(KERN_ERR "platinum_var_to_par: var->xres_virtual = %d\n", var->xres_virtual); printk(KERN_ERR "platinum_var_to_par: var->yres_virtual = %d\n", var->yres_virtual); printk(KERN_ERR "platinum_var_to_par: var->bits_per_pixel = %d\n", var->bits_per_pixel); printk(KERN_ERR "platinum_var_to_par: var->pixclock = %d\n", var->pixclock); printk(KERN_ERR "platinum_var_to_par: var->vmode = %d\n", var->vmode); return -EINVAL; } if (!platinum_reg_init[vmode-1]) { printk(KERN_ERR "platinum_var_to_par, vmode %d not valid.\n", vmode); return -EINVAL; } if (platinum_vram_reqd(vmode, cmode) > pinfo->total_vram) { printk(KERN_ERR "platinum_var_to_par, not enough ram for vmode %d, cmode %d.\n", vmode, cmode); return -EINVAL; } if (mac_vmode_to_var(vmode, cmode, var)) return -EINVAL; if (check_only) return 0; pinfo->vmode = vmode; pinfo->cmode = cmode; pinfo->xres = vmode_attrs[vmode-1].hres; pinfo->yres = vmode_attrs[vmode-1].vres; pinfo->xoffset = 0; pinfo->yoffset = 0; pinfo->vxres = pinfo->xres; pinfo->vyres = pinfo->yres; return 0;}/* * Parse user speficied options (`video=platinumfb:') */static int __init platinumfb_setup(char *options){ char *this_opt; if (!options || !*options) return 0; while ((this_opt = strsep(&options, ",")) != NULL) { if (!strncmp(this_opt, "vmode:", 6)) { int vmode = simple_strtoul(this_opt+6, NULL, 0); if (vmode > 0 && vmode <= VMODE_MAX) default_vmode = vmode; } else if (!strncmp(this_opt, "cmode:", 6)) { int depth = simple_strtoul(this_opt+6, NULL, 0); switch (depth) { case 0: case 8: default_cmode = CMODE_8; break; case 15: case 16: default_cmode = CMODE_16; break; case 24: case 32: default_cmode = CMODE_32; break; } } } return 0;}#ifdef __powerpc__#define invalidate_cache(addr) \ asm volatile("eieio; dcbf 0,%1" \ : "=m" (*(addr)) : "r" (addr) : "memory");#else#define invalidate_cache(addr)#endifstatic int __devinit platinumfb_probe(struct of_device* odev, const struct of_device_id *match){ struct device_node *dp = odev->node; struct fb_info *info; struct fb_info_platinum *pinfo; volatile __u8 *fbuffer; int bank0, bank1, bank2, bank3, rc; dev_info(&odev->dev, "Found Apple Platinum video hardware\n"); info = framebuffer_alloc(sizeof(*pinfo), &odev->dev); if (info == NULL) { dev_err(&odev->dev, "Failed to allocate fbdev !\n"); return -ENOMEM; } pinfo = info->par; if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) || of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) { dev_err(&odev->dev, "Can't get resources\n"); framebuffer_release(info); return -ENXIO; } dev_dbg(&odev->dev, " registers : 0x%llx...0x%llx\n", (unsigned long long)pinfo->rsrc_reg.start, (unsigned long long)pinfo->rsrc_reg.end); dev_dbg(&odev->dev, " framebuffer: 0x%llx...0x%llx\n", (unsigned long long)pinfo->rsrc_fb.start, (unsigned long long)pinfo->rsrc_fb.end); /* Do not try to request register space, they overlap with the * northbridge and that can fail. Only request framebuffer */ if (!request_mem_region(pinfo->rsrc_fb.start, pinfo->rsrc_fb.end - pinfo->rsrc_fb.start + 1, "platinumfb framebuffer")) { printk(KERN_ERR "platinumfb: Can't request framebuffer !\n"); framebuffer_release(info); return -ENXIO; } /* frame buffer - map only 4MB */ pinfo->frame_buffer_phys = pinfo->rsrc_fb.start; pinfo->frame_buffer = __ioremap(pinfo->rsrc_fb.start, 0x400000, _PAGE_WRITETHRU); pinfo->base_frame_buffer = pinfo->frame_buffer; /* registers */ pinfo->platinum_regs_phys = pinfo->rsrc_reg.start; pinfo->platinum_regs = ioremap(pinfo->rsrc_reg.start, 0x1000); pinfo->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ request_mem_region(pinfo->cmap_regs_phys, 0x1000, "platinumfb cmap"); pinfo->cmap_regs = ioremap(pinfo->cmap_regs_phys, 0x1000); /* Grok total video ram */ out_be32(&pinfo->platinum_regs->reg[16].r, (unsigned)pinfo->frame_buffer_phys); out_be32(&pinfo->platinum_regs->reg[20].r, 0x1011); /* select max vram */ out_be32(&pinfo->platinum_regs->reg[24].r, 0); /* switch in vram */ fbuffer = pinfo->base_frame_buffer; fbuffer[0x100000] = 0x34; fbuffer[0x100008] = 0x0; invalidate_cache(&fbuffer[0x100000]); fbuffer[0x200000] = 0x56; fbuffer[0x200008] = 0x0; invalidate_cache(&fbuffer[0x200000]); fbuffer[0x300000] = 0x78; fbuffer[0x300008] = 0x0; invalidate_cache(&fbuffer[0x300000]); bank0 = 1; /* builtin 1MB vram, always there */ bank1 = fbuffer[0x100000] == 0x34; bank2 = fbuffer[0x200000] == 0x56; bank3 = fbuffer[0x300000] == 0x78; pinfo->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000; printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n", (unsigned int) (pinfo->total_vram / 1024 / 1024), bank3, bank2, bank1, bank0); /* * Try to determine whether we have an old or a new DACula. */ out_8(&pinfo->cmap_regs->addr, 0x40); pinfo->dactype = in_8(&pinfo->cmap_regs->d2); switch (pinfo->dactype) { case 0x3c: pinfo->clktype = 1; printk(KERN_INFO "platinumfb: DACula type 0x3c\n"); break; case 0x84: pinfo->clktype = 0; printk(KERN_INFO "platinumfb: DACula type 0x84\n"); break; default: pinfo->clktype = 0; printk(KERN_INFO "platinumfb: Unknown DACula type: %x\n", pinfo->dactype); break; } dev_set_drvdata(&odev->dev, info); rc = platinum_init_fb(info); if (rc != 0) { iounmap(pinfo->frame_buffer); iounmap(pinfo->platinum_regs); iounmap(pinfo->cmap_regs); dev_set_drvdata(&odev->dev, NULL); framebuffer_release(info); } return rc;}static int __devexit platinumfb_remove(struct of_device* odev){ struct fb_info *info = dev_get_drvdata(&odev->dev); struct fb_info_platinum *pinfo = info->par; unregister_framebuffer (info); /* Unmap frame buffer and registers */ iounmap(pinfo->frame_buffer); iounmap(pinfo->platinum_regs); iounmap(pinfo->cmap_regs); release_mem_region(pinfo->rsrc_fb.start, pinfo->rsrc_fb.end - pinfo->rsrc_fb.start + 1); release_mem_region(pinfo->cmap_regs_phys, 0x1000); framebuffer_release(info); return 0;}static struct of_device_id platinumfb_match[] = { { .name = "platinum", }, {},};static struct of_platform_driver platinum_driver = { .name = "platinumfb", .match_table = platinumfb_match, .probe = platinumfb_probe, .remove = platinumfb_remove,};static int __init platinumfb_init(void){#ifndef MODULE char *option = NULL; if (fb_get_options("platinumfb", &option)) return -ENODEV; platinumfb_setup(option);#endif of_register_platform_driver(&platinum_driver); return 0;}static void __exit platinumfb_exit(void){ of_unregister_platform_driver(&platinum_driver);}MODULE_LICENSE("GPL");MODULE_DESCRIPTION("framebuffer driver for Apple Platinum video");module_init(platinumfb_init);#ifdef MODULEmodule_exit(platinumfb_exit);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -