Merge tag 'nfs-for-3.16-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[cascardo/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 <linux/platform_data/dsp-omap.h>
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  */
51 int read_ext_dsp_data(struct bridge_dev_context *dev_ctxt,
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;
180         base2 = OMAP_DSP_MEM2_BASE - OMAP_DSP_MEM1_BASE;
181         base3 = OMAP_DSP_MEM3_BASE - OMAP_DSP_MEM1_BASE;
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,
241                                              DSP_TRACESEC_END,
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 =
266                                             dev_get_symbol
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 =
277                                             dev_get_symbol
278                                             (dev_context->dev_obj, EXTEND,
279                                              &ul_ext_end);
280                         }
281                 } else {
282                         if (symbols_reloaded) {
283                                 if (!ret)
284                                         ret =
285                                             dev_get_symbol
286                                             (dev_context->dev_obj, EXTBASE,
287                                              &ul_ext_base);
288                                 if (!ret)
289                                         ret =
290                                             dev_get_symbol
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 =
313                                             dev_get_symbol
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                  */
404                 (*pdata->dsp_cm_write)(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
405                                 OMAP3430_IVA2_MOD, OMAP3430_CM_AUTOIDLE_PLL);
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                  */
412                 (*pdata->dsp_cm_rmw_bits)(OMAP3430_IVA2_DPLL_FREQSEL_MASK |
413                                 OMAP3430_EN_IVA2_DPLL_MASK,
414                                 0x3 << OMAP3430_IVA2_DPLL_FREQSEL_SHIFT |
415                                 0x7 << OMAP3430_EN_IVA2_DPLL_SHIFT,
416                                 OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL);
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 }