tegra: clock: Add checking for invalid clock IDs
authorSimon Glass <sjg@chromium.org>
Wed, 15 Apr 2015 03:03:32 +0000 (21:03 -0600)
committerTom Warren <twarren@nvidia.com>
Wed, 13 May 2015 16:24:09 +0000 (09:24 -0700)
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>
arch/arm/include/asm/arch-tegra/clock.h
arch/arm/mach-tegra/clock.c

index 9d8114c4ecfaf87e4c6bf5c6910fffe92ce35af0..a641a16a4bade121d9b7d4efa5f29288eb22ed62 100644 (file)
@@ -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.
index 7c274b5f9940044da9ff3783124961ea54c1ff93..e07f11d0901941e6b1026607ba165749f9f751ef 100644 (file)
@@ -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()... */