📄 atyfb_base.c
字号:
break; case ATYIO_FEATR: if (get_user(info->features, (u32 *)arg)) return -EFAULT; break; case ATYIO_FEATW: if (put_user(info->features, (u32 *)arg)) return -EFAULT; break;#endif /* DEBUG && CONFIG_FB_ATY_CT */ default: return -EINVAL; } return 0;}static int atyfb_rasterimg(struct fb_info *info, int start){ struct fb_info_aty *fb = (struct fb_info_aty *)info; if (fb->blitter_may_be_busy) wait_for_idle(fb); return 0;}#ifdef __sparc__static int atyfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma){ struct fb_info_aty *fb = (struct fb_info_aty *)info; unsigned int size, page, map_size = 0; unsigned long map_offset = 0; unsigned long off; int i; if (!fb->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_SHM | VM_LOCKED); if (((vma->vm_pgoff == 0) && (size == fb->total_vram)) || ((off == fb->total_vram) && (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; fb->mmap_map[i].size; i++) { unsigned long start = fb->mmap_map[i].voff; unsigned long end = start + fb->mmap_map[i].size; unsigned long offset = off + page; if (start > offset) continue; if (offset >= end) continue; map_size = fb->mmap_map[i].size - (offset - start); map_offset = fb->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) &= ~(fb->mmap_map[i].prot_mask); pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag; if (remap_page_range(vma->vm_start + page, map_offset, map_size, vma->vm_page_prot)) return -EAGAIN; page += map_size; } if (!map_size) return -EINVAL; vma->vm_flags |= VM_IO; if (!fb->mmaped) { int lastconsole = 0; if (info->display_fg) lastconsole = info->display_fg->vc_num; fb->mmaped = 1; if (fb->consolecnt && fb_display[lastconsole].fb_info == info) { fb->vtconsole = lastconsole; vt_cons[lastconsole]->vc_mode = KD_GRAPHICS; } } return 0;}static struct { u32 yoffset; u8 r[2][256]; u8 g[2][256]; u8 b[2][256];} atyfb_save;static void atyfb_save_palette(struct fb_info *fb, int enter){ struct fb_info_aty *info = (struct fb_info_aty *)fb; int i, tmp; for (i = 0; i < 256; i++) { tmp = aty_ld_8(DAC_CNTL, info) & 0xfc; if (M64_HAS(EXTRA_BRIGHT)) tmp |= 0x2; aty_st_8(DAC_CNTL, tmp, info); aty_st_8(DAC_MASK, 0xff, info); writeb(i, &info->aty_cmap_regs->rindex); atyfb_save.r[enter][i] = readb(&info->aty_cmap_regs->lut); atyfb_save.g[enter][i] = readb(&info->aty_cmap_regs->lut); atyfb_save.b[enter][i] = readb(&info->aty_cmap_regs->lut); writeb(i, &info->aty_cmap_regs->windex); writeb(atyfb_save.r[1-enter][i], &info->aty_cmap_regs->lut); writeb(atyfb_save.g[1-enter][i], &info->aty_cmap_regs->lut); writeb(atyfb_save.b[1-enter][i], &info->aty_cmap_regs->lut); }}static void atyfb_palette(int enter){ struct fb_info_aty *info; struct atyfb_par *par; struct display *d; int i; for (i = 0; i < MAX_NR_CONSOLES; i++) { d = &fb_display[i]; if (d->fb_info && d->fb_info->fbops == &atyfb_ops && d->fb_info->display_fg && d->fb_info->display_fg->vc_num == i) { atyfb_save_palette(d->fb_info, enter); info = (struct fb_info_aty *)d->fb_info; par = &info->current_par; if (enter) { atyfb_save.yoffset = par->crtc.yoffset; par->crtc.yoffset = 0; set_off_pitch(par, info); } else { par->crtc.yoffset = atyfb_save.yoffset; set_off_pitch(par, info); } break; } }}#endif /* __sparc__ */#ifdef CONFIG_PMAC_PBOOKstatic struct fb_info_aty* first_display = NULL;/* Power management routines. Those are used for PowerBook sleep. * * It appears that Rage LT and Rage LT Pro have different power * management registers. There's is some confusion about which * chipID is a Rage LT or LT pro :( */static int aty_power_mgmt_LT(int sleep, struct fb_info_aty *info){ unsigned int pm; int timeout; pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; aty_st_le32(POWER_MANAGEMENT_LG, pm, info); pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); timeout = 200000; if (sleep) { /* Sleep */ pm &= ~PWR_MGT_ON; aty_st_le32(POWER_MANAGEMENT_LG, pm, info); pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); udelay(10); pm &= ~(PWR_BLON | AUTO_PWR_UP); pm |= SUSPEND_NOW; aty_st_le32(POWER_MANAGEMENT_LG, pm, info); pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); udelay(10); pm |= PWR_MGT_ON; aty_st_le32(POWER_MANAGEMENT_LG, pm, info); do { pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); udelay(10); if ((--timeout) == 0) break; } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); } else { /* Wakeup */ pm &= ~PWR_MGT_ON; aty_st_le32(POWER_MANAGEMENT_LG, pm, info); pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); udelay(10); pm |= (PWR_BLON | AUTO_PWR_UP); pm &= ~SUSPEND_NOW; aty_st_le32(POWER_MANAGEMENT_LG, pm, info); pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); udelay(10); pm |= PWR_MGT_ON; aty_st_le32(POWER_MANAGEMENT_LG, pm, info); do { pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); udelay(10); if ((--timeout) == 0) break; } while ((pm & PWR_MGT_STATUS_MASK) != 0); } mdelay(500); return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;}static int aty_power_mgmt_LTPro(int sleep, struct fb_info_aty *info){ unsigned int pm; int timeout; pm = aty_ld_lcd(POWER_MANAGEMENT, info); pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; aty_st_lcd(POWER_MANAGEMENT, pm, info); pm = aty_ld_lcd(POWER_MANAGEMENT, info); timeout = 200; if (sleep) { /* Sleep */ pm &= ~PWR_MGT_ON; aty_st_lcd(POWER_MANAGEMENT, pm, info); pm = aty_ld_lcd(POWER_MANAGEMENT, info); udelay(10); pm &= ~(PWR_BLON | AUTO_PWR_UP); pm |= SUSPEND_NOW; aty_st_lcd(POWER_MANAGEMENT, pm, info); pm = aty_ld_lcd(POWER_MANAGEMENT, info); udelay(10); pm |= PWR_MGT_ON; aty_st_lcd(POWER_MANAGEMENT, pm, info); do { pm = aty_ld_lcd(POWER_MANAGEMENT, info); 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, info); pm = aty_ld_lcd(POWER_MANAGEMENT, info); udelay(10); pm &= ~SUSPEND_NOW; pm |= (PWR_BLON | AUTO_PWR_UP); aty_st_lcd(POWER_MANAGEMENT, pm, info); pm = aty_ld_lcd(POWER_MANAGEMENT, info); udelay(10); pm |= PWR_MGT_ON; aty_st_lcd(POWER_MANAGEMENT, pm, info); do { pm = aty_ld_lcd(POWER_MANAGEMENT, info); mdelay(1); if ((--timeout) == 0) break; } while ((pm & PWR_MGT_STATUS_MASK) != 0); } return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;}static int aty_power_mgmt(int sleep, struct fb_info_aty *info){ return M64_HAS(LT_SLEEP) ? aty_power_mgmt_LT(sleep, info) : aty_power_mgmt_LTPro(sleep, info);}/* * Save the contents of the frame buffer when we go to sleep, * and restore it when we wake up again. */static int aty_sleep_notify(struct pmu_sleep_notifier *self, int when){ struct fb_info_aty *info; int result; result = PBOOK_SLEEP_OK; for (info = first_display; info != NULL; info = info->next) { struct fb_fix_screeninfo fix; int nb; atyfb_get_fix(&fix, fg_console, (struct fb_info *)info); nb = fb_display[fg_console].var.yres * fix.line_length; switch (when) { case PBOOK_SLEEP_REQUEST: info->save_framebuffer = vmalloc(nb); if (info->save_framebuffer == NULL) return PBOOK_SLEEP_REFUSE; break; case PBOOK_SLEEP_REJECT: if (info->save_framebuffer) { vfree(info->save_framebuffer); info->save_framebuffer = 0; } break; case PBOOK_SLEEP_NOW: if (currcon >= 0) fb_display[currcon].dispsw = &fbcon_dummy; if (info->blitter_may_be_busy) wait_for_idle(info); /* Stop accel engine (stop bus mastering) */ if (info->current_par.accel_flags & FB_ACCELF_TEXT) aty_reset_engine(info); /* Backup fb content */ if (info->save_framebuffer) memcpy_fromio(info->save_framebuffer, (void *)info->frame_buffer, nb); /* Blank display and LCD */ atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); /* Set chip to "suspend" mode */ result = aty_power_mgmt(1, info); break; case PBOOK_WAKE: /* Wakeup chip */ result = aty_power_mgmt(0, info); /* Restore fb content */ if (info->save_framebuffer) { memcpy_toio((void *)info->frame_buffer, info->save_framebuffer, nb); vfree(info->save_framebuffer); info->save_framebuffer = 0; } /* Restore display */ if (currcon >= 0) { atyfb_set_dispsw(&fb_display[currcon], info, info->current_par.crtc.bpp, info->current_par.accel_flags & FB_ACCELF_TEXT); } atyfbcon_blank(0, (struct fb_info *)info); break; } } return result;}static struct pmu_sleep_notifier aty_sleep_notifier = { aty_sleep_notify, SLEEP_LEVEL_VIDEO,};#endif /* CONFIG_PMAC_PBOOK */#ifdef CONFIG_PMAC_BACKLIGHT /* * LCD backlight control */static int backlight_conv[] = { 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d, 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff};static intaty_set_backlight_enable(int on, int level, void* data){ struct fb_info_aty *info = (struct fb_info_aty *)data; unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, info); reg |= (BLMOD_EN | BIASMOD_EN); if (on && level > BACKLIGHT_OFF) { reg &= ~BIAS_MOD_LEVEL_MASK; reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT); } else { reg &= ~BIAS_MOD_LEVEL_MASK; reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT); } aty_st_lcd(LCD_MISC_CNTL, reg, info); return 0;}static intaty_set_backlight_level(int level, void* data){ return aty_set_backlight_enable(1, level, data);}static struct backlight_controller aty_backlight_controller = { aty_set_backlight_enable, aty_set_backlight_level};#endif /* CONFIG_PMAC_BACKLIGHT */ /* * Initialisation */static struct fb_info_aty *fb_list = NULL;static int __init aty_init(struct fb_info_aty *info, const char *name){ u32 chip_id; u32 i; int j, k; struct fb_var_screeninfo var; struct display *disp; u16 type; u8 rev; const char *chipname = NULL, *ramname = NULL, *xtal; int pll, mclk, gtb_memsize;#if defined(CONFIG_PPC) int sense;#endif u8 pll_ref_div; info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0); chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); type = chip_id & CFG_CHIP_TYPE; rev = (chip_id & CFG_CHIP_REV)>>24; for (j = 0; j < (sizeof(aty_chips)/sizeof(*aty_chips)); j++) if (type == aty_chips[j].chip_type && (rev & aty_chips[j].rev_mask) == aty_chips[j].rev_val) { chipname = aty_chips[j].name;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -