Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dsp-clock.c
Go to the documentation of this file.
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 #define L4_34XX_BASE 0x48000000
20 
21 #include <linux/types.h>
22 
23 /* ----------------------------------- Host OS */
24 #include <dspbridge/host_os.h>
25 #include <plat/dmtimer.h>
27 
28 /* ----------------------------------- DSP/BIOS Bridge */
29 #include <dspbridge/dbdefs.h>
30 #include <dspbridge/drv.h>
31 #include <dspbridge/dev.h>
32 #include "_tiomap.h"
33 
34 /* ----------------------------------- This */
35 #include <dspbridge/clk.h>
36 
37 /* ----------------------------------- Defines, Data Structures, Typedefs */
38 
39 #define OMAP_SSI_OFFSET 0x58000
40 #define OMAP_SSI_SIZE 0x1000
41 #define OMAP_SSI_SYSCONFIG_OFFSET 0x10
42 
43 #define SSI_AUTOIDLE (1 << 0)
44 #define SSI_SIDLE_SMARTIDLE (2 << 3)
45 #define SSI_MIDLE_NOIDLE (1 << 12)
46 
47 /* Clk types requested by the dsp */
48 #define IVA2_CLK 0
49 #define GPT_CLK 1
50 #define WDT_CLK 2
51 #define MCBSP_CLK 3
52 #define SSI_CLK 4
53 
54 /* Bridge GPT id (1 - 4), DM Timer id (5 - 8) */
55 #define DMT_ID(id) ((id) + 4)
56 #define DM_TIMER_CLOCKS 4
57 
58 /* Bridge MCBSP id (6 - 10), OMAP Mcbsp id (0 - 4) */
59 #define MCBSP_ID(id) ((id) - 6)
60 
61 static struct omap_dm_timer *timer[4];
62 
63 struct clk *iva2_clk;
64 
65 struct dsp_ssi {
66  struct clk *sst_fck;
67  struct clk *ssr_fck;
68  struct clk *ick;
69 };
70 
71 static struct dsp_ssi ssi;
72 
73 static u32 dsp_clocks;
74 
75 static inline u32 is_dsp_clk_active(u32 clk, u8 id)
76 {
77  return clk & (1 << id);
78 }
79 
80 static inline void set_dsp_clk_active(u32 *clk, u8 id)
81 {
82  *clk |= (1 << id);
83 }
84 
85 static inline void set_dsp_clk_inactive(u32 *clk, u8 id)
86 {
87  *clk &= ~(1 << id);
88 }
89 
90 static 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  */
115 void dsp_clk_exit(void)
116 {
117  int i;
118 
119  dsp_clock_disable_all(dsp_clocks);
120 
121  for (i = 0; i < DM_TIMER_CLOCKS; i++)
122  omap_dm_timer_free(timer[i]);
123 
124  clk_put(iva2_clk);
125  clk_put(ssi.sst_fck);
126  clk_put(ssi.ssr_fck);
127  clk_put(ssi.ick);
128 }
129 
130 /*
131  * ======== dsp_clk_init ========
132  * Purpose:
133  * Initialize CLK module.
134  */
135 void dsp_clk_init(void)
136 {
137  static struct platform_device dspbridge_device;
138  int i, id;
139 
140  dspbridge_device.dev.bus = &platform_bus_type;
141 
142  for (i = 0, id = 5; i < DM_TIMER_CLOCKS; i++, id++)
143  timer[i] = omap_dm_timer_request_specific(id);
144 
145  iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck");
146  if (IS_ERR(iva2_clk))
147  dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk);
148 
149  ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck");
150  ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck");
151  ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick");
152 
153  if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick))
154  dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n",
155  ssi.sst_fck, ssi.ssr_fck, ssi.ick);
156 }
157 
166 void dsp_gpt_wait_overflow(short int clk_id, unsigned int load)
167 {
168  struct omap_dm_timer *gpt = timer[clk_id - 1];
169  unsigned long timeout;
170 
171  if (!gpt)
172  return;
173 
174  /* Enable overflow interrupt */
176 
177  /*
178  * Set counter value to overflow counter after
179  * one tick and start timer.
180  */
181  omap_dm_timer_set_load_start(gpt, 0, load);
182 
183  /* Wait 80us for timer to overflow */
184  udelay(80);
185 
186  timeout = msecs_to_jiffies(5);
187  /* Check interrupt status and wait for interrupt */
189  if (time_is_after_jiffies(timeout)) {
190  pr_err("%s: GPTimer interrupt failed\n", __func__);
191  break;
192  }
193  }
194 }
195 
196 /*
197  * ======== dsp_clk_enable ========
198  * Purpose:
199  * Enable Clock .
200  *
201  */
202 int dsp_clk_enable(enum dsp_clk_id clk_id)
203 {
204  int status = 0;
205 
206  if (is_dsp_clk_active(dsp_clocks, clk_id)) {
207  dev_err(bridge, "WARN: clock id %d already enabled\n", clk_id);
208  goto out;
209  }
210 
211  switch (get_clk_type(clk_id)) {
212  case IVA2_CLK:
213  clk_enable(iva2_clk);
214  break;
215  case GPT_CLK:
216  status = omap_dm_timer_start(timer[clk_id - 1]);
217  break;
218 #ifdef CONFIG_OMAP_MCBSP
219  case MCBSP_CLK:
220  omap_mcbsp_request(MCBSP_ID(clk_id));
222  break;
223 #endif
224  case WDT_CLK:
225  dev_err(bridge, "ERROR: DSP requested to enable WDT3 clk\n");
226  break;
227  case SSI_CLK:
228  clk_enable(ssi.sst_fck);
229  clk_enable(ssi.ssr_fck);
230  clk_enable(ssi.ick);
231 
232  /*
233  * The SSI module need to configured not to have the Forced
234  * idle for master interface. If it is set to forced idle,
235  * the SSI module is transitioning to standby thereby causing
236  * the client in the DSP hang waiting for the SSI module to
237  * be active after enabling the clocks
238  */
239  ssi_clk_prepare(true);
240  break;
241  default:
242  dev_err(bridge, "Invalid clock id for enable\n");
243  status = -EPERM;
244  }
245 
246  if (!status)
247  set_dsp_clk_active(&dsp_clocks, clk_id);
248 
249 out:
250  return status;
251 }
252 
259 u32 dsp_clock_enable_all(u32 dsp_per_clocks)
260 {
261  u32 clk_id;
262  u32 status = -EPERM;
263 
264  for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
265  if (is_dsp_clk_active(dsp_per_clocks, clk_id))
266  status = dsp_clk_enable(clk_id);
267  }
268 
269  return status;
270 }
271 
272 /*
273  * ======== dsp_clk_disable ========
274  * Purpose:
275  * Disable the clock.
276  *
277  */
278 int dsp_clk_disable(enum dsp_clk_id clk_id)
279 {
280  int status = 0;
281 
282  if (!is_dsp_clk_active(dsp_clocks, clk_id)) {
283  dev_err(bridge, "ERR: clock id %d already disabled\n", clk_id);
284  goto out;
285  }
286 
287  switch (get_clk_type(clk_id)) {
288  case IVA2_CLK:
289  clk_disable(iva2_clk);
290  break;
291  case GPT_CLK:
292  status = omap_dm_timer_stop(timer[clk_id - 1]);
293  break;
294 #ifdef CONFIG_OMAP_MCBSP
295  case MCBSP_CLK:
297  omap_mcbsp_free(MCBSP_ID(clk_id));
298  break;
299 #endif
300  case WDT_CLK:
301  dev_err(bridge, "ERROR: DSP requested to disable WDT3 clk\n");
302  break;
303  case SSI_CLK:
304  ssi_clk_prepare(false);
305  ssi_clk_prepare(false);
306  clk_disable(ssi.sst_fck);
307  clk_disable(ssi.ssr_fck);
308  clk_disable(ssi.ick);
309  break;
310  default:
311  dev_err(bridge, "Invalid clock id for disable\n");
312  status = -EPERM;
313  }
314 
315  if (!status)
316  set_dsp_clk_inactive(&dsp_clocks, clk_id);
317 
318 out:
319  return status;
320 }
321 
331 {
332  u32 clk_id;
333  u32 status = -EPERM;
334 
335  for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
336  if (is_dsp_clk_active(dsp_per_clocks, clk_id))
337  status = dsp_clk_disable(clk_id);
338  }
339 
340  return status;
341 }
342 
344 {
345  u32 clk_speed_khz;
346 
347  clk_speed_khz = clk_get_rate(iva2_clk);
348  clk_speed_khz /= 1000;
349  dev_dbg(bridge, "%s: clk speed Khz = %d\n", __func__, clk_speed_khz);
350 
351  return clk_speed_khz;
352 }
353 
355 {
356  void __iomem *ssi_base;
357  unsigned int value;
358 
360  if (!ssi_base) {
361  pr_err("%s: error, SSI not configured\n", __func__);
362  return;
363  }
364 
365  if (FLAG) {
366  /* Set Autoidle, SIDLEMode to smart idle, and MIDLEmode to
367  * no idle
368  */
370  } else {
371  /* Set Autoidle, SIDLEMode to forced idle, and MIDLEmode to
372  * forced idle
373  */
374  value = SSI_AUTOIDLE;
375  }
376 
377  __raw_writel(value, ssi_base + OMAP_SSI_SYSCONFIG_OFFSET);
378  iounmap(ssi_base);
379 }
380