⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aty128fb.c

📁 linux下的VIDEO接口驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
}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 + -