📄 sstfb.c
字号:
struct sstfb_par *par = info->par; u8 pll_ctrl; sst_dac_write(DACREG_ICS_PLLRMA, DACREG_ICS_PLL_CTRL); pll_ctrl = sst_dac_read(DACREG_ICS_PLLDATA); switch(clock) { case VID_CLOCK: sst_dac_write(DACREG_ICS_PLLWMA, 0x0); /* CLK0, f0 */ sst_dac_write(DACREG_ICS_PLLDATA, t->m); sst_dac_write(DACREG_ICS_PLLDATA, t->p << 5 | t->n); /* selects freq f0 for clock 0 */ sst_dac_write(DACREG_ICS_PLLWMA, DACREG_ICS_PLL_CTRL); sst_dac_write(DACREG_ICS_PLLDATA, (pll_ctrl & 0xd8) | DACREG_ICS_CLK0 | DACREG_ICS_CLK0_0); break; case GFX_CLOCK : sst_dac_write(DACREG_ICS_PLLWMA, 0xa); /* CLK1, fA */ sst_dac_write(DACREG_ICS_PLLDATA, t->m); sst_dac_write(DACREG_ICS_PLLDATA, t->p << 5 | t->n); /* selects freq fA for clock 1 */ sst_dac_write(DACREG_ICS_PLLWMA, DACREG_ICS_PLL_CTRL); sst_dac_write(DACREG_ICS_PLLDATA, (pll_ctrl & 0xef) | DACREG_ICS_CLK1_A); break; default: dprintk("%s: wrong clock code '%d'\n", __func__, clock); return 0; } udelay(300); return 1;}static void sst_set_vidmod_att_ti(struct fb_info *info, const int bpp){ struct sstfb_par *par = info->par; u8 cr0; sst_dac_write(DACREG_WMA, 0); /* backdoor */ sst_dac_read(DACREG_RMR); /* read 4 times RMR */ sst_dac_read(DACREG_RMR); sst_dac_read(DACREG_RMR); sst_dac_read(DACREG_RMR); /* the fifth time, CR0 is read */ cr0 = sst_dac_read(DACREG_RMR); sst_dac_write(DACREG_WMA, 0); /* backdoor */ sst_dac_read(DACREG_RMR); /* read 4 times RMR */ sst_dac_read(DACREG_RMR); sst_dac_read(DACREG_RMR); sst_dac_read(DACREG_RMR); /* cr0 */ switch(bpp) { case 16: sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_16BPP); break; default: dprintk("%s: bad depth '%u'\n", __func__, bpp); break; }}static void sst_set_vidmod_ics(struct fb_info *info, const int bpp){ struct sstfb_par *par = info->par; switch(bpp) { case 16: sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_16BPP); break; default: dprintk("%s: bad depth '%u'\n", __func__, bpp); break; }}/* * detect dac type * prerequisite : write to FbiInitx enabled, video and fbi and pci fifo reset, * dram refresh disabled, FbiInit remaped. * TODO: mmh.. maybe i shoud put the "prerequisite" in the func ... */static struct dac_switch dacs[] __devinitdata = { { .name = "TI TVP3409", .detect = sst_detect_ti, .set_pll = sst_set_pll_att_ti, .set_vidmod = sst_set_vidmod_att_ti }, { .name = "AT&T ATT20C409", .detect = sst_detect_att, .set_pll = sst_set_pll_att_ti, .set_vidmod = sst_set_vidmod_att_ti }, { .name = "ICS ICS5342", .detect = sst_detect_ics, .set_pll = sst_set_pll_ics, .set_vidmod = sst_set_vidmod_ics },};static int __devinit sst_detect_dactype(struct fb_info *info, struct sstfb_par *par){ int i, ret = 0; for (i = 0; i < ARRAY_SIZE(dacs); i++) { ret = dacs[i].detect(info); if (ret) break; } if (!ret) return 0; f_dprintk("%s found %s\n", __func__, dacs[i].name); par->dac_sw = dacs[i]; return 1;}/* * Internal Routines */static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par){ u32 fbiinit0, fbiinit1, fbiinit4; struct pci_dev *dev = par->dev; struct pll_timing gfx_timings; struct sst_spec *spec; int Fout; int gfx_clock; spec = &voodoo_spec[par->type]; f_ddprintk(" fbiinit0 fbiinit1 fbiinit2 fbiinit3 fbiinit4 " " fbiinit6\n"); f_ddprintk("%0#10x %0#10x %0#10x %0#10x %0#10x %0#10x\n", sst_read(FBIINIT0), sst_read(FBIINIT1), sst_read(FBIINIT2), sst_read(FBIINIT3), sst_read(FBIINIT4), sst_read(FBIINIT6)); /* disable video clock */ pci_write_config_dword(dev, PCI_VCLK_DISABLE, 0); /* enable writing to init registers, disable pci fifo */ pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); /* reset video */ sst_set_bits(FBIINIT1, VIDEO_RESET); sst_wait_idle(); /* reset gfx + pci fifo */ sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET); sst_wait_idle(); /* unreset fifo */ /*sst_unset_bits(FBIINIT0, FIFO_RESET); sst_wait_idle();*/ /* unreset FBI */ /*sst_unset_bits(FBIINIT0, FBI_RESET); sst_wait_idle();*/ /* disable dram refresh */ sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH); sst_wait_idle(); /* remap fbinit2/3 to dac */ pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR | PCI_REMAP_DAC ); /* detect dac type */ if (!sst_detect_dactype(info, par)) { printk(KERN_ERR "sstfb: unknown dac type.\n"); //FIXME watch it: we are not in a safe state, bad bad bad. return 0; } /* set graphic clock */ gfx_clock = spec->default_gfx_clock; if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) { printk(KERN_INFO "sstfb: Using supplied graphic freq : %dMHz\n", gfxclk); gfx_clock = gfxclk *1000; } else if (gfxclk) { printk(KERN_WARNING "sstfb: %dMhz is way out of spec! Using default\n", gfxclk); } sst_calc_pll(gfx_clock, &Fout, &gfx_timings); par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK); /* disable fbiinit remap */ pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR| PCI_EN_FIFO_WR ); /* defaults init registers */ /* FbiInit0: unreset gfx, unreset fifo */ fbiinit0 = FBIINIT0_DEFAULT; fbiinit1 = FBIINIT1_DEFAULT; fbiinit4 = FBIINIT4_DEFAULT; par->vgapass = vgapass; if (par->vgapass) fbiinit0 &= ~DIS_VGA_PASSTHROUGH; else fbiinit0 |= DIS_VGA_PASSTHROUGH; if (slowpci) { fbiinit1 |= SLOW_PCI_WRITES; fbiinit4 |= SLOW_PCI_READS; } else { fbiinit1 &= ~SLOW_PCI_WRITES; fbiinit4 &= ~SLOW_PCI_READS; } sst_write(FBIINIT0, fbiinit0); sst_wait_idle(); sst_write(FBIINIT1, fbiinit1); sst_wait_idle(); sst_write(FBIINIT2, FBIINIT2_DEFAULT); sst_wait_idle(); sst_write(FBIINIT3, FBIINIT3_DEFAULT); sst_wait_idle(); sst_write(FBIINIT4, fbiinit4); sst_wait_idle(); if (IS_VOODOO2(par)) { sst_write(FBIINIT6, FBIINIT6_DEFAULT); sst_wait_idle(); } pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_FIFO_WR); pci_write_config_dword(dev, PCI_VCLK_ENABLE, 0); return 1;}static void __devexit sst_shutdown(struct fb_info *info){ struct sstfb_par *par = info->par; struct pci_dev *dev = par->dev; struct pll_timing gfx_timings; int Fout; /* reset video, gfx, fifo, disable dram + remap fbiinit2/3 */ pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); sst_set_bits(FBIINIT1, VIDEO_RESET | EN_BLANKING); sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH); sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET); sst_wait_idle(); pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR | PCI_REMAP_DAC); /* set 20Mhz gfx clock */ sst_calc_pll(20000, &Fout, &gfx_timings); par->dac_sw.set_pll(info, &gfx_timings, GFX_CLOCK); /* TODO maybe shutdown the dac, vrefresh and so on... */ pci_write_config_dword(dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET | DIS_VGA_PASSTHROUGH); pci_write_config_dword(dev, PCI_VCLK_DISABLE,0); /* maybe keep fbiinit* and PCI_INIT_enable in the fb_info struct * from start ? */ pci_write_config_dword(dev, PCI_INIT_ENABLE, 0);}/* * Interface to the world */static int __devinit sstfb_setup(char *options){ char *this_opt; if (!options || !*options) return 0; while ((this_opt = strsep(&options, ",")) != NULL) { if (!*this_opt) continue; f_ddprintk("option %s\n", this_opt); if (!strcmp(this_opt, "vganopass")) vgapass = 0; else if (!strcmp(this_opt, "vgapass")) vgapass = 1; else if (!strcmp(this_opt, "clipping")) clipping = 1; else if (!strcmp(this_opt, "noclipping")) clipping = 0; else if (!strcmp(this_opt, "fastpci")) slowpci = 0; else if (!strcmp(this_opt, "slowpci")) slowpci = 1; else if (!strncmp(this_opt, "mem:",4)) mem = simple_strtoul (this_opt+4, NULL, 0); else if (!strncmp(this_opt, "gfxclk:",7)) gfxclk = simple_strtoul (this_opt+7, NULL, 0); else mode_option = this_opt; } return 0;}static struct fb_ops sstfb_ops = { .owner = THIS_MODULE, .fb_check_var = sstfb_check_var, .fb_set_par = sstfb_set_par, .fb_setcolreg = sstfb_setcolreg, .fb_fillrect = cfb_fillrect, /* sstfb_fillrect */ .fb_copyarea = cfb_copyarea, /* sstfb_copyarea */ .fb_imageblit = cfb_imageblit, .fb_ioctl = sstfb_ioctl,};static int __devinit sstfb_probe(struct pci_dev *pdev, const struct pci_device_id *id){ struct fb_info *info; struct fb_fix_screeninfo *fix; struct sstfb_par *par; struct sst_spec *spec; int err; /* Enable device in PCI config. */ if ((err=pci_enable_device(pdev))) { printk(KERN_ERR "cannot enable device\n"); return err; } /* Allocate the fb and par structures. */ info = framebuffer_alloc(sizeof(struct sstfb_par), &pdev->dev); if (!info) return -ENOMEM; pci_set_drvdata(pdev, info); par = info->par; fix = &info->fix; par->type = id->driver_data; spec = &voodoo_spec[par->type]; f_ddprintk("found device : %s\n", spec->name); par->dev = pdev; par->revision = pdev->revision; fix->mmio_start = pci_resource_start(pdev,0); fix->mmio_len = 0x400000; fix->smem_start = fix->mmio_start + 0x400000; if (!request_mem_region(fix->mmio_start, fix->mmio_len, "sstfb MMIO")) { printk(KERN_ERR "sstfb: cannot reserve mmio memory\n"); goto fail_mmio_mem; } if (!request_mem_region(fix->smem_start, 0x400000,"sstfb FB")) { printk(KERN_ERR "sstfb: cannot reserve fb memory\n"); goto fail_fb_mem; } par->mmio_vbase = ioremap_nocache(fix->mmio_start, fix->mmio_len); if (!par->mmio_vbase) { printk(KERN_ERR "sstfb: cannot remap register area %#lx\n", fix->mmio_start); goto fail_mmio_remap; } info->screen_base = ioremap_nocache(fix->smem_start, 0x400000); if (!info->screen_base) { printk(KERN_ERR "sstfb: cannot remap framebuffer %#lx\n", fix->smem_start); goto fail_fb_remap; } if (!sst_init(info, par)) { printk(KERN_ERR "sstfb: Init failed\n"); goto fail; } sst_get_memsize(info, &fix->smem_len); strlcpy(fix->id, spec->name, sizeof(fix->id)); printk(KERN_INFO "%s (revision %d) with %s dac\n", fix->id, par->revision, par->dac_sw.name); printk(KERN_INFO "framebuffer at %#lx, mapped to 0x%p, size %dMB\n", fix->smem_start, info->screen_base, fix->smem_len >> 20); f_ddprintk("regbase_virt: %#lx\n", par->mmio_vbase); f_ddprintk("membase_phys: %#lx\n", fix->smem_start); f_ddprintk("fbbase_virt: %p\n", info->screen_base); info->flags = FBINFO_DEFAULT; info->fbops = &sstfb_ops; info->pseudo_palette = par->palette; fix->type = FB_TYPE_PACKED_PIXELS; fix->visual = FB_VISUAL_TRUECOLOR; fix->accel = FB_ACCEL_NONE; /* FIXME */ /* * According to the specs, the linelength must be of 1024 *pixels* * and the 24bpp mode is in fact a 32 bpp mode (and both are in * fact dithered to 16bit). */ fix->line_length = 2048; /* default value, for 24 or 32bit: 4096 */ fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16); if (sstfb_check_var(&info->var, info)) { printk(KERN_ERR "sstfb: invalid video mode.\n"); goto fail; } if (sstfb_set_par(info)) { printk(KERN_ERR "sstfb: can't set default video mode.\n"); goto fail; } fb_alloc_cmap(&info->cmap, 256, 0); /* register fb */ info->device = &pdev->dev; if (register_framebuffer(info) < 0) { printk(KERN_ERR "sstfb: can't register framebuffer.\n"); goto fail; } sstfb_clear_screen(info); if (device_create_file(info->dev, &device_attrs[0])) printk(KERN_WARNING "sstfb: can't create sysfs entry.\n"); printk(KERN_INFO "fb%d: %s frame buffer device at 0x%p\n", info->node, fix->id, info->screen_base); return 0;fail: fb_dealloc_cmap(&info->cmap); iounmap(info->screen_base);fail_fb_remap: iounmap(par->mmio_vbase);fail_mmio_remap: release_mem_region(fix->smem_start, 0x400000);fail_fb_mem: release_mem_region(fix->mmio_start, info->fix.mmio_len);fail_mmio_mem: framebuffer_release(info); return -ENXIO; /* no voodoo detected */}static void __devexit sstfb_remove(struct pci_dev *pdev){ struct sstfb_par *par; struct fb_info *info; info = pci_get_drvdata(pdev); par = info->par; device_remove_file(info->dev, &device_attrs[0]); sst_shutdown(info); iounmap(info->screen_base); iounmap(par->mmio_vbase); release_mem_region(info->fix.smem_start, 0x400000); release_mem_region(info->fix.mmio_start, info->fix.mmio_len); fb_dealloc_cmap(&info->cmap); unregister_framebuffer(info); framebuffer_release(info);}static const struct pci_device_id sstfb_id_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO ), .driver_data = ID_VOODOO1, }, { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2), .driver_data = ID_VOODOO2, }, { 0 },};static struct pci_driver sstfb_driver = { .name = "sstfb", .id_table = sstfb_id_tbl, .probe = sstfb_probe, .remove = __devexit_p(sstfb_remove),};static int __devinit sstfb_init(void){ char *option = NULL; if (fb_get_options("sstfb", &option)) return -ENODEV; sstfb_setup(option); return pci_register_driver(&sstfb_driver);}static void __devexit sstfb_exit(void){ pci_unregister_driver(&sstfb_driver);}module_init(sstfb_init);module_exit(sstfb_exit);MODULE_AUTHOR("(c) 2000,2002 Ghozlane Toumi <gtoumi@laposte.net>");MODULE_DESCRIPTION("FBDev driver for 3dfx Voodoo Graphics and Voodoo2 based video boards");MODULE_LICENSE("GPL");module_param(mem, int, 0);MODULE_PARM_DESC(mem, "Size of frame buffer memory in MB (1, 2, 4 MB, default=autodetect)");module_param(vgapass, bool, 0);MODULE_PARM_DESC(vgapass, "Enable VGA PassThrough mode (0 or 1) (default=0)");module_param(clipping, bool, 0);MODULE_PARM_DESC(clipping, "Enable clipping (slower, safer) (0 or 1) (default=1)");module_param(gfxclk, int, 0);MODULE_PARM_DESC(gfxclk, "Force graphic chip frequency in MHz. DANGEROUS. (default=auto)");module_param(slowpci, bool, 0);MODULE_PARM_DESC(slowpci, "Uses slow PCI settings (0 or 1) (default=0)");module_param(mode_option, charp, 0);MODULE_PARM_DESC(mode_option, "Initial video mode (default=" DEFAULT_VIDEO_MODE ")");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -