]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/staging/tidspbridge/core/dsp-clock.c
Merge branch 'zImage_DTB_append' of git://git.linaro.org/people/nico/linux into devel...
[mirror_ubuntu-bionic-kernel.git] / drivers / staging / tidspbridge / core / dsp-clock.c
CommitLineData
999e07d6
ORL
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
2094f12d
NM
19#include <linux/types.h>
20
999e07d6
ORL
21/* ----------------------------------- Host OS */
22#include <dspbridge/host_os.h>
23#include <plat/dmtimer.h>
24#include <plat/mcbsp.h>
25
26/* ----------------------------------- DSP/BIOS Bridge */
999e07d6 27#include <dspbridge/dbdefs.h>
999e07d6
ORL
28#include <dspbridge/drv.h>
29#include <dspbridge/dev.h>
30#include "_tiomap.h"
31
32/* ----------------------------------- Trace & Debug */
33#include <dspbridge/dbc.h>
34
35/* ----------------------------------- This */
36#include <dspbridge/clk.h>
37
38/* ----------------------------------- Defines, Data Structures, Typedefs */
39
40#define OMAP_SSI_OFFSET 0x58000
41#define OMAP_SSI_SIZE 0x1000
42#define OMAP_SSI_SYSCONFIG_OFFSET 0x10
43
44#define SSI_AUTOIDLE (1 << 0)
45#define SSI_SIDLE_SMARTIDLE (2 << 3)
46#define SSI_MIDLE_NOIDLE (1 << 12)
47
48/* Clk types requested by the dsp */
49#define IVA2_CLK 0
50#define GPT_CLK 1
51#define WDT_CLK 2
52#define MCBSP_CLK 3
53#define SSI_CLK 4
54
55/* Bridge GPT id (1 - 4), DM Timer id (5 - 8) */
56#define DMT_ID(id) ((id) + 4)
57
58/* Bridge MCBSP id (6 - 10), OMAP Mcbsp id (0 - 4) */
59#define MCBSP_ID(id) ((id) - 6)
60
61static struct omap_dm_timer *timer[4];
62
63struct clk *iva2_clk;
64
65struct dsp_ssi {
66 struct clk *sst_fck;
67 struct clk *ssr_fck;
68 struct clk *ick;
69};
70
71static struct dsp_ssi ssi;
72
73static u32 dsp_clocks;
74
75static inline u32 is_dsp_clk_active(u32 clk, u8 id)
76{
77 return clk & (1 << id);
78}
79
80static inline void set_dsp_clk_active(u32 *clk, u8 id)
81{
82 *clk |= (1 << id);
83}
84
85static inline void set_dsp_clk_inactive(u32 *clk, u8 id)
86{
87 *clk &= ~(1 << id);
88}
89
90static s8 get_clk_type(u8 id)
91{
92 s8 type;
93
94 if (id == DSP_CLK_IVA2)
95 type = IVA2_CLK;
96 else if (id <= DSP_CLK_GPT8)
97 type = GPT_CLK;
98 else if (id == DSP_CLK_WDT3)
99 type = WDT_CLK;
100 else if (id <= DSP_CLK_MCBSP5)
101 type = MCBSP_CLK;
102 else if (id == DSP_CLK_SSI)
103 type = SSI_CLK;
104 else
105 type = -1;
106
107 return type;
108}
109
110/*
111 * ======== dsp_clk_exit ========
112 * Purpose:
113 * Cleanup CLK module.
114 */
115void dsp_clk_exit(void)
116{
117 dsp_clock_disable_all(dsp_clocks);
118
119 clk_put(iva2_clk);
120 clk_put(ssi.sst_fck);
121 clk_put(ssi.ssr_fck);
122 clk_put(ssi.ick);
123}
124
125/*
126 * ======== dsp_clk_init ========
127 * Purpose:
128 * Initialize CLK module.
129 */
130void dsp_clk_init(void)
131{
132 static struct platform_device dspbridge_device;
133
134 dspbridge_device.dev.bus = &platform_bus_type;
135
136 iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck");
137 if (IS_ERR(iva2_clk))
138 dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk);
139
140 ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck");
141 ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck");
142 ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick");
143
144 if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick))
145 dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n",
146 ssi.sst_fck, ssi.ssr_fck, ssi.ick);
147}
148
999e07d6
ORL
149/**
150 * dsp_gpt_wait_overflow - set gpt overflow and wait for fixed timeout
151 * @clk_id: GP Timer clock id.
152 * @load: Overflow value.
153 *
154 * Sets an overflow interrupt for the desired GPT waiting for a timeout
155 * of 5 msecs for the interrupt to occur.
156 */
157void dsp_gpt_wait_overflow(short int clk_id, unsigned int load)
158{
159 struct omap_dm_timer *gpt = timer[clk_id - 1];
160 unsigned long timeout;
161
162 if (!gpt)
163 return;
164
165 /* Enable overflow interrupt */
166 omap_dm_timer_set_int_enable(gpt, OMAP_TIMER_INT_OVERFLOW);
167
168 /*
169 * Set counter value to overflow counter after
170 * one tick and start timer.
171 */
172 omap_dm_timer_set_load_start(gpt, 0, load);
173
174 /* Wait 80us for timer to overflow */
175 udelay(80);
176
177 timeout = msecs_to_jiffies(5);
178 /* Check interrupt status and wait for interrupt */
179 while (!(omap_dm_timer_read_status(gpt) & OMAP_TIMER_INT_OVERFLOW)) {
180 if (time_is_after_jiffies(timeout)) {
181 pr_err("%s: GPTimer interrupt failed\n", __func__);
182 break;
183 }
184 }
185}
186
187/*
188 * ======== dsp_clk_enable ========
189 * Purpose:
190 * Enable Clock .
191 *
192 */
9d7d0a52 193int dsp_clk_enable(enum dsp_clk_id clk_id)
999e07d6
ORL
194{
195 int status = 0;
196
197 if (is_dsp_clk_active(dsp_clocks, clk_id)) {
198 dev_err(bridge, "WARN: clock id %d already enabled\n", clk_id);
199 goto out;
200 }
201
202 switch (get_clk_type(clk_id)) {
203 case IVA2_CLK:
204 clk_enable(iva2_clk);
205 break;
206 case GPT_CLK:
207 timer[clk_id - 1] =
208 omap_dm_timer_request_specific(DMT_ID(clk_id));
209 break;
210#ifdef CONFIG_OMAP_MCBSP
211 case MCBSP_CLK:
999e07d6 212 omap_mcbsp_request(MCBSP_ID(clk_id));
81ea18ec 213 omap2_mcbsp_set_clks_src(MCBSP_ID(clk_id), MCBSP_CLKS_PAD_SRC);
999e07d6
ORL
214 break;
215#endif
216 case WDT_CLK:
217 dev_err(bridge, "ERROR: DSP requested to enable WDT3 clk\n");
218 break;
219 case SSI_CLK:
220 clk_enable(ssi.sst_fck);
221 clk_enable(ssi.ssr_fck);
222 clk_enable(ssi.ick);
223
224 /*
225 * The SSI module need to configured not to have the Forced
226 * idle for master interface. If it is set to forced idle,
227 * the SSI module is transitioning to standby thereby causing
228 * the client in the DSP hang waiting for the SSI module to
229 * be active after enabling the clocks
230 */
231 ssi_clk_prepare(true);
232 break;
233 default:
234 dev_err(bridge, "Invalid clock id for enable\n");
235 status = -EPERM;
236 }
237
e6486d8c 238 if (!status)
999e07d6
ORL
239 set_dsp_clk_active(&dsp_clocks, clk_id);
240
241out:
242 return status;
243}
244
245/**
246 * dsp_clock_enable_all - Enable clocks used by the DSP
247 * @dev_context Driver's device context strucure
248 *
249 * This function enables all the peripheral clocks that were requested by DSP.
250 */
251u32 dsp_clock_enable_all(u32 dsp_per_clocks)
252{
253 u32 clk_id;
254 u32 status = -EPERM;
255
256 for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
257 if (is_dsp_clk_active(dsp_per_clocks, clk_id))
258 status = dsp_clk_enable(clk_id);
259 }
260
261 return status;
262}
263
264/*
265 * ======== dsp_clk_disable ========
266 * Purpose:
267 * Disable the clock.
268 *
269 */
9d7d0a52 270int dsp_clk_disable(enum dsp_clk_id clk_id)
999e07d6
ORL
271{
272 int status = 0;
273
274 if (!is_dsp_clk_active(dsp_clocks, clk_id)) {
275 dev_err(bridge, "ERR: clock id %d already disabled\n", clk_id);
276 goto out;
277 }
278
279 switch (get_clk_type(clk_id)) {
280 case IVA2_CLK:
281 clk_disable(iva2_clk);
282 break;
283 case GPT_CLK:
284 omap_dm_timer_free(timer[clk_id - 1]);
285 break;
286#ifdef CONFIG_OMAP_MCBSP
287 case MCBSP_CLK:
81ea18ec 288 omap2_mcbsp_set_clks_src(MCBSP_ID(clk_id), MCBSP_CLKS_PRCM_SRC);
999e07d6
ORL
289 omap_mcbsp_free(MCBSP_ID(clk_id));
290 break;
291#endif
292 case WDT_CLK:
293 dev_err(bridge, "ERROR: DSP requested to disable WDT3 clk\n");
294 break;
295 case SSI_CLK:
296 ssi_clk_prepare(false);
297 ssi_clk_prepare(false);
298 clk_disable(ssi.sst_fck);
299 clk_disable(ssi.ssr_fck);
300 clk_disable(ssi.ick);
301 break;
302 default:
303 dev_err(bridge, "Invalid clock id for disable\n");
304 status = -EPERM;
305 }
306
e6486d8c 307 if (!status)
999e07d6
ORL
308 set_dsp_clk_inactive(&dsp_clocks, clk_id);
309
310out:
311 return status;
312}
313
314/**
315 * dsp_clock_disable_all - Disable all active clocks
316 * @dev_context Driver's device context structure
317 *
318 * This function disables all the peripheral clocks that were enabled by DSP.
319 * It is meant to be called only when DSP is entering hibernation or when DSP
320 * is in error state.
321 */
322u32 dsp_clock_disable_all(u32 dsp_per_clocks)
323{
324 u32 clk_id;
325 u32 status = -EPERM;
326
327 for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
328 if (is_dsp_clk_active(dsp_per_clocks, clk_id))
329 status = dsp_clk_disable(clk_id);
330 }
331
332 return status;
333}
334
335u32 dsp_clk_get_iva2_rate(void)
336{
337 u32 clk_speed_khz;
338
339 clk_speed_khz = clk_get_rate(iva2_clk);
340 clk_speed_khz /= 1000;
341 dev_dbg(bridge, "%s: clk speed Khz = %d\n", __func__, clk_speed_khz);
342
343 return clk_speed_khz;
344}
345
346void ssi_clk_prepare(bool FLAG)
347{
348 void __iomem *ssi_base;
349 unsigned int value;
350
351 ssi_base = ioremap(L4_34XX_BASE + OMAP_SSI_OFFSET, OMAP_SSI_SIZE);
352 if (!ssi_base) {
353 pr_err("%s: error, SSI not configured\n", __func__);
354 return;
355 }
356
357 if (FLAG) {
358 /* Set Autoidle, SIDLEMode to smart idle, and MIDLEmode to
359 * no idle
360 */
361 value = SSI_AUTOIDLE | SSI_SIDLE_SMARTIDLE | SSI_MIDLE_NOIDLE;
362 } else {
363 /* Set Autoidle, SIDLEMode to forced idle, and MIDLEmode to
364 * forced idle
365 */
366 value = SSI_AUTOIDLE;
367 }
368
369 __raw_writel(value, ssi_base + OMAP_SSI_SYSCONFIG_OFFSET);
370 iounmap(ssi_base);
371}
372