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