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 */ }
/* * 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; }
/* 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); }