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