summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2015-04-14 21:03:32 -0600
committerTom Warren <twarren@nvidia.com>2015-05-13 09:24:09 -0700
commit801b05cd613d00c98ecb3300f15e011518075ef4 (patch)
tree4424e11db0c6071ddc45e0c292026363863d6543 /arch
parentec022efb8658cce75699afc3ce6ee8b2d9d0c273 (diff)
downloadtalos-obmc-uboot-801b05cd613d00c98ecb3300f15e011518075ef4.tar.gz
talos-obmc-uboot-801b05cd613d00c98ecb3300f15e011518075ef4.zip
tegra: clock: Add checking for invalid clock IDs
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@chromium.org> Signed-off-by: Tom Warren <twarren@nvidia.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/include/asm/arch-tegra/clock.h3
-rw-r--r--arch/arm/mach-tegra/clock.c30
2 files changed, 29 insertions, 4 deletions
diff --git a/arch/arm/include/asm/arch-tegra/clock.h b/arch/arm/include/asm/arch-tegra/clock.h
index 9d8114c4ec..a641a16a4b 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.
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 7c274b5f99..e07f11d090 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -81,9 +81,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)
{
@@ -110,7 +119,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.
@@ -119,8 +128,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);
@@ -129,7 +137,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;
@@ -431,6 +451,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()... */
OpenPOWER on IntegriCloud