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 #define L4_34XX_BASE 0x48000000
21 #include <linux/types.h>
23 /* ----------------------------------- Host OS */
24 #include <dspbridge/host_os.h>
25 #include <plat/dmtimer.h>
26 #include <linux/platform_data/asoc-ti-mcbsp.h>
28 /* ----------------------------------- DSP/BIOS Bridge */
29 #include <dspbridge/dbdefs.h>
30 #include <dspbridge/drv.h>
31 #include <dspbridge/dev.h>
34 /* ----------------------------------- This */
35 #include <dspbridge/clk.h>
37 /* ----------------------------------- Defines, Data Structures, Typedefs */
39 #define OMAP_SSI_OFFSET 0x58000
40 #define OMAP_SSI_SIZE 0x1000
41 #define OMAP_SSI_SYSCONFIG_OFFSET 0x10
43 #define SSI_AUTOIDLE (1 << 0)
44 #define SSI_SIDLE_SMARTIDLE (2 << 3)
45 #define SSI_MIDLE_NOIDLE (1 << 12)
47 /* Clk types requested by the dsp */
54 /* Bridge GPT id (1 - 4), DM Timer id (5 - 8) */
55 #define DMT_ID(id) ((id) + 4)
56 #define DM_TIMER_CLOCKS 4
58 /* Bridge MCBSP id (6 - 10), OMAP Mcbsp id (0 - 4) */
59 #define MCBSP_ID(id) ((id) - 6)
61 static struct omap_dm_timer
*timer
[4];
71 static struct dsp_ssi ssi
;
73 static u32 dsp_clocks
;
75 static inline u32
is_dsp_clk_active(u32 clk
, u8 id
)
77 return clk
& (1 << id
);
80 static inline void set_dsp_clk_active(u32
*clk
, u8 id
)
85 static inline void set_dsp_clk_inactive(u32
*clk
, u8 id
)
90 static s8
get_clk_type(u8 id
)
94 if (id
== DSP_CLK_IVA2
)
96 else if (id
<= DSP_CLK_GPT8
)
98 else if (id
== DSP_CLK_WDT3
)
100 else if (id
<= DSP_CLK_MCBSP5
)
102 else if (id
== DSP_CLK_SSI
)
111 * ======== dsp_clk_exit ========
113 * Cleanup CLK module.
115 void dsp_clk_exit(void)
119 dsp_clock_disable_all(dsp_clocks
);
121 for (i
= 0; i
< DM_TIMER_CLOCKS
; i
++)
122 omap_dm_timer_free(timer
[i
]);
124 clk_unprepare(iva2_clk
);
126 clk_unprepare(ssi
.sst_fck
);
127 clk_put(ssi
.sst_fck
);
128 clk_unprepare(ssi
.ssr_fck
);
129 clk_put(ssi
.ssr_fck
);
130 clk_unprepare(ssi
.ick
);
135 * ======== dsp_clk_init ========
137 * Initialize CLK module.
139 void dsp_clk_init(void)
141 static struct platform_device dspbridge_device
;
144 dspbridge_device
.dev
.bus
= &platform_bus_type
;
146 for (i
= 0, id
= 5; i
< DM_TIMER_CLOCKS
; i
++, id
++)
147 timer
[i
] = omap_dm_timer_request_specific(id
);
149 iva2_clk
= clk_get(&dspbridge_device
.dev
, "iva2_ck");
150 if (IS_ERR(iva2_clk
))
151 dev_err(bridge
, "failed to get iva2 clock %p\n", iva2_clk
);
153 clk_prepare(iva2_clk
);
155 ssi
.sst_fck
= clk_get(&dspbridge_device
.dev
, "ssi_sst_fck");
156 ssi
.ssr_fck
= clk_get(&dspbridge_device
.dev
, "ssi_ssr_fck");
157 ssi
.ick
= clk_get(&dspbridge_device
.dev
, "ssi_ick");
159 if (IS_ERR(ssi
.sst_fck
) || IS_ERR(ssi
.ssr_fck
) || IS_ERR(ssi
.ick
)) {
160 dev_err(bridge
, "failed to get ssi: sst %p, ssr %p, ick %p\n",
161 ssi
.sst_fck
, ssi
.ssr_fck
, ssi
.ick
);
163 clk_prepare(ssi
.sst_fck
);
164 clk_prepare(ssi
.ssr_fck
);
165 clk_prepare(ssi
.ick
);
170 * dsp_gpt_wait_overflow - set gpt overflow and wait for fixed timeout
171 * @clk_id: GP Timer clock id.
172 * @load: Overflow value.
174 * Sets an overflow interrupt for the desired GPT waiting for a timeout
175 * of 5 msecs for the interrupt to occur.
177 void dsp_gpt_wait_overflow(short int clk_id
, unsigned int load
)
179 struct omap_dm_timer
*gpt
= timer
[clk_id
- 1];
180 unsigned long timeout
;
185 /* Enable overflow interrupt */
186 omap_dm_timer_set_int_enable(gpt
, OMAP_TIMER_INT_OVERFLOW
);
189 * Set counter value to overflow counter after
190 * one tick and start timer.
192 omap_dm_timer_set_load_start(gpt
, 0, load
);
194 /* Wait 80us for timer to overflow */
197 timeout
= msecs_to_jiffies(5);
198 /* Check interrupt status and wait for interrupt */
199 while (!(omap_dm_timer_read_status(gpt
) & OMAP_TIMER_INT_OVERFLOW
)) {
200 if (time_is_after_jiffies(timeout
)) {
201 pr_err("%s: GPTimer interrupt failed\n", __func__
);
208 * ======== dsp_clk_enable ========
213 int dsp_clk_enable(enum dsp_clk_id clk_id
)
217 if (is_dsp_clk_active(dsp_clocks
, clk_id
)) {
218 dev_err(bridge
, "WARN: clock id %d already enabled\n", clk_id
);
222 switch (get_clk_type(clk_id
)) {
224 clk_enable(iva2_clk
);
227 status
= omap_dm_timer_start(timer
[clk_id
- 1]);
229 #ifdef CONFIG_OMAP_MCBSP
231 omap_mcbsp_request(MCBSP_ID(clk_id
));
232 omap2_mcbsp_set_clks_src(MCBSP_ID(clk_id
), MCBSP_CLKS_PAD_SRC
);
236 dev_err(bridge
, "ERROR: DSP requested to enable WDT3 clk\n");
239 clk_enable(ssi
.sst_fck
);
240 clk_enable(ssi
.ssr_fck
);
244 * The SSI module need to configured not to have the Forced
245 * idle for master interface. If it is set to forced idle,
246 * the SSI module is transitioning to standby thereby causing
247 * the client in the DSP hang waiting for the SSI module to
248 * be active after enabling the clocks
250 ssi_clk_prepare(true);
253 dev_err(bridge
, "Invalid clock id for enable\n");
258 set_dsp_clk_active(&dsp_clocks
, clk_id
);
265 * dsp_clock_enable_all - Enable clocks used by the DSP
266 * @dev_context Driver's device context strucure
268 * This function enables all the peripheral clocks that were requested by DSP.
270 u32
dsp_clock_enable_all(u32 dsp_per_clocks
)
275 for (clk_id
= 0; clk_id
< DSP_CLK_NOT_DEFINED
; clk_id
++) {
276 if (is_dsp_clk_active(dsp_per_clocks
, clk_id
))
277 status
= dsp_clk_enable(clk_id
);
284 * ======== dsp_clk_disable ========
289 int dsp_clk_disable(enum dsp_clk_id clk_id
)
293 if (!is_dsp_clk_active(dsp_clocks
, clk_id
)) {
294 dev_err(bridge
, "ERR: clock id %d already disabled\n", clk_id
);
298 switch (get_clk_type(clk_id
)) {
300 clk_disable(iva2_clk
);
303 status
= omap_dm_timer_stop(timer
[clk_id
- 1]);
305 #ifdef CONFIG_OMAP_MCBSP
307 omap2_mcbsp_set_clks_src(MCBSP_ID(clk_id
), MCBSP_CLKS_PRCM_SRC
);
308 omap_mcbsp_free(MCBSP_ID(clk_id
));
312 dev_err(bridge
, "ERROR: DSP requested to disable WDT3 clk\n");
315 ssi_clk_prepare(false);
316 ssi_clk_prepare(false);
317 clk_disable(ssi
.sst_fck
);
318 clk_disable(ssi
.ssr_fck
);
319 clk_disable(ssi
.ick
);
322 dev_err(bridge
, "Invalid clock id for disable\n");
327 set_dsp_clk_inactive(&dsp_clocks
, clk_id
);
334 * dsp_clock_disable_all - Disable all active clocks
335 * @dev_context Driver's device context structure
337 * This function disables all the peripheral clocks that were enabled by DSP.
338 * It is meant to be called only when DSP is entering hibernation or when DSP
341 u32
dsp_clock_disable_all(u32 dsp_per_clocks
)
346 for (clk_id
= 0; clk_id
< DSP_CLK_NOT_DEFINED
; clk_id
++) {
347 if (is_dsp_clk_active(dsp_per_clocks
, clk_id
))
348 status
= dsp_clk_disable(clk_id
);
354 u32
dsp_clk_get_iva2_rate(void)
358 clk_speed_khz
= clk_get_rate(iva2_clk
);
359 clk_speed_khz
/= 1000;
360 dev_dbg(bridge
, "%s: clk speed Khz = %d\n", __func__
, clk_speed_khz
);
362 return clk_speed_khz
;
365 void ssi_clk_prepare(bool FLAG
)
367 void __iomem
*ssi_base
;
370 ssi_base
= ioremap(L4_34XX_BASE
+ OMAP_SSI_OFFSET
, OMAP_SSI_SIZE
);
372 pr_err("%s: error, SSI not configured\n", __func__
);
377 /* Set Autoidle, SIDLEMode to smart idle, and MIDLEmode to
380 value
= SSI_AUTOIDLE
| SSI_SIDLE_SMARTIDLE
| SSI_MIDLE_NOIDLE
;
382 /* Set Autoidle, SIDLEMode to forced idle, and MIDLEmode to
385 value
= SSI_AUTOIDLE
;
388 __raw_writel(value
, ssi_base
+ OMAP_SSI_SYSCONFIG_OFFSET
);