[U-Boot] [PATCH v4 2/4] Tegra2: Add more clock support

Simon Glass sjg at chromium.org
Tue Aug 30 18:23:13 CEST 2011


This adds functions to enable/disable clocks and reset to on-chip peripherals.

Signed-off-by: Simon Glass <sjg at chromium.org>
---
Changes in v2:
- Removed use of bitfield access macros

 arch/arm/cpu/armv7/tegra2/Makefile         |    2 +-
 arch/arm/cpu/armv7/tegra2/ap20.c           |   52 ++----
 arch/arm/cpu/armv7/tegra2/clock.c          |  158 +++++++++++++++++
 arch/arm/include/asm/arch-tegra2/clk_rst.h |  112 +++++++-----
 arch/arm/include/asm/arch-tegra2/clock.h   |  264 ++++++++++++++++++++++++++++
 board/nvidia/common/board.c                |   79 +++------
 6 files changed, 525 insertions(+), 142 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/tegra2/clock.c
 create mode 100644 arch/arm/include/asm/arch-tegra2/clock.h

diff --git a/arch/arm/cpu/armv7/tegra2/Makefile b/arch/arm/cpu/armv7/tegra2/Makefile
index f1ea915..b35764c 100644
--- a/arch/arm/cpu/armv7/tegra2/Makefile
+++ b/arch/arm/cpu/armv7/tegra2/Makefile
@@ -28,7 +28,7 @@ include $(TOPDIR)/config.mk
 LIB	=  $(obj)lib$(SOC).o
 
 SOBJS	:= lowlevel_init.o
-COBJS	:= ap20.o board.o sys_info.o timer.o
+COBJS	:= ap20.o board.o clock.o sys_info.o timer.o
 
 SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
diff --git a/arch/arm/cpu/armv7/tegra2/ap20.c b/arch/arm/cpu/armv7/tegra2/ap20.c
index 60dd5df..e3832e2 100644
--- a/arch/arm/cpu/armv7/tegra2/ap20.c
+++ b/arch/arm/cpu/armv7/tegra2/ap20.c
@@ -25,6 +25,7 @@
 #include <asm/io.h>
 #include <asm/arch/tegra2.h>
 #include <asm/arch/clk_rst.h>
+#include <asm/arch/clock.h>
 #include <asm/arch/pmc.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/scu.h>
@@ -35,33 +36,34 @@ u32 s_first_boot = 1;
 void init_pllx(void)
 {
 	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	struct clk_pll *pll = &clkrst->crc_pll[CLOCK_PLL_ID_XCPU];
 	u32 reg;
 
 	/* If PLLX is already enabled, just return */
-	reg = readl(&clkrst->crc_pllx_base);
+	reg = readl(&pll->pll_base);
 	if (reg & PLL_ENABLE)
 		return;
 
 	/* Set PLLX_MISC */
 	reg = CPCON;				/* CPCON[11:8]  = 0001 */
-	writel(reg, &clkrst->crc_pllx_misc);
+	writel(reg, &pll->pll_misc);
 
 	/* Use 12MHz clock here */
-	reg = (PLL_BYPASS | PLL_DIVM);
+	reg = (PLL_BYPASS | PLL_DIVM_VALUE);
 	reg |= (1000 << 8);			/* DIVN = 0x3E8 */
-	writel(reg, &clkrst->crc_pllx_base);
+	writel(reg, &pll->pll_base);
 
 	reg |= PLL_ENABLE;
-	writel(reg, &clkrst->crc_pllx_base);
+	writel(reg, &pll->pll_base);
 
 	reg &= ~PLL_BYPASS;
-	writel(reg, &clkrst->crc_pllx_base);
+	writel(reg, &pll->pll_base);
 }
 
 static void enable_cpu_clock(int enable)
 {
 	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
-	u32 reg, clk;
+	u32 clk;
 
 	/*
 	 * NOTE:
@@ -83,10 +85,6 @@ static void enable_cpu_clock(int enable)
 		writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div);
 	}
 
-	/* Fetch the register containing the main CPU complex clock enable */
-	reg = readl(&clkrst->crc_clk_out_enb_l);
-	reg |= CLK_ENB_CPU;
-
 	/*
 	 * Read the register containing the individual CPU clock enables and
 	 * always stop the clock to CPU 1.
@@ -103,7 +101,8 @@ static void enable_cpu_clock(int enable)
 	}
 
 	writel(clk, &clkrst->crc_clk_cpu_cmplx);
-	writel(reg, &clkrst->crc_clk_out_enb_l);
+
+	clock_enable(PERIPH_ID_CPU);
 }
 
 static int is_cpu_powered(void)
@@ -179,7 +178,7 @@ static void enable_cpu_power_rail(void)
 static void reset_A9_cpu(int reset)
 {
 	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
-	u32 reg, cpu;
+	u32 cpu;
 
 	/*
 	* NOTE:  Regardless of whether the request is to hold the CPU in reset
@@ -193,44 +192,27 @@ static void reset_A9_cpu(int reset)
 	cpu = SET_DBGRESET1 | SET_DERESET1 | SET_CPURESET1;
 	writel(cpu, &clkrst->crc_cpu_cmplx_set);
 
-	reg = readl(&clkrst->crc_rst_dev_l);
 	if (reset) {
 		/* Now place CPU0 into reset */
 		cpu |= SET_DBGRESET0 | SET_DERESET0 | SET_CPURESET0;
 		writel(cpu, &clkrst->crc_cpu_cmplx_set);
-
-		/* Enable master CPU reset */
-		reg |= SWR_CPU_RST;
 	} else {
 		/* Take CPU0 out of reset */
 		cpu = CLR_DBGRESET0 | CLR_DERESET0 | CLR_CPURESET0;
 		writel(cpu, &clkrst->crc_cpu_cmplx_clr);
-
-		/* Disable master CPU reset */
-		reg &= ~SWR_CPU_RST;
 	}
 
-	writel(reg, &clkrst->crc_rst_dev_l);
+	/* Enable/Disable master CPU reset */
+	reset_set_enable(PERIPH_ID_CPU, reset);
 }
 
 static void clock_enable_coresight(int enable)
 {
 	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
-	u32 rst, clk, src;
-
-	rst = readl(&clkrst->crc_rst_dev_u);
-	clk = readl(&clkrst->crc_clk_out_enb_u);
-
-	if (enable) {
-		rst &= ~SWR_CSITE_RST;
-		clk |= CLK_ENB_CSITE;
-	} else {
-		rst |= SWR_CSITE_RST;
-		clk &= ~CLK_ENB_CSITE;
-	}
+	u32 rst, src;
 
-	writel(clk, &clkrst->crc_clk_out_enb_u);
-	writel(rst, &clkrst->crc_rst_dev_u);
+	clock_set_enable(PERIPH_ID_CORESIGHT, enable);
+	reset_set_enable(PERIPH_ID_CORESIGHT, !enable);
 
 	if (enable) {
 		/*
diff --git a/arch/arm/cpu/armv7/tegra2/clock.c b/arch/arm/cpu/armv7/tegra2/clock.c
new file mode 100644
index 0000000..67eed14
--- /dev/null
+++ b/arch/arm/cpu/armv7/tegra2/clock.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Tegra2 Clock control functions */
+
+#include <asm/io.h>
+#include <asm/arch/clk_rst.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/timer.h>
+#include <asm/arch/tegra2.h>
+#include <common.h>
+
+#ifdef DEBUG
+#define assert(x)	\
+	({ if (!(x)) printf("Assertion failure '%s' %s line %d\n", \
+		#x, __FILE__, __LINE__); })
+#else
+#define assert(x)
+#endif
+
+/*
+ * Get the oscillator frequency, from the corresponding hardware configuration
+ * field.
+ */
+enum clock_osc_freq clock_get_osc_freq(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_FREQ_MASK) >> OSC_FREQ_SHIFT;
+}
+
+unsigned long clock_start_pll(enum clock_pll_id clkid, u32 divm, u32 divn,
+		u32 divp, u32 cpcon, u32 lfcon)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 data;
+	struct clk_pll *pll;
+
+	assert(clock_pll_id_isvalid(clkid));
+	pll = &clkrst->crc_pll[clkid];
+
+	/*
+	 * We cheat by treating all PLL (except PLLU) in the same fashion.
+	 * This works only because:
+	 * - same fields are always mapped at same offsets, except DCCON
+	 * - 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);
+
+	data = (divm << PLL_DIVM_SHIFT) | (divn << PLL_DIVN_SHIFT) |
+			(0 << PLL_BYPASS_SHIFT) | (1 << PLL_ENABLE_SHIFT);
+
+	if (clkid == CLOCK_PLL_ID_USB)
+		data |= divp << PLLU_VCO_FREQ_SHIFT;
+	else
+		data |= divp << PLL_DIVP_SHIFT;
+	writel(data, &pll->pll_base);
+
+	/* calculate the stable time */
+	return timer_get_us() + CLOCK_PLL_STABLE_DELAY_US;
+}
+
+void clock_set_enable(enum periph_id periph_id, int enable)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 *clk = &clkrst->crc_clk_out_enb[PERIPH_REG(periph_id)];
+	u32 reg;
+
+	/* Enable/disable the clock to this peripheral */
+	assert(clock_periph_id_isvalid(periph_id));
+	reg = readl(clk);
+	if (enable)
+		reg |= PERIPH_MASK(periph_id);
+	else
+		reg &= ~PERIPH_MASK(periph_id);
+	writel(reg, clk);
+}
+
+void clock_enable(enum periph_id clkid)
+{
+	clock_set_enable(clkid, 1);
+}
+
+void clock_disable(enum periph_id clkid)
+{
+	clock_set_enable(clkid, 0);
+}
+
+void reset_set_enable(enum periph_id periph_id, int enable)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 *reset = &clkrst->crc_rst_dev[PERIPH_REG(periph_id)];
+	u32 reg;
+
+	/* Enable/disable reset to the peripheral */
+	assert(clock_periph_id_isvalid(periph_id));
+	reg = readl(reset);
+	if (enable)
+		reg |= PERIPH_MASK(periph_id);
+	else
+		reg &= ~PERIPH_MASK(periph_id);
+	writel(reg, reset);
+}
+
+void reset_periph(enum periph_id periph_id, int us_delay)
+{
+	/* Put peripheral into reset */
+	reset_set_enable(periph_id, 1);
+	udelay(us_delay);
+
+	/* Remove reset */
+	reset_set_enable(periph_id, 0);
+
+	udelay(us_delay);
+}
+
+void reset_cmplx_set_enable(int cpu, int which, int reset)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 mask;
+
+	/* Form the mask, which depends on the cpu chosen. Tegra2 has 2 */
+	assert(cpu >= 0 && cpu < 2);
+	mask = which << cpu;
+
+	/* either enable or disable those reset for that CPU */
+	if (reset)
+		writel(mask, &clkrst->crc_cpu_cmplx_set);
+	else
+		writel(mask, &clkrst->crc_cpu_cmplx_clr);
+}
diff --git a/arch/arm/include/asm/arch-tegra2/clk_rst.h b/arch/arm/include/asm/arch-tegra2/clk_rst.h
index 36e27b5..a574c53 100644
--- a/arch/arm/include/asm/arch-tegra2/clk_rst.h
+++ b/arch/arm/include/asm/arch-tegra2/clk_rst.h
@@ -24,15 +24,34 @@
 #ifndef _CLK_RST_H_
 #define _CLK_RST_H_
 
+/* 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_misc;		/* other misc things */
+};
+
+/* PLL registers - there are several PLLs in the clock controller */
+struct clk_pll_simple {
+	uint pll_base;		/* the control register */
+	uint pll_misc;		/* other misc things */
+};
+
+/*
+ * Most PLLs use the clk_pll structure, but some have a simpler two-member
+ * structure for which we use clk_pll_simple. The reason for this non-
+ * othogonal setup is not stated.
+ */
+#define TEGRA_CLK_PLLS		6
+#define TEGRA_CLK_SIMPLE_PLLS	3	/* Number of simple PLLs */
+#define TEGRA_CLK_REGS		3	/* Number of clock enable registers */
+
 /* Clock/Reset Controller (CLK_RST_CONTROLLER_) regs */
 struct clk_rst_ctlr {
-	uint crc_rst_src;		/* _RST_SOURCE_0,	0x00 */
-	uint crc_rst_dev_l;		/* _RST_DEVICES_L_0,	0x04 */
-	uint crc_rst_dev_h;		/* _RST_DEVICES_H_0,	0x08 */
-	uint crc_rst_dev_u;		/* _RST_DEVICES_U_0,	0x0C */
-	uint crc_clk_out_enb_l;		/* _CLK_OUT_ENB_L_0,	0x10 */
-	uint crc_clk_out_enb_h;		/* _CLK_OUT_ENB_H_0,	0x14 */
-	uint crc_clk_out_enb_u;		/* _CLK_OUT_ENB_U_0,	0x18 */
+	uint crc_rst_src;			/* _RST_SOURCE_0,0x00 */
+	uint crc_rst_dev[TEGRA_CLK_REGS];	/* _RST_DEVICES_L/H/U_0 */
+	uint crc_clk_out_enb[TEGRA_CLK_REGS];	/* _CLK_OUT_ENB_L/H/U_0 */
 	uint crc_reserved0;		/* reserved_0,		0x1C */
 	uint crc_cclk_brst_pol;		/* _CCLK_BURST_POLICY_0,0x20 */
 	uint crc_super_cclk_div;	/* _SUPER_CCLK_DIVIDER_0,0x24 */
@@ -52,44 +71,11 @@ struct clk_rst_ctlr {
 	uint crc_osc_freq_det_stat;	/* _OSC_FREQ_DET_STATUS_0,0x5C */
 	uint crc_reserved2[8];		/* reserved_2[8],	0x60-7C */
 
-	uint crc_pllc_base;		/* _PLLC_BASE_0,	0x80 */
-	uint crc_pllc_out;		/* _PLLC_OUT_0,		0x84 */
-	uint crc_reserved3;		/* reserved_3,		0x88 */
-	uint crc_pllc_misc;		/* _PLLC_MISC_0,	0x8C */
-
-	uint crc_pllm_base;		/* _PLLM_BASE_0,	0x90 */
-	uint crc_pllm_out;		/* _PLLM_OUT_0,		0x94 */
-	uint crc_reserved4;		/* reserved_4,		0x98 */
-	uint crc_pllm_misc;		/* _PLLM_MISC_0,	0x9C */
-
-	uint crc_pllp_base;		/* _PLLP_BASE_0,	0xA0 */
-	uint crc_pllp_outa;		/* _PLLP_OUTA_0,	0xA4 */
-	uint crc_pllp_outb;		/* _PLLP_OUTB_0,	0xA8 */
-	uint crc_pllp_misc;		/* _PLLP_MISC_0,	0xAC */
-
-	uint crc_plla_base;		/* _PLLA_BASE_0,	0xB0 */
-	uint crc_plla_out;		/* _PLLA_OUT_0,		0xB4 */
-	uint crc_reserved5;		/* reserved_5,		0xB8 */
-	uint crc_plla_misc;		/* _PLLA_MISC_0,	0xBC */
-
-	uint crc_pllu_base;		/* _PLLU_BASE_0,	0xC0 */
-	uint crc_reserved6;		/* _reserved_6,		0xC4 */
-	uint crc_reserved7;		/* _reserved_7,		0xC8 */
-	uint crc_pllu_misc;		/* _PLLU_MISC_0,	0xCC */
-
-	uint crc_plld_base;		/* _PLLD_BASE_0,	0xD0 */
-	uint crc_reserved8;		/* _reserved_8,		0xD4 */
-	uint crc_reserved9;		/* _reserved_9,		0xD8 */
-	uint crc_plld_misc;		/* _PLLD_MISC_0,	0xDC */
+	struct clk_pll crc_pll[TEGRA_CLK_PLLS];	/* PLLs from 0x80 to 0xdc */
 
-	uint crc_pllx_base;		/* _PLLX_BASE_0,	0xE0 */
-	uint crc_pllx_misc;		/* _PLLX_MISC_0,	0xE4 */
+	/* PLLs from 0xe0 to 0xf4    */
+	struct clk_pll_simple crc_pll_simple[TEGRA_CLK_SIMPLE_PLLS];
 
-	uint crc_plle_base;		/* _PLLE_BASE_0,	0xE8 */
-	uint crc_plle_misc;		/* _PLLE_MISC_0,	0xEC */
-
-	uint crc_plls_base;		/* _PLLS_BASE_0,	0xF0 */
-	uint crc_plls_misc;		/* _PLLS_MISC_0,	0xF4 */
 	uint crc_reserved10;		/* _reserved_10,	0xF8 */
 	uint crc_reserved11;		/* _reserved_11,	0xFC */
 
@@ -157,8 +143,8 @@ struct clk_rst_ctlr {
 #define PLL_BYPASS		(1 << 31)
 #define PLL_ENABLE		(1 << 30)
 #define PLL_BASE_OVRRIDE	(1 << 28)
-#define PLL_DIVP		(1 << 20)	/* post divider, b22:20 */
-#define PLL_DIVM		0x0C		/* input divider, b4:0 */
+#define PLL_DIVP_VALUE		(1 << 20)	/* post divider, b22:20 */
+#define PLL_DIVM_VALUE		0x0C		/* input divider, b4:0 */
 
 #define SWR_UARTD_RST		(1 << 1)
 #define CLK_ENB_UARTD		(1 << 1)
@@ -191,9 +177,37 @@ struct clk_rst_ctlr {
 
 #define CPCON			(1 << 8)
 
-#define SWR_SDMMC4_RST		(1 << 15)
-#define CLK_ENB_SDMMC4		(1 << 15)
-#define SWR_SDMMC3_RST		(1 << 5)
-#define CLK_ENB_SDMMC3		(1 << 5)
+/* CLK_RST_CONTROLLER_CLK_CPU_CMPLX_0 */
+#define CPU1_CLK_STP_SHIFT	9
+
+#define CPU0_CLK_STP_SHIFT	8
+#define CPU0_CLK_STP_MASK	(1U << CPU0_CLK_STP_SHIFT)
+
+/* CLK_RST_CONTROLLER_PLLx_BASE_0 */
+#define PLL_BYPASS_SHIFT	31
+#define PLL_BYPASS_MASK		(1U << PLL_BYPASS_SHIFT)
+
+#define PLL_ENABLE_SHIFT	30
+#define PLL_ENABLE_MASK		(1U << PLL_ENABLE_SHIFT)
+
+#define PLL_BASE_OVRRIDE_MASK	(1U << 28)
+
+#define PLL_DIVP_SHIFT		20
+
+#define PLL_DIVN_SHIFT		8
+
+#define PLL_DIVM_SHIFT		0
+
+/* CLK_RST_CONTROLLER_PLLx_MISC_0 */
+#define PLL_CPCON_SHIFT		8
+#define PLL_CPCON_MASK		(15U << PLL_CPCON_SHIFT)
+
+#define PLL_LFCON_SHIFT		4
+
+#define PLLU_VCO_FREQ_SHIFT	20
+
+/* CLK_RST_CONTROLLER_OSC_CTRL_0 */
+#define OSC_FREQ_SHIFT		30
+#define OSC_FREQ_MASK		(3U << OSC_FREQ_SHIFT)
 
 #endif	/* CLK_RST_H */
diff --git a/arch/arm/include/asm/arch-tegra2/clock.h b/arch/arm/include/asm/arch-tegra2/clock.h
new file mode 100644
index 0000000..81a9f02
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra2/clock.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Tegra2 clock control functions */
+
+#ifndef _CLOCK_H
+
+
+/* Set of oscillator frequencies supported in the internal API. */
+enum clock_osc_freq {
+	/* All in MHz, so 13_0 is 13.0MHz */
+	CLOCK_OSC_FREQ_13_0,
+	CLOCK_OSC_FREQ_19_2,
+	CLOCK_OSC_FREQ_12_0,
+	CLOCK_OSC_FREQ_26_0,
+
+	CLOCK_OSC_FREQ_COUNT,
+};
+
+/* The PLLs supported by the hardware */
+enum clock_pll_id {
+	CLOCK_PLL_ID_FIRST,
+	CLOCK_PLL_ID_CGENERAL = CLOCK_PLL_ID_FIRST,
+	CLOCK_PLL_ID_MEMORY,
+	CLOCK_PLL_ID_PERIPH,
+	CLOCK_PLL_ID_AUDIO,
+	CLOCK_PLL_ID_USB,
+	CLOCK_PLL_ID_DISPLAY,
+
+	/* now the simple ones */
+	CLOCK_PLL_ID_FIRST_SIMPLE,
+	CLOCK_PLL_ID_XCPU = CLOCK_PLL_ID_FIRST_SIMPLE,
+	CLOCK_PLL_ID_EPCI,
+	CLOCK_PLL_ID_SFROM32KHZ,
+
+	CLOCK_PLL_ID_COUNT,
+};
+
+/* The clocks supported by the hardware */
+enum periph_id {
+	PERIPH_ID_FIRST,
+
+	/* Low word: 31:0 */
+	PERIPH_ID_CPU = PERIPH_ID_FIRST,
+	PERIPH_ID_RESERVED1,
+	PERIPH_ID_RESERVED2,
+	PERIPH_ID_AC97,
+	PERIPH_ID_RTC,
+	PERIPH_ID_TMR,
+	PERIPH_ID_UART1,
+	PERIPH_ID_UART2,
+
+	/* 8 */
+	PERIPH_ID_GPIO,
+	PERIPH_ID_SDMMC2,
+	PERIPH_ID_SPDIF,
+	PERIPH_ID_I2S1,
+	PERIPH_ID_I2C1,
+	PERIPH_ID_NDFLASH,
+	PERIPH_ID_SDMMC1,
+	PERIPH_ID_SDMMC4,
+
+	/* 16 */
+	PERIPH_ID_TWC,
+	PERIPH_ID_PWC,
+	PERIPH_ID_I2S2,
+	PERIPH_ID_EPP,
+	PERIPH_ID_VI,
+	PERIPH_ID_2D,
+	PERIPH_ID_USBD,
+	PERIPH_ID_ISP,
+
+	/* 24 */
+	PERIPH_ID_3D,
+	PERIPH_ID_IDE,
+	PERIPH_ID_DISP2,
+	PERIPH_ID_DISP1,
+	PERIPH_ID_HOST1X,
+	PERIPH_ID_VCP,
+	PERIPH_ID_RESERVED30,
+	PERIPH_ID_CACHE2,
+
+	/* Middle word: 63:32 */
+	PERIPH_ID_MEM,
+	PERIPH_ID_AHBDMA,
+	PERIPH_ID_APBDMA,
+	PERIPH_ID_RESERVED35,
+	PERIPH_ID_KBC,
+	PERIPH_ID_STAT_MON,
+	PERIPH_ID_PMC,
+	PERIPH_ID_FUSE,
+
+	/* 40 */
+	PERIPH_ID_KFUSE,
+	PERIPH_ID_SBC1,
+	PERIPH_ID_SNOR,
+	PERIPH_ID_SPI1,
+	PERIPH_ID_SBC2,
+	PERIPH_ID_XIO,
+	PERIPH_ID_SBC3,
+	PERIPH_ID_DVC_I2C,
+
+	/* 48 */
+	PERIPH_ID_DSI,
+	PERIPH_ID_TVO,
+	PERIPH_ID_MIPI,
+	PERIPH_ID_HDMI,
+	PERIPH_ID_CSI,
+	PERIPH_ID_TVDAC,
+	PERIPH_ID_I2C2,
+	PERIPH_ID_UART3,
+
+	/* 56 */
+	PERIPH_ID_RESERVED56,
+	PERIPH_ID_EMC,
+	PERIPH_ID_USB2,
+	PERIPH_ID_USB3,
+	PERIPH_ID_MPE,
+	PERIPH_ID_VDE,
+	PERIPH_ID_BSEA,
+	PERIPH_ID_BSEV,
+
+	/* Upper word 95:64 */
+	PERIPH_ID_SPEEDO,
+	PERIPH_ID_UART4,
+	PERIPH_ID_UART5,
+	PERIPH_ID_I2C3,
+	PERIPH_ID_SBC4,
+	PERIPH_ID_SDMMC3,
+	PERIPH_ID_PCIE,
+	PERIPH_ID_OWR,
+
+	/* 72 */
+	PERIPH_ID_AFI,
+	PERIPH_ID_CORESIGHT,
+	PERIPH_ID_RESERVED74,
+	PERIPH_ID_AVPUCQ,
+	PERIPH_ID_RESERVED76,
+	PERIPH_ID_RESERVED77,
+	PERIPH_ID_RESERVED78,
+	PERIPH_ID_RESERVED79,
+
+	/* 80 */
+	PERIPH_ID_RESERVED80,
+	PERIPH_ID_RESERVED81,
+	PERIPH_ID_RESERVED82,
+	PERIPH_ID_RESERVED83,
+	PERIPH_ID_IRAMA,
+	PERIPH_ID_IRAMB,
+	PERIPH_ID_IRAMC,
+	PERIPH_ID_IRAMD,
+
+	/* 88 */
+	PERIPH_ID_CRAM2,
+
+	PERIPH_ID_COUNT,
+};
+
+/* Converts a clock number to a clock register: 0=L, 1=H, 2=U */
+#define PERIPH_REG(id) ((id) >> 5)
+
+/* Mask value for a clock (within PERIPH_REG(id)) */
+#define PERIPH_MASK(id) (1 << ((id) & 0x1f))
+
+/* return 1 if a PLL ID is in range */
+#define clock_pll_id_isvalid(id) ((id) >= CLOCK_PLL_ID_FIRST && \
+		(id) < CLOCK_PLL_ID_COUNT)
+
+/* return 1 if a peripheral ID is in range */
+#define clock_periph_id_isvalid(id) ((id) >= PERIPH_ID_FIRST && \
+		(id) < PERIPH_ID_COUNT)
+
+/* PLL stabilization delay in usec */
+#define CLOCK_PLL_STABLE_DELAY_US 300
+
+/* return the current oscillator clock frequency */
+enum clock_osc_freq clock_get_osc_freq(void);
+
+/*
+ * Start PLL using the provided configuration parameters.
+ *
+ * @param id	clock id
+ * @param divm	input divider
+ * @param divn	feedback divider
+ * @param divp	post divider 2^n
+ * @param cpcon	charge pump setup control
+ * @param lfcon	loop filter setup control
+ *
+ * @returns monotonic time in us that the PLL will be stable
+ */
+unsigned long clock_start_pll(enum clock_pll_id id, u32 divm, u32 divn,
+		u32 divp, u32 cpcon, u32 lfcon);
+
+/*
+ * Enable a clock
+ *
+ * @param id	clock id
+ */
+void clock_enable(enum periph_id clkid);
+
+/*
+ * Set whether a clock is enabled or disabled.
+ *
+ * @param id		clock id
+ * @param enable	1 to enable, 0 to disable
+ */
+void clock_set_enable(enum periph_id clkid, int enable);
+
+/*
+ * Reset a peripheral. This puts it in reset, waits for a delay, then takes
+ * it out of reset and waits for th delay again.
+ *
+ * @param periph_id	peripheral to reset
+ * @param us_delay	time to delay in microseconds
+ */
+void reset_periph(enum periph_id periph_id, int us_delay);
+
+/*
+ * Put a peripheral into or out of reset.
+ *
+ * @param periph_id	peripheral to reset
+ * @param enable	1 to put into reset, 0 to take out of reset
+ */
+void reset_set_enable(enum periph_id periph_id, int enable);
+
+
+/* CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET/CLR_0 */
+enum crc_reset_id {
+	/* Things we can hold in reset for each CPU */
+	crc_rst_cpu = 1,
+	crc_rst_de = 1 << 2,	/* What is de? */
+	crc_rst_watchdog = 1 << 3,
+	crc_rst_debug = 1 << 4,
+};
+
+/*
+ * Put parts of the CPU complex into or out of reset.\
+ *
+ * @param cpu		cpu number (0 or 1 on Tegra2)
+ * @param which		which parts of the complex to affect (OR of crc_reset_id)
+ * @param reset		1 to assert reset, 0 to de-assert
+ */
+void reset_cmplx_set_enable(int cpu, int which, int reset);
+
+#endif
+
diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c
index 8ab9440..2777b34 100644
--- a/board/nvidia/common/board.c
+++ b/board/nvidia/common/board.c
@@ -28,6 +28,7 @@
 #include <asm/arch/sys_proto.h>
 
 #include <asm/arch/clk_rst.h>
+#include <asm/arch/clock.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/uart.h>
 #include "board.h"
@@ -76,33 +77,28 @@ int timer_init(void)
 static void clock_init_uart(void)
 {
 	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	struct clk_pll *pll = &clkrst->crc_pll[CLOCK_PLL_ID_PERIPH];
 	u32 reg;
 
-	reg = readl(&clkrst->crc_pllp_base);
+	reg = readl(&pll->pll_base);
 	if (!(reg & PLL_BASE_OVRRIDE)) {
 		/* Override pllp setup for 216MHz operation. */
-		reg = (PLL_BYPASS | PLL_BASE_OVRRIDE | PLL_DIVP);
-		reg |= (((NVRM_PLLP_FIXED_FREQ_KHZ/500) << 8) | PLL_DIVM);
-		writel(reg, &clkrst->crc_pllp_base);
+		reg = (PLL_BYPASS | PLL_BASE_OVRRIDE | PLL_DIVP_VALUE);
+		reg |= (((NVRM_PLLP_FIXED_FREQ_KHZ/500) << 8) | PLL_DIVM_VALUE);
+		writel(reg, &pll->pll_base);
 
 		reg |= PLL_ENABLE;
-		writel(reg, &clkrst->crc_pllp_base);
+		writel(reg, &pll->pll_base);
 
 		reg &= ~PLL_BYPASS;
-		writel(reg, &clkrst->crc_pllp_base);
+		writel(reg, &pll->pll_base);
 	}
 
 	/* Now do the UART reset/clock enable */
 #if defined(CONFIG_TEGRA2_ENABLE_UARTA)
-	/* Assert Reset to UART */
-	reg = readl(&clkrst->crc_rst_dev_l);
-	reg |= SWR_UARTA_RST;		/* SWR_UARTA_RST = 1 */
-	writel(reg, &clkrst->crc_rst_dev_l);
-
-	/* Enable clk to UART */
-	reg = readl(&clkrst->crc_clk_out_enb_l);
-	reg |= CLK_ENB_UARTA;		/* CLK_ENB_UARTA = 1 */
-	writel(reg, &clkrst->crc_clk_out_enb_l);
+	/* Assert UART reset and enable clock */
+	reset_set_enable(PERIPH_ID_UART1, 1);
+	clock_enable(PERIPH_ID_UART1);
 
 	/* Enable pllp_out0 to UART */
 	reg = readl(&clkrst->crc_clk_src_uarta);
@@ -113,20 +109,12 @@ static void clock_init_uart(void)
 	udelay(2);
 
 	/* De-assert reset to UART */
-	reg = readl(&clkrst->crc_rst_dev_l);
-	reg &= ~SWR_UARTA_RST;		/* SWR_UARTA_RST = 0 */
-	writel(reg, &clkrst->crc_rst_dev_l);
+	reset_set_enable(PERIPH_ID_UART1, 0);
 #endif	/* CONFIG_TEGRA2_ENABLE_UARTA */
 #if defined(CONFIG_TEGRA2_ENABLE_UARTD)
-	/* Assert Reset to UART */
-	reg = readl(&clkrst->crc_rst_dev_u);
-	reg |= SWR_UARTD_RST;		/* SWR_UARTD_RST = 1 */
-	writel(reg, &clkrst->crc_rst_dev_u);
-
-	/* Enable clk to UART */
-	reg = readl(&clkrst->crc_clk_out_enb_u);
-	reg |= CLK_ENB_UARTD;		/* CLK_ENB_UARTD = 1 */
-	writel(reg, &clkrst->crc_clk_out_enb_u);
+	/* Assert UART reset and enable clock */
+	reset_set_enable(PERIPH_ID_UART4, 1);
+	clock_enable(PERIPH_ID_UART4);
 
 	/* Enable pllp_out0 to UART */
 	reg = readl(&clkrst->crc_clk_src_uartd);
@@ -137,9 +125,7 @@ static void clock_init_uart(void)
 	udelay(2);
 
 	/* De-assert reset to UART */
-	reg = readl(&clkrst->crc_rst_dev_u);
-	reg &= ~SWR_UARTD_RST;		/* SWR_UARTD_RST = 0 */
-	writel(reg, &clkrst->crc_rst_dev_u);
+	reset_set_enable(PERIPH_ID_UART4, 0);
 #endif	/* CONFIG_TEGRA2_ENABLE_UARTD */
 }
 
@@ -183,16 +169,8 @@ static void clock_init_mmc(void)
 	u32 reg;
 
 	/* Do the SDMMC resets/clock enables */
-
-	/* Assert Reset to SDMMC4 */
-	reg = readl(&clkrst->crc_rst_dev_l);
-	reg |= SWR_SDMMC4_RST;		/* SWR_SDMMC4_RST = 1 */
-	writel(reg, &clkrst->crc_rst_dev_l);
-
-	/* Enable clk to SDMMC4 */
-	reg = readl(&clkrst->crc_clk_out_enb_l);
-	reg |= CLK_ENB_SDMMC4;		/* CLK_ENB_SDMMC4 = 1 */
-	writel(reg, &clkrst->crc_clk_out_enb_l);
+	reset_set_enable(PERIPH_ID_SDMMC4, 1);
+	clock_enable(PERIPH_ID_SDMMC4);
 
 	/* Enable pllp_out0 to SDMMC4 */
 	reg = readl(&clkrst->crc_clk_src_sdmmc4);
@@ -206,20 +184,10 @@ static void clock_init_mmc(void)
 	 */
 	udelay(2);
 
-	/* De-assert reset to SDMMC4 */
-	reg = readl(&clkrst->crc_rst_dev_l);
-	reg &= ~SWR_SDMMC4_RST;		/* SWR_SDMMC4_RST = 0 */
-	writel(reg, &clkrst->crc_rst_dev_l);
-
-	/* Assert Reset to SDMMC3 */
-	reg = readl(&clkrst->crc_rst_dev_u);
-	reg |= SWR_SDMMC3_RST;		/* SWR_SDMMC3_RST = 1 */
-	writel(reg, &clkrst->crc_rst_dev_u);
+	reset_set_enable(PERIPH_ID_SDMMC4, 1);
 
-	/* Enable clk to SDMMC3 */
-	reg = readl(&clkrst->crc_clk_out_enb_u);
-	reg |= CLK_ENB_SDMMC3;		/* CLK_ENB_SDMMC3 = 1 */
-	writel(reg, &clkrst->crc_clk_out_enb_u);
+	reset_set_enable(PERIPH_ID_SDMMC3, 1);
+	clock_enable(PERIPH_ID_SDMMC3);
 
 	/* Enable pllp_out0 to SDMMC4, set divisor to 11 for 20MHz */
 	reg = readl(&clkrst->crc_clk_src_sdmmc3);
@@ -230,10 +198,7 @@ static void clock_init_mmc(void)
 	/* wait for 2us */
 	udelay(2);
 
-	/* De-assert reset to SDMMC3 */
-	reg = readl(&clkrst->crc_rst_dev_u);
-	reg &= ~SWR_SDMMC3_RST;		/* SWR_SDMMC3_RST = 0 */
-	writel(reg, &clkrst->crc_rst_dev_u);
+	reset_set_enable(PERIPH_ID_SDMMC3, 0);
 }
 
 /*
-- 
1.7.3.1



More information about the U-Boot mailing list