kernels/linux-2.4.0/drivers/video/cyber2000fb.c
/*
 * The following was discovered by a good monitor, bit twiddling, theorising
 * and but mostly luck.  Strangely, it looks like everyone elses' PLL!
 *
 * Clock registers:
 *   fclock = fpll / div2
 *   fpll   = fref * mult / div1
 * where:
 *   fref = 14.318MHz (69842ps)
 *   mult = reg0xb0.7:0
 *   div1 = (reg0xb1.5:0 + 1)
 *   div2 =  2^(reg0xb1.7:6)
 *   fpll should be between 115 and 260 MHz
 *  (8696ps and 3846ps)
 */
The following was discovered by a good monitor, bit twiddling, theorising
and but mostly luck.  Strangely, it looks like everyone elses' PLL!


The following was discovered by a good monitor bit twiddling theorising and but mostly luck . Strangely it looks like everyone elses ' PLL!
static int
cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb,
			 struct fb_var_screeninfo *var)
{
	u_long pll_ps = var->pixclock;
	const u_long ref_ps = cfb->ref_ps;
	u_int div2, t_div1, best_div1, best_mult;
	int best_diff;
	for (div2 = 0; div2 < 4; div2++) {
		u_long new_pll;
		new_pll = pll_ps / cfb->divisors[div2];
		if (8696 > new_pll && new_pll > 3846) {
			pll_ps = new_pll;
			break;
		}
	}
	if (div2 == 4)
		return -EINVAL;
	best_diff = 0x7fffffff;
	best_mult = 32;
	best_div1 = 255;
	for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) {
		u_int rr, t_mult, t_pll_ps;
		int diff;
		rr = ref_ps * t_div1;
		t_mult = (rr + pll_ps / 2) / pll_ps;
		if (t_mult > 256 || t_mult < 2)
			continue;
		t_pll_ps = (rr + t_mult / 2) / t_mult;
		diff = pll_ps - t_pll_ps;
		if (diff < 0)
			diff = -diff;
		if (diff < best_diff) {
			best_diff = diff;
			best_mult = t_mult;
			best_div1 = t_div1;
		}
		if (diff == 0)
			break;
	}
	hw->clock_mult = best_mult - 1;
	hw->clock_div  = div2 << 6 | (best_div1 - 1);
	return 0;
}
static int cyber2000fb_decode_clock ( struct par_info * hw , struct cfb_info * cfb , struct fb_var_screeninfo * var ) { u_long pll_ps = var -> pixclock ; const u_long ref_ps = cfb -> ref_ps ; u_int div2 , t_div1 , best_div1 , best_mult ; int best_diff ; for ( div2 = 0 ; div2 < 4 ; div2 ++ ) { u_long new_pll ; new_pll = pll_ps / cfb -> divisors [ div2 ] ; if ( 8696 > new_pll && new_pll > 3846 ) { pll_ps = new_pll ; break ; } } if ( div2 == 4 ) return - EINVAL ; best_diff = 0x7fffffff ; best_mult = 32 ; best_div1 = 255 ; for ( t_div1 = 32 ; t_div1 > 1 ; t_div1 -= 1 ) { u_int rr , t_mult , t_pll_ps ; int diff ; rr = ref_ps * t_div1 ; t_mult = ( rr + pll_ps / 2 ) / pll_ps ; if ( t_mult > 256 || t_mult < 2 ) continue ; t_pll_ps = ( rr + t_mult / 2 ) / t_mult ; diff = pll_ps - t_pll_ps ; if ( diff < 0 ) diff = - diff ; if ( diff < best_diff ) { best_diff = diff ; best_mult = t_mult ; best_div1 = t_div1 ; } if ( diff == 0 ) break ; } hw -> clock_mult = best_mult - 1 ; hw -> clock_div = div2 << 6 | ( best_div1 - 1 ) ; return 0 ; }
The following was discovered by a good monitor, bit twiddling, theorising
 and but mostly luck.
The following was discovered by a good monitor bit twiddling theorising and but mostly luck .
/*
	 * Step 1:
	 *   find div2 such that 115MHz < fpll < 260MHz
	 *   and 0 <= div2 < 4
	 */ /*
	 * Step 2:
	 *  Given pll_ps and ref_ps, find:
	 *    pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005
	 *  where { 1 < best_div1 < 32, 1 < best_mult < 256 }
	 *    pll_ps_calc = best_div1 / (ref_ps * best_mult)
	 */ /*
		 * Find the multiplier for this divisor
		 */ /*
		 * Is the multiplier within the correct range?
		 */ /*
		 * Calculate the actual clock period from this multiplier
		 * and divisor, and estimate the error.
		 */ /*
		 * If we hit an exact value, there is no point in continuing.
		 */ /*
	 * Step 3:
	 *  combine values
	 */