xref: /netbsd-src/sys/arch/evbarm/stand/bootimx23/clock_prep.c (revision 7788a0781fe6ff2cce37368b4578a7ade0850cb1)
1 /* $Id: clock_prep.c,v 1.2 2012/12/16 19:08:44 jkunz 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 static void enable_pll(void);
43 static void enable_ref_cpu(int);
44 static void enable_ref_emi(int);
45 static void enable_ref_io(int);
46 static void use_ref_cpu(void);
47 static void use_ref_emi(void);
48 static void use_ref_io(void);
49 static void set_hbus_div(int);
50 static void set_emi_div(int);
51 static void set_ssp_div(int);
52 
53 /*
54  * Clock frequences set by clock_prep()
55  */
56 #define CPU_FRAC	0x13		/* CPUCLK @ 454.74 MHz */
57 #define HBUS_DIV	0x3		/* AHBCLK @ 151.58 MHz */
58 #define EMI_FRAC	0x21		/* EMICLK @ 130.91 MHz */
59 #define EMI_DIV		0x2
60 #define IO_FRAC		0x12		/* IOCLK  @ 480.00 MHz */
61 #define SSP_DIV		0x5		/* SSPCLK @  96.00 MHz */
62 
63 /* Offset to frac register for CLKCTRL_WR_BYTE macro. */
64 #define HW_CLKCTRL_FRAC_CPU (HW_CLKCTRL_FRAC+0)
65 #define HW_CLKCTRL_FRAC_EMI (HW_CLKCTRL_FRAC+1)
66 #define HW_CLKCTRL_FRAC_IO (HW_CLKCTRL_FRAC+3)
67 
68 #define CLKCTRL_RD(reg) *(volatile uint32_t *)((HW_CLKCTRL_BASE) + (reg))
69 #define CLKCTRL_WR(reg, val)						\
70 do {									\
71 	*(volatile uint32_t *)((HW_CLKCTRL_BASE) + (reg)) = val;	\
72 } while (0)
73 #define CLKCTRL_WR_BYTE(reg, val)					\
74 do {									\
75 	*(volatile uint8_t *)((HW_CLKCTRL_BASE) + (reg)) = val;	\
76 } while (0)
77 
78 /*
79  * Initializes fast PLL based clocks for CPU, HBUS and DRAM.
80  */
81 int
82 clock_prep(void)
83 {
84 
85 	enable_pll();
86 	enable_ref_cpu(CPU_FRAC);
87 	enable_ref_emi(EMI_FRAC);
88 	enable_ref_io(IO_FRAC);
89 	set_emi_div(EMI_DIV);
90 	set_hbus_div(HBUS_DIV);
91 	use_ref_cpu();
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 static 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 static 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 static 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 static 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 static 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 static 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 static 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 static 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 static 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 static 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