1239281Sgonzo/*-
2239281Sgonzo * Copyright (c) 2011
3239281Sgonzo *	Ben Gray <ben.r.gray@gmail.com>.
4239281Sgonzo * All rights reserved.
5239281Sgonzo *
6239281Sgonzo * Redistribution and use in source and binary forms, with or without
7239281Sgonzo * modification, are permitted provided that the following conditions
8239281Sgonzo * are met:
9239281Sgonzo * 1. Redistributions of source code must retain the above copyright
10239281Sgonzo *    notice, this list of conditions and the following disclaimer.
11239281Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
12239281Sgonzo *    notice, this list of conditions and the following disclaimer in the
13239281Sgonzo *    documentation and/or other materials provided with the distribution.
14239281Sgonzo * 3. The name of the company nor the name of the author may be used to
15239281Sgonzo *    endorse or promote products derived from this software without specific
16239281Sgonzo *    prior written permission.
17239281Sgonzo *
18239281Sgonzo * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR
19239281Sgonzo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20239281Sgonzo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21239281Sgonzo * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22239281Sgonzo * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23239281Sgonzo * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24239281Sgonzo * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25239281Sgonzo * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26239281Sgonzo * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27239281Sgonzo * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28239281Sgonzo */
29239281Sgonzo
30239281Sgonzo#include <sys/cdefs.h>
31239281Sgonzo__FBSDID("$FreeBSD$");
32239281Sgonzo
33239281Sgonzo#include <sys/param.h>
34239281Sgonzo#include <sys/systm.h>
35239281Sgonzo#include <sys/kernel.h>
36239281Sgonzo#include <sys/module.h>
37239281Sgonzo#include <sys/bus.h>
38239281Sgonzo#include <sys/resource.h>
39239281Sgonzo#include <sys/rman.h>
40239281Sgonzo#include <sys/lock.h>
41239281Sgonzo#include <sys/malloc.h>
42239281Sgonzo
43239281Sgonzo#include <machine/bus.h>
44239281Sgonzo#include <machine/cpu.h>
45239281Sgonzo#include <machine/cpufunc.h>
46239281Sgonzo#include <machine/frame.h>
47239281Sgonzo#include <machine/resource.h>
48239281Sgonzo#include <machine/intr.h>
49239281Sgonzo
50239281Sgonzo#include <arm/ti/tivar.h>
51239281Sgonzo#include <arm/ti/ti_prcm.h>
52239281Sgonzo#include <arm/ti/omap4/omap4_reg.h>
53239281Sgonzo
54239281Sgonzo#include <dev/fdt/fdt_common.h>
55239281Sgonzo#include <dev/ofw/openfirm.h>
56239281Sgonzo#include <dev/ofw/ofw_bus.h>
57239281Sgonzo#include <dev/ofw/ofw_bus_subr.h>
58239281Sgonzo
59239281Sgonzo/*
60239281Sgonzo *	This file defines the clock configuration for the OMAP4xxx series of
61239281Sgonzo *	devices.
62239281Sgonzo *
63239281Sgonzo *	How This is Suppose to Work
64239281Sgonzo *	===========================
65239281Sgonzo *	- There is a top level omap_prcm module that defines all OMAP SoC drivers
66239281Sgonzo *	should use to enable/disable the system clocks regardless of the version
67239281Sgonzo *	of OMAP device they are running on.  This top level PRCM module is just
68239281Sgonzo *	a thin shim to chip specific functions that perform the donkey work of
69239281Sgonzo *	configuring the clock - this file is the 'donkey' for OMAP44xx devices.
70239281Sgonzo *
71239281Sgonzo *	- The key bit in this file is the omap_clk_devmap array, it's
72239281Sgonzo *	used by the omap_prcm driver to determine what clocks are valid and which
73239281Sgonzo *	functions to call to manipulate them.
74239281Sgonzo *
75239281Sgonzo *	- In essence you just need to define some callbacks for each of the
76239281Sgonzo *	clocks and then you're done.
77239281Sgonzo *
78239281Sgonzo *	- The other thing that is worth noting is that when the omap_prcm device
79239281Sgonzo *	is registered you typically pass in some memory ranges which are the
80239281Sgonzo *	SYS_MEMORY resources.  These resources are in turn allocated using
81239281Sgonzo *	bus_allocate_resources(...) and the resource handles are passed to all
82239281Sgonzo *	individual clock callback handlers.
83239281Sgonzo *
84239281Sgonzo *
85239281Sgonzo *
86239281Sgonzo *	OMAP4 devices are different from the previous OMAP3 devices in that there
87239281Sgonzo *	is no longer a separate functional and interface clock for each module,
88239281Sgonzo *	instead there is typically an interface clock that spans many modules.
89239281Sgonzo *
90239281Sgonzo */
91239281Sgonzo
92239281Sgonzo#define FREQ_96MHZ    96000000
93239281Sgonzo#define FREQ_64MHZ    64000000
94239281Sgonzo#define FREQ_48MHZ    48000000
95239281Sgonzo#define FREQ_32KHZ    32000
96239281Sgonzo
97239281Sgonzo/**
98239281Sgonzo *	We need three memory regions to cover all the clock configuration registers.
99239281Sgonzo *
100239281Sgonzo *	   PRM Instance -  0x4A30 6000 : 0x4A30 8000
101239281Sgonzo *	   CM1 Instance -  0x4A00 4000 : 0x4A00 5000
102239281Sgonzo *	   CM2 Instance -  0x4A00 8000 : 0x4A00 A000
103239281Sgonzo *
104239281Sgonzo */
105239281Sgonzo#define PRM_INSTANCE_MEM_REGION    0
106239281Sgonzo#define CM1_INSTANCE_MEM_REGION    1
107239281Sgonzo#define CM2_INSTANCE_MEM_REGION    2
108239281Sgonzo
109239281Sgonzo/**
110239281Sgonzo *	Address offsets from the PRM memory region to the top level clock control
111239281Sgonzo *	registers.
112239281Sgonzo */
113239281Sgonzo#define CKGEN_PRM_OFFSET               0x00000100UL
114239281Sgonzo#define MPU_PRM_OFFSET                 0x00000300UL
115239281Sgonzo#define DSP_PRM_OFFSET                 0x00000400UL
116239281Sgonzo#define ABE_PRM_OFFSET                 0x00000500UL
117239281Sgonzo#define ALWAYS_ON_PRM_OFFSET           0x00000600UL
118239281Sgonzo#define CORE_PRM_OFFSET                0x00000700UL
119239281Sgonzo#define IVAHD_PRM_OFFSET               0x00000F00UL
120239281Sgonzo#define CAM_PRM_OFFSET                 0x00001000UL
121239281Sgonzo#define DSS_PRM_OFFSET                 0x00001100UL
122239281Sgonzo#define SGX_PRM_OFFSET                 0x00001200UL
123239281Sgonzo#define L3INIT_PRM_OFFSET              0x00001300UL
124239281Sgonzo#define L4PER_PRM_OFFSET               0x00001400UL
125239281Sgonzo#define WKUP_PRM_OFFSET                0x00001700UL
126239281Sgonzo#define WKUP_CM_OFFSET                 0x00001800UL
127239281Sgonzo#define EMU_PRM_OFFSET                 0x00001900UL
128239281Sgonzo#define EMU_CM_OFFSET                  0x00001A00UL
129239281Sgonzo#define DEVICE_PRM_OFFSET              0x00001B00UL
130239281Sgonzo#define INSTR_PRM_OFFSET               0x00001F00UL
131239281Sgonzo
132239281Sgonzo#define CM_ABE_DSS_SYS_CLKSEL_OFFSET   (CKGEN_PRM_OFFSET + 0x0000UL)
133239281Sgonzo#define CM_L4_WKUP_CLKSELL_OFFSET      (CKGEN_PRM_OFFSET + 0x0008UL)
134239281Sgonzo#define CM_ABE_PLL_REF_CLKSEL_OFFSET   (CKGEN_PRM_OFFSET + 0x000CUL)
135239281Sgonzo#define CM_SYS_CLKSEL_OFFSET           (CKGEN_PRM_OFFSET + 0x0010UL)
136239281Sgonzo
137239281Sgonzo/**
138239281Sgonzo *	Address offsets from the CM1 memory region to the top level clock control
139239281Sgonzo *	registers.
140239281Sgonzo */
141239281Sgonzo#define CKGEN_CM1_OFFSET               0x00000100UL
142239281Sgonzo#define MPU_CM1_OFFSET                 0x00000300UL
143239281Sgonzo#define DSP_CM1_OFFSET                 0x00000400UL
144239281Sgonzo#define ABE_CM1_OFFSET                 0x00000500UL
145239281Sgonzo#define RESTORE_CM1_OFFSET             0x00000E00UL
146239281Sgonzo#define INSTR_CM1_OFFSET               0x00000F00UL
147239281Sgonzo
148239281Sgonzo#define CM_CLKSEL_DPLL_MPU             (CKGEN_CM1_OFFSET + 0x006CUL)
149239281Sgonzo
150239281Sgonzo/**
151239281Sgonzo *	Address offsets from the CM2 memory region to the top level clock control
152239281Sgonzo *	registers.
153239281Sgonzo */
154239281Sgonzo#define INTRCONN_SOCKET_CM2_OFFSET     0x00000000UL
155239281Sgonzo#define CKGEN_CM2_OFFSET               0x00000100UL
156239281Sgonzo#define ALWAYS_ON_CM2_OFFSET           0x00000600UL
157239281Sgonzo#define CORE_CM2_OFFSET                0x00000700UL
158239281Sgonzo#define IVAHD_CM2_OFFSET               0x00000F00UL
159239281Sgonzo#define CAM_CM2_OFFSET                 0x00001000UL
160239281Sgonzo#define DSS_CM2_OFFSET                 0x00001100UL
161239281Sgonzo#define SGX_CM2_OFFSET                 0x00001200UL
162239281Sgonzo#define L3INIT_CM2_OFFSET              0x00001300UL
163239281Sgonzo#define L4PER_CM2_OFFSET               0x00001400UL
164239281Sgonzo#define RESTORE_CM2_OFFSET             0x00001E00UL
165239281Sgonzo#define INSTR_CM2_OFFSET               0x00001F00UL
166239281Sgonzo
167239281Sgonzo#define CLKCTRL_MODULEMODE_MASK       0x00000003UL
168239281Sgonzo#define CLKCTRL_MODULEMODE_DISABLE    0x00000000UL
169239281Sgonzo#define CLKCTRL_MODULEMODE_AUTO       0x00000001UL
170239281Sgonzo#define CLKCTRL_MODULEMODE_ENABLE     0x00000001UL
171239281Sgonzo
172239281Sgonzo#define CLKCTRL_IDLEST_MASK           0x00030000UL
173239281Sgonzo#define CLKCTRL_IDLEST_ENABLED        0x00000000UL
174239281Sgonzo#define CLKCTRL_IDLEST_WAKING         0x00010000UL
175239281Sgonzo#define CLKCTRL_IDLEST_IDLE           0x00020000UL
176239281Sgonzo#define CLKCTRL_IDLEST_DISABLED       0x00030000UL
177239281Sgonzo
178239281Sgonzostatic struct resource_spec omap4_scm_res_spec[] = {
179239281Sgonzo	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Control memory window */
180239281Sgonzo	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* Control memory window */
181239281Sgonzo	{ SYS_RES_MEMORY,	2,	RF_ACTIVE },	/* Control memory window */
182239281Sgonzo	{ -1, 0 }
183239281Sgonzo};
184239281Sgonzo
185239281Sgonzostruct omap4_prcm_softc {
186239281Sgonzo	struct resource	*sc_res[3];
187239281Sgonzo};
188239281Sgonzo
189239281Sgonzostatic struct omap4_prcm_softc *omap4_prcm_sc;
190239281Sgonzo
191239281Sgonzostatic int omap4_clk_generic_activate(struct ti_clock_dev *clkdev);
192239281Sgonzostatic int omap4_clk_generic_deactivate(struct ti_clock_dev *clkdev);
193239281Sgonzostatic int omap4_clk_generic_accessible(struct ti_clock_dev *clkdev);
194239281Sgonzostatic int omap4_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
195239281Sgonzostatic int omap4_clk_generic_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
196239281Sgonzo
197239281Sgonzostatic int omap4_clk_gptimer_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
198239281Sgonzostatic int omap4_clk_gptimer_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
199239281Sgonzo
200239281Sgonzostatic int omap4_clk_hsmmc_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
201239281Sgonzostatic int omap4_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
202239281Sgonzo
203239281Sgonzostatic int omap4_clk_hsusbhost_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
204239281Sgonzostatic int omap4_clk_hsusbhost_activate(struct ti_clock_dev *clkdev);
205239281Sgonzostatic int omap4_clk_hsusbhost_deactivate(struct ti_clock_dev *clkdev);
206239281Sgonzostatic int omap4_clk_hsusbhost_accessible(struct ti_clock_dev *clkdev);
207239281Sgonzo
208239281Sgonzostatic int omap4_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
209239281Sgonzostatic int omap4_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
210239281Sgonzo
211239281Sgonzo/**
212239281Sgonzo *	omap_clk_devmap - Array of clock devices available on OMAP4xxx devices
213239281Sgonzo *
214239281Sgonzo *	This map only defines which clocks are valid and the callback functions
215239281Sgonzo *	for clock activate, deactivate, etc.  It is used by the top level omap_prcm
216239281Sgonzo *	driver.
217239281Sgonzo *
218239281Sgonzo *	The actual details of the clocks (config registers, bit fields, sources,
219239281Sgonzo *	etc) are in the private g_omap3_clk_details array below.
220239281Sgonzo *
221239281Sgonzo */
222239281Sgonzo
223239281Sgonzo#define OMAP4_GENERIC_CLOCK_DEV(i) \
224239281Sgonzo	{	.id = (i), \
225239281Sgonzo		.clk_activate = omap4_clk_generic_activate, \
226239281Sgonzo		.clk_deactivate = omap4_clk_generic_deactivate, \
227239281Sgonzo		.clk_set_source = omap4_clk_generic_set_source, \
228239281Sgonzo		.clk_accessible = omap4_clk_generic_accessible, \
229239281Sgonzo		.clk_get_source_freq = omap4_clk_generic_get_source_freq \
230239281Sgonzo	}
231239281Sgonzo
232239281Sgonzo#define OMAP4_GPTIMER_CLOCK_DEV(i) \
233239281Sgonzo	{	.id = (i), \
234239281Sgonzo		.clk_activate = omap4_clk_generic_activate, \
235239281Sgonzo		.clk_deactivate = omap4_clk_generic_deactivate, \
236239281Sgonzo		.clk_set_source = omap4_clk_gptimer_set_source, \
237239281Sgonzo		.clk_accessible = omap4_clk_generic_accessible, \
238239281Sgonzo		.clk_get_source_freq = omap4_clk_gptimer_get_source_freq \
239239281Sgonzo	}
240239281Sgonzo
241239281Sgonzo#define OMAP4_HSMMC_CLOCK_DEV(i) \
242239281Sgonzo	{	.id = (i), \
243239281Sgonzo		.clk_activate = omap4_clk_generic_activate, \
244239281Sgonzo		.clk_deactivate = omap4_clk_generic_deactivate, \
245239281Sgonzo		.clk_set_source = omap4_clk_hsmmc_set_source, \
246239281Sgonzo		.clk_accessible = omap4_clk_generic_accessible, \
247239281Sgonzo		.clk_get_source_freq = omap4_clk_hsmmc_get_source_freq \
248239281Sgonzo	}
249239281Sgonzo
250239281Sgonzo#define OMAP4_HSUSBHOST_CLOCK_DEV(i) \
251239281Sgonzo	{	.id = (i), \
252239281Sgonzo		.clk_activate = omap4_clk_hsusbhost_activate, \
253239281Sgonzo		.clk_deactivate = omap4_clk_hsusbhost_deactivate, \
254239281Sgonzo		.clk_set_source = omap4_clk_hsusbhost_set_source, \
255239281Sgonzo		.clk_accessible = omap4_clk_hsusbhost_accessible, \
256239281Sgonzo		.clk_get_source_freq = NULL \
257239281Sgonzo	}
258239281Sgonzo
259239281Sgonzo
260239281Sgonzostruct ti_clock_dev ti_clk_devmap[] = {
261239281Sgonzo
262239281Sgonzo	/* System clocks */
263239281Sgonzo	{	.id                  = SYS_CLK,
264239281Sgonzo		.clk_activate        = NULL,
265239281Sgonzo		.clk_deactivate      = NULL,
266239281Sgonzo		.clk_set_source      = NULL,
267239281Sgonzo		.clk_accessible      = NULL,
268239281Sgonzo		.clk_get_source_freq = omap4_clk_get_sysclk_freq,
269239281Sgonzo	},
270239281Sgonzo	/* MPU (ARM) core clocks */
271239281Sgonzo	{	.id                  = MPU_CLK,
272239281Sgonzo		.clk_activate        = NULL,
273239281Sgonzo		.clk_deactivate      = NULL,
274239281Sgonzo		.clk_set_source      = NULL,
275239281Sgonzo		.clk_accessible      = NULL,
276239281Sgonzo		.clk_get_source_freq = omap4_clk_get_arm_fclk_freq,
277239281Sgonzo	},
278239281Sgonzo
279239281Sgonzo
280239281Sgonzo	/* UART device clocks */
281239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(UART1_CLK),
282239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(UART2_CLK),
283239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(UART3_CLK),
284239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(UART4_CLK),
285239281Sgonzo
286239281Sgonzo	/* Timer device source clocks */
287239281Sgonzo	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER1_CLK),
288239281Sgonzo	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER2_CLK),
289239281Sgonzo	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER3_CLK),
290239281Sgonzo	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER4_CLK),
291239281Sgonzo	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER5_CLK),
292239281Sgonzo	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER6_CLK),
293239281Sgonzo	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER7_CLK),
294239281Sgonzo	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER8_CLK),
295239281Sgonzo	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER9_CLK),
296239281Sgonzo	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER10_CLK),
297239281Sgonzo	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER11_CLK),
298239281Sgonzo
299239281Sgonzo	/* MMC device clocks (MMC1 and MMC2 can have different input clocks) */
300239281Sgonzo	OMAP4_HSMMC_CLOCK_DEV(MMC1_CLK),
301239281Sgonzo	OMAP4_HSMMC_CLOCK_DEV(MMC2_CLK),
302239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(MMC3_CLK),
303239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(MMC4_CLK),
304239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(MMC5_CLK),
305239281Sgonzo
306239281Sgonzo	/* USB HS (high speed TLL, EHCI and OHCI) */
307239281Sgonzo	OMAP4_HSUSBHOST_CLOCK_DEV(USBTLL_CLK),
308239281Sgonzo	OMAP4_HSUSBHOST_CLOCK_DEV(USBHSHOST_CLK),
309239281Sgonzo	OMAP4_HSUSBHOST_CLOCK_DEV(USBFSHOST_CLK),
310239281Sgonzo	OMAP4_HSUSBHOST_CLOCK_DEV(USBP1_PHY_CLK),
311239281Sgonzo	OMAP4_HSUSBHOST_CLOCK_DEV(USBP2_PHY_CLK),
312239281Sgonzo	OMAP4_HSUSBHOST_CLOCK_DEV(USBP1_UTMI_CLK),
313239281Sgonzo	OMAP4_HSUSBHOST_CLOCK_DEV(USBP2_UTMI_CLK),
314239281Sgonzo	OMAP4_HSUSBHOST_CLOCK_DEV(USBP1_HSIC_CLK),
315239281Sgonzo	OMAP4_HSUSBHOST_CLOCK_DEV(USBP2_HSIC_CLK),
316239281Sgonzo
317239281Sgonzo	/* GPIO */
318239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(GPIO1_CLK),
319239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(GPIO2_CLK),
320239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(GPIO3_CLK),
321239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(GPIO4_CLK),
322239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(GPIO5_CLK),
323239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(GPIO6_CLK),
324239281Sgonzo
325239281Sgonzo	/* sDMA */
326239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(SDMA_CLK),
327239281Sgonzo
328239281Sgonzo	/* I2C */
329239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(I2C1_CLK),
330239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(I2C2_CLK),
331239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(I2C3_CLK),
332239281Sgonzo	OMAP4_GENERIC_CLOCK_DEV(I2C4_CLK),
333239281Sgonzo
334239281Sgonzo	{  INVALID_CLK_IDENT, NULL, NULL, NULL, NULL }
335239281Sgonzo};
336239281Sgonzo
337239281Sgonzo/**
338239281Sgonzo *	omap4_clk_details - Stores details for all the different clocks supported
339239281Sgonzo *
340239281Sgonzo *	Whenever an operation on a clock is being performed (activated, deactivated,
341239281Sgonzo *	etc) this array is looked up to find the correct register and bit(s) we
342239281Sgonzo *	should be modifying.
343239281Sgonzo *
344239281Sgonzo */
345239281Sgonzostruct omap4_clk_details {
346239281Sgonzo	clk_ident_t id;
347239281Sgonzo
348239281Sgonzo	uint32_t    mem_region;
349239281Sgonzo	uint32_t    clksel_reg;
350239281Sgonzo
351239281Sgonzo	int32_t     src_freq;
352239281Sgonzo
353239281Sgonzo	uint32_t    enable_mode;
354239281Sgonzo};
355239281Sgonzo
356239281Sgonzo#define OMAP4_GENERIC_CLOCK_DETAILS(i, f, m, r, e) \
357239281Sgonzo	{	.id = (i), \
358239281Sgonzo		.mem_region = (m), \
359239281Sgonzo		.clksel_reg = (r), \
360239281Sgonzo		.src_freq = (f), \
361239281Sgonzo		.enable_mode = (e), \
362239281Sgonzo	}
363239281Sgonzo
364239281Sgonzostatic struct omap4_clk_details g_omap4_clk_details[] = {
365239281Sgonzo
366239281Sgonzo	/* UART */
367239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(UART1_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
368239281Sgonzo		(L4PER_CM2_OFFSET + 0x0140), CLKCTRL_MODULEMODE_ENABLE),
369239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(UART2_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
370239281Sgonzo		(L4PER_CM2_OFFSET + 0x0148), CLKCTRL_MODULEMODE_ENABLE),
371239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(UART3_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
372239281Sgonzo		(L4PER_CM2_OFFSET + 0x0140), CLKCTRL_MODULEMODE_ENABLE),
373239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(UART4_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
374239281Sgonzo		(L4PER_CM2_OFFSET + 0x0148), CLKCTRL_MODULEMODE_ENABLE),
375239281Sgonzo
376239281Sgonzo	/* General purpose timers */
377239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER1_CLK,  -1, PRM_INSTANCE_MEM_REGION,
378239281Sgonzo		(WKUP_CM_OFFSET + 0x040), CLKCTRL_MODULEMODE_ENABLE),
379239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER2_CLK,  -1, CM2_INSTANCE_MEM_REGION,
380239281Sgonzo		(L4PER_CM2_OFFSET + 0x038), CLKCTRL_MODULEMODE_ENABLE),
381239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER3_CLK,  -1, CM2_INSTANCE_MEM_REGION,
382239281Sgonzo		(L4PER_CM2_OFFSET + 0x040), CLKCTRL_MODULEMODE_ENABLE),
383239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER4_CLK,  -1, CM2_INSTANCE_MEM_REGION,
384239281Sgonzo		(L4PER_CM2_OFFSET + 0x048), CLKCTRL_MODULEMODE_ENABLE),
385239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER5_CLK,  -1, CM1_INSTANCE_MEM_REGION,
386239281Sgonzo		(ABE_CM1_OFFSET + 0x068), CLKCTRL_MODULEMODE_ENABLE),
387239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER6_CLK,  -1, CM1_INSTANCE_MEM_REGION,
388239281Sgonzo		(ABE_CM1_OFFSET + 0x070), CLKCTRL_MODULEMODE_ENABLE),
389239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER7_CLK,  -1, CM1_INSTANCE_MEM_REGION,
390239281Sgonzo		(ABE_CM1_OFFSET + 0x078), CLKCTRL_MODULEMODE_ENABLE),
391239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER8_CLK,  -1, CM1_INSTANCE_MEM_REGION,
392239281Sgonzo		(ABE_CM1_OFFSET + 0x080), CLKCTRL_MODULEMODE_ENABLE),
393239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER9_CLK,  -1, CM2_INSTANCE_MEM_REGION,
394239281Sgonzo		(L4PER_CM2_OFFSET + 0x050), CLKCTRL_MODULEMODE_ENABLE),
395239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER10_CLK, -1, CM2_INSTANCE_MEM_REGION,
396239281Sgonzo		(L4PER_CM2_OFFSET + 0x028), CLKCTRL_MODULEMODE_ENABLE),
397239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER11_CLK, -1, CM2_INSTANCE_MEM_REGION,
398239281Sgonzo		(L4PER_CM2_OFFSET + 0x030), CLKCTRL_MODULEMODE_ENABLE),
399239281Sgonzo
400239281Sgonzo	/* HSMMC (MMC1 and MMC2 can have different input clocks) */
401239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(MMC1_CLK, -1, CM2_INSTANCE_MEM_REGION,
402239281Sgonzo		(L3INIT_CM2_OFFSET + 0x028), /*CLKCTRL_MODULEMODE_ENABLE*/2),
403239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(MMC2_CLK, -1, CM2_INSTANCE_MEM_REGION,
404239281Sgonzo		(L3INIT_CM2_OFFSET + 0x030), /*CLKCTRL_MODULEMODE_ENABLE*/2),
405239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(MMC3_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
406239281Sgonzo		(L4PER_CM2_OFFSET + 0x120), /*CLKCTRL_MODULEMODE_ENABLE*/2),
407239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(MMC4_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
408239281Sgonzo		(L4PER_CM2_OFFSET + 0x128), /*CLKCTRL_MODULEMODE_ENABLE*/2),
409239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(MMC5_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
410239281Sgonzo	       (L4PER_CM2_OFFSET + 0x160), /*CLKCTRL_MODULEMODE_ENABLE*/1),
411239281Sgonzo
412239281Sgonzo	/* GPIO modules */
413239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPIO1_CLK, -1, PRM_INSTANCE_MEM_REGION,
414239281Sgonzo		(WKUP_CM_OFFSET + 0x038), CLKCTRL_MODULEMODE_AUTO),
415239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPIO2_CLK, -1, CM2_INSTANCE_MEM_REGION,
416239281Sgonzo		(L4PER_CM2_OFFSET + 0x060), CLKCTRL_MODULEMODE_AUTO),
417239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPIO3_CLK, -1, CM2_INSTANCE_MEM_REGION,
418239281Sgonzo		(L4PER_CM2_OFFSET + 0x068), CLKCTRL_MODULEMODE_AUTO),
419239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPIO4_CLK, -1, CM2_INSTANCE_MEM_REGION,
420239281Sgonzo		(L4PER_CM2_OFFSET + 0x070), CLKCTRL_MODULEMODE_AUTO),
421239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPIO5_CLK, -1, CM2_INSTANCE_MEM_REGION,
422239281Sgonzo		(L4PER_CM2_OFFSET + 0x078), CLKCTRL_MODULEMODE_AUTO),
423239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(GPIO6_CLK, -1, CM2_INSTANCE_MEM_REGION,
424239281Sgonzo		(L4PER_CM2_OFFSET + 0x080), CLKCTRL_MODULEMODE_AUTO),
425239281Sgonzo
426239281Sgonzo	/* sDMA block */
427239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(SDMA_CLK, -1, CM2_INSTANCE_MEM_REGION,
428239281Sgonzo		(CORE_CM2_OFFSET + 0x300), CLKCTRL_MODULEMODE_AUTO),
429239281Sgonzo
430239281Sgonzo	/* I2C modules */
431239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(I2C1_CLK, -1, CM2_INSTANCE_MEM_REGION,
432239281Sgonzo		(L4PER_CM2_OFFSET + 0x0A0), CLKCTRL_MODULEMODE_ENABLE),
433239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(I2C2_CLK, -1, CM2_INSTANCE_MEM_REGION,
434239281Sgonzo		(L4PER_CM2_OFFSET + 0x0A8), CLKCTRL_MODULEMODE_ENABLE),
435239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(I2C3_CLK, -1, CM2_INSTANCE_MEM_REGION,
436239281Sgonzo		(L4PER_CM2_OFFSET + 0x0B0), CLKCTRL_MODULEMODE_ENABLE),
437239281Sgonzo	OMAP4_GENERIC_CLOCK_DETAILS(I2C4_CLK, -1, CM2_INSTANCE_MEM_REGION,
438239281Sgonzo		(L4PER_CM2_OFFSET + 0x0B8), CLKCTRL_MODULEMODE_ENABLE),
439239281Sgonzo
440239281Sgonzo	{ INVALID_CLK_IDENT, 0, 0, 0, 0 },
441239281Sgonzo};
442239281Sgonzo
443239281Sgonzo/**
444239281Sgonzo *	MAX_MODULE_ENABLE_WAIT - the number of loops to wait for the module to come
445239281Sgonzo *	alive.
446239281Sgonzo *
447239281Sgonzo */
448239281Sgonzo#define MAX_MODULE_ENABLE_WAIT    100
449239281Sgonzo
450239281Sgonzo/**
451239281Sgonzo *	ARRAY_SIZE - Macro to return the number of elements in a static const array.
452239281Sgonzo *
453239281Sgonzo */
454239281Sgonzo#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
455239281Sgonzo
456239281Sgonzo/**
457239281Sgonzo *	omap4_clk_details - writes a 32-bit value to one of the timer registers
458239281Sgonzo *	@timer: Timer device context
459239281Sgonzo *	@off: The offset of a register from the timer register address range
460239281Sgonzo *	@val: The value to write into the register
461239281Sgonzo *
462239281Sgonzo *
463239281Sgonzo *	RETURNS:
464239281Sgonzo *	nothing
465239281Sgonzo */
466239281Sgonzostatic struct omap4_clk_details*
467239281Sgonzoomap4_clk_details(clk_ident_t id)
468239281Sgonzo{
469239281Sgonzo	struct omap4_clk_details *walker;
470239281Sgonzo
471239281Sgonzo	for (walker = g_omap4_clk_details; walker->id != INVALID_CLK_IDENT; walker++) {
472239281Sgonzo		if (id == walker->id)
473239281Sgonzo			return (walker);
474239281Sgonzo	}
475239281Sgonzo
476239281Sgonzo	return NULL;
477239281Sgonzo}
478239281Sgonzo
479239281Sgonzo/**
480239281Sgonzo *	omap4_clk_generic_activate - checks if a module is accessible
481239281Sgonzo *	@module: identifier for the module to check, see omap3_prcm.h for a list
482239281Sgonzo *	         of possible modules.
483239281Sgonzo *	         Example: OMAP3_MODULE_MMC1
484239281Sgonzo *
485239281Sgonzo *
486239281Sgonzo *
487239281Sgonzo *	LOCKING:
488239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
489239281Sgonzo *
490239281Sgonzo *	RETURNS:
491239281Sgonzo *	Returns 0 on success or a positive error code on failure.
492239281Sgonzo */
493239281Sgonzostatic int
494239281Sgonzoomap4_clk_generic_activate(struct ti_clock_dev *clkdev)
495239281Sgonzo{
496239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
497239281Sgonzo	struct omap4_clk_details* clk_details;
498239281Sgonzo	struct resource* clk_mem_res;
499239281Sgonzo	uint32_t clksel;
500239281Sgonzo	unsigned int i;
501239281Sgonzo
502239281Sgonzo	if (sc == NULL)
503239281Sgonzo		return ENXIO;
504239281Sgonzo
505239281Sgonzo	clk_details = omap4_clk_details(clkdev->id);
506239281Sgonzo
507239281Sgonzo	if (clk_details == NULL)
508239281Sgonzo		return (ENXIO);
509239281Sgonzo
510239281Sgonzo	clk_mem_res = sc->sc_res[clk_details->mem_region];
511239281Sgonzo
512239281Sgonzo	if (clk_mem_res == NULL)
513239281Sgonzo		return (EINVAL);
514239281Sgonzo
515239281Sgonzo	/* All the 'generic' clocks have a CLKCTRL register which is more or less
516239281Sgonzo	 * generic - the have at least two fielda called MODULEMODE and IDLEST.
517239281Sgonzo	 */
518239281Sgonzo	clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
519239281Sgonzo	clksel &= ~CLKCTRL_MODULEMODE_MASK;
520239281Sgonzo	clksel |=  clk_details->enable_mode;
521239281Sgonzo	bus_write_4(clk_mem_res, clk_details->clksel_reg, clksel);
522239281Sgonzo
523239281Sgonzo	/* Now poll on the IDLEST register to tell us if the module has come up.
524239281Sgonzo	 * TODO: We need to take into account the parent clocks.
525239281Sgonzo	 */
526239281Sgonzo
527239281Sgonzo	/* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */
528239281Sgonzo	for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) {
529239281Sgonzo		clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
530239281Sgonzo		if ((clksel & CLKCTRL_IDLEST_MASK) == CLKCTRL_IDLEST_ENABLED)
531239281Sgonzo			break;
532239281Sgonzo		DELAY(10);
533239281Sgonzo	}
534239281Sgonzo
535239281Sgonzo	/* Check the enabled state */
536239281Sgonzo	if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED) {
537239281Sgonzo		printf("Error: failed to enable module with clock %d\n", clkdev->id);
538239281Sgonzo		printf("Error: 0x%08x => 0x%08x\n", clk_details->clksel_reg, clksel);
539239281Sgonzo		return (ETIMEDOUT);
540239281Sgonzo	}
541239281Sgonzo
542239281Sgonzo	return (0);
543239281Sgonzo}
544239281Sgonzo
545239281Sgonzo/**
546239281Sgonzo *	omap4_clk_generic_deactivate - checks if a module is accessible
547239281Sgonzo *	@module: identifier for the module to check, see omap3_prcm.h for a list
548239281Sgonzo *	         of possible modules.
549239281Sgonzo *	         Example: OMAP3_MODULE_MMC1
550239281Sgonzo *
551239281Sgonzo *
552239281Sgonzo *
553239281Sgonzo *	LOCKING:
554239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
555239281Sgonzo *
556239281Sgonzo *	RETURNS:
557239281Sgonzo *	Returns 0 on success or a positive error code on failure.
558239281Sgonzo */
559239281Sgonzostatic int
560239281Sgonzoomap4_clk_generic_deactivate(struct ti_clock_dev *clkdev)
561239281Sgonzo{
562239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
563239281Sgonzo	struct omap4_clk_details* clk_details;
564239281Sgonzo	struct resource* clk_mem_res;
565239281Sgonzo	uint32_t clksel;
566239281Sgonzo
567239281Sgonzo	if (sc == NULL)
568239281Sgonzo		return ENXIO;
569239281Sgonzo
570239281Sgonzo	clk_details = omap4_clk_details(clkdev->id);
571239281Sgonzo
572239281Sgonzo	if (clk_details == NULL)
573239281Sgonzo		return (ENXIO);
574239281Sgonzo
575239281Sgonzo	clk_mem_res = sc->sc_res[clk_details->mem_region];
576239281Sgonzo
577239281Sgonzo	if (clk_mem_res == NULL)
578239281Sgonzo		return (EINVAL);
579239281Sgonzo
580239281Sgonzo	/* All the 'generic' clocks have a CLKCTRL register which is more or less
581239281Sgonzo	 * generic - the have at least two fielda called MODULEMODE and IDLEST.
582239281Sgonzo	 */
583239281Sgonzo	clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
584239281Sgonzo	clksel &= ~CLKCTRL_MODULEMODE_MASK;
585239281Sgonzo	clksel |=  CLKCTRL_MODULEMODE_DISABLE;
586239281Sgonzo	bus_write_4(clk_mem_res, clk_details->clksel_reg, clksel);
587239281Sgonzo
588239281Sgonzo	return (0);
589239281Sgonzo}
590239281Sgonzo
591239281Sgonzo/**
592239281Sgonzo *	omap4_clk_generic_set_source - checks if a module is accessible
593239281Sgonzo *	@module: identifier for the module to check, see omap3_prcm.h for a list
594239281Sgonzo *	         of possible modules.
595239281Sgonzo *	         Example: OMAP3_MODULE_MMC1
596239281Sgonzo *
597239281Sgonzo *
598239281Sgonzo *
599239281Sgonzo *	LOCKING:
600239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
601239281Sgonzo *
602239281Sgonzo *	RETURNS:
603239281Sgonzo *	Returns 0 on success or a positive error code on failure.
604239281Sgonzo */
605239281Sgonzostatic int
606239281Sgonzoomap4_clk_generic_set_source(struct ti_clock_dev *clkdev,
607239281Sgonzo                             clk_src_t clksrc)
608239281Sgonzo{
609239281Sgonzo
610239281Sgonzo	return (0);
611239281Sgonzo}
612239281Sgonzo
613239281Sgonzo/**
614239281Sgonzo *	omap4_clk_generic_accessible - checks if a module is accessible
615239281Sgonzo *	@module: identifier for the module to check, see omap3_prcm.h for a list
616239281Sgonzo *	         of possible modules.
617239281Sgonzo *	         Example: OMAP3_MODULE_MMC1
618239281Sgonzo *
619239281Sgonzo *
620239281Sgonzo *
621239281Sgonzo *	LOCKING:
622239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
623239281Sgonzo *
624239281Sgonzo *	RETURNS:
625239281Sgonzo *	Returns 0 on success or a negative error code on failure.
626239281Sgonzo */
627239281Sgonzostatic int
628239281Sgonzoomap4_clk_generic_accessible(struct ti_clock_dev *clkdev)
629239281Sgonzo{
630239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
631239281Sgonzo	struct omap4_clk_details* clk_details;
632239281Sgonzo	struct resource* clk_mem_res;
633239281Sgonzo	uint32_t clksel;
634239281Sgonzo
635239281Sgonzo	if (sc == NULL)
636239281Sgonzo		return ENXIO;
637239281Sgonzo
638239281Sgonzo	clk_details = omap4_clk_details(clkdev->id);
639239281Sgonzo
640239281Sgonzo	if (clk_details == NULL)
641239281Sgonzo		return (ENXIO);
642239281Sgonzo
643239281Sgonzo	clk_mem_res = sc->sc_res[clk_details->mem_region];
644239281Sgonzo
645239281Sgonzo	if (clk_mem_res == NULL)
646239281Sgonzo		return (EINVAL);
647239281Sgonzo
648239281Sgonzo	clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
649239281Sgonzo
650239281Sgonzo	/* Check the enabled state */
651239281Sgonzo	if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED)
652239281Sgonzo		return (0);
653239281Sgonzo
654239281Sgonzo	return (1);
655239281Sgonzo}
656239281Sgonzo
657239281Sgonzo/**
658239281Sgonzo *	omap4_clk_generic_get_source_freq - checks if a module is accessible
659239281Sgonzo *	@module: identifier for the module to check, see omap3_prcm.h for a list
660239281Sgonzo *	         of possible modules.
661239281Sgonzo *	         Example: OMAP3_MODULE_MMC1
662239281Sgonzo *
663239281Sgonzo *
664239281Sgonzo *
665239281Sgonzo *	LOCKING:
666239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
667239281Sgonzo *
668239281Sgonzo *	RETURNS:
669239281Sgonzo *	Returns 0 on success or a negative error code on failure.
670239281Sgonzo */
671239281Sgonzostatic int
672239281Sgonzoomap4_clk_generic_get_source_freq(struct ti_clock_dev *clkdev,
673239281Sgonzo                                  unsigned int *freq
674239281Sgonzo                                  )
675239281Sgonzo{
676239281Sgonzo	struct omap4_clk_details* clk_details = omap4_clk_details(clkdev->id);
677239281Sgonzo
678239281Sgonzo	if (clk_details == NULL)
679239281Sgonzo		return (ENXIO);
680239281Sgonzo
681239281Sgonzo	/* Simply return the stored frequency */
682239281Sgonzo	if (freq)
683239281Sgonzo		*freq = (unsigned int)clk_details->src_freq;
684239281Sgonzo
685239281Sgonzo	return (0);
686239281Sgonzo}
687239281Sgonzo
688239281Sgonzo
689239281Sgonzo/**
690239281Sgonzo *	omap4_clk_gptimer_set_source - checks if a module is accessible
691239281Sgonzo *	@module: identifier for the module to check, see omap3_prcm.h for a list
692239281Sgonzo *	         of possible modules.
693239281Sgonzo *	         Example: OMAP3_MODULE_MMC1
694239281Sgonzo *
695239281Sgonzo *
696239281Sgonzo *
697239281Sgonzo *	LOCKING:
698239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
699239281Sgonzo *
700239281Sgonzo *	RETURNS:
701239281Sgonzo *	Returns 0 on success or a negative error code on failure.
702239281Sgonzo */
703239281Sgonzostatic int
704239281Sgonzoomap4_clk_gptimer_set_source(struct ti_clock_dev *clkdev,
705239281Sgonzo                             clk_src_t clksrc)
706239281Sgonzo{
707239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
708239281Sgonzo	struct omap4_clk_details* clk_details;
709239281Sgonzo	struct resource* clk_mem_res;
710239281Sgonzo
711239281Sgonzo	if (sc == NULL)
712239281Sgonzo		return ENXIO;
713239281Sgonzo
714239281Sgonzo	clk_details = omap4_clk_details(clkdev->id);
715239281Sgonzo
716239281Sgonzo	if (clk_details == NULL)
717239281Sgonzo		return (ENXIO);
718239281Sgonzo
719239281Sgonzo	clk_mem_res = sc->sc_res[clk_details->mem_region];
720239281Sgonzo
721239281Sgonzo	if (clk_mem_res == NULL)
722239281Sgonzo		return (EINVAL);
723239281Sgonzo
724239281Sgonzo	/* TODO: Implement */
725239281Sgonzo
726239281Sgonzo	return (0);
727239281Sgonzo}
728239281Sgonzo
729239281Sgonzo/**
730239281Sgonzo *	omap4_clk_gptimer_get_source_freq - checks if a module is accessible
731239281Sgonzo *	@module: identifier for the module to check, see omap3_prcm.h for a list
732239281Sgonzo *	         of possible modules.
733239281Sgonzo *	         Example: OMAP3_MODULE_MMC1
734239281Sgonzo *
735239281Sgonzo *
736239281Sgonzo *
737239281Sgonzo *	LOCKING:
738239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
739239281Sgonzo *
740239281Sgonzo *	RETURNS:
741239281Sgonzo *	Returns 0 on success or a negative error code on failure.
742239281Sgonzo */
743239281Sgonzostatic int
744239281Sgonzoomap4_clk_gptimer_get_source_freq(struct ti_clock_dev *clkdev,
745239281Sgonzo                                  unsigned int *freq
746239281Sgonzo                                  )
747239281Sgonzo{
748239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
749239281Sgonzo	struct omap4_clk_details* clk_details;
750239281Sgonzo	struct resource* clk_mem_res;
751239281Sgonzo	uint32_t clksel;
752239281Sgonzo	unsigned int src_freq;
753239281Sgonzo
754239281Sgonzo	if (sc == NULL)
755239281Sgonzo		return ENXIO;
756239281Sgonzo
757239281Sgonzo	clk_details = omap4_clk_details(clkdev->id);
758239281Sgonzo
759239281Sgonzo	if (clk_details == NULL)
760239281Sgonzo		return (ENXIO);
761239281Sgonzo
762239281Sgonzo	clk_mem_res = sc->sc_res[clk_details->mem_region];
763239281Sgonzo
764239281Sgonzo	if (clk_mem_res == NULL)
765239281Sgonzo		return (EINVAL);
766239281Sgonzo
767239281Sgonzo	/* Need to read the CLKSEL field to determine the clock source */
768239281Sgonzo	clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
769239281Sgonzo	if (clksel & (0x1UL << 24))
770239281Sgonzo		src_freq = FREQ_32KHZ;
771239281Sgonzo	else
772239281Sgonzo		omap4_clk_get_sysclk_freq(NULL, &src_freq);
773239281Sgonzo
774239281Sgonzo	/* Return the frequency */
775239281Sgonzo	if (freq)
776239281Sgonzo		*freq = src_freq;
777239281Sgonzo
778239281Sgonzo	return (0);
779239281Sgonzo}
780239281Sgonzo
781239281Sgonzo/**
782239281Sgonzo *	omap4_clk_hsmmc_set_source - sets the source clock (freq)
783239281Sgonzo *	@clkdev: pointer to the clockdev structure (id field will contain clock id)
784239281Sgonzo *
785239281Sgonzo *	The MMC 1 and 2 clocks can be source from either a 64MHz or 96MHz clock.
786239281Sgonzo *
787239281Sgonzo *	LOCKING:
788239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
789239281Sgonzo *
790239281Sgonzo *	RETURNS:
791239281Sgonzo *	Returns 0 on success or a negative error code on failure.
792239281Sgonzo */
793239281Sgonzostatic int
794239281Sgonzoomap4_clk_hsmmc_set_source(struct ti_clock_dev *clkdev,
795239281Sgonzo                           clk_src_t clksrc)
796239281Sgonzo{
797239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
798239281Sgonzo	struct omap4_clk_details* clk_details;
799239281Sgonzo	struct resource* clk_mem_res;
800239281Sgonzo	uint32_t clksel;
801239281Sgonzo
802239281Sgonzo	if (sc == NULL)
803239281Sgonzo		return ENXIO;
804239281Sgonzo
805239281Sgonzo	clk_details = omap4_clk_details(clkdev->id);
806239281Sgonzo
807239281Sgonzo	if (clk_details == NULL)
808239281Sgonzo		return (ENXIO);
809239281Sgonzo
810239281Sgonzo	clk_mem_res = sc->sc_res[clk_details->mem_region];
811239281Sgonzo
812239281Sgonzo	if (clk_mem_res == NULL)
813239281Sgonzo		return (EINVAL);
814239281Sgonzo
815239281Sgonzo	/* For MMC modules 3, 4 & 5 you can't change the freq, it's always 48MHz */
816239281Sgonzo	if ((clkdev->id == MMC3_CLK) || (clkdev->id == MMC4_CLK) ||
817239281Sgonzo	    (clkdev->id == MMC5_CLK)) {
818239281Sgonzo		if (clksrc != F48MHZ_CLK)
819239281Sgonzo			return (EINVAL);
820239281Sgonzo		return 0;
821239281Sgonzo	}
822239281Sgonzo
823239281Sgonzo
824239281Sgonzo	clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
825239281Sgonzo
826239281Sgonzo	/* Bit 24 is set if 96MHz clock or cleared for 64MHz clock */
827239281Sgonzo	if (clksrc == F64MHZ_CLK)
828239281Sgonzo		clksel &= ~(0x1UL << 24);
829239281Sgonzo	else if (clksrc == F96MHZ_CLK)
830239281Sgonzo		clksel |= (0x1UL << 24);
831239281Sgonzo	else
832239281Sgonzo		return (EINVAL);
833239281Sgonzo
834239281Sgonzo	bus_write_4(clk_mem_res, clk_details->clksel_reg, clksel);
835239281Sgonzo
836239281Sgonzo	return (0);
837239281Sgonzo}
838239281Sgonzo
839239281Sgonzo/**
840239281Sgonzo *	omap4_clk_hsmmc_get_source_freq - checks if a module is accessible
841239281Sgonzo *	@clkdev: pointer to the clockdev structure (id field will contain clock id)
842239281Sgonzo *
843239281Sgonzo *
844239281Sgonzo *
845239281Sgonzo *	LOCKING:
846239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
847239281Sgonzo *
848239281Sgonzo *	RETURNS:
849239281Sgonzo *	Returns 0 on success or a negative error code on failure.
850239281Sgonzo */
851239281Sgonzostatic int
852239281Sgonzoomap4_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev,
853239281Sgonzo                                unsigned int *freq
854239281Sgonzo                                )
855239281Sgonzo{
856239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
857239281Sgonzo	struct omap4_clk_details* clk_details;
858239281Sgonzo	struct resource* clk_mem_res;
859239281Sgonzo	uint32_t clksel;
860239281Sgonzo	unsigned int src_freq;
861239281Sgonzo
862239281Sgonzo	if (sc == NULL)
863239281Sgonzo		return ENXIO;
864239281Sgonzo
865239281Sgonzo	clk_details = omap4_clk_details(clkdev->id);
866239281Sgonzo
867239281Sgonzo	if (clk_details == NULL)
868239281Sgonzo		return (ENXIO);
869239281Sgonzo
870239281Sgonzo	clk_mem_res = sc->sc_res[clk_details->mem_region];
871239281Sgonzo
872239281Sgonzo	if (clk_mem_res == NULL)
873239281Sgonzo		return (EINVAL);
874239281Sgonzo
875239281Sgonzo	switch (clkdev->id) {
876239281Sgonzo	case MMC1_CLK:
877239281Sgonzo	case MMC2_CLK:
878239281Sgonzo		/* Need to read the CLKSEL field to determine the clock source */
879239281Sgonzo		clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
880239281Sgonzo		if (clksel & (0x1UL << 24))
881239281Sgonzo			src_freq = FREQ_96MHZ;
882239281Sgonzo		else
883239281Sgonzo			src_freq = FREQ_64MHZ;
884239281Sgonzo		break;
885239281Sgonzo	case MMC3_CLK:
886239281Sgonzo	case MMC4_CLK:
887239281Sgonzo	case MMC5_CLK:
888239281Sgonzo		src_freq = FREQ_48MHZ;
889239281Sgonzo		break;
890239281Sgonzo	default:
891239281Sgonzo		return (EINVAL);
892239281Sgonzo	}
893239281Sgonzo
894239281Sgonzo	/* Return the frequency */
895239281Sgonzo	if (freq)
896239281Sgonzo		*freq = src_freq;
897239281Sgonzo
898239281Sgonzo	return (0);
899239281Sgonzo}
900239281Sgonzo
901239281Sgonzo/**
902239281Sgonzo *	omap4_clk_get_sysclk_freq - gets the sysclk frequency
903239281Sgonzo *	@sc: pointer to the clk module/device context
904239281Sgonzo *
905239281Sgonzo *	Read the clocking information from the power-control/boot-strap registers,
906239281Sgonzo *  and stored in two global variables.
907239281Sgonzo *
908239281Sgonzo *	RETURNS:
909239281Sgonzo *	nothing, values are saved in global variables
910239281Sgonzo */
911239281Sgonzostatic int
912239281Sgonzoomap4_clk_get_sysclk_freq(struct ti_clock_dev *clkdev,
913239281Sgonzo                          unsigned int *freq)
914239281Sgonzo{
915239281Sgonzo	uint32_t clksel;
916239281Sgonzo	uint32_t sysclk;
917239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
918239281Sgonzo
919239281Sgonzo	if (sc == NULL)
920239281Sgonzo		return ENXIO;
921239281Sgonzo
922239281Sgonzo	/* Read the input clock freq from the configuration register (CM_SYS_CLKSEL) */
923239281Sgonzo	clksel = bus_read_4(sc->sc_res[PRM_INSTANCE_MEM_REGION], CM_SYS_CLKSEL_OFFSET);
924239281Sgonzo	switch (clksel & 0x7) {
925239281Sgonzo	case 0x1:
926239281Sgonzo		/* 12Mhz */
927239281Sgonzo		sysclk = 12000000;
928239281Sgonzo		break;
929239281Sgonzo	case 0x3:
930239281Sgonzo		/* 16.8Mhz */
931239281Sgonzo		sysclk = 16800000;
932239281Sgonzo		break;
933239281Sgonzo	case 0x4:
934239281Sgonzo		/* 19.2Mhz */
935239281Sgonzo		sysclk = 19200000;
936239281Sgonzo		break;
937239281Sgonzo	case 0x5:
938239281Sgonzo		/* 26Mhz */
939239281Sgonzo		sysclk = 26000000;
940239281Sgonzo		break;
941239281Sgonzo	case 0x7:
942239281Sgonzo		/* 38.4Mhz */
943239281Sgonzo		sysclk = 38400000;
944239281Sgonzo		break;
945239281Sgonzo	default:
946239281Sgonzo		panic("%s: Invalid clock freq", __func__);
947239281Sgonzo	}
948239281Sgonzo
949239281Sgonzo	/* Return the value */
950239281Sgonzo	if (freq)
951239281Sgonzo		*freq = sysclk;
952239281Sgonzo
953239281Sgonzo	return (0);
954239281Sgonzo}
955239281Sgonzo
956239281Sgonzo/**
957239281Sgonzo *	omap4_clk_get_arm_fclk_freq - gets the MPU clock frequency
958239281Sgonzo *	@clkdev: ignored
959239281Sgonzo *	@freq: pointer which upon return will contain the freq in hz
960239281Sgonzo *	@mem_res: array of allocated memory resources
961239281Sgonzo *
962239281Sgonzo *	Reads the frequency setting information registers and returns the value
963239281Sgonzo *	in the freq variable.
964239281Sgonzo *
965239281Sgonzo *	RETURNS:
966239281Sgonzo *	returns 0 on success, a positive error code on failure.
967239281Sgonzo */
968239281Sgonzostatic int
969239281Sgonzoomap4_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev,
970239281Sgonzo                            unsigned int *freq)
971239281Sgonzo{
972239281Sgonzo	uint32_t clksel;
973239281Sgonzo	uint32_t pll_mult, pll_div;
974239281Sgonzo	uint32_t mpuclk, sysclk;
975239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
976239281Sgonzo
977239281Sgonzo	if (sc == NULL)
978239281Sgonzo		return ENXIO;
979239281Sgonzo
980239281Sgonzo	/* Read the clksel register which contains the DPLL multiple and divide
981239281Sgonzo	 * values.  These are applied to the sysclk.
982239281Sgonzo	 */
983239281Sgonzo	clksel = bus_read_4(sc->sc_res[CM1_INSTANCE_MEM_REGION], CM_CLKSEL_DPLL_MPU);
984239281Sgonzo
985239281Sgonzo	pll_mult = ((clksel >> 8) & 0x7ff);
986239281Sgonzo	pll_div = (clksel & 0x7f) + 1;
987239281Sgonzo
988239281Sgonzo
989239281Sgonzo	/* Get the system clock freq */
990239281Sgonzo	omap4_clk_get_sysclk_freq(NULL, &sysclk);
991239281Sgonzo
992239281Sgonzo
993239281Sgonzo	/* Calculate the MPU freq */
994239281Sgonzo	mpuclk = (sysclk * pll_mult) / pll_div;
995239281Sgonzo
996239281Sgonzo	/* Return the value */
997239281Sgonzo	if (freq)
998239281Sgonzo		*freq = mpuclk;
999239281Sgonzo
1000239281Sgonzo	return (0);
1001239281Sgonzo}
1002239281Sgonzo
1003239281Sgonzo/**
1004239281Sgonzo *	omap4_clk_hsusbhost_activate - activates the USB clocks for the given module
1005239281Sgonzo *	@clkdev: pointer to the clock device structure.
1006249586Sgabor *	@mem_res: array of memory resources allocated by the top level PRCM driver.
1007239281Sgonzo *
1008239281Sgonzo *	The USB clocking setup seems to be a bit more tricky than the other modules,
1009239281Sgonzo *	to start with the clocking diagram for the HS host module shows 13 different
1010239281Sgonzo *	clocks.  So to try and make it easier to follow the clocking activation
1011239281Sgonzo *	and deactivation is handled in it's own set of callbacks.
1012239281Sgonzo *
1013239281Sgonzo *	LOCKING:
1014239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
1015239281Sgonzo *
1016239281Sgonzo *	RETURNS:
1017239281Sgonzo *	Returns 0 on success or a positive error code on failure.
1018239281Sgonzo */
1019239281Sgonzo
1020239281Sgonzostruct dpll_param {
1021239281Sgonzo	unsigned int m;
1022239281Sgonzo	unsigned int n;
1023239281Sgonzo	unsigned int m2;
1024239281Sgonzo	unsigned int m3;
1025239281Sgonzo	unsigned int m4;
1026239281Sgonzo	unsigned int m5;
1027239281Sgonzo	unsigned int m6;
1028239281Sgonzo	unsigned int m7;
1029239281Sgonzo};
1030239281Sgonzo/* USB parameters */
1031239281Sgonzostruct dpll_param usb_dpll_param[7] = {
1032239281Sgonzo	/* 12M values */
1033239281Sgonzo	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
1034239281Sgonzo	/* 13M values */
1035239281Sgonzo	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
1036239281Sgonzo	/* 16.8M values */
1037239281Sgonzo	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
1038239281Sgonzo	/* 19.2M values */
1039239281Sgonzo	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
1040239281Sgonzo	/* 26M values */
1041239281Sgonzo	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
1042239281Sgonzo	/* 27M values */
1043239281Sgonzo	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
1044239281Sgonzo	/* 38.4M values */
1045239281Sgonzo#ifdef CONFIG_OMAP4_SDC
1046239281Sgonzo	{0x32, 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0},
1047239281Sgonzo#else
1048239281Sgonzo	{0x32, 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0},
1049239281Sgonzo#endif
1050239281Sgonzo};
1051239281Sgonzostatic int
1052239281Sgonzoomap4_clk_hsusbhost_activate(struct ti_clock_dev *clkdev)
1053239281Sgonzo{
1054239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
1055239281Sgonzo	struct resource* clk_mem_res;
1056239281Sgonzo	uint32_t clksel_reg_off;
1057239281Sgonzo	uint32_t clksel;
1058239281Sgonzo	unsigned int i;
1059239281Sgonzo
1060239281Sgonzo	if (sc == NULL)
1061239281Sgonzo		return ENXIO;
1062239281Sgonzo
1063239281Sgonzo	switch (clkdev->id) {
1064239281Sgonzo	case USBTLL_CLK:
1065239281Sgonzo		/* For the USBTLL module we need to enable the following clocks:
1066239281Sgonzo		 *  - INIT_L4_ICLK  (will be enabled by bootloader)
1067239281Sgonzo		 *  - TLL_CH0_FCLK
1068239281Sgonzo		 *  - TLL_CH1_FCLK
1069239281Sgonzo		 */
1070239281Sgonzo
1071239281Sgonzo		/* We need the CM_L3INIT_HSUSBTLL_CLKCTRL register in CM2 register set */
1072239281Sgonzo		clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
1073239281Sgonzo		clksel_reg_off = L3INIT_CM2_OFFSET + 0x68;
1074239281Sgonzo
1075239281Sgonzo		/* Enable the module and also enable the optional func clocks for
1076239281Sgonzo		 * channels 0 & 1 (is this needed ?)
1077239281Sgonzo		 */
1078239281Sgonzo		clksel = bus_read_4(clk_mem_res, clksel_reg_off);
1079239281Sgonzo		clksel &= ~CLKCTRL_MODULEMODE_MASK;
1080239281Sgonzo		clksel |=  CLKCTRL_MODULEMODE_ENABLE;
1081239281Sgonzo
1082239281Sgonzo		clksel |= (0x1 << 8); /* USB-HOST optional clock: USB_CH0_CLK */
1083239281Sgonzo		clksel |= (0x1 << 9); /* USB-HOST optional clock: USB_CH1_CLK */
1084239281Sgonzo		break;
1085239281Sgonzo
1086239281Sgonzo	case USBHSHOST_CLK:
1087239281Sgonzo	case USBP1_PHY_CLK:
1088239281Sgonzo	case USBP2_PHY_CLK:
1089239281Sgonzo	case USBP1_UTMI_CLK:
1090239281Sgonzo	case USBP2_UTMI_CLK:
1091239281Sgonzo	case USBP1_HSIC_CLK:
1092239281Sgonzo	case USBP2_HSIC_CLK:
1093239281Sgonzo		/* For the USB HS HOST module we need to enable the following clocks:
1094239281Sgonzo		 *  - INIT_L4_ICLK     (will be enabled by bootloader)
1095239281Sgonzo		 *  - INIT_L3_ICLK     (will be enabled by bootloader)
1096239281Sgonzo		 *  - INIT_48MC_FCLK
1097239281Sgonzo		 *  - UTMI_ROOT_GFCLK  (UTMI only, create a new clock for that ?)
1098239281Sgonzo		 *  - UTMI_P1_FCLK     (UTMI only, create a new clock for that ?)
1099239281Sgonzo		 *  - UTMI_P2_FCLK     (UTMI only, create a new clock for that ?)
1100239281Sgonzo		 *  - HSIC_P1_60       (HSIC only, create a new clock for that ?)
1101239281Sgonzo		 *  - HSIC_P1_480      (HSIC only, create a new clock for that ?)
1102239281Sgonzo		 *  - HSIC_P2_60       (HSIC only, create a new clock for that ?)
1103239281Sgonzo		 *  - HSIC_P2_480      (HSIC only, create a new clock for that ?)
1104239281Sgonzo		 */
1105239281Sgonzo
1106239281Sgonzo		/* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
1107239281Sgonzo		clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
1108239281Sgonzo		clksel_reg_off = L3INIT_CM2_OFFSET + 0x58;
1109239281Sgonzo		clksel = bus_read_4(clk_mem_res, clksel_reg_off);
1110239281Sgonzo		/* Enable the module and also enable the optional func clocks */
1111239281Sgonzo		if (clkdev->id == USBHSHOST_CLK) {
1112239281Sgonzo			clksel &= ~CLKCTRL_MODULEMODE_MASK;
1113239281Sgonzo			clksel |=  /*CLKCTRL_MODULEMODE_ENABLE*/2;
1114239281Sgonzo
1115239281Sgonzo			clksel |= (0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */
1116239281Sgonzo		}
1117239281Sgonzo
1118239281Sgonzo		else if (clkdev->id == USBP1_UTMI_CLK)
1119239281Sgonzo			clksel |= (0x1 << 8);  /* UTMI_P1_CLK */
1120239281Sgonzo		else if (clkdev->id == USBP2_UTMI_CLK)
1121239281Sgonzo			clksel |= (0x1 << 9);  /* UTMI_P2_CLK */
1122239281Sgonzo
1123239281Sgonzo		else if (clkdev->id == USBP1_HSIC_CLK)
1124239281Sgonzo			clksel |= (0x5 << 11);  /* HSIC60M_P1_CLK + HSIC480M_P1_CLK */
1125239281Sgonzo		else if (clkdev->id == USBP2_HSIC_CLK)
1126239281Sgonzo			clksel |= (0x5 << 12);  /* HSIC60M_P2_CLK + HSIC480M_P2_CLK */
1127239281Sgonzo
1128239281Sgonzo		break;
1129239281Sgonzo
1130239281Sgonzo	default:
1131239281Sgonzo		return (EINVAL);
1132239281Sgonzo	}
1133239281Sgonzo
1134239281Sgonzo	bus_write_4(clk_mem_res, clksel_reg_off, clksel);
1135239281Sgonzo
1136239281Sgonzo	/* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */
1137239281Sgonzo	for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) {
1138239281Sgonzo		clksel = bus_read_4(clk_mem_res, clksel_reg_off);
1139239281Sgonzo		if ((clksel & CLKCTRL_IDLEST_MASK) == CLKCTRL_IDLEST_ENABLED)
1140239281Sgonzo			break;
1141239281Sgonzo	}
1142239281Sgonzo
1143239281Sgonzo	/* Check the enabled state */
1144239281Sgonzo	if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED) {
1145239281Sgonzo		printf("Error: HERE failed to enable module with clock %d\n", clkdev->id);
1146239281Sgonzo		printf("Error: 0x%08x => 0x%08x\n", clksel_reg_off, clksel);
1147239281Sgonzo		return (ETIMEDOUT);
1148239281Sgonzo	}
1149239281Sgonzo
1150239281Sgonzo	return (0);
1151239281Sgonzo}
1152239281Sgonzo
1153239281Sgonzo/**
1154239281Sgonzo *	omap4_clk_generic_deactivate - checks if a module is accessible
1155239281Sgonzo *	@clkdev: pointer to the clock device structure.
1156249586Sgabor *	@mem_res: array of memory resources allocated by the top level PRCM driver.
1157239281Sgonzo *
1158239281Sgonzo *
1159239281Sgonzo *
1160239281Sgonzo *	LOCKING:
1161239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
1162239281Sgonzo *
1163239281Sgonzo *	RETURNS:
1164239281Sgonzo *	Returns 0 on success or a positive error code on failure.
1165239281Sgonzo */
1166239281Sgonzostatic int
1167239281Sgonzoomap4_clk_hsusbhost_deactivate(struct ti_clock_dev *clkdev)
1168239281Sgonzo{
1169239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
1170239281Sgonzo	struct resource* clk_mem_res;
1171239281Sgonzo	uint32_t clksel_reg_off;
1172239281Sgonzo	uint32_t clksel;
1173239281Sgonzo
1174239281Sgonzo	if (sc == NULL)
1175239281Sgonzo		return ENXIO;
1176239281Sgonzo
1177239281Sgonzo	switch (clkdev->id) {
1178239281Sgonzo	case USBTLL_CLK:
1179239281Sgonzo		/* We need the CM_L3INIT_HSUSBTLL_CLKCTRL register in CM2 register set */
1180239281Sgonzo		clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
1181239281Sgonzo		clksel_reg_off = L3INIT_CM2_OFFSET + 0x68;
1182239281Sgonzo
1183239281Sgonzo		clksel = bus_read_4(clk_mem_res, clksel_reg_off);
1184239281Sgonzo		clksel &= ~CLKCTRL_MODULEMODE_MASK;
1185239281Sgonzo		clksel |=  CLKCTRL_MODULEMODE_DISABLE;
1186239281Sgonzo		break;
1187239281Sgonzo
1188239281Sgonzo	case USBHSHOST_CLK:
1189239281Sgonzo	case USBP1_PHY_CLK:
1190239281Sgonzo	case USBP2_PHY_CLK:
1191239281Sgonzo	case USBP1_UTMI_CLK:
1192239281Sgonzo	case USBP2_UTMI_CLK:
1193239281Sgonzo	case USBP1_HSIC_CLK:
1194239281Sgonzo	case USBP2_HSIC_CLK:
1195239281Sgonzo		/* For the USB HS HOST module we need to enable the following clocks:
1196239281Sgonzo		 *  - INIT_L4_ICLK     (will be enabled by bootloader)
1197239281Sgonzo		 *  - INIT_L3_ICLK     (will be enabled by bootloader)
1198239281Sgonzo		 *  - INIT_48MC_FCLK
1199239281Sgonzo		 *  - UTMI_ROOT_GFCLK  (UTMI only, create a new clock for that ?)
1200239281Sgonzo		 *  - UTMI_P1_FCLK     (UTMI only, create a new clock for that ?)
1201239281Sgonzo		 *  - UTMI_P2_FCLK     (UTMI only, create a new clock for that ?)
1202239281Sgonzo		 *  - HSIC_P1_60       (HSIC only, create a new clock for that ?)
1203239281Sgonzo		 *  - HSIC_P1_480      (HSIC only, create a new clock for that ?)
1204239281Sgonzo		 *  - HSIC_P2_60       (HSIC only, create a new clock for that ?)
1205239281Sgonzo		 *  - HSIC_P2_480      (HSIC only, create a new clock for that ?)
1206239281Sgonzo		 */
1207239281Sgonzo
1208239281Sgonzo		/* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
1209239281Sgonzo		clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
1210239281Sgonzo		clksel_reg_off = L3INIT_CM2_OFFSET + 0x58;
1211239281Sgonzo		clksel = bus_read_4(clk_mem_res, clksel_reg_off);
1212239281Sgonzo
1213239281Sgonzo		/* Enable the module and also enable the optional func clocks */
1214239281Sgonzo		if (clkdev->id == USBHSHOST_CLK) {
1215239281Sgonzo			clksel &= ~CLKCTRL_MODULEMODE_MASK;
1216239281Sgonzo			clksel |=  CLKCTRL_MODULEMODE_DISABLE;
1217239281Sgonzo
1218239281Sgonzo			clksel &= ~(0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */
1219239281Sgonzo		}
1220239281Sgonzo
1221239281Sgonzo		else if (clkdev->id == USBP1_UTMI_CLK)
1222239281Sgonzo			clksel &= ~(0x1 << 8);  /* UTMI_P1_CLK */
1223239281Sgonzo		else if (clkdev->id == USBP2_UTMI_CLK)
1224239281Sgonzo			clksel &= ~(0x1 << 9);  /* UTMI_P2_CLK */
1225239281Sgonzo
1226239281Sgonzo		else if (clkdev->id == USBP1_HSIC_CLK)
1227239281Sgonzo			clksel &= ~(0x5 << 11);  /* HSIC60M_P1_CLK + HSIC480M_P1_CLK */
1228239281Sgonzo		else if (clkdev->id == USBP2_HSIC_CLK)
1229239281Sgonzo			clksel &= ~(0x5 << 12);  /* HSIC60M_P2_CLK + HSIC480M_P2_CLK */
1230239281Sgonzo
1231239281Sgonzo		break;
1232239281Sgonzo
1233239281Sgonzo	default:
1234239281Sgonzo		return (EINVAL);
1235239281Sgonzo	}
1236239281Sgonzo
1237239281Sgonzo	bus_write_4(clk_mem_res, clksel_reg_off, clksel);
1238239281Sgonzo
1239239281Sgonzo	return (0);
1240239281Sgonzo}
1241239281Sgonzo
1242239281Sgonzo/**
1243239281Sgonzo *	omap4_clk_hsusbhost_accessible - checks if a module is accessible
1244239281Sgonzo *	@clkdev: pointer to the clock device structure.
1245249586Sgabor *	@mem_res: array of memory resources allocated by the top level PRCM driver.
1246239281Sgonzo *
1247239281Sgonzo *
1248239281Sgonzo *
1249239281Sgonzo *	LOCKING:
1250239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
1251239281Sgonzo *
1252239281Sgonzo *	RETURNS:
1253239281Sgonzo *	Returns 0 if module is not enable, 1 if module is enabled or a negative
1254239281Sgonzo *	error code on failure.
1255239281Sgonzo */
1256239281Sgonzostatic int
1257239281Sgonzoomap4_clk_hsusbhost_accessible(struct ti_clock_dev *clkdev)
1258239281Sgonzo{
1259239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
1260239281Sgonzo	struct resource* clk_mem_res;
1261239281Sgonzo	uint32_t clksel_reg_off;
1262239281Sgonzo	uint32_t clksel;
1263239281Sgonzo
1264239281Sgonzo	if (sc == NULL)
1265239281Sgonzo		return ENXIO;
1266239281Sgonzo
1267239281Sgonzo	if (clkdev->id == USBTLL_CLK) {
1268239281Sgonzo		/* We need the CM_L3INIT_HSUSBTLL_CLKCTRL register in CM2 register set */
1269239281Sgonzo		clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
1270239281Sgonzo		clksel_reg_off = L3INIT_CM2_OFFSET + 0x68;
1271239281Sgonzo	}
1272239281Sgonzo	else if (clkdev->id == USBHSHOST_CLK) {
1273239281Sgonzo		/* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
1274239281Sgonzo		clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
1275239281Sgonzo		clksel_reg_off = L3INIT_CM2_OFFSET + 0x58;
1276239281Sgonzo	}
1277239281Sgonzo	else {
1278239281Sgonzo		return (EINVAL);
1279239281Sgonzo	}
1280239281Sgonzo
1281239281Sgonzo	clksel = bus_read_4(clk_mem_res, clksel_reg_off);
1282239281Sgonzo
1283239281Sgonzo	/* Check the enabled state */
1284239281Sgonzo	if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED)
1285239281Sgonzo		return (0);
1286239281Sgonzo
1287239281Sgonzo	return (1);
1288239281Sgonzo}
1289239281Sgonzo
1290239281Sgonzo/**
1291239281Sgonzo *	omap4_clk_hsusbhost_set_source - sets the source clocks
1292239281Sgonzo *	@clkdev: pointer to the clock device structure.
1293239281Sgonzo *	@clksrc: the clock source ID for the given clock.
1294249586Sgabor *	@mem_res: array of memory resources allocated by the top level PRCM driver.
1295239281Sgonzo *
1296239281Sgonzo *
1297239281Sgonzo *
1298239281Sgonzo *	LOCKING:
1299239281Sgonzo *	Inherits the locks from the omap_prcm driver, no internal locking.
1300239281Sgonzo *
1301239281Sgonzo *	RETURNS:
1302239281Sgonzo *	Returns 0 if sucessful otherwise a negative error code on failure.
1303239281Sgonzo */
1304239281Sgonzostatic int
1305239281Sgonzoomap4_clk_hsusbhost_set_source(struct ti_clock_dev *clkdev,
1306239281Sgonzo                               clk_src_t clksrc)
1307239281Sgonzo{
1308239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
1309239281Sgonzo	struct resource* clk_mem_res;
1310239281Sgonzo	uint32_t clksel_reg_off;
1311239281Sgonzo	uint32_t clksel;
1312239281Sgonzo	unsigned int bit;
1313239281Sgonzo
1314239281Sgonzo	if (sc == NULL)
1315239281Sgonzo		return ENXIO;
1316239281Sgonzo
1317239281Sgonzo	if (clkdev->id == USBP1_PHY_CLK)
1318239281Sgonzo		bit = 24;
1319239281Sgonzo	else if (clkdev->id != USBP2_PHY_CLK)
1320239281Sgonzo		bit = 25;
1321239281Sgonzo	else
1322239281Sgonzo		return (EINVAL);
1323239281Sgonzo
1324239281Sgonzo	/* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
1325239281Sgonzo	clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
1326239281Sgonzo	clksel_reg_off = L3INIT_CM2_OFFSET + 0x58;
1327239281Sgonzo	clksel = bus_read_4(clk_mem_res, clksel_reg_off);
1328239281Sgonzo
1329239281Sgonzo	/* Set the clock source to either external or internal */
1330239281Sgonzo	if (clksrc == EXT_CLK)
1331239281Sgonzo		clksel |= (0x1 << bit);
1332239281Sgonzo	else
1333239281Sgonzo		clksel &= ~(0x1 << bit);
1334239281Sgonzo
1335239281Sgonzo	bus_write_4(clk_mem_res, clksel_reg_off, clksel);
1336239281Sgonzo
1337239281Sgonzo	return (0);
1338239281Sgonzo}
1339239281Sgonzo
1340239281Sgonzo#define PRM_RSTCTRL		0x1b00
1341239281Sgonzo#define PRM_RSTCTRL_RESET	0x2
1342239281Sgonzo
1343239281Sgonzostatic void
1344239281Sgonzoomap4_prcm_reset(void)
1345239281Sgonzo{
1346239281Sgonzo	struct omap4_prcm_softc *sc = omap4_prcm_sc;
1347239281Sgonzo	bus_write_4(sc->sc_res[0], PRM_RSTCTRL,
1348239281Sgonzo	    bus_read_4(sc->sc_res[0], PRM_RSTCTRL) | PRM_RSTCTRL_RESET);
1349239281Sgonzo	bus_read_4(sc->sc_res[0], PRM_RSTCTRL);
1350239281Sgonzo}
1351239281Sgonzo
1352239281Sgonzo/**
1353239281Sgonzo *	omap4_prcm_probe - probe function for the driver
1354239281Sgonzo *	@dev: prcm device handle
1355239281Sgonzo *
1356239281Sgonzo *	Simply sets the name of the driver module.
1357239281Sgonzo *
1358239281Sgonzo *	LOCKING:
1359239281Sgonzo *	None
1360239281Sgonzo *
1361239281Sgonzo *	RETURNS:
1362239281Sgonzo *	Always returns 0
1363239281Sgonzo */
1364239281Sgonzostatic int
1365239281Sgonzoomap4_prcm_probe(device_t dev)
1366239281Sgonzo{
1367239281Sgonzo	if (!ofw_bus_is_compatible(dev, "ti,omap4_prcm"))
1368239281Sgonzo		return (ENXIO);
1369239281Sgonzo
1370239281Sgonzo	device_set_desc(dev, "TI OMAP Power, Reset and Clock Management");
1371239281Sgonzo	return (0);
1372239281Sgonzo}
1373239281Sgonzo
1374239281Sgonzo/**
1375239281Sgonzo *	omap_prcm_attach - attach function for the driver
1376239281Sgonzo *	@dev: prcm device handle
1377239281Sgonzo *
1378239281Sgonzo *	Allocates and sets up the driver context, this simply entails creating a
1379239281Sgonzo *	bus mappings for the PRCM register set.
1380239281Sgonzo *
1381239281Sgonzo *	LOCKING:
1382239281Sgonzo *	None
1383239281Sgonzo *
1384239281Sgonzo *	RETURNS:
1385239281Sgonzo *	Always returns 0
1386239281Sgonzo */
1387253971Scognet
1388253971Scognetextern uint32_t platform_arm_tmr_freq;
1389253971Scognet
1390239281Sgonzostatic int
1391239281Sgonzoomap4_prcm_attach(device_t dev)
1392239281Sgonzo{
1393239281Sgonzo	struct omap4_prcm_softc *sc = device_get_softc(dev);
1394253971Scognet	unsigned int freq;
1395239281Sgonzo
1396239281Sgonzo	if (bus_alloc_resources(dev, omap4_scm_res_spec, sc->sc_res)) {
1397239281Sgonzo		device_printf(dev, "could not allocate resources\n");
1398239281Sgonzo		return (ENXIO);
1399239281Sgonzo	}
1400239281Sgonzo
1401239281Sgonzo	omap4_prcm_sc = sc;
1402239281Sgonzo	ti_cpu_reset = omap4_prcm_reset;
1403253971Scognet	omap4_clk_get_arm_fclk_freq(NULL, &freq);
1404253971Scognet	platform_arm_tmr_freq = freq / 2;
1405239281Sgonzo
1406239281Sgonzo	return (0);
1407239281Sgonzo}
1408239281Sgonzo
1409239281Sgonzostatic device_method_t omap4_prcm_methods[] = {
1410239281Sgonzo	DEVMETHOD(device_probe, omap4_prcm_probe),
1411239281Sgonzo	DEVMETHOD(device_attach, omap4_prcm_attach),
1412239281Sgonzo	{0, 0},
1413239281Sgonzo};
1414239281Sgonzo
1415239281Sgonzostatic driver_t omap4_prcm_driver = {
1416239281Sgonzo	"omap4_prcm",
1417239281Sgonzo	omap4_prcm_methods,
1418239281Sgonzo	sizeof(struct omap4_prcm_softc),
1419239281Sgonzo};
1420239281Sgonzo
1421239281Sgonzostatic devclass_t omap4_prcm_devclass;
1422239281Sgonzo
1423239281SgonzoDRIVER_MODULE(omap4_prcm, simplebus, omap4_prcm_driver, omap4_prcm_devclass, 0, 0);
1424239281SgonzoMODULE_VERSION(omap4_prcm, 1);
1425