📄 aty128fb.c
字号:
static void __devexit aty128_remove(struct pci_dev *pdev){ struct fb_info *info = pci_get_drvdata(pdev); struct aty128fb_par *par; if (!info) return; par = info->par; unregister_framebuffer(info);#ifdef CONFIG_MTRR if (par->mtrr.vram_valid) mtrr_del(par->mtrr.vram, info->fix.smem_start, par->vram_size);#endif /* CONFIG_MTRR */ iounmap(par->regbase); iounmap(info->screen_base); release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); release_mem_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); framebuffer_release(info);}#endif /* CONFIG_PCI */ /* * Blank the display. */static int aty128fb_blank(int blank, struct fb_info *fb){ struct aty128fb_par *par = fb->par; u8 state = 0; if (par->lock_blank || par->asleep) return 0;#ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && blank) set_backlight_enable(0);#endif /* CONFIG_PMAC_BACKLIGHT */ if (blank & FB_BLANK_VSYNC_SUSPEND) state |= 2; if (blank & FB_BLANK_HSYNC_SUSPEND) state |= 1; if (blank & FB_BLANK_POWERDOWN) state |= 4; aty_st_8(CRTC_EXT_CNTL+1, state); if (par->chip_gen == rage_M3) { aty128_set_crt_enable(par, par->crt_on && !blank); aty128_set_lcd_enable(par, par->lcd_on && !blank); }#ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && !blank) set_backlight_enable(1);#endif /* CONFIG_PMAC_BACKLIGHT */ return 0;}/* * Set a single color register. The values supplied are already * rounded down to the hardware's capabilities (according to the * entries in the var structure). Return != 0 for invalid regno. */static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info){ struct aty128fb_par *par = info->par; if (regno > 255 || (par->crtc.depth == 16 && regno > 63) || (par->crtc.depth == 15 && regno > 31)) return 1; red >>= 8; green >>= 8; blue >>= 8; if (regno < 16) { int i; u32 *pal = info->pseudo_palette; switch (par->crtc.depth) { case 15: pal[regno] = (regno << 10) | (regno << 5) | regno; break; case 16: pal[regno] = (regno << 11) | (regno << 6) | regno; break; case 24: pal[regno] = (regno << 16) | (regno << 8) | regno; break; case 32: i = (regno << 8) | regno; pal[regno] = (i << 16) | i; break; } } if (par->crtc.depth == 16 && regno > 0) { /* * With the 5-6-5 split of bits for RGB at 16 bits/pixel, we * have 32 slots for R and B values but 64 slots for G values. * Thus the R and B values go in one slot but the G value * goes in a different slot, and we have to avoid disturbing * the other fields in the slots we touch. */ par->green[regno] = green; if (regno < 32) { par->red[regno] = red; par->blue[regno] = blue; aty128_st_pal(regno * 8, red, par->green[regno*2], blue, par); } red = par->red[regno/2]; blue = par->blue[regno/2]; regno <<= 2; } else if (par->crtc.bpp == 16) regno <<= 3; aty128_st_pal(regno, red, green, blue, par); return 0;}#define ATY_MIRROR_LCD_ON 0x00000001#define ATY_MIRROR_CRT_ON 0x00000002/* out param: u32* backlight value: 0 to 15 */#define FBIO_ATY128_GET_MIRROR _IOR('@', 1, __u32)/* in param: u32* backlight value: 0 to 15 */#define FBIO_ATY128_SET_MIRROR _IOW('@', 2, __u32)static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, struct fb_info *info){ struct aty128fb_par *par = info->par; u32 value; int rc; switch (cmd) { case FBIO_ATY128_SET_MIRROR: if (par->chip_gen != rage_M3) return -EINVAL; rc = get_user(value, (__u32 __user *)arg); if (rc) return rc; par->lcd_on = (value & 0x01) != 0; par->crt_on = (value & 0x02) != 0; if (!par->crt_on && !par->lcd_on) par->lcd_on = 1; aty128_set_crt_enable(par, par->crt_on); aty128_set_lcd_enable(par, par->lcd_on); return 0; case FBIO_ATY128_GET_MIRROR: if (par->chip_gen != rage_M3) return -EINVAL; value = (par->crt_on << 1) | par->lcd_on; return put_user(value, (__u32 __user *)arg); } return -EINVAL;}#ifdef CONFIG_PMAC_BACKLIGHTstatic int backlight_conv[] = { 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24};/* We turn off the LCD completely instead of just dimming the backlight. * This provides greater power saving and the display is useless without * backlight anyway */#define BACKLIGHT_LVDS_OFF/* That one prevents proper CRT output with LCD off */#undef BACKLIGHT_DAC_OFFstatic int aty128_set_backlight_enable(int on, int level, void *data){ struct aty128fb_par *par = data; unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); if (!par->lcd_on) on = 0; reg |= LVDS_BL_MOD_EN | LVDS_BLON; if (on && level > BACKLIGHT_OFF) { reg |= LVDS_DIGION; if (!(reg & LVDS_ON)) { reg &= ~LVDS_BLON; aty_st_le32(LVDS_GEN_CNTL, reg); (void)aty_ld_le32(LVDS_GEN_CNTL); mdelay(10); reg |= LVDS_BLON; aty_st_le32(LVDS_GEN_CNTL, reg); } reg &= ~LVDS_BL_MOD_LEVEL_MASK; reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT);#ifdef BACKLIGHT_LVDS_OFF reg |= LVDS_ON | LVDS_EN; reg &= ~LVDS_DISPLAY_DIS;#endif aty_st_le32(LVDS_GEN_CNTL, reg);#ifdef BACKLIGHT_DAC_OFF aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));#endif } else { reg &= ~LVDS_BL_MOD_LEVEL_MASK; reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT);#ifdef BACKLIGHT_LVDS_OFF reg |= LVDS_DISPLAY_DIS; aty_st_le32(LVDS_GEN_CNTL, reg); (void)aty_ld_le32(LVDS_GEN_CNTL); udelay(10); reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);#endif aty_st_le32(LVDS_GEN_CNTL, reg);#ifdef BACKLIGHT_DAC_OFF aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);#endif } return 0;}static int aty128_set_backlight_level(int level, void* data){ return aty128_set_backlight_enable(1, level, data);}#endif /* CONFIG_PMAC_BACKLIGHT */#if 0 /* * Accelerated functions */static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty, u_int width, u_int height, struct fb_info_aty128 *par){ u32 save_dp_datatype, save_dp_cntl, dstval; if (!width || !height) return; dstval = depth_to_dst(par->current_par.crtc.depth); if (dstval == DST_24BPP) { srcx *= 3; dstx *= 3; width *= 3; } else if (dstval == -EINVAL) { printk("aty128fb: invalid depth or RGBA\n"); return; } wait_for_fifo(2, par); save_dp_datatype = aty_ld_le32(DP_DATATYPE); save_dp_cntl = aty_ld_le32(DP_CNTL); wait_for_fifo(6, par); aty_st_le32(SRC_Y_X, (srcy << 16) | srcx); aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT); aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM); aty_st_le32(DP_DATATYPE, save_dp_datatype | dstval | SRC_DSTCOLOR); aty_st_le32(DST_Y_X, (dsty << 16) | dstx); aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); par->blitter_may_be_busy = 1; wait_for_fifo(2, par); aty_st_le32(DP_DATATYPE, save_dp_datatype); aty_st_le32(DP_CNTL, save_dp_cntl); } /* * Text mode accelerated functions */static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width){ sx *= fontwidth(p); sy *= fontheight(p); dx *= fontwidth(p); dy *= fontheight(p); width *= fontwidth(p); height *= fontheight(p); aty128_rectcopy(sx, sy, dx, dy, width, height, (struct fb_info_aty128 *)p->fb_info);}#endif /* 0 */static void aty128_set_suspend(struct aty128fb_par *par, int suspend){ u32 pmgt; u16 pwr_command; struct pci_dev *pdev = par->pdev; if (!par->pm_reg) return; /* Set the chip into the appropriate suspend mode (we use D2, * D3 would require a complete re-initialisation of the chip, * including PCI config registers, clocks, AGP configuration, ...) */ if (suspend) { /* Make sure CRTC2 is reset. Remove that the day we decide to * actually use CRTC2 and replace it with real code for disabling * the CRTC2 output during sleep */ aty_st_le32(CRTC2_GEN_CNTL, aty_ld_le32(CRTC2_GEN_CNTL) & ~(CRTC2_EN)); /* Set the power management mode to be PCI based */ /* Use this magic value for now */ pmgt = 0x0c005407; aty_st_pll(POWER_MANAGEMENT, pmgt); (void)aty_ld_pll(POWER_MANAGEMENT); aty_st_le32(BUS_CNTL1, 0x00000010); aty_st_le32(MEM_POWER_MISC, 0x0c830000); mdelay(100); pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); /* Switch PCI power management to D2 */ pci_write_config_word(pdev, par->pm_reg+PCI_PM_CTRL, (pwr_command & ~PCI_PM_CTRL_STATE_MASK) | 2); pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); } else { /* Switch back PCI power management to D0 */ mdelay(100); pci_write_config_word(pdev, par->pm_reg+PCI_PM_CTRL, 0); pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); mdelay(100); }}static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state){ struct fb_info *info = pci_get_drvdata(pdev); struct aty128fb_par *par = info->par; /* We don't do anything but D2, for now we return 0, but * we may want to change that. How do we know if the BIOS * can properly take care of D3 ? Also, with swsusp, we * know we'll be rebooted, ... */#ifndef CONFIG_PPC_PMAC /* HACK ALERT ! Once I find a proper way to say to each driver * individually what will happen with it's PCI slot, I'll change * that. On laptops, the AGP slot is just unclocked, so D2 is * expected, while on desktops, the card is powered off */ return 0;#endif /* CONFIG_PPC_PMAC */ if (state.event == pdev->dev.power.power_state.event) return 0; printk(KERN_DEBUG "aty128fb: suspending...\n"); acquire_console_sem(); fb_set_suspend(info, 1); /* Make sure engine is reset */ wait_for_idle(par); aty128_reset_engine(par); wait_for_idle(par); /* Blank display and LCD */ aty128fb_blank(VESA_POWERDOWN, info); /* Sleep */ par->asleep = 1; par->lock_blank = 1;#ifdef CONFIG_PPC_PMAC /* On powermac, we have hooks to properly suspend/resume AGP now, * use them here. We'll ultimately need some generic support here, * but the generic code isn't quite ready for that yet */ pmac_suspend_agp_for_card(pdev);#endif /* CONFIG_PPC_PMAC */ /* We need a way to make sure the fbdev layer will _not_ touch the * framebuffer before we put the chip to suspend state. On 2.4, I * used dummy fb ops, 2.5 need proper support for this at the * fbdev level */ if (state.event != PM_EVENT_ON) aty128_set_suspend(par, 1); release_console_sem(); pdev->dev.power.power_state = state; return 0;}static int aty128_do_resume(struct pci_dev *pdev){ struct fb_info *info = pci_get_drvdata(pdev); struct aty128fb_par *par = info->par; if (pdev->dev.power.power_state.event == PM_EVENT_ON) return 0; /* Wakeup chip */ aty128_set_suspend(par, 0); par->asleep = 0; /* Restore display & engine */ aty128_reset_engine(par); wait_for_idle(par); aty128fb_set_par(info); fb_pan_display(info, &info->var); fb_set_cmap(&info->cmap, info); /* Refresh */ fb_set_suspend(info, 0); /* Unblank */ par->lock_blank = 0; aty128fb_blank(0, info);#ifdef CONFIG_PPC_PMAC /* On powermac, we have hooks to properly suspend/resume AGP now, * use them here. We'll ultimately need some generic support here, * but the generic code isn't quite ready for that yet */ pmac_resume_agp_for_card(pdev);#endif /* CONFIG_PPC_PMAC */ pdev->dev.power.power_state = PMSG_ON; printk(KERN_DEBUG "aty128fb: resumed !\n"); return 0;}static int aty128_pci_resume(struct pci_dev *pdev){ int rc; acquire_console_sem(); rc = aty128_do_resume(pdev); release_console_sem(); return rc;}static int __init aty128fb_init(void){#ifndef MODULE char *option = NULL; if (fb_get_options("aty128fb", &option)) return -ENODEV; aty128fb_setup(option);#endif return pci_register_driver(&aty128fb_driver);}static void __exit aty128fb_exit(void){ pci_unregister_driver(&aty128fb_driver);}module_init(aty128fb_init);module_exit(aty128fb_exit);MODULE_AUTHOR("(c)1999-2003 Brad Douglas <brad@neruo.com>");MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards");MODULE_LICENSE("GPL");module_param(mode_option, charp, 0);MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");#ifdef CONFIG_MTRRmodule_param_named(nomtrr, mtrr, invbool, 0);MODULE_PARM_DESC(nomtrr, "bool: Disable MTRR support (0 or 1=disabled) (default=0)");#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -