am335x_prcm.c revision 251015
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 251015 2013-05-27 00:06:24Z gonzo $");
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_TIMER5_CLKCTRL		(CM_PER + 0x0EC)
82#define CM_PER_TIMER6_CLKCTRL		(CM_PER + 0x0F0)
83#define CM_PER_MMC1_CLKCTRL		(CM_PER + 0x0F4)
84#define CM_PER_MMC2_CLKCTRL		(CM_PER + 0x0F8)
85#define CM_PER_TPTC1_CLKCTRL		(CM_PER + 0x0FC)
86#define CM_PER_TPTC2_CLKCTRL		(CM_PER + 0x100)
87#define CM_PER_OCPWP_L3_CLKSTCTRL	(CM_PER + 0x12C)
88#define CM_PER_OCPWP_CLKCTRL		(CM_PER + 0x130)
89#define CM_PER_CPSW_CLKSTCTRL		(CM_PER + 0x144)
90
91#define CM_WKUP				0x400
92#define CM_WKUP_CLKSTCTRL		(CM_WKUP + 0x000)
93#define CM_WKUP_CONTROL_CLKCTRL		(CM_WKUP + 0x004)
94#define CM_WKUP_GPIO0_CLKCTRL		(CM_WKUP + 0x008)
95#define CM_WKUP_CM_L3_AON_CLKSTCTRL	(CM_WKUP + 0x01C)
96#define CM_WKUP_CM_CLKSEL_DPLL_MPU	(CM_WKUP + 0x02C)
97#define CM_WKUP_CM_IDLEST_DPLL_DISP	(CM_WKUP + 0x048)
98#define CM_WKUP_CM_CLKSEL_DPLL_DISP	(CM_WKUP + 0x054)
99#define CM_WKUP_CM_CLKDCOLDO_DPLL_PER	(CM_WKUP + 0x07C)
100#define CM_WKUP_CM_CLKMODE_DPLL_DISP	(CM_WKUP + 0x098)
101#define CM_WKUP_I2C0_CLKCTRL		(CM_WKUP + 0x0B8)
102
103#define CM_DPLL				0x500
104#define CLKSEL_TIMER7_CLK		(CM_DPLL + 0x004)
105#define CLKSEL_TIMER2_CLK		(CM_DPLL + 0x008)
106#define CLKSEL_TIMER3_CLK		(CM_DPLL + 0x00C)
107#define CLKSEL_TIMER4_CLK		(CM_DPLL + 0x010)
108#define CLKSEL_TIMER5_CLK		(CM_DPLL + 0x018)
109#define CLKSEL_TIMER6_CLK		(CM_DPLL + 0x01C)
110
111#define PRM_DEVICE_OFFSET		0xF00
112#define PRM_RSTCTRL			(PRM_DEVICE_OFFSET + 0x00)
113
114struct am335x_prcm_softc {
115	struct resource *	res[2];
116	bus_space_tag_t		bst;
117	bus_space_handle_t	bsh;
118};
119
120static struct resource_spec am335x_prcm_spec[] = {
121	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
122	{ -1, 0 }
123};
124
125static struct am335x_prcm_softc *am335x_prcm_sc = NULL;
126
127static int am335x_clk_generic_activate(struct ti_clock_dev *clkdev);
128static int am335x_clk_gpio_activate(struct ti_clock_dev *clkdev);
129static int am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev);
130static int am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
131static int am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev,  unsigned int *freq);
132static int am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
133static int am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
134static int am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
135static void am335x_prcm_reset(void);
136static int am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev);
137static int am335x_clk_musb0_activate(struct ti_clock_dev *clkdev);
138static int am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev);
139
140#define AM335X_GENERIC_CLOCK_DEV(i) \
141	{	.id = (i), \
142		.clk_activate = am335x_clk_generic_activate, \
143		.clk_deactivate = am335x_clk_generic_deactivate, \
144		.clk_set_source = am335x_clk_generic_set_source, \
145		.clk_accessible = NULL, \
146		.clk_get_source_freq = NULL \
147	}
148
149#define AM335X_GPIO_CLOCK_DEV(i) \
150	{	.id = (i), \
151		.clk_activate = am335x_clk_gpio_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_MMCHS_CLOCK_DEV(i) \
159	{	.id = (i), \
160		.clk_activate = am335x_clk_generic_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 = am335x_clk_hsmmc_get_source_freq \
165	}
166
167struct ti_clock_dev ti_clk_devmap[] = {
168	/* System clocks */
169	{	.id                  = SYS_CLK,
170		.clk_activate        = NULL,
171		.clk_deactivate      = NULL,
172		.clk_set_source      = NULL,
173		.clk_accessible      = NULL,
174		.clk_get_source_freq = am335x_clk_get_sysclk_freq,
175	},
176	/* MPU (ARM) core clocks */
177	{	.id                  = MPU_CLK,
178		.clk_activate        = NULL,
179		.clk_deactivate      = NULL,
180		.clk_set_source      = NULL,
181		.clk_accessible      = NULL,
182		.clk_get_source_freq = am335x_clk_get_arm_fclk_freq,
183	},
184	/* CPSW Ethernet Switch core clocks */
185	{	.id                  = CPSW_CLK,
186		.clk_activate        = am335x_clk_cpsw_activate,
187		.clk_deactivate      = NULL,
188		.clk_set_source      = NULL,
189		.clk_accessible      = NULL,
190		.clk_get_source_freq = NULL,
191	},
192
193	/* Mentor USB HS controller core clocks */
194	{	.id                  = MUSB0_CLK,
195		.clk_activate        = am335x_clk_musb0_activate,
196		.clk_deactivate      = NULL,
197		.clk_set_source      = NULL,
198		.clk_accessible      = NULL,
199		.clk_get_source_freq = NULL,
200	},
201
202	/* LCD controller clocks */
203	{	.id                  = LCDC_CLK,
204		.clk_activate        = am335x_clk_lcdc_activate,
205		.clk_deactivate      = NULL,
206		.clk_set_source      = NULL,
207		.clk_accessible      = NULL,
208		.clk_get_source_freq = am335x_clk_get_arm_disp_freq,
209	},
210
211	/* DMTimer */
212	AM335X_GENERIC_CLOCK_DEV(DMTIMER2_CLK),
213	AM335X_GENERIC_CLOCK_DEV(DMTIMER3_CLK),
214	AM335X_GENERIC_CLOCK_DEV(DMTIMER4_CLK),
215	AM335X_GENERIC_CLOCK_DEV(DMTIMER5_CLK),
216	AM335X_GENERIC_CLOCK_DEV(DMTIMER6_CLK),
217	AM335X_GENERIC_CLOCK_DEV(DMTIMER7_CLK),
218
219	/* GPIO */
220	AM335X_GPIO_CLOCK_DEV(GPIO0_CLK),
221	AM335X_GPIO_CLOCK_DEV(GPIO1_CLK),
222	AM335X_GPIO_CLOCK_DEV(GPIO2_CLK),
223	AM335X_GPIO_CLOCK_DEV(GPIO3_CLK),
224
225	/* I2C */
226	AM335X_GENERIC_CLOCK_DEV(I2C0_CLK),
227	AM335X_GENERIC_CLOCK_DEV(I2C1_CLK),
228	AM335X_GENERIC_CLOCK_DEV(I2C2_CLK),
229
230	/* EDMA */
231	AM335X_GENERIC_CLOCK_DEV(EDMA_TPCC_CLK),
232	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC0_CLK),
233	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC1_CLK),
234	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC2_CLK),
235
236	/* MMCHS */
237	AM335X_MMCHS_CLOCK_DEV(MMC0_CLK),
238	AM335X_MMCHS_CLOCK_DEV(MMC1_CLK),
239	AM335X_MMCHS_CLOCK_DEV(MMC2_CLK),
240
241	/* PWMSS */
242	AM335X_GENERIC_CLOCK_DEV(PWMSS0_CLK),
243	AM335X_GENERIC_CLOCK_DEV(PWMSS1_CLK),
244	AM335X_GENERIC_CLOCK_DEV(PWMSS2_CLK),
245
246	{  INVALID_CLK_IDENT, NULL, NULL, NULL, NULL }
247};
248
249struct am335x_clk_details {
250	clk_ident_t	id;
251	uint32_t	clkctrl_reg;
252	uint32_t	clksel_reg;
253};
254
255#define _CLK_DETAIL(i, c, s) \
256	{	.id = (i), \
257		.clkctrl_reg = (c), \
258		.clksel_reg = (s), \
259	}
260
261static struct am335x_clk_details g_am335x_clk_details[] = {
262
263	/* DMTimer modules */
264	_CLK_DETAIL(DMTIMER2_CLK, CM_PER_TIMER2_CLKCTRL, CLKSEL_TIMER2_CLK),
265	_CLK_DETAIL(DMTIMER3_CLK, CM_PER_TIMER3_CLKCTRL, CLKSEL_TIMER3_CLK),
266	_CLK_DETAIL(DMTIMER4_CLK, CM_PER_TIMER4_CLKCTRL, CLKSEL_TIMER4_CLK),
267	_CLK_DETAIL(DMTIMER5_CLK, CM_PER_TIMER5_CLKCTRL, CLKSEL_TIMER5_CLK),
268	_CLK_DETAIL(DMTIMER6_CLK, CM_PER_TIMER6_CLKCTRL, CLKSEL_TIMER6_CLK),
269	_CLK_DETAIL(DMTIMER7_CLK, CM_PER_TIMER7_CLKCTRL, CLKSEL_TIMER7_CLK),
270
271	/* GPIO modules */
272	_CLK_DETAIL(GPIO0_CLK, CM_WKUP_GPIO0_CLKCTRL, 0),
273	_CLK_DETAIL(GPIO1_CLK, CM_PER_GPIO1_CLKCTRL, 0),
274	_CLK_DETAIL(GPIO2_CLK, CM_PER_GPIO2_CLKCTRL, 0),
275	_CLK_DETAIL(GPIO3_CLK, CM_PER_GPIO3_CLKCTRL, 0),
276
277	/* I2C modules */
278	_CLK_DETAIL(I2C0_CLK, CM_WKUP_I2C0_CLKCTRL, 0),
279	_CLK_DETAIL(I2C1_CLK, CM_PER_I2C1_CLKCTRL, 0),
280	_CLK_DETAIL(I2C2_CLK, CM_PER_I2C2_CLKCTRL, 0),
281
282	/* EDMA modules */
283	_CLK_DETAIL(EDMA_TPCC_CLK, CM_PER_TPCC_CLKCTRL, 0),
284	_CLK_DETAIL(EDMA_TPTC0_CLK, CM_PER_TPTC0_CLKCTRL, 0),
285	_CLK_DETAIL(EDMA_TPTC1_CLK, CM_PER_TPTC1_CLKCTRL, 0),
286	_CLK_DETAIL(EDMA_TPTC2_CLK, CM_PER_TPTC2_CLKCTRL, 0),
287
288	/* MMCHS modules*/
289	_CLK_DETAIL(MMC0_CLK, CM_PER_MMC0_CLKCTRL, 0),
290	_CLK_DETAIL(MMC1_CLK, CM_PER_MMC1_CLKCTRL, 0),
291	_CLK_DETAIL(MMC2_CLK, CM_PER_MMC1_CLKCTRL, 0),
292
293	/* PWMSS modules */
294	_CLK_DETAIL(PWMSS0_CLK, CM_PER_EPWMSS0_CLKCTRL, 0),
295	_CLK_DETAIL(PWMSS1_CLK, CM_PER_EPWMSS1_CLKCTRL, 0),
296	_CLK_DETAIL(PWMSS2_CLK, CM_PER_EPWMSS2_CLKCTRL, 0),
297
298	{ INVALID_CLK_IDENT, 0},
299};
300
301/* Read/Write macros */
302#define prcm_read_4(reg)		\
303	bus_space_read_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg)
304#define prcm_write_4(reg, val)		\
305	bus_space_write_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg, val)
306
307void am335x_prcm_setup_dmtimer(int);
308
309static int
310am335x_prcm_probe(device_t dev)
311{
312	if (ofw_bus_is_compatible(dev, "am335x,prcm")) {
313		device_set_desc(dev, "AM335x Power and Clock Management");
314		return(BUS_PROBE_DEFAULT);
315	}
316
317	return (ENXIO);
318}
319
320static int
321am335x_prcm_attach(device_t dev)
322{
323	struct am335x_prcm_softc *sc = device_get_softc(dev);
324	unsigned int sysclk, fclk;
325
326	if (am335x_prcm_sc)
327		return (ENXIO);
328
329	if (bus_alloc_resources(dev, am335x_prcm_spec, sc->res)) {
330		device_printf(dev, "could not allocate resources\n");
331		return (ENXIO);
332	}
333
334	sc->bst = rman_get_bustag(sc->res[0]);
335	sc->bsh = rman_get_bushandle(sc->res[0]);
336
337	am335x_prcm_sc = sc;
338	ti_cpu_reset = am335x_prcm_reset;
339
340	am335x_clk_get_sysclk_freq(NULL, &sysclk);
341	am335x_clk_get_arm_fclk_freq(NULL, &fclk);
342	device_printf(dev, "Clocks: System %u.%01u MHz, CPU %u MHz\n",
343		sysclk/1000000, (sysclk % 1000000)/100000, fclk/1000000);
344
345	return (0);
346}
347
348static device_method_t am335x_prcm_methods[] = {
349	DEVMETHOD(device_probe,		am335x_prcm_probe),
350	DEVMETHOD(device_attach,	am335x_prcm_attach),
351	{ 0, 0 }
352};
353
354static driver_t am335x_prcm_driver = {
355	"am335x_prcm",
356	am335x_prcm_methods,
357	sizeof(struct am335x_prcm_softc),
358};
359
360static devclass_t am335x_prcm_devclass;
361
362DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver,
363	am335x_prcm_devclass, 0, 0);
364MODULE_DEPEND(am335x_prcm, ti_scm, 1, 1, 1);
365
366static struct am335x_clk_details*
367am335x_clk_details(clk_ident_t id)
368{
369	struct am335x_clk_details *walker;
370
371	for (walker = g_am335x_clk_details; walker->id != INVALID_CLK_IDENT; walker++) {
372		if (id == walker->id)
373			return (walker);
374	}
375
376	return NULL;
377}
378
379static int
380am335x_clk_generic_activate(struct ti_clock_dev *clkdev)
381{
382	struct am335x_prcm_softc *sc = am335x_prcm_sc;
383	struct am335x_clk_details* clk_details;
384
385	if (sc == NULL)
386		return ENXIO;
387
388	clk_details = am335x_clk_details(clkdev->id);
389
390	if (clk_details == NULL)
391		return (ENXIO);
392
393	/* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */
394	prcm_write_4(clk_details->clkctrl_reg, 2);
395	while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 2)
396		DELAY(10);
397
398	return (0);
399}
400
401static int
402am335x_clk_gpio_activate(struct ti_clock_dev *clkdev)
403{
404	struct am335x_prcm_softc *sc = am335x_prcm_sc;
405	struct am335x_clk_details* clk_details;
406
407	if (sc == NULL)
408		return ENXIO;
409
410	clk_details = am335x_clk_details(clkdev->id);
411
412	if (clk_details == NULL)
413		return (ENXIO);
414
415	/* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */
416	/* set *_CLKCTRL register OPTFCLKEN_GPIO_1_G DBCLK[18] to FCLK_EN(1) */
417	prcm_write_4(clk_details->clkctrl_reg, 2 | (1 << 18));
418	while ((prcm_read_4(clk_details->clkctrl_reg) &
419	    (3 | (1 << 18) )) != (2 | (1 << 18)))
420		DELAY(10);
421
422	return (0);
423}
424
425static int
426am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev)
427{
428	struct am335x_prcm_softc *sc = am335x_prcm_sc;
429	struct am335x_clk_details* clk_details;
430
431	if (sc == NULL)
432		return ENXIO;
433
434	clk_details = am335x_clk_details(clkdev->id);
435
436	if (clk_details == NULL)
437		return (ENXIO);
438
439	/* set *_CLKCTRL register MODULEMODE[1:0] to disable(0) */
440	prcm_write_4(clk_details->clkctrl_reg, 0);
441	while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 0)
442		DELAY(10);
443
444	return (0);
445}
446
447static int
448am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc)
449{
450	struct am335x_prcm_softc *sc = am335x_prcm_sc;
451	struct am335x_clk_details* clk_details;
452	uint32_t reg;
453
454	if (sc == NULL)
455		return ENXIO;
456
457	clk_details = am335x_clk_details(clkdev->id);
458
459	if (clk_details == NULL)
460		return (ENXIO);
461
462	switch (clksrc) {
463		case EXT_CLK:
464			reg = 0; /* SEL2: TCLKIN clock */
465			break;
466		case SYSCLK_CLK:
467			reg = 1; /* SEL1: CLK_M_OSC clock */
468			break;
469		case F32KHZ_CLK:
470			reg = 2; /* SEL3: CLK_32KHZ clock */
471			break;
472		default:
473			return (ENXIO);
474	}
475
476	prcm_write_4(clk_details->clksel_reg, reg);
477	while ((prcm_read_4(clk_details->clksel_reg) & 0x3) != reg)
478		DELAY(10);
479
480	return (0);
481}
482
483static int
484am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev,  unsigned int *freq)
485{
486	*freq = 96000000;
487	return (0);
488}
489
490static int
491am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
492{
493	uint32_t ctrl_status;
494
495	/* Read the input clock freq from the control module */
496	/* control_status reg (0x40) */
497	if (ti_scm_reg_read_4(0x40, &ctrl_status))
498		return ENXIO;
499
500	switch ((ctrl_status>>22) & 0x3) {
501	case 0x0:
502		/* 19.2Mhz */
503		*freq = 19200000;
504		break;
505	case 0x1:
506		/* 24Mhz */
507		*freq = 24000000;
508		break;
509	case 0x2:
510		/* 25Mhz */
511		*freq = 25000000;
512		break;
513	case 0x3:
514		/* 26Mhz */
515		*freq = 26000000;
516		break;
517	}
518
519	return (0);
520}
521
522#define DPLL_BYP_CLKSEL(reg)	((reg>>23) & 1)
523#define DPLL_DIV(reg)		((reg & 0x7f)+1)
524#define DPLL_MULT(reg)		((reg>>8) & 0x7FF)
525
526static int
527am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
528{
529	uint32_t reg;
530	uint32_t sysclk;
531
532	reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_MPU);
533
534	/*Check if we are running in bypass */
535	if (DPLL_BYP_CLKSEL(reg))
536		return ENXIO;
537
538	am335x_clk_get_sysclk_freq(NULL, &sysclk);
539	*freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg));
540	return(0);
541}
542
543static int
544am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
545{
546	uint32_t reg;
547	uint32_t sysclk;
548
549	reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_DISP);
550
551	/*Check if we are running in bypass */
552	if (DPLL_BYP_CLKSEL(reg))
553		return ENXIO;
554
555	am335x_clk_get_sysclk_freq(NULL, &sysclk);
556	*freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg));
557	return(0);
558}
559
560static void
561am335x_prcm_reset(void)
562{
563	prcm_write_4(PRM_RSTCTRL, (1<<1));
564}
565
566static int
567am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev)
568{
569	struct am335x_prcm_softc *sc = am335x_prcm_sc;
570
571	if (sc == NULL)
572		return ENXIO;
573
574	/* set MODULENAME to ENABLE */
575	prcm_write_4(CM_PER_CPGMAC0_CLKCTRL, 2);
576
577	/* wait for IDLEST to become Func(0) */
578	while(prcm_read_4(CM_PER_CPGMAC0_CLKCTRL) & (3<<16));
579
580	/*set CLKTRCTRL to SW_WKUP(2) */
581	prcm_write_4(CM_PER_CPSW_CLKSTCTRL, 2);
582
583	/* wait for 125 MHz OCP clock to become active */
584	while((prcm_read_4(CM_PER_CPSW_CLKSTCTRL) & (1<<4)) == 0);
585	return(0);
586}
587
588static int
589am335x_clk_musb0_activate(struct ti_clock_dev *clkdev)
590{
591	struct am335x_prcm_softc *sc = am335x_prcm_sc;
592
593	if (sc == NULL)
594		return ENXIO;
595
596	/* set ST_DPLL_CLKDCOLDO(9) to CLK_GATED(1) */
597	/* set DPLL_CLKDCOLDO_GATE_CTRL(8) to CLK_ENABLE(1)*/
598        prcm_write_4(CM_WKUP_CM_CLKDCOLDO_DPLL_PER, 0x300);
599
600	/*set MODULEMODE to ENABLE(2) */
601	prcm_write_4(CM_PER_USB0_CLKCTRL, 2);
602
603	/* wait for MODULEMODE to become ENABLE(2) */
604	while ((prcm_read_4(CM_PER_USB0_CLKCTRL) & 0x3) != 2)
605		DELAY(10);
606
607	/* wait for IDLEST to become Func(0) */
608	while(prcm_read_4(CM_PER_USB0_CLKCTRL) & (3<<16))
609		DELAY(10);
610
611	return(0);
612}
613
614static int
615am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev)
616{
617	struct am335x_prcm_softc *sc = am335x_prcm_sc;
618
619	if (sc == NULL)
620		return (ENXIO);
621
622	/* Bypass mode */
623	prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x4);
624
625	/* Make sure it's in bypass mode */
626	while (!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP)
627	    & (1 << 8)))
628		DELAY(10);
629
630	/*
631	 * For now set frequenct to  5xSYSFREQ
632	 * More flexible control might be required
633	 */
634	prcm_write_4(CM_WKUP_CM_CLKSEL_DPLL_DISP, (5 << 8) | 0);
635
636	/* Locked mode */
637	prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x7);
638
639	int timeout = 10000;
640	while ((!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP)
641	    & (1 << 0))) && timeout--)
642		DELAY(10);
643
644	/*set MODULEMODE to ENABLE(2) */
645	prcm_write_4(CM_PER_LCDC_CLKCTRL, 2);
646
647	/* wait for MODULEMODE to become ENABLE(2) */
648	while ((prcm_read_4(CM_PER_LCDC_CLKCTRL) & 0x3) != 2)
649		DELAY(10);
650
651	/* wait for IDLEST to become Func(0) */
652	while(prcm_read_4(CM_PER_LCDC_CLKCTRL) & (3<<16))
653		DELAY(10);
654
655	return (0);
656}
657