xref: /freebsd/sys/arm/freescale/vybrid/vf_ccm.c (revision de7b456e596ff18032d2cbfdf244c66f36770da4)
1 /*-
2  * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /*
28  * Vybrid Family Clock Controller Module (CCM)
29  * Chapter 10, Vybrid Reference Manual, Rev. 5, 07/2013
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/bus.h>
38 #include <sys/kernel.h>
39 #include <sys/module.h>
40 #include <sys/malloc.h>
41 #include <sys/rman.h>
42 #include <sys/timeet.h>
43 #include <sys/timetc.h>
44 #include <sys/watchdog.h>
45 
46 #include <dev/fdt/fdt_common.h>
47 #include <dev/ofw/openfirm.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
50 
51 #include <machine/bus.h>
52 #include <machine/fdt.h>
53 #include <machine/cpu.h>
54 #include <machine/intr.h>
55 
56 #include <arm/freescale/vybrid/vf_common.h>
57 
58 #define	CCM_CCR		0x00	/* Control Register */
59 #define	CCM_CSR		0x04	/* Status Register */
60 #define	CCM_CCSR	0x08	/* Clock Switcher Register */
61 #define	CCM_CACRR	0x0C	/* ARM Clock Root Register */
62 #define	CCM_CSCMR1	0x10	/* Serial Clock Multiplexer Register 1 */
63 #define	CCM_CSCDR1	0x14	/* Serial Clock Divider Register 1 */
64 #define	CCM_CSCDR2	0x18	/* Serial Clock Divider Register 2 */
65 #define	CCM_CSCDR3	0x1C	/* Serial Clock Divider Register 3 */
66 #define	CCM_CSCMR2	0x20	/* Serial Clock Multiplexer Register 2 */
67 #define	CCM_CTOR	0x28	/* Testing Observability Register */
68 #define	CCM_CLPCR	0x2C	/* Low Power Control Register */
69 #define	CCM_CISR	0x30	/* Interrupt Status Register */
70 #define	CCM_CIMR	0x34	/* Interrupt Mask Register */
71 #define	CCM_CCOSR	0x38	/* Clock Output Source Register */
72 #define	CCM_CGPR	0x3C	/* General Purpose Register */
73 
74 #define	CCM_CCGRN	12
75 #define	CCM_CCGR(n)	(0x40 + (n * 0x04))	/* Clock Gating Register */
76 #define	CCM_CMEOR(n)	(0x70 + (n * 0x70))	/* Module Enable Override Reg */
77 #define	CCM_CCPGR(n)	(0x90 + (n * 0x04))	/* Platform Clock Gating Reg */
78 
79 #define	CCM_CPPDSR	0x88	/* PLL PFD Disable Status Register */
80 #define	CCM_CCOWR	0x8C	/* CORE Wakeup Register */
81 
82 #define	PLL3_PFD4_EN	(1 << 31)
83 #define	PLL3_PFD3_EN	(1 << 30)
84 #define	PLL3_PFD2_EN	(1 << 29)
85 #define	PLL3_PFD1_EN	(1 << 28)
86 #define	PLL2_PFD4_EN	(1 << 15)
87 #define	PLL2_PFD3_EN	(1 << 14)
88 #define	PLL2_PFD2_EN	(1 << 13)
89 #define	PLL2_PFD1_EN	(1 << 12)
90 #define	PLL1_PFD4_EN	(1 << 11)
91 #define	PLL1_PFD3_EN	(1 << 10)
92 #define	PLL1_PFD2_EN	(1 << 9)
93 #define	PLL1_PFD1_EN	(1 << 8)
94 
95 /* CCM_CCR */
96 #define	FIRC_EN		(1 << 16)
97 #define	FXOSC_EN	(1 << 12)
98 #define	FXOSC_RDY	(1 << 5)
99 
100 /* CCM_CSCDR1 */
101 #define	ENET_TS_EN	(1 << 23)
102 #define	RMII_CLK_EN	(1 << 24)
103 
104 struct ccm_softc {
105 	struct resource		*res[1];
106 	bus_space_tag_t		bst;
107 	bus_space_handle_t	bsh;
108 	device_t		dev;
109 };
110 
111 static struct resource_spec ccm_spec[] = {
112 	{ SYS_RES_MEMORY,       0,      RF_ACTIVE },
113 	{ -1, 0 }
114 };
115 
116 static int
117 ccm_probe(device_t dev)
118 {
119 
120 	if (!ofw_bus_is_compatible(dev, "fsl,mvf600-ccm"))
121 		return (ENXIO);
122 
123 	device_set_desc(dev, "Vybrid Family CCM Unit");
124 	return (BUS_PROBE_DEFAULT);
125 }
126 
127 static int
128 ccm_attach(device_t dev)
129 {
130 	struct ccm_softc *sc;
131 	int reg;
132 	int i;
133 
134 	sc = device_get_softc(dev);
135 	sc->dev = dev;
136 
137 	if (bus_alloc_resources(dev, ccm_spec, sc->res)) {
138 		device_printf(dev, "could not allocate resources\n");
139 		return (ENXIO);
140 	}
141 
142 	/* Memory interface */
143 	sc->bst = rman_get_bustag(sc->res[0]);
144 	sc->bsh = rman_get_bushandle(sc->res[0]);
145 
146 	/* Enable oscillator */
147 	reg = READ4(sc, CCM_CCR);
148 	reg |= (FIRC_EN | FXOSC_EN);
149 	WRITE4(sc, CCM_CCR, reg);
150 
151 	/* Wait 10 times */
152 	for (i = 0; i < 10; i++) {
153 		if (READ4(sc, CCM_CSR) & FXOSC_RDY) {
154 			device_printf(sc->dev, "On board oscillator is ready.\n");
155 			break;
156 		}
157 
158 		cpufunc_nullop();
159 	}
160 
161 	/* Clock is on during all modes, except stop mode. */
162 	for (i = 0; i < CCM_CCGRN; i++) {
163 		WRITE4(sc, CCM_CCGR(i), 0xffffffff);
164 	}
165 
166 	/* Enable ENET clocks */
167 	reg = READ4(sc, CCM_CSCDR1);
168 	reg |= (ENET_TS_EN | RMII_CLK_EN);
169 	WRITE4(sc, CCM_CSCDR1, reg);
170 
171 	return (0);
172 }
173 
174 static device_method_t ccm_methods[] = {
175 	DEVMETHOD(device_probe,		ccm_probe),
176 	DEVMETHOD(device_attach,	ccm_attach),
177 	{ 0, 0 }
178 };
179 
180 static driver_t ccm_driver = {
181 	"ccm",
182 	ccm_methods,
183 	sizeof(struct ccm_softc),
184 };
185 
186 static devclass_t ccm_devclass;
187 
188 DRIVER_MODULE(ccm, simplebus, ccm_driver, ccm_devclass, 0, 0);
189