Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tiomap_io.c
Go to the documentation of this file.
1 /*
2  * tiomap_io.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * Implementation for the io read/write routines.
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 
20 
21 /* ----------------------------------- DSP/BIOS Bridge */
22 #include <dspbridge/dbdefs.h>
23 
24 /* ----------------------------------- Platform Manager */
25 #include <dspbridge/dev.h>
26 #include <dspbridge/drv.h>
27 
28 /* ----------------------------------- OS Adaptation Layer */
29 #include <dspbridge/wdt.h>
30 
31 /* ----------------------------------- specific to this file */
32 #include "_tiomap.h"
33 #include "_tiomap_pwr.h"
34 #include "tiomap_io.h"
35 
36 static u32 ul_ext_base;
37 static u32 ul_ext_end;
38 
39 static u32 shm0_end;
40 static u32 ul_dyn_ext_base;
41 static u32 ul_trace_sec_beg;
42 static u32 ul_trace_sec_end;
43 static u32 ul_shm_base_virt;
44 
45 bool symbols_reloaded = true;
46 
47 /*
48  * ======== read_ext_dsp_data ========
49  * Copies DSP external memory buffers to the host side buffers.
50  */
52  u8 *host_buff, u32 dsp_addr,
53  u32 ul_num_bytes, u32 mem_type)
54 {
55  int status = 0;
56  struct bridge_dev_context *dev_context = dev_ctxt;
57  u32 offset;
58  u32 ul_tlb_base_virt = 0;
59  u32 ul_shm_offset_virt = 0;
60  u32 dw_ext_prog_virt_mem;
61  u32 dw_base_addr = dev_context->dsp_ext_base_addr;
62  bool trace_read = false;
63 
64  if (!ul_shm_base_virt) {
65  status = dev_get_symbol(dev_context->dev_obj,
66  SHMBASENAME, &ul_shm_base_virt);
67  }
68 
69  /* Check if it is a read of Trace section */
70  if (!status && !ul_trace_sec_beg) {
71  status = dev_get_symbol(dev_context->dev_obj,
72  DSP_TRACESEC_BEG, &ul_trace_sec_beg);
73  }
74 
75  if (!status && !ul_trace_sec_end) {
76  status = dev_get_symbol(dev_context->dev_obj,
77  DSP_TRACESEC_END, &ul_trace_sec_end);
78  }
79 
80  if (!status) {
81  if ((dsp_addr <= ul_trace_sec_end) &&
82  (dsp_addr >= ul_trace_sec_beg))
83  trace_read = true;
84  }
85 
86  /* If reading from TRACE, force remap/unmap */
87  if (trace_read && dw_base_addr) {
88  dw_base_addr = 0;
89  dev_context->dsp_ext_base_addr = 0;
90  }
91 
92  if (!dw_base_addr) {
93  /* Initialize ul_ext_base and ul_ext_end */
94  ul_ext_base = 0;
95  ul_ext_end = 0;
96 
97  /* Get DYNEXT_BEG, EXT_BEG and EXT_END. */
98  if (!status && !ul_dyn_ext_base) {
99  status = dev_get_symbol(dev_context->dev_obj,
100  DYNEXTBASE, &ul_dyn_ext_base);
101  }
102 
103  if (!status) {
104  status = dev_get_symbol(dev_context->dev_obj,
105  EXTBASE, &ul_ext_base);
106  }
107 
108  if (!status) {
109  status = dev_get_symbol(dev_context->dev_obj,
110  EXTEND, &ul_ext_end);
111  }
112 
113  /* Trace buffer is right after the shm SEG0,
114  * so set the base address to SHMBASE */
115  if (trace_read) {
116  ul_ext_base = ul_shm_base_virt;
117  ul_ext_end = ul_trace_sec_end;
118  }
119 
120 
121  if (ul_ext_end < ul_ext_base)
122  status = -EPERM;
123 
124  if (!status) {
125  ul_tlb_base_virt =
126  dev_context->atlb_entry[0].dsp_va * DSPWORDSIZE;
127  dw_ext_prog_virt_mem =
128  dev_context->atlb_entry[0].gpp_va;
129 
130  if (!trace_read) {
131  ul_shm_offset_virt =
132  ul_shm_base_virt - ul_tlb_base_virt;
133  ul_shm_offset_virt +=
134  PG_ALIGN_HIGH(ul_ext_end - ul_dyn_ext_base +
135  1, HW_PAGE_SIZE64KB);
136  dw_ext_prog_virt_mem -= ul_shm_offset_virt;
137  dw_ext_prog_virt_mem +=
138  (ul_ext_base - ul_dyn_ext_base);
139  dev_context->dsp_ext_base_addr =
140  dw_ext_prog_virt_mem;
141 
142  /*
143  * This dsp_ext_base_addr will get cleared
144  * only when the board is stopped.
145  */
146  if (!dev_context->dsp_ext_base_addr)
147  status = -EPERM;
148  }
149 
150  dw_base_addr = dw_ext_prog_virt_mem;
151  }
152  }
153 
154  if (!dw_base_addr || !ul_ext_base || !ul_ext_end)
155  status = -EPERM;
156 
157  offset = dsp_addr - ul_ext_base;
158 
159  if (!status)
160  memcpy(host_buff, (u8 *) dw_base_addr + offset, ul_num_bytes);
161 
162  return status;
163 }
164 
165 /*
166  * ======== write_dsp_data ========
167  * purpose:
168  * Copies buffers to the DSP internal/external memory.
169  */
170 int write_dsp_data(struct bridge_dev_context *dev_context,
171  u8 *host_buff, u32 dsp_addr, u32 ul_num_bytes,
172  u32 mem_type)
173 {
174  u32 offset;
175  u32 dw_base_addr = dev_context->dsp_base_addr;
176  struct cfg_hostres *resources = dev_context->resources;
177  int status = 0;
178  u32 base1, base2, base3;
179  base1 = OMAP_DSP_MEM1_SIZE;
182 
183  if (!resources)
184  return -EPERM;
185 
186  offset = dsp_addr - dev_context->dsp_start_add;
187  if (offset < base1) {
188  dw_base_addr = MEM_LINEAR_ADDRESS(resources->mem_base[2],
189  resources->mem_length[2]);
190  } else if (offset > base1 && offset < base2 + OMAP_DSP_MEM2_SIZE) {
191  dw_base_addr = MEM_LINEAR_ADDRESS(resources->mem_base[3],
192  resources->mem_length[3]);
193  offset = offset - base2;
194  } else if (offset >= base2 + OMAP_DSP_MEM2_SIZE &&
195  offset < base3 + OMAP_DSP_MEM3_SIZE) {
196  dw_base_addr = MEM_LINEAR_ADDRESS(resources->mem_base[4],
197  resources->mem_length[4]);
198  offset = offset - base3;
199  } else {
200  return -EPERM;
201  }
202  if (ul_num_bytes)
203  memcpy((u8 *) (dw_base_addr + offset), host_buff, ul_num_bytes);
204  else
205  *((u32 *) host_buff) = dw_base_addr + offset;
206 
207  return status;
208 }
209 
210 /*
211  * ======== write_ext_dsp_data ========
212  * purpose:
213  * Copies buffers to the external memory.
214  *
215  */
216 int write_ext_dsp_data(struct bridge_dev_context *dev_context,
217  u8 *host_buff, u32 dsp_addr,
218  u32 ul_num_bytes, u32 mem_type,
219  bool dynamic_load)
220 {
221  u32 dw_base_addr = dev_context->dsp_ext_base_addr;
222  u32 dw_offset = 0;
223  u8 temp_byte1, temp_byte2;
224  u8 remain_byte[4];
225  s32 i;
226  int ret = 0;
227  u32 dw_ext_prog_virt_mem;
228  u32 ul_tlb_base_virt = 0;
229  u32 ul_shm_offset_virt = 0;
230  struct cfg_hostres *host_res = dev_context->resources;
231  bool trace_load = false;
232  temp_byte1 = 0x0;
233  temp_byte2 = 0x0;
234 
235  if (symbols_reloaded) {
236  /* Check if it is a load to Trace section */
237  ret = dev_get_symbol(dev_context->dev_obj,
238  DSP_TRACESEC_BEG, &ul_trace_sec_beg);
239  if (!ret)
240  ret = dev_get_symbol(dev_context->dev_obj,
242  &ul_trace_sec_end);
243  }
244  if (!ret) {
245  if ((dsp_addr <= ul_trace_sec_end) &&
246  (dsp_addr >= ul_trace_sec_beg))
247  trace_load = true;
248  }
249 
250  /* If dynamic, force remap/unmap */
251  if ((dynamic_load || trace_load) && dw_base_addr) {
252  dw_base_addr = 0;
253  MEM_UNMAP_LINEAR_ADDRESS((void *)
254  dev_context->dsp_ext_base_addr);
255  dev_context->dsp_ext_base_addr = 0x0;
256  }
257  if (!dw_base_addr) {
258  if (symbols_reloaded)
259  /* Get SHM_BEG EXT_BEG and EXT_END. */
260  ret = dev_get_symbol(dev_context->dev_obj,
261  SHMBASENAME, &ul_shm_base_virt);
262  if (dynamic_load) {
263  if (!ret) {
264  if (symbols_reloaded)
265  ret =
267  (dev_context->dev_obj, DYNEXTBASE,
268  &ul_ext_base);
269  }
270  if (!ret) {
271  /* DR OMAPS00013235 : DLModules array may be
272  * in EXTMEM. It is expected that DYNEXTMEM and
273  * EXTMEM are contiguous, so checking for the
274  * upper bound at EXTEND should be Ok. */
275  if (symbols_reloaded)
276  ret =
278  (dev_context->dev_obj, EXTEND,
279  &ul_ext_end);
280  }
281  } else {
282  if (symbols_reloaded) {
283  if (!ret)
284  ret =
286  (dev_context->dev_obj, EXTBASE,
287  &ul_ext_base);
288  if (!ret)
289  ret =
291  (dev_context->dev_obj, EXTEND,
292  &ul_ext_end);
293  }
294  }
295  /* Trace buffer it right after the shm SEG0, so set the
296  * base address to SHMBASE */
297  if (trace_load)
298  ul_ext_base = ul_shm_base_virt;
299 
300  if (ul_ext_end < ul_ext_base)
301  ret = -EPERM;
302 
303  if (!ret) {
304  ul_tlb_base_virt =
305  dev_context->atlb_entry[0].dsp_va * DSPWORDSIZE;
306 
307  if (symbols_reloaded) {
308  ret = dev_get_symbol
309  (dev_context->dev_obj,
310  DSP_TRACESEC_END, &shm0_end);
311  if (!ret) {
312  ret =
314  (dev_context->dev_obj, DYNEXTBASE,
315  &ul_dyn_ext_base);
316  }
317  }
318  ul_shm_offset_virt =
319  ul_shm_base_virt - ul_tlb_base_virt;
320  if (trace_load) {
321  dw_ext_prog_virt_mem =
322  dev_context->atlb_entry[0].gpp_va;
323  } else {
324  dw_ext_prog_virt_mem = host_res->mem_base[1];
325  dw_ext_prog_virt_mem +=
326  (ul_ext_base - ul_dyn_ext_base);
327  }
328 
329  dev_context->dsp_ext_base_addr =
330  (u32) MEM_LINEAR_ADDRESS((void *)
331  dw_ext_prog_virt_mem,
332  ul_ext_end - ul_ext_base);
333  dw_base_addr += dev_context->dsp_ext_base_addr;
334  /* This dsp_ext_base_addr will get cleared only when
335  * the board is stopped. */
336  if (!dev_context->dsp_ext_base_addr)
337  ret = -EPERM;
338  }
339  }
340  if (!dw_base_addr || !ul_ext_base || !ul_ext_end)
341  ret = -EPERM;
342 
343  if (!ret) {
344  for (i = 0; i < 4; i++)
345  remain_byte[i] = 0x0;
346 
347  dw_offset = dsp_addr - ul_ext_base;
348  /* Also make sure the dsp_addr is < ul_ext_end */
349  if (dsp_addr > ul_ext_end || dw_offset > dsp_addr)
350  ret = -EPERM;
351  }
352  if (!ret) {
353  if (ul_num_bytes)
354  memcpy((u8 *) dw_base_addr + dw_offset, host_buff,
355  ul_num_bytes);
356  else
357  *((u32 *) host_buff) = dw_base_addr + dw_offset;
358  }
359  /* Unmap here to force remap for other Ext loads */
360  if ((dynamic_load || trace_load) && dev_context->dsp_ext_base_addr) {
361  MEM_UNMAP_LINEAR_ADDRESS((void *)
362  dev_context->dsp_ext_base_addr);
363  dev_context->dsp_ext_base_addr = 0x0;
364  }
365  symbols_reloaded = false;
366  return ret;
367 }
368 
369 int sm_interrupt_dsp(struct bridge_dev_context *dev_context, u16 mb_val)
370 {
371 #ifdef CONFIG_TIDSPBRIDGE_DVFS
372  u32 opplevel = 0;
373 #endif
374  struct omap_dsp_platform_data *pdata =
375  omap_dspbridge_dev->dev.platform_data;
376  struct cfg_hostres *resources = dev_context->resources;
377  int status = 0;
378  u32 temp;
379 
380  if (!dev_context->mbox)
381  return 0;
382 
383  if (!resources)
384  return -EPERM;
385 
386  if (dev_context->brd_state == BRD_DSP_HIBERNATION ||
387  dev_context->brd_state == BRD_HIBERNATION) {
388 #ifdef CONFIG_TIDSPBRIDGE_DVFS
389  if (pdata->dsp_get_opp)
390  opplevel = (*pdata->dsp_get_opp) ();
391  if (opplevel == VDD1_OPP1) {
392  if (pdata->dsp_set_min_opp)
393  (*pdata->dsp_set_min_opp) (VDD1_OPP2);
394  }
395 #endif
396  /* Restart the peripheral clocks */
397  dsp_clock_enable_all(dev_context->dsp_per_clks);
398  dsp_wdt_enable(true);
399 
400  /*
401  * 2:0 AUTO_IVA2_DPLL - Enabling IVA2 DPLL auto control
402  * in CM_AUTOIDLE_PLL_IVA2 register
403  */
406 
407  /*
408  * 7:4 IVA2_DPLL_FREQSEL - IVA2 internal frq set to
409  * 0.75 MHz - 1.0 MHz
410  * 2:0 EN_IVA2_DPLL - Enable IVA2 DPLL in lock mode
411  */
417 
418  /* Restore mailbox settings */
419  omap_mbox_restore_ctx(dev_context->mbox);
420 
421  /* Access MMU SYS CONFIG register to generate a short wakeup */
422  temp = readl(resources->dmmu_base + 0x10);
423 
424  dev_context->brd_state = BRD_RUNNING;
425  } else if (dev_context->brd_state == BRD_RETENTION) {
426  /* Restart the peripheral clocks */
427  dsp_clock_enable_all(dev_context->dsp_per_clks);
428  }
429 
430  status = omap_mbox_msg_send(dev_context->mbox, mb_val);
431 
432  if (status) {
433  pr_err("omap_mbox_msg_send Fail and status = %d\n", status);
434  status = -EPERM;
435  }
436 
437  return 0;
438 }