📄 aty128fb.c
字号:
}static inline void_aty_st_le32(volatile unsigned int regindex, u32 val, const struct fb_info_aty128 *info){#if defined(__powerpc__) asm("stwbrx %0,%1,%2;eieio" : : "r"(val), "b"(regindex), "r"(info->regbase) : "memory");#else writel (val, info->regbase + regindex);#endif}static inline u8_aty_ld_8(unsigned int regindex, const struct fb_info_aty128 *info){ return readb (info->regbase + regindex);}static inline void_aty_st_8(unsigned int regindex, u8 val, const struct fb_info_aty128 *info){ writeb (val, info->regbase + regindex);}#define aty_ld_le32(regindex) _aty_ld_le32(regindex, info)#define aty_st_le32(regindex, val) _aty_st_le32(regindex, val, info)#define aty_ld_8(regindex) _aty_ld_8(regindex, info)#define aty_st_8(regindex, val) _aty_st_8(regindex, val, info) /* * Functions to read from/write to the pll registers */#define aty_ld_pll(pll_index) _aty_ld_pll(pll_index, info)#define aty_st_pll(pll_index, val) _aty_st_pll(pll_index, val, info)static u32_aty_ld_pll(unsigned int pll_index, const struct fb_info_aty128 *info){ aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F); return aty_ld_le32(CLOCK_CNTL_DATA);} 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 & 0x3F) | 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!\n");}/* 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 | (depth_to_dst(par->crtc.depth) << 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 depth values to their register representation */static u32depth_to_dst(u32 depth) { if (depth <= 8) return DST_8BPP; else if (depth <= 15) return DST_15BPP; else if (depth == 16) return DST_16BPP; else if (depth <= 24) return DST_24BPP; else if (depth <= 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? */ aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~(0x00030000));}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, dst; 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; if (bpp != 16) depth = bpp; else depth = (var->green.length == 6) ? 16 : 15; /* 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 depth into ATI register depth */ dst = depth_to_dst(depth); if (dst == -EINVAL) { printk(KERN_ERR "aty128fb: Invalid depth or RGBA\n"); return -EINVAL; } /* convert register depth to bytes per pixel */ bytpp = mode_bytpp[dst]; /* 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 | (dst << 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; if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) crtc->offset_cntl = 0x00010000; else crtc->offset_cntl = 0; crtc->vxres = vxres; crtc->vyres = vyres; crtc->xoffset = xoffset; crtc->yoffset = yoffset; crtc->depth = depth; crtc->bpp = bpp; return 0;}static intaty128_pix_width_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: 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_16BPP: var->bits_per_pixel = 16; var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; var->transp.offset = 0; var->transp.length = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -