atyfb.c

来自「讲述linux的初始化过程」· C语言 代码 · 共 2,436 行 · 第 1/5 页

C
2,436
字号
      pll->program_bits = program_bits;      pll->locationAddr = 0;      pll->post_divider = divider;  /* fuer nix */      pll->period_in_ps = period_in_ps;      return 0;}static u32 aty_pll_1703_to_var(const struct pll_18818 *pll){    return(pll->period_in_ps);  /* default for now */}static void aty_set_pll_1703(const struct fb_info_aty *info,			     const struct pll_18818 *pll){    u32 program_bits;    u32 locationAddr;    char old_crtc_ext_disp;    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),	     info);    program_bits = pll->program_bits;    locationAddr = pll->locationAddr;    /* Program clock */    aty_dac_waste4(info);    (void)aty_ld_8(DAC_REGS + 2, info);    aty_st_8(DAC_REGS+2, (locationAddr << 1) + 0x20, info);    aty_st_8(DAC_REGS+2, 0, info);    aty_st_8(DAC_REGS+2, (program_bits & 0xFF00) >> 8, info);    aty_st_8(DAC_REGS+2, (program_bits & 0xFF), info);    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);    return;}static int aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll){    u32 tempA, tempB, fOut, longMHz100, diff, preDiff;    u32 mhz100;				/* in 0.01 MHz */    u32 program_bits;    /* u32 post_divider; */    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;    u16 m, n, k=0, save_m, save_n, twoToKth;    /* Calculate the programming word */    mhz100 = 100000000 / period_in_ps;    mach64MinFreq = MIN_FREQ_2595;    mach64MaxFreq = MAX_FREQ_2595;    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */    save_m = 0;    save_n = 0;    /* Calculate program word */    if (mhz100 == 0)	program_bits = 0xE0;    else    {	if (mhz100 < mach64MinFreq)	    mhz100 = mach64MinFreq;	if (mhz100 > mach64MaxFreq)	    mhz100 = mach64MaxFreq;	longMHz100 = mhz100 * 256 / 100;   /* 8 bit scale this */	while (mhz100 < (mach64MinFreq << 3))        {	    mhz100 <<= 1;	    k++;	}	twoToKth = 1 << k;	diff = 0;	preDiff = 0xFFFFFFFF;	for (m = MIN_M; m <= MAX_M; m++)        {	    for (n = MIN_N; n <= MAX_N; n++)            {		tempA = (14.31818 * 65536);		tempA *= (n + 8);  /* 43..256 */		tempB = twoToKth * 256;		tempB *= (m + 2);  /* 4..32 */		fOut = tempA / tempB;  /* 8 bit scale */		if (longMHz100 > fOut)		    diff = longMHz100 - fOut;		else		    diff = fOut - longMHz100;		if (diff < preDiff)                {		    save_m = m;		    save_n = n;		    preDiff = diff;		}	    }	}	program_bits = (k << 6) + (save_m) + (save_n << 8);    }    pll->program_bits = program_bits;    pll->locationAddr = 0;    pll->post_divider = 0;    pll->period_in_ps = period_in_ps;    return 0;}static u32 aty_pll_8398_to_var(const struct pll_18818 *pll){    return(pll->period_in_ps);  /* default for now */}static void aty_set_pll_8398(const struct fb_info_aty *info,			     const struct pll_18818 *pll){    u32 program_bits;    u32 locationAddr;    char old_crtc_ext_disp;    char tmp;    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),	     info);    program_bits = pll->program_bits;    locationAddr = pll->locationAddr;    /* Program clock */    tmp = aty_ld_8(DAC_CNTL, info);    aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info);    aty_st_8(DAC_REGS, locationAddr, info);    aty_st_8(DAC_REGS+1, (program_bits & 0xff00) >> 8, info);    aty_st_8(DAC_REGS+1, (program_bits & 0xff), info);    tmp = aty_ld_8(DAC_CNTL, info);    aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info);    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);    return;}static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll){    /*     *  FIXME: use real calculations instead of using fixed values from the old     *	       driver     */    static struct {	u32 limit;	/* pixlock rounding limit (arbitrary) */	u8 m;		/* (df<<6) | vco_div_count */	u8 n;		/* ref_div_count */    } RGB514_clocks[7] = {	{  8000, (3<<6) | 20, 9 },	/*  7395 ps / 135.2273 MHz */	{ 10000, (1<<6) | 19, 3 },	/*  9977 ps / 100.2273 MHz */	{ 13000, (1<<6) |  2, 3 },	/* 12509 ps /  79.9432 MHz */	{ 14000, (2<<6) |  8, 7 },	/* 13394 ps /  74.6591 MHz */	{ 16000, (1<<6) | 44, 6 },	/* 15378 ps /  65.0284 MHz */	{ 25000, (1<<6) | 15, 5 },	/* 17460 ps /  57.2727 MHz */	{ 50000, (0<<6) | 53, 7 },	/* 33145 ps /  30.1705 MHz */    };    int i;    for (i = 0; i < sizeof(RGB514_clocks)/sizeof(*RGB514_clocks); i++)	if (vclk_per <= RGB514_clocks[i].limit) {	    pll->m = RGB514_clocks[i].m;	    pll->n = RGB514_clocks[i].n;	    return 0;	}    return -EINVAL;}static void aty_StrobeClock(const struct fb_info_aty *info){    u8 tmp;    udelay(26);    tmp = aty_ld_8(CLOCK_CNTL, info);    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, tmp | CLOCK_STROBE, info);    return;}static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info){    u8 tmp;    data &= 0x01;    tmp = aty_ld_8(CLOCK_CNTL, info);    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x04) | (data << 2),	     info);    tmp = aty_ld_8(CLOCK_CNTL, info);    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (0 << 3), info);    aty_StrobeClock(info);    tmp = aty_ld_8(CLOCK_CNTL, info);    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (1 << 3), info);    aty_StrobeClock(info);    return;}static u32 aty_pll_gx_to_var(const struct pll_gx *pll,			     const struct fb_info_aty *info){    u8 df, vco_div_count, ref_div_count;    df = pll->m >> 6;    vco_div_count = pll->m & 0x3f;    ref_div_count = pll->n;    return ((info->ref_clk_per*ref_div_count)<<(3-df))/(vco_div_count+65);}    /*     *  PLL programming (Mach64 CT family)     */static void aty_set_pll_ct(const struct fb_info_aty *info,			   const struct pll_ct *pll){    aty_st_pll(PLL_REF_DIV, pll->pll_ref_div, info);    aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, info);    aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, info);    aty_st_pll(PLL_VCLK_CNTL, pll->pll_vclk_cntl, info);    aty_st_pll(VCLK_POST_DIV, pll->vclk_post_div, info);    aty_st_pll(VCLK0_FB_DIV, pll->vclk_fb_div, info);    aty_st_pll(PLL_EXT_CNTL, pll->pll_ext_cntl, info);    if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID ||	  Gx == ET_CHIP_ID ||	  ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) {	if (info->ram_type >= SDRAM)	    aty_st_pll(DLL_CNTL, 0xa6, info);	else	    aty_st_pll(DLL_CNTL, 0xa0, info);	aty_st_pll(VFC_CNTL, 0x1b, info);	aty_st_le32(DSP_CONFIG, pll->dsp_config, info);	aty_st_le32(DSP_ON_OFF, pll->dsp_on_off, info);    }}static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp,		      struct pll_ct *pll){    u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on;    u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size;    /* xclocks_per_row<<11 */    xclks_per_row = (pll->mclk_fb_div*pll->vclk_post_div_real*64<<11)/		    (pll->vclk_fb_div*pll->mclk_post_div_real*bpp);    if (xclks_per_row < (1<<11))	FAIL("Dotclock to high");    if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == VT_CHIP_ID ||	Gx == VU_CHIP_ID || Gx == GV_CHIP_ID || Gx == GW_CHIP_ID ||	Gx == GZ_CHIP_ID) {	fifo_size = 24;	dsp_loop_latency = 0;    } else {	fifo_size = 32;	dsp_loop_latency = 2;    }    dsp_precision = 0;    y = (xclks_per_row*fifo_size)>>11;    while (y) {	y >>= 1;	dsp_precision++;    }    dsp_precision -= 5;    /* fifo_off<<6 */    fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(3<<6);    if (info->total_vram > 1*1024*1024) {	if (info->ram_type >= SDRAM) {	    /* >1 MB SDRAM */	    dsp_loop_latency += 8;	    page_size = 8;	} else {	    /* >1 MB DRAM */	    dsp_loop_latency += 6;	    page_size = 9;	}    } else {	if (info->ram_type >= SDRAM) {	    /* <2 MB SDRAM */	    dsp_loop_latency += 9;	    page_size = 10;	} else {	    /* <2 MB DRAM */	    dsp_loop_latency += 8;	    page_size = 10;	}    }    /* fifo_on<<6 */    if (xclks_per_row >= (page_size<<11))	fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5);    else	fifo_on = (3*page_size+2)<<6;    dsp_xclks_per_row = xclks_per_row>>dsp_precision;    dsp_on = fifo_on>>dsp_precision;    dsp_off = fifo_off>>dsp_precision;    pll->dsp_config = (dsp_xclks_per_row & 0x3fff) |		      ((dsp_loop_latency & 0xf)<<16) |		      ((dsp_precision & 7)<<20);    pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff)<<16);    return 0;}static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,			    struct pll_ct *pll){    u32 q, x;			/* x is a workaround for sparc64-linux-gcc */    x = x;			/* x is a workaround for sparc64-linux-gcc */    pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per;    /* FIXME: use the VTB/GTB /3 post divider if it's better suited */    q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per;	/* actually 8*q */    if (q < 16*8 || q > 255*8)	FAIL("mclk out of range");    else if (q < 32*8)	pll->mclk_post_div_real = 8;    else if (q < 64*8)	pll->mclk_post_div_real = 4;    else if (q < 128*8)	pll->mclk_post_div_real = 2;    else	pll->mclk_post_div_real = 1;    pll->mclk_fb_div = q*pll->mclk_post_div_real/8;    /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */    q = info->ref_clk_per*pll->pll_ref_div*4/vclk_per;	/* actually 8*q */    if (q < 16*8 || q > 255*8)	FAIL("vclk out of range");    else if (q < 32*8)	pll->vclk_post_div_real = 8;    else if (q < 64*8)	pll->vclk_post_div_real = 4;    else if (q < 128*8)	pll->vclk_post_div_real = 2;    else	pll->vclk_post_div_real = 1;    pll->vclk_fb_div = q*pll->vclk_post_div_real/8;    return 0;}static void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll){    u8 mpostdiv = 0;    u8 vpostdiv = 0;    if ((((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||	 (Gx == GV_CHIP_ID) || (Gx == GW_CHIP_ID) || (Gx == GZ_CHIP_ID) ||	 (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||	 (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) ||	 (Gx == VU_CHIP_ID)) && (info->ram_type >= SDRAM))	pll->pll_gen_cntl = 0x04;    else	pll->pll_gen_cntl = 0x84;    switch (pll->mclk_post_div_real) {	case 1:	    mpostdiv = 0;	    break;	case 2:	    mpostdiv = 1;	    break;	case 3:	    mpostdiv = 4;	    break;	case 4:	    mpostdiv = 2;	    break;	case 8:	    mpostdiv = 3;	    break;    }    pll->pll_gen_cntl |= mpostdiv<<4;	/* mclk */    if (Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48))	pll->pll_ext_cntl = 0;    else    	pll->pll_ext_cntl = mpostdiv;	/* xclk == mclk */    switch (pll->vclk_post_div_real) {	case 2:	    vpostdiv = 1;	    break;	case 3:	    pll->pll_ext_cntl |= 0x10;	case 1:	    vpostdiv = 0;	    break;	case 6:	    pll->pll_ext_cntl |= 0x10;	case 4:	    vpostdiv = 2;	    break;	case 12:	    pll->pll_ext_cntl |= 0x10;	case 8:	    vpostdiv = 3;	    break;    }    pll->pll_vclk_cntl = 0x03;	/* VCLK = PLL_VCLK/VCLKx_POST */    pll->vclk_post_div = vpostdiv;}static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,			     u8 bpp, struct pll_ct *pll){    int err;    if ((err = aty_valid_pll_ct(info, vclk_per, pll)))	return err;    if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID ||	  Gx == ET_CHIP_ID ||	  ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) {	if ((err = aty_dsp_gt(info, bpp, pll)))	    return err;    }    aty_calc_pll_ct(info, pll);    return 0;}static u32 aty_pll_ct_to_var(const struct pll_ct *pll,			     const struct fb_info_aty *info){    u32 ref_clk_per = info->ref_clk_per;    u8 pll_ref_div = pll->pll_ref_div;    u8 vclk_fb_div = pll->vclk_fb_div;    u8 vclk_post_div = pll->vclk_post_div_real;    return ref_clk_per*pll_ref_div*vclk_post_div/vclk_fb_div/2;}/* ------------------------------------------------------------------------- */static void atyfb_set_par(const struct atyfb_par *par,			  struct fb_info_aty *info){    u32 i;    int accelmode;    int muxmode;    u8 tmp;    accelmode = par->accel_flags;  /* hack */    info->current_par = *par;    if (info->blitter_may_be_busy)	wait_for_idle(info);    tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info);    aty_set_crtc(info, &par-

⌨️ 快捷键说明

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