• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/staging/tidspbridge/core/
1/*
2 * clk.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * Clock and Timer services.
7 *
8 * Copyright (C) 2005-2006 Texas Instruments, Inc.
9 *
10 * This package is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 */
18
19#include <linux/types.h>
20
21/*  ----------------------------------- Host OS */
22#include <dspbridge/host_os.h>
23#include <plat/dmtimer.h>
24#include <plat/mcbsp.h>
25
26/*  ----------------------------------- DSP/BIOS Bridge */
27#include <dspbridge/dbdefs.h>
28#include <dspbridge/cfg.h>
29#include <dspbridge/drv.h>
30#include <dspbridge/dev.h>
31#include "_tiomap.h"
32
33/*  ----------------------------------- Trace & Debug */
34#include <dspbridge/dbc.h>
35
36/*  ----------------------------------- This */
37#include <dspbridge/clk.h>
38
39/*  ----------------------------------- Defines, Data Structures, Typedefs */
40
41#define OMAP_SSI_OFFSET			0x58000
42#define OMAP_SSI_SIZE			0x1000
43#define OMAP_SSI_SYSCONFIG_OFFSET	0x10
44
45#define SSI_AUTOIDLE			(1 << 0)
46#define SSI_SIDLE_SMARTIDLE		(2 << 3)
47#define SSI_MIDLE_NOIDLE		(1 << 12)
48
49/* Clk types requested by the dsp */
50#define IVA2_CLK	0
51#define GPT_CLK		1
52#define WDT_CLK		2
53#define MCBSP_CLK	3
54#define SSI_CLK		4
55
56/* Bridge GPT id (1 - 4), DM Timer id (5 - 8) */
57#define DMT_ID(id) ((id) + 4)
58
59/* Bridge MCBSP id (6 - 10), OMAP Mcbsp id (0 - 4) */
60#define MCBSP_ID(id) ((id) - 6)
61
62static struct omap_dm_timer *timer[4];
63
64struct clk *iva2_clk;
65
66struct dsp_ssi {
67	struct clk *sst_fck;
68	struct clk *ssr_fck;
69	struct clk *ick;
70};
71
72static struct dsp_ssi ssi;
73
74static u32 dsp_clocks;
75
76static inline u32 is_dsp_clk_active(u32 clk, u8 id)
77{
78	return clk & (1 << id);
79}
80
81static inline void set_dsp_clk_active(u32 *clk, u8 id)
82{
83	*clk |= (1 << id);
84}
85
86static inline void set_dsp_clk_inactive(u32 *clk, u8 id)
87{
88	*clk &= ~(1 << id);
89}
90
91static s8 get_clk_type(u8 id)
92{
93	s8 type;
94
95	if (id == DSP_CLK_IVA2)
96		type = IVA2_CLK;
97	else if (id <= DSP_CLK_GPT8)
98		type = GPT_CLK;
99	else if (id == DSP_CLK_WDT3)
100		type = WDT_CLK;
101	else if (id <= DSP_CLK_MCBSP5)
102		type = MCBSP_CLK;
103	else if (id == DSP_CLK_SSI)
104		type = SSI_CLK;
105	else
106		type = -1;
107
108	return type;
109}
110
111/*
112 *  ======== dsp_clk_exit ========
113 *  Purpose:
114 *      Cleanup CLK module.
115 */
116void dsp_clk_exit(void)
117{
118	dsp_clock_disable_all(dsp_clocks);
119
120	clk_put(iva2_clk);
121	clk_put(ssi.sst_fck);
122	clk_put(ssi.ssr_fck);
123	clk_put(ssi.ick);
124}
125
126/*
127 *  ======== dsp_clk_init ========
128 *  Purpose:
129 *      Initialize CLK module.
130 */
131void dsp_clk_init(void)
132{
133	static struct platform_device dspbridge_device;
134
135	dspbridge_device.dev.bus = &platform_bus_type;
136
137	iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck");
138	if (IS_ERR(iva2_clk))
139		dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk);
140
141	ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck");
142	ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck");
143	ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick");
144
145	if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick))
146		dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n",
147					ssi.sst_fck, ssi.ssr_fck, ssi.ick);
148}
149
150#ifdef CONFIG_OMAP_MCBSP
151static void mcbsp_clk_prepare(bool flag, u8 id)
152{
153	struct cfg_hostres *resources;
154	struct dev_object *hdev_object = NULL;
155	struct bridge_dev_context *bridge_context = NULL;
156	u32 val;
157
158	hdev_object = (struct dev_object *)drv_get_first_dev_object();
159	if (!hdev_object)
160		return;
161
162	dev_get_bridge_context(hdev_object, &bridge_context);
163	if (!bridge_context)
164		return;
165
166	resources = bridge_context->resources;
167	if (!resources)
168		return;
169
170	if (flag) {
171		if (id == DSP_CLK_MCBSP1) {
172			/* set MCBSP1_CLKS, on McBSP1 ON */
173			val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
174			val |= 1 << 2;
175			__raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
176		} else if (id == DSP_CLK_MCBSP2) {
177			/* set MCBSP2_CLKS, on McBSP2 ON */
178			val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
179			val |= 1 << 6;
180			__raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
181		}
182	} else {
183		if (id == DSP_CLK_MCBSP1) {
184			/* clear MCBSP1_CLKS, on McBSP1 OFF */
185			val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
186			val &= ~(1 << 2);
187			__raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
188		} else if (id == DSP_CLK_MCBSP2) {
189			/* clear MCBSP2_CLKS, on McBSP2 OFF */
190			val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
191			val &= ~(1 << 6);
192			__raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
193		}
194	}
195}
196#endif
197
198/**
199 * dsp_gpt_wait_overflow - set gpt overflow and wait for fixed timeout
200 * @clk_id:      GP Timer clock id.
201 * @load:        Overflow value.
202 *
203 * Sets an overflow interrupt for the desired GPT waiting for a timeout
204 * of 5 msecs for the interrupt to occur.
205 */
206void dsp_gpt_wait_overflow(short int clk_id, unsigned int load)
207{
208	struct omap_dm_timer *gpt = timer[clk_id - 1];
209	unsigned long timeout;
210
211	if (!gpt)
212		return;
213
214	/* Enable overflow interrupt */
215	omap_dm_timer_set_int_enable(gpt, OMAP_TIMER_INT_OVERFLOW);
216
217	/*
218	 * Set counter value to overflow counter after
219	 * one tick and start timer.
220	 */
221	omap_dm_timer_set_load_start(gpt, 0, load);
222
223	/* Wait 80us for timer to overflow */
224	udelay(80);
225
226	timeout = msecs_to_jiffies(5);
227	/* Check interrupt status and wait for interrupt */
228	while (!(omap_dm_timer_read_status(gpt) & OMAP_TIMER_INT_OVERFLOW)) {
229		if (time_is_after_jiffies(timeout)) {
230			pr_err("%s: GPTimer interrupt failed\n", __func__);
231			break;
232		}
233	}
234}
235
236/*
237 *  ======== dsp_clk_enable ========
238 *  Purpose:
239 *      Enable Clock .
240 *
241 */
242int dsp_clk_enable(enum dsp_clk_id clk_id)
243{
244	int status = 0;
245
246	if (is_dsp_clk_active(dsp_clocks, clk_id)) {
247		dev_err(bridge, "WARN: clock id %d already enabled\n", clk_id);
248		goto out;
249	}
250
251	switch (get_clk_type(clk_id)) {
252	case IVA2_CLK:
253		clk_enable(iva2_clk);
254		break;
255	case GPT_CLK:
256		timer[clk_id - 1] =
257				omap_dm_timer_request_specific(DMT_ID(clk_id));
258		break;
259#ifdef CONFIG_OMAP_MCBSP
260	case MCBSP_CLK:
261		mcbsp_clk_prepare(true, clk_id);
262		omap_mcbsp_set_io_type(MCBSP_ID(clk_id), OMAP_MCBSP_POLL_IO);
263		omap_mcbsp_request(MCBSP_ID(clk_id));
264		break;
265#endif
266	case WDT_CLK:
267		dev_err(bridge, "ERROR: DSP requested to enable WDT3 clk\n");
268		break;
269	case SSI_CLK:
270		clk_enable(ssi.sst_fck);
271		clk_enable(ssi.ssr_fck);
272		clk_enable(ssi.ick);
273
274		/*
275		 * The SSI module need to configured not to have the Forced
276		 * idle for master interface. If it is set to forced idle,
277		 * the SSI module is transitioning to standby thereby causing
278		 * the client in the DSP hang waiting for the SSI module to
279		 * be active after enabling the clocks
280		 */
281		ssi_clk_prepare(true);
282		break;
283	default:
284		dev_err(bridge, "Invalid clock id for enable\n");
285		status = -EPERM;
286	}
287
288	if (!status)
289		set_dsp_clk_active(&dsp_clocks, clk_id);
290
291out:
292	return status;
293}
294
295/**
296 * dsp_clock_enable_all - Enable clocks used by the DSP
297 * @dev_context		Driver's device context strucure
298 *
299 * This function enables all the peripheral clocks that were requested by DSP.
300 */
301u32 dsp_clock_enable_all(u32 dsp_per_clocks)
302{
303	u32 clk_id;
304	u32 status = -EPERM;
305
306	for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
307		if (is_dsp_clk_active(dsp_per_clocks, clk_id))
308			status = dsp_clk_enable(clk_id);
309	}
310
311	return status;
312}
313
314/*
315 *  ======== dsp_clk_disable ========
316 *  Purpose:
317 *      Disable the clock.
318 *
319 */
320int dsp_clk_disable(enum dsp_clk_id clk_id)
321{
322	int status = 0;
323
324	if (!is_dsp_clk_active(dsp_clocks, clk_id)) {
325		dev_err(bridge, "ERR: clock id %d already disabled\n", clk_id);
326		goto out;
327	}
328
329	switch (get_clk_type(clk_id)) {
330	case IVA2_CLK:
331		clk_disable(iva2_clk);
332		break;
333	case GPT_CLK:
334		omap_dm_timer_free(timer[clk_id - 1]);
335		break;
336#ifdef CONFIG_OMAP_MCBSP
337	case MCBSP_CLK:
338		mcbsp_clk_prepare(false, clk_id);
339		omap_mcbsp_free(MCBSP_ID(clk_id));
340		break;
341#endif
342	case WDT_CLK:
343		dev_err(bridge, "ERROR: DSP requested to disable WDT3 clk\n");
344		break;
345	case SSI_CLK:
346		ssi_clk_prepare(false);
347		ssi_clk_prepare(false);
348		clk_disable(ssi.sst_fck);
349		clk_disable(ssi.ssr_fck);
350		clk_disable(ssi.ick);
351		break;
352	default:
353		dev_err(bridge, "Invalid clock id for disable\n");
354		status = -EPERM;
355	}
356
357	if (!status)
358		set_dsp_clk_inactive(&dsp_clocks, clk_id);
359
360out:
361	return status;
362}
363
364/**
365 * dsp_clock_disable_all - Disable all active clocks
366 * @dev_context		Driver's device context structure
367 *
368 * This function disables all the peripheral clocks that were enabled by DSP.
369 * It is meant to be called only when DSP is entering hibernation or when DSP
370 * is in error state.
371 */
372u32 dsp_clock_disable_all(u32 dsp_per_clocks)
373{
374	u32 clk_id;
375	u32 status = -EPERM;
376
377	for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
378		if (is_dsp_clk_active(dsp_per_clocks, clk_id))
379			status = dsp_clk_disable(clk_id);
380	}
381
382	return status;
383}
384
385u32 dsp_clk_get_iva2_rate(void)
386{
387	u32 clk_speed_khz;
388
389	clk_speed_khz = clk_get_rate(iva2_clk);
390	clk_speed_khz /= 1000;
391	dev_dbg(bridge, "%s: clk speed Khz = %d\n", __func__, clk_speed_khz);
392
393	return clk_speed_khz;
394}
395
396void ssi_clk_prepare(bool FLAG)
397{
398	void __iomem *ssi_base;
399	unsigned int value;
400
401	ssi_base = ioremap(L4_34XX_BASE + OMAP_SSI_OFFSET, OMAP_SSI_SIZE);
402	if (!ssi_base) {
403		pr_err("%s: error, SSI not configured\n", __func__);
404		return;
405	}
406
407	if (FLAG) {
408		/* Set Autoidle, SIDLEMode to smart idle, and MIDLEmode to
409		 * no idle
410		 */
411		value = SSI_AUTOIDLE | SSI_SIDLE_SMARTIDLE | SSI_MIDLE_NOIDLE;
412	} else {
413		/* Set Autoidle, SIDLEMode to forced idle, and MIDLEmode to
414		 * forced idle
415		 */
416		value = SSI_AUTOIDLE;
417	}
418
419	__raw_writel(value, ssi_base + OMAP_SSI_SYSCONFIG_OFFSET);
420	iounmap(ssi_base);
421}
422