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