Commit | Line | Data |
---|---|---|
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 | ||
38 | static u32 ul_ext_base; | |
39 | static u32 ul_ext_end; | |
40 | ||
41 | static u32 shm0_end; | |
42 | static u32 ul_dyn_ext_base; | |
43 | static u32 ul_trace_sec_beg; | |
44 | static u32 ul_trace_sec_end; | |
45 | static u32 ul_shm_base_virt; | |
46 | ||
47 | bool symbols_reloaded = true; | |
48 | ||
49 | /* | |
50 | * ======== read_ext_dsp_data ======== | |
51 | * Copies DSP external memory buffers to the host side buffers. | |
52 | */ | |
e6890692 | 53 | int 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 | 181 | int 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 | */ | |
227 | int 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 | ||
386 | int 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 | } |