1248557Sray/*	$NetBSD: imx51_ccm.c,v 1.1 2012/04/17 09:33:31 bsh Exp $	*/
2331722Seadler/*
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: stable/11/sys/arm/freescale/imx/imx51_ccm.c 331722 2018-03-29 02:50:57Z eadler $");
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>
81323400Sian#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
100323400Sian/*
101323400Sian * The fdt data does not provide reg properties describing the DPLL register
102323400Sian * blocks we need to access, presumably because the needed addresses are
103323400Sian * hard-coded within the linux driver.  That leaves us with no choice but to do
104323400Sian * the same thing, if we want to run with vendor-supplied fdt data.  So here we
105323400Sian * have tables of the physical addresses we need for each soc, and we'll use
106323400Sian * bus_space_map() at attach() time to get access to them.
107323400Sian */
108323400Sianstatic uint32_t imx51_dpll_addrs[IMX51_N_DPLLS] = {
109323400Sian	0x83f80000,	/* DPLL1 */
110323400Sian	0x83f84000,	/* DPLL2 */
111323400Sian	0x83f88000,	/* DPLL3 */
112323400Sian};
113323400Sian
114323400Sianstatic uint32_t imx53_dpll_addrs[IMX51_N_DPLLS] = {
115323400Sian	0x63f80000,     /* DPLL1 */
116323400Sian	0x63f84000,     /* DPLL2 */
117323400Sian	0x63f88000,     /* DPLL3 */
118323400Sian};
119323400Sian
120323400Sian#define	DPLL_REGS_SZ	(16 * 1024)
121323400Sian
122248557Sraystruct imxccm_softc {
123248557Sray	device_t	sc_dev;
124323400Sian	struct resource *ccmregs;
125248557Sray	u_int64_t 	pll_freq[IMX51_N_DPLLS];
126323400Sian	bus_space_tag_t    pllbst;
127323400Sian	bus_space_handle_t pllbsh[IMX51_N_DPLLS];
128248557Sray};
129248557Sray
130248557Sraystruct imxccm_softc *ccm_softc = NULL;
131248557Sray
132248557Sraystatic uint64_t imx51_get_pll_freq(u_int);
133248557Sray
134248557Sraystatic int imxccm_match(device_t);
135248557Sraystatic int imxccm_attach(device_t);
136248557Sray
137248557Sraystatic device_method_t imxccm_methods[] = {
138248557Sray	DEVMETHOD(device_probe, imxccm_match),
139248557Sray	DEVMETHOD(device_attach, imxccm_attach),
140248557Sray
141248557Sray	DEVMETHOD_END
142248557Sray};
143248557Sray
144248557Sraystatic driver_t imxccm_driver = {
145248557Sray	"imxccm",
146248557Sray	imxccm_methods,
147248557Sray	sizeof(struct imxccm_softc),
148248557Sray};
149248557Sray
150248557Sraystatic devclass_t imxccm_devclass;
151248557Sray
152248557SrayEARLY_DRIVER_MODULE(imxccm, simplebus, imxccm_driver, imxccm_devclass, 0, 0,
153248557Sray    BUS_PASS_CPU);
154248557Sray
155323400Sianstatic inline uint32_t
156323400Sianpll_read_4(struct imxccm_softc *sc, int pll, int reg)
157323400Sian{
158248557Sray
159323400Sian	return (bus_space_read_4(sc->pllbst, sc->pllbsh[pll - 1], reg));
160323400Sian}
161323400Sian
162323400Sianstatic inline uint32_t
163323400Sianccm_read_4(struct imxccm_softc *sc, int reg)
164323400Sian{
165323400Sian
166323400Sian	return (bus_read_4(sc->ccmregs, reg));
167323400Sian}
168323400Sian
169323400Sianstatic inline void
170323400Sianccm_write_4(struct imxccm_softc *sc, int reg, uint32_t val)
171323400Sian{
172323400Sian
173323400Sian	bus_write_4(sc->ccmregs, reg, val);
174323400Sian}
175323400Sian
176248557Sraystatic int
177248557Srayimxccm_match(device_t dev)
178248557Sray{
179248557Sray
180261410Sian	if (!ofw_bus_status_okay(dev))
181261410Sian		return (ENXIO);
182261410Sian
183255130Srpaulo	if (!ofw_bus_is_compatible(dev, "fsl,imx51-ccm") &&
184255130Srpaulo	    !ofw_bus_is_compatible(dev, "fsl,imx53-ccm"))
185248557Sray		return (ENXIO);
186248557Sray
187248557Sray	device_set_desc(dev, "Freescale Clock Control Module");
188248557Sray	return (BUS_PROBE_DEFAULT);
189248557Sray}
190248557Sray
191248557Sraystatic int
192248557Srayimxccm_attach(device_t dev)
193248557Sray{
194248557Sray	struct imxccm_softc *sc;
195323400Sian	int idx;
196323400Sian	u_int soc;
197323400Sian	uint32_t *pll_addrs;
198248557Sray
199248557Sray	sc = device_get_softc(dev);
200248557Sray	sc->sc_dev = dev;
201248557Sray
202323400Sian	switch ((soc = imx_soc_type())) {
203323400Sian	case IMXSOC_51:
204323400Sian		pll_addrs = imx51_dpll_addrs;
205323400Sian		break;
206323400Sian	case IMXSOC_53:
207323400Sian		pll_addrs = imx53_dpll_addrs;
208323400Sian		break;
209323400Sian	default:
210323400Sian		device_printf(dev, "No support for SoC type 0x%08x\n", soc);
211323400Sian		goto noclocks;
212323400Sian	}
213323400Sian
214323400Sian	idx = 0;
215323400Sian	sc->ccmregs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &idx,
216323400Sian	    RF_ACTIVE);
217323400Sian	if (sc->ccmregs == NULL) {
218248557Sray		device_printf(dev, "could not allocate resources\n");
219323400Sian		goto noclocks;
220248557Sray	}
221248557Sray
222323400Sian	sc->pllbst = fdtbus_bs_tag;
223323400Sian	for (idx = 0; idx < IMX51_N_DPLLS; ++idx) {
224323400Sian		if (bus_space_map(sc->pllbst, pll_addrs[idx], DPLL_REGS_SZ, 0,
225323400Sian		    &sc->pllbsh[idx]) != 0) {
226323400Sian			device_printf(dev, "Cannot map DPLL registers\n");
227323400Sian			goto noclocks;
228323400Sian		}
229323400Sian	}
230323400Sian
231248557Sray	ccm_softc = sc;
232248557Sray
233248557Sray	imx51_get_pll_freq(1);
234248557Sray	imx51_get_pll_freq(2);
235248557Sray	imx51_get_pll_freq(3);
236248557Sray
237248557Sray	device_printf(dev, "PLL1=%lluMHz, PLL2=%lluMHz, PLL3=%lluMHz\n",
238248557Sray	    sc->pll_freq[0] / 1000000,
239248557Sray	    sc->pll_freq[1] / 1000000,
240248557Sray	    sc->pll_freq[2] / 1000000);
241248557Sray	device_printf(dev, "CPU clock=%d, UART clock=%d\n",
242248557Sray	    imx51_get_clock(IMX51CLK_ARM_ROOT),
243248557Sray	    imx51_get_clock(IMX51CLK_UART_CLK_ROOT));
244248557Sray	device_printf(dev,
245248557Sray	    "mainbus clock=%d, ahb clock=%d ipg clock=%d perclk=%d\n",
246248557Sray	    imx51_get_clock(IMX51CLK_MAIN_BUS_CLK),
247248557Sray	    imx51_get_clock(IMX51CLK_AHB_CLK_ROOT),
248248557Sray	    imx51_get_clock(IMX51CLK_IPG_CLK_ROOT),
249248557Sray	    imx51_get_clock(IMX51CLK_PERCLK_ROOT));
250248557Sray
251248557Sray
252248557Sray	return (0);
253323400Sian
254323400Siannoclocks:
255323400Sian
256323400Sian	panic("Cannot continue without clock support");
257248557Sray}
258248557Sray
259248557Srayu_int
260248557Srayimx51_get_clock(enum imx51_clock clk)
261248557Sray{
262248557Sray	u_int freq;
263248557Sray	u_int sel;
264248557Sray	uint32_t cacrr;	/* ARM clock root register */
265248557Sray	uint32_t ccsr;
266248557Sray	uint32_t cscdr1;
267248557Sray	uint32_t cscmr1;
268248557Sray	uint32_t cbcdr;
269248557Sray	uint32_t cbcmr;
270248557Sray	uint32_t cdcr;
271248557Sray
272248557Sray	if (ccm_softc == NULL)
273248557Sray		return (0);
274248557Sray
275248557Sray	switch (clk) {
276248557Sray	case IMX51CLK_PLL1:
277248557Sray	case IMX51CLK_PLL2:
278248557Sray	case IMX51CLK_PLL3:
279248557Sray		return ccm_softc->pll_freq[clk-IMX51CLK_PLL1];
280248557Sray	case IMX51CLK_PLL1SW:
281323400Sian		ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
282248557Sray		if ((ccsr & CCSR_PLL1_SW_CLK_SEL) == 0)
283248557Sray			return ccm_softc->pll_freq[1-1];
284248557Sray		/* step clock */
285248557Sray		/* FALLTHROUGH */
286248557Sray	case IMX51CLK_PLL1STEP:
287323400Sian		ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
288248557Sray		switch ((ccsr & CCSR_STEP_SEL_MASK) >> CCSR_STEP_SEL_SHIFT) {
289248557Sray		case 0:
290248557Sray			return imx51_get_clock(IMX51CLK_LP_APM);
291248557Sray		case 1:
292248557Sray			return 0; /* XXX PLL bypass clock */
293248557Sray		case 2:
294248557Sray			return ccm_softc->pll_freq[2-1] /
295248557Sray			    (1 + ((ccsr & CCSR_PLL2_DIV_PODF_MASK) >>
296248557Sray				CCSR_PLL2_DIV_PODF_SHIFT));
297248557Sray		case 3:
298248557Sray			return ccm_softc->pll_freq[3-1] /
299248557Sray			    (1 + ((ccsr & CCSR_PLL3_DIV_PODF_MASK) >>
300248557Sray				CCSR_PLL3_DIV_PODF_SHIFT));
301248557Sray		}
302248557Sray		/*NOTREACHED*/
303248557Sray	case IMX51CLK_PLL2SW:
304323400Sian		ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
305248557Sray		if ((ccsr & CCSR_PLL2_SW_CLK_SEL) == 0)
306248557Sray			return imx51_get_clock(IMX51CLK_PLL2);
307248557Sray		return 0; /* XXX PLL2 bypass clk */
308248557Sray	case IMX51CLK_PLL3SW:
309323400Sian		ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
310248557Sray		if ((ccsr & CCSR_PLL3_SW_CLK_SEL) == 0)
311248557Sray			return imx51_get_clock(IMX51CLK_PLL3);
312248557Sray		return 0; /* XXX PLL3 bypass clk */
313248557Sray
314248557Sray	case IMX51CLK_LP_APM:
315323400Sian		ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
316248557Sray		return (ccsr & CCSR_LP_APM) ?
317248557Sray			    imx51_get_clock(IMX51CLK_FPM) : IMX51_OSC_FREQ;
318248557Sray
319248557Sray	case IMX51CLK_ARM_ROOT:
320248557Sray		freq = imx51_get_clock(IMX51CLK_PLL1SW);
321323400Sian		cacrr = ccm_read_4(ccm_softc, CCMC_CACRR);
322248557Sray		return freq / (cacrr + 1);
323248557Sray
324248557Sray		/* ... */
325248557Sray	case IMX51CLK_MAIN_BUS_CLK_SRC:
326323400Sian		cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
327248557Sray		if ((cbcdr & CBCDR_PERIPH_CLK_SEL) == 0)
328248557Sray			freq = imx51_get_clock(IMX51CLK_PLL2SW);
329248557Sray		else {
330248557Sray			freq = 0;
331323400Sian			cbcmr = ccm_read_4(ccm_softc,  CCMC_CBCMR);
332248557Sray			switch ((cbcmr & CBCMR_PERIPH_APM_SEL_MASK) >>
333248557Sray				CBCMR_PERIPH_APM_SEL_SHIFT) {
334248557Sray			case 0:
335248557Sray				freq = imx51_get_clock(IMX51CLK_PLL1SW);
336248557Sray				break;
337248557Sray			case 1:
338248557Sray				freq = imx51_get_clock(IMX51CLK_PLL3SW);
339248557Sray				break;
340248557Sray			case 2:
341248557Sray				freq = imx51_get_clock(IMX51CLK_LP_APM);
342248557Sray				break;
343248557Sray			case 3:
344248557Sray				/* XXX: error */
345248557Sray				break;
346248557Sray			}
347248557Sray		}
348248557Sray		return freq;
349248557Sray	case IMX51CLK_MAIN_BUS_CLK:
350248557Sray		freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
351323400Sian		cdcr = ccm_read_4(ccm_softc, CCMC_CDCR);
352256774Sian		return freq / (1 + ((cdcr & CDCR_PERIPH_CLK_DVFS_PODF_MASK) >>
353256774Sian			CDCR_PERIPH_CLK_DVFS_PODF_SHIFT));
354248557Sray	case IMX51CLK_AHB_CLK_ROOT:
355248557Sray		freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK);
356323400Sian		cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
357248557Sray		return freq / (1 + ((cbcdr & CBCDR_AHB_PODF_MASK) >>
358248557Sray				    CBCDR_AHB_PODF_SHIFT));
359248557Sray	case IMX51CLK_IPG_CLK_ROOT:
360248557Sray		freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
361323400Sian		cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
362248557Sray		return freq / (1 + ((cbcdr & CBCDR_IPG_PODF_MASK) >>
363248557Sray				    CBCDR_IPG_PODF_SHIFT));
364248557Sray
365248557Sray	case IMX51CLK_PERCLK_ROOT:
366323400Sian		cbcmr = ccm_read_4(ccm_softc, CCMC_CBCMR);
367248557Sray		if (cbcmr & CBCMR_PERCLK_IPG_SEL)
368248557Sray			return imx51_get_clock(IMX51CLK_IPG_CLK_ROOT);
369248557Sray		if (cbcmr & CBCMR_PERCLK_LP_APM_SEL)
370248557Sray			freq = imx51_get_clock(IMX51CLK_LP_APM);
371248557Sray		else
372248557Sray			freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
373323400Sian		cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
374248557Sray
375248557Sray#ifdef IMXCCMDEBUG
376248557Sray		printf("cbcmr=%x cbcdr=%x\n", cbcmr, cbcdr);
377248557Sray#endif
378248557Sray
379248557Sray		freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED1_MASK) >>
380248557Sray			CBCDR_PERCLK_PRED1_SHIFT);
381248557Sray		freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED2_MASK) >>
382248557Sray			CBCDR_PERCLK_PRED2_SHIFT);
383248557Sray		freq /= 1 + ((cbcdr & CBCDR_PERCLK_PODF_MASK) >>
384248557Sray			CBCDR_PERCLK_PODF_SHIFT);
385248557Sray		return freq;
386248557Sray	case IMX51CLK_UART_CLK_ROOT:
387323400Sian		cscdr1 = ccm_read_4(ccm_softc, CCMC_CSCDR1);
388323400Sian		cscmr1 = ccm_read_4(ccm_softc, CCMC_CSCMR1);
389248557Sray
390248557Sray#ifdef IMXCCMDEBUG
391248557Sray		printf("cscdr1=%x cscmr1=%x\n", cscdr1, cscmr1);
392248557Sray#endif
393248557Sray
394248557Sray		sel = (cscmr1 & CSCMR1_UART_CLK_SEL_MASK) >>
395248557Sray		    CSCMR1_UART_CLK_SEL_SHIFT;
396248557Sray
397248557Sray		freq = 0; /* shut up GCC */
398248557Sray		switch (sel) {
399248557Sray		case 0:
400248557Sray		case 1:
401248557Sray		case 2:
402248557Sray			freq = imx51_get_clock(IMX51CLK_PLL1SW + sel);
403248557Sray			break;
404248557Sray		case 3:
405248557Sray			freq = imx51_get_clock(IMX51CLK_LP_APM);
406248557Sray			break;
407248557Sray		}
408248557Sray
409248557Sray		return freq / (1 + ((cscdr1 & CSCDR1_UART_CLK_PRED_MASK) >>
410248557Sray			CSCDR1_UART_CLK_PRED_SHIFT)) /
411248557Sray		    (1 + ((cscdr1 & CSCDR1_UART_CLK_PODF_MASK) >>
412248557Sray			CSCDR1_UART_CLK_PODF_SHIFT));
413248557Sray	case IMX51CLK_IPU_HSP_CLK_ROOT:
414248557Sray		freq = 0;
415323400Sian		cbcmr = ccm_read_4(ccm_softc,  CCMC_CBCMR);
416248557Sray		switch ((cbcmr & CBCMR_IPU_HSP_CLK_SEL_MASK) >>
417248557Sray				CBCMR_IPU_HSP_CLK_SEL_SHIFT) {
418248557Sray			case 0:
419248557Sray				freq = imx51_get_clock(IMX51CLK_ARM_AXI_A_CLK);
420248557Sray				break;
421248557Sray			case 1:
422248557Sray				freq = imx51_get_clock(IMX51CLK_ARM_AXI_B_CLK);
423248557Sray				break;
424248557Sray			case 2:
425248557Sray				freq = imx51_get_clock(
426248557Sray					IMX51CLK_EMI_SLOW_CLK_ROOT);
427248557Sray				break;
428248557Sray			case 3:
429248557Sray				freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
430248557Sray				break;
431248557Sray			}
432248557Sray		return freq;
433248557Sray	default:
434248557Sray		device_printf(ccm_softc->sc_dev,
435248557Sray		    "clock %d: not supported yet\n", clk);
436248557Sray		return 0;
437248557Sray	}
438248557Sray}
439248557Sray
440248557Sray
441248557Sraystatic uint64_t
442248557Srayimx51_get_pll_freq(u_int pll_no)
443248557Sray{
444248557Sray	uint32_t dp_ctrl;
445248557Sray	uint32_t dp_op;
446248557Sray	uint32_t dp_mfd;
447248557Sray	uint32_t dp_mfn;
448248557Sray	uint32_t mfi;
449248557Sray	int32_t mfn;
450248557Sray	uint32_t mfd;
451248557Sray	uint32_t pdf;
452248557Sray	uint32_t ccr;
453248557Sray	uint64_t freq = 0;
454248557Sray	u_int ref = 0;
455248557Sray
456248557Sray	KASSERT(1 <= pll_no && pll_no <= IMX51_N_DPLLS, ("Wrong PLL id"));
457248557Sray
458323400Sian	dp_ctrl = pll_read_4(ccm_softc, pll_no, DPLL_DP_CTL);
459248557Sray
460248557Sray	if (dp_ctrl & DP_CTL_HFSM) {
461323400Sian		dp_op  = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_OP);
462323400Sian		dp_mfd = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_MFD);
463323400Sian		dp_mfn = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_MFN);
464248557Sray	} else {
465323400Sian		dp_op  = pll_read_4(ccm_softc, pll_no, DPLL_DP_OP);
466323400Sian		dp_mfd = pll_read_4(ccm_softc, pll_no, DPLL_DP_MFD);
467323400Sian		dp_mfn = pll_read_4(ccm_softc, pll_no, DPLL_DP_MFN);
468248557Sray	}
469248557Sray
470248557Sray	pdf = dp_op & DP_OP_PDF_MASK;
471248557Sray	mfi = max(5, (dp_op & DP_OP_MFI_MASK) >> DP_OP_MFI_SHIFT);
472248557Sray	mfd = dp_mfd;
473248557Sray	if (dp_mfn & 0x04000000)
474248557Sray		/* 27bit signed value */
475248557Sray		mfn = (uint32_t)(0xf8000000 | dp_mfn);
476248557Sray	else
477248557Sray		mfn = dp_mfn;
478248557Sray
479248557Sray	switch (dp_ctrl &  DP_CTL_REF_CLK_SEL_MASK) {
480248557Sray	case DP_CTL_REF_CLK_SEL_COSC:
481248557Sray		/* Internal Oscillator */
482248557Sray		/* TODO: get from FDT "fsl,imx-osc" */
483248557Sray		ref = 24000000; /* IMX51_OSC_FREQ */
484248557Sray		break;
485248557Sray	case DP_CTL_REF_CLK_SEL_FPM:
486323400Sian		ccr = ccm_read_4(ccm_softc, CCMC_CCR);
487248557Sray		if (ccr & CCR_FPM_MULT)
488248557Sray		/* TODO: get from FDT "fsl,imx-ckil" */
489248557Sray			ref = 32768 * 1024;
490248557Sray		else
491248557Sray		/* TODO: get from FDT "fsl,imx-ckil" */
492248557Sray			ref = 32768 * 512;
493248557Sray		break;
494248557Sray	default:
495248557Sray		ref = 0;
496248557Sray	}
497248557Sray
498248557Sray	if (dp_ctrl & DP_CTL_REF_CLK_DIV)
499248557Sray		ref /= 2;
500248557Sray
501248557Sray	ref *= 4;
502248557Sray	freq = (int64_t)ref * mfi + (int64_t)ref * mfn / (mfd + 1);
503248557Sray	freq /= pdf + 1;
504248557Sray
505248557Sray	if (!(dp_ctrl & DP_CTL_DPDCK0_2_EN))
506248557Sray		freq /= 2;
507248557Sray
508248557Sray#ifdef IMXCCMDEBUG
509248557Sray	printf("ref: %dKHz ", ref);
510248557Sray	printf("dp_ctl: %08x ", dp_ctrl);
511248557Sray	printf("pdf: %3d ", pdf);
512248557Sray	printf("mfi: %3d ", mfi);
513248557Sray	printf("mfd: %3d ", mfd);
514248557Sray	printf("mfn: %3d ", mfn);
515248557Sray	printf("pll: %d\n", (uint32_t)freq);
516248557Sray#endif
517248557Sray
518248557Sray	ccm_softc->pll_freq[pll_no-1] = freq;
519248557Sray
520248557Sray	return (freq);
521248557Sray}
522248557Sray
523248557Srayvoid
524248557Srayimx51_clk_gating(int clk_src, int mode)
525248557Sray{
526248557Sray	int field, group;
527248557Sray	uint32_t reg;
528248557Sray
529248557Sray	group = CCMR_CCGR_MODULE(clk_src);
530248557Sray	field = clk_src % CCMR_CCGR_NSOURCE;
531323400Sian	reg = ccm_read_4(ccm_softc, CCMC_CCGR(group));
532248557Sray	reg &= ~(0x03 << field * 2);
533248557Sray	reg |= (mode << field * 2);
534323400Sian	ccm_write_4(ccm_softc, CCMC_CCGR(group), reg);
535248557Sray}
536248557Sray
537248557Srayint
538248557Srayimx51_get_clk_gating(int clk_src)
539248557Sray{
540248557Sray	uint32_t reg;
541248557Sray
542323400Sian	reg = ccm_read_4(ccm_softc,
543248557Sray	    CCMC_CCGR(CCMR_CCGR_MODULE(clk_src)));
544248557Sray	return ((reg >> (clk_src % CCMR_CCGR_NSOURCE) * 2) & 0x03);
545248557Sray}
546248557Sray
547257383Sian/*
548257383Sian * Code from here down is temporary, in lieu of a SoC-independent clock API.
549257383Sian */
550257383Sian
551257383Sianvoid
552257383Sianimx_ccm_usb_enable(device_t dev)
553257383Sian{
554257383Sian	uint32_t regval;
555257383Sian
556257383Sian	/*
557257383Sian	 * Select PLL2 as the source for the USB clock.
558257383Sian	 * The default is PLL3, but U-boot changes it to PLL2.
559257383Sian	 */
560323400Sian	regval = ccm_read_4(ccm_softc, CCMC_CSCMR1);
561257383Sian	regval &= ~CSCMR1_USBOH3_CLK_SEL_MASK;
562257383Sian	regval |= 1 << CSCMR1_USBOH3_CLK_SEL_SHIFT;
563323400Sian	ccm_write_4(ccm_softc, CCMC_CSCMR1, regval);
564257383Sian
565257383Sian	/*
566257383Sian	 * Set the USB clock pre-divider to div-by-5, post-divider to div-by-2.
567257383Sian	 */
568323400Sian	regval = ccm_read_4(ccm_softc, CCMC_CSCDR1);
569257383Sian	regval &= ~CSCDR1_USBOH3_CLK_PODF_MASK;
570257383Sian	regval &= ~CSCDR1_USBOH3_CLK_PRED_MASK;
571257383Sian	regval |= 4 << CSCDR1_USBOH3_CLK_PRED_SHIFT;
572257383Sian	regval |= 1 << CSCDR1_USBOH3_CLK_PODF_SHIFT;
573323400Sian	ccm_write_4(ccm_softc, CCMC_CSCDR1, regval);
574257383Sian
575257383Sian	/*
576257383Sian	 * The same two clocks gates are used on imx51 and imx53.
577257383Sian	 */
578257383Sian	imx51_clk_gating(CCGR_USBOH3_IPG_AHB_CLK, CCGR_CLK_MODE_ALWAYS);
579257383Sian	imx51_clk_gating(CCGR_USBOH3_60M_CLK, CCGR_CLK_MODE_ALWAYS);
580257383Sian}
581257383Sian
582257383Sianvoid
583257383Sianimx_ccm_usbphy_enable(device_t dev)
584257383Sian{
585257383Sian	uint32_t regval;
586257383Sian
587257383Sian	/*
588257383Sian	 * Select PLL3 as the source for the USBPHY clock.  U-boot does this
589257383Sian	 * only for imx53, but the bit exists on imx51.  That seems a bit
590257383Sian	 * strange, but we'll go with it until more is known.
591257383Sian	 */
592257383Sian	if (imx_soc_type() == IMXSOC_53) {
593323400Sian		regval = ccm_read_4(ccm_softc, CCMC_CSCMR1);
594257383Sian		regval |= 1 << CSCMR1_USBPHY_CLK_SEL_SHIFT;
595323400Sian		ccm_write_4(ccm_softc, CCMC_CSCMR1, regval);
596257383Sian	}
597257383Sian
598257383Sian	/*
599257383Sian	 * For the imx51 there's just one phy gate control, enable it.
600257383Sian	 */
601257383Sian	if (imx_soc_type() == IMXSOC_51) {
602257383Sian		imx51_clk_gating(CCGR_USB_PHY_CLK, CCGR_CLK_MODE_ALWAYS);
603257383Sian		return;
604257383Sian	}
605257383Sian
606257383Sian	/*
607257383Sian	 * For imx53 we don't have a full set of clock defines yet, but the
608257383Sian	 * datasheet says:
609257383Sian	 *   gate reg 4, bits 13-12 usb ph2 clock (usb_phy2_clk_enable)
610257383Sian	 *   gate reg 4, bits 11-10 usb ph1 clock (usb_phy1_clk_enable)
611257383Sian	 *
612257383Sian	 * We should use the fdt data for the device to figure out which of
613257383Sian	 * the two we're working on, but for now just turn them both on.
614257383Sian	 */
615257383Sian	if (imx_soc_type() == IMXSOC_53) {
616257383Sian		imx51_clk_gating(__CCGR_NUM(4, 5), CCGR_CLK_MODE_ALWAYS);
617257383Sian		imx51_clk_gating(__CCGR_NUM(4, 6), CCGR_CLK_MODE_ALWAYS);
618257383Sian		return;
619257383Sian	}
620257383Sian}
621257383Sian
622264977Sianuint32_t
623331506Sianimx_ccm_ecspi_hz(void)
624331506Sian{
625331506Sian
626331506Sian	return (imx51_get_clock(IMX51CLK_CSPI_CLK_ROOT));
627331506Sian}
628331506Sian
629331506Sianuint32_t
630264977Sianimx_ccm_ipg_hz(void)
631264977Sian{
632264977Sian
633264977Sian	return (imx51_get_clock(IMX51CLK_IPG_CLK_ROOT));
634264977Sian}
635264977Sian
636264977Sianuint32_t
637264977Sianimx_ccm_sdhci_hz(void)
638264977Sian{
639264977Sian
640264977Sian	return (imx51_get_clock(IMX51CLK_ESDHC1_CLK_ROOT));
641264977Sian}
642264977Sian
643264977Sianuint32_t
644264977Sianimx_ccm_perclk_hz(void)
645264977Sian{
646264977Sian
647264977Sian	return (imx51_get_clock(IMX51CLK_PERCLK_ROOT));
648264977Sian}
649264977Sian
650264977Sianuint32_t
651264977Sianimx_ccm_uart_hz(void)
652264977Sian{
653264977Sian
654264977Sian	return (imx51_get_clock(IMX51CLK_UART_CLK_ROOT));
655264977Sian}
656271055Sian
657271055Sianuint32_t
658271055Sianimx_ccm_ahb_hz(void)
659271055Sian{
660271055Sian
661271055Sian	return (imx51_get_clock(IMX51CLK_AHB_CLK_ROOT));
662271055Sian}
663331506Sian
664