imx51_ccm.c revision 271055
1248557Sray/*	$NetBSD: imx51_ccm.c,v 1.1 2012/04/17 09:33:31 bsh Exp $	*/
2248557Sray/*
3248557Sray * Copyright (c) 2010, 2011, 2012  Genetec Corporation.  All rights reserved.
4248557Sray * Written by Hashimoto Kenichi for Genetec Corporation.
5248557Sray *
6248557Sray * Redistribution and use in source and binary forms, with or without
7248557Sray * modification, are permitted provided that the following conditions
8248557Sray * are met:
9248557Sray * 1. Redistributions of source code must retain the above copyright
10248557Sray *    notice, this list of conditions and the following disclaimer.
11248557Sray * 2. Redistributions in binary form must reproduce the above copyright
12248557Sray *    notice, this list of conditions and the following disclaimer in the
13248557Sray *    documentation and/or other materials provided with the distribution.
14248557Sray *
15248557Sray * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
16248557Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17248557Sray * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18248557Sray * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
19248557Sray * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20248557Sray * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21248557Sray * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22248557Sray * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23248557Sray * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24248557Sray * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25248557Sray * POSSIBILITY OF SUCH DAMAGE.
26248557Sray */
27248557Sray
28248557Sray/*-
29250357Sray * Copyright (c) 2012, 2013 The FreeBSD Foundation
30248557Sray * All rights reserved.
31248557Sray *
32248557Sray * Portions of this software were developed by Oleksandr Rybalko
33248557Sray * under sponsorship from the FreeBSD Foundation.
34248557Sray *
35248557Sray * Redistribution and use in source and binary forms, with or without
36248557Sray * modification, are permitted provided that the following conditions
37248557Sray * are met:
38248557Sray * 1.	Redistributions of source code must retain the above copyright
39248557Sray *	notice, this list of conditions and the following disclaimer.
40248557Sray * 2.	Redistributions in binary form must reproduce the above copyright
41248557Sray *	notice, this list of conditions and the following disclaimer in the
42248557Sray *	documentation and/or other materials provided with the distribution.
43248557Sray *
44248557Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
45248557Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46248557Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47248557Sray * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
48248557Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49248557Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50248557Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51248557Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52248557Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53248557Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54248557Sray * SUCH DAMAGE.
55248557Sray */
56248557Sray
57248557Sray/*
58248557Sray * Clock Controller Module (CCM)
59248557Sray */
60248557Sray
61248557Sray#include <sys/cdefs.h>
62248557Sray__FBSDID("$FreeBSD: head/sys/arm/freescale/imx/imx51_ccm.c 271055 2014-09-03 21:45:39Z ian $");
63248557Sray
64248557Sray#include <sys/param.h>
65248557Sray#include <sys/systm.h>
66248557Sray#include <sys/bus.h>
67248557Sray#include <sys/kernel.h>
68248557Sray#include <sys/module.h>
69248557Sray#include <sys/malloc.h>
70248557Sray#include <sys/rman.h>
71248557Sray#include <machine/bus.h>
72248557Sray#include <machine/cpu.h>
73248557Sray#include <machine/intr.h>
74248557Sray
75248557Sray#include <dev/fdt/fdt_common.h>
76248557Sray#include <dev/ofw/openfirm.h>
77248557Sray#include <dev/ofw/ofw_bus.h>
78248557Sray#include <dev/ofw/ofw_bus_subr.h>
79248557Sray
80248557Sray#include <machine/bus.h>
81248557Sray#include <machine/fdt.h>
82248557Sray
83248557Sray#include <arm/freescale/imx/imx51_ccmvar.h>
84248557Sray#include <arm/freescale/imx/imx51_ccmreg.h>
85248557Sray#include <arm/freescale/imx/imx51_dpllreg.h>
86264977Sian#include <arm/freescale/imx/imx_ccmvar.h>
87257383Sian#include <arm/freescale/imx/imx_machdep.h>
88248557Sray
89248557Sray#define	IMXCCMDEBUG
90248557Sray#undef	IMXCCMDEBUG
91248557Sray
92248557Sray#ifndef	IMX51_OSC_FREQ
93248557Sray#define	IMX51_OSC_FREQ	(24 * 1000 * 1000)	/* 24MHz */
94248557Sray#endif
95248557Sray
96248557Sray#ifndef	IMX51_CKIL_FREQ
97248557Sray#define	IMX51_CKIL_FREQ	32768
98248557Sray#endif
99248557Sray
100248557Sraystruct imxccm_softc {
101248557Sray	device_t	sc_dev;
102248557Sray	struct resource *res[7];
103248557Sray	u_int64_t 	pll_freq[IMX51_N_DPLLS];
104248557Sray};
105248557Sray
106248557Sraystruct imxccm_softc *ccm_softc = NULL;
107248557Sray
108248557Sraystatic uint64_t imx51_get_pll_freq(u_int);
109248557Sray
110248557Sraystatic int imxccm_match(device_t);
111248557Sraystatic int imxccm_attach(device_t);
112248557Sray
113248557Sraystatic device_method_t imxccm_methods[] = {
114248557Sray	DEVMETHOD(device_probe, imxccm_match),
115248557Sray	DEVMETHOD(device_attach, imxccm_attach),
116248557Sray
117248557Sray	DEVMETHOD_END
118248557Sray};
119248557Sray
120248557Sraystatic driver_t imxccm_driver = {
121248557Sray	"imxccm",
122248557Sray	imxccm_methods,
123248557Sray	sizeof(struct imxccm_softc),
124248557Sray};
125248557Sray
126248557Sraystatic devclass_t imxccm_devclass;
127248557Sray
128248557SrayEARLY_DRIVER_MODULE(imxccm, simplebus, imxccm_driver, imxccm_devclass, 0, 0,
129248557Sray    BUS_PASS_CPU);
130248557Sray
131248557Sraystatic struct resource_spec imxccm_spec[] = {
132248557Sray	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Global registers */
133248557Sray	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* DPLLIP1 */
134248557Sray	{ SYS_RES_MEMORY,	2,	RF_ACTIVE },	/* DPLLIP2 */
135248557Sray	{ SYS_RES_MEMORY,	3,	RF_ACTIVE },	/* DPLLIP3 */
136248557Sray	{ SYS_RES_IRQ,		0,	RF_ACTIVE },    /* 71 */
137248557Sray	{ SYS_RES_IRQ,		1,	RF_ACTIVE },    /* 72 */
138248557Sray	{ -1, 0 }
139248557Sray};
140248557Sray
141248557Sraystatic int
142248557Srayimxccm_match(device_t dev)
143248557Sray{
144248557Sray
145261410Sian	if (!ofw_bus_status_okay(dev))
146261410Sian		return (ENXIO);
147261410Sian
148255130Srpaulo	if (!ofw_bus_is_compatible(dev, "fsl,imx51-ccm") &&
149255130Srpaulo	    !ofw_bus_is_compatible(dev, "fsl,imx53-ccm"))
150248557Sray		return (ENXIO);
151248557Sray
152248557Sray	device_set_desc(dev, "Freescale Clock Control Module");
153248557Sray	return (BUS_PROBE_DEFAULT);
154248557Sray}
155248557Sray
156248557Sraystatic int
157248557Srayimxccm_attach(device_t dev)
158248557Sray{
159248557Sray	struct imxccm_softc *sc;
160248557Sray
161248557Sray	sc = device_get_softc(dev);
162248557Sray	sc->sc_dev = dev;
163248557Sray
164248557Sray	if (bus_alloc_resources(dev, imxccm_spec, sc->res)) {
165248557Sray		device_printf(dev, "could not allocate resources\n");
166248557Sray		return (ENXIO);
167248557Sray	}
168248557Sray
169248557Sray	ccm_softc = sc;
170248557Sray
171248557Sray	imx51_get_pll_freq(1);
172248557Sray	imx51_get_pll_freq(2);
173248557Sray	imx51_get_pll_freq(3);
174248557Sray
175248557Sray	device_printf(dev, "PLL1=%lluMHz, PLL2=%lluMHz, PLL3=%lluMHz\n",
176248557Sray	    sc->pll_freq[0] / 1000000,
177248557Sray	    sc->pll_freq[1] / 1000000,
178248557Sray	    sc->pll_freq[2] / 1000000);
179248557Sray	device_printf(dev, "CPU clock=%d, UART clock=%d\n",
180248557Sray	    imx51_get_clock(IMX51CLK_ARM_ROOT),
181248557Sray	    imx51_get_clock(IMX51CLK_UART_CLK_ROOT));
182248557Sray	device_printf(dev,
183248557Sray	    "mainbus clock=%d, ahb clock=%d ipg clock=%d perclk=%d\n",
184248557Sray	    imx51_get_clock(IMX51CLK_MAIN_BUS_CLK),
185248557Sray	    imx51_get_clock(IMX51CLK_AHB_CLK_ROOT),
186248557Sray	    imx51_get_clock(IMX51CLK_IPG_CLK_ROOT),
187248557Sray	    imx51_get_clock(IMX51CLK_PERCLK_ROOT));
188248557Sray
189248557Sray
190248557Sray	return (0);
191248557Sray}
192248557Sray
193248557Srayu_int
194248557Srayimx51_get_clock(enum imx51_clock clk)
195248557Sray{
196248557Sray	u_int freq;
197248557Sray	u_int sel;
198248557Sray	uint32_t cacrr;	/* ARM clock root register */
199248557Sray	uint32_t ccsr;
200248557Sray	uint32_t cscdr1;
201248557Sray	uint32_t cscmr1;
202248557Sray	uint32_t cbcdr;
203248557Sray	uint32_t cbcmr;
204248557Sray	uint32_t cdcr;
205248557Sray
206248557Sray	if (ccm_softc == NULL)
207248557Sray		return (0);
208248557Sray
209248557Sray	switch (clk) {
210248557Sray	case IMX51CLK_PLL1:
211248557Sray	case IMX51CLK_PLL2:
212248557Sray	case IMX51CLK_PLL3:
213248557Sray		return ccm_softc->pll_freq[clk-IMX51CLK_PLL1];
214248557Sray	case IMX51CLK_PLL1SW:
215248557Sray		ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR);
216248557Sray		if ((ccsr & CCSR_PLL1_SW_CLK_SEL) == 0)
217248557Sray			return ccm_softc->pll_freq[1-1];
218248557Sray		/* step clock */
219248557Sray		/* FALLTHROUGH */
220248557Sray	case IMX51CLK_PLL1STEP:
221248557Sray		ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR);
222248557Sray		switch ((ccsr & CCSR_STEP_SEL_MASK) >> CCSR_STEP_SEL_SHIFT) {
223248557Sray		case 0:
224248557Sray			return imx51_get_clock(IMX51CLK_LP_APM);
225248557Sray		case 1:
226248557Sray			return 0; /* XXX PLL bypass clock */
227248557Sray		case 2:
228248557Sray			return ccm_softc->pll_freq[2-1] /
229248557Sray			    (1 + ((ccsr & CCSR_PLL2_DIV_PODF_MASK) >>
230248557Sray				CCSR_PLL2_DIV_PODF_SHIFT));
231248557Sray		case 3:
232248557Sray			return ccm_softc->pll_freq[3-1] /
233248557Sray			    (1 + ((ccsr & CCSR_PLL3_DIV_PODF_MASK) >>
234248557Sray				CCSR_PLL3_DIV_PODF_SHIFT));
235248557Sray		}
236248557Sray		/*NOTREACHED*/
237248557Sray	case IMX51CLK_PLL2SW:
238248557Sray		ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR);
239248557Sray		if ((ccsr & CCSR_PLL2_SW_CLK_SEL) == 0)
240248557Sray			return imx51_get_clock(IMX51CLK_PLL2);
241248557Sray		return 0; /* XXX PLL2 bypass clk */
242248557Sray	case IMX51CLK_PLL3SW:
243248557Sray		ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR);
244248557Sray		if ((ccsr & CCSR_PLL3_SW_CLK_SEL) == 0)
245248557Sray			return imx51_get_clock(IMX51CLK_PLL3);
246248557Sray		return 0; /* XXX PLL3 bypass clk */
247248557Sray
248248557Sray	case IMX51CLK_LP_APM:
249248557Sray		ccsr = bus_read_4(ccm_softc->res[0], CCMC_CCSR);
250248557Sray		return (ccsr & CCSR_LP_APM) ?
251248557Sray			    imx51_get_clock(IMX51CLK_FPM) : IMX51_OSC_FREQ;
252248557Sray
253248557Sray	case IMX51CLK_ARM_ROOT:
254248557Sray		freq = imx51_get_clock(IMX51CLK_PLL1SW);
255248557Sray		cacrr = bus_read_4(ccm_softc->res[0], CCMC_CACRR);
256248557Sray		return freq / (cacrr + 1);
257248557Sray
258248557Sray		/* ... */
259248557Sray	case IMX51CLK_MAIN_BUS_CLK_SRC:
260248557Sray		cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR);
261248557Sray		if ((cbcdr & CBCDR_PERIPH_CLK_SEL) == 0)
262248557Sray			freq = imx51_get_clock(IMX51CLK_PLL2SW);
263248557Sray		else {
264248557Sray			freq = 0;
265248557Sray			cbcmr = bus_read_4(ccm_softc->res[0],  CCMC_CBCMR);
266248557Sray			switch ((cbcmr & CBCMR_PERIPH_APM_SEL_MASK) >>
267248557Sray				CBCMR_PERIPH_APM_SEL_SHIFT) {
268248557Sray			case 0:
269248557Sray				freq = imx51_get_clock(IMX51CLK_PLL1SW);
270248557Sray				break;
271248557Sray			case 1:
272248557Sray				freq = imx51_get_clock(IMX51CLK_PLL3SW);
273248557Sray				break;
274248557Sray			case 2:
275248557Sray				freq = imx51_get_clock(IMX51CLK_LP_APM);
276248557Sray				break;
277248557Sray			case 3:
278248557Sray				/* XXX: error */
279248557Sray				break;
280248557Sray			}
281248557Sray		}
282248557Sray		return freq;
283248557Sray	case IMX51CLK_MAIN_BUS_CLK:
284248557Sray		freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
285248557Sray		cdcr = bus_read_4(ccm_softc->res[0], CCMC_CDCR);
286256774Sian		return freq / (1 + ((cdcr & CDCR_PERIPH_CLK_DVFS_PODF_MASK) >>
287256774Sian			CDCR_PERIPH_CLK_DVFS_PODF_SHIFT));
288248557Sray	case IMX51CLK_AHB_CLK_ROOT:
289248557Sray		freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK);
290248557Sray		cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR);
291248557Sray		return freq / (1 + ((cbcdr & CBCDR_AHB_PODF_MASK) >>
292248557Sray				    CBCDR_AHB_PODF_SHIFT));
293248557Sray	case IMX51CLK_IPG_CLK_ROOT:
294248557Sray		freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
295248557Sray		cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR);
296248557Sray		return freq / (1 + ((cbcdr & CBCDR_IPG_PODF_MASK) >>
297248557Sray				    CBCDR_IPG_PODF_SHIFT));
298248557Sray
299248557Sray	case IMX51CLK_PERCLK_ROOT:
300248557Sray		cbcmr = bus_read_4(ccm_softc->res[0], CCMC_CBCMR);
301248557Sray		if (cbcmr & CBCMR_PERCLK_IPG_SEL)
302248557Sray			return imx51_get_clock(IMX51CLK_IPG_CLK_ROOT);
303248557Sray		if (cbcmr & CBCMR_PERCLK_LP_APM_SEL)
304248557Sray			freq = imx51_get_clock(IMX51CLK_LP_APM);
305248557Sray		else
306248557Sray			freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
307248557Sray		cbcdr = bus_read_4(ccm_softc->res[0], CCMC_CBCDR);
308248557Sray
309248557Sray#ifdef IMXCCMDEBUG
310248557Sray		printf("cbcmr=%x cbcdr=%x\n", cbcmr, cbcdr);
311248557Sray#endif
312248557Sray
313248557Sray		freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED1_MASK) >>
314248557Sray			CBCDR_PERCLK_PRED1_SHIFT);
315248557Sray		freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED2_MASK) >>
316248557Sray			CBCDR_PERCLK_PRED2_SHIFT);
317248557Sray		freq /= 1 + ((cbcdr & CBCDR_PERCLK_PODF_MASK) >>
318248557Sray			CBCDR_PERCLK_PODF_SHIFT);
319248557Sray		return freq;
320248557Sray	case IMX51CLK_UART_CLK_ROOT:
321248557Sray		cscdr1 = bus_read_4(ccm_softc->res[0], CCMC_CSCDR1);
322248557Sray		cscmr1 = bus_read_4(ccm_softc->res[0], CCMC_CSCMR1);
323248557Sray
324248557Sray#ifdef IMXCCMDEBUG
325248557Sray		printf("cscdr1=%x cscmr1=%x\n", cscdr1, cscmr1);
326248557Sray#endif
327248557Sray
328248557Sray		sel = (cscmr1 & CSCMR1_UART_CLK_SEL_MASK) >>
329248557Sray		    CSCMR1_UART_CLK_SEL_SHIFT;
330248557Sray
331248557Sray		freq = 0; /* shut up GCC */
332248557Sray		switch (sel) {
333248557Sray		case 0:
334248557Sray		case 1:
335248557Sray		case 2:
336248557Sray			freq = imx51_get_clock(IMX51CLK_PLL1SW + sel);
337248557Sray			break;
338248557Sray		case 3:
339248557Sray			freq = imx51_get_clock(IMX51CLK_LP_APM);
340248557Sray			break;
341248557Sray		}
342248557Sray
343248557Sray		return freq / (1 + ((cscdr1 & CSCDR1_UART_CLK_PRED_MASK) >>
344248557Sray			CSCDR1_UART_CLK_PRED_SHIFT)) /
345248557Sray		    (1 + ((cscdr1 & CSCDR1_UART_CLK_PODF_MASK) >>
346248557Sray			CSCDR1_UART_CLK_PODF_SHIFT));
347248557Sray	case IMX51CLK_IPU_HSP_CLK_ROOT:
348248557Sray		freq = 0;
349248557Sray		cbcmr = bus_read_4(ccm_softc->res[0],  CCMC_CBCMR);
350248557Sray		switch ((cbcmr & CBCMR_IPU_HSP_CLK_SEL_MASK) >>
351248557Sray				CBCMR_IPU_HSP_CLK_SEL_SHIFT) {
352248557Sray			case 0:
353248557Sray				freq = imx51_get_clock(IMX51CLK_ARM_AXI_A_CLK);
354248557Sray				break;
355248557Sray			case 1:
356248557Sray				freq = imx51_get_clock(IMX51CLK_ARM_AXI_B_CLK);
357248557Sray				break;
358248557Sray			case 2:
359248557Sray				freq = imx51_get_clock(
360248557Sray					IMX51CLK_EMI_SLOW_CLK_ROOT);
361248557Sray				break;
362248557Sray			case 3:
363248557Sray				freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
364248557Sray				break;
365248557Sray			}
366248557Sray		return freq;
367248557Sray	default:
368248557Sray		device_printf(ccm_softc->sc_dev,
369248557Sray		    "clock %d: not supported yet\n", clk);
370248557Sray		return 0;
371248557Sray	}
372248557Sray}
373248557Sray
374248557Sray
375248557Sraystatic uint64_t
376248557Srayimx51_get_pll_freq(u_int pll_no)
377248557Sray{
378248557Sray	uint32_t dp_ctrl;
379248557Sray	uint32_t dp_op;
380248557Sray	uint32_t dp_mfd;
381248557Sray	uint32_t dp_mfn;
382248557Sray	uint32_t mfi;
383248557Sray	int32_t mfn;
384248557Sray	uint32_t mfd;
385248557Sray	uint32_t pdf;
386248557Sray	uint32_t ccr;
387248557Sray	uint64_t freq = 0;
388248557Sray	u_int ref = 0;
389248557Sray
390248557Sray	KASSERT(1 <= pll_no && pll_no <= IMX51_N_DPLLS, ("Wrong PLL id"));
391248557Sray
392248557Sray	dp_ctrl = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_CTL);
393248557Sray
394248557Sray	if (dp_ctrl & DP_CTL_HFSM) {
395248557Sray		dp_op = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_HFS_OP);
396248557Sray		dp_mfd = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_HFS_MFD);
397248557Sray		dp_mfn = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_HFS_MFN);
398248557Sray	} else {
399248557Sray		dp_op = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_OP);
400248557Sray		dp_mfd = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_MFD);
401248557Sray		dp_mfn = bus_read_4(ccm_softc->res[pll_no], DPLL_DP_MFN);
402248557Sray	}
403248557Sray
404248557Sray	pdf = dp_op & DP_OP_PDF_MASK;
405248557Sray	mfi = max(5, (dp_op & DP_OP_MFI_MASK) >> DP_OP_MFI_SHIFT);
406248557Sray	mfd = dp_mfd;
407248557Sray	if (dp_mfn & 0x04000000)
408248557Sray		/* 27bit signed value */
409248557Sray		mfn = (uint32_t)(0xf8000000 | dp_mfn);
410248557Sray	else
411248557Sray		mfn = dp_mfn;
412248557Sray
413248557Sray	switch (dp_ctrl &  DP_CTL_REF_CLK_SEL_MASK) {
414248557Sray	case DP_CTL_REF_CLK_SEL_COSC:
415248557Sray		/* Internal Oscillator */
416248557Sray		/* TODO: get from FDT "fsl,imx-osc" */
417248557Sray		ref = 24000000; /* IMX51_OSC_FREQ */
418248557Sray		break;
419248557Sray	case DP_CTL_REF_CLK_SEL_FPM:
420248557Sray		ccr = bus_read_4(ccm_softc->res[0], CCMC_CCR);
421248557Sray		if (ccr & CCR_FPM_MULT)
422248557Sray		/* TODO: get from FDT "fsl,imx-ckil" */
423248557Sray			ref = 32768 * 1024;
424248557Sray		else
425248557Sray		/* TODO: get from FDT "fsl,imx-ckil" */
426248557Sray			ref = 32768 * 512;
427248557Sray		break;
428248557Sray	default:
429248557Sray		ref = 0;
430248557Sray	}
431248557Sray
432248557Sray	if (dp_ctrl & DP_CTL_REF_CLK_DIV)
433248557Sray		ref /= 2;
434248557Sray
435248557Sray	ref *= 4;
436248557Sray	freq = (int64_t)ref * mfi + (int64_t)ref * mfn / (mfd + 1);
437248557Sray	freq /= pdf + 1;
438248557Sray
439248557Sray	if (!(dp_ctrl & DP_CTL_DPDCK0_2_EN))
440248557Sray		freq /= 2;
441248557Sray
442248557Sray#ifdef IMXCCMDEBUG
443248557Sray	printf("ref: %dKHz ", ref);
444248557Sray	printf("dp_ctl: %08x ", dp_ctrl);
445248557Sray	printf("pdf: %3d ", pdf);
446248557Sray	printf("mfi: %3d ", mfi);
447248557Sray	printf("mfd: %3d ", mfd);
448248557Sray	printf("mfn: %3d ", mfn);
449248557Sray	printf("pll: %d\n", (uint32_t)freq);
450248557Sray#endif
451248557Sray
452248557Sray	ccm_softc->pll_freq[pll_no-1] = freq;
453248557Sray
454248557Sray	return (freq);
455248557Sray}
456248557Sray
457248557Srayvoid
458248557Srayimx51_clk_gating(int clk_src, int mode)
459248557Sray{
460248557Sray	int field, group;
461248557Sray	uint32_t reg;
462248557Sray
463248557Sray	group = CCMR_CCGR_MODULE(clk_src);
464248557Sray	field = clk_src % CCMR_CCGR_NSOURCE;
465248557Sray	reg = bus_read_4(ccm_softc->res[0], CCMC_CCGR(group));
466248557Sray	reg &= ~(0x03 << field * 2);
467248557Sray	reg |= (mode << field * 2);
468248557Sray	bus_write_4(ccm_softc->res[0], CCMC_CCGR(group), reg);
469248557Sray}
470248557Sray
471248557Srayint
472248557Srayimx51_get_clk_gating(int clk_src)
473248557Sray{
474248557Sray	uint32_t reg;
475248557Sray
476248557Sray	reg = bus_read_4(ccm_softc->res[0],
477248557Sray	    CCMC_CCGR(CCMR_CCGR_MODULE(clk_src)));
478248557Sray	return ((reg >> (clk_src % CCMR_CCGR_NSOURCE) * 2) & 0x03);
479248557Sray}
480248557Sray
481257383Sian/*
482257383Sian * Code from here down is temporary, in lieu of a SoC-independent clock API.
483257383Sian */
484257383Sian
485257383Sianvoid
486257383Sianimx_ccm_usb_enable(device_t dev)
487257383Sian{
488257383Sian	uint32_t regval;
489257383Sian
490257383Sian	/*
491257383Sian	 * Select PLL2 as the source for the USB clock.
492257383Sian	 * The default is PLL3, but U-boot changes it to PLL2.
493257383Sian	 */
494257383Sian	regval = bus_read_4(ccm_softc->res[0], CCMC_CSCMR1);
495257383Sian	regval &= ~CSCMR1_USBOH3_CLK_SEL_MASK;
496257383Sian	regval |= 1 << CSCMR1_USBOH3_CLK_SEL_SHIFT;
497257383Sian	bus_write_4(ccm_softc->res[0], CCMC_CSCMR1, regval);
498257383Sian
499257383Sian	/*
500257383Sian	 * Set the USB clock pre-divider to div-by-5, post-divider to div-by-2.
501257383Sian	 */
502257383Sian	regval = bus_read_4(ccm_softc->res[0], CCMC_CSCDR1);
503257383Sian	regval &= ~CSCDR1_USBOH3_CLK_PODF_MASK;
504257383Sian	regval &= ~CSCDR1_USBOH3_CLK_PRED_MASK;
505257383Sian	regval |= 4 << CSCDR1_USBOH3_CLK_PRED_SHIFT;
506257383Sian	regval |= 1 << CSCDR1_USBOH3_CLK_PODF_SHIFT;
507257383Sian	bus_write_4(ccm_softc->res[0], CCMC_CSCDR1, regval);
508257383Sian
509257383Sian	/*
510257383Sian	 * The same two clocks gates are used on imx51 and imx53.
511257383Sian	 */
512257383Sian	imx51_clk_gating(CCGR_USBOH3_IPG_AHB_CLK, CCGR_CLK_MODE_ALWAYS);
513257383Sian	imx51_clk_gating(CCGR_USBOH3_60M_CLK, CCGR_CLK_MODE_ALWAYS);
514257383Sian}
515257383Sian
516257383Sianvoid
517257383Sianimx_ccm_usbphy_enable(device_t dev)
518257383Sian{
519257383Sian	uint32_t regval;
520257383Sian
521257383Sian	/*
522257383Sian	 * Select PLL3 as the source for the USBPHY clock.  U-boot does this
523257383Sian	 * only for imx53, but the bit exists on imx51.  That seems a bit
524257383Sian	 * strange, but we'll go with it until more is known.
525257383Sian	 */
526257383Sian	if (imx_soc_type() == IMXSOC_53) {
527257383Sian		regval = bus_read_4(ccm_softc->res[0], CCMC_CSCMR1);
528257383Sian		regval |= 1 << CSCMR1_USBPHY_CLK_SEL_SHIFT;
529257383Sian		bus_write_4(ccm_softc->res[0], CCMC_CSCMR1, regval);
530257383Sian	}
531257383Sian
532257383Sian	/*
533257383Sian	 * For the imx51 there's just one phy gate control, enable it.
534257383Sian	 */
535257383Sian	if (imx_soc_type() == IMXSOC_51) {
536257383Sian		imx51_clk_gating(CCGR_USB_PHY_CLK, CCGR_CLK_MODE_ALWAYS);
537257383Sian		return;
538257383Sian	}
539257383Sian
540257383Sian	/*
541257383Sian	 * For imx53 we don't have a full set of clock defines yet, but the
542257383Sian	 * datasheet says:
543257383Sian	 *   gate reg 4, bits 13-12 usb ph2 clock (usb_phy2_clk_enable)
544257383Sian	 *   gate reg 4, bits 11-10 usb ph1 clock (usb_phy1_clk_enable)
545257383Sian	 *
546257383Sian	 * We should use the fdt data for the device to figure out which of
547257383Sian	 * the two we're working on, but for now just turn them both on.
548257383Sian	 */
549257383Sian	if (imx_soc_type() == IMXSOC_53) {
550257383Sian		imx51_clk_gating(__CCGR_NUM(4, 5), CCGR_CLK_MODE_ALWAYS);
551257383Sian		imx51_clk_gating(__CCGR_NUM(4, 6), CCGR_CLK_MODE_ALWAYS);
552257383Sian		return;
553257383Sian	}
554257383Sian}
555257383Sian
556264977Sianuint32_t
557264977Sianimx_ccm_ipg_hz(void)
558264977Sian{
559264977Sian
560264977Sian	return (imx51_get_clock(IMX51CLK_IPG_CLK_ROOT));
561264977Sian}
562264977Sian
563264977Sianuint32_t
564264977Sianimx_ccm_sdhci_hz(void)
565264977Sian{
566264977Sian
567264977Sian	return (imx51_get_clock(IMX51CLK_ESDHC1_CLK_ROOT));
568264977Sian}
569264977Sian
570264977Sianuint32_t
571264977Sianimx_ccm_perclk_hz(void)
572264977Sian{
573264977Sian
574264977Sian	return (imx51_get_clock(IMX51CLK_PERCLK_ROOT));
575264977Sian}
576264977Sian
577264977Sianuint32_t
578264977Sianimx_ccm_uart_hz(void)
579264977Sian{
580264977Sian
581264977Sian	return (imx51_get_clock(IMX51CLK_UART_CLK_ROOT));
582264977Sian}
583271055Sian
584271055Sianuint32_t
585271055Sianimx_ccm_ahb_hz(void)
586271055Sian{
587271055Sian
588271055Sian	return (imx51_get_clock(IMX51CLK_AHB_CLK_ROOT));
589271055Sian}
590