/* * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. * Copyright 2014 Google Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "clk_rst.h" #include "flow.h" #include "maincpu.h" #include "pmc.h" #include "sysctr.h" static struct clk_rst_ctlr *clk_rst = (void *)TEGRA_CLK_RST_BASE; static struct flow_ctlr *flow = (void *)TEGRA_FLOW_BASE; static struct tegra_pmc_regs *pmc = (void *)TEGRA_PMC_BASE; static struct sysctr_regs *sysctr = (void *)TEGRA_SYSCTR0_BASE; struct pll_dividers { u32 n : 10; u32 m : 8; u32 p : 4; u32 cpcon: 4; u32 : 6; }; /* Some PLLs have more restrictive divider bit lengths or are missing some * fields. Make sure to use the right struct in the osc_table definition to get * compile-time checking, but keep the bits aligned with struct pll_dividers so * they can be used interchangeably at run time. Add new formats as required. */ struct pllcx_dividers { u32 n : 8; u32 : 2; u32 m : 8; u32 p : 4; u32 : 10; }; struct pllpad_dividers { u32 n : 10; u32 m : 5; u32 : 3; u32 p : 3; u32 : 1; u32 cpcon : 4; u32 : 6; }; struct pllu_dividers { u32 n : 10; u32 m : 5; u32 : 3; u32 p : 1; u32 : 3; u32 cpcon : 4; u32 : 6; }; union __attribute__((transparent_union)) pll_fields { u32 raw; struct pll_dividers div; struct pllcx_dividers cx; struct pllpad_dividers pad; struct pllu_dividers u; }; /* This table defines the frequency dividers for every PLL to turn the external * OSC clock into the frequencies defined by TEGRA_PLL*_KHZ in soc/clock.h. * All PLLs have three dividers (N, M and P), with the governing formula for * the output frequency being OUT = (IN / m) * N / (2^P). * Yes, it really is one equation with three unknowns ... */ struct { int khz; struct pllcx_dividers pllx; /* target: CONFIG_PLLX_KHZ */ struct pllpad_dividers pllp; /* target: 408 MHz */ struct pllcx_dividers pllc; /* target: 600 MHz */ struct pllpad_dividers plld; /* target: 925 MHz */ struct pllu_dividers pllu; /* target; 960 MHz */ struct pllcx_dividers plldp; /* target; 270 MHz */ struct pllcx_dividers plld2; /* target; 570 MHz */ } static const osc_table[16] = { [OSC_FREQ_OSC12]{ .khz = 12000, .pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0}, .pllp = {.n = 34, .m = 1, .p = 0, .cpcon = 2}, .pllc = {.n = 50, .m = 1, .p = 0}, .plld = {.n = 283, .m = 12, .p = 0, .cpcon = 8}, /* 283 MHz */ .pllu = {.n = 80, .m = 1, .p = 0, .cpcon = 3}, .plldp = {.n = 90, .m = 1, .p = 3}, /* 270 MHz */ .plld2 = {.n = 95, .m = 1, .p = 1}, /* 570 MHz */ }, [OSC_FREQ_OSC13]{ .khz = 13000, .pllx = {.n = TEGRA_PLLX_KHZ / 13000, .m = 1, .p = 0}, .pllp = {.n = 408, .m = 13, .p = 0, .cpcon = 8}, .pllc = {.n = 231, .m = 5, .p = 0}, /* 600.6 MHz */ .plld = {.n = 283, .m = 13, .p = 0, .cpcon = 8}, /* 283 MHz*/ .pllu = {.n = 960, .m = 13, .p = 0, .cpcon = 12}, .plldp = {.n = 83, .m = 1, .p = 3}, /* 269.75 MHz */ .plld2 = {.n = 88, .m = 1, .p = 1}, /* 572 MHz */ }, [OSC_FREQ_OSC16P8]{ .khz = 16800, .pllx = {.n = TEGRA_PLLX_KHZ / 16800, .m = 1, .p = 0}, .pllp = {.n = 170, .m = 7, .p = 0, .cpcon = 4}, .pllc = {.n = 250, .m = 7, .p = 0}, .plld = {.n = 286, .m = 17, .p = 0, .cpcon = 8}, /* 282.6 MHz*/ .pllu = {.n = 400, .m = 7, .p = 0, .cpcon = 8}, .plldp = {.n = 64, .m = 1, .p = 3}, /* 268.8 MHz */ .plld2 = {.n = 68, .m = 1, .p = 1}, /* 571.2 MHz */ }, [OSC_FREQ_OSC19P2]{ .khz = 19200, .pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m = 1, .p = 0}, .pllp = {.n = 85, .m = 4, .p = 0, .cpcon = 3}, .pllc = {.n = 125, .m = 4, .p = 0}, .plld = {.n = 251, .m = 17, .p = 0, .cpcon = 8}, /* 283.5 MHz */ .pllu = {.n = 50, .m = 1, .p = 0, .cpcon = 2}, .plldp = {.n = 56, .m = 1, .p = 3}, /* 270.75 MHz */ .plld2 = {.n = 59, .m = 1, .p = 1}, /* 570 MHz */ }, [OSC_FREQ_OSC26]{ .khz = 26000, .pllx = {.n = TEGRA_PLLX_KHZ / 26000, .m = 1, .p = 0}, .pllp = {.n = 204, .m = 13, .p = 0, .cpcon = 5}, .pllc = {.n = 23, .m = 1, .p = 0}, /* 598 MHz */ .plld = {.n = 283, .m = 26, .p = 0, .cpcon = 8}, /* 283 MHz */ .pllu = {.n = 480, .m = 13, .p = 0, .cpcon = 8}, .plldp = {.n = 83, .m = 2, .p = 3}, /* 266.50 MHz */ .plld2 = {.n = 88, .m = 2, .p = 1}, /* 570 MHz */ }, [OSC_FREQ_OSC38P4]{ .khz = 38400, /* * There is a predivide by 2 before this PLL. Its values * should match the 19.2MHz values. */ .pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m = 1, .p = 0}, .pllp = {.n = 85, .m = 4, .p = 0, .cpcon = 3}, .pllc = {.n = 125, .m = 4, .p = 0}, .plld = {.n = 125, .m = 17, .p = 0, .cpcon = 8}, /* 282.4 MHz */ .pllu = {.n = 50, .m = 1, .p = 0, .cpcon = 2}, .plldp = {.n = 56, .m = 2, .p = 3}, /* 268 MHz */ .plld2 = {.n = 59, .m = 2, .p = 1}, /* 566 MHz */ }, [OSC_FREQ_OSC48]{ .khz = 48000, /* * There is a predivide by 4 before this PLL. Its values * should match the 12MHz values. */ .pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0}, .pllp = {.n = 24, .m = 1, .p = 0, .cpcon = 2}, .pllc = {.n = 50, .m = 1, .p = 0}, .plld = {.n = 71, .m = 12, .p = 0, .cpcon = 8}, /* 284 MHz */ .pllu = {.n = 80, .m = 1, .p = 0, .cpcon = 3}, .plldp = {.n = 90, .m = 4, .p = 3}, /* 264 MHz */ .plld2 = {.n = 95, .m = 4, .p = 1}, /* 570 MHz */ }, }; /* Get the oscillator frequency, from the corresponding hardware * configuration field. This is actually a per-soc thing. Avoid the * temptation to make it common. */ static u32 clock_get_osc_bits(void) { return readl(&clk_rst->osc_ctrl) >> OSC_CTRL_OSC_FREQ_SHIFT; } int clock_get_osc_khz(void) { return osc_table[clock_get_osc_bits()].khz; } void clock_init_arm_generic_timer(void) { uint32_t freq = clock_get_osc_khz() * 1000; // Set the cntfrq register. __asm__ __volatile__("mcr p15, 0, %0, c14, c0, 0\n" :: "r"(freq)); // Record the system timer frequency. write32(freq, &sysctr->cntfid0); // Enable the system counter. uint32_t cntcr = read32(&sysctr->cntcr); cntcr |= SYSCTR_CNTCR_EN | SYSCTR_CNTCR_HDBG; write32(cntcr, &sysctr->cntcr); } #define SOR0_CLK_SEL0 (1 << 14) #define SOR0_CLK_SEL1 (1 << 15) void sor_clock_stop(void) { /* The Serial Output Resource clock has to be off * before we start the plldp. Learned the hard way. * FIXME: this has to be cleaned up a bit more. * Waiting on some new info from Nvidia. */ clrbits_le32(&clk_rst->clk_src_sor, SOR0_CLK_SEL0 | SOR0_CLK_SEL1); } void sor_clock_start(void) { /* uses PLLP, has a non-standard bit layout. */ setbits_le32(&clk_rst->clk_src_sor, SOR0_CLK_SEL0); } static void init_pll(u32 *base, u32 *misc, const union pll_fields pll) { u32 dividers = pll.div.n << PLL_BASE_DIVN_SHIFT | pll.div.m << PLL_BASE_DIVM_SHIFT | pll.div.p << PLL_BASE_DIVP_SHIFT; /* Write dividers but BYPASS the PLL while we're messing with it. */ writel(dividers | PLL_BASE_BYPASS, base); /* Set CPCON field (defaults to 0 if it doesn't exist for this PLL) */ writel(pll.div.cpcon << PLL_MISC_CPCON_SHIFT, misc); /* enable PLL and take it back out of BYPASS (we don't wait for lock * because we assume that to be done by the time we start using it). */ writel(dividers | PLL_BASE_ENABLE, base); } static void init_utmip_pll(void) { int khz = clock_get_osc_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(80 << 16 | /* (rst) phy_divn */ 1 << 8 | /* (rst) phy_divm */ 0, &clk_rst->utmip_pll_cfg0); /* 960MHz * 1 / 80 == 12 MHz */ write32(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) */ 0, &clk_rst->utmip_pll_cfg1); /* TODO: TRM can't decide if actv is 5us or 10us, keep an eye on it */ write32(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 */ 0, &clk_rst->utmip_pll_cfg2); setbits_le32(&clk_rst->utmip_pll_cfg2, 1 << 30); /* PHY_XTAL_CLKEN */ } /* Graphics just has to be different. There's a few more bits we * need to set in here, but it makes sense just to restrict all the * special bits to this one function. */ static void graphics_pll(void) { int osc = clock_get_osc_bits(); u32 *cfg = &clk_rst->plldp_ss_cfg; /* the vendor code sets the dither bit (28) * an undocumented bit (24) * and clamp while we mess with it (22) * Dither is pretty important to display port * so we really do need to handle these bits. * I'm not willing to not clamp it, even if * it might "mostly work" with it not set, * I don't want to find out in a few months * that it is needed. */ u32 scfg = (1<<28) | (1<<24) | (1<<22); writel(scfg, cfg); init_pll(&clk_rst->plldp_base, &clk_rst->plldp_misc, osc_table[osc].plldp); /* leave dither and undoc bits set, release clamp */ scfg = (1<<28) | (1<<24); writel(scfg, cfg); /* set lock bit */ setbits_le32(&clk_rst->plldp_misc, PLLDPD2_MISC_LOCK_ENABLE); /* init clock source for disp1 */ /* init plld (the actual output is plld_out0 that is 1/2 of plld. */ init_pll(&clk_rst->plld_base, &clk_rst->plld_misc, osc_table[osc].plld); setbits_le32(&clk_rst->plld_misc, PLLUD_MISC_LOCK_ENABLE); setbits_le32(&clk_rst->plld_misc, PLLD_MISC_CLK_ENABLE); udelay(10); /* wait for plld ready */ } /* Initialize the UART and put it on CLK_M so we can use it during clock_init(). * Will later move it to PLLP in clock_config(). The divisor must be very small * to accomodate 12KHz OSCs, so we override the 16.0 UART divider with the 15.1 * CLK_SOURCE divider to get more precision. (This might still not be enough for * some OSCs... if you use 13KHz, be prepared to have a bad time.) The 1800 has * been determined through trial and error (must lead to div 13 at 24MHz). */ void clock_early_uart(void) { write32(CLK_M << CLK_SOURCE_SHIFT | CLK_UART_DIV_OVERRIDE | CLK_DIVIDER(TEGRA_CLK_M_KHZ, 1800), &clk_rst->clk_src_uarta); setbits_le32(&clk_rst->clk_out_enb_l, CLK_L_UARTA); udelay(2); clrbits_le32(&clk_rst->rst_dev_l, CLK_L_UARTA); } /* Enable output clock (CLK1~3) for external peripherals. */ void clock_external_output(int clk_id) { switch (clk_id) { case 1: setbits_le32(&pmc->clk_out_cntrl, 1 << 2); break; case 2: setbits_le32(&pmc->clk_out_cntrl, 1 << 10); break; case 3: setbits_le32(&pmc->clk_out_cntrl, 1 << 18); break; default: printk(BIOS_CRIT, "ERROR: Unknown output clock id %d\n", clk_id); break; } } /* Start PLLM for SDRAM. */ void clock_sdram(u32 m, u32 n, u32 p, u32 setup, u32 ph45, u32 ph90, u32 ph135, u32 kvco, u32 kcp, u32 stable_time, u32 emc_source, u32 same_freq) { u32 misc1 = ((setup << PLLM_MISC1_SETUP_SHIFT) | (ph45 << PLLM_MISC1_PD_LSHIFT_PH45_SHIFT) | (ph90 << PLLM_MISC1_PD_LSHIFT_PH90_SHIFT) | (ph135 << PLLM_MISC1_PD_LSHIFT_PH135_SHIFT)), misc2 = ((kvco << PLLM_MISC2_KVCO_SHIFT) | (kcp << PLLM_MISC2_KCP_SHIFT)), base; if (same_freq) emc_source |= CLK_SOURCE_EMC_MC_EMC_SAME_FREQ; else emc_source &= ~CLK_SOURCE_EMC_MC_EMC_SAME_FREQ; /* * Note PLLM_BASE.PLLM_OUT1_RSTN must be in RESET_ENABLE mode, and * PLLM_BASE.ENABLE must be in DISABLE state (both are the default * values after coldboot reset). */ writel(misc1, &clk_rst->pllm_misc1); writel(misc2, &clk_rst->pllm_misc2); /* PLLM.BASE needs BYPASS=0, different from general init_pll */ base = readl(&clk_rst->pllm_base); base &= ~(PLLCMX_BASE_DIVN_MASK | PLLCMX_BASE_DIVM_MASK | PLLM_BASE_DIVP_MASK | PLL_BASE_BYPASS); base |= ((m << PLL_BASE_DIVM_SHIFT) | (n << PLL_BASE_DIVN_SHIFT) | (p << PLL_BASE_DIVP_SHIFT)); writel(base, &clk_rst->pllm_base); setbits_le32(&clk_rst->pllm_base, PLL_BASE_ENABLE); /* stable_time is required, before we can start to check lock. */ udelay(stable_time); while (!(readl(&clk_rst->pllm_base) & PLL_BASE_LOCK)) { udelay(1); } /* * After PLLM reports being locked, we have to delay 10us before * enabling PLLM_OUT. */ udelay(10); /* Put OUT1 out of reset state (start to output). */ setbits_le32(&clk_rst->pllm_out, PLLM_OUT1_RSTN_RESET_DISABLE); /* Enable and start MEM(MC) and EMC. */ clock_enable_clear_reset(0, CLK_H_MEM | CLK_H_EMC, 0, 0, 0, 0); writel(emc_source, &clk_rst->clk_src_emc); udelay(IO_STABILIZATION_DELAY); } void clock_cpu0_config_and_reset(void *entry) { void * const evp_cpu_reset = (uint8_t *)TEGRA_EVP_BASE + 0x100; write32(CONFIG_STACK_TOP, &maincpu_stack_pointer); write32((uintptr_t)entry, &maincpu_entry_point); write32((uintptr_t)&maincpu_setup, evp_cpu_reset); /* Set active CPU cluster to G */ clrbits_le32(&flow->cluster_control, 1); // Set up cclk_brst and divider. write32((CRC_CCLK_BRST_POL_PLLX_OUT0 << 0) | (CRC_CCLK_BRST_POL_PLLX_OUT0 << 4) | (CRC_CCLK_BRST_POL_PLLX_OUT0 << 8) | (CRC_CCLK_BRST_POL_PLLX_OUT0 << 12) | (CRC_CCLK_BRST_POL_CPU_STATE_RUN << 28), &clk_rst->cclk_brst_pol); write32(CRC_SUPER_CCLK_DIVIDER_SUPER_CDIV_ENB, &clk_rst->super_cclk_div); // Enable the clocks for CPUs 0-3. uint32_t cpu_cmplx_clr = read32(&clk_rst->clk_cpu_cmplx_clr); cpu_cmplx_clr |= CRC_CLK_CLR_CPU0_STP | CRC_CLK_CLR_CPU1_STP | CRC_CLK_CLR_CPU2_STP | CRC_CLK_CLR_CPU3_STP; write32(cpu_cmplx_clr, &clk_rst->clk_cpu_cmplx_clr); // Enable other CPU related clocks. setbits_le32(&clk_rst->clk_out_enb_l, CLK_L_CPU); setbits_le32(&clk_rst->clk_out_enb_v, CLK_V_CPUG); setbits_le32(&clk_rst->clk_out_enb_v, CLK_V_CPULP); // Disable the reset on the non-CPU parts of the fast cluster. write32(CRC_RST_CPUG_CLR_NONCPU, &clk_rst->rst_cpug_cmplx_clr); // Disable the various resets on the CPUs. write32(CRC_RST_CPUG_CLR_CPU0 | CRC_RST_CPUG_CLR_CPU1 | CRC_RST_CPUG_CLR_CPU2 | CRC_RST_CPUG_CLR_CPU3 | CRC_RST_CPUG_CLR_DBG0 | CRC_RST_CPUG_CLR_DBG1 | CRC_RST_CPUG_CLR_DBG2 | CRC_RST_CPUG_CLR_DBG3 | CRC_RST_CPUG_CLR_CORE0 | CRC_RST_CPUG_CLR_CORE1 | CRC_RST_CPUG_CLR_CORE2 | CRC_RST_CPUG_CLR_CORE3 | CRC_RST_CPUG_CLR_CX0 | CRC_RST_CPUG_CLR_CX1 | CRC_RST_CPUG_CLR_CX2 | CRC_RST_CPUG_CLR_CX3 | CRC_RST_CPUG_CLR_L2 | CRC_RST_CPUG_CLR_PDBG, &clk_rst->rst_cpug_cmplx_clr); // Disable the reset on the non-CPU parts of the slow cluster. write32(CRC_RST_CPULP_CLR_NONCPU, &clk_rst->rst_cpulp_cmplx_clr); // Disable the various resets on the LP CPU. write32(CRC_RST_CPULP_CLR_CPU0 | CRC_RST_CPULP_CLR_DBG0 | CRC_RST_CPULP_CLR_CORE0 | CRC_RST_CPULP_CLR_CX0 | CRC_RST_CPULP_CLR_L2 | CRC_RST_CPULP_CLR_PDBG, &clk_rst->rst_cpulp_cmplx_clr); } void clock_halt_avp(void) { for (;;) { write32(FLOW_EVENT_JTAG | FLOW_EVENT_LIC_IRQ | FLOW_EVENT_GIC_IRQ | FLOW_MODE_WAITEVENT, &flow->halt_cop_events); } } void clock_init(void) { u32 osc = clock_get_osc_bits(); /* Set PLLC dynramp_step A to 0x2b and B to 0xb (from U-Boot -- why? */ writel(0x2b << 17 | 0xb << 9, &clk_rst->pllc_misc2); /* Max out the AVP clock before everything else (need PLLC for that). */ init_pll(&clk_rst->pllc_base, &clk_rst->pllc_misc, osc_table[osc].pllc); /* Be more careful with processor clock, wait for the lock. (~10us) */ setbits_le32(&clk_rst->pllc_misc, PLLC_MISC_LOCK_ENABLE); while (!(read32(&clk_rst->pllc_base) & PLL_BASE_LOCK)) /* wait */; /* Typical ratios are 1:2:2 or 1:2:3 sclk:hclk:pclk (See: APB DMA * features section in the TRM). */ write32(1 << HCLK_DIVISOR_SHIFT | 0 << PCLK_DIVISOR_SHIFT, &clk_rst->clk_sys_rate); /* pclk = hclk = sclk/2 */ write32(CLK_DIVIDER(TEGRA_PLLC_KHZ, 300000) << PLL_OUT_RATIO_SHIFT | PLL_OUT_CLKEN | PLL_OUT_RSTN, &clk_rst->pllc_out); write32(SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT | SCLK_SOURCE_PLLC_OUT1 << SCLK_RUN_SHIFT, &clk_rst->sclk_brst_pol); /* sclk = 300 MHz */ /* Change the oscillator drive strength (from U-Boot -- why?) */ clrsetbits_le32(&clk_rst->osc_ctrl, OSC_XOFS_MASK, OSC_DRIVE_STRENGTH << OSC_XOFS_SHIFT); /* * Ambiguous quote from u-boot. TODO: what's this mean? * "should update same value in PMC_OSC_EDPD_OVER XOFS * field for warmboot " */ clrsetbits_le32(&pmc->osc_edpd_over, PMC_OSC_EDPD_OVER_XOFS_MASK, OSC_DRIVE_STRENGTH << PMC_OSC_EDPD_OVER_XOFS_SHIFT); /* Disable IDDQ for PLLX before we set it up (from U-Boot -- why?) */ clrbits_le32(&clk_rst->pllx_misc3, PLLX_IDDQ_MASK); /* Set up PLLP_OUT(1|2|3|4) divisor to generate (9.6|48|102|204)MHz */ write32((CLK_DIVIDER(TEGRA_PLLP_KHZ, 9600) << PLL_OUT_RATIO_SHIFT | PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT1_SHIFT | (CLK_DIVIDER(TEGRA_PLLP_KHZ, 48000) << PLL_OUT_RATIO_SHIFT | PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT2_SHIFT, &clk_rst->pllp_outa); write32((CLK_DIVIDER(TEGRA_PLLP_KHZ, 102000) << PLL_OUT_RATIO_SHIFT | PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT3_SHIFT | (CLK_DIVIDER(TEGRA_PLLP_KHZ, 204000) << PLL_OUT_RATIO_SHIFT | PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT4_SHIFT, &clk_rst->pllp_outb); init_pll(&clk_rst->pllx_base, &clk_rst->pllx_misc, osc_table[osc].pllx); init_pll(&clk_rst->pllp_base, &clk_rst->pllp_misc, osc_table[osc].pllp); init_pll(&clk_rst->pllu_base, &clk_rst->pllu_misc, osc_table[osc].pllu); init_utmip_pll(); graphics_pll(); } void clock_enable_clear_reset(u32 l, u32 h, u32 u, u32 v, u32 w, u32 x) { if (l) writel(l, &clk_rst->clk_enb_l_set); if (h) writel(h, &clk_rst->clk_enb_h_set); if (u) writel(u, &clk_rst->clk_enb_u_set); if (v) writel(v, &clk_rst->clk_enb_v_set); if (w) writel(w, &clk_rst->clk_enb_w_set); if (x) writel(x, &clk_rst->clk_enb_x_set); /* Give clocks time to stabilize. */ udelay(IO_STABILIZATION_DELAY); if (l) writel(l, &clk_rst->rst_dev_l_clr); if (h) writel(h, &clk_rst->rst_dev_h_clr); if (u) writel(u, &clk_rst->rst_dev_u_clr); if (v) writel(v, &clk_rst->rst_dev_v_clr); if (w) writel(w, &clk_rst->rst_dev_w_clr); if (x) writel(x, &clk_rst->rst_dev_x_clr); }