am335x_prcm.c revision 253830
1/*-
2 * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
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#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/arm/ti/am335x/am335x_prcm.c 253830 2013-07-31 05:52:03Z rpaulo $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/bus.h>
33#include <sys/kernel.h>
34#include <sys/module.h>
35#include <sys/malloc.h>
36#include <sys/rman.h>
37#include <sys/timeet.h>
38#include <sys/timetc.h>
39#include <sys/watchdog.h>
40#include <machine/bus.h>
41#include <machine/cpu.h>
42#include <machine/frame.h>
43#include <machine/intr.h>
44
45#include <arm/ti/tivar.h>
46#include <arm/ti/ti_scm.h>
47#include <arm/ti/ti_prcm.h>
48
49#include <dev/fdt/fdt_common.h>
50#include <dev/ofw/openfirm.h>
51#include <dev/ofw/ofw_bus.h>
52#include <dev/ofw/ofw_bus_subr.h>
53
54#include <machine/bus.h>
55#include <machine/fdt.h>
56
57#define CM_PER				0
58#define CM_PER_L4LS_CLKSTCTRL		(CM_PER + 0x000)
59#define CM_PER_L3S_CLKSTCTRL		(CM_PER + 0x004)
60#define CM_PER_L3_CLKSTCTRL		(CM_PER + 0x00C)
61#define CM_PER_CPGMAC0_CLKCTRL		(CM_PER + 0x014)
62#define CM_PER_LCDC_CLKCTRL		(CM_PER + 0x018)
63#define CM_PER_USB0_CLKCTRL		(CM_PER + 0x01C)
64#define CM_PER_TPTC0_CLKCTRL		(CM_PER + 0x024)
65#define CM_PER_MMC0_CLKCTRL		(CM_PER + 0x03C)
66#define CM_PER_I2C2_CLKCTRL		(CM_PER + 0x044)
67#define CM_PER_I2C1_CLKCTRL		(CM_PER + 0x048)
68#define CM_PER_TIMER7_CLKCTRL		(CM_PER + 0x07C)
69#define CM_PER_TIMER2_CLKCTRL		(CM_PER + 0x080)
70#define CM_PER_TIMER3_CLKCTRL		(CM_PER + 0x084)
71#define CM_PER_TIMER4_CLKCTRL		(CM_PER + 0x088)
72#define CM_PER_GPIO1_CLKCTRL		(CM_PER + 0x0AC)
73#define CM_PER_GPIO2_CLKCTRL		(CM_PER + 0x0B0)
74#define CM_PER_GPIO3_CLKCTRL		(CM_PER + 0x0B4)
75#define CM_PER_TPCC_CLKCTRL		(CM_PER + 0x0BC)
76#define CM_PER_EPWMSS1_CLKCTRL		(CM_PER + 0x0CC)
77#define CM_PER_EPWMSS0_CLKCTRL		(CM_PER + 0x0D4)
78#define CM_PER_EPWMSS2_CLKCTRL		(CM_PER + 0x0D8)
79#define CM_PER_L3_INSTR_CLKCTRL		(CM_PER + 0x0DC)
80#define CM_PER_L3_CLKCTRL		(CM_PER + 0x0E0)
81#define	CM_PER_PRUSS_CLKCTRL		(CM_PER + 0x0E8)
82#define CM_PER_TIMER5_CLKCTRL		(CM_PER + 0x0EC)
83#define CM_PER_TIMER6_CLKCTRL		(CM_PER + 0x0F0)
84#define CM_PER_MMC1_CLKCTRL		(CM_PER + 0x0F4)
85#define CM_PER_MMC2_CLKCTRL		(CM_PER + 0x0F8)
86#define CM_PER_TPTC1_CLKCTRL		(CM_PER + 0x0FC)
87#define CM_PER_TPTC2_CLKCTRL		(CM_PER + 0x100)
88#define	CM_PER_SPINLOCK0_CLKCTRL	(CM_PER + 0x10C)
89#define	CM_PER_MAILBOX0_CLKCTRL		(CM_PER + 0x110)
90#define CM_PER_OCPWP_L3_CLKSTCTRL	(CM_PER + 0x12C)
91#define CM_PER_OCPWP_CLKCTRL		(CM_PER + 0x130)
92#define CM_PER_CPSW_CLKSTCTRL		(CM_PER + 0x144)
93#define	CM_PER_PRUSS_CLKSTCTRL		(CM_PER + 0x140)
94
95#define CM_WKUP				0x400
96#define CM_WKUP_CLKSTCTRL		(CM_WKUP + 0x000)
97#define CM_WKUP_CONTROL_CLKCTRL		(CM_WKUP + 0x004)
98#define CM_WKUP_GPIO0_CLKCTRL		(CM_WKUP + 0x008)
99#define CM_WKUP_CM_L3_AON_CLKSTCTRL	(CM_WKUP + 0x01C)
100#define CM_WKUP_CM_CLKSEL_DPLL_MPU	(CM_WKUP + 0x02C)
101#define CM_WKUP_CM_IDLEST_DPLL_DISP	(CM_WKUP + 0x048)
102#define CM_WKUP_CM_CLKSEL_DPLL_DISP	(CM_WKUP + 0x054)
103#define CM_WKUP_CM_CLKDCOLDO_DPLL_PER	(CM_WKUP + 0x07C)
104#define CM_WKUP_CM_CLKMODE_DPLL_DISP	(CM_WKUP + 0x098)
105#define CM_WKUP_I2C0_CLKCTRL		(CM_WKUP + 0x0B8)
106
107#define CM_DPLL				0x500
108#define CLKSEL_TIMER7_CLK		(CM_DPLL + 0x004)
109#define CLKSEL_TIMER2_CLK		(CM_DPLL + 0x008)
110#define CLKSEL_TIMER3_CLK		(CM_DPLL + 0x00C)
111#define CLKSEL_TIMER4_CLK		(CM_DPLL + 0x010)
112#define CLKSEL_TIMER5_CLK		(CM_DPLL + 0x018)
113#define CLKSEL_TIMER6_CLK		(CM_DPLL + 0x01C)
114#define	CLKSEL_PRUSS_OCP_CLK		(CM_DPLL + 0x030)
115
116#define	PRM_PER				0xC00
117#define	PRM_PER_RSTCTRL			(PRM_PER + 0x00)
118
119#define PRM_DEVICE_OFFSET		0xF00
120#define PRM_RSTCTRL			(PRM_DEVICE_OFFSET + 0x00)
121
122struct am335x_prcm_softc {
123	struct resource *	res[2];
124	bus_space_tag_t		bst;
125	bus_space_handle_t	bsh;
126};
127
128static struct resource_spec am335x_prcm_spec[] = {
129	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
130	{ -1, 0 }
131};
132
133static struct am335x_prcm_softc *am335x_prcm_sc = NULL;
134
135static int am335x_clk_generic_activate(struct ti_clock_dev *clkdev);
136static int am335x_clk_gpio_activate(struct ti_clock_dev *clkdev);
137static int am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev);
138static int am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
139static int am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev,  unsigned int *freq);
140static int am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
141static int am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
142static int am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
143static void am335x_prcm_reset(void);
144static int am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev);
145static int am335x_clk_musb0_activate(struct ti_clock_dev *clkdev);
146static int am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev);
147static int am335x_clk_pruss_activate(struct ti_clock_dev *clkdev);
148
149#define AM335X_GENERIC_CLOCK_DEV(i) \
150	{	.id = (i), \
151		.clk_activate = am335x_clk_generic_activate, \
152		.clk_deactivate = am335x_clk_generic_deactivate, \
153		.clk_set_source = am335x_clk_generic_set_source, \
154		.clk_accessible = NULL, \
155		.clk_get_source_freq = NULL \
156	}
157
158#define AM335X_GPIO_CLOCK_DEV(i) \
159	{	.id = (i), \
160		.clk_activate = am335x_clk_gpio_activate, \
161		.clk_deactivate = am335x_clk_generic_deactivate, \
162		.clk_set_source = am335x_clk_generic_set_source, \
163		.clk_accessible = NULL, \
164		.clk_get_source_freq = NULL \
165	}
166
167#define AM335X_MMCHS_CLOCK_DEV(i) \
168	{	.id = (i), \
169		.clk_activate = am335x_clk_generic_activate, \
170		.clk_deactivate = am335x_clk_generic_deactivate, \
171		.clk_set_source = am335x_clk_generic_set_source, \
172		.clk_accessible = NULL, \
173		.clk_get_source_freq = am335x_clk_hsmmc_get_source_freq \
174	}
175
176struct ti_clock_dev ti_clk_devmap[] = {
177	/* System clocks */
178	{	.id                  = SYS_CLK,
179		.clk_activate        = NULL,
180		.clk_deactivate      = NULL,
181		.clk_set_source      = NULL,
182		.clk_accessible      = NULL,
183		.clk_get_source_freq = am335x_clk_get_sysclk_freq,
184	},
185	/* MPU (ARM) core clocks */
186	{	.id                  = MPU_CLK,
187		.clk_activate        = NULL,
188		.clk_deactivate      = NULL,
189		.clk_set_source      = NULL,
190		.clk_accessible      = NULL,
191		.clk_get_source_freq = am335x_clk_get_arm_fclk_freq,
192	},
193	/* CPSW Ethernet Switch core clocks */
194	{	.id                  = CPSW_CLK,
195		.clk_activate        = am335x_clk_cpsw_activate,
196		.clk_deactivate      = NULL,
197		.clk_set_source      = NULL,
198		.clk_accessible      = NULL,
199		.clk_get_source_freq = NULL,
200	},
201
202	/* Mentor USB HS controller core clocks */
203	{	.id                  = MUSB0_CLK,
204		.clk_activate        = am335x_clk_musb0_activate,
205		.clk_deactivate      = NULL,
206		.clk_set_source      = NULL,
207		.clk_accessible      = NULL,
208		.clk_get_source_freq = NULL,
209	},
210
211	/* LCD controller clocks */
212	{	.id                  = LCDC_CLK,
213		.clk_activate        = am335x_clk_lcdc_activate,
214		.clk_deactivate      = NULL,
215		.clk_set_source      = NULL,
216		.clk_accessible      = NULL,
217		.clk_get_source_freq = am335x_clk_get_arm_disp_freq,
218	},
219
220	/* DMTimer */
221	AM335X_GENERIC_CLOCK_DEV(DMTIMER2_CLK),
222	AM335X_GENERIC_CLOCK_DEV(DMTIMER3_CLK),
223	AM335X_GENERIC_CLOCK_DEV(DMTIMER4_CLK),
224	AM335X_GENERIC_CLOCK_DEV(DMTIMER5_CLK),
225	AM335X_GENERIC_CLOCK_DEV(DMTIMER6_CLK),
226	AM335X_GENERIC_CLOCK_DEV(DMTIMER7_CLK),
227
228	/* GPIO */
229	AM335X_GPIO_CLOCK_DEV(GPIO0_CLK),
230	AM335X_GPIO_CLOCK_DEV(GPIO1_CLK),
231	AM335X_GPIO_CLOCK_DEV(GPIO2_CLK),
232	AM335X_GPIO_CLOCK_DEV(GPIO3_CLK),
233
234	/* I2C */
235	AM335X_GENERIC_CLOCK_DEV(I2C0_CLK),
236	AM335X_GENERIC_CLOCK_DEV(I2C1_CLK),
237	AM335X_GENERIC_CLOCK_DEV(I2C2_CLK),
238
239	/* EDMA */
240	AM335X_GENERIC_CLOCK_DEV(EDMA_TPCC_CLK),
241	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC0_CLK),
242	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC1_CLK),
243	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC2_CLK),
244
245	/* MMCHS */
246	AM335X_MMCHS_CLOCK_DEV(MMC0_CLK),
247	AM335X_MMCHS_CLOCK_DEV(MMC1_CLK),
248	AM335X_MMCHS_CLOCK_DEV(MMC2_CLK),
249
250	/* PWMSS */
251	AM335X_GENERIC_CLOCK_DEV(PWMSS0_CLK),
252	AM335X_GENERIC_CLOCK_DEV(PWMSS1_CLK),
253	AM335X_GENERIC_CLOCK_DEV(PWMSS2_CLK),
254
255	/* System Mailbox clock */
256	AM335X_GENERIC_CLOCK_DEV(MAILBOX0_CLK),
257
258	/* SPINLOCK */
259	AM335X_GENERIC_CLOCK_DEV(SPINLOCK0_CLK),
260
261	/* PRU-ICSS */
262	{	.id		     = PRUSS_CLK,
263		.clk_activate	     = am335x_clk_pruss_activate,
264		.clk_deactivate      = NULL,
265		.clk_set_source      = NULL,
266		.clk_accessible      = NULL,
267		.clk_get_source_freq = NULL,
268	},
269
270
271
272	{  INVALID_CLK_IDENT, NULL, NULL, NULL, NULL }
273};
274
275struct am335x_clk_details {
276	clk_ident_t	id;
277	uint32_t	clkctrl_reg;
278	uint32_t	clksel_reg;
279};
280
281#define _CLK_DETAIL(i, c, s) \
282	{	.id = (i), \
283		.clkctrl_reg = (c), \
284		.clksel_reg = (s), \
285	}
286
287static struct am335x_clk_details g_am335x_clk_details[] = {
288
289	/* DMTimer modules */
290	_CLK_DETAIL(DMTIMER2_CLK, CM_PER_TIMER2_CLKCTRL, CLKSEL_TIMER2_CLK),
291	_CLK_DETAIL(DMTIMER3_CLK, CM_PER_TIMER3_CLKCTRL, CLKSEL_TIMER3_CLK),
292	_CLK_DETAIL(DMTIMER4_CLK, CM_PER_TIMER4_CLKCTRL, CLKSEL_TIMER4_CLK),
293	_CLK_DETAIL(DMTIMER5_CLK, CM_PER_TIMER5_CLKCTRL, CLKSEL_TIMER5_CLK),
294	_CLK_DETAIL(DMTIMER6_CLK, CM_PER_TIMER6_CLKCTRL, CLKSEL_TIMER6_CLK),
295	_CLK_DETAIL(DMTIMER7_CLK, CM_PER_TIMER7_CLKCTRL, CLKSEL_TIMER7_CLK),
296
297	/* GPIO modules */
298	_CLK_DETAIL(GPIO0_CLK, CM_WKUP_GPIO0_CLKCTRL, 0),
299	_CLK_DETAIL(GPIO1_CLK, CM_PER_GPIO1_CLKCTRL, 0),
300	_CLK_DETAIL(GPIO2_CLK, CM_PER_GPIO2_CLKCTRL, 0),
301	_CLK_DETAIL(GPIO3_CLK, CM_PER_GPIO3_CLKCTRL, 0),
302
303	/* I2C modules */
304	_CLK_DETAIL(I2C0_CLK, CM_WKUP_I2C0_CLKCTRL, 0),
305	_CLK_DETAIL(I2C1_CLK, CM_PER_I2C1_CLKCTRL, 0),
306	_CLK_DETAIL(I2C2_CLK, CM_PER_I2C2_CLKCTRL, 0),
307
308	/* EDMA modules */
309	_CLK_DETAIL(EDMA_TPCC_CLK, CM_PER_TPCC_CLKCTRL, 0),
310	_CLK_DETAIL(EDMA_TPTC0_CLK, CM_PER_TPTC0_CLKCTRL, 0),
311	_CLK_DETAIL(EDMA_TPTC1_CLK, CM_PER_TPTC1_CLKCTRL, 0),
312	_CLK_DETAIL(EDMA_TPTC2_CLK, CM_PER_TPTC2_CLKCTRL, 0),
313
314	/* MMCHS modules*/
315	_CLK_DETAIL(MMC0_CLK, CM_PER_MMC0_CLKCTRL, 0),
316	_CLK_DETAIL(MMC1_CLK, CM_PER_MMC1_CLKCTRL, 0),
317	_CLK_DETAIL(MMC2_CLK, CM_PER_MMC1_CLKCTRL, 0),
318
319	/* PWMSS modules */
320	_CLK_DETAIL(PWMSS0_CLK, CM_PER_EPWMSS0_CLKCTRL, 0),
321	_CLK_DETAIL(PWMSS1_CLK, CM_PER_EPWMSS1_CLKCTRL, 0),
322	_CLK_DETAIL(PWMSS2_CLK, CM_PER_EPWMSS2_CLKCTRL, 0),
323
324	_CLK_DETAIL(MAILBOX0_CLK, CM_PER_MAILBOX0_CLKCTRL, 0),
325	_CLK_DETAIL(SPINLOCK0_CLK, CM_PER_SPINLOCK0_CLKCTRL, 0),
326
327	{ INVALID_CLK_IDENT, 0},
328};
329
330/* Read/Write macros */
331#define prcm_read_4(reg)		\
332	bus_space_read_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg)
333#define prcm_write_4(reg, val)		\
334	bus_space_write_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg, val)
335
336void am335x_prcm_setup_dmtimer(int);
337
338static int
339am335x_prcm_probe(device_t dev)
340{
341	if (ofw_bus_is_compatible(dev, "am335x,prcm")) {
342		device_set_desc(dev, "AM335x Power and Clock Management");
343		return(BUS_PROBE_DEFAULT);
344	}
345
346	return (ENXIO);
347}
348
349static int
350am335x_prcm_attach(device_t dev)
351{
352	struct am335x_prcm_softc *sc = device_get_softc(dev);
353	unsigned int sysclk, fclk;
354
355	if (am335x_prcm_sc)
356		return (ENXIO);
357
358	if (bus_alloc_resources(dev, am335x_prcm_spec, sc->res)) {
359		device_printf(dev, "could not allocate resources\n");
360		return (ENXIO);
361	}
362
363	sc->bst = rman_get_bustag(sc->res[0]);
364	sc->bsh = rman_get_bushandle(sc->res[0]);
365
366	am335x_prcm_sc = sc;
367	ti_cpu_reset = am335x_prcm_reset;
368
369	am335x_clk_get_sysclk_freq(NULL, &sysclk);
370	am335x_clk_get_arm_fclk_freq(NULL, &fclk);
371	device_printf(dev, "Clocks: System %u.%01u MHz, CPU %u MHz\n",
372		sysclk/1000000, (sysclk % 1000000)/100000, fclk/1000000);
373
374	return (0);
375}
376
377static device_method_t am335x_prcm_methods[] = {
378	DEVMETHOD(device_probe,		am335x_prcm_probe),
379	DEVMETHOD(device_attach,	am335x_prcm_attach),
380	{ 0, 0 }
381};
382
383static driver_t am335x_prcm_driver = {
384	"am335x_prcm",
385	am335x_prcm_methods,
386	sizeof(struct am335x_prcm_softc),
387};
388
389static devclass_t am335x_prcm_devclass;
390
391DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver,
392	am335x_prcm_devclass, 0, 0);
393MODULE_DEPEND(am335x_prcm, ti_scm, 1, 1, 1);
394
395static struct am335x_clk_details*
396am335x_clk_details(clk_ident_t id)
397{
398	struct am335x_clk_details *walker;
399
400	for (walker = g_am335x_clk_details; walker->id != INVALID_CLK_IDENT; walker++) {
401		if (id == walker->id)
402			return (walker);
403	}
404
405	return NULL;
406}
407
408static int
409am335x_clk_generic_activate(struct ti_clock_dev *clkdev)
410{
411	struct am335x_prcm_softc *sc = am335x_prcm_sc;
412	struct am335x_clk_details* clk_details;
413
414	if (sc == NULL)
415		return ENXIO;
416
417	clk_details = am335x_clk_details(clkdev->id);
418
419	if (clk_details == NULL)
420		return (ENXIO);
421
422	/* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */
423	prcm_write_4(clk_details->clkctrl_reg, 2);
424	while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 2)
425		DELAY(10);
426
427	return (0);
428}
429
430static int
431am335x_clk_gpio_activate(struct ti_clock_dev *clkdev)
432{
433	struct am335x_prcm_softc *sc = am335x_prcm_sc;
434	struct am335x_clk_details* clk_details;
435
436	if (sc == NULL)
437		return ENXIO;
438
439	clk_details = am335x_clk_details(clkdev->id);
440
441	if (clk_details == NULL)
442		return (ENXIO);
443
444	/* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */
445	/* set *_CLKCTRL register OPTFCLKEN_GPIO_1_G DBCLK[18] to FCLK_EN(1) */
446	prcm_write_4(clk_details->clkctrl_reg, 2 | (1 << 18));
447	while ((prcm_read_4(clk_details->clkctrl_reg) &
448	    (3 | (1 << 18) )) != (2 | (1 << 18)))
449		DELAY(10);
450
451	return (0);
452}
453
454static int
455am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev)
456{
457	struct am335x_prcm_softc *sc = am335x_prcm_sc;
458	struct am335x_clk_details* clk_details;
459
460	if (sc == NULL)
461		return ENXIO;
462
463	clk_details = am335x_clk_details(clkdev->id);
464
465	if (clk_details == NULL)
466		return (ENXIO);
467
468	/* set *_CLKCTRL register MODULEMODE[1:0] to disable(0) */
469	prcm_write_4(clk_details->clkctrl_reg, 0);
470	while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 0)
471		DELAY(10);
472
473	return (0);
474}
475
476static int
477am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc)
478{
479	struct am335x_prcm_softc *sc = am335x_prcm_sc;
480	struct am335x_clk_details* clk_details;
481	uint32_t reg;
482
483	if (sc == NULL)
484		return ENXIO;
485
486	clk_details = am335x_clk_details(clkdev->id);
487
488	if (clk_details == NULL)
489		return (ENXIO);
490
491	switch (clksrc) {
492		case EXT_CLK:
493			reg = 0; /* SEL2: TCLKIN clock */
494			break;
495		case SYSCLK_CLK:
496			reg = 1; /* SEL1: CLK_M_OSC clock */
497			break;
498		case F32KHZ_CLK:
499			reg = 2; /* SEL3: CLK_32KHZ clock */
500			break;
501		default:
502			return (ENXIO);
503	}
504
505	prcm_write_4(clk_details->clksel_reg, reg);
506	while ((prcm_read_4(clk_details->clksel_reg) & 0x3) != reg)
507		DELAY(10);
508
509	return (0);
510}
511
512static int
513am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev,  unsigned int *freq)
514{
515	*freq = 96000000;
516	return (0);
517}
518
519static int
520am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
521{
522	uint32_t ctrl_status;
523
524	/* Read the input clock freq from the control module */
525	/* control_status reg (0x40) */
526	if (ti_scm_reg_read_4(0x40, &ctrl_status))
527		return ENXIO;
528
529	switch ((ctrl_status>>22) & 0x3) {
530	case 0x0:
531		/* 19.2Mhz */
532		*freq = 19200000;
533		break;
534	case 0x1:
535		/* 24Mhz */
536		*freq = 24000000;
537		break;
538	case 0x2:
539		/* 25Mhz */
540		*freq = 25000000;
541		break;
542	case 0x3:
543		/* 26Mhz */
544		*freq = 26000000;
545		break;
546	}
547
548	return (0);
549}
550
551#define DPLL_BYP_CLKSEL(reg)	((reg>>23) & 1)
552#define DPLL_DIV(reg)		((reg & 0x7f)+1)
553#define DPLL_MULT(reg)		((reg>>8) & 0x7FF)
554
555static int
556am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
557{
558	uint32_t reg;
559	uint32_t sysclk;
560
561	reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_MPU);
562
563	/*Check if we are running in bypass */
564	if (DPLL_BYP_CLKSEL(reg))
565		return ENXIO;
566
567	am335x_clk_get_sysclk_freq(NULL, &sysclk);
568	*freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg));
569	return(0);
570}
571
572static int
573am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
574{
575	uint32_t reg;
576	uint32_t sysclk;
577
578	reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_DISP);
579
580	/*Check if we are running in bypass */
581	if (DPLL_BYP_CLKSEL(reg))
582		return ENXIO;
583
584	am335x_clk_get_sysclk_freq(NULL, &sysclk);
585	*freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg));
586	return(0);
587}
588
589static void
590am335x_prcm_reset(void)
591{
592	prcm_write_4(PRM_RSTCTRL, (1<<1));
593}
594
595static int
596am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev)
597{
598	struct am335x_prcm_softc *sc = am335x_prcm_sc;
599
600	if (sc == NULL)
601		return ENXIO;
602
603	/* set MODULENAME to ENABLE */
604	prcm_write_4(CM_PER_CPGMAC0_CLKCTRL, 2);
605
606	/* wait for IDLEST to become Func(0) */
607	while(prcm_read_4(CM_PER_CPGMAC0_CLKCTRL) & (3<<16));
608
609	/*set CLKTRCTRL to SW_WKUP(2) */
610	prcm_write_4(CM_PER_CPSW_CLKSTCTRL, 2);
611
612	/* wait for 125 MHz OCP clock to become active */
613	while((prcm_read_4(CM_PER_CPSW_CLKSTCTRL) & (1<<4)) == 0);
614	return(0);
615}
616
617static int
618am335x_clk_musb0_activate(struct ti_clock_dev *clkdev)
619{
620	struct am335x_prcm_softc *sc = am335x_prcm_sc;
621
622	if (sc == NULL)
623		return ENXIO;
624
625	/* set ST_DPLL_CLKDCOLDO(9) to CLK_GATED(1) */
626	/* set DPLL_CLKDCOLDO_GATE_CTRL(8) to CLK_ENABLE(1)*/
627        prcm_write_4(CM_WKUP_CM_CLKDCOLDO_DPLL_PER, 0x300);
628
629	/*set MODULEMODE to ENABLE(2) */
630	prcm_write_4(CM_PER_USB0_CLKCTRL, 2);
631
632	/* wait for MODULEMODE to become ENABLE(2) */
633	while ((prcm_read_4(CM_PER_USB0_CLKCTRL) & 0x3) != 2)
634		DELAY(10);
635
636	/* wait for IDLEST to become Func(0) */
637	while(prcm_read_4(CM_PER_USB0_CLKCTRL) & (3<<16))
638		DELAY(10);
639
640	return(0);
641}
642
643static int
644am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev)
645{
646	struct am335x_prcm_softc *sc = am335x_prcm_sc;
647
648	if (sc == NULL)
649		return (ENXIO);
650
651	/* Bypass mode */
652	prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x4);
653
654	/* Make sure it's in bypass mode */
655	while (!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP)
656	    & (1 << 8)))
657		DELAY(10);
658
659	/*
660	 * For now set frequency to  5xSYSFREQ
661	 * More flexible control might be required
662	 */
663	prcm_write_4(CM_WKUP_CM_CLKSEL_DPLL_DISP, (5 << 8) | 0);
664
665	/* Locked mode */
666	prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x7);
667
668	int timeout = 10000;
669	while ((!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP)
670	    & (1 << 0))) && timeout--)
671		DELAY(10);
672
673	/*set MODULEMODE to ENABLE(2) */
674	prcm_write_4(CM_PER_LCDC_CLKCTRL, 2);
675
676	/* wait for MODULEMODE to become ENABLE(2) */
677	while ((prcm_read_4(CM_PER_LCDC_CLKCTRL) & 0x3) != 2)
678		DELAY(10);
679
680	/* wait for IDLEST to become Func(0) */
681	while(prcm_read_4(CM_PER_LCDC_CLKCTRL) & (3<<16))
682		DELAY(10);
683
684	return (0);
685}
686
687static int
688am335x_clk_pruss_activate(struct ti_clock_dev *clkdev)
689{
690	struct am335x_prcm_softc *sc = am335x_prcm_sc;
691
692	if (sc == NULL)
693		return (ENXIO);
694
695	/* Set MODULEMODE to ENABLE(2) */
696	prcm_write_4(CM_PER_PRUSS_CLKCTRL, 2);
697
698	/* Wait for MODULEMODE to become ENABLE(2) */
699	while ((prcm_read_4(CM_PER_PRUSS_CLKCTRL) & 0x3) != 2)
700		DELAY(10);
701
702	/* Set CLKTRCTRL to SW_WKUP(2) */
703	prcm_write_4(CM_PER_PRUSS_CLKSTCTRL, 2);
704
705	/* Wait for the 200 MHz OCP clock to become active */
706	while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<4)) == 0)
707		DELAY(10);
708
709	/* Wait for the 200 MHz IEP clock to become active */
710	while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<5)) == 0)
711		DELAY(10);
712
713	/* Wait for the 192 MHz UART clock to become active */
714	while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<6)) == 0)
715		DELAY(10);
716
717	/* Select DISP DPLL as OCP clock */
718	prcm_write_4(CLKSEL_PRUSS_OCP_CLK, 1);
719	while ((prcm_read_4(CLKSEL_PRUSS_OCP_CLK) & 0x3) != 1)
720		DELAY(10);
721
722	/* Clear the RESET bit */
723	prcm_write_4(PRM_PER_RSTCTRL, prcm_read_4(PRM_PER_RSTCTRL) & ~2);
724
725	return (0);
726}
727