4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * Clock and Timer services.
8 * Copyright (C) 2005-2006 Texas Instruments, Inc.
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.
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.
19 #include <linux/types.h>
21 /* ----------------------------------- Host OS */
22 #include <dspbridge/host_os.h>
23 #include <plat/dmtimer.h>
24 #include <plat/mcbsp.h>
26 /* ----------------------------------- DSP/BIOS Bridge */
27 #include <dspbridge/dbdefs.h>
28 #include <dspbridge/drv.h>
29 #include <dspbridge/dev.h>
32 /* ----------------------------------- Trace & Debug */
33 #include <dspbridge/dbc.h>
35 /* ----------------------------------- This */
36 #include <dspbridge/clk.h>
38 /* ----------------------------------- Defines, Data Structures, Typedefs */
40 #define OMAP_SSI_OFFSET 0x58000
41 #define OMAP_SSI_SIZE 0x1000
42 #define OMAP_SSI_SYSCONFIG_OFFSET 0x10
44 #define SSI_AUTOIDLE (1 << 0)
45 #define SSI_SIDLE_SMARTIDLE (2 << 3)
46 #define SSI_MIDLE_NOIDLE (1 << 12)
48 /* Clk types requested by the dsp */
55 /* Bridge GPT id (1 - 4), DM Timer id (5 - 8) */
56 #define DMT_ID(id) ((id) + 4)
57 #define DM_TIMER_CLOCKS 4
59 /* Bridge MCBSP id (6 - 10), OMAP Mcbsp id (0 - 4) */
60 #define MCBSP_ID(id) ((id) - 6)
62 static struct omap_dm_timer *timer[4];
72 static struct dsp_ssi ssi;
74 static u32 dsp_clocks;
76 static inline u32 is_dsp_clk_active(u32 clk, u8 id)
78 return clk & (1 << id);
81 static inline void set_dsp_clk_active(u32 *clk, u8 id)
86 static inline void set_dsp_clk_inactive(u32 *clk, u8 id)
91 static s8 get_clk_type(u8 id)
95 if (id == DSP_CLK_IVA2)
97 else if (id <= DSP_CLK_GPT8)
99 else if (id == DSP_CLK_WDT3)
101 else if (id <= DSP_CLK_MCBSP5)
103 else if (id == DSP_CLK_SSI)
112 * ======== dsp_clk_exit ========
114 * Cleanup CLK module.
116 void dsp_clk_exit(void)
120 dsp_clock_disable_all(dsp_clocks);
122 for (i = 0; i < DM_TIMER_CLOCKS; i++)
123 omap_dm_timer_free(timer[i]);
126 clk_put(ssi.sst_fck);
127 clk_put(ssi.ssr_fck);
132 * ======== dsp_clk_init ========
134 * Initialize CLK module.
136 void dsp_clk_init(void)
138 static struct platform_device dspbridge_device;
141 dspbridge_device.dev.bus = &platform_bus_type;
143 for (i = 0, id = 5; i < DM_TIMER_CLOCKS; i++, id++)
144 timer[i] = omap_dm_timer_request_specific(id);
146 iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck");
147 if (IS_ERR(iva2_clk))
148 dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk);
150 ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck");
151 ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck");
152 ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick");
154 if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick))
155 dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n",
156 ssi.sst_fck, ssi.ssr_fck, ssi.ick);
160 * dsp_gpt_wait_overflow - set gpt overflow and wait for fixed timeout
161 * @clk_id: GP Timer clock id.
162 * @load: Overflow value.
164 * Sets an overflow interrupt for the desired GPT waiting for a timeout
165 * of 5 msecs for the interrupt to occur.
167 void dsp_gpt_wait_overflow(short int clk_id, unsigned int load)
169 struct omap_dm_timer *gpt = timer[clk_id - 1];
170 unsigned long timeout;
175 /* Enable overflow interrupt */
176 omap_dm_timer_set_int_enable(gpt, OMAP_TIMER_INT_OVERFLOW);
179 * Set counter value to overflow counter after
180 * one tick and start timer.
182 omap_dm_timer_set_load_start(gpt, 0, load);
184 /* Wait 80us for timer to overflow */
187 timeout = msecs_to_jiffies(5);
188 /* Check interrupt status and wait for interrupt */
189 while (!(omap_dm_timer_read_status(gpt) & OMAP_TIMER_INT_OVERFLOW)) {
190 if (time_is_after_jiffies(timeout)) {
191 pr_err("%s: GPTimer interrupt failed\n", __func__);
198 * ======== dsp_clk_enable ========
203 int dsp_clk_enable(enum dsp_clk_id clk_id)
207 if (is_dsp_clk_active(dsp_clocks, clk_id)) {
208 dev_err(bridge, "WARN: clock id %d already enabled\n", clk_id);
212 switch (get_clk_type(clk_id)) {
214 clk_enable(iva2_clk);
217 status = omap_dm_timer_start(timer[clk_id - 1]);
219 #ifdef CONFIG_OMAP_MCBSP
221 omap_mcbsp_request(MCBSP_ID(clk_id));
222 omap2_mcbsp_set_clks_src(MCBSP_ID(clk_id), MCBSP_CLKS_PAD_SRC);
226 dev_err(bridge, "ERROR: DSP requested to enable WDT3 clk\n");
229 clk_enable(ssi.sst_fck);
230 clk_enable(ssi.ssr_fck);
234 * The SSI module need to configured not to have the Forced
235 * idle for master interface. If it is set to forced idle,
236 * the SSI module is transitioning to standby thereby causing
237 * the client in the DSP hang waiting for the SSI module to
238 * be active after enabling the clocks
240 ssi_clk_prepare(true);
243 dev_err(bridge, "Invalid clock id for enable\n");
248 set_dsp_clk_active(&dsp_clocks, clk_id);
255 * dsp_clock_enable_all - Enable clocks used by the DSP
256 * @dev_context Driver's device context strucure
258 * This function enables all the peripheral clocks that were requested by DSP.
260 u32 dsp_clock_enable_all(u32 dsp_per_clocks)
265 for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
266 if (is_dsp_clk_active(dsp_per_clocks, clk_id))
267 status = dsp_clk_enable(clk_id);
274 * ======== dsp_clk_disable ========
279 int dsp_clk_disable(enum dsp_clk_id clk_id)
283 if (!is_dsp_clk_active(dsp_clocks, clk_id)) {
284 dev_err(bridge, "ERR: clock id %d already disabled\n", clk_id);
288 switch (get_clk_type(clk_id)) {
290 clk_disable(iva2_clk);
293 status = omap_dm_timer_stop(timer[clk_id - 1]);
295 #ifdef CONFIG_OMAP_MCBSP
297 omap2_mcbsp_set_clks_src(MCBSP_ID(clk_id), MCBSP_CLKS_PRCM_SRC);
298 omap_mcbsp_free(MCBSP_ID(clk_id));
302 dev_err(bridge, "ERROR: DSP requested to disable WDT3 clk\n");
305 ssi_clk_prepare(false);
306 ssi_clk_prepare(false);
307 clk_disable(ssi.sst_fck);
308 clk_disable(ssi.ssr_fck);
309 clk_disable(ssi.ick);
312 dev_err(bridge, "Invalid clock id for disable\n");
317 set_dsp_clk_inactive(&dsp_clocks, clk_id);
324 * dsp_clock_disable_all - Disable all active clocks
325 * @dev_context Driver's device context structure
327 * This function disables all the peripheral clocks that were enabled by DSP.
328 * It is meant to be called only when DSP is entering hibernation or when DSP
331 u32 dsp_clock_disable_all(u32 dsp_per_clocks)
336 for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
337 if (is_dsp_clk_active(dsp_per_clocks, clk_id))
338 status = dsp_clk_disable(clk_id);
344 u32 dsp_clk_get_iva2_rate(void)
348 clk_speed_khz = clk_get_rate(iva2_clk);
349 clk_speed_khz /= 1000;
350 dev_dbg(bridge, "%s: clk speed Khz = %d\n", __func__, clk_speed_khz);
352 return clk_speed_khz;
355 void ssi_clk_prepare(bool FLAG)
357 void __iomem *ssi_base;
360 ssi_base = ioremap(L4_34XX_BASE + OMAP_SSI_OFFSET, OMAP_SSI_SIZE);
362 pr_err("%s: error, SSI not configured\n", __func__);
367 /* Set Autoidle, SIDLEMode to smart idle, and MIDLEmode to
370 value = SSI_AUTOIDLE | SSI_SIDLE_SMARTIDLE | SSI_MIDLE_NOIDLE;
372 /* Set Autoidle, SIDLEMode to forced idle, and MIDLEmode to
375 value = SSI_AUTOIDLE;
378 __raw_writel(value, ssi_base + OMAP_SSI_SYSCONFIG_OFFSET);