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 */
read_ext_dsp_data(struct bridge_dev_context * dev_ctxt,u8 * host_buff,u32 dsp_addr,u32 ul_num_bytes,u32 mem_type)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->dsp_ext_base_addr;
65 bool trace_read = false;
66
67 if (!ul_shm_base_virt) {
68 status = dev_get_symbol(dev_context->dev_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->dev_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->dev_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->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->dev_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->dev_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->dev_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].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].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->dsp_ext_base_addr =
152 dw_ext_prog_virt_mem;
153
154 /*
155 * This dsp_ext_base_addr will get cleared
156 * only when the board is stopped.
157 */
158 if (!dev_context->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 */
write_dsp_data(struct bridge_dev_context * dev_context,u8 * host_buff,u32 dsp_addr,u32 ul_num_bytes,u32 mem_type)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->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->dsp_start_add;
199 if (offset < base1) {
200 dw_base_addr = MEM_LINEAR_ADDRESS(resources->mem_base[2],
201 resources->mem_length[2]);
202 } else if (offset > base1 && offset < base2 + OMAP_DSP_MEM2_SIZE) {
203 dw_base_addr = MEM_LINEAR_ADDRESS(resources->mem_base[3],
204 resources->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->mem_base[4],
209 resources->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 */
write_ext_dsp_data(struct bridge_dev_context * dev_context,u8 * host_buff,u32 dsp_addr,u32 ul_num_bytes,u32 mem_type,bool dynamic_load)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->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->dev_obj,
250 DSP_TRACESEC_BEG, &ul_trace_sec_beg);
251 if (!ret)
252 ret = dev_get_symbol(dev_context->dev_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->dsp_ext_base_addr);
267 dev_context->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->dev_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->dev_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->dev_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->dev_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->dev_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].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->dev_obj,
328 DSP_TRACESEC_END, &shm0_end);
329 if (!ret) {
330 ret =
331 dev_get_symbol
332 (dev_context->dev_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].gpp_va;
341 } else {
342 dw_ext_prog_virt_mem = host_res->mem_base[1];
343 dw_ext_prog_virt_mem +=
344 (ul_ext_base - ul_dyn_ext_base);
345 }
346
347 dev_context->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->dsp_ext_base_addr;
352 /* This dsp_ext_base_addr will get cleared only when
353 * the board is stopped. */
354 if (!dev_context->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->dsp_ext_base_addr) {
379 MEM_UNMAP_LINEAR_ADDRESS((void *)
380 dev_context->dsp_ext_base_addr);
381 dev_context->dsp_ext_base_addr = 0x0;
382 }
383 symbols_reloaded = false;
384 return ret;
385 }
386
sm_interrupt_dsp(struct bridge_dev_context * dev_context,u16 mb_val)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->brd_state == BRD_DSP_HIBERNATION ||
405 dev_context->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->dmmu_base + 0x10);
441
442 dev_context->brd_state = BRD_RUNNING;
443 } else if (dev_context->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 }
457