Пример #1
0
static void init_utmip_pll(void)
{
	int khz = clock_get_pll_input_khz();

	/* Shut off PLL crystal clock while we mess with it */
	clrbits_le32(&clk_rst->utmip_pll_cfg2, 1 << 30); /* PHY_XTAL_CLKEN */
	udelay(1);

	write32(&clk_rst->utmip_pll_cfg0,	/* 960MHz * 1 / 80 == 12 MHz */
		80 << 16 |			/* (rst) phy_divn */
		 1 <<  8);			/* (rst) phy_divm */

	write32(&clk_rst->utmip_pll_cfg1,
		CEIL_DIV(khz, 8000) << 27 |	/* pllu_enbl_cnt / 8 (1us) */
				  0 << 16 |	/* PLLU pwrdn */
				  0 << 14 |	/* pll_enable pwrdn */
				  0 << 12 |	/* pll_active pwrdn */
		 CEIL_DIV(khz, 102) << 0);	/* phy_stbl_cnt / 256 (2.5ms) */

	/* TODO: TRM can't decide if actv is 5us or 10us, keep an eye on it */
	write32(&clk_rst->utmip_pll_cfg2,
				  0 << 24 |	/* SAMP_D/XDEV pwrdn */
		CEIL_DIV(khz, 3200) << 18 |	/* phy_actv_cnt / 16 (5us) */
		 CEIL_DIV(khz, 256) <<  6 |	/* pllu_stbl_cnt / 256 (1ms) */
				  0 <<  4 |	/* SAMP_C/USB3 pwrdn */
				  0 <<  2 |	/* SAMP_B/XHOST pwrdn */
				  0 <<  0);	/* SAMP_A/USBD pwrdn */

	setbits_le32(&clk_rst->utmip_pll_cfg2, 1 << 30); /* PHY_XTAL_CLKEN */
}
Пример #2
0
/*
 * Init PLLD clock source.
 *
 * @frequency: the requested plld frequency
 *
 * Return the plld frequency if success, otherwise return 0.
 */
u32
clock_display(u32 frequency)
{
	/**
	 * plld (fo) = vco >> p, where 500MHz < vco < 1000MHz
	 *           = (cf * n) >> p, where 1MHz < cf < 6MHz
	 *           = ((ref / m) * n) >> p
	 *
	 * Iterate the possible values of p (3 bits, 2^7) to find out a minimum
	 * safe vco, then find best (m, n). since m has only 5 bits, we can
	 * iterate all possible values.  Note Tegra 124 supports 11 bits for n,
	 * but our pll_fields has only 10 bits for n.
	 *
	 * Note values undershoot or overshoot target output frequency may not
	 * work if the values are not in "safe" range by panel specification.
	 */
	struct pllpad_dividers plld = { 0 };
	u32 ref = clock_get_pll_input_khz() * 1000, m, n, p = 0;
	u32 cf, vco, rounded_rate = frequency;
	u32 diff, best_diff;
	const u32 max_m = 1 << 5, max_n = 1 << 10, max_p = 1 << 3,
		  mhz = 1000 * 1000, min_vco = 500 * mhz, max_vco = 1000 * mhz,
		  min_cf = 1 * mhz, max_cf = 6 * mhz;

	for (vco = frequency; vco < min_vco && p < max_p; p++)
		vco <<= 1;

	if (vco < min_vco || vco > max_vco) {
		printk(BIOS_ERR, "%s: Cannot find out a supported VCO"
			" for Frequency (%u).\n", __func__, frequency);
		return 0;
	}

	plld.p = p;
	best_diff = vco;

	for (m = 1; m < max_m && best_diff; m++) {
		cf = ref / m;
		if (cf < min_cf)
			break;
		if (cf > max_cf)
			continue;

		n = vco / cf;
		if (n >= max_n)
			continue;

		diff = vco - n * cf;
		if (n + 1 < max_n && diff > cf / 2) {
			n++;
			diff = cf - diff;
		}

		if (diff >= best_diff)
			continue;

		best_diff = diff;
		plld.m = m;
		plld.n = n;
	}

	if (plld.n < 50)
		plld.cpcon = 2;
	else if (plld.n < 300)
		plld.cpcon = 3;
	else if (plld.n < 600)
		plld.cpcon = 8;
	else
		plld.cpcon = 12;

	if (best_diff) {
		printk(BIOS_WARNING, "%s: Failed to match output frequency %u, "
		       "best difference is %u.\n", __func__, frequency,
		       best_diff);
		rounded_rate = (ref / plld.m * plld.n) >> plld.p;
	}

	printk(BIOS_DEBUG, "%s: PLLD=%u ref=%u, m/n/p/cpcon=%u/%u/%u/%u\n",
	       __func__, rounded_rate, ref, plld.m, plld.n, plld.p, plld.cpcon);

	init_pll(&clk_rst->plld_base, &clk_rst->plld_misc, plld,
		 (PLLUD_MISC_LOCK_ENABLE | PLLD_MISC_CLK_ENABLE));

	return rounded_rate;
}
Пример #3
0
/* Assume USBx clocked, out of reset, UTMI+ PLL set up, SAMP_x out of pwrdn */
void usb_setup_utmip(void *usb_base)
{
	struct usb_ctlr *usb = (struct usb_ctlr *)usb_base;

	/* KHz formulas were guessed from U-Boot constants. Formats unclear. */
	int khz = clock_get_pll_input_khz();

	/* Stop UTMI+ crystal clock while we mess with its settings */
	clrbits_le32(&usb->utmip.misc1, 1 << 30);	/* PHY_XTAL_CLKEN */
	udelay(1);

	/* Take stuff out of pwrdn and add some magic numbers from U-Boot */
	write32(0x8 << 25 |		/* HS slew rate [10:4] */
		0x3 << 22 |		/* HS driver output 'SETUP' [6:4] */
		0 << 21 |		/* LS bias selection */
		0 << 18 |		/* PDZI pwrdn */
		0 << 16 |		/* PD2 pwrdn */
		0 << 14 |		/* PD pwrdn */
		1 << 13 |		/* (rst) HS receiver terminations */
		0x1 << 10 |		/* (rst) LS falling slew rate */
		0x1 << 8 |		/* (rst) LS rising slew rate */
		0x4 << 0 |		/* HS driver output 'SETUP' [3:0] */
		0, &usb->utmip.xcvr0);
	write32(0x7 << 18 |		/* Termination range adjustment */
		0 << 4 |		/* PDDR pwrdn */
		0 << 2 |		/* PDCHRP pwrdn */
		0 << 0 |		/* PDDISC pwrdn */
		0, &usb->utmip.xcvr1);
	write32(1 << 19 |		/* FS send initial J before sync(?) */
		1 << 16 |		/* (rst) Allow stuff error on SoP */
		1 << 9 |		/* (rst) Check disc only on EoP */
		0, &usb->utmip.tx);
	write32(0x2 << 30 |		/* (rst) Keep pattern on active */
		1 << 28 |		/* (rst) Realign inertia on pkt */
		0x1 << 24 |		/* (rst) edges-1 to move sampling */
		0x3 << 21 |		/* (rst) squelch delay on EoP */
		0x11 << 15 |		/* cycles until IDLE */
		0x10 << 10 |		/* elastic input depth */
		0, &usb->utmip.hsrx0);

	/* U-Boot claims the USBD values for these are used across all UTMI+
	 * PHYs. That sounds so horribly wrong that I'm not going to implement
	 * it, but keep it in mind if we're ever not using the USBD port. */
	write32(0x1 << 24 |		/* HS disconnect detect level [2] */
		1 << 23 |		/* (rst) IDPD value */
		1 << 22 |		/* (rst) IDPD select */
		1 << 11 |		/* (rst) OTG pwrdn */
		0 << 10 |		/* bias pwrdn */
		0x1 << 2 |		/* HS disconnect detect level [1:0] */
		0x2 << 0 |		/* HS squelch detect level */
		0, &usb->utmip.bias0);

	write32(khz / 2200 << 3 |	/* bias pwrdn cycles (20us?) */
		1 << 2 |		/* (rst) VBUS wakeup pwrdn */
		0 << 0 |		/* PDTRK pwrdn */
		0, &usb->utmip.bias1);

	write32(0xffff << 16 |		/* (rst) */
		25 * khz / 10 << 0 |	/* TODO: what's this, really? */
		0, &usb->utmip.debounce);

	udelay(1);
	setbits_le32(&usb->utmip.misc1, 1 << 30); /* PHY_XTAL_CLKEN */

	write32(1 << 12 |		/* UTMI+ enable */
		0 << 11 |		/* UTMI+ reset */
		0, &usb->suspend_ctrl);

	usb_ehci_reset_and_prepare(usb, USB_PHY_UTMIP);
	printk(BIOS_DEBUG, "USB controller @ %p set up with UTMI+ PHY\n",usb_base);
}