📄 cyber2000fb.c
字号:
EXT_OVERSCAN_GREEN, 0, EXT_OVERSCAN_BLUE, 0, /* some of these are questionable when we have a BIOS */ EXT_MEM_CTL0, EXT_MEM_CTL0_7CLK | EXT_MEM_CTL0_RAS_1 | EXT_MEM_CTL0_MULTCAS, EXT_HIDDEN_CTL1, 0x30, EXT_FIFO_CTL, 0x0b, EXT_FIFO_CTL + 1, 0x17, 0x76, 0x00, EXT_HIDDEN_CTL4, 0xc8};/* * Initialise the CyberPro hardware. On the CyberPro5XXXX, * ensure that we're using the correct PLL (5XXX's may be * programmed to use an additional set of PLLs.) */static void cyberpro_init_hw(struct cfb_info *cfb){ int i; for (i = 0; i < sizeof(igs_regs); i += 2) cyber2000_grphw(igs_regs[i], igs_regs[i + 1], cfb); if (cfb->id == ID_CYBERPRO_5000) { unsigned char val; cyber2000fb_writeb(0xba, 0x3ce, cfb); val = cyber2000fb_readb(0x3cf, cfb) & 0x80; cyber2000fb_writeb(val, 0x3cf, cfb); }}static struct cfb_info __devinit *cyberpro_alloc_fb_info(unsigned int id, char *name){ struct cfb_info *cfb; cfb = kzalloc(sizeof(struct cfb_info), GFP_KERNEL); if (!cfb) return NULL; cfb->id = id; if (id == ID_CYBERPRO_5000) cfb->ref_ps = 40690; /* 24.576 MHz */ else cfb->ref_ps = 69842; /* 14.31818 MHz (69841?) */ cfb->divisors[0] = 1; cfb->divisors[1] = 2; cfb->divisors[2] = 4; if (id == ID_CYBERPRO_2000) cfb->divisors[3] = 8; else cfb->divisors[3] = 6; strcpy(cfb->fb.fix.id, name); cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; cfb->fb.fix.type_aux = 0; cfb->fb.fix.xpanstep = 0; cfb->fb.fix.ypanstep = 1; cfb->fb.fix.ywrapstep = 0; switch (id) { case ID_IGA_1682: cfb->fb.fix.accel = 0; break; case ID_CYBERPRO_2000: cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2000; break; case ID_CYBERPRO_2010: cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2010; break; case ID_CYBERPRO_5000: cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER5000; break; } cfb->fb.var.nonstd = 0; cfb->fb.var.activate = FB_ACTIVATE_NOW; cfb->fb.var.height = -1; cfb->fb.var.width = -1; cfb->fb.var.accel_flags = FB_ACCELF_TEXT; cfb->fb.fbops = &cyber2000fb_ops; cfb->fb.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; cfb->fb.pseudo_palette = cfb->pseudo_palette; fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0); return cfb;}static void cyberpro_free_fb_info(struct cfb_info *cfb){ if (cfb) { /* * Free the colourmap */ fb_alloc_cmap(&cfb->fb.cmap, 0, 0); kfree(cfb); }}/* * Parse Cyber2000fb options. Usage: * video=cyber2000:font:fontname */#ifndef MODULEstatic int cyber2000fb_setup(char *options){ char *opt; if (!options || !*options) return 0; while ((opt = strsep(&options, ",")) != NULL) { if (!*opt) continue; if (strncmp(opt, "font:", 5) == 0) { static char default_font_storage[40]; strlcpy(default_font_storage, opt + 5, sizeof(default_font_storage)); default_font = default_font_storage; continue; } printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n", opt); } return 0;}#endif /* MODULE *//* * The CyberPro chips can be placed on many different bus types. * This probe function is common to all bus types. The bus-specific * probe function is expected to have: * - enabled access to the linear memory region * - memory mapped access to the registers * - initialised mem_ctl1 and mem_ctl2 appropriately. */static int __devinit cyberpro_common_probe(struct cfb_info *cfb){ u_long smem_size; u_int h_sync, v_sync; int err; cyberpro_init_hw(cfb); /* * Get the video RAM size and width from the VGA register. * This should have been already initialised by the BIOS, * but if it's garbage, claim default 1MB VRAM (woody) */ cfb->mem_ctl1 = cyber2000_grphr(EXT_MEM_CTL1, cfb); cfb->mem_ctl2 = cyber2000_grphr(EXT_MEM_CTL2, cfb); /* * Determine the size of the memory. */ switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) { case MEM_CTL2_SIZE_4MB: smem_size = 0x00400000; break; case MEM_CTL2_SIZE_2MB: smem_size = 0x00200000; break; case MEM_CTL2_SIZE_1MB: smem_size = 0x00100000; break; default: smem_size = 0x00100000; break; } cfb->fb.fix.smem_len = smem_size; cfb->fb.fix.mmio_len = MMIO_SIZE; cfb->fb.screen_base = cfb->region; err = -EINVAL; if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0, &cyber2000fb_default_mode, 8)) { printk(KERN_ERR "%s: no valid mode found\n", cfb->fb.fix.id); goto failed; } cfb->fb.var.yres_virtual = cfb->fb.fix.smem_len * 8 / (cfb->fb.var.bits_per_pixel * cfb->fb.var.xres_virtual); if (cfb->fb.var.yres_virtual < cfb->fb.var.yres) cfb->fb.var.yres_virtual = cfb->fb.var.yres;/* fb_set_var(&cfb->fb.var, -1, &cfb->fb); */ /* * Calculate the hsync and vsync frequencies. Note that * we split the 1e12 constant up so that we can preserve * the precision and fit the results into 32-bit registers. * (1953125000 * 512 = 1e12) */ h_sync = 1953125000 / cfb->fb.var.pixclock; h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin + cfb->fb.var.right_margin + cfb->fb.var.hsync_len); v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin + cfb->fb.var.lower_margin + cfb->fb.var.vsync_len); printk(KERN_INFO "%s: %dKiB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10, cfb->fb.var.xres, cfb->fb.var.yres, h_sync / 1000, h_sync % 1000, v_sync); if (cfb->dev) cfb->fb.device = &cfb->dev->dev; err = register_framebuffer(&cfb->fb);failed: return err;}static void cyberpro_common_resume(struct cfb_info *cfb){ cyberpro_init_hw(cfb); /* * Reprogram the MEM_CTL1 and MEM_CTL2 registers */ cyber2000_grphw(EXT_MEM_CTL1, cfb->mem_ctl1, cfb); cyber2000_grphw(EXT_MEM_CTL2, cfb->mem_ctl2, cfb); /* * Restore the old video mode and the palette. * We also need to tell fbcon to redraw the console. */ cyber2000fb_set_par(&cfb->fb);}#ifdef CONFIG_ARCH_SHARK#include <asm/arch/hardware.h>static int __devinit cyberpro_vl_probe(void){ struct cfb_info *cfb; int err = -ENOMEM; if (!request_mem_region(FB_START, FB_SIZE, "CyberPro2010")) return err; cfb = cyberpro_alloc_fb_info(ID_CYBERPRO_2010, "CyberPro2010"); if (!cfb) goto failed_release; cfb->dev = NULL; cfb->region = ioremap(FB_START, FB_SIZE); if (!cfb->region) goto failed_ioremap; cfb->regs = cfb->region + MMIO_OFFSET; cfb->fb.fix.mmio_start = FB_START + MMIO_OFFSET; cfb->fb.fix.smem_start = FB_START; /* * Bring up the hardware. This is expected to enable access * to the linear memory region, and allow access to the memory * mapped registers. Also, mem_ctl1 and mem_ctl2 must be * initialised. */ cyber2000fb_writeb(0x18, 0x46e8, cfb); cyber2000fb_writeb(0x01, 0x102, cfb); cyber2000fb_writeb(0x08, 0x46e8, cfb); cyber2000fb_writeb(EXT_BIU_MISC, 0x3ce, cfb); cyber2000fb_writeb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf, cfb); cfb->mclk_mult = 0xdb; cfb->mclk_div = 0x54; err = cyberpro_common_probe(cfb); if (err) goto failed; if (int_cfb_info == NULL) int_cfb_info = cfb; return 0;failed: iounmap(cfb->region);failed_ioremap: cyberpro_free_fb_info(cfb);failed_release: release_mem_region(FB_START, FB_SIZE); return err;}#endif /* CONFIG_ARCH_SHARK *//* * PCI specific support. */#ifdef CONFIG_PCI/* * We need to wake up the CyberPro, and make sure its in linear memory * mode. Unfortunately, this is specific to the platform and card that * we are running on. * * On x86 and ARM, should we be initialising the CyberPro first via the * IO registers, and then the MMIO registers to catch all cases? Can we * end up in the situation where the chip is in MMIO mode, but not awake * on an x86 system? */static int cyberpro_pci_enable_mmio(struct cfb_info *cfb){ unsigned char val;#if defined(__sparc_v9__)#error "You lose, consult DaveM."#elif defined(__sparc__) /* * SPARC does not have an "outb" instruction, so we generate * I/O cycles storing into a reserved memory space at * physical address 0x3000000 */ unsigned char __iomem *iop; iop = ioremap(0x3000000, 0x5000); if (iop == NULL) { prom_printf("iga5000: cannot map I/O\n"); return -ENOMEM; } writeb(0x18, iop + 0x46e8); writeb(0x01, iop + 0x102); writeb(0x08, iop + 0x46e8); writeb(EXT_BIU_MISC, iop + 0x3ce); writeb(EXT_BIU_MISC_LIN_ENABLE, iop + 0x3cf); iounmap(iop);#else /* * Most other machine types are "normal", so * we use the standard IO-based wakeup. */ outb(0x18, 0x46e8); outb(0x01, 0x102); outb(0x08, 0x46e8); outb(EXT_BIU_MISC, 0x3ce); outb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf);#endif /* * Allow the CyberPro to accept PCI burst accesses */ if (cfb->id == ID_CYBERPRO_2010) { printk(KERN_INFO "%s: NOT enabling PCI bursts\n", cfb->fb.fix.id); } else { val = cyber2000_grphr(EXT_BUS_CTL, cfb); if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) { printk(KERN_INFO "%s: enabling PCI bursts\n", cfb->fb.fix.id); val |= EXT_BUS_CTL_PCIBURST_WRITE; if (cfb->id == ID_CYBERPRO_5000) val |= EXT_BUS_CTL_PCIBURST_READ; cyber2000_grphw(EXT_BUS_CTL, val, cfb); } } return 0;}static int __devinitcyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id){ struct cfb_info *cfb; char name[16]; int err; sprintf(name, "CyberPro%4X", id->device); err = pci_enable_device(dev); if (err) return err; err = pci_request_regions(dev, name); if (err) return err; err = -ENOMEM; cfb = cyberpro_alloc_fb_info(id->driver_data, name); if (!cfb) goto failed_release; cfb->dev = dev; cfb->region = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); if (!cfb->region) goto failed_ioremap; cfb->regs = cfb->region + MMIO_OFFSET; cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET; cfb->fb.fix.smem_start = pci_resource_start(dev, 0); /* * Bring up the hardware. This is expected to enable access * to the linear memory region, and allow access to the memory * mapped registers. Also, mem_ctl1 and mem_ctl2 must be * initialised. */ err = cyberpro_pci_enable_mmio(cfb); if (err) goto failed; /* * Use MCLK from BIOS. FIXME: what about hotplug? */ cfb->mclk_mult = cyber2000_grphr(EXT_MCLK_MULT, cfb); cfb->mclk_div = cyber2000_grphr(EXT_MCLK_DIV, cfb);#ifdef __arm__ /* * MCLK on the NetWinder and the Shark is fixed at 75MHz */ if (machine_is_netwinder()) { cfb->mclk_mult = 0xdb; cfb->mclk_div = 0x54; }#endif err = cyberpro_common_probe(cfb); if (err) goto failed; /* * Our driver data */ pci_set_drvdata(dev, cfb); if (int_cfb_info == NULL) int_cfb_info = cfb; return 0;failed: iounmap(cfb->region);failed_ioremap: cyberpro_free_fb_info(cfb);failed_release: pci_release_regions(dev); return err;}static void __devexit cyberpro_pci_remove(struct pci_dev *dev){ struct cfb_info *cfb = pci_get_drvdata(dev); if (cfb) { /* * If unregister_framebuffer fails, then * we will be leaving hooks that could cause * oopsen laying around. */ if (unregister_framebuffer(&cfb->fb)) printk(KERN_WARNING "%s: danger Will Robinson, " "danger danger! Oopsen imminent!\n", cfb->fb.fix.id); iounmap(cfb->region); cyberpro_free_fb_info(cfb); /* * Ensure that the driver data is no longer * valid. */ pci_set_drvdata(dev, NULL); if (cfb == int_cfb_info) int_cfb_info = NULL; pci_release_regions(dev); }}static int cyberpro_pci_suspend(struct pci_dev *dev, pm_message_t state){ return 0;}/* * Re-initialise the CyberPro hardware */static int cyberpro_pci_resume(struct pci_dev *dev){ struct cfb_info *cfb = pci_get_drvdata(dev); if (cfb) { cyberpro_pci_enable_mmio(cfb); cyberpro_common_resume(cfb); } return 0;}static struct pci_device_id cyberpro_pci_table[] = {/* Not yet * { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682, * PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 }, */ { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 }, { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2010 }, { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_5000 }, { 0, }};MODULE_DEVICE_TABLE(pci, cyberpro_pci_table);static struct pci_driver cyberpro_driver = { .name = "CyberPro", .probe = cyberpro_pci_probe, .remove = __devexit_p(cyberpro_pci_remove), .suspend = cyberpro_pci_suspend, .resume = cyberpro_pci_resume, .id_table = cyberpro_pci_table};#endif/* * I don't think we can use the "module_init" stuff here because * the fbcon stuff may not be initialised yet. Hence the #ifdef * around module_init. * * Tony: "module_init" is now required */static int __init cyber2000fb_init(void){ int ret = -1, err;#ifndef MODULE char *option = NULL; if (fb_get_options("cyber2000fb", &option)) return -ENODEV; cyber2000fb_setup(option);#endif#ifdef CONFIG_ARCH_SHARK err = cyberpro_vl_probe(); if (!err) { ret = 0; __module_get(THIS_MODULE); }#endif#ifdef CONFIG_PCI err = pci_register_driver(&cyberpro_driver); if (!err) ret = 0;#endif return ret ? err : 0;}static void __exit cyberpro_exit(void){ pci_unregister_driver(&cyberpro_driver);}module_init(cyber2000fb_init);module_exit(cyberpro_exit);MODULE_AUTHOR("Russell King");MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -