[U-Boot] [PATCH v3 13/25] tegra: clock: Add checking for invalid clock IDs

Simon Glass sjg at chromium.org
Wed Feb 11 15:52:06 CET 2015


The get_pll() function can do the wrong thing if passed values that are
out of range. Add checks for this and add a function which can return
a 'simple' PLL. This can be defined by SoCs with their own clocks.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

Changes in v3: None
Changes in v2: None

 arch/arm/cpu/tegra-common/clock.c       | 30 ++++++++++++++++++++++++++----
 arch/arm/include/asm/arch-tegra/clock.h |  3 +++
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/arch/arm/cpu/tegra-common/clock.c b/arch/arm/cpu/tegra-common/clock.c
index 11c7435..87c2950 100644
--- a/arch/arm/cpu/tegra-common/clock.c
+++ b/arch/arm/cpu/tegra-common/clock.c
@@ -80,9 +80,18 @@ static struct clk_pll *get_pll(enum clock_id clkid)
 			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
 
 	assert(clock_id_is_pll(clkid));
+	if (clkid >= (enum clock_id)TEGRA_CLK_PLLS) {
+		debug("%s: Invalid PLL\n", __func__);
+		return NULL;
+	}
 	return &clkrst->crc_pll[clkid];
 }
 
+__weak struct clk_pll_simple *clock_get_simple_pll(enum clock_id clkid)
+{
+	return NULL;
+}
+
 int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn,
 		u32 *divp, u32 *cpcon, u32 *lfcon)
 {
@@ -109,7 +118,7 @@ unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn,
 		u32 divp, u32 cpcon, u32 lfcon)
 {
 	struct clk_pll *pll = get_pll(clkid);
-	u32 data;
+	u32 misc_data, data;
 
 	/*
 	 * We cheat by treating all PLL (except PLLU) in the same fashion.
@@ -118,8 +127,7 @@ unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn,
 	 * - DCCON is always 0, doesn't conflict
 	 * - M,N, P of PLLP values are ignored for PLLP
 	 */
-	data = (cpcon << PLL_CPCON_SHIFT) | (lfcon << PLL_LFCON_SHIFT);
-	writel(data, &pll->pll_misc);
+	misc_data = (cpcon << PLL_CPCON_SHIFT) | (lfcon << PLL_LFCON_SHIFT);
 
 	data = (divm << PLL_DIVM_SHIFT) | (divn << PLL_DIVN_SHIFT) |
 			(0 << PLL_BYPASS_SHIFT) | (1 << PLL_ENABLE_SHIFT);
@@ -128,7 +136,19 @@ unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn,
 		data |= divp << PLLU_VCO_FREQ_SHIFT;
 	else
 		data |= divp << PLL_DIVP_SHIFT;
-	writel(data, &pll->pll_base);
+	if (pll) {
+		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);
+	}
 
 	/* calculate the stable time */
 	return timer_get_us() + CLOCK_PLL_STABLE_DELAY_US;
@@ -430,6 +450,8 @@ unsigned clock_get_rate(enum clock_id clkid)
 		return parent_rate;
 
 	pll = get_pll(clkid);
+	if (!pll)
+		return 0;
 	base = readl(&pll->pll_base);
 
 	/* Oh for bf_unpack()... */
diff --git a/arch/arm/include/asm/arch-tegra/clock.h b/arch/arm/include/asm/arch-tegra/clock.h
index 9d8114c..a641a16 100644
--- a/arch/arm/include/asm/arch-tegra/clock.h
+++ b/arch/arm/include/asm/arch-tegra/clock.h
@@ -265,6 +265,9 @@ void clock_early_init(void);
 /* Returns a pointer to the clock source register for a peripheral */
 u32 *get_periph_source_reg(enum periph_id periph_id);
 
+/* Returns a pointer to the given 'simple' PLL */
+struct clk_pll_simple *clock_get_simple_pll(enum clock_id clkid);
+
 /**
  * Given a peripheral ID and the required source clock, this returns which
  * value should be programmed into the source mux for that peripheral.
-- 
2.2.0.rc0.207.ga3a616c



More information about the U-Boot mailing list