/*
* Copyright (c) 2010-2015, NVIDIA CORPORATION. All rights reserved.
*
- * 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 <http://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-2.0
*/
/* Tegra SoC common clock control functions */
{
struct clk_pll *pll = NULL;
struct clk_pll_info *pllinfo = &tegra_pll_info_table[clkid];
+ struct clk_pll_simple *simple_pll = NULL;
u32 misc_data, data;
- if (clkid < (enum clock_id)TEGRA_CLK_PLLS)
+ if (clkid < (enum clock_id)TEGRA_CLK_PLLS) {
pll = get_pll(clkid);
+ } else {
+ simple_pll = clock_get_simple_pll(clkid);
+ if (!simple_pll) {
+ debug("%s: Uknown simple PLL %d\n", __func__, clkid);
+ return 0;
+ }
+ }
/*
* pllinfo has the m/n/p and kcp/kvco mask and shift
* values for all of the PLLs used in U-Boot, with any
* SoC differences accounted for.
+ *
+ * Preserve EN_LOCKDET, etc.
*/
- misc_data = readl(&pll->pll_misc); /* preserve EN_LOCKDET, etc. */
- misc_data &= ~(pllinfo->kcp_mask << pllinfo->kcp_shift) | (cpcon << pllinfo->kcp_shift);
- misc_data &= ~(pllinfo->kvco_mask << pllinfo->kvco_shift) | (lfcon << pllinfo->kvco_shift);
+ if (pll)
+ misc_data = readl(&pll->pll_misc);
+ else
+ misc_data = readl(&simple_pll->pll_misc);
+ misc_data &= ~(pllinfo->kcp_mask << pllinfo->kcp_shift);
+ misc_data |= cpcon << pllinfo->kcp_shift;
+ misc_data &= ~(pllinfo->kvco_mask << pllinfo->kvco_shift);
+ misc_data |= lfcon << pllinfo->kvco_shift;
data = (divm << pllinfo->m_shift) | (divn << pllinfo->n_shift);
data |= divp << pllinfo->p_shift;
writel(misc_data, &pll->pll_misc);
writel(data, &pll->pll_base);
} else {
- struct clk_pll_simple *pll = clock_get_simple_pll(clkid);
-
- if (!pll) {
- debug("%s: Uknown simple PLL %d\n", __func__, clkid);
- return 0;
- }
- writel(misc_data, &pll->pll_misc);
- writel(data, &pll->pll_base);
+ writel(misc_data, &simple_pll->pll_misc);
+ writel(data, &simple_pll->pll_base);
}
/* calculate the stable time */
writel(mask, &clkrst->crc_cpu_cmplx_clr);
}
+unsigned int __weak clk_m_get_rate(unsigned int parent_rate)
+{
+ return parent_rate;
+}
+
unsigned clock_get_rate(enum clock_id clkid)
{
struct clk_pll *pll;
if (clkid == CLOCK_ID_OSC)
return parent_rate;
+ if (clkid == CLOCK_ID_CLK_M)
+ return clk_m_get_rate(parent_rate);
+
pll = get_pll(clkid);
if (!pll)
return 0;
* PLLU uses p_mask/p_shift for VCO on all but T210,
* T210 uses normal DIVP. Handled in pllinfo table.
*/
- divm <<= (base >> pllinfo->p_shift) & pllinfo->p_mask;
+#ifdef CONFIG_TEGRA210
+ /*
+ * PLLP's primary output (pllP_out0) on T210 is the VCO, and divp is
+ * not applied. pllP_out2 does have divp applied. All other pllP_outN
+ * are divided down from pllP_out0. We only support pllP_out0 in
+ * U-Boot at the time of writing this comment.
+ */
+ if (clkid != CLOCK_ID_PERIPH)
+#endif
+ divm <<= (base >> pllinfo->p_shift) & pllinfo->p_mask;
do_div(rate, divm);
return rate;
}
reset_set_enable(periph_id, 0);
}
-#ifdef CONFIG_OF_CONTROL
+#if CONFIG_IS_ENABLED(OF_CONTROL)
int clock_decode_periph_id(const void *blob, int node)
{
enum periph_id id;
assert(clock_periph_id_isvalid(id));
return id;
}
-#endif /* CONFIG_OF_CONTROL */
+#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
int clock_verify(void)
{
pll_rate[CLOCK_ID_XCPU] = clock_get_rate(CLOCK_ID_XCPU);
pll_rate[CLOCK_ID_SFROM32KHZ] = 32768;
pll_rate[CLOCK_ID_OSC] = clock_get_rate(CLOCK_ID_OSC);
+ pll_rate[CLOCK_ID_CLK_M] = clock_get_rate(CLOCK_ID_CLK_M);
debug("Osc = %d\n", pll_rate[CLOCK_ID_OSC]);
+ debug("CLKM = %d\n", pll_rate[CLOCK_ID_CLK_M]);
debug("PLLC = %d\n", pll_rate[CLOCK_ID_CGENERAL]);
debug("PLLM = %d\n", pll_rate[CLOCK_ID_MEMORY]);
debug("PLLP = %d\n", pll_rate[CLOCK_ID_PERIPH]);