clock_prep.c revision 1.2.2.2 1 /* $Id: clock_prep.c,v 1.2.2.2 2013/01/16 05:32:56 yamt Exp $ */
2
3 /*
4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Petri Laakso.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #include <sys/cdefs.h>
34 #include <sys/types.h>
35
36 #include <arm/imx/imx23_clkctrlreg.h>
37
38 #include <lib/libsa/stand.h>
39
40 #include "common.h"
41
42 void enable_pll(void);
43 void enable_ref_cpu(int);
44 void enable_ref_emi(int);
45 void enable_ref_io(int);
46 void use_ref_cpu(void);
47 void use_ref_emi(void);
48 void use_ref_io(void);
49 void set_hbus_div(int);
50 void set_emi_div(int);
51 void set_ssp_div(int);
52
53 /* Clock frequences after clock_prep() */
54 #define CPU_FRAC 0x13 /* CPUCLK @ 454.74 MHz */
55 #define HBUS_DIV 0x3 /* AHBCLK @ 151.58 MHz */
56 #define EMI_FRAC 0x21 /* EMICLK @ 130.91 MHz */
57 #define EMI_DIV 0x2
58 #define IO_FRAC 0x12 /* IOCLK @ 480.00 MHz */
59 #define SSP_DIV 0x5 /* SSPCLK @ 96.00 MHz */
60
61 /* Offset to frac register for byte store instructions. (strb) */
62 #define HW_CLKCTRL_FRAC_CPU (HW_CLKCTRL_FRAC+0)
63 #define HW_CLKCTRL_FRAC_EMI (HW_CLKCTRL_FRAC+1)
64 #define HW_CLKCTRL_FRAC_IO (HW_CLKCTRL_FRAC+3)
65
66 #define CLKCTRL_RD(reg) *(volatile uint32_t *)((HW_CLKCTRL_BASE) + (reg))
67 #define CLKCTRL_WR(reg, val) \
68 do { \
69 *(volatile uint32_t *)((HW_CLKCTRL_BASE) + (reg)) = val; \
70 } while (0)
71 #define CLKCTRL_WR_BYTE(reg, val) \
72 do { \
73 *(volatile uint8_t *)((HW_CLKCTRL_BASE) + (reg)) = val; \
74 } while (0)
75
76 /*
77 * Initializes fast PLL based clocks for CPU, HBUS and DRAM.
78 */
79 int
80 clock_prep(void)
81 {
82
83 enable_pll();
84 enable_ref_cpu(CPU_FRAC);
85 enable_ref_emi(EMI_FRAC);
86 enable_ref_io(IO_FRAC);
87 set_emi_div(EMI_DIV);
88 set_hbus_div(HBUS_DIV);
89 delay_us(1000);
90 use_ref_cpu();
91 //delay_us(1000);
92 use_ref_emi();
93 use_ref_io();
94 set_ssp_div(SSP_DIV);
95
96 return 0;
97 }
98
99 /*
100 * Turn PLL on and wait until it's locked to 480 MHz.
101 */
102 void
103 enable_pll(void)
104 {
105
106 CLKCTRL_WR(HW_CLKCTRL_PLLCTRL0_SET, HW_CLKCTRL_PLLCTRL0_POWER);
107 while (!(CLKCTRL_RD(HW_CLKCTRL_PLLCTRL1) & HW_CLKCTRL_PLLCTRL1_LOCK));
108
109 return;
110 }
111
112 /*
113 * Enable fractional divider clock ref_cpu with divide value "frac".
114 */
115 void
116 enable_ref_cpu(int frac)
117 {
118 uint32_t reg;
119
120 reg = CLKCTRL_RD(HW_CLKCTRL_FRAC);
121 reg &= ~(HW_CLKCTRL_FRAC_CLKGATECPU | HW_CLKCTRL_FRAC_CPUFRAC);
122 reg |= __SHIFTIN(frac, HW_CLKCTRL_FRAC_CPUFRAC);
123 CLKCTRL_WR_BYTE(HW_CLKCTRL_FRAC_CPU, reg);
124
125 return;
126 }
127
128 /*
129 * Enable fractional divider clock ref_emi with divide value "frac".
130 */
131 void
132 enable_ref_emi(int frac)
133 {
134 uint32_t reg;
135
136 reg = CLKCTRL_RD(HW_CLKCTRL_FRAC);
137 reg &= ~(HW_CLKCTRL_FRAC_CLKGATEEMI | HW_CLKCTRL_FRAC_EMIFRAC);
138 reg |= __SHIFTIN(frac, HW_CLKCTRL_FRAC_EMIFRAC);
139 CLKCTRL_WR_BYTE(HW_CLKCTRL_FRAC_EMI, (reg >> 8));
140
141 return;
142 }
143
144 /*
145 * Enable fractional divider clock ref_io with divide value "frac".
146 */
147 void
148 enable_ref_io(int frac)
149 {
150 uint32_t reg;
151
152 reg = CLKCTRL_RD(HW_CLKCTRL_FRAC);
153 reg &= ~(HW_CLKCTRL_FRAC_CLKGATEIO | HW_CLKCTRL_FRAC_IOFRAC);
154 reg |= __SHIFTIN(frac, HW_CLKCTRL_FRAC_IOFRAC);
155 CLKCTRL_WR_BYTE(HW_CLKCTRL_FRAC_IO, (reg >> 24));
156
157 return;
158 }
159
160 /*
161 * Divide CLK_P by "div" to get CLK_H frequency.
162 */
163 void
164 set_hbus_div(int div)
165 {
166 uint32_t reg;
167
168 reg = CLKCTRL_RD(HW_CLKCTRL_HBUS);
169 reg &= ~(HW_CLKCTRL_HBUS_DIV);
170 reg |= __SHIFTIN(div, HW_CLKCTRL_HBUS_DIV);
171 while (CLKCTRL_RD(HW_CLKCTRL_HBUS) & HW_CLKCTRL_HBUS_BUSY);
172 CLKCTRL_WR(HW_CLKCTRL_HBUS, reg);
173
174 return;
175 }
176
177 /*
178 * ref_emi is divied "div" to get CLK_EMI.
179 */
180 void
181 set_emi_div(int div)
182 {
183 uint32_t reg;
184
185 reg = CLKCTRL_RD(HW_CLKCTRL_EMI);
186 reg &= ~(HW_CLKCTRL_EMI_DIV_EMI);
187 reg |= __SHIFTIN(div, HW_CLKCTRL_EMI_DIV_EMI);
188 CLKCTRL_WR(HW_CLKCTRL_EMI, reg);
189
190 return;
191 }
192
193 /*
194 * ref_io is divied "div" to get CLK_SSP.
195 */
196 void
197 set_ssp_div(int div)
198 {
199 uint32_t reg;
200
201 reg = CLKCTRL_RD(HW_CLKCTRL_SSP);
202 reg &= ~(HW_CLKCTRL_SSP_DIV);
203 reg |= __SHIFTIN(div, HW_CLKCTRL_SSP_DIV);
204 CLKCTRL_WR(HW_CLKCTRL_SSP, reg);
205
206 return;
207 }
208
209 /*
210 * Transition from ref_xtal to use ref_cpu.
211 */
212 void
213 use_ref_cpu(void)
214 {
215 CLKCTRL_WR(HW_CLKCTRL_CLKSEQ_CLR, HW_CLKCTRL_CLKSEQ_BYPASS_CPU);
216 return;
217 }
218
219 /*
220 * Transition from ref_xtal to use ref_emi and source CLK_EMI from ref_emi.
221 */
222 void
223 use_ref_emi(void)
224 {
225 uint32_t reg;
226
227 /* Enable ref_emi. */
228 CLKCTRL_WR(HW_CLKCTRL_CLKSEQ_CLR, HW_CLKCTRL_CLKSEQ_BYPASS_EMI);
229
230 /* CLK_EMI sourced by the ref_emi. */
231 reg = CLKCTRL_RD(HW_CLKCTRL_EMI);
232 reg &= ~(HW_CLKCTRL_EMI_CLKGATE);
233 CLKCTRL_WR(HW_CLKCTRL_EMI, reg);
234
235 return;
236 }
237
238 /*
239 * Transition from ref_xtal to use ref_io and source CLK_SSP from ref_io.
240 */
241 void
242 use_ref_io(void)
243 {
244 uint32_t reg;
245
246 /* Enable ref_io for SSP. */
247 CLKCTRL_WR(HW_CLKCTRL_CLKSEQ_CLR, HW_CLKCTRL_CLKSEQ_BYPASS_SSP);
248
249 /* CLK_SSP sourced by the ref_io. */
250 reg = CLKCTRL_RD(HW_CLKCTRL_SSP);
251 reg &= ~(HW_CLKCTRL_SSP_CLKGATE);
252 CLKCTRL_WR(HW_CLKCTRL_SSP, reg);
253
254 return;
255 }
256