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