• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/staging/tidspbridge/core/
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 */
53int read_ext_dsp_data(struct bridge_dev_context *dev_ctxt,
54			     u8 *host_buff, u32 dsp_addr,
55			     u32 ul_num_bytes, u32 mem_type)
56{
57	int status = 0;
58	struct bridge_dev_context *dev_context = dev_ctxt;
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 */
73	if (!status && !ul_trace_sec_beg) {
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
79	if (!status && !ul_trace_sec_end) {
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
85	if (!status) {
86		if ((dsp_addr <= ul_trace_sec_end) &&
87		    (dsp_addr >= ul_trace_sec_beg))
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. */
103		if (!status && !ul_dyn_ext_base) {
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
109		if (!status) {
110			status = dev_get_symbol(dev_context->hdev_obj,
111						EXTBASE, &ul_ext_base);
112		}
113		DBC_ASSERT(ul_ext_base != 0);
114
115		if (!status) {
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
134		if (!status) {
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
168	offset = dsp_addr - ul_ext_base;
169
170	if (!status)
171		memcpy(host_buff, (u8 *) dw_base_addr + offset, ul_num_bytes);
172
173	return status;
174}
175
176/*
177 *  ======== write_dsp_data ========
178 *  purpose:
179 *      Copies buffers to the DSP internal/external memory.
180 */
181int write_dsp_data(struct bridge_dev_context *dev_context,
182			  u8 *host_buff, u32 dsp_addr, u32 ul_num_bytes,
183			  u32 mem_type)
184{
185	u32 offset;
186	u32 dw_base_addr = dev_context->dw_dsp_base_addr;
187	struct cfg_hostres *resources = dev_context->resources;
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
197	offset = dsp_addr - dev_context->dw_dsp_start_add;
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)
214		memcpy((u8 *) (dw_base_addr + offset), host_buff, ul_num_bytes);
215	else
216		*((u32 *) host_buff) = dw_base_addr + offset;
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,
228			      u8 *host_buff, u32 dsp_addr,
229			      u32 ul_num_bytes, u32 mem_type,
230			      bool dynamic_load)
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);
250		if (!ret)
251			ret = dev_get_symbol(dev_context->hdev_obj,
252					     DSP_TRACESEC_END,
253					     &ul_trace_sec_end);
254	}
255	if (!ret) {
256		if ((dsp_addr <= ul_trace_sec_end) &&
257		    (dsp_addr >= ul_trace_sec_beg))
258			trace_load = true;
259	}
260
261	/* If dynamic, force remap/unmap */
262	if ((dynamic_load || trace_load) && dw_base_addr) {
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);
274		if (dynamic_load) {
275			if (!ret) {
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);
283			if (!ret) {
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) {
296				if (!ret)
297					ret =
298					    dev_get_symbol
299					    (dev_context->hdev_obj, EXTBASE,
300					     &ul_ext_base);
301				DBC_ASSERT(ul_ext_base != 0);
302				if (!ret)
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
319		if (!ret) {
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) {
325				ret = dev_get_symbol
326					    (dev_context->hdev_obj,
327					     DSP_TRACESEC_END, &shm0_end);
328				if (!ret) {
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
360	if (!ret) {
361		for (i = 0; i < 4; i++)
362			remain_byte[i] = 0x0;
363
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)
367			ret = -EPERM;
368	}
369	if (!ret) {
370		if (ul_num_bytes)
371			memcpy((u8 *) dw_base_addr + dw_offset, host_buff,
372			       ul_num_bytes);
373		else
374			*((u32 *) host_buff) = dw_base_addr + dw_offset;
375	}
376	/* Unmap here to force remap for other Ext loads */
377	if ((dynamic_load || trace_load) && dev_context->dw_dsp_ext_base_addr) {
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{
388#ifdef CONFIG_TIDSPBRIDGE_DVFS
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) {
405#ifdef CONFIG_TIDSPBRIDGE_DVFS
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 */
439		temp = readl(resources->dw_dmmu_base + 0x10);
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}
456