📄 atyfb_base.c
字号:
#endif /* DEBUG */ if (!M64_HAS(INTEGRATED)) { /* Don't forget MEM_CNTL */ tmp = aty_ld_le32(MEM_CNTL, par) & 0xf0ffffff; switch (var->bits_per_pixel) { case 8: tmp |= 0x02000000; break; case 16: tmp |= 0x03000000; break; case 32: tmp |= 0x06000000; break; } aty_st_le32(MEM_CNTL, tmp, par); } else { tmp = aty_ld_le32(MEM_CNTL, par) & 0xf00fffff; if (!M64_HAS(MAGIC_POSTDIV)) tmp |= par->mem_refresh_rate << 20; switch (var->bits_per_pixel) { case 8: case 24: tmp |= 0x00000000; break; case 16: tmp |= 0x04000000; break; case 32: tmp |= 0x08000000; break; } if (M64_HAS(CT_BUS)) { aty_st_le32(DAC_CNTL, 0x87010184, par); aty_st_le32(BUS_CNTL, 0x680000f9, par); } else if (M64_HAS(VT_BUS)) { aty_st_le32(DAC_CNTL, 0x87010184, par); aty_st_le32(BUS_CNTL, 0x680000f9, par); } else if (M64_HAS(MOBIL_BUS)) { aty_st_le32(DAC_CNTL, 0x80010102, par); aty_st_le32(BUS_CNTL, 0x7b33a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par); } else { /* GT */ aty_st_le32(DAC_CNTL, 0x86010102, par); aty_st_le32(BUS_CNTL, 0x7b23a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par); aty_st_le32(EXT_MEM_CNTL, aty_ld_le32(EXT_MEM_CNTL, par) | 0x5000001, par); } aty_st_le32(MEM_CNTL, tmp, par); } aty_st_8(DAC_MASK, 0xff, par); info->fix.line_length = var->xres_virtual * var->bits_per_pixel/8; info->fix.visual = var->bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; /* Initialize the graphics engine */ if (par->accel_flags & FB_ACCELF_TEXT) aty_init_engine(par, info);#ifdef CONFIG_BOOTX_TEXT btext_update_display(info->fix.smem_start, (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8, ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1, var->bits_per_pixel, par->crtc.vxres * var->bits_per_pixel / 8);#endif /* CONFIG_BOOTX_TEXT */#if 0 /* switch to accelerator mode */ if (!(par->crtc.gen_cntl & CRTC_EXT_DISP_EN)) aty_st_le32(CRTC_GEN_CNTL, par->crtc.gen_cntl | CRTC_EXT_DISP_EN, par);#endif#ifdef DEBUG{ /* dump non shadow CRTC, pll, LCD registers */ int i; u32 base; /* CRTC registers */ base = 0x2000; printk("debug atyfb: Mach64 non-shadow register values:"); for (i = 0; i < 256; i = i+4) { if(i%16 == 0) printk("\ndebug atyfb: 0x%04X: ", base + i); printk(" %08X", aty_ld_le32(i, par)); } printk("\n\n");#ifdef CONFIG_FB_ATY_CT /* PLL registers */ base = 0x00; printk("debug atyfb: Mach64 PLL register values:"); for (i = 0; i < 64; i++) { if(i%16 == 0) printk("\ndebug atyfb: 0x%02X: ", base + i); if(i%4 == 0) printk(" "); printk("%02X", aty_ld_pll_ct(i, par)); } printk("\n\n");#endif /* CONFIG_FB_ATY_CT */#ifdef CONFIG_FB_ATY_GENERIC_LCD if (par->lcd_table != 0) { /* LCD registers */ base = 0x00; printk("debug atyfb: LCD register values:"); if(M64_HAS(LT_LCD_REGS)) { for(i = 0; i <= POWER_MANAGEMENT; i++) { if(i == EXT_VERT_STRETCH) continue; printk("\ndebug atyfb: 0x%04X: ", lt_lcd_regs[i]); printk(" %08X", aty_ld_lcd(i, par)); } } else { for (i = 0; i < 64; i++) { if(i%4 == 0) printk("\ndebug atyfb: 0x%02X: ", base + i); printk(" %08X", aty_ld_lcd(i, par)); } } printk("\n\n"); }#endif /* CONFIG_FB_ATY_GENERIC_LCD */}#endif /* DEBUG */ return 0;}static int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ struct atyfb_par *par = (struct atyfb_par *) info->par; int err; struct crtc crtc; union aty_pll pll; u32 pixclock; memcpy(&pll, &(par->pll), sizeof(pll)); if((err = aty_var_to_crtc(info, var, &crtc))) return err; pixclock = atyfb_get_pixclock(var, par); if (pixclock == 0) { if (!(var->activate & FB_ACTIVATE_TEST)) PRINTKE("Invalid pixclock\n"); return -EINVAL; } else { if((err = par->pll_ops->var_to_pll(info, pixclock, var->bits_per_pixel, &pll))) return err; } if (var->accel_flags & FB_ACCELF_TEXT) info->var.accel_flags = FB_ACCELF_TEXT; else info->var.accel_flags = 0; aty_crtc_to_var(&crtc, var); var->pixclock = par->pll_ops->pll_to_var(info, &pll); return 0;}static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info){ u32 xoffset = info->var.xoffset; u32 yoffset = info->var.yoffset; u32 vxres = par->crtc.vxres; u32 bpp = info->var.bits_per_pixel; par->crtc.off_pitch = ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19);} /* * Open/Release the frame buffer device */static int atyfb_open(struct fb_info *info, int user){ struct atyfb_par *par = (struct atyfb_par *) info->par; if (user) { par->open++;#ifdef __sparc__ par->mmaped = 0;#endif } return (0);}static irqreturn_t aty_irq(int irq, void *dev_id){ struct atyfb_par *par = dev_id; int handled = 0; u32 int_cntl; spin_lock(&par->int_lock); int_cntl = aty_ld_le32(CRTC_INT_CNTL, par); if (int_cntl & CRTC_VBLANK_INT) { /* clear interrupt */ aty_st_le32(CRTC_INT_CNTL, (int_cntl & CRTC_INT_EN_MASK) | CRTC_VBLANK_INT_AK, par); par->vblank.count++; if (par->vblank.pan_display) { par->vblank.pan_display = 0; aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par); } wake_up_interruptible(&par->vblank.wait); handled = 1; } spin_unlock(&par->int_lock); return IRQ_RETVAL(handled);}static int aty_enable_irq(struct atyfb_par *par, int reenable){ u32 int_cntl; if (!test_and_set_bit(0, &par->irq_flags)) { if (request_irq(par->irq, aty_irq, IRQF_SHARED, "atyfb", par)) { clear_bit(0, &par->irq_flags); return -EINVAL; } spin_lock_irq(&par->int_lock); int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK; /* clear interrupt */ aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_AK, par); /* enable interrupt */ aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par); spin_unlock_irq(&par->int_lock); } else if (reenable) { spin_lock_irq(&par->int_lock); int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK; if (!(int_cntl & CRTC_VBLANK_INT_EN)) { printk("atyfb: someone disabled IRQ [%08x]\n", int_cntl); /* re-enable interrupt */ aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par ); } spin_unlock_irq(&par->int_lock); } return 0;}static int aty_disable_irq(struct atyfb_par *par){ u32 int_cntl; if (test_and_clear_bit(0, &par->irq_flags)) { if (par->vblank.pan_display) { par->vblank.pan_display = 0; aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par); } spin_lock_irq(&par->int_lock); int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK; /* disable interrupt */ aty_st_le32(CRTC_INT_CNTL, int_cntl & ~CRTC_VBLANK_INT_EN, par ); spin_unlock_irq(&par->int_lock); free_irq(par->irq, par); } return 0;}static int atyfb_release(struct fb_info *info, int user){ struct atyfb_par *par = (struct atyfb_par *) info->par; if (user) { par->open--; mdelay(1); wait_for_idle(par); if (!par->open) {#ifdef __sparc__ int was_mmaped = par->mmaped; par->mmaped = 0; if (was_mmaped) { struct fb_var_screeninfo var; /* Now reset the default display config, we have no * idea what the program(s) which mmap'd the chip did * to the configuration, nor whether it restored it * correctly. */ var = default_var; if (noaccel) var.accel_flags &= ~FB_ACCELF_TEXT; else var.accel_flags |= FB_ACCELF_TEXT; if (var.yres == var.yres_virtual) { u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2)); var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual; if (var.yres_virtual < var.yres) var.yres_virtual = var.yres; } }#endif aty_disable_irq(par); } } return (0);} /* * Pan or Wrap the Display * * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag */static int atyfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info){ struct atyfb_par *par = (struct atyfb_par *) info->par; u32 xres, yres, xoffset, yoffset; xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8; yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1; if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN) yres >>= 1; xoffset = (var->xoffset + 7) & ~7; yoffset = var->yoffset; if (xoffset + xres > par->crtc.vxres || yoffset + yres > par->crtc.vyres) return -EINVAL; info->var.xoffset = xoffset; info->var.yoffset = yoffset; if (par->asleep) return 0; set_off_pitch(par, info); if ((var->activate & FB_ACTIVATE_VBL) && !aty_enable_irq(par, 0)) { par->vblank.pan_display = 1; } else { par->vblank.pan_display = 0; aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par); } return 0;}static int aty_waitforvblank(struct atyfb_par *par, u32 crtc){ struct aty_interrupt *vbl; unsigned int count; int ret; switch (crtc) { case 0: vbl = &par->vblank; break; default: return -ENODEV; } ret = aty_enable_irq(par, 0); if (ret) return ret; count = vbl->count; ret = wait_event_interruptible_timeout(vbl->wait, count != vbl->count, HZ/10); if (ret < 0) { return ret; } if (ret == 0) { aty_enable_irq(par, 1); return -ETIMEDOUT; } return 0;}#ifdef DEBUG#define ATYIO_CLKR 0x41545900 /* ATY\00 */#define ATYIO_CLKW 0x41545901 /* ATY\01 */struct atyclk { u32 ref_clk_per; u8 pll_ref_div; u8 mclk_fb_div; u8 mclk_post_div; /* 1,2,3,4,8 */ u8 mclk_fb_mult; /* 2 or 4 */ u8 xclk_post_div; /* 1,2,3,4,8 */ u8 vclk_fb_div; u8 vclk_post_div; /* 1,2,3,4,6,8,12 */ u32 dsp_xclks_per_row; /* 0-16383 */ u32 dsp_loop_latency; /* 0-15 */ u32 dsp_precision; /* 0-7 */ u32 dsp_on; /* 0-2047 */ u32 dsp_off; /* 0-2047 */};#define ATYIO_FEATR 0x41545902 /* ATY\02 */#define ATYIO_FEATW 0x41545903 /* ATY\03 */#endif#ifndef FBIO_WAITFORVSYNC#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)#endifstatic int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg){ struct atyfb_par *par = (struct atyfb_par *) info->par;#ifdef __sparc__ struct fbtype fbtyp;#endif switch (cmd) {#ifdef __sparc__ case FBIOGTYPE: fbtyp.fb_type = FBTYPE_PCI_GENERIC; fbtyp.fb_width = par->crtc.vxres; fbtyp.fb_height = par->crtc.vyres; fbtyp.fb_depth = info->var.bits_per_pixel; fbtyp.fb_cmsize = info->cmap.len; fbtyp.fb_size = info->fix.smem_len; if (copy_to_user((struct fbtype __user *) arg, &fbtyp, sizeof(fbtyp))) return -EFAULT; break;#endif /* __sparc__ */ case FBIO_WAITFORVSYNC: { u32 crtc; if (get_user(crtc, (__u32 __user *) arg)) return -EFAULT; return aty_waitforvblank(par, crtc); } break;#if defined(DEBUG) && defined(CONFIG_FB_ATY_CT) case ATYIO_CLKR: if (M64_HAS(INTEGRATED)) { struct atyclk clk; union aty_pll *pll = &(par->pll); u32 dsp_config = pll->ct.dsp_config; u32 dsp_on_off = pll->ct.dsp_on_off; clk.ref_clk_per = par->ref_clk_per; clk.pll_ref_div = pll->ct.pll_ref_div; clk.mclk_fb_div = pll->ct.mclk_fb_div; clk.mclk_post_div = pll->ct.mclk_post_div_real; clk.mclk_fb_mult = pll->ct.mclk_fb_mult; clk.xclk_post_div = pll->ct.xclk_post_div_real; clk.vclk_fb_div = pll->ct.vclk_fb_div; clk.vclk_post_div = pll->ct.vclk_post_div_real; clk.dsp_xclks_per_row = dsp_config & 0x3fff; clk.dsp_loop_latency = (dsp_config >> 16) & 0xf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -