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

📄 aty128fb.c

📁 linux下的VIDEO接口驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	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_pix_width_to_var(pix_width, var);    var->xres = xres;    var->yres = yres;    var->xres_virtual = crtc->vxres;    var->yres_virtual = crtc->vyres;    var->xoffset = crtc->xoffset;    var->yoffset = crtc->yoffset;    var->left_margin  = left;    var->right_margin = right;    var->upper_margin = upper;    var->lower_margin = lower;    var->hsync_len = hslen;    var->vsync_len = vslen;    var->sync  = sync;    var->vmode = FB_VMODE_NONINTERLACED;    return 0;}static voidaty128_set_crt_enable(struct fb_info_aty128 *info, int on){    if (on) {	aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | CRT_CRTC_ON);	aty_st_le32(DAC_CNTL, (aty_ld_le32(DAC_CNTL) | DAC_PALETTE2_SNOOP_EN));    } else	aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & ~CRT_CRTC_ON);}static voidaty128_set_lcd_enable(struct fb_info_aty128 *info, int on){    u32 reg;        if (on) {	reg = aty_ld_le32(LVDS_GEN_CNTL);	reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION;	reg &= ~LVDS_DISPLAY_DIS;	aty_st_le32(LVDS_GEN_CNTL, reg);#ifdef CONFIG_PMAC_BACKLIGHT	aty128_set_backlight_enable(get_backlight_enable(), get_backlight_level(), info);#endif	    } else {#ifdef CONFIG_PMAC_BACKLIGHT	aty128_set_backlight_enable(0, 0, info);#endif		reg = aty_ld_le32(LVDS_GEN_CNTL);	reg |= LVDS_DISPLAY_DIS;        aty_st_le32(LVDS_GEN_CNTL, reg);        mdelay(100);	reg &= ~(LVDS_ON /*| LVDS_EN*/);	aty_st_le32(LVDS_GEN_CNTL, reg);    }}static voidaty128_set_pll(struct aty128_pll *pll, const struct fb_info_aty128 *info){    u32 div3;    unsigned char post_conv[] =	/* register values for post dividers */        { 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 };    /* select PPLL_DIV_3 */    aty_st_le32(CLOCK_CNTL_INDEX, aty_ld_le32(CLOCK_CNTL_INDEX) | (3 << 8));    /* reset PLL */    aty_st_pll(PPLL_CNTL,		aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN);    /* write the reference divider */    aty_pll_wait_readupdate(info);    aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider & 0x3ff);    aty_pll_writeupdate(info);    div3 = aty_ld_pll(PPLL_DIV_3);    div3 &= ~PPLL_FB3_DIV_MASK;    div3 |= pll->feedback_divider;    div3 &= ~PPLL_POST3_DIV_MASK;    div3 |= post_conv[pll->post_divider] << 16;    /* write feedback and post dividers */    aty_pll_wait_readupdate(info);    aty_st_pll(PPLL_DIV_3, div3);    aty_pll_writeupdate(info);    aty_pll_wait_readupdate(info);    aty_st_pll(HTOTAL_CNTL, 0);	/* no horiz crtc adjustment */    aty_pll_writeupdate(info);    /* clear the reset, just in case */    aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET);#if 0    if (info->chip_gen == rage_M3) {	/* XXX energy saving, disable VCLK during blanking */	aty_pll_wait_readupdate(info);    	aty_st_pll(VCLK_ECP_CNTL, aty_ld_pll(VCLK_ECP_CNTL) | 0xc0);		aty_pll_writeupdate(info);	/* Set PM clocks */	aty_pll_wait_readupdate(info);	aty_st_pll(XCLK_CNTL, aty_ld_pll(XCLK_CNTL) | 0x00330000);	aty_pll_writeupdate(info);	aty_pll_wait_readupdate(info);	aty_st_pll(MCLK_CNTL, aty_ld_pll(MCLK_CNTL) | 0x00000700);	aty_pll_writeupdate(info);    }#endif    }static intaty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,			const struct fb_info_aty128 *info){    const struct aty128_constants c = info->constants;    unsigned char post_dividers[] = {1,2,4,8,3,6,12};    u32 output_freq;    u32 vclk;        /* in .01 MHz */    int i;    u32 n, d;    vclk = 100000000 / period_in_ps;	/* convert units to 10 kHz */    /* adjust pixel clock if necessary */    if (vclk > c.ppll_max)	vclk = c.ppll_max;    if (vclk * 12 < c.ppll_min)	vclk = c.ppll_min/12;    /* now, find an acceptable divider */    for (i = 0; i < sizeof(post_dividers); i++) {	output_freq = post_dividers[i] * vclk;	if (output_freq >= c.ppll_min && output_freq <= c.ppll_max)	    break;    }    /* calculate feedback divider */    n = c.ref_divider * output_freq;    d = c.dotclock;    pll->post_divider = post_dividers[i];    pll->feedback_divider = round_div(n, d);    pll->vclk = vclk;    DBG("post %d feedback %d vlck %d output %d ref_divider %d "			"vclk_per: %d\n", pll->post_divider,			pll->feedback_divider, vclk, output_freq,			c.ref_divider, period_in_ps);    return 0;}static intaty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var,		const struct fb_info_aty128 *info){    var->pixclock = 100000000 / pll->vclk;    return 0;}static voidaty128_set_fifo(const struct aty128_ddafifo *dsp,			const struct fb_info_aty128 *info){    aty_st_le32(DDA_CONFIG, dsp->dda_config);    aty_st_le32(DDA_ON_OFF, dsp->dda_on_off);}static intaty128_ddafifo(struct aty128_ddafifo *dsp,		const struct aty128_pll *pll,		u32 depth,		const struct fb_info_aty128 *info){    const struct aty128_meminfo *m = info->mem;    u32 xclk = info->constants.xclk;    u32 fifo_width = info->constants.fifo_width;    u32 fifo_depth = info->constants.fifo_depth;    s32 x, b, p, ron, roff;    u32 n, d, bpp;    /* round up to multiple of 8 */    bpp = (depth+7) & ~7;    n = xclk * fifo_width;    d = pll->vclk * bpp;    x = round_div(n, d);    ron = 4 * m->MB +	3 * ((m->Trcd - 2 > 0) ? m->Trcd - 2 : 0) +	2 * m->Trp +	m->Twr +	m->CL +	m->Tr2w +	x;    DBG("x %x\n", x);    b = 0;    while (x) {	x >>= 1;	b++;    }    p = b + 1;    ron <<= (11 - p);    n <<= (11 - p);    x = round_div(n, d);    roff = x * (fifo_depth - 4);    if ((ron + m->Rloop) >= roff) {	printk(KERN_ERR "aty128fb: Mode out of range!\n");	return -EINVAL;    }    DBG("p: %x rloop: %x x: %x ron: %x roff: %x\n",			p, m->Rloop, x, ron, roff);    dsp->dda_config = p << 16 | m->Rloop << 20 | x;    dsp->dda_on_off = ron << 16 | roff;    return 0;}/* * This actually sets the video mode. */static voidaty128_set_par(struct aty128fb_par *par,			struct fb_info_aty128 *info){     u32 config;    info->current_par = *par;        if (info->blitter_may_be_busy)        wait_for_idle(info);    /* clear all registers that may interfere with mode setting */    aty_st_le32(OVR_CLR, 0);    aty_st_le32(OVR_WID_LEFT_RIGHT, 0);    aty_st_le32(OVR_WID_TOP_BOTTOM, 0);    aty_st_le32(OV0_SCALE_CNTL, 0);    aty_st_le32(MPP_TB_CONFIG, 0);    aty_st_le32(MPP_GP_CONFIG, 0);    aty_st_le32(SUBPIC_CNTL, 0);    aty_st_le32(VIPH_CONTROL, 0);    aty_st_le32(I2C_CNTL_1, 0);         /* turn off i2c */    aty_st_le32(GEN_INT_CNTL, 0);	/* turn off interrupts */    aty_st_le32(CAP0_TRIG_CNTL, 0);    aty_st_le32(CAP1_TRIG_CNTL, 0);    aty_st_8(CRTC_EXT_CNTL + 1, 4);	/* turn video off */    aty128_set_crtc(&par->crtc, info);    aty128_set_pll(&par->pll, info);    aty128_set_fifo(&par->fifo_reg, info);    config = aty_ld_le32(CONFIG_CNTL) & ~3;#if defined(__BIG_ENDIAN)    if (par->crtc.bpp == 32)	config |= 2;	/* make aperture do 32 bit swapping */    else if (par->crtc.bpp == 16)	config |= 1;	/* make aperture do 16 bit swapping */#endif    aty_st_le32(CONFIG_CNTL, config);    aty_st_8(CRTC_EXT_CNTL + 1, 0);	/* turn the video back on */#ifdef CONFIG_PMAC_PBOOK    if (info->chip_gen == rage_M3) {	aty128_set_crt_enable(info, info->crt_on);	aty128_set_lcd_enable(info, info->lcd_on);    }#endif    if (par->accel_flags & FB_ACCELF_TEXT)        aty128_init_engine(par, info);#ifdef CONFIG_FB_COMPAT_XPMAC    if (!console_fb_info || console_fb_info == &info->fb_info) {        struct fb_var_screeninfo var;        int cmode, vmode;	display_info.height = ((par->crtc.v_total >> 16) & 0x7ff) + 1;	display_info.width = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3;	display_info.depth = par->crtc.bpp;	display_info.pitch = (par->crtc.vxres * par->crtc.bpp) >> 3;        aty128_encode_var(&var, par, info);	if (mac_var_to_vmode(&var, &vmode, &cmode))	    display_info.mode = 0;	else	    display_info.mode = vmode;	strcpy(display_info.name, aty128fb_name);	display_info.fb_address = info->frame_buffer_phys;	display_info.cmap_adr_address = 0;	display_info.cmap_data_address = 0;	display_info.disp_reg_address = info->regbase_phys;    }#endif /* CONFIG_FB_COMPAT_XPMAC */#if defined(CONFIG_BOOTX_TEXT)    btext_update_display(info->frame_buffer_phys,		    (((par->crtc.h_total>>16) & 0xff)+1)*8,		    ((par->crtc.v_total>>16) & 0x7ff)+1,		    par->crtc.bpp,		    par->crtc.vxres*par->crtc.bpp/8);#endif /* CONFIG_BOOTX_TEXT */}    /*     *  encode/decode the User Defined Part of the Display     */static intaty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par,			const struct fb_info_aty128 *info){    int err;    if ((err = aty128_var_to_crtc(var, &par->crtc, info)))	return err;    if ((err = aty128_var_to_pll(var->pixclock, &par->pll, info)))	return err;    if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.depth, info)))	return err;    if (var->accel_flags & FB_ACCELF_TEXT)	par->accel_flags = FB_ACCELF_TEXT;    else	par->accel_flags = 0;    return 0;}static intaty128_encode_var(struct fb_var_screeninfo *var,			const struct aty128fb_par *par,			const struct fb_info_aty128 *info){    int err;    if ((err = aty128_crtc_to_var(&par->crtc, var)))	return err;    if ((err = aty128_pll_to_var(&par->pll, var, info)))	return err;    var->red.msb_right = 0;    var->green.msb_right = 0;    var->blue.msb_right = 0;    var->transp.msb_right = 0;    var->nonstd = 0;    var->activate = 0;    var->height = -1;    var->width = -1;    var->accel_flags = par->accel_flags;    return 0;}               /*     *  Get the User Defined Part of the Display     */static intaty128fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb){    const struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;    if (con == -1)	aty128_encode_var(var, &info->default_par, info);     else	*var = fb_display[con].var;    return 0;}    /*     *  Set the User Defined Part of the Display     */static intaty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb){    struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;    struct aty128fb_par par;    struct display *display;    int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldgreen, oldaccel;    int accel, err;    display = (con >= 0) ? &fb_display[con] : fb->disp;    /* basic (in)sanity checks */    if (!var->xres)        var->xres = 1;    if (!var->yres)        var->yres = 1;    if (var->xres > var->xres_virtual)        var->xres_virtual = var->xres;    if (var->yres > var->yres_virtual)        var->yres_virtual = var->yres;    switch (var->bits_per_pixel) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -