[U-Boot] [PATCH 2/3] tegra20: add clock_set_pllout function
Lucas Stach
dev at lynxeye.de
Sun Aug 19 18:08:15 CEST 2012
Common practice on Tegra 2 boards is to use the pllp_out4 FO
to generate the ULPI reference clock. For this to work we have
to override the default hardware generated output divider.
This function adds a clean way to do so.
Signed-off-by: Lucas Stach <dev at lynxeye.de>
---
arch/arm/cpu/tegra20-common/clock.c | 25 +++++++++++++++++++++++++
arch/arm/cpu/tegra20-common/warmboot_avp.c | 2 +-
arch/arm/include/asm/arch-tegra20/clk_rst.h | 11 +++++++++--
arch/arm/include/asm/arch-tegra20/clock.h | 19 +++++++++++++++++++
4 Dateien geändert, 54 Zeilen hinzugefügt(+), 3 Zeilen entfernt(-)
diff --git a/arch/arm/cpu/tegra20-common/clock.c b/arch/arm/cpu/tegra20-common/clock.c
index d9bb851..068b552 100644
--- a/arch/arm/cpu/tegra20-common/clock.c
+++ b/arch/arm/cpu/tegra20-common/clock.c
@@ -604,6 +604,31 @@ unsigned long clock_get_periph_rate(enum periph_id periph_id,
(readl(reg) & OUT_CLK_DIVISOR_MASK) >> OUT_CLK_DIVISOR_SHIFT);
}
+int clock_set_pllout(enum clock_id clkid, enum pll_out_id pllout, unsigned rate)
+{
+ struct clk_pll *pll = get_pll(clkid);
+ int data = 0, div = 0, offset = 0;
+
+ if (!clock_id_is_pll(clkid))
+ return -1;
+
+ div = clk_get_divider(8, pll_rate[clkid], rate);
+
+ if (div < 0)
+ return -1;
+
+ /* out2 and out4 are in the high part of the register */
+ if (pllout == PLL_OUT2 || pllout == PLL_OUT4)
+ offset = 16;
+
+ data = (div << PLL_OUT_RATIO_SHIFT) |
+ PLL_OUT_OVRRIDE | PLL_OUT_CLKEN | PLL_OUT_RSTN;
+ clrsetbits_le32(&pll->pll_out[pllout >> 1],
+ PLL_OUT_RATIO_MASK << offset, data << offset);
+
+ return 0;
+}
+
/**
* Find the best available 7.1 format divisor given a parent clock rate and
* required child clock rate. This function assumes that a second-stage
diff --git a/arch/arm/cpu/tegra20-common/warmboot_avp.c b/arch/arm/cpu/tegra20-common/warmboot_avp.c
index cd01908..f6c71cb 100644
--- a/arch/arm/cpu/tegra20-common/warmboot_avp.c
+++ b/arch/arm/cpu/tegra20-common/warmboot_avp.c
@@ -214,7 +214,7 @@ void wb_start(void)
reg = PLLM_OUT1_RSTN_RESET_DISABLE | PLLM_OUT1_CLKEN_ENABLE |
PLLM_OUT1_RATIO_VAL_8;
- writel(reg, &clkrst->crc_pll[CLOCK_ID_MEMORY].pll_out);
+ writel(reg, &clkrst->crc_pll[CLOCK_ID_MEMORY].pll_out[0]);
reg = SCLK_SWAKE_FIQ_SRC_PLLM_OUT1 | SCLK_SWAKE_IRQ_SRC_PLLM_OUT1 |
SCLK_SWAKE_RUN_SRC_PLLM_OUT1 | SCLK_SWAKE_IDLE_SRC_PLLM_OUT1 |
diff --git a/arch/arm/include/asm/arch-tegra20/clk_rst.h b/arch/arm/include/asm/arch-tegra20/clk_rst.h
index 8c3be91..7b548c2 100644
--- a/arch/arm/include/asm/arch-tegra20/clk_rst.h
+++ b/arch/arm/include/asm/arch-tegra20/clk_rst.h
@@ -27,8 +27,7 @@
/* PLL registers - there are several PLLs in the clock controller */
struct clk_pll {
uint pll_base; /* the control register */
- uint pll_out; /* output control */
- uint reserved;
+ uint pll_out[2]; /* output control */
uint pll_misc; /* other misc things */
};
@@ -112,6 +111,14 @@ struct clk_rst_ctlr {
#define PLL_DIVM_SHIFT 0
#define PLL_DIVM_MASK (0x1f << PLL_DIVM_SHIFT)
+/* CLK_RST_CONTROLLER_PLLx_OUTx_0 */
+#define PLL_OUT_RSTN (1 << 0)
+#define PLL_OUT_CLKEN (1 << 1)
+#define PLL_OUT_OVRRIDE (1 << 2)
+
+#define PLL_OUT_RATIO_SHIFT 8
+#define PLL_OUT_RATIO_MASK (0xffU << PLL_OUT_RATIO_SHIFT)
+
/* CLK_RST_CONTROLLER_PLLx_MISC_0 */
#define PLL_CPCON_SHIFT 8
#define PLL_CPCON_MASK (15U << PLL_CPCON_SHIFT)
diff --git a/arch/arm/include/asm/arch-tegra20/clock.h b/arch/arm/include/asm/arch-tegra20/clock.h
index 20db9e6..dfef51e 100644
--- a/arch/arm/include/asm/arch-tegra20/clock.h
+++ b/arch/arm/include/asm/arch-tegra20/clock.h
@@ -186,6 +186,13 @@ enum periph_id {
PERIPH_ID_NONE = -1,
};
+enum pll_out_id {
+ PLL_OUT1,
+ PLL_OUT2,
+ PLL_OUT3,
+ PLL_OUT4
+};
+
/* Converts a clock number to a clock register: 0=L, 1=H, 2=U */
#define PERIPH_REG(id) ((id) >> 5)
@@ -218,6 +225,18 @@ unsigned long clock_start_pll(enum clock_id id, u32 divm, u32 divn,
u32 divp, u32 cpcon, u32 lfcon);
/**
+ * Set PLL output frequency
+ *
+ * @param clkid clock id
+ * @param pllout pll output id (
+ * @param rate desired output rate
+ *
+ * @return 0 if ok, -1 on error (invalid clock id or no suitable divider)
+ */
+int clock_set_pllout(enum clock_id clkid, enum pll_out_id pllout,
+ unsigned rate);
+
+/**
* Read low-level parameters of a PLL.
*
* @param id clock id to read (note: USB is not supported)
--
1.7.11.2
More information about the U-Boot
mailing list