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 */
read_ext_dsp_data(struct bridge_dev_context * dev_ctxt,u8 * host_buff,u32 dsp_addr,u32 ul_num_bytes,u32 mem_type)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 */
write_dsp_data(struct bridge_dev_context * dev_context,u8 * host_buff,u32 dsp_addr,u32 ul_num_bytes,u32 mem_type)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 */
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)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
sm_interrupt_dsp(struct bridge_dev_context * dev_context,u16 mb_val)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 }
439