static int aty_init_pll_ct()

in fbdev/aty/mach64_ct.c [403:606]


static int aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll)
{
	struct atyfb_par *par = (struct atyfb_par *) info->par;
	u8 mpost_div, xpost_div, sclk_post_div_real;
	u32 q, memcntl, trp;
	u32 dsp_config;
#ifdef DEBUG
	int pllmclk, pllsclk;
#endif
	pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
	pll->ct.xclk_post_div = pll->ct.pll_ext_cntl & 0x07;
	pll->ct.xclk_ref_div = 1;
	switch (pll->ct.xclk_post_div) {
	case 0:  case 1:  case 2:  case 3:
		break;

	case 4:
		pll->ct.xclk_ref_div = 3;
		pll->ct.xclk_post_div = 0;
		break;

	default:
		printk(KERN_CRIT "atyfb: Unsupported xclk source:  %d.\n", pll->ct.xclk_post_div);
		return -EINVAL;
	}
	pll->ct.mclk_fb_mult = 2;
	if(pll->ct.pll_ext_cntl & PLL_MFB_TIMES_4_2B) {
		pll->ct.mclk_fb_mult = 4;
		pll->ct.xclk_post_div -= 1;
	}

#ifdef DEBUG
	printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n",
		__func__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div);
#endif

	memcntl = aty_ld_le32(MEM_CNTL, par);
	trp = (memcntl & 0x300) >> 8;

	pll->ct.xclkpagefaultdelay = ((memcntl & 0xc00) >> 10) + ((memcntl & 0x1000) >> 12) + trp + 2;
	pll->ct.xclkmaxrasdelay = ((memcntl & 0x70000) >> 16) + trp + 2;

	if (M64_HAS(FIFO_32)) {
		pll->ct.fifo_size = 32;
	} else {
		pll->ct.fifo_size = 24;
		pll->ct.xclkpagefaultdelay += 2;
		pll->ct.xclkmaxrasdelay += 3;
	}

	switch (par->ram_type) {
	case DRAM:
		if (info->fix.smem_len<=ONE_MB) {
			pll->ct.dsp_loop_latency = 10;
		} else {
			pll->ct.dsp_loop_latency = 8;
			pll->ct.xclkpagefaultdelay += 2;
		}
		break;
	case EDO:
	case PSEUDO_EDO:
		if (info->fix.smem_len<=ONE_MB) {
			pll->ct.dsp_loop_latency = 9;
		} else {
			pll->ct.dsp_loop_latency = 8;
			pll->ct.xclkpagefaultdelay += 1;
		}
		break;
	case SDRAM:
		if (info->fix.smem_len<=ONE_MB) {
			pll->ct.dsp_loop_latency = 11;
		} else {
			pll->ct.dsp_loop_latency = 10;
			pll->ct.xclkpagefaultdelay += 1;
		}
		break;
	case SGRAM:
		pll->ct.dsp_loop_latency = 8;
		pll->ct.xclkpagefaultdelay += 3;
		break;
	default:
		pll->ct.dsp_loop_latency = 11;
		pll->ct.xclkpagefaultdelay += 3;
		break;
	}

	if (pll->ct.xclkmaxrasdelay <= pll->ct.xclkpagefaultdelay)
		pll->ct.xclkmaxrasdelay = pll->ct.xclkpagefaultdelay + 1;

	/* Allow BIOS to override */
	dsp_config = aty_ld_le32(DSP_CONFIG, par);
	aty_ld_le32(DSP_ON_OFF, par);
	aty_ld_le32(VGA_DSP_CONFIG, par);
	aty_ld_le32(VGA_DSP_ON_OFF, par);

	if (dsp_config)
		pll->ct.dsp_loop_latency = (dsp_config & DSP_LOOP_LATENCY) >> 16;
#if 0
	FIXME: is it relevant for us?
	if ((!dsp_on_off && !M64_HAS(RESET_3D)) ||
		((dsp_on_off == vga_dsp_on_off) &&
		(!dsp_config || !((dsp_config ^ vga_dsp_config) & DSP_XCLKS_PER_QW)))) {
		vga_dsp_on_off &= VGA_DSP_OFF;
		vga_dsp_config &= VGA_DSP_XCLKS_PER_QW;
		if (ATIDivide(vga_dsp_on_off, vga_dsp_config, 5, 1) > 24)
			pll->ct.fifo_size = 32;
		else
			pll->ct.fifo_size = 24;
	}
#endif
	/* Exit if the user does not want us to tamper with the clock
	rates of her chip. */
	if (par->mclk_per == 0) {
		u8 mclk_fb_div, pll_ext_cntl;
		pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
		pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
		pll->ct.xclk_post_div_real = aty_postdividers[pll_ext_cntl & 0x07];
		mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par);
		if (pll_ext_cntl & PLL_MFB_TIMES_4_2B)
			mclk_fb_div <<= 1;
		pll->ct.mclk_fb_div = mclk_fb_div;
		return 0;
	}

	pll->ct.pll_ref_div = par->pll_per * 2 * 255 / par->ref_clk_per;

	/* FIXME: use the VTB/GTB /3 post divider if it's better suited */
	q = par->ref_clk_per * pll->ct.pll_ref_div * 8 /
		(pll->ct.mclk_fb_mult * par->xclk_per);

	if (q < 16*8 || q > 255*8) {
		printk(KERN_CRIT "atxfb: xclk out of range\n");
		return -EINVAL;
	} else {
		xpost_div  = (q < 128*8);
		xpost_div += (q <  64*8);
		xpost_div += (q <  32*8);
	}
	pll->ct.xclk_post_div_real = aty_postdividers[xpost_div];
	pll->ct.mclk_fb_div = q * pll->ct.xclk_post_div_real / 8;

#ifdef CONFIG_PPC
	if (machine_is(powermac)) {
		/* Override PLL_EXT_CNTL & 0x07. */
		pll->ct.xclk_post_div = xpost_div;
		pll->ct.xclk_ref_div = 1;
	}
#endif

#ifdef DEBUG
	pllmclk = (1000000 * pll->ct.mclk_fb_mult * pll->ct.mclk_fb_div) /
			(par->ref_clk_per * pll->ct.pll_ref_div);
	printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n",
		__func__, pllmclk, pllmclk / pll->ct.xclk_post_div_real);
#endif

	if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM))
		pll->ct.pll_gen_cntl = OSC_EN;
	else
		pll->ct.pll_gen_cntl = OSC_EN | DLL_PWDN /* | FORCE_DCLK_TRI_STATE */;

	if (M64_HAS(MAGIC_POSTDIV))
		pll->ct.pll_ext_cntl = 0;
	else
		pll->ct.pll_ext_cntl = xpost_div;

	if (pll->ct.mclk_fb_mult == 4)
		pll->ct.pll_ext_cntl |= PLL_MFB_TIMES_4_2B;

	if (par->mclk_per == par->xclk_per) {
		pll->ct.pll_gen_cntl |= (xpost_div << 4); /* mclk == xclk */
	} else {
		/*
		* The chip clock is not equal to the memory clock.
		* Therefore we will use sclk to clock the chip.
		*/
		pll->ct.pll_gen_cntl |= (6 << 4); /* mclk == sclk */

		q = par->ref_clk_per * pll->ct.pll_ref_div * 4 / par->mclk_per;
		if (q < 16*8 || q > 255*8) {
			printk(KERN_CRIT "atyfb: mclk out of range\n");
			return -EINVAL;
		} else {
			mpost_div  = (q < 128*8);
			mpost_div += (q <  64*8);
			mpost_div += (q <  32*8);
		}
		sclk_post_div_real = aty_postdividers[mpost_div];
		pll->ct.sclk_fb_div = q * sclk_post_div_real / 8;
		pll->ct.spll_cntl2 = mpost_div << 4;
#ifdef DEBUG
		pllsclk = (1000000 * 2 * pll->ct.sclk_fb_div) /
			(par->ref_clk_per * pll->ct.pll_ref_div);
		printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
			__func__, pllsclk, pllsclk / sclk_post_div_real);
#endif
	}

	/* Disable the extra precision pixel clock controls since we do not use them. */
	pll->ct.ext_vpll_cntl = aty_ld_pll_ct(EXT_VPLL_CNTL, par);
	pll->ct.ext_vpll_cntl &= ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC);

	return 0;
}