1/* $Id: clock_prep.c,v 1.3 2013/10/07 17:36:40 matt 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/cdefs.h>
33#include <sys/param.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#define CLKCTRL_HBUS	(HW_CLKCTRL_BASE + HW_CLKCTRL_HBUS)
43#define CLKCTRL_PLL0	(HW_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0)
44#define CLKCTRL_PLL0_S	(HW_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0_SET)
45#define CLKCTRL_PLL0_C	(HW_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0_CLR)
46#define CLKCTRL_PLL1	(HW_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL1)
47#define CLKCTRL_FRAC	(HW_CLKCTRL_BASE + HW_CLKCTRL_FRAC)
48#define CLKCTRL_FRAC_S	(HW_CLKCTRL_BASE + HW_CLKCTRL_FRAC_SET)
49#define CLKCTRL_FRAC_C	(HW_CLKCTRL_BASE + HW_CLKCTRL_FRAC_CLR)
50#define CLKCTRL_SEQ	(HW_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ)
51#define CLKCTRL_SEQ_S	(HW_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ_SET)
52#define CLKCTRL_SEQ_C	(HW_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ_CLR)
53#define CLKCTRL_EMI	(HW_CLKCTRL_BASE + HW_CLKCTRL_EMI)
54#define CLKCTRL_SSP	(HW_CLKCTRL_BASE + HW_CLKCTRL_SSP)
55
56void en_pll(void);
57void set_hbus_div(unsigned int);
58void set_cpu_frac(unsigned int);
59void bypass_cpu(void);
60void set_emi_div(unsigned int);
61void set_emi_frac(unsigned int);
62void bypass_emi(void);
63
64/*
65 * Power on 480 MHz PLL.
66 */
67void
68en_pll(void)
69{
70
71	REG_WR(CLKCTRL_PLL0_S, HW_CLKCTRL_PLLCTRL0_POWER);
72	while(!(REG_RD(CLKCTRL_PLL1) & HW_CLKCTRL_PLLCTRL1))
73		;
74
75	return;
76}
77void
78bypass_cpu(void)
79{
80
81	REG_WR(CLKCTRL_SEQ_C, HW_CLKCTRL_CLKSEQ_BYPASS_CPU);
82
83	return;
84}
85void
86bypass_emi(void)
87{
88	REG_WR(CLKCTRL_SEQ_C, HW_CLKCTRL_CLKSEQ_BYPASS_EMI);
89
90	return;
91}
92void
93bypass_ssp(void)
94{
95	REG_WR(CLKCTRL_SEQ_C, HW_CLKCTRL_CLKSEQ_BYPASS_SSP);
96
97	return;
98}
99void
100bypass_saif(void)
101{
102	REG_WR(CLKCTRL_SEQ_C, HW_CLKCTRL_CLKSEQ_BYPASS_SAIF);
103
104	return;
105}
106/*
107 * Set HBUS divider value.
108 */
109void
110set_hbus_div(unsigned int div)
111{
112	uint32_t tmp_r;
113
114	while (REG_RD(CLKCTRL_HBUS) & HW_CLKCTRL_HBUS_BUSY)
115		;
116
117	tmp_r = REG_RD(CLKCTRL_HBUS);
118	tmp_r &= ~HW_CLKCTRL_HBUS_DIV;
119	tmp_r |= __SHIFTIN(div, HW_CLKCTRL_HBUS_DIV);
120	REG_WR(CLKCTRL_HBUS, tmp_r);
121
122	while (REG_RD(CLKCTRL_HBUS) & HW_CLKCTRL_HBUS_BUSY)
123		;
124
125	return;
126}
127/*
128 * Set CPU frac.
129 */
130void
131set_cpu_frac(unsigned int frac)
132{
133	uint8_t tmp_r;
134
135	tmp_r = REG_RD_BYTE(CLKCTRL_FRAC);
136	tmp_r &= ~(HW_CLKCTRL_FRAC_CLKGATECPU | HW_CLKCTRL_FRAC_CPUFRAC);
137	tmp_r |= __SHIFTIN(frac, HW_CLKCTRL_FRAC_CPUFRAC);
138	REG_WR_BYTE(CLKCTRL_FRAC, tmp_r);
139
140	return;
141}
142/*
143 * Set EMI frac.
144 */
145void
146set_emi_frac(unsigned int frac)
147{
148	uint8_t *emi_frac;
149	uint16_t tmp_r;
150
151	emi_frac = (uint8_t *)(CLKCTRL_FRAC);
152	emi_frac++;
153
154	tmp_r = *emi_frac<<8;
155	tmp_r &= ~(HW_CLKCTRL_FRAC_CLKGATEEMI | HW_CLKCTRL_FRAC_EMIFRAC);
156	tmp_r |= __SHIFTIN(frac, HW_CLKCTRL_FRAC_EMIFRAC);
157
158	*emi_frac = tmp_r>>8;
159
160	return;
161}
162/*
163 * Set EMU divider value.
164 */
165void
166set_emi_div(unsigned int div)
167{
168	uint32_t tmp_r;
169
170	while (REG_RD(CLKCTRL_EMI) &
171		(HW_CLKCTRL_EMI_BUSY_REF_XTAL | HW_CLKCTRL_EMI_BUSY_REF_EMI))
172		;
173
174	tmp_r = REG_RD(CLKCTRL_EMI);
175	tmp_r &= ~(HW_CLKCTRL_EMI_CLKGATE | HW_CLKCTRL_EMI_DIV_EMI);
176	tmp_r |= __SHIFTIN(div, HW_CLKCTRL_EMI_DIV_EMI);
177	REG_WR(CLKCTRL_EMI, tmp_r);
178
179	return;
180}
181/*
182 * Set SSP divider value.
183 */
184void
185set_ssp_div(unsigned int div)
186{
187	uint32_t tmp_r;
188
189	tmp_r = REG_RD(CLKCTRL_SSP);
190	tmp_r &= ~HW_CLKCTRL_SSP_CLKGATE;
191	REG_WR(CLKCTRL_SSP, tmp_r);
192
193	while (REG_RD(CLKCTRL_SSP) & HW_CLKCTRL_SSP_BUSY)
194		;
195
196	tmp_r = REG_RD(CLKCTRL_SSP);
197	tmp_r &= ~HW_CLKCTRL_SSP_DIV;
198	tmp_r |= __SHIFTIN(div, HW_CLKCTRL_SSP_DIV);
199	REG_WR(CLKCTRL_SSP, tmp_r);
200
201	while (REG_RD(CLKCTRL_SSP) & HW_CLKCTRL_SSP_BUSY)
202		;
203
204	return;
205}
206/*
207 * Set IO frac.
208 */
209void
210set_io_frac(unsigned int frac)
211{
212	uint8_t *io_frac;
213	uint32_t tmp_r;
214
215	io_frac = (uint8_t *)(CLKCTRL_FRAC);
216	io_frac++; /* emi */
217	io_frac++; /* pix */
218	io_frac++; /* io */
219	tmp_r = (*io_frac)<<24;
220	tmp_r &= ~(HW_CLKCTRL_FRAC_CLKGATEIO | HW_CLKCTRL_FRAC_IOFRAC);
221	tmp_r |= __SHIFTIN(frac, HW_CLKCTRL_FRAC_IOFRAC);
222
223	*io_frac = (uint8_t)(tmp_r>>24);
224
225	return;
226}
227