📄 aty128fb.c
字号:
static void_aty_st_pll(unsigned int pll_index, u32 val, const struct fb_info_aty128 *info){ aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x1F) | PLL_WR_EN); aty_st_le32(CLOCK_CNTL_DATA, val);}/* return true when the PLL has completed an atomic update */static intaty_pll_readupdate(const struct fb_info_aty128 *info){ return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R);}static voidaty_pll_wait_readupdate(const struct fb_info_aty128 *info){ unsigned long timeout = jiffies + HZ/100; // should be more than enough int reset = 1; while (time_before(jiffies, timeout)) if (aty_pll_readupdate(info)) { reset = 0; break; } if (reset) /* reset engine?? */ printk(KERN_DEBUG "aty128fb: PLL write timeout!");}/* tell PLL to update */static voidaty_pll_writeupdate(const struct fb_info_aty128 *info){ aty_pll_wait_readupdate(info); aty_st_pll(PPLL_REF_DIV, aty_ld_pll(PPLL_REF_DIV) | PPLL_ATOMIC_UPDATE_W);}/* write to the scratch register to test r/w functionality */static int __initregister_test(const struct fb_info_aty128 *info){ u32 val; int flag = 0; val = aty_ld_le32(BIOS_0_SCRATCH); aty_st_le32(BIOS_0_SCRATCH, 0x55555555); if (aty_ld_le32(BIOS_0_SCRATCH) == 0x55555555) { aty_st_le32(BIOS_0_SCRATCH, 0xAAAAAAAA); if (aty_ld_le32(BIOS_0_SCRATCH) == 0xAAAAAAAA) flag = 1; } aty_st_le32(BIOS_0_SCRATCH, val); // restore value return flag;} /* * Accelerator engine functions */static voiddo_wait_for_fifo(u16 entries, struct fb_info_aty128 *info){ int i; for (;;) { for (i = 0; i < 2000000; i++) { info->fifo_slots = aty_ld_le32(GUI_STAT) & 0x0fff; if (info->fifo_slots >= entries) return; } aty128_reset_engine(info); }}static voidwait_for_idle(struct fb_info_aty128 *info){ int i; do_wait_for_fifo(64, info); for (;;) { for (i = 0; i < 2000000; i++) { if (!(aty_ld_le32(GUI_STAT) & (1 << 31))) { aty128_flush_pixel_cache(info); info->blitter_may_be_busy = 0; return; } } aty128_reset_engine(info); }}static voidwait_for_fifo(u16 entries, struct fb_info_aty128 *info){ if (info->fifo_slots < entries) do_wait_for_fifo(64, info); info->fifo_slots -= entries;}static voidaty128_flush_pixel_cache(const struct fb_info_aty128 *info){ int i; u32 tmp; tmp = aty_ld_le32(PC_NGUI_CTLSTAT); tmp &= ~(0x00ff); tmp |= 0x00ff; aty_st_le32(PC_NGUI_CTLSTAT, tmp); for (i = 0; i < 2000000; i++) if (!(aty_ld_le32(PC_NGUI_CTLSTAT) & PC_BUSY)) break;}static voidaty128_reset_engine(const struct fb_info_aty128 *info){ u32 gen_reset_cntl, clock_cntl_index, mclk_cntl; aty128_flush_pixel_cache(info); clock_cntl_index = aty_ld_le32(CLOCK_CNTL_INDEX); mclk_cntl = aty_ld_pll(MCLK_CNTL); aty_st_pll(MCLK_CNTL, mclk_cntl | 0x00030000); gen_reset_cntl = aty_ld_le32(GEN_RESET_CNTL); aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl | SOFT_RESET_GUI); aty_ld_le32(GEN_RESET_CNTL); aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl & ~(SOFT_RESET_GUI)); aty_ld_le32(GEN_RESET_CNTL); aty_st_pll(MCLK_CNTL, mclk_cntl); aty_st_le32(CLOCK_CNTL_INDEX, clock_cntl_index); aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl); /* use old pio mode */ aty_st_le32(PM4_BUFFER_CNTL, PM4_BUFFER_CNTL_NONPM4); DBG("engine reset");}static voidaty128_init_engine(const struct aty128fb_par *par, struct fb_info_aty128 *info){ u32 pitch_value; wait_for_idle(info); /* 3D scaler not spoken here */ wait_for_fifo(1, info); aty_st_le32(SCALE_3D_CNTL, 0x00000000); aty128_reset_engine(info); pitch_value = par->crtc.pitch; if (par->crtc.bpp == 24) { pitch_value = pitch_value * 3; } wait_for_fifo(4, info); /* setup engine offset registers */ aty_st_le32(DEFAULT_OFFSET, 0x00000000); /* setup engine pitch registers */ aty_st_le32(DEFAULT_PITCH, pitch_value); /* set the default scissor register to max dimensions */ aty_st_le32(DEFAULT_SC_BOTTOM_RIGHT, (0x1FFF << 16) | 0x1FFF); /* set the drawing controls registers */ aty_st_le32(DP_GUI_MASTER_CNTL, GMC_SRC_PITCH_OFFSET_DEFAULT | GMC_DST_PITCH_OFFSET_DEFAULT | GMC_SRC_CLIP_DEFAULT | GMC_DST_CLIP_DEFAULT | GMC_BRUSH_SOLIDCOLOR | (bpp_to_depth(par->crtc.bpp) << 8) | GMC_SRC_DSTCOLOR | GMC_BYTE_ORDER_MSB_TO_LSB | GMC_DP_CONVERSION_TEMP_6500 | ROP3_PATCOPY | GMC_DP_SRC_RECT | GMC_3D_FCN_EN_CLR | GMC_DST_CLR_CMP_FCN_CLEAR | GMC_AUX_CLIP_CLEAR | GMC_WRITE_MASK_SET); wait_for_fifo(8, info); /* clear the line drawing registers */ aty_st_le32(DST_BRES_ERR, 0); aty_st_le32(DST_BRES_INC, 0); aty_st_le32(DST_BRES_DEC, 0); /* set brush color registers */ aty_st_le32(DP_BRUSH_FRGD_CLR, 0xFFFFFFFF); /* white */ aty_st_le32(DP_BRUSH_BKGD_CLR, 0x00000000); /* black */ /* set source color registers */ aty_st_le32(DP_SRC_FRGD_CLR, 0xFFFFFFFF); /* white */ aty_st_le32(DP_SRC_BKGD_CLR, 0x00000000); /* black */ /* default write mask */ aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF); /* Wait for all the writes to be completed before returning */ wait_for_idle(info);}/* convert bpp values to their register representation */static u32bpp_to_depth(u32 bpp){ if (bpp <= 8) return DST_8BPP; else if (bpp <= 16) return DST_15BPP; else if (bpp <= 24) return DST_24BPP; else if (bpp <= 32) return DST_32BPP; return -EINVAL;} /* * CRTC programming *//* Program the CRTC registers */static voidaty128_set_crtc(const struct aty128_crtc *crtc, const struct fb_info_aty128 *info){ aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl); aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total); aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid); aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_total); aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid); aty_st_le32(CRTC_PITCH, crtc->pitch); aty_st_le32(CRTC_OFFSET, crtc->offset); aty_st_le32(CRTC_OFFSET_CNTL, crtc->offset_cntl); /* Disable ATOMIC updating. Is this the right place? * -- BenH: Breaks on my G4 */#if 0 aty_st_le32(PPLL_CNTL, aty_ld_le32(PPLL_CNTL) & ~(0x00030000));#endif}static intaty128_var_to_crtc(const struct fb_var_screeninfo *var, struct aty128_crtc *crtc, const struct fb_info_aty128 *info){ u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; u32 left, right, upper, lower, hslen, vslen, sync, vmode; u32 h_total, h_disp, h_sync_strt, h_sync_wid, h_sync_pol; u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 depth, bytpp; u8 hsync_strt_pix[5] = { 0, 0x12, 9, 6, 5 }; u8 mode_bytpp[7] = { 0, 0, 1, 2, 2, 3, 4 }; /* input */ xres = var->xres; yres = var->yres; vxres = var->xres_virtual; vyres = var->yres_virtual; xoffset = var->xoffset; yoffset = var->yoffset; bpp = var->bits_per_pixel; left = var->left_margin; right = var->right_margin; upper = var->upper_margin; lower = var->lower_margin; hslen = var->hsync_len; vslen = var->vsync_len; sync = var->sync; vmode = var->vmode; /* check for mode eligibility * accept only non interlaced modes */ if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) return -EINVAL; /* convert (and round up) and validate */ xres = (xres + 7) & ~7; xoffset = (xoffset + 7) & ~7; if (vxres < xres + xoffset) vxres = xres + xoffset; if (vyres < yres + yoffset) vyres = yres + yoffset; /* convert bpp into ATI register depth */ depth = bpp_to_depth(bpp); /* make sure we didn't get an invalid depth */ if (depth == -EINVAL) { printk(KERN_ERR "aty128fb: Invalid depth\n"); return -EINVAL; } /* convert depth to bpp */ bytpp = mode_bytpp[depth]; /* make sure there is enough video ram for the mode */ if ((u32)(vxres * vyres * bytpp) > info->vram_size) { printk(KERN_ERR "aty128fb: Not enough memory for mode\n"); return -EINVAL; } h_disp = (xres >> 3) - 1; h_total = (((xres + right + hslen + left) >> 3) - 1) & 0xFFFFL; v_disp = yres - 1; v_total = (yres + upper + vslen + lower - 1) & 0xFFFFL; /* check to make sure h_total and v_total are in range */ if (((h_total >> 3) - 1) > 0x1ff || (v_total - 1) > 0x7FF) { printk(KERN_ERR "aty128fb: invalid width ranges\n"); return -EINVAL; } h_sync_wid = (hslen + 7) >> 3; if (h_sync_wid == 0) h_sync_wid = 1; else if (h_sync_wid > 0x3f) /* 0x3f = max hwidth */ h_sync_wid = 0x3f; h_sync_strt = h_disp + (right >> 3); v_sync_wid = vslen; if (v_sync_wid == 0) v_sync_wid = 1; else if (v_sync_wid > 0x1f) /* 0x1f = max vwidth */ v_sync_wid = 0x1f; v_sync_strt = v_disp + lower; h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; crtc->gen_cntl = 0x3000000L | c_sync | (depth << 8); crtc->h_total = h_total | (h_disp << 16); crtc->v_total = v_total | (v_disp << 16); crtc->h_sync_strt_wid = hsync_strt_pix[bytpp] | (h_sync_strt << 3) | (h_sync_wid << 16) | (h_sync_pol << 23); crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) | (v_sync_pol << 23); crtc->pitch = vxres >> 3; crtc->offset = 0; crtc->offset_cntl = 0; crtc->vxres = vxres; crtc->vyres = vyres; crtc->xoffset = xoffset; crtc->yoffset = yoffset; crtc->bpp = bpp; return 0;}static intaty128_bpp_to_var(int pix_width, struct fb_var_screeninfo *var){ /* fill in pixel info */ switch (pix_width) { case CRTC_PIX_WIDTH_8BPP: var->bits_per_pixel = 8; var->red.offset = 0; var->red.length = 8; var->green.offset = 0; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 0; var->transp.length = 0; break; case CRTC_PIX_WIDTH_15BPP: case CRTC_PIX_WIDTH_16BPP: var->bits_per_pixel = 16; var->red.offset = 10; var->red.length = 5; var->green.offset = 5; var->green.length = 5; var->blue.offset = 0; var->blue.length = 5; var->transp.offset = 0; var->transp.length = 0; break; case CRTC_PIX_WIDTH_24BPP: var->bits_per_pixel = 24; var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 0; var->transp.length = 0; break; case CRTC_PIX_WIDTH_32BPP: var->bits_per_pixel = 32; var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 24; var->transp.length = 8; break; default: printk(KERN_ERR "aty128fb: Invalid pixel width\n"); return -EINVAL; } return 0;}static intaty128_crtc_to_var(const struct aty128_crtc *crtc, struct fb_var_screeninfo *var){ u32 xres, yres, left, right, upper, lower, hslen, vslen, sync; u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 pix_width; /* fun with masking */ h_total = crtc->h_total & 0x1ff; h_disp = (crtc->h_total >> 16) & 0xff; h_sync_strt = (crtc->h_sync_strt_wid >> 3) & 0x1ff; h_sync_dly = crtc->h_sync_strt_wid & 0x7; h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x3f; h_sync_pol = (crtc->h_sync_strt_wid >> 23) & 0x1; v_total = crtc->v_total & 0x7ff; v_disp = (crtc->v_total >> 16) & 0x7ff; v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f; v_sync_pol = (crtc->v_sync_strt_wid >> 23) & 0x1; c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; /* do conversions */ xres = (h_disp + 1) << 3; yres = v_disp + 1; left = ((h_total - h_sync_strt - h_sync_wid) << 3) - h_sync_dly; right = ((h_sync_strt - h_disp) << 3) + h_sync_dly; hslen = h_sync_wid << 3; upper = v_total - v_sync_strt - v_sync_wid; lower = v_sync_strt - v_disp; vslen = v_sync_wid; sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); aty128_bpp_to_var(pix_width, var); var->xres = xres; var->yres = yres; var->xres_virtual = crtc->vxres;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -