Tegra2: Use clock and pinmux functions to simplify code
[oweals/u-boot.git] / arch / arm / cpu / armv7 / tegra2 / clock.c
1 /*
2  * Copyright (c) 2011 The Chromium OS Authors.
3  * See file CREDITS for list of people who contributed to this
4  * project.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19  * MA 02111-1307 USA
20  */
21
22 /* Tegra2 Clock control functions */
23
24 #include <asm/io.h>
25 #include <asm/arch/clk_rst.h>
26 #include <asm/arch/clock.h>
27 #include <asm/arch/timer.h>
28 #include <asm/arch/tegra2.h>
29 #include <common.h>
30
31 #ifdef DEBUG
32 #define assert(x)       \
33         ({ if (!(x)) printf("Assertion failure '%s' %s line %d\n", \
34                 #x, __FILE__, __LINE__); })
35 #else
36 #define assert(x)
37 #endif
38
39 /*
40  * Get the oscillator frequency, from the corresponding hardware configuration
41  * field.
42  */
43 enum clock_osc_freq clock_get_osc_freq(void)
44 {
45         struct clk_rst_ctlr *clkrst =
46                         (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
47         u32 reg;
48
49         reg = readl(&clkrst->crc_osc_ctrl);
50         return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
51 }
52
53 unsigned long clock_start_pll(enum clock_pll_id clkid, u32 divm, u32 divn,
54                 u32 divp, u32 cpcon, u32 lfcon)
55 {
56         struct clk_rst_ctlr *clkrst =
57                         (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
58         u32 data;
59         struct clk_pll *pll;
60
61         assert(clock_pll_id_isvalid(clkid));
62         pll = &clkrst->crc_pll[clkid];
63
64         /*
65          * We cheat by treating all PLL (except PLLU) in the same fashion.
66          * This works only because:
67          * - same fields are always mapped at same offsets, except DCCON
68          * - DCCON is always 0, doesn't conflict
69          * - M,N, P of PLLP values are ignored for PLLP
70          */
71         data = (cpcon << PLL_CPCON_SHIFT) | (lfcon << PLL_LFCON_SHIFT);
72         writel(data, &pll->pll_misc);
73
74         data = (divm << PLL_DIVM_SHIFT) | (divn << PLL_DIVN_SHIFT) |
75                         (0 << PLL_BYPASS_SHIFT) | (1 << PLL_ENABLE_SHIFT);
76
77         if (clkid == CLOCK_PLL_ID_USB)
78                 data |= divp << PLLU_VCO_FREQ_SHIFT;
79         else
80                 data |= divp << PLL_DIVP_SHIFT;
81         writel(data, &pll->pll_base);
82
83         /* calculate the stable time */
84         return timer_get_us() + CLOCK_PLL_STABLE_DELAY_US;
85 }
86
87 void clock_set_enable(enum periph_id periph_id, int enable)
88 {
89         struct clk_rst_ctlr *clkrst =
90                         (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
91         u32 *clk = &clkrst->crc_clk_out_enb[PERIPH_REG(periph_id)];
92         u32 reg;
93
94         /* Enable/disable the clock to this peripheral */
95         assert(clock_periph_id_isvalid(periph_id));
96         reg = readl(clk);
97         if (enable)
98                 reg |= PERIPH_MASK(periph_id);
99         else
100                 reg &= ~PERIPH_MASK(periph_id);
101         writel(reg, clk);
102 }
103
104 void clock_enable(enum periph_id clkid)
105 {
106         clock_set_enable(clkid, 1);
107 }
108
109 void clock_disable(enum periph_id clkid)
110 {
111         clock_set_enable(clkid, 0);
112 }
113
114 void reset_set_enable(enum periph_id periph_id, int enable)
115 {
116         struct clk_rst_ctlr *clkrst =
117                         (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
118         u32 *reset = &clkrst->crc_rst_dev[PERIPH_REG(periph_id)];
119         u32 reg;
120
121         /* Enable/disable reset to the peripheral */
122         assert(clock_periph_id_isvalid(periph_id));
123         reg = readl(reset);
124         if (enable)
125                 reg |= PERIPH_MASK(periph_id);
126         else
127                 reg &= ~PERIPH_MASK(periph_id);
128         writel(reg, reset);
129 }
130
131 void reset_periph(enum periph_id periph_id, int us_delay)
132 {
133         /* Put peripheral into reset */
134         reset_set_enable(periph_id, 1);
135         udelay(us_delay);
136
137         /* Remove reset */
138         reset_set_enable(periph_id, 0);
139
140         udelay(us_delay);
141 }
142
143 void reset_cmplx_set_enable(int cpu, int which, int reset)
144 {
145         struct clk_rst_ctlr *clkrst =
146                         (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
147         u32 mask;
148
149         /* Form the mask, which depends on the cpu chosen. Tegra2 has 2 */
150         assert(cpu >= 0 && cpu < 2);
151         mask = which << cpu;
152
153         /* either enable or disable those reset for that CPU */
154         if (reset)
155                 writel(mask, &clkrst->crc_cpu_cmplx_set);
156         else
157                 writel(mask, &clkrst->crc_cpu_cmplx_clr);
158 }