📄 atyfb_base.c
字号:
clk.dsp_precision = (dsp_config >> 20) & 7; clk.dsp_off = dsp_on_off & 0x7ff; clk.dsp_on = (dsp_on_off >> 16) & 0x7ff; if (copy_to_user((struct atyclk __user *) arg, &clk, sizeof(clk))) return -EFAULT; } else return -EINVAL; break; case ATYIO_CLKW: if (M64_HAS(INTEGRATED)) { struct atyclk clk; union aty_pll *pll = &(par->pll); if (copy_from_user(&clk, (struct atyclk __user *) arg, sizeof(clk))) return -EFAULT; par->ref_clk_per = clk.ref_clk_per; pll->ct.pll_ref_div = clk.pll_ref_div; pll->ct.mclk_fb_div = clk.mclk_fb_div; pll->ct.mclk_post_div_real = clk.mclk_post_div; pll->ct.mclk_fb_mult = clk.mclk_fb_mult; pll->ct.xclk_post_div_real = clk.xclk_post_div; pll->ct.vclk_fb_div = clk.vclk_fb_div; pll->ct.vclk_post_div_real = clk.vclk_post_div; pll->ct.dsp_config = (clk.dsp_xclks_per_row & 0x3fff) | ((clk.dsp_loop_latency & 0xf)<<16)| ((clk.dsp_precision & 7)<<20); pll->ct.dsp_on_off = (clk.dsp_off & 0x7ff) | ((clk.dsp_on & 0x7ff)<<16); /*aty_calc_pll_ct(info, &pll->ct);*/ aty_set_pll_ct(info, pll); } else return -EINVAL; break; case ATYIO_FEATR: if (get_user(par->features, (u32 __user *) arg)) return -EFAULT; break; case ATYIO_FEATW: if (put_user(par->features, (u32 __user *) arg)) return -EFAULT; break;#endif /* DEBUG && CONFIG_FB_ATY_CT */ default: return -EINVAL; } return 0;}static int atyfb_sync(struct fb_info *info){ struct atyfb_par *par = (struct atyfb_par *) info->par; if (par->blitter_may_be_busy) wait_for_idle(par); return 0;}#ifdef __sparc__static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma){ struct atyfb_par *par = (struct atyfb_par *) info->par; unsigned int size, page, map_size = 0; unsigned long map_offset = 0; unsigned long off; int i; if (!par->mmap_map) return -ENXIO; if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; size = vma->vm_end - vma->vm_start; /* To stop the swapper from even considering these pages. */ vma->vm_flags |= (VM_IO | VM_RESERVED); if (((vma->vm_pgoff == 0) && (size == info->fix.smem_len)) || ((off == info->fix.smem_len) && (size == PAGE_SIZE))) off += 0x8000000000000000UL; vma->vm_pgoff = off >> PAGE_SHIFT; /* propagate off changes */ /* Each page, see which map applies */ for (page = 0; page < size;) { map_size = 0; for (i = 0; par->mmap_map[i].size; i++) { unsigned long start = par->mmap_map[i].voff; unsigned long end = start + par->mmap_map[i].size; unsigned long offset = off + page; if (start > offset) continue; if (offset >= end) continue; map_size = par->mmap_map[i].size - (offset - start); map_offset = par->mmap_map[i].poff + (offset - start); break; } if (!map_size) { page += PAGE_SIZE; continue; } if (page + map_size > size) map_size = size - page; pgprot_val(vma->vm_page_prot) &= ~(par->mmap_map[i].prot_mask); pgprot_val(vma->vm_page_prot) |= par->mmap_map[i].prot_flag; if (remap_pfn_range(vma, vma->vm_start + page, map_offset >> PAGE_SHIFT, map_size, vma->vm_page_prot)) return -EAGAIN; page += map_size; } if (!map_size) return -EINVAL; if (!par->mmaped) par->mmaped = 1; return 0;}#endif /* __sparc__ */#if defined(CONFIG_PM) && defined(CONFIG_PCI)#ifdef CONFIG_PPC_PMAC/* Power management routines. Those are used for PowerBook sleep. */static int aty_power_mgmt(int sleep, struct atyfb_par *par){ u32 pm; int timeout; pm = aty_ld_lcd(POWER_MANAGEMENT, par); pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; aty_st_lcd(POWER_MANAGEMENT, pm, par); pm = aty_ld_lcd(POWER_MANAGEMENT, par); timeout = 2000; if (sleep) { /* Sleep */ pm &= ~PWR_MGT_ON; aty_st_lcd(POWER_MANAGEMENT, pm, par); pm = aty_ld_lcd(POWER_MANAGEMENT, par); udelay(10); pm &= ~(PWR_BLON | AUTO_PWR_UP); pm |= SUSPEND_NOW; aty_st_lcd(POWER_MANAGEMENT, pm, par); pm = aty_ld_lcd(POWER_MANAGEMENT, par); udelay(10); pm |= PWR_MGT_ON; aty_st_lcd(POWER_MANAGEMENT, pm, par); do { pm = aty_ld_lcd(POWER_MANAGEMENT, par); mdelay(1); if ((--timeout) == 0) break; } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); } else { /* Wakeup */ pm &= ~PWR_MGT_ON; aty_st_lcd(POWER_MANAGEMENT, pm, par); pm = aty_ld_lcd(POWER_MANAGEMENT, par); udelay(10); pm &= ~SUSPEND_NOW; pm |= (PWR_BLON | AUTO_PWR_UP); aty_st_lcd(POWER_MANAGEMENT, pm, par); pm = aty_ld_lcd(POWER_MANAGEMENT, par); udelay(10); pm |= PWR_MGT_ON; aty_st_lcd(POWER_MANAGEMENT, pm, par); do { pm = aty_ld_lcd(POWER_MANAGEMENT, par); mdelay(1); if ((--timeout) == 0) break; } while ((pm & PWR_MGT_STATUS_MASK) != 0); } mdelay(500); return timeout ? 0 : -EIO;}#endif /* CONFIG_PPC_PMAC */static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state){ struct fb_info *info = pci_get_drvdata(pdev); struct atyfb_par *par = (struct atyfb_par *) info->par; if (state.event == pdev->dev.power.power_state.event) return 0; acquire_console_sem(); fb_set_suspend(info, 1); /* Idle & reset engine */ wait_for_idle(par); aty_reset_engine(par); /* Blank display and LCD */ atyfb_blank(FB_BLANK_POWERDOWN, info); par->asleep = 1; par->lock_blank = 1; /* Because we may change PCI D state ourselves, we need to * first save the config space content so the core can * restore it properly on resume. */ pci_save_state(pdev);#ifdef CONFIG_PPC_PMAC /* Set chip to "suspend" mode */ if (machine_is(powermac) && aty_power_mgmt(1, par)) { par->asleep = 0; par->lock_blank = 0; atyfb_blank(FB_BLANK_UNBLANK, info); fb_set_suspend(info, 0); release_console_sem(); return -EIO; }#else pci_set_power_state(pdev, pci_choose_state(pdev, state));#endif release_console_sem(); pdev->dev.power.power_state = state; return 0;}static void aty_resume_chip(struct fb_info *info){ struct atyfb_par *par = info->par; aty_st_le32(MEM_CNTL, par->mem_cntl, par); if (par->pll_ops->resume_pll) par->pll_ops->resume_pll(info, &par->pll); if (par->aux_start) aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par);}static int atyfb_pci_resume(struct pci_dev *pdev){ struct fb_info *info = pci_get_drvdata(pdev); struct atyfb_par *par = (struct atyfb_par *) info->par; if (pdev->dev.power.power_state.event == PM_EVENT_ON) return 0; acquire_console_sem(); /* PCI state will have been restored by the core, so * we should be in D0 now with our config space fully * restored */#ifdef CONFIG_PPC_PMAC if (machine_is(powermac) && pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) aty_power_mgmt(0, par);#endif aty_resume_chip(info); par->asleep = 0; /* Restore display */ atyfb_set_par(info); /* Refresh */ fb_set_suspend(info, 0); /* Unblank */ par->lock_blank = 0; atyfb_blank(FB_BLANK_UNBLANK, info); release_console_sem(); pdev->dev.power.power_state = PMSG_ON; return 0;}#endif /* defined(CONFIG_PM) && defined(CONFIG_PCI) *//* Backlight */#ifdef CONFIG_FB_ATY_BACKLIGHT#define MAX_LEVEL 0xFFstatic int aty_bl_get_level_brightness(struct atyfb_par *par, int level){ struct fb_info *info = pci_get_drvdata(par->pdev); int atylevel; /* Get and convert the value */ /* No locking of bl_curve since we read a single value */ atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL; if (atylevel < 0) atylevel = 0; else if (atylevel > MAX_LEVEL) atylevel = MAX_LEVEL; return atylevel;}static int aty_bl_update_status(struct backlight_device *bd){ struct atyfb_par *par = bl_get_data(bd); unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par); int level; if (bd->props.power != FB_BLANK_UNBLANK || bd->props.fb_blank != FB_BLANK_UNBLANK) level = 0; else level = bd->props.brightness; reg |= (BLMOD_EN | BIASMOD_EN); if (level > 0) { reg &= ~BIAS_MOD_LEVEL_MASK; reg |= (aty_bl_get_level_brightness(par, level) << BIAS_MOD_LEVEL_SHIFT); } else { reg &= ~BIAS_MOD_LEVEL_MASK; reg |= (aty_bl_get_level_brightness(par, 0) << BIAS_MOD_LEVEL_SHIFT); } aty_st_lcd(LCD_MISC_CNTL, reg, par); return 0;}static int aty_bl_get_brightness(struct backlight_device *bd){ return bd->props.brightness;}static struct backlight_ops aty_bl_data = { .get_brightness = aty_bl_get_brightness, .update_status = aty_bl_update_status,};static void aty_bl_init(struct atyfb_par *par){ struct fb_info *info = pci_get_drvdata(par->pdev); struct backlight_device *bd; char name[12];#ifdef CONFIG_PMAC_BACKLIGHT if (!pmac_has_backlight_type("ati")) return;#endif snprintf(name, sizeof(name), "atybl%d", info->node); bd = backlight_device_register(name, info->dev, par, &aty_bl_data); if (IS_ERR(bd)) { info->bl_dev = NULL; printk(KERN_WARNING "aty: Backlight registration failed\n"); goto error; } info->bl_dev = bd; fb_bl_default_curve(info, 0, 0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL, 0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL); bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd->props.brightness = bd->props.max_brightness; bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); printk("aty: Backlight initialized (%s)\n", name); return;error: return;}static void aty_bl_exit(struct backlight_device *bd){ backlight_device_unregister(bd); printk("aty: Backlight unloaded\n");}#endif /* CONFIG_FB_ATY_BACKLIGHT */static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk){ const int ragepro_tbl[] = { 44, 50, 55, 66, 75, 80, 100 }; const int ragexl_tbl[] = { 50, 66, 75, 83, 90, 95, 100, 105, 110, 115, 120, 125, 133, 143, 166 }; const int *refresh_tbl; int i, size; if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) { refresh_tbl = ragexl_tbl; size = ARRAY_SIZE(ragexl_tbl); } else { refresh_tbl = ragepro_tbl; size = ARRAY_SIZE(ragepro_tbl); } for (i=0; i < size; i++) { if (xclk < refresh_tbl[i]) break; } par->mem_refresh_rate = i;} /* * Initialisation */static struct fb_info *fb_list = NULL;#if defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD)static int __devinit atyfb_get_timings_from_lcd(struct atyfb_par *par, struct fb_var_screeninfo *var){ int ret = -EINVAL; if (par->lcd_table != 0 && (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { *var = default_var; var->xres = var->xres_virtual = par->lcd_hdisp; var->right_margin = par->lcd_right_margin; var->left_margin = par->lcd_hblank_len - (pa
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -