summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2012-04-02 13:18:47 +0000
committerAlbert ARIBAUD <albert.u.boot@aribaud.net>2012-05-15 08:31:37 +0200
commitffc76482c2d86ca29168527e57fb75c0ea08ec6d (patch)
tree3a238ea8f71feb6320c8e34ec296c1df2f905e9e /arch/arm
parentf9f3e1b8df9804c98a2a3077d0acb24247e0e74b (diff)
tegra: Add functions to access low-level Osc/PLL details
Add clock_ll_read_pll() to read PLL parameters and clock_get_osc_bypass() to find out if the Oscillator is bypassed. These are needed by warmboot. Signed-off-by: Simon Glass <sjg@chromium.org> Signed-off-by: Tom Warren <twarren@nvidia.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/cpu/armv7/tegra2/clock.c32
-rw-r--r--arch/arm/include/asm/arch-tegra2/clk_rst.h3
-rw-r--r--arch/arm/include/asm/arch-tegra2/clock.h22
3 files changed, 57 insertions, 0 deletions
diff --git a/arch/arm/cpu/armv7/tegra2/clock.c b/arch/arm/cpu/armv7/tegra2/clock.c
index 39376ab86e..b6b32107fe 100644
--- a/arch/arm/cpu/armv7/tegra2/clock.c
+++ b/arch/arm/cpu/armv7/tegra2/clock.c
@@ -410,6 +410,16 @@ enum clock_osc_freq clock_get_osc_freq(void)
return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
}
+int clock_get_osc_bypass(void)
+{
+ struct clk_rst_ctlr *clkrst =
+ (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+ u32 reg;
+
+ reg = readl(&clkrst->crc_osc_ctrl);
+ return (reg & OSC_XOBP_MASK) >> OSC_XOBP_SHIFT;
+}
+
/* Returns a pointer to the registers of the given pll */
static struct clk_pll *get_pll(enum clock_id clkid)
{
@@ -420,6 +430,28 @@ static struct clk_pll *get_pll(enum clock_id clkid)
return &clkrst->crc_pll[clkid];
}
+int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn,
+ u32 *divp, u32 *cpcon, u32 *lfcon)
+{
+ struct clk_pll *pll = get_pll(clkid);
+ u32 data;
+
+ assert(clkid != CLOCK_ID_USB);
+
+ /* Safety check, adds to code size but is small */
+ if (!clock_id_isvalid(clkid) || clkid == CLOCK_ID_USB)
+ return -1;
+ data = readl(&pll->pll_base);
+ *divm = (data & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT;
+ *divn = (data & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT;
+ *divp = (data & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT;
+ data = readl(&pll->pll_misc);
+ *cpcon = (data & PLL_CPCON_MASK) >> PLL_CPCON_SHIFT;
+ *lfcon = (data & PLL_LFCON_MASK) >> PLL_LFCON_SHIFT;
+
+ return 0;
+}
+
unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn,
u32 divp, u32 cpcon, u32 lfcon)
{
diff --git a/arch/arm/include/asm/arch-tegra2/clk_rst.h b/arch/arm/include/asm/arch-tegra2/clk_rst.h
index 415e420012..8c3be91514 100644
--- a/arch/arm/include/asm/arch-tegra2/clk_rst.h
+++ b/arch/arm/include/asm/arch-tegra2/clk_rst.h
@@ -117,6 +117,7 @@ struct clk_rst_ctlr {
#define PLL_CPCON_MASK (15U << PLL_CPCON_SHIFT)
#define PLL_LFCON_SHIFT 4
+#define PLL_LFCON_MASK (15U << PLL_LFCON_SHIFT)
#define PLLU_VCO_FREQ_SHIFT 20
#define PLLU_VCO_FREQ_MASK (1U << PLLU_VCO_FREQ_SHIFT)
@@ -124,6 +125,8 @@ struct clk_rst_ctlr {
/* CLK_RST_CONTROLLER_OSC_CTRL_0 */
#define OSC_FREQ_SHIFT 30
#define OSC_FREQ_MASK (3U << OSC_FREQ_SHIFT)
+#define OSC_XOBP_SHIFT 1
+#define OSC_XOBP_MASK (1U << OSC_XOBP_SHIFT)
/*
* CLK_RST_CONTROLLER_CLK_SOURCE_x_OUT_0 - the mask here is normally 8 bits
diff --git a/arch/arm/include/asm/arch-tegra2/clock.h b/arch/arm/include/asm/arch-tegra2/clock.h
index 6b12c76e8d..1d3ae38644 100644
--- a/arch/arm/include/asm/arch-tegra2/clock.h
+++ b/arch/arm/include/asm/arch-tegra2/clock.h
@@ -210,6 +210,21 @@ enum clock_osc_freq clock_get_osc_freq(void);
unsigned long clock_start_pll(enum clock_id id, u32 divm, u32 divn,
u32 divp, u32 cpcon, u32 lfcon);
+/**
+ * Read low-level parameters of a PLL.
+ *
+ * @param id clock id to read (note: USB is not supported)
+ * @param divm returns input divider
+ * @param divn returns feedback divider
+ * @param divp returns post divider 2^n
+ * @param cpcon returns charge pump setup control
+ * @param lfcon returns loop filter setup control
+ *
+ * @returns 0 if ok, -1 on error (invalid clock id)
+ */
+int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn,
+ u32 *divp, u32 *cpcon, u32 *lfcon);
+
/*
* Enable a clock
*
@@ -368,6 +383,13 @@ void clock_ll_start_uart(enum periph_id periph_id);
*/
enum periph_id clock_decode_periph_id(const void *blob, int node);
+/**
+ * Checks if the oscillator bypass is enabled (XOBP bit)
+ *
+ * @return 1 if bypass is enabled, 0 if not
+ */
+int clock_get_osc_bypass(void);
+
/*
* Checks that clocks are valid and prints a warning if not
*