Update from omapzoom 18-Aug-2008
[bridge-dev.git] / 0009-TI-DSP-BRIDGE-Mini-driver.patch
blob2dc72145a2b5a7ae0be116efd60b7786a54ca4bb
1 From f1cf13edf69692bdb003d434068ed625affd572d Mon Sep 17 00:00:00 2001
2 From: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
3 Date: Fri, 15 Aug 2008 01:55:54 +0300
4 Subject: [PATCH 09/10] TI DSP BRIDGE: Mini driver
6 Initial port from omapzoom
7 http://omapzoom.org/gf/project/omapbridge
9 For details,
10 http://omapzoom.org/gf/project/omapbridge/docman/?subdir=3
12 Signed-off-by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
13 ---
14 drivers/dsp/bridge/wmd/_cmm.h | 59 +
15 drivers/dsp/bridge/wmd/_deh.h | 48 +
16 drivers/dsp/bridge/wmd/_msg_sm.h | 158 +++
17 drivers/dsp/bridge/wmd/_tiomap.h | 400 ++++++
18 drivers/dsp/bridge/wmd/_tiomap_api.h | 182 +++
19 drivers/dsp/bridge/wmd/_tiomap_clk.h | 123 ++
20 drivers/dsp/bridge/wmd/_tiomap_mmu.h | 53 +
21 drivers/dsp/bridge/wmd/_tiomap_pwr.h | 82 ++
22 drivers/dsp/bridge/wmd/_tiomap_util.h | 47 +
23 drivers/dsp/bridge/wmd/chnl_sm.c | 1101 ++++++++++++++++
24 drivers/dsp/bridge/wmd/io_sm.c | 1843 ++++++++++++++++++++++++++
25 drivers/dsp/bridge/wmd/mmu_fault.c | 171 +++
26 drivers/dsp/bridge/wmd/mmu_fault.h | 52 +
27 drivers/dsp/bridge/wmd/msg_sm.c | 599 +++++++++
28 drivers/dsp/bridge/wmd/tiomap3430.c | 2171 +++++++++++++++++++++++++++++++
29 drivers/dsp/bridge/wmd/tiomap3430_pwr.c | 568 ++++++++
30 drivers/dsp/bridge/wmd/tiomap_io.c | 430 ++++++
31 drivers/dsp/bridge/wmd/tiomap_io.h | 112 ++
32 drivers/dsp/bridge/wmd/tiomap_sm.c | 305 +++++
33 drivers/dsp/bridge/wmd/ue_deh.c | 502 +++++++
34 20 files changed, 9006 insertions(+), 0 deletions(-)
35 create mode 100644 drivers/dsp/bridge/wmd/_cmm.h
36 create mode 100644 drivers/dsp/bridge/wmd/_deh.h
37 create mode 100644 drivers/dsp/bridge/wmd/_msg_sm.h
38 create mode 100644 drivers/dsp/bridge/wmd/_tiomap.h
39 create mode 100644 drivers/dsp/bridge/wmd/_tiomap_api.h
40 create mode 100644 drivers/dsp/bridge/wmd/_tiomap_clk.h
41 create mode 100644 drivers/dsp/bridge/wmd/_tiomap_mmu.h
42 create mode 100644 drivers/dsp/bridge/wmd/_tiomap_pwr.h
43 create mode 100644 drivers/dsp/bridge/wmd/_tiomap_util.h
44 create mode 100644 drivers/dsp/bridge/wmd/chnl_sm.c
45 create mode 100644 drivers/dsp/bridge/wmd/io_sm.c
46 create mode 100644 drivers/dsp/bridge/wmd/mmu_fault.c
47 create mode 100644 drivers/dsp/bridge/wmd/mmu_fault.h
48 create mode 100644 drivers/dsp/bridge/wmd/msg_sm.c
49 create mode 100644 drivers/dsp/bridge/wmd/tiomap3430.c
50 create mode 100644 drivers/dsp/bridge/wmd/tiomap3430_pwr.c
51 create mode 100644 drivers/dsp/bridge/wmd/tiomap_io.c
52 create mode 100644 drivers/dsp/bridge/wmd/tiomap_io.h
53 create mode 100644 drivers/dsp/bridge/wmd/tiomap_sm.c
54 create mode 100644 drivers/dsp/bridge/wmd/ue_deh.c
56 Index: lk/drivers/dsp/bridge/wmd/_cmm.h
57 ===================================================================
58 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
59 +++ lk/drivers/dsp/bridge/wmd/_cmm.h 2008-08-18 10:38:38.000000000 +0300
60 @@ -0,0 +1,59 @@
61 +/*
62 + * linux/drivers/dsp/bridge/wmd/linux/omap/wmdchnl/common/_cmm.h
63 + *
64 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
65 + *
66 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
67 + *
68 + * This package is free software; you can redistribute it and/or modify
69 + * it under the terms of the GNU General Public License version 2 as
70 + * published by the Free Software Foundation.
71 + *
72 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
73 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
74 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
75 + */
78 +/*
79 + * ======== _cmm.h ========
80 + * Description:
81 + * Private header file defining CMM manager objects and defines needed
82 + * by IO manager to register shared memory regions when DSP base image
83 + * is loaded(WMD_IO_OnLoaded).
84 + *
85 + * Public Functions:
86 + * None.
87 + *
88 + * Notes:
89 + *
90 + *! Revision History:
91 + *! ================
92 + *! 24-Aug-2001 ag Created.
93 + */
95 +#ifndef _CMM_
96 +#define _CMM_
98 +/*
99 + * These target side symbols define the beginning and ending addresses
100 + * of the section of shared memory used for shared memory manager CMM.
101 + * They are defined in the *cfg.cmd file by cdb code.
102 + */
103 +#define SHM0_SHARED_BASE_SYM "_SHM0_BEG"
104 +#define SHM0_SHARED_END_SYM "_SHM0_END"
105 +#define SHM0_SHARED_RESERVED_BASE_SYM "_SHM0_RSVDSTRT"
108 + * Shared Memory Region #0(SHMSEG0) is used in the following way:
110 + * |(_SHM0_BEG) | (_SHM0_RSVDSTRT) | (_SHM0_END)
111 + * V V V
112 + * ------------------------------------------------------------
113 + * | DSP-side allocations | GPP-side allocations |
114 + * ------------------------------------------------------------
117 + */
119 +#endif /* _CMM_ */
120 Index: lk/drivers/dsp/bridge/wmd/_deh.h
121 ===================================================================
122 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
123 +++ lk/drivers/dsp/bridge/wmd/_deh.h 2008-08-18 10:38:38.000000000 +0300
124 @@ -0,0 +1,48 @@
126 + * linux/drivers/dsp/bridge/wmd/linux/omap/common/_deh.h
128 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
130 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
132 + * This package is free software; you can redistribute it and/or modify
133 + * it under the terms of the GNU General Public License version 2 as
134 + * published by the Free Software Foundation.
136 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
137 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
138 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
139 + */
143 + * ======== _deh.h ========
144 + * Description:
145 + * Private header for DEH module.
147 + *! Revision History:
148 + *! ================
149 + *! 21-Sep-2001 kc: created.
150 + */
152 +#ifndef _DEH_
153 +#define _DEH_
155 +#include <dpc.h>
156 +#include <isr.h>
157 +#include <ntfy.h>
158 +#include <wmd.h>
160 +#define SIGNATURE 0x5f484544 /* "DEH_" backwards */
162 +/* DEH Manager: only one created per board: */
163 +struct DEH_MGR {
164 + u32 dwSignature; /* Used for object validation. */
165 + struct WMD_DEV_CONTEXT *hWmdContext; /* WMD device context. */
166 + struct NTFY_OBJECT *hNtfy; /* NTFY object */
167 + struct DPC_OBJECT *hMmuFaultDpc; /* DPC object handle. */
168 + struct ISR_IRQ *hMmuFaultIsr; /* DSP MMU ISR handle. */
169 + struct DSP_ERRORINFO errInfo; /* DSP exception info. */
170 +} ;
172 +#endif /* _DEH_ */
173 Index: lk/drivers/dsp/bridge/wmd/_msg_sm.h
174 ===================================================================
175 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
176 +++ lk/drivers/dsp/bridge/wmd/_msg_sm.h 2008-08-18 10:38:38.000000000 +0300
177 @@ -0,0 +1,158 @@
179 + * linux/drivers/dsp/bridge/wmd/linux/omap/wmdchnl/common/_msg_sm.h
181 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
183 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
185 + * This package is free software; you can redistribute it and/or modify
186 + * it under the terms of the GNU General Public License version 2 as
187 + * published by the Free Software Foundation.
189 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
190 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
191 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
192 + */
196 + * ======== _msg_sm.h ========
197 + * Description:
198 + * Private header file defining MSG manager objects and defines needed
199 + * by IO manager.
201 + * Public Functions:
202 + * None.
204 + * Notes:
206 + *! Revision History:
207 + *! ================
208 + *! 09-May-2001 jeh Code Review cleanup.
209 + *! 08-Nov-2000 jeh Created.
210 + */
212 +#ifndef _MSG_SM_
213 +#define _MSG_SM_
215 +#include <list.h>
216 +#include <msgdefs.h>
219 + * These target side symbols define the beginning and ending addresses
220 + * of the section of shared memory used for messages. They are
221 + * defined in the *cfg.cmd file by cdb code.
222 + */
223 +#define MSG_SHARED_BUFFER_BASE_SYM "_MSG_BEG"
224 +#define MSG_SHARED_BUFFER_LIMIT_SYM "_MSG_END"
226 +#ifndef _CHNL_WORDSIZE
227 +#define _CHNL_WORDSIZE 4 /* default _CHNL_WORDSIZE is 2 bytes/word */
228 +#endif
231 + * ======== MSG ========
232 + * There is a control structure for messages to the DSP, and a control
233 + * structure for messages from the DSP. The shared memory region for
234 + * transferring messages is partitioned as follows:
236 + * ----------------------------------------------------------
237 + * |Control | Messages from DSP | Control | Messages to DSP |
238 + * ----------------------------------------------------------
240 + * MSG control structure for messages to the DSP is used in the following
241 + * way:
243 + * bufEmpty - This flag is set to FALSE by the GPP after it has output
244 + * messages for the DSP. The DSP host driver sets it to
245 + * TRUE after it has copied the messages.
246 + * postSWI - Set to 1 by the GPP after it has written the messages,
247 + * set the size, and set bufEmpty to FALSE.
248 + * The DSP Host driver uses SWI_andn of the postSWI field
249 + * when a host interrupt occurs. The host driver clears
250 + * this after posting the SWI.
251 + * size - Number of messages to be read by the DSP.
253 + * For messages from the DSP:
254 + * bufEmpty - This flag is set to FALSE by the DSP after it has output
255 + * messages for the GPP. The DPC on the GPP sets it to
256 + * TRUE after it has copied the messages.
257 + * postSWI - Set to 1 the DPC on the GPP after copying the messages.
258 + * size - Number of messages to be read by the GPP.
259 + */
260 +struct MSG {
261 + SMWORD bufEmpty; /* to/from DSP buffer is empty */
262 + SMWORD postSWI; /* Set to "1" to post MSG SWI */
263 + SMWORD size; /* Number of messages to/from the DSP */
264 + SMWORD resvd;
265 +} ;
268 + * ======== MSG_MGR ========
269 + * The MSG_MGR maintains a list of all MSG_QUEUEs. Each NODE object can
270 + * have MSG_QUEUE to hold all messages that come up from the corresponding
271 + * node on the DSP. The MSG_MGR also has a shared queue of messages
272 + * ready to go to the DSP.
273 + */
274 +struct MSG_MGR {
275 + /* The first two fields must match those in msgobj.h */
276 + u32 dwSignature;
277 + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD. */
279 + struct IO_MGR *hIOMgr; /* IO manager */
280 + struct LST_LIST *queueList; /* List of MSG_QUEUEs */
281 + struct SYNC_CSOBJECT *hSyncCS; /* For critical sections */
282 + /* Signalled when MsgFrame is available */
283 + struct SYNC_OBJECT *hSyncEvent;
284 + struct LST_LIST *msgFreeList; /* Free MsgFrames ready to be filled */
285 + struct LST_LIST *msgUsedList; /* MsgFrames ready to go to DSP */
286 + u32 uMsgsPending; /* # of queued messages to go to DSP */
287 + u32 uMaxMsgs; /* Max # of msgs that fit in buffer */
288 + MSG_ONEXIT onExit; /* called when RMS_EXIT is received */
289 +} ;
292 + * ======== MSG_QUEUE ========
293 + * Each NODE has a MSG_QUEUE for receiving messages from the
294 + * corresponding node on the DSP. The MSG_QUEUE object maintains a list
295 + * of messages that have been sent to the host, but not yet read (MSG_Get),
296 + * and a list of free frames that can be filled when new messages arrive
297 + * from the DSP.
298 + * The MSG_QUEUE's hSynEvent gets posted when a message is ready.
299 + */
300 +struct MSG_QUEUE {
301 + struct LST_ELEM listElem;
302 + u32 dwSignature;
303 + struct MSG_MGR *hMsgMgr;
304 + u32 uMaxMsgs; /* Node message depth */
305 + u32 dwId; /* Node environment pointer */
306 + struct LST_LIST *msgFreeList; /* Free MsgFrames ready to be filled */
307 + /* Filled MsgFramess waiting to be read */
308 + struct LST_LIST *msgUsedList;
309 + HANDLE hArg; /* Handle passed to mgr onExit callback */
310 + struct SYNC_OBJECT *hSyncEvent; /* Signalled when message is ready */
311 + struct SYNC_OBJECT *hSyncDone; /* For synchronizing cleanup */
312 + struct SYNC_OBJECT *hSyncDoneAck; /* For synchronizing cleanup */
313 + struct NTFY_OBJECT *hNtfy; /* For notification of message ready */
314 + bool fDone; /* TRUE <==> deleting the object */
315 + u32 refCount; /* Number of pending MSG_get/put calls */
319 + * ======== MSG_DSPMSG ========
320 + */
321 +struct MSG_DSPMSG {
322 + struct DSP_MSG msg;
323 + u32 dwId; /* Identifies the node the message goes to */
324 +} ;
327 + * ======== MSG_FRAME ========
328 + */
329 +struct MSG_FRAME {
330 + struct LST_ELEM listElem;
331 + struct MSG_DSPMSG msgData;
332 +} ;
334 +#endif /* _MSG_SM_ */
336 Index: lk/drivers/dsp/bridge/wmd/_tiomap.h
337 ===================================================================
338 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
339 +++ lk/drivers/dsp/bridge/wmd/_tiomap.h 2008-08-18 10:38:38.000000000 +0300
340 @@ -0,0 +1,400 @@
342 + * linux/drivers/dsp/bridge/wmd/linux/omap/common/_tiomap.h
344 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
346 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
348 + * This package is free software; you can redistribute it and/or modify
349 + * it under the terms of the GNU General Public License version 2 as
350 + * published by the Free Software Foundation.
352 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
353 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
354 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
355 + */
358 + * ======== _tiomap.h ========
359 + * Description:
360 + * Definitions and types private to this WMD.
362 + *! Revision History
363 + *! ================
364 + *! 12-Apr-2004 hp: Removed the L4 entry of Dsp DMA , not needed
365 + *! 08-Mar-2004 sb: Added the Dynamic Memory Mapping feature - PgTableAttrs
366 + *! 21-Mar-2003 sb: Added numTLBEntries to struct WMD_DEV_CONTEXT
367 + *! 20-Feb-2003 vp: Ported to Linux platform.
368 + *! 30-Jul-2002 rr: Modified TBC_ID_VALUE to 0xb47002f.
369 + *! 10-May-2002 sg: Added ARM_SYSST_OFFSET and IDLE_DSP_MASK.
370 + *! 14-Mar-2002 rr: Added Boot vector field to pDevContext.
371 + *! Added TBC Register defines and value for OMAP1510.
372 + *! 12-Jan-2002 ag: wIntrVal2Dsp Added.
373 + *! 05-Nov-2001 kc: Added MMU fault related definitions.
374 + *! 03-Aug-2001 ag Added TLB table for OEM cofig of DSP-MMU.
375 + *! 23-Aug-2001 rr: Added API_SIZE define.
376 + *! 16-Aug-2001 rr: Added dwDspExtBaseAddr to access the Ext memory.
377 + *! 24-Jul-2001 ag: Added Internal SRAM MMU table entry.
378 + *! 27-Jun-2001 rr: Name changed to _tihelen.h.
379 + *! 27-Jun-2001 ag: Added dwIntAddr in WMD_DEV_CONTEXT used for MB INTRs msk.
380 + *! 07-May-2001 ag: Added DSP Clock Module CLKM2.
381 + *! Added TIHEL_SDRAMPHYSBASE used for DSP MMU init.
382 + *! Added ClearBit() MACRO.
383 + *! 18-Jan-2001 rr: Created
384 + */
386 +#ifndef _TIOMAP_
387 +#define _TIOMAP_
389 +#include <devdefs.h>
390 +#include <hw_defs.h>
391 +#include <hw_mbox.h>
392 +#include <wmdioctl.h> /* for WMDIOCTL_EXTPROC defn */
393 +#include "sync.h"
394 +#include "clk.h"
396 +struct MAP_L4PERIPHERAL {
397 + u32 physAddr;
398 + u32 dspVirtAddr;
399 +} ;
401 +#define ARM_MAILBOX_START 0xfffcf000
402 +#define ARM_MAILBOX_LENGTH 0x800
404 +/* New Registers in OMAP3.1 */
406 +#define TESTBLOCK_ID_START 0xfffed400
407 +#define TESTBLOCK_ID_LENGTH 0xff
409 +/* ID Returned by OMAP1510 */
410 +#define TBC_ID_VALUE 0xB47002F
412 +#define SPACE_LENGTH 0x2000
413 +#define API_CLKM_DPLL_DMA 0xfffec000
414 +#define ARM_INTERRUPT_OFFSET 0xb00
416 +#define BIOS_24XX
418 +#define L4_PERIPHERAL_NULL 0x0
419 +#define DSPVA_PERIPHERAL_NULL 0x0
421 +#define MAX_LOCK_TLB_ENTRIES 15
423 +#define L4_PERIPHERAL_PRM 0x48306000 /*PRM L4 Peripheral */
424 +#define DSPVA_PERIPHERAL_PRM 0x1181e000
425 +#define L4_PERIPHERAL_SCM 0x48002000 /*SCM L4 Peripheral */
426 +#define DSPVA_PERIPHERAL_SCM 0x1181f000
427 +#define L4_PERIPHERAL_MMU 0x5D000000 /*MMU L4 Peripheral */
428 +#define DSPVA_PERIPHERAL_MMU 0x11820000
429 +#define L4_PERIPHERAL_CM 0x48004000 /* Core L4, Clock Management */
430 +#define DSPVA_PERIPHERAL_CM 0x1181c000
431 +#define L4_PERIPHERAL_PER 0x48005000 /* PER */
432 +#define DSPVA_PERIPHERAL_PER 0x1181d000
434 +#define L4_PERIPHERAL_GPIO1 0x48310000
435 +#define DSPVA_PERIPHERAL_GPIO1 0x11809000
436 +#define L4_PERIPHERAL_GPIO2 0x49050000
437 +#define DSPVA_PERIPHERAL_GPIO2 0x1180a000
438 +#define L4_PERIPHERAL_GPIO3 0x49052000
439 +#define DSPVA_PERIPHERAL_GPIO3 0x1180b000
440 +#define L4_PERIPHERAL_GPIO4 0x49054000
441 +#define DSPVA_PERIPHERAL_GPIO4 0x1180c000
442 +#define L4_PERIPHERAL_GPIO5 0x49056000
443 +#define DSPVA_PERIPHERAL_GPIO5 0x1180d000
445 +#define L4_PERIPHERAL_IVA2WDT 0x49030000
446 +#define DSPVA_PERIPHERAL_IVA2WDT 0x1180e000
448 +#define L4_PERIPHERAL_DISPLAY 0x48050000
449 +#define DSPVA_PERIPHERAL_DISPLAY 0x1180f000
451 +#define L4_PERIPHERAL_SSI 0x48058000
452 +#define DSPVA_PERIPHERAL_SSI 0x11804000
453 +#define L4_PERIPHERAL_GDD 0x48059000
454 +#define DSPVA_PERIPHERAL_GDD 0x11805000
455 +#define L4_PERIPHERAL_SS1 0x4805a000
456 +#define DSPVA_PERIPHERAL_SS1 0x11806000
457 +#define L4_PERIPHERAL_SS2 0x4805b000
458 +#define DSPVA_PERIPHERAL_SS2 0x11807000
460 +#define L4_PERIPHERAL_CAMERA 0x480BC000
461 +#define DSPVA_PERIPHERAL_CAMERA 0x11819000
463 +#define L4_PERIPHERAL_SDMA 0x48056000
464 +#define DSPVA_PERIPHERAL_SDMA 0x11810000 /*0x1181d000 conflicts with PER */
466 +#define L4_PERIPHERAL_UART1 0x4806a000
467 +#define DSPVA_PERIPHERAL_UART1 0x11811000
468 +#define L4_PERIPHERAL_UART2 0x4806c000
469 +#define DSPVA_PERIPHERAL_UART2 0x11812000
470 +#define L4_PERIPHERAL_UART3 0x49020000
471 +#define DSPVA_PERIPHERAL_UART3 0x11813000
473 +#define L4_PERIPHERAL_MCBSP1 0x48074000
474 +#define DSPVA_PERIPHERAL_MCBSP1 0x11814000
475 +#define L4_PERIPHERAL_MCBSP2 0x49022000
476 +#define DSPVA_PERIPHERAL_MCBSP2 0x11815000
477 +#define L4_PERIPHERAL_MCBSP3 0x49024000
478 +#define DSPVA_PERIPHERAL_MCBSP3 0x11816000
479 +#define L4_PERIPHERAL_MCBSP4 0x49026000
480 +#define DSPVA_PERIPHERAL_MCBSP4 0x11817000
481 +#define L4_PERIPHERAL_MCBSP5 0x48096000
482 +#define DSPVA_PERIPHERAL_MCBSP5 0x11818000
484 +#define L4_PERIPHERAL_GPTIMER5 0x49038000
485 +#define DSPVA_PERIPHERAL_GPTIMER5 0x11800000
486 +#define L4_PERIPHERAL_GPTIMER6 0x4903a000
487 +#define DSPVA_PERIPHERAL_GPTIMER6 0x11801000
488 +#define L4_PERIPHERAL_GPTIMER7 0x4903c000
489 +#define DSPVA_PERIPHERAL_GPTIMER7 0x11802000
490 +#define L4_PERIPHERAL_GPTIMER8 0x4903e000
491 +#define DSPVA_PERIPHERAL_GPTIMER8 0x11803000
493 +#define L4_PERIPHERAL_SPI1 0x48098000
494 +#define DSPVA_PERIPHERAL_SPI1 0x1181a000
495 +#define L4_PERIPHERAL_SPI2 0x4809a000
496 +#define DSPVA_PERIPHERAL_SPI2 0x1181b000
498 +#define L4_PERIPHERAL_MBOX 0x48094000
499 +#define DSPVA_PERIPHERAL_MBOX 0x11808000
501 +#define PM_GRPSEL_BASE 0x48307000
502 +#define DSPVA_GRPSEL_BASE 0x11821000
504 +/* define a static array with L4 mappings */
505 +static const struct MAP_L4PERIPHERAL L4PeripheralTable[] = {
506 + {L4_PERIPHERAL_MBOX, DSPVA_PERIPHERAL_MBOX},
507 + {L4_PERIPHERAL_SCM, DSPVA_PERIPHERAL_SCM},
508 + {L4_PERIPHERAL_MMU, DSPVA_PERIPHERAL_MMU},
509 + {L4_PERIPHERAL_GPTIMER5, DSPVA_PERIPHERAL_GPTIMER5},
510 + {L4_PERIPHERAL_GPTIMER6, DSPVA_PERIPHERAL_GPTIMER6},
511 + {L4_PERIPHERAL_GPTIMER7, DSPVA_PERIPHERAL_GPTIMER7},
512 + {L4_PERIPHERAL_GPTIMER8, DSPVA_PERIPHERAL_GPTIMER8},
513 + {L4_PERIPHERAL_GPIO1, DSPVA_PERIPHERAL_GPIO1},
514 + {L4_PERIPHERAL_GPIO2, DSPVA_PERIPHERAL_GPIO2},
515 + {L4_PERIPHERAL_GPIO3, DSPVA_PERIPHERAL_GPIO3},
516 + {L4_PERIPHERAL_GPIO4, DSPVA_PERIPHERAL_GPIO4},
517 + {L4_PERIPHERAL_GPIO5, DSPVA_PERIPHERAL_GPIO5},
518 + {L4_PERIPHERAL_IVA2WDT, DSPVA_PERIPHERAL_IVA2WDT},
519 + {L4_PERIPHERAL_DISPLAY, DSPVA_PERIPHERAL_DISPLAY},
520 + {L4_PERIPHERAL_SSI, DSPVA_PERIPHERAL_SSI},
521 + {L4_PERIPHERAL_GDD, DSPVA_PERIPHERAL_GDD},
522 + {L4_PERIPHERAL_SS1, DSPVA_PERIPHERAL_SS1},
523 + {L4_PERIPHERAL_SS2, DSPVA_PERIPHERAL_SS2},
524 + {L4_PERIPHERAL_UART1, DSPVA_PERIPHERAL_UART1},
525 + {L4_PERIPHERAL_UART2, DSPVA_PERIPHERAL_UART2},
526 + {L4_PERIPHERAL_UART3, DSPVA_PERIPHERAL_UART3},
527 + {L4_PERIPHERAL_MCBSP1, DSPVA_PERIPHERAL_MCBSP1},
528 + {L4_PERIPHERAL_MCBSP2, DSPVA_PERIPHERAL_MCBSP2},
529 + {L4_PERIPHERAL_MCBSP3, DSPVA_PERIPHERAL_MCBSP3},
530 + {L4_PERIPHERAL_MCBSP4, DSPVA_PERIPHERAL_MCBSP4},
531 + {L4_PERIPHERAL_MCBSP5, DSPVA_PERIPHERAL_MCBSP5},
532 + {L4_PERIPHERAL_CAMERA, DSPVA_PERIPHERAL_CAMERA},
533 + {L4_PERIPHERAL_SPI1, DSPVA_PERIPHERAL_SPI1},
534 + {L4_PERIPHERAL_SPI2, DSPVA_PERIPHERAL_SPI2},
535 + {L4_PERIPHERAL_PRM, DSPVA_PERIPHERAL_PRM},
536 + {L4_PERIPHERAL_CM, DSPVA_PERIPHERAL_CM},
537 + {L4_PERIPHERAL_PER, DSPVA_PERIPHERAL_PER},
538 + {PM_GRPSEL_BASE, DSPVA_GRPSEL_BASE},
539 + {L4_PERIPHERAL_NULL, DSPVA_PERIPHERAL_NULL}
543 + * 15 10 0
544 + * ---------------------------------
545 + * |0|0|1|0|0|0|c|c|c|i|i|i|i|i|i|i|
546 + * ---------------------------------
547 + * | (class) | (module specific) |
549 + * where c -> Externel Clock Command: Clk & Autoidle Disable/Enable
550 + * i -> External Clock ID Timers 5,6,7,8, McBSP1,2 and WDT3
551 + */
553 +/* MBX_PM_CLK_IDMASK: DSP External clock id mask. */
554 +#define MBX_PM_CLK_IDMASK 0x7F
556 +/* MBX_PM_CLK_CMDSHIFT: DSP External clock command shift. */
557 +#define MBX_PM_CLK_CMDSHIFT 7
559 +/* MBX_PM_CLK_CMDMASK: DSP External clock command mask. */
560 +#define MBX_PM_CLK_CMDMASK 7
562 +/* MBX_PM_MAX_RESOURCES: CORE 1 Clock resources. */
563 +#define MBX_CORE1_RESOURCES 7
565 +/* MBX_PM_MAX_RESOURCES: CORE 2 Clock Resources. */
566 +#define MBX_CORE2_RESOURCES 1
568 +/* MBX_PM_MAX_RESOURCES: TOTAL Clock Reosurces. */
569 +#define MBX_PM_MAX_RESOURCES 11
571 +/* Power Management Commands */
572 +enum BPWR_ExtClockCmd {
573 + BPWR_DisableClock = 0,
574 + BPWR_EnableClock,
575 + BPWR_DisableAutoIdle,
576 + BPWR_EnableAutoIdle
577 +} ;
579 +/* OMAP242x specific resources */
580 +enum BPWR_ExtClockId {
581 + BPWR_GPTimer5 = 0x10,
582 + BPWR_GPTimer6,
583 + BPWR_GPTimer7,
584 + BPWR_GPTimer8,
585 + BPWR_WDTimer3,
586 + BPWR_MCBSP1,
587 + BPWR_MCBSP2,
588 + BPWR_MCBSP3,
589 + BPWR_MCBSP4,
590 + BPWR_MCBSP5,
591 + BPWR_SSI = 0x20
592 +} ;
594 +static const u32 BPWR_CLKID[] = {
595 + (u32) BPWR_GPTimer5,
596 + (u32) BPWR_GPTimer6,
597 + (u32) BPWR_GPTimer7,
598 + (u32) BPWR_GPTimer8,
599 + (u32) BPWR_WDTimer3,
600 + (u32) BPWR_MCBSP1,
601 + (u32) BPWR_MCBSP2,
602 + (u32) BPWR_MCBSP3,
603 + (u32) BPWR_MCBSP4,
604 + (u32) BPWR_MCBSP5,
605 + (u32) BPWR_SSI
608 +struct BPWR_Clk_t {
609 + u32 clkId;
610 + enum SERVICES_ClkId funClk;
611 + enum SERVICES_ClkId intClk;
612 +} ;
614 +static const struct BPWR_Clk_t BPWR_Clks[] = {
615 + {(u32) BPWR_GPTimer5, SERVICESCLK_gpt5_fck, SERVICESCLK_gpt5_ick},
616 + {(u32) BPWR_GPTimer6, SERVICESCLK_gpt6_fck, SERVICESCLK_gpt6_ick},
617 + {(u32) BPWR_GPTimer7, SERVICESCLK_gpt7_fck, SERVICESCLK_gpt7_ick},
618 + {(u32) BPWR_GPTimer8, SERVICESCLK_gpt8_fck, SERVICESCLK_gpt8_ick},
619 + {(u32) BPWR_WDTimer3, SERVICESCLK_wdt3_fck, SERVICESCLK_wdt3_ick},
620 + {(u32) BPWR_MCBSP1, SERVICESCLK_mcbsp1_fck, SERVICESCLK_mcbsp1_ick},
621 + {(u32) BPWR_MCBSP2, SERVICESCLK_mcbsp2_fck, SERVICESCLK_mcbsp2_ick},
622 + {(u32) BPWR_MCBSP3, SERVICESCLK_mcbsp3_fck, SERVICESCLK_mcbsp3_ick},
623 + {(u32) BPWR_MCBSP4, SERVICESCLK_mcbsp4_fck, SERVICESCLK_mcbsp4_ick},
624 + {(u32) BPWR_MCBSP5, SERVICESCLK_mcbsp5_fck, SERVICESCLK_mcbsp5_ick},
625 + {(u32) BPWR_SSI, SERVICESCLK_ssi_fck, SERVICESCLK_ssi_ick}
628 +/* Interrupt Register Offsets */
629 +#define INTH_IT_REG_OFFSET 0x00 /* Interrupt register offset */
630 +#define INTH_MASK_IT_REG_OFFSET 0x04 /* Mask Interrupt reg offset */
632 +#define DSP_MAILBOX1_INT 10
635 + * INTH_InterruptKind_t
636 + * Identify the kind of interrupt: either FIQ/IRQ
637 + */
638 +enum INTH_InterruptKind_t {
639 + INTH_IRQ = 0,
640 + INTH_FIQ = 1
641 +} ;
643 +enum INTH_SensitiveEdge_t {
644 + FALLING_EDGE_SENSITIVE = 0,
645 + LOW_LEVEL_SENSITIVE = 1
646 +} ;
649 + * Bit definition of Interrupt Level Registers
650 + */
652 +/* Mail Box defines */
653 +#define MB_ARM2DSP1_REG_OFFSET 0x00
655 +#define MB_ARM2DSP1B_REG_OFFSET 0x04
657 +#define MB_DSP2ARM1B_REG_OFFSET 0x0C
659 +#define MB_ARM2DSP1_FLAG_REG_OFFSET 0x18
661 +#define MB_ARM2DSP_FLAG 0x0001
663 +#define MBOX_ARM2DSP HW_MBOX_ID_0
664 +#define MBOX_DSP2ARM HW_MBOX_ID_1
665 +#define MBOX_ARM HW_MBOX_U0_ARM
666 +#define MBOX_DSP HW_MBOX_U1_DSP1
668 +#define ENABLE true
669 +#define DISABLE false
671 +#define HIGH_LEVEL true
672 +#define LOW_LEVEL false
674 +/* Macro's */
675 +#define REG16(A) (*(REG_UWORD16 *)(A))
677 +#define ClearBit(reg, mask) (reg &= ~mask)
678 +#define SetBit(reg, mask) (reg |= mask)
680 +#define SetGroupBits16(reg, position, width, value) \
681 + do {\
682 + reg &= ~((0xFFFF >> (16 - (width))) << (position)) ; \
683 + reg |= ((value & (0xFFFF >> (16 - (width)))) << (position)); \
684 + } while (0);
686 +#define ClearBitIndex(reg, index) (reg &= ~(1 << (index)))
688 +/* This mini driver's device context: */
689 +struct WMD_DEV_CONTEXT {
690 + struct DEV_OBJECT *hDevObject; /* Handle to WCD device object. */
691 + u32 dwDspBaseAddr; /* Arm's API to DSP virtual base addr */
692 + /*
693 + * DSP External memory prog address as seen virtually by the OS on
694 + * the host side.
695 + */
696 + u32 dwDspExtBaseAddr; /* See the comment above */
697 + u32 dwAPIRegBase; /* API memory mapped registers */
698 + u32 dwDSPMmuBase; /* DSP MMU Mapped registers */
699 + u32 dwMailBoxBase; /* Mail box mapped registers */
700 + u32 dwAPIClkBase; /* CLK Registers */
701 + u32 dwDSPClkM2Base; /* DSP Clock Module m2 */
702 + u32 dwPublicRhea; /* Pub Rhea */
703 + u32 dwIntAddr; /* MB INTR reg */
704 + u32 dwTCEndianism; /* TC Endianism register */
705 + u32 dwTestBase; /* DSP MMU Mapped registers */
706 + u32 dwSelfLoop; /* Pointer to the selfloop */
707 + u32 dwDSPStartAdd; /* API Boot vector */
708 + u32 dwInternalSize; /* Internal memory size */
710 + /*
711 + * Processor specific info is set when prog loaded and read from DCD.
712 + * [See WMD_BRD_Ctrl()] PROC info contains DSP-MMU TLB entries.
713 + */
714 + /* DMMU TLB entries */
715 + struct WMDIOCTL_EXTPROC aTLBEntry[WMDIOCTL_NUMOFMMUTLB];
716 + u32 dwBrdState; /* Last known board state. */
717 + u32 ulIntMask; /* int mask */
718 + u16 ioBase; /* Board I/O base */
719 + u16 wIntrVal2Dsp; /* MBX value to DSP. See mbx_sh.h */
720 + u32 numTLBEntries; /* DSP MMU TLB entry counter */
721 + u32 fixedTLBEntries; /* Fixed DSPMMU TLB entry count */
723 + /* TC Settings */
724 + bool tcWordSwapOn; /* Traffic Controller Word Swap */
725 + struct PgTableAttrs *pPtAttrs;
726 + u32 uDspPerClks;
727 +} ;
729 + /*
730 + * ======== WMD_TLB_DspVAToMpuPA ========
731 + * Given a DSP virtual address, traverse the page table and return
732 + * a corresponding MPU physical address and size.
733 + */
734 +extern DSP_STATUS WMD_TLB_DspVAToMpuPA(struct WMD_DEV_CONTEXT *pDevContext,
735 + IN u32 ulVirtAddr,
736 + OUT u32 *ulPhysAddr,
737 + OUT u32 *sizeTlb);
739 +#endif /* _TIOMAP_ */
741 Index: lk/drivers/dsp/bridge/wmd/_tiomap_api.h
742 ===================================================================
743 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
744 +++ lk/drivers/dsp/bridge/wmd/_tiomap_api.h 2008-08-18 10:38:38.000000000 +0300
745 @@ -0,0 +1,182 @@
747 + * linux/drivers/dsp/bridge/wmd/linux/omap/common/_tiomap_api.h
749 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
751 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
753 + * This package is free software; you can redistribute it and/or modify
754 + * it under the terms of the GNU General Public License version 2 as
755 + * published by the Free Software Foundation.
757 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
758 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
759 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
760 + */
764 + * ======== _tiomap_api.h ========
765 + * Description:
766 + * Definitions, types and function prototypes for the API module.
768 + *! Revision History
769 + *! ================
770 + *! 27-Mar-2003 vp: Updated for Power Management
771 + *! - Added setAPI function
772 + *! - Added API_DSP_BOOT_IDLE enumeration
773 + *! - Modified setDSPBootMode function to take boot mode option
774 + *! 19-Feb-2003 vp: Ported to Linux platform.
775 + *! 08-Oct-2002 rr: Created.
776 + */
778 +#ifndef _TIOMAP_API_
779 +#define _TIOMAP_API_
781 +/* I/O ARM Memory Mapping and ARM Peripheral mapping */
782 +#define ARM_API_START 0xfffec900
783 +#define ARM_API_LENGTH 0xff
785 +/* API I/F Registers */
786 +#define API_CTRL_OFFSET 0x0000 /* 32 bit control register */
787 +#define API_STATUS_OFFSET 0x0010 /* 16 bit status register(RO) */
788 +#define API_DSP_STATUS_OFFSET 0x0014 /* 16 bit DSP status register */
789 +#define API_DSP_BOOT_OFFSET 0x0018 /* 16 bit Boot configuration
790 + * register
791 + */
792 +#define API_SIZE 0x001c
793 +#define API_DSP_API_OFFSET 0x0020 /* 16 bit API Configuration
794 + * register
795 + */
797 +/* API_DSP_STATUS_REG related */
798 +#define API_DSP_STATUS_HOM_MODE 0x0c00 /* HOM Mode bits - set if HOM */
800 +/* SAM/HOM bit in API_DSP_STATUS register value */
801 +#define SAM_BIT 0x0400
803 +/* Define position bit fields */
804 +#define API_HIGH_FREQ_POSBIT 0
805 +#define API_TIMEOUT_EN_POSBIT 1
806 +#define API_API_ERR_EN_POSBIT 3
807 +#define API_ACCESS_FACTOR_POSBIT 4
808 +#define API_TIMEOUT_POSBIT 8
809 +#define API_ENDIANISM_POSBIT 16
810 +#define API_ACCESS_PRIORITY_POSBIT 18
812 +typedef enum {
813 + API_HIGH_FREQ_LOW = 0,
814 + API_HIGH_FREQ_HIGH = 1
815 +} API_HighFreq_t;
817 +typedef enum {
818 + API_TIMEOUT_DIS = 0,
819 + API_TIMEOUT_EN = 1
820 +} API_TimeoutEn_t;
822 +typedef enum {
823 + API_API_ERR_DIS = 0,
824 + API_API_ERR_EN = 1
825 +} API_ApiErrEn_t;
827 +typedef enum {
828 + API_ACCESS_FACTOR_0 = 0,
829 + API_ACCESS_FACTOR_1,
830 + API_ACCESS_FACTOR_2,
831 + API_ACCESS_FACTOR_3,
832 + API_ACCESS_FACTOR_4,
833 + API_ACCESS_FACTOR_5,
834 + API_ACCESS_FACTOR_6,
835 + API_ACCESS_FACTOR_7,
836 + API_ACCESS_FACTOR_8,
837 + API_ACCESS_FACTOR_9,
838 + API_ACCESS_FACTOR_10,
839 + API_ACCESS_FACTOR_11,
840 + API_ACCESS_FACTOR_12,
841 + API_ACCESS_FACTOR_13,
842 + API_ACCESS_FACTOR_14,
843 + API_ACCESS_FACTOR_15
844 +} API_AccessFactor_t;
846 +typedef enum {
847 + API_TIMEOUT_MIN = 0,
848 + API_TIMEOUT_MAX = 255
849 +} API_Timeout_t;
851 +typedef enum {
852 + API_ENDIANISM_NO_CONVERT = 0,
853 + API_ENDIANISM_CONVERT_ALL_ACCESS = 2,
854 + API_ENDIANISM_CONVERT_API_MEM_ONLY = 3
855 +} API_Endianism_t;
857 +typedef enum {
858 + API_ACCESS_PRIORITY_ARM_DMA_HSAB = 0,
859 + API_ACCESS_PRIORITY_ARM_HSAB_DMA,
860 + API_ACCESS_PRIORITY_DMA_ARM_HSAB,
861 + API_ACCESS_PRIORITY_HSAB_ARM_DMA,
862 + API_ACCESS_PRIORITY_DMA_HSAB_ARM,
863 + API_ACCESS_PRIORITY_HSAB_DMA_ARM
864 +} API_AccessPriority_t;
866 +typedef enum {
867 + API_DSP_BOOT_INTERNAL = 5,
868 + API_DSP_BOOT_EXTERNAL = 4,
869 + API_DSP_BOOT_EMIF16 = 3,
870 + API_DSP_BOOT_IDLE = 2,
871 + API_DSP_BOOT_PSEUDO_EXT = 1,
872 + API_DSP_BOOT_MPNMC = 0
873 +} API_DSPBootMode_t;
875 +/* Function prototypes */
878 + * ======== setAPIsize ========
879 + * Configures the SARAM blocks which can be accessed in the HOM mode
880 + * Register 0xfffe:c900 offset 0x1c.
881 + */
882 +extern void setAPIsize(struct WMD_DEV_CONTEXT *pDevContext, u16 size);
885 + * ======== setDspBootModeAPI ========
886 + * Sets up the DSP boot mode
887 + * Register 0xfffe:c900 offset 18.
888 + * Boot mode is set API_DSP_BOOT_INTERNAL; DSP will start executing from
889 + * SARAM location 0x10000 byte address.
890 + */
891 +extern void setDspBootModeAPI(struct WMD_DEV_CONTEXT *pDevContext,
892 + API_DSPBootMode_t dsp_boot_mode);
895 + * ======== setAPI ========
896 + * Configures the API interface.
897 + * Register 0xfffe:c900 offset 0x0.
898 + * - Set the API access priority to ARM-DMA-HSAB
899 + * - Sets the no byte swap
900 + * - Time out is set to MAX
901 + * - Access factor is 4
902 + * - Enable the time out
903 + * - Set it to high frequency mode
904 + */
905 +extern void setAPI(struct WMD_DEV_CONTEXT *pDevContext,
906 + API_HighFreq_t high_freq,
907 + API_TimeoutEn_t timeout_en,
908 + API_ApiErrEn_t api_err_en,
909 + API_AccessFactor_t access_factor,
910 + API_Timeout_t timeout,
911 + API_Endianism_t endianism,
912 + API_AccessPriority_t access_priority);
915 + * ======== setupAPI ========
916 + * Configures the API interface.
917 + * Register 0xfffe:c900 offset 0x0.
918 + * - Set the API access priority to ARM-DMA-HSAB
919 + * - Sets the no byte swap
920 + * - Time out is set to MAX
921 + * - Access factor is 4
922 + * - Enable the time out
923 + * - Set it to high frequency mode
924 + */
925 +extern void setupAPI(struct WMD_DEV_CONTEXT *pDevContext);
927 +#endif /* _TIOMAP_API_ */
928 Index: lk/drivers/dsp/bridge/wmd/_tiomap_clk.h
929 ===================================================================
930 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
931 +++ lk/drivers/dsp/bridge/wmd/_tiomap_clk.h 2008-08-18 10:38:38.000000000 +0300
932 @@ -0,0 +1,123 @@
934 + * linux/drivers/dsp/bridge/wmd/linux/omap/common/_tiomap_clk.h
936 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
938 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
940 + * This package is free software; you can redistribute it and/or modify
941 + * it under the terms of the GNU General Public License version 2 as
942 + * published by the Free Software Foundation.
944 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
945 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
946 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
947 + */
951 + * ======== _tiomap_clk.h ========
952 + * Description:
953 + * Definitions and types for the CLOCK and RESET modules. This
954 + * includes enabling/disabling peripheral clocks,reseting and releasing
955 + * the DSP.
956 + *! Revision History
957 + *! ================
958 + *! 08-Oct-2002 rr: Created.
959 + */
961 +#ifndef _TIOMAP_CLK_
962 +#define _TIOMAP_CLK_
964 +#include "_tiomap.h"
966 +/* ARM CLK Module */
967 +#define ARM_CLKM_START 0xfffece00
968 +#define ARM_CLKM_LENGTH 0xff
969 +#define ARM_SYSST_OFFSET 0x18
970 +#define IDLE_DSP_MASK 0x40
972 +/* DSP CLK Module */
973 +#define DSP_CLKM2_BASE 0xe1008000
974 +#define DSP_CLKM2_LENGTH 0xff
975 +#define DSP_IDLECT2_OFFSET 0x8 /* Clock domain control */
977 +/* CLK related defines */
978 +/* ARM_CKCTL */
979 +#define ARM_CKCTL_OFFEST 0x0
981 +#define EN_DSPCK_POS 13
982 +#define EN_DSPCK_NUMB 1
984 +/* ARM_RSTCT1 */
985 +#define ARM_RSTCT1_OFFSET 0x10
987 +#define DSP_RST_POS 2
988 +#define DSP_RST_NUMB 1
989 +#define DSP_EN_POS 1
990 +#define DSP_EN_NUMB 1
992 +/* ARM_IDLECT2 */
993 +#define ARM_IDLECT2_OFFSET 0x8
995 +#define EN_APICK_POS 6
996 +#define EN_APICK_NUMB 1
998 +/* Function prototypes */
1000 + * ======== dspPeripheralClockDisable ========
1001 + * Disables the clock for the DSP external periperal clock (DSPPER_CK)
1002 + * Register 0xe100:8000 offset 0x8 bit position 1 is set to zero.
1003 + */
1004 +extern void dspPeripheralClockDisable(struct WMD_DEV_CONTEXT *pDevContext);
1007 + * ======== dspPeripheralClockEnable ========
1008 + * Enables the clock for DSP external refernce clock, periperal clock, USART clk
1009 + * GPIO clk and GPIO peripheral clock.
1010 + * Register 0xe100:8000 offset 0x8 bit position 0,1,2,3,4 and 5 are set to 1.
1011 + */
1012 +extern void dspPeripheralClockEnable(struct WMD_DEV_CONTEXT *pDevContext);
1015 + * ======== releaseDSP ========
1016 + * Releases the DSP from reset. Th DSP starts running.from whatever
1017 + * boot mode is set to. If it is set to internal boot mode, the DSP
1018 + * starts executing from location 0x10000 byte address.
1019 + * 0xfffe:ce00 bit postion 1 is set to one.
1020 + */
1021 +extern DSP_STATUS releaseDSP(struct WMD_DEV_CONTEXT *pDevContext,
1022 + BOOL fCheckForSAM);
1025 + * ======== releaseDspInterFace ========
1026 + * Enables the pritoiry registers, EMIF configuration registers and
1027 + * the API control logic in the DSP subsystem so that they can be programmed.
1028 + * 0xfffe:ce00 bit postion 2 is set to one.
1029 + */
1030 +extern void releaseDSPInterface(struct WMD_DEV_CONTEXT *pDevContext);
1033 + * ======== resetDSP ========
1034 + * Resets the DSP. This stops the DSP from running.
1035 + * 0xfffe:ce00 bit postion 1 is set to zero
1036 + */
1037 +extern void resetDSP(struct WMD_DEV_CONTEXT *pDevContext);
1040 + * ======== resetDSPInterface ========
1041 + * Resets the pritoiry registers, EMIF configuration registers and
1042 + * the API control logic in the DSP subsystem. This is required to configure
1043 + * the API and MMU.
1044 + * 0xfffe:ce00 bit postion 2 is set to zero.
1045 + */
1046 +extern void resetDSPInterface(struct WMD_DEV_CONTEXT *pDevContext);
1048 + /*
1049 + * ======== setTCEndianism =========
1050 + * Sets the endianism register.
1051 + */
1052 +extern void setTCEndianism(struct WMD_DEV_CONTEXT *pDevContext, u32 value);
1054 +#endif /* _TIOMAP_CLK_ */
1056 Index: lk/drivers/dsp/bridge/wmd/_tiomap_mmu.h
1057 ===================================================================
1058 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1059 +++ lk/drivers/dsp/bridge/wmd/_tiomap_mmu.h 2008-08-18 10:38:38.000000000 +0300
1060 @@ -0,0 +1,53 @@
1062 + * linux/drivers/dsp/bridge/wmd/linux/omap/2430/_tiomap_mmu.h
1064 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
1066 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
1068 + * This package is free software; you can redistribute it and/or modify
1069 + * it under the terms of the GNU General Public License version 2 as
1070 + * published by the Free Software Foundation.
1072 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1073 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1074 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1075 + */
1079 + * ======== _tiomap_mmu.h ========
1080 + * Description:
1081 + * Definitions and types for the DSP MMU modules
1083 + *! Revision History
1084 + *! ================
1085 + *! 19-Apr-2004 sb: Renamed HW types. Removed dspMmuTlbEntry
1086 + *! 05-Jan-2004 vp: Moved the file to a platform specific folder from common.
1087 + *! 21-Mar-2003 sb: Added macro definition TIHEL_LARGEPAGESIZE
1088 + *! 08-Oct-2002 rr: Created.
1089 + */
1091 +#ifndef _TIOMAP_MMU_
1092 +#define _TIOMAP_MMU_
1094 +#include "_tiomap.h"
1097 + * ======== configureDspMmu ========
1099 + * Make DSP MMu page table entries.
1100 + * Note: Not utilizing Coarse / Fine page tables.
1101 + * SECTION = 1MB, LARGE_PAGE = 64KB, SMALL_PAGE = 4KB, TINY_PAGE = 1KB.
1102 + * DSP Byte address 0x40_0000 is word addr 0x20_0000.
1103 + */
1104 +extern void configureDspMmu(struct WMD_DEV_CONTEXT *pDevContext,
1105 + u32 dataBasePhys,
1106 + u32 dspBaseVirt,
1107 + u32 sizeInBytes,
1108 + s32 nEntryStart,
1109 + enum HW_Endianism_t endianism,
1110 + enum HW_ElementSize_t elemSize,
1111 + enum HW_MMUMixedSize_t mixedSize);
1113 +#endif /* _TIOMAP_MMU_ */
1114 Index: lk/drivers/dsp/bridge/wmd/_tiomap_pwr.h
1115 ===================================================================
1116 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1117 +++ lk/drivers/dsp/bridge/wmd/_tiomap_pwr.h 2008-08-18 10:38:38.000000000 +0300
1118 @@ -0,0 +1,82 @@
1120 + * linux/drivers/dsp/bridge/wmd/linux/omap/common/_tiomap_pwr.h
1122 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
1124 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
1126 + * This package is free software; you can redistribute it and/or modify
1127 + * it under the terms of the GNU General Public License version 2 as
1128 + * published by the Free Software Foundation.
1130 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1131 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1132 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1133 + */
1137 + * ======== _tiomap_pwr.h ========
1138 + * Description:
1139 + * Definitions and types for the DSP wake/sleep routines.
1141 + *! Revision History
1142 + *! ================
1143 + *! 08-Oct-2002 rr: Created.
1144 + */
1146 +#ifndef _TIOMAP_PWR_
1147 +#define _TIOMAP_PWR_
1149 +/* Wait time between MBX and IDLE checks for PWR */
1150 +#define PWR_WAIT_USECS 500
1151 +#define PWR_WAIT_MSECS 50
1154 + * ======== WakeDSP =========
1155 + * Wakes up the DSP from DeepSleep
1156 + */
1157 +extern DSP_STATUS WakeDSP(struct WMD_DEV_CONTEXT *pDevContext, IN void *pArgs);
1160 + * ======== SleepDSP =========
1161 + * Places the DSP in DeepSleep.
1162 + */
1163 +extern DSP_STATUS SleepDSP(struct WMD_DEV_CONTEXT *pDevContext,
1164 + IN u32 dwCmd, IN void *pArgs);
1166 + * ========InterruptDSP========
1167 + * Sends an interrupt to DSP unconditionally.
1168 + */
1169 +extern void InterruptDSP(struct WMD_DEV_CONTEXT *pDevContext, IN u16 wMbVal);
1172 + * ======== WakeDSP =========
1173 + * Wakes up the DSP from DeepSleep
1174 + */
1175 +extern DSP_STATUS DSPPeripheralClkCtrl(struct WMD_DEV_CONTEXT *pDevContext,
1176 + IN void *pArgs);
1178 + * ======== handle_hibernation_fromDSP ========
1179 + * Handle Hibernation requested from DSP
1180 + */
1181 +DSP_STATUS handle_hibernation_fromDSP(struct WMD_DEV_CONTEXT *pDevContext);
1183 + * ======== PostScale_DSP ========
1184 + * Handle Post Scale notification to DSP
1185 + */
1186 +DSP_STATUS PostScale_DSP(struct WMD_DEV_CONTEXT *pDevContext, IN void *pArgs);
1188 + * ======== PreScale_DSP ========
1189 + * Handle Pre Scale notification to DSP
1190 + */
1191 +DSP_STATUS PreScale_DSP(struct WMD_DEV_CONTEXT *pDevContext, IN void *pArgs);
1193 + * ======== handle_constraints_set ========
1194 + * Handle constraints request from DSP
1195 + */
1196 +DSP_STATUS handle_constraints_set(struct WMD_DEV_CONTEXT *pDevContext,
1197 + IN void *pArgs);
1199 +#endif /* _TIOMAP_PWR_ */
1201 Index: lk/drivers/dsp/bridge/wmd/_tiomap_util.h
1202 ===================================================================
1203 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1204 +++ lk/drivers/dsp/bridge/wmd/_tiomap_util.h 2008-08-18 10:38:38.000000000 +0300
1205 @@ -0,0 +1,47 @@
1207 + * linux/drivers/dsp/bridge/wmd/linux/omap/common/_tiomap_util.h
1209 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
1211 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
1213 + * This package is free software; you can redistribute it and/or modify
1214 + * it under the terms of the GNU General Public License version 2 as
1215 + * published by the Free Software Foundation.
1217 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1218 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1219 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1220 + */
1224 + * ======== _tiomap_util.h ========
1225 + * Description:
1226 + * Definitions and types for the utility routines.
1228 + *! Revision History
1229 + *! ================
1230 + *! 08-Oct-2002 rr: Created.
1231 + */
1233 +#ifndef _TIOMAP_UTIL_
1234 +#define _TIOMAP_UTIL_
1236 +/* Time out Values in uSeconds*/
1237 +#define TIHELEN_ACKTIMEOUT 10000
1238 +#define TIHELEN_WRITE_DELAY 10
1240 +/* Time delay for HOM->SAM transition. */
1241 +#define WAIT_SAM 1000000 /* in usec (1000 millisec) */
1244 + * ======== WaitForStart ========
1245 + * Wait for the singal from DSP that it has started, or time out.
1246 + * The argument dwSyncAddr is set to 1 before releasing the DSP.
1247 + * If the DSP starts running, it will clear this location.
1248 + */
1249 +extern bool WaitForStart(struct WMD_DEV_CONTEXT *pDevContext, u32 dwSyncAddr);
1251 +#endif /* _TIOMAP_UTIL_ */
1253 Index: lk/drivers/dsp/bridge/wmd/chnl_sm.c
1254 ===================================================================
1255 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1256 +++ lk/drivers/dsp/bridge/wmd/chnl_sm.c 2008-08-18 10:38:38.000000000 +0300
1257 @@ -0,0 +1,1101 @@
1259 + * linux/drivers/dsp/bridge/wmd/linux/omap/wmdchnl/common/chnl_sm.c
1261 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
1263 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
1265 + * This package is free software; you can redistribute it and/or modify
1266 + * it under the terms of the GNU General Public License version 2 as
1267 + * published by the Free Software Foundation.
1269 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1270 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1271 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1272 + */
1276 + * ======== chnl_sm.c ========
1277 + * Description:
1278 + * Implements upper edge functions for WMD channel module.
1280 + * Public Functions:
1281 + * WMD_CHNL_AddIOReq
1282 + * WMD_CHNL_CancelIO
1283 + * WMD_CHNL_Close
1284 + * WMD_CHNL_Create
1285 + * WMD_CHNL_Destroy
1286 + * WMD_CHNL_FlushIO
1287 + * WMD_CHNL_GetInfo
1288 + * WMD_CHNL_GetIOC
1289 + * WMD_CHNL_GetMgrInfo
1290 + * WMD_CHNL_Idle
1291 + * WMD_CHNL_Open
1293 + * Notes:
1294 + * The lower edge functions must be implemented by the WMD writer, and
1295 + * are declared in chnl_sm.h.
1297 + * Care is taken in this code to prevent simulataneous access to channel
1298 + * queues from
1299 + * 1. Threads.
1300 + * 2. IO_DPC(), scheduled from the IO_ISR() as an event.
1302 + * This is done primarily by:
1303 + * - Semaphores.
1304 + * - state flags in the channel object; and
1305 + * - ensuring the IO_Dispatch() routine, which is called from both
1306 + * CHNL_AddIOReq() and the DPC(if implemented), is not re-entered.
1308 + * Channel Invariant:
1309 + * There is an important invariant condition which must be maintained per
1310 + * channel outside of WMD_CHNL_GetIOC() and IO_Dispatch(), violation of
1311 + * which may cause timeouts and/or failure offunction SYNC_WaitOnEvent.
1312 + * This invariant condition is:
1314 + * LST_Empty(pChnl->pIOCompletions) ==> pChnl->hSyncEvent is reset
1315 + * and
1316 + * !LST_Empty(pChnl->pIOCompletions) ==> pChnl->hSyncEvent is set.
1318 + *! Revision History:
1319 + *! ================
1320 + *! 10-Feb-2004 sb: Consolidated the MAILBOX_IRQ macro at the top of the file.
1321 + *! 05-Jan-2004 vp: Updated for 2.6 kernel on 24xx platform.
1322 + *! 23-Apr-2003 sb: Fixed mailbox deadlock
1323 + *! 24-Feb-2003 vp: Code Review Updates.
1324 + *! 18-Oct-2002 vp: Ported to Linux platform
1325 + *! 29-Aug-2002 rr Changed the SYNC error code return to DSP error code return
1326 + * in WMD_CHNL_GetIOC.
1327 + *! 22-Jan-2002 ag Zero-copy support added.
1328 + *! CMM_CallocBuf() used for SM allocations.
1329 + *! 04-Feb-2001 ag DSP-DMA support added.
1330 + *! 22-Nov-2000 kc: Updated usage of PERF_RegisterStat.
1331 + *! 06-Nov-2000 jeh Move ISR_Install, DPC_Create from CHNL_Create to IO_Create.
1332 + *! 13-Oct-2000 jeh Added dwArg parameter to WMD_CHNL_AddIOReq(), added
1333 + *! WMD_CHNL_Idle and WMD_CHNL_RegisterNotify for DSPStream.
1334 + *! Remove #ifdef DEBUG from around channel cIOCs field.
1335 + *! 21-Sep-2000 rr: PreOMAP chnl class library acts like a IO class library.
1336 + *! 25-Sep-2000 ag: MEM_[Unmap]LinearAddress added for #ifdef CHNL_PREOMAP.
1337 + *! 07-Sep-2000 rr: Added new channel class for PreOMAP.
1338 + *! 11-Jul-2000 jeh Allow NULL user event in WMD_CHNL_Open().
1339 + *! 06-Jul-2000 rr: Changed prefix PROC to PRCS for process module calls.
1340 + *! 20-Jan-2000 ag: Incorporated code review comments.
1341 + *! 05-Jan-2000 ag: Text format cleanup.
1342 + *! 07-Dec-1999 ag: Now setting ChnlMgr fSharedIRQ flag before ISR_Install().
1343 + *! 01-Dec-1999 ag: WMD_CHNL_Open() now accepts named sync event.
1344 + *! 14-Nov-1999 ag: DPC_Schedule() uncommented.
1345 + *! 28-Oct-1999 ag: CHNL Attrs userEvent not supported.
1346 + *! SM addrs taken from COFF(IO) or host resource(SM).
1347 + *! 25-May-1999 jg: CHNL_IOCLASS boards now get their shared memory buffer
1348 + *! address and length from symbols defined in the currently
1349 + *! loaded COFF file. See _chn_sm.h.
1350 + *! 18-Jun-1997 gp: Moved waiting back to ring 0 to improve performance.
1351 + *! 22-Jan-1998 gp: Update User's pIOC struct in GetIOC at lower IRQL (NT).
1352 + *! 16-Jan-1998 gp: Commented out PERF stuff, since it is not all there in NT.
1353 + *! 13-Jan-1998 gp: Protect IOCTLs from IO_DPC by raising IRQL to DIRQL (NT).
1354 + *! 22-Oct-1997 gp: Call SYNC_OpenEvent in CHNL_Open, for NT support.
1355 + *! 18-Jun-1997 gp: Moved waiting back to ring 0 to improve performance.
1356 + *! 16-Jun-1997 gp: Added call into lower edge CHNL function to allow override
1357 + *! of the SHM window length reported by Windows CM.
1358 + *! 05-Jun-1997 gp: Removed unnecessary critical sections.
1359 + *! 18-Mar-1997 gp: Ensured CHNL_FlushIO on input leaves channel in READY state.
1360 + *! 06-Jan-1997 gp: ifdefed to support the IO variant of SHM channel class lib.
1361 + *! 21-Jan-1997 gp: CHNL_Close: set pChnl = NULL for DBC_Ensure().
1362 + *! 14-Jan-1997 gp: Updated based on code review feedback.
1363 + *! 03-Jan-1997 gp: Added CHNL_E_WAITTIMEOUT error return code to CHNL_FlushIO()
1364 + *! 23-Oct-1996 gp: Tag channel with ring 0 process handle.
1365 + *! 13-Sep-1996 gp: Added performance statistics for channel.
1366 + *! 09-Sep-1996 gp: Added WMD_CHNL_GetMgrInfo().
1367 + *! 04-Sep-1996 gp: Removed shared memory control struct offset: made zero.
1368 + *! 01-Aug-1996 gp: Implemented basic channel manager and channel create/delete.
1369 + *! 17-Jul-1996 gp: Started pseudo coding.
1370 + *! 11-Jul-1996 gp: Stubbed out.
1371 + */
1373 +/* ----------------------------------- OS */
1374 +#include <host_os.h>
1376 +/* ----------------------------------- DSP/BIOS Bridge */
1377 +#include <std.h>
1378 +#include <dbdefs.h>
1379 +#include <errbase.h>
1381 +/* ----------------------------------- Trace & Debug */
1382 +#include <dbc.h>
1383 +#include <dbg.h>
1385 +/* ----------------------------------- OS Adaptation Layer */
1386 +#include <mem.h>
1387 +#include <cfg.h>
1388 +#include <csl.h>
1389 +#include <prcs.h>
1390 +#include <sync.h>
1392 +/* ----------------------------------- Mini-Driver */
1393 +#include <wmd.h>
1394 +#include <wmdchnl.h>
1396 +/* ----------------------------------- Platform Manager */
1397 +#include <dev.h>
1399 +/* ----------------------------------- Others */
1400 +#include <io_sm.h>
1402 +/* ----------------------------------- Define for This */
1403 +#define USERMODE_ADDR PAGE_OFFSET
1405 +#define MAILBOX_IRQ INT_MAIL_MPU_IRQ
1407 +/* ----------------------------------- Function Prototypes */
1408 +static struct LST_LIST *CreateChirpList(u32 uChirps);
1410 +static void FreeChirpList(struct LST_LIST *pList);
1412 +static struct CHNL_IRP *MakeNewChirp(void);
1414 +static DSP_STATUS SearchFreeChannel(struct CHNL_MGR *pChnlMgr,
1415 + OUT u32 *pdwChnl);
1418 + * ======== WMD_CHNL_AddIOReq ========
1419 + * Enqueue an I/O request for data transfer on a channel to the DSP.
1420 + * The direction (mode) is specified in the channel object. Note the DSP
1421 + * address is specified for channels opened in direct I/O mode.
1422 + */
1423 +DSP_STATUS WMD_CHNL_AddIOReq(struct CHNL_OBJECT *hChnl, void *pHostBuf,
1424 + u32 cBytes, u32 cBufSize,
1425 + OPTIONAL u32 dwDspAddr, u32 dwArg)
1427 + DSP_STATUS status = DSP_SOK;
1428 + struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl;
1429 + struct CHNL_IRP *pChirp = NULL;
1430 + u32 dwState;
1431 + bool fIsEOS;
1432 + struct CHNL_MGR *pChnlMgr = pChnl->pChnlMgr;
1433 + u8 *pHostSysBuf = NULL;
1434 + bool fSchedDPC = false;
1435 + u16 wMbVal = 0;
1437 + DBG_Trace(DBG_ENTER,
1438 + "> WMD_CHNL_AddIOReq pChnl %p CHNL_IsOutput %x uChnlType "
1439 + "%x Id %d\n", pChnl, CHNL_IsOutput(pChnl->uMode),
1440 + pChnl->uChnlType, pChnl->uId);
1442 + fIsEOS = (cBytes == 0) ? true : false;
1444 + if (pChnl->uChnlType == CHNL_PCPY && pChnl->uId > 1 && pHostBuf) {
1445 + if (!(pHostBuf < (void *)USERMODE_ADDR)) {
1446 + pHostSysBuf = pHostBuf;
1447 + goto func_cont;
1449 + /* if addr in user mode, then copy to kernel space */
1450 + pHostSysBuf = MEM_Alloc(cBufSize, MEM_NONPAGED);
1451 + if (pHostSysBuf == NULL) {
1452 + status = DSP_EMEMORY;
1453 + DBG_Trace(DBG_LEVEL7,
1454 + "No memory to allocate kernel buffer\n");
1455 + goto func_cont;
1457 + if (CHNL_IsOutput(pChnl->uMode)) {
1458 + status = copy_from_user(pHostSysBuf, pHostBuf,
1459 + cBufSize);
1460 + if (status) {
1461 + DBG_Trace(DBG_LEVEL7,
1462 + "Error copying user buffer to "
1463 + "kernel, %d bytes remaining.\n",
1464 + status);
1465 + MEM_Free(pHostSysBuf);
1466 + pHostSysBuf = NULL;
1467 + status = DSP_EPOINTER;
1471 +func_cont:
1472 + /* Validate args: */
1473 + if (pHostBuf == NULL) {
1474 + status = DSP_EPOINTER;
1475 + } else if (!MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) {
1476 + status = DSP_EHANDLE;
1477 + } else if (fIsEOS && CHNL_IsInput(pChnl->uMode)) {
1478 + status = CHNL_E_NOEOS;
1479 + } else {
1480 + /* Check the channel state: only queue chirp if channel state
1481 + * allows */
1482 + dwState = pChnl->dwState;
1483 + if (dwState != CHNL_STATEREADY) {
1484 + if (dwState & CHNL_STATECANCEL) {
1485 + status = CHNL_E_CANCELLED;
1486 + } else if ((dwState & CHNL_STATEEOS)
1487 + && CHNL_IsOutput(pChnl->uMode)) {
1488 + status = CHNL_E_EOS;
1489 + } else {
1490 + /* No other possible states left: */
1491 + DBC_Assert(0);
1495 + /* Mailbox IRQ is disabled to avoid race condition with DMA/ZCPY
1496 + * channels. DPCCS is held to avoid race conditions with PCPY channels.
1497 + * If DPC is scheduled in process context (IO_Schedule) and any
1498 + * non-mailbox interrupt occurs, that DPC will run and break CS. Hence
1499 + * we disable ALL DPCs. We will try to disable ONLY IO DPC later. */
1500 + SYNC_EnterCS(pChnlMgr->hCSObj);
1501 + disable_irq(MAILBOX_IRQ);
1502 + if (pChnl->uChnlType == CHNL_PCPY) {
1503 + /* This is a processor-copy channel. */
1504 + if (DSP_SUCCEEDED(status) && CHNL_IsOutput(pChnl->uMode)) {
1505 + /* Check buffer size on output channels for fit. */
1506 + if (cBytes > IO_BufSize(pChnl->pChnlMgr->hIOMgr))
1507 + status = CHNL_E_BUFSIZE;
1511 + if (DSP_SUCCEEDED(status)) {
1512 + /* Get a free chirp: */
1513 + pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->pFreeList);
1514 + if (pChirp == NULL)
1515 + status = CHNL_E_NOIORPS;
1518 + if (DSP_SUCCEEDED(status)) {
1519 + /* Enqueue the chirp on the chnl's IORequest queue: */
1520 + pChirp->pHostUserBuf = pChirp->pHostSysBuf = pHostBuf;
1521 + if (pChnl->uChnlType == CHNL_PCPY && pChnl->uId > 1)
1522 + pChirp->pHostSysBuf = pHostSysBuf;
1524 + if (DSP_SUCCEEDED(status)) {
1525 + /* Note: for dma chans dwDspAddr contains dsp address
1526 + * of SM buffer.*/
1527 + DBC_Assert(pChnlMgr->uWordSize != 0);
1528 + /* DSP address */
1529 + pChirp->uDspAddr = dwDspAddr / pChnlMgr->uWordSize;
1530 + pChirp->cBytes = cBytes;
1531 + pChirp->cBufSize = cBufSize;
1532 + /* Only valid for output channel */
1533 + pChirp->dwArg = dwArg;
1534 + pChirp->status = (fIsEOS ? CHNL_IOCSTATEOS :
1535 + CHNL_IOCSTATCOMPLETE);
1536 + LST_PutTail(pChnl->pIORequests, (struct LST_ELEM *)
1537 + pChirp);
1538 + pChnl->cIOReqs++;
1539 + DBC_Assert(pChnl->cIOReqs <= pChnl->cChirps);
1540 + /* If end of stream, update the channel state to prevent
1541 + * more IOR's: */
1542 + if (fIsEOS)
1543 + pChnl->dwState |= CHNL_STATEEOS;
1546 + /* Legacy DSM Processor-Copy */
1547 + DBC_Assert(pChnl->uChnlType == CHNL_PCPY);
1548 + /* Request IO from the DSP */
1549 + IO_RequestChnl(pChnlMgr->hIOMgr, pChnl,
1550 + (CHNL_IsInput(pChnl->uMode) ?
1551 + IO_INPUT : IO_OUTPUT), &wMbVal);
1552 + fSchedDPC = true;
1556 + enable_irq(MAILBOX_IRQ);
1557 + SYNC_LeaveCS(pChnlMgr->hCSObj);
1558 + if (wMbVal != 0)
1559 + IO_IntrDSP2(pChnlMgr->hIOMgr, wMbVal);
1561 + if (fSchedDPC == true) {
1562 + /* Schedule a DPC, to do the actual data transfer: */
1563 + IO_Schedule(pChnlMgr->hIOMgr);
1565 + DBG_Trace(DBG_ENTER, "< WMD_CHNL_AddIOReq pChnl %p\n", pChnl);
1566 + return status;
1570 + * ======== WMD_CHNL_CancelIO ========
1571 + * Return all I/O requests to the client which have not yet been
1572 + * transferred. The channel's I/O completion object is
1573 + * signalled, and all the I/O requests are queued as IOC's, with the
1574 + * status field set to CHNL_IOCSTATCANCEL.
1575 + * This call is typically used in abort situations, and is a prelude to
1576 + * CHNL_Close();
1577 + */
1578 +DSP_STATUS WMD_CHNL_CancelIO(struct CHNL_OBJECT *hChnl)
1580 + DSP_STATUS status = DSP_SOK;
1581 + struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl;
1582 + u32 iChnl = -1;
1583 + CHNL_MODE uMode;
1584 + struct CHNL_IRP *pChirp;
1585 + struct CHNL_MGR *pChnlMgr = NULL;
1587 + /* Check args: */
1588 + if (MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) {
1589 + iChnl = pChnl->uId;
1590 + uMode = pChnl->uMode;
1591 + pChnlMgr = pChnl->pChnlMgr;
1592 + } else {
1593 + status = DSP_EHANDLE;
1595 + if (DSP_FAILED(status))
1596 + goto func_end;
1598 + /* Mark this channel as cancelled, to prevent further IORequests or
1599 + * IORequests or dispatching. */
1600 + SYNC_EnterCS(pChnlMgr->hCSObj);
1601 + pChnl->dwState |= CHNL_STATECANCEL;
1602 + if (LST_IsEmpty(pChnl->pIORequests))
1603 + goto func_cont;
1605 + if (pChnl->uChnlType == CHNL_PCPY) {
1606 + /* Indicate we have no more buffers available for transfer: */
1607 + if (CHNL_IsInput(pChnl->uMode)) {
1608 + IO_CancelChnl(pChnlMgr->hIOMgr, iChnl);
1609 + } else {
1610 + /* Record that we no longer have output buffers
1611 + * available: */
1612 + pChnlMgr->dwOutputMask &= ~(1 << iChnl);
1615 + /* Move all IOR's to IOC queue: */
1616 + while (!LST_IsEmpty(pChnl->pIORequests)) {
1617 + pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->pIORequests);
1618 + if (pChirp) {
1619 + pChirp->cBytes = 0;
1620 + pChirp->status |= CHNL_IOCSTATCANCEL;
1621 + LST_PutTail(pChnl->pIOCompletions,
1622 + (struct LST_ELEM *)pChirp);
1623 + pChnl->cIOCs++;
1624 + pChnl->cIOReqs--;
1625 + DBC_Assert(pChnl->cIOReqs >= 0);
1628 +func_cont:
1629 + SYNC_LeaveCS(pChnlMgr->hCSObj);
1630 +func_end:
1631 + return status;
1635 + * ======== WMD_CHNL_Close ========
1636 + * Purpose:
1637 + * Ensures all pending I/O on this channel is cancelled, discards all
1638 + * queued I/O completion notifications, then frees the resources allocated
1639 + * for this channel, and makes the corresponding logical channel id
1640 + * available for subsequent use.
1641 + */
1642 +DSP_STATUS WMD_CHNL_Close(struct CHNL_OBJECT *hChnl)
1644 + DSP_STATUS status;
1645 + struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl;
1647 + /* Check args: */
1648 + if (!MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) {
1649 + status = DSP_EHANDLE;
1650 + goto func_cont;
1653 + /* Cancel IO: this ensures no further IO requests or
1654 + * notifications.*/
1655 + status = WMD_CHNL_CancelIO(hChnl);
1657 +func_cont:
1658 + if (DSP_SUCCEEDED(status)) {
1659 + /* Assert I/O on this channel is now cancelled: Protects
1660 + * from IO_DPC. */
1661 + DBC_Assert((pChnl->dwState & CHNL_STATECANCEL));
1662 + /* Invalidate channel object: Protects from
1663 + * CHNL_GetIOCompletion(). */
1664 + pChnl->dwSignature = 0x0000;
1665 + /* Free the slot in the channel manager: */
1666 + pChnl->pChnlMgr->apChannel[pChnl->uId] = NULL;
1667 + pChnl->pChnlMgr->cOpenChannels -= 1;
1668 + if (pChnl->hNtfy) {
1669 + NTFY_Delete(pChnl->hNtfy);
1670 + pChnl->hNtfy = NULL;
1672 + /* Reset channel event: (NOTE: hUserEvent freed in user
1673 + * context.). */
1674 + if (pChnl->hSyncEvent) {
1675 + SYNC_ResetEvent(pChnl->hSyncEvent);
1676 + SYNC_CloseEvent(pChnl->hSyncEvent);
1677 + pChnl->hSyncEvent = NULL;
1679 + /* Free I/O request and I/O completion queues: */
1680 + if (pChnl->pIOCompletions) {
1681 + FreeChirpList(pChnl->pIOCompletions);
1682 + pChnl->pIOCompletions = NULL;
1683 + pChnl->cIOCs = 0;
1685 + if (pChnl->pIORequests) {
1686 + FreeChirpList(pChnl->pIORequests);
1687 + pChnl->pIORequests = NULL;
1688 + pChnl->cIOReqs = 0;
1690 + if (pChnl->pFreeList) {
1691 + FreeChirpList(pChnl->pFreeList);
1692 + pChnl->pFreeList = NULL;
1694 + /* Release channel object. */
1695 + MEM_FreeObject(pChnl);
1696 + pChnl = NULL;
1698 + DBC_Ensure(DSP_FAILED(status) ||
1699 + !MEM_IsValidHandle(pChnl, CHNL_SIGNATURE));
1700 + return status;
1704 + * ======== WMD_CHNL_Create ========
1705 + * Create a channel manager object, responsible for opening new channels
1706 + * and closing old ones for a given board.
1707 + */
1708 +DSP_STATUS WMD_CHNL_Create(OUT struct CHNL_MGR **phChnlMgr,
1709 + struct DEV_OBJECT *hDevObject,
1710 + IN CONST struct CHNL_MGRATTRS *pMgrAttrs)
1712 + DSP_STATUS status = DSP_SOK;
1713 + struct CHNL_MGR *pChnlMgr = NULL;
1714 + s32 cChannels;
1715 +#ifdef DEBUG
1716 + struct CHNL_MGR *hChnlMgr;
1717 +#endif
1718 + /* Check DBC requirements: */
1719 + DBC_Require(phChnlMgr != NULL);
1720 + DBC_Require(pMgrAttrs != NULL);
1721 + DBC_Require(pMgrAttrs->cChannels > 0);
1722 + DBC_Require(pMgrAttrs->cChannels <= CHNL_MAXCHANNELS);
1723 + DBC_Require(pMgrAttrs->uWordSize != 0);
1724 +#ifdef DEBUG
1725 + /* This for the purposes of DBC_Require: */
1726 + status = DEV_GetChnlMgr(hDevObject, &hChnlMgr);
1727 + DBC_Require(status != DSP_EHANDLE);
1728 + DBC_Require(hChnlMgr == NULL);
1729 +#endif
1730 + if (DSP_SUCCEEDED(status)) {
1731 + /* Allocate channel manager object: */
1732 + MEM_AllocObject(pChnlMgr, struct CHNL_MGR, CHNL_MGRSIGNATURE);
1733 + if (pChnlMgr) {
1734 + /* The cChannels attr must equal the # of supported
1735 + * chnls for each transport(# chnls for PCPY = DDMA =
1736 + * ZCPY): i.e. pMgrAttrs->cChannels = CHNL_MAXCHANNELS =
1737 + * DDMA_MAXDDMACHNLS = DDMA_MAXZCPYCHNLS. */
1738 + DBC_Assert(pMgrAttrs->cChannels == CHNL_MAXCHANNELS);
1739 + cChannels = (CHNL_MAXCHANNELS + (CHNL_MAXCHANNELS *
1740 + CHNL_PCPY));
1741 + /* Create array of channels: */
1742 + pChnlMgr->apChannel = MEM_Calloc(
1743 + sizeof(struct CHNL_OBJECT *) *
1744 + cChannels, MEM_NONPAGED);
1745 + if (pChnlMgr->apChannel) {
1746 + /* Initialize CHNL_MGR object: */
1747 + /* Shared memory driver. */
1748 + pChnlMgr->dwType = CHNL_TYPESM;
1749 + pChnlMgr->uWordSize = pMgrAttrs->uWordSize;
1750 + /* total # chnls supported */
1751 + pChnlMgr->cChannels = cChannels;
1752 + pChnlMgr->cOpenChannels = 0;
1753 + pChnlMgr->dwOutputMask = 0;
1754 + pChnlMgr->dwLastOutput = 0;
1755 + pChnlMgr->hDevObject = hDevObject;
1756 + if (DSP_SUCCEEDED(status)) {
1757 + status = SYNC_InitializeDPCCS
1758 + (&pChnlMgr->hCSObj);
1760 + } else {
1761 + status = DSP_EMEMORY;
1763 + } else {
1764 + status = DSP_EMEMORY;
1767 + if (DSP_FAILED(status)) {
1768 + WMD_CHNL_Destroy(pChnlMgr);
1769 + *phChnlMgr = NULL;
1770 + } else {
1771 + /* Return channel manager object to caller... */
1772 + *phChnlMgr = pChnlMgr;
1774 + return status;
1778 + * ======== WMD_CHNL_Destroy ========
1779 + * Purpose:
1780 + * Close all open channels, and destroy the channel manager.
1781 + */
1782 +DSP_STATUS WMD_CHNL_Destroy(struct CHNL_MGR *hChnlMgr)
1784 + DSP_STATUS status = DSP_SOK;
1785 + struct CHNL_MGR *pChnlMgr = hChnlMgr;
1786 + u32 iChnl;
1788 + if (MEM_IsValidHandle(hChnlMgr, CHNL_MGRSIGNATURE)) {
1789 + /* Close all open channels: */
1790 + for (iChnl = 0; iChnl < pChnlMgr->cChannels; iChnl++) {
1791 + if (DSP_SUCCEEDED
1792 + (WMD_CHNL_Close(pChnlMgr->apChannel[iChnl]))) {
1793 + DBC_Assert(pChnlMgr->apChannel[iChnl] == NULL);
1796 + /* release critical section */
1797 + if (pChnlMgr->hCSObj)
1798 + SYNC_DeleteCS(pChnlMgr->hCSObj);
1800 + /* Free channel manager object: */
1801 + if (pChnlMgr->apChannel)
1802 + MEM_Free(pChnlMgr->apChannel);
1804 + /* Set hChnlMgr to NULL in device object. */
1805 + DEV_SetChnlMgr(pChnlMgr->hDevObject, NULL);
1806 + /* Free this Chnl Mgr object: */
1807 + MEM_FreeObject(hChnlMgr);
1808 + } else {
1809 + status = DSP_EHANDLE;
1811 + return status;
1815 + * ======== WMD_CHNL_FlushIO ========
1816 + * purpose:
1817 + * Flushes all the outstanding data requests on a channel.
1818 + */
1819 +DSP_STATUS WMD_CHNL_FlushIO(struct CHNL_OBJECT *hChnl, u32 dwTimeOut)
1821 + DSP_STATUS status = DSP_SOK;
1822 + struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl;
1823 + CHNL_MODE uMode = -1;
1824 + struct CHNL_MGR *pChnlMgr;
1825 + struct CHNL_IOC chnlIOC;
1826 + /* Check args: */
1827 + if (MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) {
1828 + if ((dwTimeOut == CHNL_IOCNOWAIT)
1829 + && CHNL_IsOutput(pChnl->uMode)) {
1830 + status = DSP_EINVALIDARG;
1831 + } else {
1832 + uMode = pChnl->uMode;
1833 + pChnlMgr = pChnl->pChnlMgr;
1835 + } else {
1836 + status = DSP_EHANDLE;
1838 + if (DSP_SUCCEEDED(status)) {
1839 + /* Note: Currently, if another thread continues to add IO
1840 + * requests to this channel, this function will continue to
1841 + * flush all such queued IO requests. */
1842 + if (CHNL_IsOutput(uMode) && (pChnl->uChnlType == CHNL_PCPY)) {
1843 + /* Wait for IO completions, up to the specified
1844 + * timeout: */
1845 + while (!LST_IsEmpty(pChnl->pIORequests) &&
1846 + DSP_SUCCEEDED(status)) {
1847 + status = WMD_CHNL_GetIOC(hChnl, dwTimeOut,
1848 + &chnlIOC);
1849 + if (DSP_FAILED(status))
1850 + continue;
1852 + if (chnlIOC.status & CHNL_IOCSTATTIMEOUT)
1853 + status = CHNL_E_WAITTIMEOUT;
1856 + } else {
1857 + status = WMD_CHNL_CancelIO(hChnl);
1858 + /* Now, leave the channel in the ready state: */
1859 + pChnl->dwState &= ~CHNL_STATECANCEL;
1862 + DBC_Ensure(DSP_FAILED(status) || LST_IsEmpty(pChnl->pIORequests));
1863 + return status;
1867 + * ======== WMD_CHNL_GetInfo ========
1868 + * Purpose:
1869 + * Retrieve information related to a channel.
1870 + */
1871 +DSP_STATUS WMD_CHNL_GetInfo(struct CHNL_OBJECT *hChnl,
1872 + OUT struct CHNL_INFO *pInfo)
1874 + DSP_STATUS status = DSP_SOK;
1875 + struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl;
1876 + if (pInfo != NULL) {
1877 + if (MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) {
1878 + /* Return the requested information: */
1879 + pInfo->hChnlMgr = pChnl->pChnlMgr;
1880 + pInfo->hEvent = pChnl->hUserEvent;
1881 + pInfo->dwID = pChnl->uId;
1882 + pInfo->dwMode = pChnl->uMode;
1883 + pInfo->cPosition = pChnl->cBytesMoved;
1884 + pInfo->hProcess = pChnl->hProcess;
1885 + pInfo->hSyncEvent = pChnl->hSyncEvent;
1886 + pInfo->cIOCs = pChnl->cIOCs;
1887 + pInfo->cIOReqs = pChnl->cIOReqs;
1888 + pInfo->dwState = pChnl->dwState;
1889 + } else {
1890 + status = DSP_EHANDLE;
1892 + } else {
1893 + status = DSP_EPOINTER;
1895 + return status;
1899 + * ======== WMD_CHNL_GetIOC ========
1900 + * Optionally wait for I/O completion on a channel. Dequeue an I/O
1901 + * completion record, which contains information about the completed
1902 + * I/O request.
1903 + * Note: Ensures Channel Invariant (see notes above).
1904 + */
1905 +DSP_STATUS WMD_CHNL_GetIOC(struct CHNL_OBJECT *hChnl, u32 dwTimeOut,
1906 + OUT struct CHNL_IOC *pIOC)
1908 + DSP_STATUS status = DSP_SOK;
1909 + struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl;
1910 + struct CHNL_IRP *pChirp;
1911 + DSP_STATUS statSync;
1912 + bool fDequeueIOC = true;
1913 + struct CHNL_IOC ioc = { NULL, 0, 0, 0, 0 };
1914 + u8 *pHostSysBuf = NULL;
1916 + DBG_Trace(DBG_ENTER, "> WMD_CHNL_GetIOC pChnl %p CHNL_IsOutput %x "
1917 + "uChnlType %x\n", pChnl, CHNL_IsOutput(pChnl->uMode),
1918 + pChnl->uChnlType);
1919 + /* Check args: */
1920 + if (pIOC == NULL) {
1921 + status = DSP_EPOINTER;
1922 + } else if (!MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) {
1923 + status = DSP_EHANDLE;
1924 + } else if (dwTimeOut == CHNL_IOCNOWAIT) {
1925 + if (LST_IsEmpty(pChnl->pIOCompletions))
1926 + status = CHNL_E_NOIOC;
1929 + if (DSP_FAILED(status))
1930 + goto func_end;
1932 + ioc.status = CHNL_IOCSTATCOMPLETE;
1933 + if (dwTimeOut != CHNL_IOCNOWAIT && LST_IsEmpty(pChnl->pIOCompletions)) {
1934 + if (dwTimeOut == CHNL_IOCINFINITE)
1935 + dwTimeOut = SYNC_INFINITE;
1937 + statSync = SYNC_WaitOnEvent(pChnl->hSyncEvent, dwTimeOut);
1938 + if (statSync == DSP_ETIMEOUT) {
1939 + /* No response from DSP */
1940 + ioc.status |= CHNL_IOCSTATTIMEOUT;
1941 + fDequeueIOC = false;
1942 + } else if (statSync == DSP_EFAIL) {
1943 + /* This can occur when the user mode thread is
1944 + * aborted (^C), or when _VWIN32_WaitSingleObject()
1945 + * fails due to unkown causes. */
1946 + /* Even though Wait failed, there may be something in
1947 + * the Q: */
1948 + if (LST_IsEmpty(pChnl->pIOCompletions)) {
1949 + ioc.status |= CHNL_IOCSTATCANCEL;
1950 + fDequeueIOC = false;
1954 + /* See comment in AddIOReq */
1955 + SYNC_EnterCS(pChnl->pChnlMgr->hCSObj);
1956 + disable_irq(MAILBOX_IRQ);
1957 + if (fDequeueIOC) {
1958 + /* Dequeue IOC and set pIOC; */
1959 + DBC_Assert(!LST_IsEmpty(pChnl->pIOCompletions));
1960 + pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->pIOCompletions);
1961 + /* Update pIOC from channel state and chirp: */
1962 + if (pChirp) {
1963 + pChnl->cIOCs--;
1964 + /* If this is a zero-copy channel, then set IOC's pBuf
1965 + * to the DSP's address. This DSP address will get
1966 + * translated to user's virtual addr later. */
1968 + pHostSysBuf = pChirp->pHostSysBuf;
1969 + ioc.pBuf = pChirp->pHostUserBuf;
1971 + ioc.cBytes = pChirp->cBytes;
1972 + ioc.cBufSize = pChirp->cBufSize;
1973 + ioc.dwArg = pChirp->dwArg;
1974 + ioc.status |= pChirp->status;
1975 + /* Place the used chirp on the free list: */
1976 + LST_PutTail(pChnl->pFreeList, (struct LST_ELEM *)
1977 + pChirp);
1978 + } else {
1979 + ioc.pBuf = NULL;
1980 + ioc.cBytes = 0;
1982 + } else {
1983 + ioc.pBuf = NULL;
1984 + ioc.cBytes = 0;
1985 + ioc.dwArg = 0;
1986 + ioc.cBufSize = 0;
1988 + /* Ensure invariant: If any IOC's are queued for this channel... */
1989 + if (!LST_IsEmpty(pChnl->pIOCompletions)) {
1990 + /* Since DSPStream_Reclaim() does not take a timeout
1991 + * parameter, we pass the stream's timeout value to
1992 + * WMD_CHNL_GetIOC. We cannot determine whether or not
1993 + * we have waited in User mode. Since the stream's timeout
1994 + * value may be non-zero, we still have to set the event.
1995 + * Therefore, this optimization is taken out.
1997 + * if (dwTimeOut == CHNL_IOCNOWAIT) {
1998 + * ... ensure event is set..
1999 + * SYNC_SetEvent(pChnl->hSyncEvent);
2000 + * } */
2001 + SYNC_SetEvent(pChnl->hSyncEvent);
2002 + } else {
2003 + /* else, if list is empty, ensure event is reset. */
2004 + SYNC_ResetEvent(pChnl->hSyncEvent);
2006 + enable_irq(MAILBOX_IRQ);
2007 + SYNC_LeaveCS(pChnl->pChnlMgr->hCSObj);
2008 + if (fDequeueIOC && (pChnl->uChnlType == CHNL_PCPY && pChnl->uId > 1)) {
2009 + if (!(ioc.pBuf < (void *) USERMODE_ADDR))
2010 + goto func_cont;
2012 + /* If the addr is in user mode, then copy it */
2013 + if (!pHostSysBuf || !ioc.pBuf) {
2014 + status = DSP_EPOINTER;
2015 + DBG_Trace(DBG_LEVEL7,
2016 + "System buffer NULL in IO completion.\n");
2017 + goto func_cont;
2019 + if (!CHNL_IsInput(pChnl->uMode))
2020 + goto func_cont1;
2022 + /*pHostUserBuf */
2023 + status = copy_to_user(ioc.pBuf, pHostSysBuf, ioc.cBytes);
2024 +#ifndef RES_CLEANUP_DISABLE
2025 + if (status) {
2026 + if (current->flags & PF_EXITING) {
2027 + DBG_Trace(DBG_LEVEL7,
2028 + "\n2current->flags == PF_EXITING, "
2029 + " current->flags;0x%x\n",
2030 + current->flags);
2031 + status = 0;
2032 + } else {
2033 + DBG_Trace(DBG_LEVEL7,
2034 + "\n2current->flags != PF_EXITING, "
2035 + " current->flags;0x%x\n",
2036 + current->flags);
2039 +#endif
2040 + if (status) {
2041 + DBG_Trace(DBG_LEVEL7,
2042 + "Error copying kernel buffer to user, %d"
2043 + " bytes remaining. in_interupt %d\n",
2044 + status, in_interrupt());
2045 + status = DSP_EPOINTER;
2047 +func_cont1:
2048 + MEM_Free(pHostSysBuf);
2050 +func_cont:
2051 + /* Update User's IOC block: */
2052 + *pIOC = ioc;
2053 +func_end:
2054 + DBG_Trace(DBG_ENTER, "< WMD_CHNL_GetIOC pChnl %p\n", pChnl);
2055 + return status;
2059 + * ======== WMD_CHNL_GetMgrInfo ========
2060 + * Retrieve information related to the channel manager.
2061 + */
2062 +DSP_STATUS WMD_CHNL_GetMgrInfo(struct CHNL_MGR *hChnlMgr, u32 uChnlID,
2063 + OUT struct CHNL_MGRINFO *pMgrInfo)
2065 + DSP_STATUS status = DSP_SOK;
2066 + struct CHNL_MGR *pChnlMgr = (struct CHNL_MGR *)hChnlMgr;
2068 + if (pMgrInfo != NULL) {
2069 + if (uChnlID <= CHNL_MAXCHANNELS) {
2070 + if (MEM_IsValidHandle(hChnlMgr, CHNL_MGRSIGNATURE)) {
2071 + /* Return the requested information: */
2072 + pMgrInfo->hChnl = pChnlMgr->apChannel[uChnlID];
2073 + pMgrInfo->cOpenChannels = pChnlMgr->
2074 + cOpenChannels;
2075 + pMgrInfo->dwType = pChnlMgr->dwType;
2076 + /* total # of chnls */
2077 + pMgrInfo->cChannels = pChnlMgr->cChannels;
2078 + } else {
2079 + status = DSP_EHANDLE;
2081 + } else {
2082 + status = CHNL_E_BADCHANID;
2084 + } else {
2085 + status = DSP_EPOINTER;
2088 + return status;
2092 + * ======== WMD_CHNL_Idle ========
2093 + * Idles a particular channel.
2094 + */
2095 +DSP_STATUS WMD_CHNL_Idle(struct CHNL_OBJECT *hChnl, u32 dwTimeOut,
2096 + bool fFlush)
2098 + CHNL_MODE uMode;
2099 + struct CHNL_MGR *pChnlMgr;
2100 + DSP_STATUS status = DSP_SOK;
2102 + DBC_Require(MEM_IsValidHandle(hChnl, CHNL_SIGNATURE));
2104 + uMode = hChnl->uMode;
2105 + pChnlMgr = hChnl->pChnlMgr;
2107 + if (CHNL_IsOutput(uMode) && !fFlush) {
2108 + /* Wait for IO completions, up to the specified timeout: */
2109 + status = WMD_CHNL_FlushIO(hChnl, dwTimeOut);
2110 + } else {
2111 + status = WMD_CHNL_CancelIO(hChnl);
2113 + /* Reset the byte count and put channel back in ready state. */
2114 + hChnl->cBytesMoved = 0;
2115 + hChnl->dwState &= ~CHNL_STATECANCEL;
2118 + return status;
2122 + * ======== WMD_CHNL_Open ========
2123 + * Open a new half-duplex channel to the DSP board.
2124 + */
2125 +DSP_STATUS WMD_CHNL_Open(OUT struct CHNL_OBJECT **phChnl,
2126 + struct CHNL_MGR *hChnlMgr, CHNL_MODE uMode,
2127 + u32 uChnlId, CONST IN struct CHNL_ATTRS *pAttrs)
2129 + DSP_STATUS status = DSP_SOK;
2130 + struct CHNL_MGR *pChnlMgr = hChnlMgr;
2131 + struct CHNL_OBJECT *pChnl = NULL;
2132 + struct SYNC_ATTRS *pSyncAttrs = NULL;
2133 + struct SYNC_OBJECT *hSyncEvent = NULL;
2134 + /* Ensure DBC requirements: */
2135 + DBC_Require(phChnl != NULL);
2136 + DBC_Require(pAttrs != NULL);
2137 + *phChnl = NULL;
2138 + /* Validate Args: */
2139 + if (pAttrs->uIOReqs == 0) {
2140 + status = DSP_EINVALIDARG;
2141 + } else {
2142 + if (!MEM_IsValidHandle(hChnlMgr, CHNL_MGRSIGNATURE)) {
2143 + status = DSP_EHANDLE;
2144 + } else {
2145 + if (uChnlId != CHNL_PICKFREE) {
2146 + if (uChnlId >= pChnlMgr->cChannels) {
2147 + status = CHNL_E_BADCHANID;
2148 + } else if (pChnlMgr->apChannel[uChnlId] !=
2149 + NULL) {
2150 + status = CHNL_E_CHANBUSY;
2152 + } else {
2153 + /* Check for free channel */
2154 + status = SearchFreeChannel(pChnlMgr, &uChnlId);
2158 + if (DSP_FAILED(status))
2159 + goto func_end;
2161 + DBC_Assert(uChnlId < pChnlMgr->cChannels);
2162 + /* Create channel object: */
2163 + MEM_AllocObject(pChnl, struct CHNL_OBJECT, 0x0000);
2164 + if (!pChnl) {
2165 + status = DSP_EMEMORY;
2166 + goto func_cont;
2168 + /* Protect queues from IO_DPC: */
2169 + pChnl->dwState = CHNL_STATECANCEL;
2170 + /* Allocate initial IOR and IOC queues: */
2171 + pChnl->pFreeList = CreateChirpList(pAttrs->uIOReqs);
2172 + pChnl->pIORequests = CreateChirpList(0);
2173 + pChnl->pIOCompletions = CreateChirpList(0);
2174 + pChnl->cChirps = pAttrs->uIOReqs;
2175 + pChnl->cIOCs = 0;
2176 + pChnl->cIOReqs = 0;
2177 + /* #WinCE# Let SYNC_ create our event */
2178 + status = SYNC_OpenEvent(&hSyncEvent, pSyncAttrs);
2179 + if (DSP_SUCCEEDED(status)) {
2180 + status = NTFY_Create(&pChnl->hNtfy);
2181 + if (DSP_FAILED(status)) {
2182 + /* The only failure that could have occurred */
2183 + status = DSP_EMEMORY;
2186 + if (DSP_SUCCEEDED(status)) {
2187 + if (pChnl->pIOCompletions && pChnl->pIORequests &&
2188 + pChnl->pFreeList) {
2189 + /* Initialize CHNL object fields: */
2190 + pChnl->pChnlMgr = pChnlMgr;
2191 + pChnl->uId = uChnlId;
2192 + pChnl->uMode = uMode;
2193 + pChnl->hUserEvent = hSyncEvent; /* for Linux */
2194 + pChnl->hSyncEvent = hSyncEvent;
2195 + PRCS_GetCurrentHandle(&pChnl->hProcess);
2196 + pChnl->pCBArg = 0;
2197 + pChnl->cBytesMoved = 0;
2198 + /* Default to proc-copy */
2199 + pChnl->uChnlType = CHNL_PCPY;
2200 + } else {
2201 + status = DSP_EMEMORY;
2203 + } else {
2204 + status = DSP_EINVALIDARG;
2206 + if (DSP_FAILED(status)) {
2207 + /* Free memory */
2208 + if (pChnl->pIOCompletions) {
2209 + FreeChirpList(pChnl->pIOCompletions);
2210 + pChnl->pIOCompletions = NULL;
2211 + pChnl->cIOCs = 0;
2213 + if (pChnl->pIORequests) {
2214 + FreeChirpList(pChnl->pIORequests);
2215 + pChnl->pIORequests = NULL;
2217 + if (pChnl->pFreeList) {
2218 + FreeChirpList(pChnl->pFreeList);
2219 + pChnl->pFreeList = NULL;
2221 + if (hSyncEvent) {
2222 + SYNC_CloseEvent(hSyncEvent);
2223 + hSyncEvent = NULL;
2225 + if (pChnl->hNtfy) {
2226 + NTFY_Delete(pChnl->hNtfy);
2227 + pChnl->hNtfy = NULL;
2229 + MEM_FreeObject(pChnl);
2231 +func_cont:
2232 + if (DSP_SUCCEEDED(status)) {
2233 + /* Insert channel object in channel manager: */
2234 + pChnlMgr->apChannel[pChnl->uId] = pChnl;
2235 + SYNC_EnterCS(pChnlMgr->hCSObj);
2236 + pChnlMgr->cOpenChannels++;
2237 + SYNC_LeaveCS(pChnlMgr->hCSObj);
2238 + /* Return result... */
2239 + pChnl->dwSignature = CHNL_SIGNATURE;
2240 + pChnl->dwState = CHNL_STATEREADY;
2241 + *phChnl = pChnl;
2243 +func_end:
2244 + DBC_Ensure((DSP_SUCCEEDED(status) &&
2245 + MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) ||
2246 + (*phChnl == NULL));
2247 + return status;
2251 + * ======== WMD_CHNL_RegisterNotify ========
2252 + * Registers for events on a particular channel.
2253 + */
2254 +DSP_STATUS WMD_CHNL_RegisterNotify(struct CHNL_OBJECT *hChnl, u32 uEventMask,
2255 + u32 uNotifyType,
2256 + struct DSP_NOTIFICATION *hNotification)
2258 + DSP_STATUS status = DSP_SOK;
2260 + DBC_Assert(!(uEventMask & ~(DSP_STREAMDONE | DSP_STREAMIOCOMPLETION)));
2262 + status = NTFY_Register(hChnl->hNtfy, hNotification, uEventMask,
2263 + uNotifyType);
2265 + return status;
2269 + * ======== CreateChirpList ========
2270 + * Purpose:
2271 + * Initialize a queue of channel I/O Request/Completion packets.
2272 + * Parameters:
2273 + * uChirps: Number of Chirps to allocate.
2274 + * Returns:
2275 + * Pointer to queue of IRPs, or NULL.
2276 + * Requires:
2277 + * Ensures:
2278 + */
2279 +static struct LST_LIST *CreateChirpList(u32 uChirps)
2281 + struct LST_LIST *pChirpList;
2282 + struct CHNL_IRP *pChirp;
2283 + u32 i;
2285 + pChirpList = LST_Create();
2287 + if (pChirpList) {
2288 + /* Make N chirps and place on queue. */
2289 + for (i = 0; (i < uChirps) && ((pChirp = MakeNewChirp()) !=
2290 + NULL); i++) {
2291 + LST_PutTail(pChirpList, (struct LST_ELEM *)pChirp);
2294 + /* If we couldn't allocate all chirps, free those allocated: */
2295 + if (i != uChirps) {
2296 + FreeChirpList(pChirpList);
2297 + pChirpList = NULL;
2301 + return pChirpList;
2305 + * ======== FreeChirpList ========
2306 + * Purpose:
2307 + * Free the queue of Chirps.
2308 + */
2309 +static void FreeChirpList(struct LST_LIST *pChirpList)
2311 + DBC_Require(pChirpList != NULL);
2313 + while (!LST_IsEmpty(pChirpList))
2314 + MEM_Free(LST_GetHead(pChirpList));
2316 + LST_Delete(pChirpList);
2320 + * ======== MakeNewChirp ========
2321 + * Allocate the memory for a new channel IRP.
2322 + */
2323 +static struct CHNL_IRP *MakeNewChirp(void)
2325 + struct CHNL_IRP *pChirp;
2327 + pChirp = (struct CHNL_IRP *)MEM_Calloc(
2328 + sizeof(struct CHNL_IRP), MEM_NONPAGED);
2329 + if (pChirp != NULL) {
2330 + /* LST_InitElem only resets the list's member values. */
2331 + LST_InitElem(&pChirp->link);
2334 + return pChirp;
2338 + * ======== SearchFreeChannel ========
2339 + * Search for a free channel slot in the array of channel pointers.
2340 + */
2341 +static DSP_STATUS SearchFreeChannel(struct CHNL_MGR *pChnlMgr,
2342 + OUT u32 *pdwChnl)
2344 + DSP_STATUS status = CHNL_E_OUTOFSTREAMS;
2345 + u32 i;
2347 + DBC_Require(MEM_IsValidHandle(pChnlMgr, CHNL_MGRSIGNATURE));
2349 + for (i = 0; i < pChnlMgr->cChannels; i++) {
2350 + if (pChnlMgr->apChannel[i] == NULL) {
2351 + status = DSP_SOK;
2352 + *pdwChnl = i;
2353 + break;
2357 + return status;
2359 Index: lk/drivers/dsp/bridge/wmd/io_sm.c
2360 ===================================================================
2361 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
2362 +++ lk/drivers/dsp/bridge/wmd/io_sm.c 2008-08-18 10:38:38.000000000 +0300
2363 @@ -0,0 +1,1843 @@
2365 + * linux/drivers/dsp/bridge/wmd/linux/omap/wmdchnl/common/io_sm.c
2367 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
2369 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
2371 + * This package is free software; you can redistribute it and/or modify
2372 + * it under the terms of the GNU General Public License version 2 as
2373 + * published by the Free Software Foundation.
2375 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
2376 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
2377 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2378 + */
2381 + * ======== io_sm.c ========
2382 + * Description:
2383 + * IO dispatcher for a shared memory channel driver.
2385 + * Public Functions:
2386 + * WMD_IO_Create
2387 + * WMD_IO_Destroy
2388 + * WMD_IO_OnLoaded
2389 + * IO_AndSetValue
2390 + * IO_BufSize
2391 + * IO_CancelChnl
2392 + * IO_DPC
2393 + * IO_ISR
2394 + * IO_IVAISR
2395 + * IO_OrSetValue
2396 + * IO_ReadValue
2397 + * IO_ReadValueLong
2398 + * IO_RequestChnl
2399 + * IO_Schedule
2400 + * IO_WriteValue
2401 + * IO_WriteValueLong
2403 + * Channel Invariant:
2404 + * There is an important invariant condition which must be maintained per
2405 + * channel outside of WMD_CHNL_GetIOC() and IO_Dispatch(), violation of
2406 + * which may cause timeouts and/or failure of the WIN32_WaitSingleObject
2407 + * function (SYNC_WaitOnEvent).
2409 + *! Revision History:
2410 + *! ================
2411 + *! 28-Apr-2004 vp: Updated IVA MMU entries based on Aptix validation.
2412 + *! 19-Apr-2004 sb: Clear MBX_DEH_RESET from hIOMgr->wIntrVal to prevent
2413 + DEH when MPU invokes DPC before next DSP interrupt.
2414 + Revert back GP timer mapping endianness to LE
2415 + *! 22-Apr-2004 sb: Fixed SHM & peripherals endianness settings for 2420
2416 + Optimized num. of SHM entries for any SHM size.
2417 + *! 08-Mar-2004 sb: Updated HW_MMU page size macros
2418 + *! 09-Feb-2004 vp: Updated for IVA link driver.
2419 + *! 05-Jan-2004 vp: Updated for the 24xx platform.
2420 + *! 23-Apr-2003 sb: Fixed mailbox deadlock
2421 + *! 13-Apr-2003 vp: Updated to support TC Word Swap option.
2422 + *! 21-Mar-2003 sb: OEM configuration updates
2423 + *! 24-Feb-2003 vp: Code Review Updates.
2424 + *! 18-Oct-2002 sb: Ported to Linux platform
2425 + *! 28-Mar-2002 jeh Assume word addresses for SHM, MSG, ... symbol values.
2426 + *! 25-Jan-2002 ag bDspAck incorrectly set in IO_DDZCDispatchChnl()
2427 + *! 05-Jan-2002 ag Set MBX value to DSP using IO_InterruptDSP2().
2428 + *! Check for CHNL_STATECANCEL in ACK processing.
2429 + *! 20-Dec-2001 ag Removed #ifdef CHNL_NOIPCINTR & CHNL_PREOMAP for DSP-DMA.
2430 + *! Removed unused fxn GetDDMAChnl().
2431 + *! 11-Dec-2001 ag Fix in DDMA_Dispatch for multi-bufs.
2432 + *! 06-Nov-2001 ag DSP-DMA I/O processing support added.
2433 + *! 05-Nov-2001 kc Updated to support DEH module.
2434 + *! 18-Sep-2001 ag Using virtual cached addressing for SM.
2435 + *! 29-Aug-2001 ag User SM regions registered during prog load.
2436 + *! 10-Aug-2001 ag Removed dependency on platform\inc\Config.h.
2437 + *! MMU setup OnLoaded & per DEV context.
2438 + *! 08-May-2001 ag Don't SwapWord if TIHELEN.
2439 + *! 31-May-2001 ag Fixed bug in pInput calc.
2440 + *! 21-May-2001 ag Helen SM uses TICFG_BRIDGE_DATA_BASE[SIZE] in Config.h.
2441 + *! 04-May-2001 jeh Replaced CHNL_PREOMAP with CHNL_OMAP, added CHNL_HELEN.
2442 + *! Cleaned up WMD_IO_OnLoaded a bit.
2443 + *! 10-Apr-2001 rr: Replaced DBG_ENTER with DBG_LEVEL3.
2444 + *! 28-Mar-2001 ag Added CHNL_NOIPCINTR. Disables IPC INTR handling.
2445 + *! 16-Feb-2001 jeh Messaging disabled for PREOMAP.
2446 + *! 16-Dec-2000 ag IO_DispatchMsg() enabled for PreOMAP.
2447 + *! SM must be in last 4 Meg region SDRAM for PreOMAP.
2448 + *! 14-Dec-2000 jeh Now reads SM addresses from COFF for PreOMAP.
2449 + *! 04-Dec-2000 jeh Bug fixes for messaging.
2450 + *! 20-Nov-2000 jeh Updated to handle messaging.
2451 + *! 23-Oct-2000 jeh Added notifications of IO complete and end of stream for
2452 + *! DSPStream support. Pass arg in SHM structure.
2453 + *! 07-Jul-2000 rr: Changed Prefix proc to prcs for Process module.
2454 + *! 03-Feb-2000 rr: DBG statements during fxn entry added.
2455 + *! 21-Jan-2000 ag: Clean-up per code review.
2456 + *! 10-Dev-1999 ag: Added critical section in IO_Dispatch() to protect IOCL/IOR.
2457 + *! Removed DBC_Asserts after cancelled/closed channels.
2458 + *! Replaced x86 specific __asm int 3 with DBC_Assert(false);
2459 + *! 12-Nov-1999 ag: Removed some warnings when compiling for 16 bit targets.
2460 + *! (See #if _CHNL_WORDSIZE).
2461 + *! 04-Nov-1999 ag: WinCE port.
2462 + *! 25-May-1999 jg: Test that CHNL_IOCLASS boards have a loaded program with
2463 + *! a defined shared memory buffer.
2464 + *! 09-Jul-1997 gp: Added some checks for validity of SHM control block values.
2465 + *! 17-Jan-1997 db: Added capability to log shared memory header.
2466 + *! 15-Jan-1997 gp: Code Review mods: moved static dwLastId to CHNL_MGR object.
2467 + *! 03-Jan-1997 gp: Added call to CHNLSM_DPC from IO_DPC. Check for ISR failing
2468 + *! to process interrupt on a non-shared IRQ line.
2469 + *! 10-Dec-1996 gp: Added EOS notification on input channel (CHNL_MODEFROMDSP).
2470 + *! 27-Nov-1996 gp: Fixed bug in IO_Dispatch(), which fixed flushing.
2471 + *! 23-Oct-1996 gp: Ensure client buffer bounds are not overrun on input.
2472 + *! 12-Aug-1996 gp: Created.
2473 + */
2475 +/* ----------------------------------- Host OS */
2476 +#include <host_os.h>
2477 +#ifndef CONFIG_DISABLE_BRIDGE_PM
2478 +#ifndef CONFIG_DISABLE_BRIDGE_DVFS
2479 +#include <asm/arch/resource.h>
2480 +#endif
2481 +#endif
2483 +/* ----------------------------------- DSP/BIOS Bridge */
2484 +#include <std.h>
2485 +#include <dbdefs.h>
2486 +#include <errbase.h>
2488 +/* ----------------------------------- Trace & Debug */
2489 +#include <dbc.h>
2490 +#include <dbg.h>
2492 +/* ----------------------------------- OS Adaptation Layer */
2493 +#include <cfg.h>
2494 +#include <dpc.h>
2495 +#include <mem.h>
2496 +#include <ntfy.h>
2497 +#include <sync.h>
2498 +#include <reg.h>
2500 +/* ------------------------------------ Hardware Abstraction Layer */
2501 +#include <hw_defs.h>
2502 +#include <hw_mmu.h>
2504 +/* ----------------------------------- Mini Driver */
2505 +#include <wmddeh.h>
2506 +#include <wmdio.h>
2507 +#include <wmdioctl.h>
2508 +#include <_tiomap.h>
2509 +#include <tiomap_io.h>
2510 +#include <_tiomap_pwr.h>
2511 +#include <tiomap_io.h>
2513 +/* ----------------------------------- Platform Manager */
2514 +#include <cod.h>
2515 +#include <dev.h>
2516 +#include <chnl_sm.h>
2517 +#include <dbreg.h>
2519 +/* ----------------------------------- Others */
2520 +#include <rms_sh.h>
2521 +#include <mgr.h>
2522 +#include "_cmm.h"
2524 +/* ----------------------------------- This */
2525 +#include <io_sm.h>
2526 +#include "_msg_sm.h"
2528 +/* ----------------------------------- Defines, Data Structures, Typedefs */
2529 +#define OUTPUTNOTREADY 0xffff
2530 +#define NOTENABLED 0xffff /* channel(s) not enabled */
2532 +#define EXTEND "_EXT_END"
2534 +#define SwapWord(x) (x)
2535 +#define ulPageAlignSize 0x10000 /* Page Align Size */
2537 +#define MAX_PM_REQS 32
2539 +/* IO Manager: only one created per board: */
2540 +struct IO_MGR {
2541 + /* These four fields must be the first fields in a IO_MGR_ struct: */
2542 + u32 dwSignature; /* Used for object validation */
2543 + struct WMD_DEV_CONTEXT *hWmdContext; /* WMD device context */
2544 + struct WMD_DRV_INTERFACE *pIntfFxns; /* Function interface to WMD */
2545 + struct DEV_OBJECT *hDevObject; /* Device this board represents */
2547 + /* These fields initialized in WMD_IO_Create(): */
2548 + struct CHNL_MGR *hChnlMgr;
2549 + struct SHM *pSharedMem; /* Shared Memory control */
2550 + u8 *pInput; /* Address of input channel */
2551 + u8 *pOutput; /* Address of output channel */
2552 + struct MSG_MGR *hMsgMgr; /* Message manager */
2553 + struct MSG *pMsgInputCtrl; /* Msg control for from DSP messages */
2554 + struct MSG *pMsgOutputCtrl; /* Msg control for to DSP messages */
2555 + u8 *pMsgInput; /* Address of input messages */
2556 + u8 *pMsgOutput; /* Address of output messages */
2557 + u32 uSMBufSize; /* Size of a shared memory I/O channel */
2558 + struct ISR_IRQ *hIRQ; /* Virutalized IRQ handle */
2559 + bool fSharedIRQ; /* Is this IRQ shared? */
2560 + struct DPC_OBJECT *hDPC; /* DPC object handle */
2561 + struct SYNC_CSOBJECT *hCSObj; /* Critical section object handle */
2562 + u32 uWordSize; /* Size in bytes of DSP word */
2563 + u16 wIntrVal; /* interrupt value */
2564 + /* private extnd proc info; mmu setup */
2565 + struct MGR_PROCESSOREXTINFO extProcInfo;
2566 + struct CMM_OBJECT *hCmmMgr; /* Shared Mem Mngr */
2567 + u32 dQuePowerMbxVal[MAX_PM_REQS];
2568 + u32 iQuePowerHead;
2569 + u32 iQuePowerTail;
2570 +#ifndef DSP_TRACEBUF_DISABLED
2571 + u32 ulTraceBufferBegin; /* Trace message start address */
2572 + u32 ulTraceBufferEnd; /* Trace message end address */
2573 + u32 ulTraceBufferCurrent; /* Trace message current address */
2574 + u32 ulGPPReadPointer; /* GPP Read pointer to Trace buffer */
2575 + u8 *pMsg;
2576 + u32 ulGppVa;
2577 + u32 ulDspVa;
2578 +#endif
2579 +} ;
2581 +/* ----------------------------------- Function Prototypes */
2582 +static void IO_DispatchChnl(IN struct IO_MGR *pIOMgr,
2583 + IN OUT struct CHNL_OBJECT *pChnl, u32 iMode);
2584 +static void IO_DispatchMsg(IN struct IO_MGR *pIOMgr, struct MSG_MGR *hMsgMgr);
2585 +static void IO_DispatchPM(IN struct IO_MGR *pIOMgr);
2586 +static void NotifyChnlComplete(struct CHNL_OBJECT *pChnl,
2587 + struct CHNL_IRP *pChirp);
2588 +static void InputChnl(struct IO_MGR *pIOMgr, struct CHNL_OBJECT *pChnl,
2589 + u32 iMode);
2590 +static void OutputChnl(struct IO_MGR *pIOMgr, struct CHNL_OBJECT *pChnl,
2591 + u32 iMode);
2592 +static void InputMsg(struct IO_MGR *pIOMgr, struct MSG_MGR *hMsgMgr);
2593 +static void OutputMsg(struct IO_MGR *pIOMgr, struct MSG_MGR *hMsgMgr);
2594 +static u32 FindReadyOutput(struct CHNL_MGR *pChnlMgr,
2595 + struct CHNL_OBJECT *pChnl, u32 dwMask);
2596 +static u32 ReadData(struct WMD_DEV_CONTEXT *hDevContext, void *pDest,
2597 + void *pSrc, u32 uSize);
2598 +static u32 WriteData(struct WMD_DEV_CONTEXT *hDevContext, void *pDest,
2599 + void *pSrc, u32 uSize);
2600 +#ifndef DSP_TRACEBUF_DISABLED
2601 +void PrintDSPDebugTrace(struct IO_MGR *hIOMgr);
2602 +#endif
2604 +/* Bus Addr (cached kernel)*/
2605 +static DSP_STATUS registerSHMSegs(struct IO_MGR *hIOMgr,
2606 + struct COD_MANAGER *hCodMan,
2607 + u32 dwGPPBasePA);
2609 +extern u32 DRV_GetFirstDevExtension();
2611 +#ifndef CONFIG_DISABLE_BRIDGE_PM
2612 +#ifndef CONFIG_DISABLE_BRIDGE_DVFS
2613 +/* The maximum number of OPPs that are supported by Baseport */
2614 +extern s32 dsp_max_opps;
2615 +/* The Vdd1 opp table information */
2616 +extern u32 vdd1_dsp_freq[6][4] ;
2617 +/* The contraint handle for OPP information */
2618 +extern struct constraint_handle *dsp_constraint_handle;
2619 +#endif
2620 +#endif
2622 + * ======== WMD_IO_Create ========
2623 + * Create an IO manager object.
2624 + */
2625 +DSP_STATUS WMD_IO_Create(OUT struct IO_MGR **phIOMgr,
2626 + struct DEV_OBJECT *hDevObject,
2627 + IN CONST struct IO_ATTRS *pMgrAttrs)
2629 + DSP_STATUS status = DSP_SOK;
2630 + struct IO_MGR *pIOMgr = NULL;
2631 + struct SHM *pSharedMem = NULL;
2632 + struct WMD_DEV_CONTEXT *hWmdContext = NULL;
2633 + struct CFG_HOSTRES hostRes;
2634 + struct CFG_DEVNODE *hDevNode;
2635 + struct CHNL_MGR *hChnlMgr;
2636 + u32 devType;
2637 + /* Check DBC requirements: */
2638 + DBC_Require(phIOMgr != NULL);
2639 + DBC_Require(pMgrAttrs != NULL);
2640 + DBC_Require(pMgrAttrs->uWordSize != 0);
2641 + /* This for the purposes of DBC_Require: */
2642 + status = DEV_GetChnlMgr(hDevObject, &hChnlMgr);
2643 + DBC_Require(status != DSP_EHANDLE);
2644 + DBC_Require(hChnlMgr != NULL);
2645 + DBC_Require(hChnlMgr->hIOMgr == NULL);
2646 + /* Message manager will be created when a file is loaded, since
2647 + * size of message buffer in shared memory is configurable in
2648 + * the base image. */
2649 + DEV_GetWMDContext(hDevObject, &hWmdContext);
2650 + DBC_Assert(hWmdContext);
2651 + DEV_GetDevType(hDevObject, &devType);
2652 + /* DSP shared memory area will get set properly when
2653 + * a program is loaded. They are unknown until a COFF file is
2654 + * loaded. I chose the value -1 because it was less likely to be
2655 + * a valid address than 0. */
2656 + pSharedMem = (struct SHM *) -1;
2657 + if (DSP_FAILED(status))
2658 + goto func_cont;
2660 + /* Allocate IO manager object: */
2661 + MEM_AllocObject(pIOMgr, struct IO_MGR, IO_MGRSIGNATURE);
2662 + if (pIOMgr == NULL) {
2663 + status = DSP_EMEMORY;
2664 + goto func_cont;
2666 + /* Initialize CHNL_MGR object: */
2667 +#ifndef DSP_TRACEBUF_DISABLED
2668 + pIOMgr->pMsg = NULL;
2669 +#endif
2670 + pIOMgr->hChnlMgr = hChnlMgr;
2671 + pIOMgr->uWordSize = pMgrAttrs->uWordSize;
2672 + pIOMgr->pSharedMem = pSharedMem;
2673 + if (DSP_SUCCEEDED(status))
2674 + status = SYNC_InitializeCS(&pIOMgr->hCSObj);
2676 + if (devType == DSP_UNIT) {
2677 + /* Create a DPC object: */
2678 + status = DPC_Create(&pIOMgr->hDPC, IO_DPC, (void *)pIOMgr);
2679 + if (DSP_SUCCEEDED(status))
2680 + status = DEV_GetDevNode(hDevObject, &hDevNode);
2682 + pIOMgr->iQuePowerHead = 0;
2683 + pIOMgr->iQuePowerTail = 0;
2685 + if (DSP_SUCCEEDED(status)) {
2686 + status = CFG_GetHostResources((struct CFG_DEVNODE *)
2687 + DRV_GetFirstDevExtension() , &hostRes);
2689 + if (DSP_SUCCEEDED(status)) {
2690 + pIOMgr->hWmdContext = hWmdContext;
2691 + pIOMgr->fSharedIRQ = pMgrAttrs->fShared;
2692 + IO_DisableInterrupt(hWmdContext);
2693 + if (devType == DSP_UNIT) {
2694 + /* Plug the channel ISR:. */
2695 + status = ISR_Install(&pIOMgr->hIRQ, &hostRes, IO_ISR,
2696 + ISR_MAILBOX1, (void *)pIOMgr);
2698 + if (DSP_SUCCEEDED(status)) {
2699 + /* Enable interrupt used for dsp i/o link */
2700 + /* moved IO_EnableInterrupt(hWmdContext); */
2701 + } else {
2702 + status = CHNL_E_ISR;
2704 + } else {
2705 + status = CHNL_E_ISR;
2707 +func_cont:
2708 + if (DSP_FAILED(status)) {
2709 + /* Cleanup: */
2710 + WMD_IO_Destroy(pIOMgr);
2711 + *phIOMgr = NULL;
2712 + } else {
2713 + /* Return IO manager object to caller... */
2714 + hChnlMgr->hIOMgr = pIOMgr;
2715 + *phIOMgr = pIOMgr;
2717 + return status;
2721 + * ======== WMD_IO_Destroy ========
2722 + * Purpose:
2723 + * Disable interrupts, destroy the IO manager.
2724 + */
2725 +DSP_STATUS WMD_IO_Destroy(struct IO_MGR *hIOMgr)
2727 + DSP_STATUS status = DSP_SOK;
2728 + struct WMD_DEV_CONTEXT *hWmdContext;
2729 + if (MEM_IsValidHandle(hIOMgr, IO_MGRSIGNATURE)) {
2730 + /* Unplug IRQ: */
2731 + if (hIOMgr->hIRQ) {
2732 + /* Disable interrupts from the board: */
2733 + if (DSP_SUCCEEDED(DEV_GetWMDContext(hIOMgr->hDevObject,
2734 + &hWmdContext))) {
2735 + DBC_Assert(hWmdContext);
2737 + (void)CHNLSM_DisableInterrupt(hWmdContext);
2738 + (void)ISR_Uninstall(hIOMgr->hIRQ);
2739 + (void)DPC_Destroy(hIOMgr->hDPC);
2741 +#ifndef DSP_TRACEBUF_DISABLED
2742 + if (hIOMgr->pMsg)
2743 + MEM_Free(hIOMgr->pMsg);
2744 +#endif
2745 + SYNC_DeleteCS(hIOMgr->hCSObj); /* Leak Fix. */
2746 + /* Free this IO manager object: */
2747 + MEM_FreeObject(hIOMgr);
2748 + } else {
2749 + status = DSP_EHANDLE;
2751 + return status;
2755 + * ======== WMD_IO_OnLoaded ========
2756 + * Purpose:
2757 + * Called when a new program is loaded to get shared memory buffer
2758 + * parameters from COFF file. ulSharedBufferBase and ulSharedBufferLimit
2759 + * are in DSP address units.
2760 + */
2761 +DSP_STATUS WMD_IO_OnLoaded(struct IO_MGR *hIOMgr)
2763 + struct COD_MANAGER *hCodMan;
2764 + struct CHNL_MGR *hChnlMgr;
2765 + struct MSG_MGR *hMsgMgr;
2766 + u32 ulShmBase;
2767 + u32 ulShmBaseOffset;
2768 + u32 ulShmLimit;
2769 + u32 ulShmLength = -1;
2770 + u32 ulMemLength = -1;
2771 + u32 ulMsgBase;
2772 + u32 ulMsgLimit;
2773 + u32 ulMsgLength = -1;
2774 + u32 ulExtEnd;
2775 + u32 ulGppPa = 0;
2776 + u32 ulGppVa = 0;
2777 + u32 ulDspVa = 0;
2778 + u32 ulSegSize = 0;
2779 + u32 ulPadSize = 0;
2780 + u32 i;
2781 + DSP_STATUS status = DSP_SOK;
2782 + u32 uNumProcs = 0;
2783 + s32 ndx = 0;
2784 + /* DSP MMU setup table */
2785 + struct WMDIOCTL_EXTPROC aEProc[WMDIOCTL_NUMOFMMUTLB];
2786 + struct CFG_HOSTRES hostRes;
2787 + u32 mapAttrs;
2788 + u32 ulShm0End;
2789 + u32 ulDynExtBase;
2790 + u32 ulSeg1Size = 0;
2791 + u32 paCurr = 0;
2792 + u32 vaCurr = 0;
2793 + u32 gppVaCurr = 0;
2794 + u32 numBytes = 0;
2795 + u32 allBits = 0;
2796 + u32 pgSize[] = { HW_PAGE_SIZE_16MB, HW_PAGE_SIZE_1MB,
2797 + HW_PAGE_SIZE_64KB, HW_PAGE_SIZE_4KB };
2799 + status = DEV_GetCodMgr(hIOMgr->hDevObject, &hCodMan);
2800 + DBC_Assert(DSP_SUCCEEDED(status));
2801 + hChnlMgr = hIOMgr->hChnlMgr;
2802 + /* The message manager is destroyed when the board is stopped. */
2803 + DEV_GetMsgMgr(hIOMgr->hDevObject, &hIOMgr->hMsgMgr);
2804 + hMsgMgr = hIOMgr->hMsgMgr;
2805 + DBC_Assert(MEM_IsValidHandle(hChnlMgr, CHNL_MGRSIGNATURE));
2806 + DBC_Assert(MEM_IsValidHandle(hMsgMgr, MSGMGR_SIGNATURE));
2807 + if (hIOMgr->pSharedMem)
2808 + hIOMgr->pSharedMem = NULL;
2810 + /* Get start and length of channel part of shared memory */
2811 + status = COD_GetSymValue(hCodMan, CHNL_SHARED_BUFFER_BASE_SYM,
2812 + &ulShmBase);
2813 + if (DSP_FAILED(status)) {
2814 + status = CHNL_E_NOMEMMAP;
2815 + goto func_cont1;
2817 + status = COD_GetSymValue(hCodMan, CHNL_SHARED_BUFFER_LIMIT_SYM,
2818 + &ulShmLimit);
2819 + if (DSP_FAILED(status)) {
2820 + status = CHNL_E_NOMEMMAP;
2821 + goto func_cont1;
2823 + if (ulShmLimit <= ulShmBase) {
2824 + status = CHNL_E_INVALIDMEMBASE;
2825 + } else {
2826 + /* get total length in bytes */
2827 + ulShmLength = (ulShmLimit - ulShmBase + 1) * hIOMgr->uWordSize;
2828 + /* Calculate size of a PROCCOPY shared memory region */
2829 + DBG_Trace(DBG_LEVEL7,
2830 + "**(proc)PROCCOPY SHMMEM SIZE: 0x%x bytes\n",
2831 + (ulShmLength - sizeof(struct SHM)));
2833 +func_cont1:
2834 + if (DSP_SUCCEEDED(status)) {
2835 + /* Get start and length of message part of shared memory */
2836 + status = COD_GetSymValue(hCodMan, MSG_SHARED_BUFFER_BASE_SYM,
2837 + &ulMsgBase);
2839 + if (DSP_SUCCEEDED(status)) {
2840 + status = COD_GetSymValue(hCodMan, MSG_SHARED_BUFFER_LIMIT_SYM,
2841 + &ulMsgLimit);
2842 + if (DSP_SUCCEEDED(status)) {
2843 + if (ulMsgLimit <= ulMsgBase) {
2844 + status = CHNL_E_INVALIDMEMBASE;
2845 + } else {
2846 + /* Length (bytes) of messaging part of shared
2847 + * memory */
2848 + ulMsgLength = (ulMsgLimit - ulMsgBase + 1) *
2849 + hIOMgr->uWordSize;
2850 + /* Total length (bytes) of shared memory:
2851 + * chnl + msg */
2852 + ulMemLength = ulShmLength + ulMsgLength;
2854 + } else {
2855 + status = CHNL_E_NOMEMMAP;
2858 + if (DSP_SUCCEEDED(status)) {
2859 +#ifndef DSP_TRACEBUF_DISABLED
2860 + status = COD_GetSymValue(hCodMan, DSP_TRACESEC_END, &ulShm0End);
2861 + DBG_Trace(DBG_LEVEL7, "_BRIDGE_TRACE_END value = %x \n",
2862 + ulShm0End);
2863 +#else
2864 + status = COD_GetSymValue(hCodMan, SHM0_SHARED_END_SYM,
2865 + &ulShm0End);
2866 + DBG_Trace(DBG_LEVEL7, "_SHM0_END = %x \n", ulShm0End);
2867 +#endif
2868 + if (DSP_FAILED(status))
2869 + status = CHNL_E_NOMEMMAP;
2872 + if (DSP_SUCCEEDED(status)) {
2873 + status = COD_GetSymValue(hCodMan, DYNEXTBASE, &ulDynExtBase);
2874 + if (DSP_FAILED(status))
2875 + status = CHNL_E_NOMEMMAP;
2878 + if (DSP_SUCCEEDED(status)) {
2879 + status = COD_GetSymValue(hCodMan, EXTEND, &ulExtEnd);
2880 + if (DSP_FAILED(status))
2881 + status = CHNL_E_NOMEMMAP;
2884 + if (DSP_SUCCEEDED(status)) {
2885 + /* Get memory reserved in host resources */
2886 + (void)MGR_EnumProcessorInfo(0,
2887 + (struct DSP_PROCESSORINFO *)&hIOMgr->extProcInfo,
2888 + sizeof(struct MGR_PROCESSOREXTINFO), &uNumProcs);
2889 + CFG_GetHostResources((
2890 + struct CFG_DEVNODE *)DRV_GetFirstDevExtension(),
2891 + &hostRes);
2892 + /* The first MMU TLB entry(TLB_0) in DCD is ShmBase. */
2893 + ndx = 0;
2894 + ulGppPa = hostRes.dwMemPhys[1];
2895 + ulGppVa = hostRes.dwMemBase[1];
2896 + /* THIS IS THE VIRTUAL UNCACHED IOREMAPPED ADDRESS !!! */
2897 + /* Why can't we directly take the DSPVA from the symbols? */
2898 + ulDspVa = hIOMgr->extProcInfo.tyTlb[0].ulDspVirt;
2899 + ulSegSize = (ulShm0End - ulDspVa) * hIOMgr->uWordSize;
2900 + ulSeg1Size = (ulExtEnd - ulDynExtBase) * hIOMgr->uWordSize;
2901 + ulSeg1Size = (ulSeg1Size + 0xFFF) & (~0xFFFUL); /* 4K align*/
2902 + ulSegSize = (ulSegSize + 0xFFFF) & (~0xFFFFUL); /* 64K align*/
2903 + ulPadSize = ulPageAlignSize - ((ulGppPa + ulSeg1Size) %
2904 + ulPageAlignSize);
2905 + if (ulPadSize == ulPageAlignSize)
2906 + ulPadSize = 0x0;
2908 + DBG_Trace(DBG_LEVEL7, "ulGppPa %x, ulGppVa %x, ulDspVa %x, "
2909 + "ulShm0End %x, ulDynExtBase %x, ulExtEnd %x, "
2910 + "ulSegSize %x ulSeg1Size %x \n", ulGppPa, ulGppVa,
2911 + ulDspVa, ulShm0End, ulDynExtBase, ulExtEnd, ulSegSize,
2912 + ulSeg1Size);
2914 + if ((ulSegSize + ulSeg1Size + ulPadSize) >
2915 + hostRes.dwMemLength[1]) {
2916 + DBG_Trace(DBG_LEVEL7, "ulGppPa %x, ulGppVa %x, ulDspVa "
2917 + "%x, ulShm0End %x, ulDynExtBase %x, ulExtEnd "
2918 + "%x, ulSegSize %x, ulSeg1Size %x \n", ulGppPa,
2919 + ulGppVa, ulDspVa, ulShm0End, ulDynExtBase,
2920 + ulExtEnd, ulSegSize, ulSeg1Size);
2921 + DBG_Trace(DBG_LEVEL7, "Insufficient SHM Reserved 0x%x. "
2922 + "Required 0x%x\n", hostRes.dwMemLength[1],
2923 + ulSegSize + ulSeg1Size + ulPadSize);
2924 + status = DSP_EMEMORY;
2927 + if (DSP_FAILED(status))
2928 + goto func_cont;
2930 + paCurr = ulGppPa;
2931 + vaCurr = ulDynExtBase * hIOMgr->uWordSize;
2932 + gppVaCurr = ulGppVa;
2933 + numBytes = ulSeg1Size;
2935 + /*
2936 + * Try to fit into TLB entries. If not possible, push them to page
2937 + * tables. It is quite possible that if sections are not on
2938 + * bigger page boundary, we may end up making several small pages.
2939 + * So, push them onto page tables, if that is the case.
2940 + */
2941 + mapAttrs = 0x00000000;
2942 + mapAttrs = DSP_MAPLITTLEENDIAN;
2943 + mapAttrs |= DSP_MAPPHYSICALADDR;
2944 + mapAttrs |= DSP_MAPELEMSIZE32;
2945 + while (numBytes && DSP_SUCCEEDED(status)) {
2946 + /* To find the max. page size with which both PA & VA are
2947 + * aligned */
2948 + allBits = paCurr | vaCurr;
2949 + DBG_Trace(DBG_LEVEL1, "allBits %x, paCurr %x, vaCurr %x, "
2950 + "numBytes %x\n", allBits, paCurr, vaCurr, numBytes);
2951 + for (i = 0; i < 4; i++) {
2952 + if ((numBytes >= pgSize[i]) && ((allBits &
2953 + (pgSize[i] - 1)) == 0)) {
2954 + status = hIOMgr->pIntfFxns->pfnBrdMemMap
2955 + (hIOMgr->hWmdContext, paCurr, vaCurr,
2956 + pgSize[i], mapAttrs);
2957 + DBC_Assert(DSP_SUCCEEDED(status));
2958 + paCurr += pgSize[i];
2959 + vaCurr += pgSize[i];
2960 + gppVaCurr += pgSize[i];
2961 + numBytes -= pgSize[i];
2962 + /* Don't try smaller sizes. Hopefully we have
2963 + * reached an address aligned to a bigger page
2964 + * size*/
2965 + break;
2969 + paCurr += ulPadSize;
2970 + vaCurr += ulPadSize;
2971 + gppVaCurr += ulPadSize;
2973 + /* configure the TLB entries for the next cacheable segment */
2974 + numBytes = ulSegSize;
2975 + vaCurr = ulDspVa * hIOMgr->uWordSize;
2976 + allBits = 0x0;
2977 + while (numBytes && DSP_SUCCEEDED(status)) {
2978 + /* To find the max. page size with which both PA & VA are
2979 + * aligned*/
2980 + allBits = paCurr | vaCurr;
2981 + DBG_Trace(DBG_LEVEL1, "allBits for Seg1 %x, paCurr %x, "
2982 + "vaCurr %x, numBytes %x\n", allBits, paCurr, vaCurr,
2983 + numBytes);
2984 + for (i = 0; i < 4; i++) {
2985 + if (!(numBytes >= pgSize[i]) ||
2986 + !((allBits & (pgSize[i]-1)) == 0)) {
2987 + continue;
2989 + if (ndx < MAX_LOCK_TLB_ENTRIES) {
2990 + /* This is the physical address written to
2991 + * DSP MMU */
2992 + aEProc[ndx].ulGppPa = paCurr;
2993 + /* THIS IS THE VIRTUAL UNCACHED IOREMAPPED
2994 + * ADDRESS!!! */
2995 + aEProc[ndx].ulGppVa = gppVaCurr;
2996 + aEProc[ndx].ulDspVa = vaCurr / hIOMgr->
2997 + uWordSize;
2998 + aEProc[ndx].ulSize = pgSize[i];
2999 + aEProc[ndx].endianism = HW_LITTLE_ENDIAN;
3000 + aEProc[ndx].elemSize = HW_ELEM_SIZE_16BIT;
3001 + aEProc[ndx].mixedMode = HW_MMU_CPUES;
3002 + DBG_Trace(DBG_LEVEL1, "SHM MMU TLB entry PA %lx"
3003 + " VA %lx DSP_VA %lx Size %lx\n",
3004 + aEProc[ndx].ulGppPa,
3005 + aEProc[ndx].ulGppVa,
3006 + aEProc[ndx].ulDspVa *
3007 + hIOMgr->uWordSize, pgSize[i]);
3008 + ndx++;
3009 + } else {
3010 + status = hIOMgr->pIntfFxns->pfnBrdMemMap(
3011 + hIOMgr->hWmdContext, paCurr, vaCurr, pgSize[i],
3012 + mapAttrs);
3013 + DBG_Trace(DBG_LEVEL1, "SHM MMU PTE entry PA %lx"
3014 + " VA %lx DSP_VA %lx Size %lx\n",
3015 + aEProc[ndx].ulGppPa,
3016 + aEProc[ndx].ulGppVa,
3017 + aEProc[ndx].ulDspVa *
3018 + hIOMgr->uWordSize, pgSize[i]);
3019 + DBC_Assert(DSP_SUCCEEDED(status));
3021 + paCurr += pgSize[i];
3022 + vaCurr += pgSize[i];
3023 + gppVaCurr += pgSize[i];
3024 + numBytes -= pgSize[i];
3025 + /* Don't try smaller sizes. Hopefully we have reached
3026 + an address aligned to a bigger page size*/
3027 + break;
3031 + /* Copy remaining entries from CDB. All entries are 1 MB and should not
3032 + * conflict with SHM entries on MPU or DSP side */
3033 + for (i = 3; i < 7 && ndx < WMDIOCTL_NUMOFMMUTLB &&
3034 + DSP_SUCCEEDED(status); i++) {
3035 + if (hIOMgr->extProcInfo.tyTlb[i].ulGppPhys == 0)
3036 + continue;
3038 + if ((hIOMgr->extProcInfo.tyTlb[i].ulGppPhys > ulGppPa - 0x100000
3039 + && hIOMgr->extProcInfo.tyTlb[i].ulGppPhys <=
3040 + ulGppPa + ulSegSize)
3041 + || (hIOMgr->extProcInfo.tyTlb[i].ulDspVirt > ulDspVa -
3042 + 0x100000 / hIOMgr->uWordSize && hIOMgr->
3043 + extProcInfo.tyTlb[i].ulDspVirt
3044 + <= ulDspVa + ulSegSize / hIOMgr->uWordSize)) {
3045 + DBG_Trace(DBG_LEVEL7, "CDB MMU entry %d conflicts with "
3046 + "SHM.\n\tCDB: GppPa %x, DspVa %x.\n\tSHM: "
3047 + "GppPa %x, DspVa %x, Bytes %x.\n", i,
3048 + hIOMgr->extProcInfo.tyTlb[i].ulGppPhys,
3049 + hIOMgr->extProcInfo.tyTlb[i].ulDspVirt,
3050 + ulGppPa, ulDspVa, ulSegSize);
3051 + status = DSP_EFAIL;
3052 + } else {
3053 + if (ndx < MAX_LOCK_TLB_ENTRIES) {
3054 + aEProc[ndx].ulDspVa = hIOMgr->extProcInfo.
3055 + tyTlb[i].ulDspVirt;
3056 + aEProc[ndx].ulGppPa = hIOMgr->extProcInfo.
3057 + tyTlb[i].ulGppPhys;
3058 + aEProc[ndx].ulGppVa = 0;
3059 + /* Can't convert, so set to zero*/
3060 + aEProc[ndx].ulSize = 0x100000; /* 1 MB*/
3061 + DBG_Trace(DBG_LEVEL1, "SHM MMU entry PA %x "
3062 + "DSP_VA 0x%x\n", aEProc[ndx].ulGppPa,
3063 + aEProc[ndx].ulDspVa);
3064 + ndx++;
3065 + } else {
3066 + status = hIOMgr->pIntfFxns->pfnBrdMemMap
3067 + (hIOMgr->hWmdContext,
3068 + hIOMgr->extProcInfo.tyTlb[i].ulGppPhys,
3069 + hIOMgr->extProcInfo.tyTlb[i].ulDspVirt,
3070 + 0x100000, mapAttrs);
3074 + if (i < 7 && DSP_SUCCEEDED(status)) {
3075 + /* All CDB entries could not be made*/
3076 + status = DSP_EFAIL;
3078 +func_cont:
3079 + mapAttrs = 0x00000000;
3080 + mapAttrs = DSP_MAPLITTLEENDIAN;
3081 + mapAttrs |= DSP_MAPPHYSICALADDR;
3082 + mapAttrs |= DSP_MAPELEMSIZE32;
3083 + /* Map the L4 peripherals */
3085 + int i = 0;
3086 + while (L4PeripheralTable[i].physAddr && DSP_SUCCEEDED(status)) {
3087 + status = hIOMgr->pIntfFxns->pfnBrdMemMap
3088 + (hIOMgr->hWmdContext,
3089 + L4PeripheralTable[i].physAddr,
3090 + L4PeripheralTable[i].dspVirtAddr,
3091 + HW_PAGE_SIZE_4KB, mapAttrs);
3092 + DBC_Assert(DSP_SUCCEEDED(status));
3093 + i++;
3097 + if (DSP_SUCCEEDED(status)) {
3098 + for (i = ndx; i < WMDIOCTL_NUMOFMMUTLB; i++) {
3099 + aEProc[i].ulDspVa = 0;
3100 + aEProc[i].ulGppPa = 0;
3101 + aEProc[i].ulGppVa = 0;
3102 + aEProc[i].ulSize = 0;
3104 + /* Set the SHM physical address entry (grayed out in CDB file)
3105 + * to the virtual uncached ioremapped address of SHM reserved
3106 + * on MPU */
3107 + hIOMgr->extProcInfo.tyTlb[0].ulGppPhys = (ulGppVa + ulSeg1Size +
3108 + ulPadSize);
3109 + DBG_Trace(DBG_LEVEL1, "*********extProcInfo *********%x \n",
3110 + hIOMgr->extProcInfo.tyTlb[0].ulGppPhys);
3111 + /* Need SHM Phys addr. IO supports only one DSP for now:
3112 + * uNumProcs=1 */
3113 + if ((hIOMgr->extProcInfo.tyTlb[0].ulGppPhys == 0) ||
3114 + (uNumProcs != 1)) {
3115 + status = CHNL_E_NOMEMMAP;
3116 + DBC_Assert(false);
3117 + } else {
3118 + DBC_Assert(aEProc[0].ulDspVa <= ulShmBase);
3119 + /* ulShmBase may not be at ulDspVa address */
3120 + ulShmBaseOffset = (ulShmBase - aEProc[0].ulDspVa) *
3121 + hIOMgr->uWordSize;
3122 + /* WMD_BRD_Ctrl() will set dev context dsp-mmu info. In
3123 + * _BRD_Start() the MMU will be re-programed with MMU
3124 + * DSPVa-GPPPa pair info while DSP is in a known
3125 + * (reset) state. */
3126 + DBC_Assert(hIOMgr->pIntfFxns != NULL);
3127 + DBC_Assert(hIOMgr->hWmdContext != NULL);
3128 + status = hIOMgr->pIntfFxns->pfnDevCntrl(hIOMgr->
3129 + hWmdContext, WMDIOCTL_SETMMUCONFIG, aEProc);
3130 + ulShmBase = hIOMgr->extProcInfo.tyTlb[0].ulGppPhys;
3131 + DBG_Trace(DBG_LEVEL1, "extProcInfo.tyTlb[0].ulGppPhys "
3132 + "%x \n ", hIOMgr->extProcInfo.tyTlb[0].
3133 + ulGppPhys);
3134 + ulShmBase += ulShmBaseOffset;
3135 + ulShmBase = (u32)MEM_LinearAddress((void *)ulShmBase,
3136 + ulMemLength);
3137 + DBC_Assert(ulShmBase != 0);
3138 + if (DSP_SUCCEEDED(status)) {
3139 + status = registerSHMSegs(hIOMgr, hCodMan,
3140 + aEProc[0].ulGppPa);
3141 + /* Register SM */
3145 + if (DSP_SUCCEEDED(status)) {
3146 + hIOMgr->pSharedMem = (struct SHM *)ulShmBase;
3147 + hIOMgr->pInput = (u8 *)hIOMgr->pSharedMem +
3148 + sizeof(struct SHM);
3149 + hIOMgr->pOutput = hIOMgr->pInput + (ulShmLength -
3150 + sizeof(struct SHM))/2;
3151 + hIOMgr->uSMBufSize = hIOMgr->pOutput - hIOMgr->pInput;
3152 + DBG_Trace(DBG_LEVEL3,
3153 + "hIOMgr: pInput %p pOutput %p ulShmLength %x\n",
3154 + hIOMgr->pInput, hIOMgr->pOutput, ulShmLength);
3155 + DBG_Trace(DBG_LEVEL3,
3156 + "pSharedMem %p uSMBufSize %x sizeof(SHM) %x\n",
3157 + hIOMgr->pSharedMem, hIOMgr->uSMBufSize,
3158 + sizeof(struct SHM));
3159 + /* Set up Shared memory addresses for messaging. */
3160 + hIOMgr->pMsgInputCtrl = (struct MSG *)((u8 *)
3161 + hIOMgr->pSharedMem +
3162 + ulShmLength);
3163 + hIOMgr->pMsgInput = (u8 *)hIOMgr->pMsgInputCtrl +
3164 + sizeof(struct MSG);
3165 + hIOMgr->pMsgOutputCtrl = (struct MSG *)((u8 *)hIOMgr->
3166 + pMsgInputCtrl + ulMsgLength / 2);
3167 + hIOMgr->pMsgOutput = (u8 *)hIOMgr->pMsgOutputCtrl +
3168 + sizeof(struct MSG);
3169 + hMsgMgr->uMaxMsgs = ((u8 *)hIOMgr->pMsgOutputCtrl -
3170 + hIOMgr->pMsgInput) /
3171 + sizeof(struct MSG_DSPMSG);
3172 + DBG_Trace(DBG_LEVEL7, "IO MGR SHM details : pSharedMem 0x%x, "
3173 + "pInput 0x%x, pOutput 0x%x, pMsgInputCtrl 0x%x, "
3174 + "pMsgInput 0x%x, pMsgOutputCtrl 0x%x, pMsgOutput "
3175 + "0x%x \n", (u8 *)hIOMgr->pSharedMem,
3176 + (u8 *)hIOMgr->pInput, (u8 *)hIOMgr->pOutput,
3177 + (u8 *)hIOMgr->pMsgInputCtrl,
3178 + (u8 *)hIOMgr->pMsgInput,
3179 + (u8 *)hIOMgr->pMsgOutputCtrl,
3180 + (u8 *)hIOMgr->pMsgOutput);
3181 + DBG_Trace(DBG_LEVEL7, "** (proc) MAX MSGS IN SHARED MEMORY: "
3182 + "0x%x\n", hMsgMgr->uMaxMsgs);
3183 + memzero((void *) hIOMgr->pSharedMem, sizeof(struct SHM));
3185 +#ifndef DSP_TRACEBUF_DISABLED
3186 + if (DSP_SUCCEEDED(status)) {
3187 + /* Get the start address of trace buffer */
3188 + if (DSP_SUCCEEDED(status)) {
3189 + status = COD_GetSymValue(hCodMan, SYS_PUTCBEG,
3190 + &hIOMgr->ulTraceBufferBegin);
3191 + if (DSP_FAILED(status))
3192 + status = CHNL_E_NOMEMMAP;
3195 + hIOMgr->ulGPPReadPointer = hIOMgr->ulTraceBufferBegin =
3196 + (ulGppVa + ulSeg1Size + ulPadSize) +
3197 + (hIOMgr->ulTraceBufferBegin - ulDspVa);
3198 + /* Get the end address of trace buffer */
3199 + if (DSP_SUCCEEDED(status)) {
3200 + status = COD_GetSymValue(hCodMan, SYS_PUTCEND,
3201 + &hIOMgr->ulTraceBufferEnd);
3202 + if (DSP_FAILED(status))
3203 + status = CHNL_E_NOMEMMAP;
3206 + hIOMgr->ulTraceBufferEnd = (ulGppVa + ulSeg1Size + ulPadSize) +
3207 + (hIOMgr->ulTraceBufferEnd - ulDspVa);
3208 + /* Get the current address of DSP write pointer */
3209 + if (DSP_SUCCEEDED(status)) {
3210 + status = COD_GetSymValue(hCodMan,
3211 + BRIDGE_SYS_PUTC_current,
3212 + &hIOMgr->ulTraceBufferCurrent);
3213 + if (DSP_FAILED(status))
3214 + status = CHNL_E_NOMEMMAP;
3217 + hIOMgr->ulTraceBufferCurrent = (ulGppVa + ulSeg1Size +
3218 + ulPadSize) + (hIOMgr->
3219 + ulTraceBufferCurrent - ulDspVa);
3220 + /* Calculate the size of trace buffer */
3221 + if (hIOMgr->pMsg)
3222 + MEM_Free(hIOMgr->pMsg);
3223 + hIOMgr->pMsg = MEM_Alloc(((hIOMgr->ulTraceBufferEnd -
3224 + hIOMgr->ulTraceBufferBegin) *
3225 + hIOMgr->uWordSize) + 2, MEM_NONPAGED);
3226 + if (!hIOMgr->pMsg)
3227 + status = DSP_EMEMORY;
3229 + DBG_Trace(DBG_LEVEL1, "** hIOMgr->pMsg: 0x%x\n", hIOMgr->pMsg);
3230 + hIOMgr->ulDspVa = ulDspVa;
3231 + hIOMgr->ulGppVa = (ulGppVa + ulSeg1Size + ulPadSize);
3233 +#endif
3234 + IO_EnableInterrupt(hIOMgr->hWmdContext);
3235 + return status;
3239 + * ======== IO_BufSize ========
3240 + * Size of shared memory I/O channel.
3241 + */
3242 +u32 IO_BufSize(struct IO_MGR *hIOMgr)
3244 + DBC_Require(MEM_IsValidHandle(hIOMgr, IO_MGRSIGNATURE));
3246 + return hIOMgr->uSMBufSize;
3250 + * ======== IO_CancelChnl ========
3251 + * Cancel IO on a given PCPY channel.
3252 + */
3253 +void IO_CancelChnl(struct IO_MGR *hIOMgr, u32 ulChnl)
3255 + struct IO_MGR *pIOMgr = (struct IO_MGR *)hIOMgr;
3256 + struct SHM *sm;
3258 + DBC_Require(MEM_IsValidHandle(hIOMgr, IO_MGRSIGNATURE));
3259 + sm = hIOMgr->pSharedMem;
3261 + /* Inform DSP that we have no more buffers on this channel: */
3262 + IO_AndValue(pIOMgr->hWmdContext, struct SHM, sm, hostFreeMask,
3263 + (~(1 << ulChnl)));
3265 + IO_InterruptDSP(pIOMgr->hWmdContext);
3269 + * ======== IO_DispatchChnl ========
3270 + * Proc-copy chanl dispatch.
3271 + */
3272 +static void IO_DispatchChnl(IN struct IO_MGR *pIOMgr,
3273 + IN OUT struct CHNL_OBJECT *pChnl, u32 iMode)
3275 + DBC_Require(MEM_IsValidHandle(pIOMgr, IO_MGRSIGNATURE));
3277 + DBG_Trace(DBG_LEVEL3, "Entering IO_DispatchChnl \n");
3279 + /* See if there is any data available for transfer: */
3280 + DBC_Assert(iMode == IO_SERVICE);
3282 + /* Any channel will do for this mode: */
3283 + InputChnl(pIOMgr, pChnl, iMode);
3284 + OutputChnl(pIOMgr, pChnl, iMode);
3288 + * ======== IO_DispatchMsg ========
3289 + * Performs I/O dispatch on message queues.
3290 + */
3291 +static void IO_DispatchMsg(IN struct IO_MGR *pIOMgr, struct MSG_MGR *hMsgMgr)
3293 + DBC_Require(MEM_IsValidHandle(pIOMgr, IO_MGRSIGNATURE));
3295 + DBG_Trace(DBG_LEVEL3, "Entering IO_DispatchMsg \n");
3297 + /* We are performing both input and output processing. */
3298 + InputMsg(pIOMgr, hMsgMgr);
3299 + OutputMsg(pIOMgr, hMsgMgr);
3303 + * ======== IO_DispatchPM ========
3304 + * Performs I/O dispatch on PM related messages from DSP
3305 + */
3306 +static void IO_DispatchPM(IN struct IO_MGR *pIOMgr)
3308 + DSP_STATUS status;
3309 + u32 pArg[2];
3311 + DBC_Require(MEM_IsValidHandle(pIOMgr, IO_MGRSIGNATURE));
3313 + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM: Entering IO_DispatchPM : \n");
3315 + /* Perform Power message processing here */
3316 + while (pIOMgr->iQuePowerHead != pIOMgr->iQuePowerTail) {
3317 + pArg[0] = *(u32 *)&(pIOMgr->dQuePowerMbxVal[pIOMgr->
3318 + iQuePowerTail]);
3319 + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM - pArg[0] - 0x%x: \n",
3320 + pArg[0]);
3321 + /* Send the command to the WMD clk/pwr manager to handle */
3322 + if (pArg[0] == MBX_PM_HIBERNATE_EN) {
3323 + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM : Hibernate "
3324 + "command\n");
3325 + status = pIOMgr->pIntfFxns->pfnDevCntrl(pIOMgr->
3326 + hWmdContext, WMDIOCTL_PWR_HIBERNATE, pArg);
3327 + if (DSP_FAILED(status)) {
3328 + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM : "
3329 + "Hibernation command failed\n");
3331 + } else if (pArg[0] == MBX_PM_OPP_REQ) {
3332 + pArg[1] = pIOMgr->pSharedMem->oppRequest.rqstOppPt;
3333 + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM : Value of OPP "
3334 + "value =0x%x \n", pArg[1]);
3335 + status = pIOMgr->pIntfFxns->pfnDevCntrl(pIOMgr->
3336 + hWmdContext, WMDIOCTL_CONSTRAINT_REQUEST,
3337 + pArg);
3338 + if (DSP_FAILED(status)) {
3339 + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM : Failed "
3340 + "to set constraint = 0x%x \n",
3341 + pArg[1]);
3344 + } else {
3345 + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM - clock control - "
3346 + "value of msg = 0x%x: \n", pArg[0]);
3347 + status = pIOMgr->pIntfFxns->pfnDevCntrl(pIOMgr->
3348 + hWmdContext, WMDIOCTL_CLK_CTRL, pArg);
3349 + if (DSP_FAILED(status)) {
3350 + DBG_Trace(DBG_LEVEL7, "IO_DispatchPM : Failed "
3351 + "to control the DSP clk = 0x%x \n",
3352 + *pArg);
3355 + /* increment the tail count here */
3356 + pIOMgr->iQuePowerTail++;
3357 + if (pIOMgr->iQuePowerTail >= MAX_PM_REQS)
3358 + pIOMgr->iQuePowerTail = 0;
3364 + * ======== IO_DPC ========
3365 + * Deferred procedure call for shared memory channel driver ISR. Carries
3366 + * out the dispatch of I/O as a non-preemptible event.It can only be
3367 + * pre-empted by an ISR.
3368 + */
3369 +void IO_DPC(IN OUT void *pRefData)
3371 + struct IO_MGR *pIOMgr = (struct IO_MGR *)pRefData;
3372 + struct CHNL_MGR *pChnlMgr;
3373 + struct MSG_MGR *pMsgMgr;
3374 + struct DEH_MGR *hDehMgr;
3376 + DBC_Require(MEM_IsValidHandle(pIOMgr, IO_MGRSIGNATURE));
3377 + pChnlMgr = pIOMgr->hChnlMgr;
3378 + DEV_GetMsgMgr(pIOMgr->hDevObject, &pMsgMgr);
3379 + DEV_GetDehMgr(pIOMgr->hDevObject, &hDehMgr);
3380 + DBC_Require(MEM_IsValidHandle(pChnlMgr, CHNL_MGRSIGNATURE));
3381 + DBG_Trace(DBG_LEVEL7, "Entering IO_DPC(0x%x)\n", pRefData);
3382 + /* Check value of interrupt register to ensure it is a valid error */
3383 + if ((pIOMgr->wIntrVal > DEH_BASE) && (pIOMgr->wIntrVal < DEH_LIMIT)) {
3384 + /* notify DSP/BIOS exception */
3385 + if (hDehMgr)
3386 + WMD_DEH_Notify(hDehMgr, DSP_SYSERROR, pIOMgr->wIntrVal);
3389 + /* Call WMD's DPC: */
3390 + IO_CALLDPC(pIOMgr->hWmdContext);
3391 + IO_DispatchChnl(pIOMgr, NULL, IO_SERVICE);
3392 +#ifdef CHNL_MESSAGES
3393 + if (pMsgMgr) {
3394 + DBC_Require(MEM_IsValidHandle(pMsgMgr, MSGMGR_SIGNATURE));
3395 + IO_DispatchMsg(pIOMgr, pMsgMgr);
3397 +#endif
3398 +#ifndef DSP_TRACEBUF_DISABLED
3399 + if (pIOMgr->wIntrVal & MBX_DBG_CLASS) {
3400 + /* notify DSP Trace message */
3401 + if (pIOMgr->wIntrVal & MBX_DBG_SYSPRINTF)
3402 + PrintDSPDebugTrace(pIOMgr);
3404 +#endif
3405 + IO_DispatchPM(pIOMgr);
3406 +#ifndef DSP_TRACEBUF_DISABLED
3407 + PrintDSPDebugTrace(pIOMgr);
3408 +#endif
3413 + * ======== IO_ISR ========
3414 + * Main interrupt handler for the shared memory IO manager.
3415 + * Calls the WMD's CHNL_ISR to determine if this interrupt is ours, then
3416 + * schedules a DPC to dispatch I/O.
3417 + */
3418 +bool IO_ISR(IN void *pRefData)
3420 + struct IO_MGR *hIOMgr = (struct IO_MGR *)pRefData;
3421 + bool fSchedDPC;
3422 + DBC_Require(MEM_IsValidHandle(hIOMgr, IO_MGRSIGNATURE));
3423 + DBG_Trace(DBG_LEVEL3, "Entering IO_ISR(0x%x)\n", pRefData);
3424 + /* Call WMD's CHNLSM_ISR() to see if interrupt is ours, and process. */
3425 + if (IO_CALLISR(hIOMgr->hWmdContext, &fSchedDPC, &hIOMgr->wIntrVal)) {
3427 + DBG_Trace(DBG_LEVEL3, "IO_ISR %x\n", hIOMgr->wIntrVal);
3428 + if (hIOMgr->wIntrVal & MBX_PM_CLASS) {
3429 + hIOMgr->dQuePowerMbxVal[hIOMgr->iQuePowerHead] =
3430 + hIOMgr->wIntrVal;
3431 + hIOMgr->iQuePowerHead++;
3432 + if (hIOMgr->iQuePowerHead >= MAX_PM_REQS)
3433 + hIOMgr->iQuePowerHead = 0;
3436 + if (hIOMgr->wIntrVal == MBX_DEH_RESET) {
3437 + DBG_Trace(DBG_LEVEL6, "*** DSP RESET ***\n");
3438 + hIOMgr->wIntrVal = 0;
3439 + } else if (fSchedDPC) {
3440 + /* PROC-COPY defer i/o */
3441 + DPC_Schedule(hIOMgr->hDPC);
3444 + return true;
3445 + } else {
3446 + /* Ensure that, if WMD didn't claim it, the IRQ is shared. */
3447 + DBC_Ensure(hIOMgr->fSharedIRQ);
3448 + /* If not ours, return false. */
3449 + return false;
3454 + * ======== IO_RequestChnl ========
3455 + * Purpose:
3456 + * Request chanenel I/O from the DSP. Sets flags in shared memory, then
3457 + * interrupts the DSP.
3458 + */
3459 +void IO_RequestChnl(struct IO_MGR *pIOMgr, struct CHNL_OBJECT *pChnl,
3460 + u32 iMode, OUT u16 *pwMbVal)
3462 + struct CHNL_MGR *pChnlMgr;
3463 + struct SHM *sm;
3464 + DBC_Require(pChnl != NULL);
3465 + DBC_Require(pwMbVal != NULL);
3466 + pChnlMgr = pIOMgr->hChnlMgr;
3467 + sm = pIOMgr->pSharedMem;
3468 + if (iMode == IO_INPUT) {
3469 + /* Assertion fires if CHNL_AddIOReq() called on a stream
3470 + * which was cancelled, or attached to a dead board: */
3471 + DBC_Assert((pChnl->dwState == CHNL_STATEREADY) ||
3472 + (pChnl->dwState == CHNL_STATEEOS));
3473 + /* Indicate to the DSP we have a buffer available for input: */
3474 + IO_OrValue(pIOMgr->hWmdContext, struct SHM, sm, hostFreeMask,
3475 + (1 << pChnl->uId));
3476 + *pwMbVal = MBX_PCPY_CLASS;
3477 + } else if (iMode == IO_OUTPUT) {
3478 + /* This assertion fails if CHNL_AddIOReq() was called on a
3479 + * stream which was cancelled, or attached to a dead board: */
3480 + DBC_Assert((pChnl->dwState & ~CHNL_STATEEOS) ==
3481 + CHNL_STATEREADY);
3482 + /* Record the fact that we have a buffer available for
3483 + * output: */
3484 + pChnlMgr->dwOutputMask |= (1 << pChnl->uId);
3485 + } else {
3486 + DBC_Assert(iMode); /* Shouldn't get here. */
3491 + * ======== IO_Schedule ========
3492 + * Schedule DPC for IO.
3493 + */
3494 +void IO_Schedule(struct IO_MGR *pIOMgr)
3496 + DBC_Require(MEM_IsValidHandle(pIOMgr, IO_MGRSIGNATURE));
3498 + DPC_Schedule(pIOMgr->hDPC);
3502 + * ======== FindReadyOutput ========
3503 + * Search for a host output channel which is ready to send. If this is
3504 + * called as a result of servicing the DPC, then implement a round
3505 + * robin search; otherwise, this was called by a client thread (via
3506 + * IO_Dispatch()), so just start searching from the current channel id.
3507 + */
3508 +static u32 FindReadyOutput(struct CHNL_MGR *pChnlMgr,
3509 + struct CHNL_OBJECT *pChnl, u32 dwMask)
3511 + u32 uRetval = OUTPUTNOTREADY;
3512 + u32 id, startId;
3513 + u32 shift;
3515 + id = (pChnl != NULL ? pChnl->uId : (pChnlMgr->dwLastOutput + 1));
3516 + id = ((id == CHNL_MAXCHANNELS) ? 0 : id);
3517 + DBC_Assert(id < CHNL_MAXCHANNELS);
3518 + if (dwMask) {
3519 + shift = (1 << id);
3520 + startId = id;
3521 + do {
3522 + if (dwMask & shift) {
3523 + uRetval = id;
3524 + if (pChnl == NULL)
3525 + pChnlMgr->dwLastOutput = id;
3527 + break;
3529 + id = id + 1;
3530 + id = ((id == CHNL_MAXCHANNELS) ? 0 : id);
3531 + shift = (1 << id);
3532 + } while (id != startId);
3534 + DBC_Ensure((uRetval == OUTPUTNOTREADY) || (uRetval < CHNL_MAXCHANNELS));
3535 + return uRetval;
3539 + * ======== InputChnl ========
3540 + * Dispatch a buffer on an input channel.
3541 + */
3542 +static void InputChnl(struct IO_MGR *pIOMgr, struct CHNL_OBJECT *pChnl,
3543 + u32 iMode)
3545 + struct CHNL_MGR *pChnlMgr;
3546 + struct SHM *sm;
3547 + u32 chnlId;
3548 + u32 uBytes;
3549 + struct CHNL_IRP *pChirp = NULL;
3550 + u32 dwArg;
3551 + bool fClearChnl = false;
3552 + bool fNotifyClient = false;
3554 + sm = pIOMgr->pSharedMem;
3555 + pChnlMgr = pIOMgr->hChnlMgr;
3557 + DBG_Trace(DBG_LEVEL3, "> InputChnl\n");
3559 + /* Attempt to perform input.... */
3560 + if (!IO_GetValue(pIOMgr->hWmdContext, struct SHM, sm, inputFull))
3561 + goto func_end;
3563 + uBytes = IO_GetValue(pIOMgr->hWmdContext, struct SHM, sm, inputSize) *
3564 + pChnlMgr->uWordSize;
3565 + chnlId = IO_GetValue(pIOMgr->hWmdContext, struct SHM, sm, inputId);
3566 + dwArg = IO_GetLong(pIOMgr->hWmdContext, struct SHM, sm, arg);
3567 + if (!(chnlId >= 0) || !(chnlId < CHNL_MAXCHANNELS)) {
3568 + /* Shouldn't be here: would indicate corrupted SHM. */
3569 + DBC_Assert(chnlId);
3570 + goto func_end;
3572 + pChnl = pChnlMgr->apChannel[chnlId];
3573 + if ((pChnl != NULL) && CHNL_IsInput(pChnl->uMode)) {
3574 + if ((pChnl->dwState & ~CHNL_STATEEOS) == CHNL_STATEREADY) {
3575 + /* Get the I/O request, and attempt a transfer: */
3576 + pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->
3577 + pIORequests);
3578 + if (pChirp) {
3579 + pChnl->cIOReqs--;
3580 + DBC_Assert(pChnl->cIOReqs >= 0);
3581 + /* Ensure we don't overflow the client's
3582 + * buffer: */
3583 + uBytes = min(uBytes, pChirp->cBytes);
3584 + /* Transfer buffer from DSP side: */
3585 + uBytes = ReadData(pIOMgr->hWmdContext,
3586 + pChirp->pHostSysBuf,
3587 + pIOMgr->pInput, uBytes);
3588 + pChnl->cBytesMoved += uBytes;
3589 + pChirp->cBytes = uBytes;
3590 + pChirp->dwArg = dwArg;
3591 + pChirp->status = CHNL_IOCSTATCOMPLETE;
3592 + DBG_Trace(DBG_LEVEL7, "Input Chnl:status= 0x%x "
3593 + "\n", *((RMS_WORD *)(pChirp->
3594 + pHostSysBuf)));
3595 + if (uBytes == 0) {
3596 + /* This assertion fails if the DSP
3597 + * sends EOS more than once on this
3598 + * channel: */
3599 + DBC_Assert(!(pChnl->dwState &
3600 + CHNL_STATEEOS));
3601 + /* Zero bytes indicates EOS. Update
3602 + * IOC status for this chirp, and also
3603 + * the channel state: */
3604 + pChirp->status |= CHNL_IOCSTATEOS;
3605 + pChnl->dwState |= CHNL_STATEEOS;
3606 + /* Notify that end of stream has
3607 + * occurred */
3608 + NTFY_Notify(pChnl->hNtfy,
3609 + DSP_STREAMDONE);
3610 + DBG_Trace(DBG_LEVEL7, "Input Chnl NTFY "
3611 + "chnl = 0x%x\n", pChnl);
3613 + /* Tell DSP if no more I/O buffers available: */
3614 + if (LST_IsEmpty(pChnl->pIORequests)) {
3615 + IO_AndValue(pIOMgr->hWmdContext,
3616 + struct SHM, sm, hostFreeMask,
3617 + ~(1 << pChnl->uId));
3619 + fClearChnl = true;
3620 + fNotifyClient = true;
3621 + } else {
3622 + /* Input full for this channel, but we have no
3623 + * buffers available. The channel must be
3624 + * "idling". Clear out the physical input
3625 + * channel. */
3626 + fClearChnl = true;
3628 + } else {
3629 + /* Input channel cancelled: clear input channel. */
3630 + fClearChnl = true;
3632 + } else {
3633 + /* DPC fired after host closed channel: clear input channel. */
3634 + fClearChnl = true;
3636 + if (fClearChnl) {
3637 + /* Indicate to the DSP we have read the input: */
3638 + IO_SetValue(pIOMgr->hWmdContext, struct SHM, sm, inputFull, 0);
3639 + IO_InterruptDSP(pIOMgr->hWmdContext);
3641 + if (fNotifyClient) {
3642 + /* Notify client with IO completion record: */
3643 + NotifyChnlComplete(pChnl, pChirp);
3645 +func_end:
3646 + DBG_Trace(DBG_LEVEL3, "< InputChnl\n");
3650 + * ======== InputMsg ========
3651 + * Copies messages from shared memory to the message queues.
3652 + */
3653 +static void InputMsg(struct IO_MGR *pIOMgr, struct MSG_MGR *hMsgMgr)
3655 + u32 uMsgs;
3656 + u32 i;
3657 + u8 *pMsgInput;
3658 + struct MSG_QUEUE *hMsgQueue;
3659 + struct MSG_FRAME *pMsg;
3660 + struct MSG_DSPMSG msg;
3661 + struct MSG *pCtrl;
3662 + u32 fInputEmpty;
3663 + u32 addr;
3665 + pCtrl = pIOMgr->pMsgInputCtrl;
3666 + /* Get the number of input messages to be read. */
3667 + fInputEmpty = IO_GetValue(pIOMgr->hWmdContext, struct MSG, pCtrl,
3668 + bufEmpty);
3669 + uMsgs = IO_GetValue(pIOMgr->hWmdContext, struct MSG, pCtrl, size);
3670 + if (fInputEmpty || uMsgs >= hMsgMgr->uMaxMsgs)
3671 + return;
3673 + pMsgInput = pIOMgr->pMsgInput;
3674 + for (i = 0; i < uMsgs; i++) {
3675 + /* Read the next message */
3676 + addr = (u32)&(((struct MSG_DSPMSG *)pMsgInput)->msg.dwCmd);
3677 + msg.msg.dwCmd = ReadExt32BitDspData(pIOMgr->hWmdContext, addr);
3678 + addr = (u32)&(((struct MSG_DSPMSG *)pMsgInput)->msg.dwArg1);
3679 + msg.msg.dwArg1 = ReadExt32BitDspData(pIOMgr->hWmdContext, addr);
3680 + addr = (u32)&(((struct MSG_DSPMSG *)pMsgInput)->msg.dwArg2);
3681 + msg.msg.dwArg2 = ReadExt32BitDspData(pIOMgr->hWmdContext, addr);
3682 + addr = (u32)&(((struct MSG_DSPMSG *)pMsgInput)->dwId);
3683 + msg.dwId = ReadExt32BitDspData(pIOMgr->hWmdContext, addr);
3684 + pMsgInput += sizeof(struct MSG_DSPMSG);
3685 + /* Determine which queue to put the message in */
3686 + hMsgQueue = (struct MSG_QUEUE *)LST_First(hMsgMgr->queueList);
3687 + DBG_Trace(DBG_LEVEL7, "InputMsg RECVD: dwCmd=0x%x dwArg1=0x%x "
3688 + "dwArg2=0x%x dwId=0x%x \n", msg.msg.dwCmd,
3689 + msg.msg.dwArg1, msg.msg.dwArg2, msg.dwId);
3690 + /* Interrupt may occur before shared memory and message
3691 + * input locations have been set up. If all nodes were
3692 + * cleaned up, hMsgMgr->uMaxMsgs should be 0. */
3693 + if (hMsgQueue)
3694 + DBC_Assert(uMsgs <= hMsgMgr->uMaxMsgs);
3696 + while (hMsgQueue != NULL) {
3697 + if (msg.dwId == hMsgQueue->dwId) {
3698 + /* Found it */
3699 + if (msg.msg.dwCmd == RMS_EXITACK) {
3700 + /* The exit message does not get
3701 + * queued */
3702 + /* Call the node exit notification */
3703 + /* Node handle */ /* status */
3704 + (*hMsgMgr->onExit)((HANDLE)hMsgQueue->
3705 + hArg, msg.msg.dwArg1);
3706 + } else {
3707 + /* Not an exit acknowledgement, queue
3708 + * the message */
3709 + pMsg = (struct MSG_FRAME *)LST_GetHead
3710 + (hMsgQueue->msgFreeList);
3711 + if (pMsg) {
3712 + pMsg->msgData = msg;
3713 + LST_PutTail(hMsgQueue->
3714 + msgUsedList,
3715 + (struct LST_ELEM *)pMsg);
3716 + NTFY_Notify(hMsgQueue->hNtfy,
3717 + DSP_NODEMESSAGEREADY);
3718 + SYNC_SetEvent(hMsgQueue->
3719 + hSyncEvent);
3720 + } else {
3721 + /* No free frame to copy the
3722 + * message into */
3723 + DBG_Trace(DBG_LEVEL7, "NO FREE "
3724 + "MSG FRAMES, DISCARDING"
3725 + " MESSAGE\n");
3728 + break;
3730 + hMsgQueue = (struct MSG_QUEUE *)LST_Next(hMsgMgr->
3731 + queueList, (struct LST_ELEM *)hMsgQueue);
3734 + /* Set the post SWI flag */
3735 + if (uMsgs > 0) {
3736 + /* Tell the DSP we've read the messages */
3737 + IO_SetValue(pIOMgr->hWmdContext, struct MSG, pCtrl, bufEmpty,
3738 + true);
3739 + IO_SetValue(pIOMgr->hWmdContext, struct MSG, pCtrl, postSWI,
3740 + true);
3741 + IO_InterruptDSP(pIOMgr->hWmdContext);
3746 + * ======== NotifyChnlComplete ========
3747 + * Purpose:
3748 + * Signal the channel event, notifying the client that I/O has completed.
3749 + */
3750 +static void NotifyChnlComplete(struct CHNL_OBJECT *pChnl,
3751 + struct CHNL_IRP *pChirp)
3753 + bool fSignalEvent;
3755 + DBC_Require(MEM_IsValidHandle(pChnl, CHNL_SIGNATURE));
3756 + DBC_Require(pChnl->hSyncEvent != NULL);
3757 + /* Note: we signal the channel event only if the queue of IO
3758 + * completions is empty. If it is not empty, the event is sure to be
3759 + * signalled by the only IO completion list consumer:
3760 + * WMD_CHNL_GetIOC(). */
3761 + fSignalEvent = LST_IsEmpty(pChnl->pIOCompletions);
3762 + /* Enqueue the IO completion info for the client: */
3763 + LST_PutTail(pChnl->pIOCompletions, (struct LST_ELEM *) pChirp);
3764 + pChnl->cIOCs++;
3765 + DBC_Assert(pChnl->cIOCs <= pChnl->cChirps);
3766 + /* Signal the channel event (if not already set) that IO is complete: */
3767 + if (fSignalEvent)
3768 + SYNC_SetEvent(pChnl->hSyncEvent);
3770 + /* Notify that IO is complete */
3771 + NTFY_Notify(pChnl->hNtfy, DSP_STREAMIOCOMPLETION);
3775 + * ======== OutputChnl ========
3776 + * Purpose:
3777 + * Dispatch a buffer on an output channel.
3778 + */
3779 +static void OutputChnl(struct IO_MGR *pIOMgr, struct CHNL_OBJECT *pChnl,
3780 + u32 iMode)
3782 + struct CHNL_MGR *pChnlMgr;
3783 + struct SHM *sm;
3784 + u32 chnlId;
3785 + struct CHNL_IRP *pChirp;
3786 + u32 dwDspFMask;
3788 + pChnlMgr = pIOMgr->hChnlMgr;
3789 + sm = pIOMgr->pSharedMem;
3790 + DBG_Trace(DBG_LEVEL3, "> OutputChnl\n");
3791 + /* Attempt to perform output: */
3792 + if (IO_GetValue(pIOMgr->hWmdContext, struct SHM, sm, outputFull))
3793 + goto func_end;
3795 + if (pChnl && !((pChnl->dwState & ~CHNL_STATEEOS) == CHNL_STATEREADY))
3796 + goto func_end;
3798 + /* Look to see if both a PC and DSP output channel are ready: */
3799 + dwDspFMask = IO_GetValue(pIOMgr->hWmdContext, struct SHM, sm,
3800 + dspFreeMask);
3801 + chnlId = FindReadyOutput(pChnlMgr, pChnl, (pChnlMgr->dwOutputMask &
3802 + dwDspFMask));
3803 + if (chnlId == OUTPUTNOTREADY)
3804 + goto func_end;
3806 + pChnl = pChnlMgr->apChannel[chnlId];
3807 + if (!pChnl) {
3808 + /* Shouldn't get here: */
3809 + DBC_Assert(pChnl == NULL);
3810 + goto func_end;
3812 + /* Get the I/O request, and attempt a transfer: */
3813 + pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->pIORequests);
3814 + if (!pChirp)
3815 + goto func_end;
3817 + pChnl->cIOReqs--;
3818 + DBC_Assert(pChnl->cIOReqs >= 0);
3819 + /* Record fact that no more I/O buffers available: */
3820 + if (LST_IsEmpty(pChnl->pIORequests))
3821 + pChnlMgr->dwOutputMask &= ~(1 << chnlId);
3823 + /* Transfer buffer to DSP side: */
3824 + pChirp->cBytes = WriteData(pIOMgr->hWmdContext, pIOMgr->pOutput,
3825 + pChirp->pHostSysBuf, min(pIOMgr->uSMBufSize, pChirp->
3826 + cBytes));
3827 + pChnl->cBytesMoved += pChirp->cBytes;
3828 + /* Write all 32 bits of arg */
3829 + IO_SetLong(pIOMgr->hWmdContext, struct SHM, sm, arg, pChirp->dwArg);
3830 +#if _CHNL_WORDSIZE == 2
3831 + IO_SetValue(pIOMgr->hWmdContext, struct SHM, sm, outputId,
3832 + (u16)chnlId);
3833 + IO_SetValue(pIOMgr->hWmdContext, struct SHM, sm, outputSize,
3834 + (u16)(pChirp->cBytes + (pChnlMgr->uWordSize-1)) /
3835 + (u16)pChnlMgr->uWordSize);
3836 +#else
3837 + IO_SetValue(pIOMgr->hWmdContext, struct SHM, sm, outputId, chnlId);
3838 + IO_SetValue(pIOMgr->hWmdContext, struct SHM, sm, outputSize,
3839 + (pChirp->cBytes + (pChnlMgr->uWordSize - 1)) / pChnlMgr->
3840 + uWordSize);
3841 +#endif
3842 + IO_SetValue(pIOMgr->hWmdContext, struct SHM, sm, outputFull, 1);
3843 + /* Indicate to the DSP we have written the output: */
3844 + IO_InterruptDSP(pIOMgr->hWmdContext);
3845 + /* Notify client with IO completion record (keep EOS) */
3846 + pChirp->status &= CHNL_IOCSTATEOS;
3847 + NotifyChnlComplete(pChnl, pChirp);
3848 + /* Notify if stream is done. */
3849 + if (pChirp->status & CHNL_IOCSTATEOS)
3850 + NTFY_Notify(pChnl->hNtfy, DSP_STREAMDONE);
3852 +func_end:
3853 + DBG_Trace(DBG_LEVEL3, "< OutputChnl\n");
3856 + * ======== OutputMsg ========
3857 + * Copies messages from the message queues to the shared memory.
3858 + */
3859 +static void OutputMsg(struct IO_MGR *pIOMgr, struct MSG_MGR *hMsgMgr)
3861 + u32 uMsgs = 0;
3862 + u32 i;
3863 + u8 *pMsgOutput;
3864 + struct MSG_FRAME *pMsg;
3865 + struct MSG *pCtrl;
3866 + u32 fOutputEmpty;
3867 + u32 val;
3868 + u32 addr;
3870 + pCtrl = pIOMgr->pMsgOutputCtrl;
3872 + /* Check if output has been cleared */
3873 + fOutputEmpty = IO_GetValue(pIOMgr->hWmdContext, struct MSG, pCtrl,
3874 + bufEmpty);
3875 + if (fOutputEmpty) {
3876 + uMsgs = (hMsgMgr->uMsgsPending > hMsgMgr->uMaxMsgs) ?
3877 + hMsgMgr->uMaxMsgs : hMsgMgr->uMsgsPending;
3878 + pMsgOutput = pIOMgr->pMsgOutput;
3879 + /* Copy uMsgs messages into shared memory */
3880 + for (i = 0; i < uMsgs; i++) {
3881 + pMsg = (struct MSG_FRAME *)LST_GetHead(hMsgMgr->
3882 + msgUsedList);
3883 + DBC_Assert(pMsg != NULL);
3884 + if (pMsg != NULL) {
3885 + val = (pMsg->msgData).dwId;
3886 + addr = (u32)&(((struct MSG_DSPMSG *)
3887 + pMsgOutput)->dwId);
3888 + WriteExt32BitDspData(pIOMgr->hWmdContext, addr,
3889 + val);
3890 + val = (pMsg->msgData).msg.dwCmd;
3891 + addr = (u32)&((((struct MSG_DSPMSG *)
3892 + pMsgOutput)->msg).dwCmd);
3893 + WriteExt32BitDspData(pIOMgr->hWmdContext, addr,
3894 + val);
3895 + val = (pMsg->msgData).msg.dwArg1;
3896 + addr =
3897 + (u32)&((((struct MSG_DSPMSG *)
3898 + pMsgOutput)->msg).dwArg1);
3899 + WriteExt32BitDspData(pIOMgr->hWmdContext, addr,
3900 + val);
3901 + val = (pMsg->msgData).msg.dwArg2;
3902 + addr =
3903 + (u32)&((((struct MSG_DSPMSG *)
3904 + pMsgOutput)->msg).dwArg2);
3905 + WriteExt32BitDspData(pIOMgr->hWmdContext, addr,
3906 + val);
3907 + pMsgOutput += sizeof(struct MSG_DSPMSG);
3908 + LST_PutTail(hMsgMgr->msgFreeList,
3909 + (struct LST_ELEM *) pMsg);
3910 + SYNC_SetEvent(hMsgMgr->hSyncEvent);
3911 + } else {
3912 + DBG_Trace(DBG_LEVEL3, "pMsg is NULL\n");
3916 + if (uMsgs > 0) {
3917 + hMsgMgr->uMsgsPending -= uMsgs;
3918 +#if _CHNL_WORDSIZE == 2
3919 + IO_SetValue(pIOMgr->hWmdContext, struct MSG, pCtrl,
3920 + size, (u16)uMsgs);
3921 +#else
3922 + IO_SetValue(pIOMgr->hWmdContext, struct MSG, pCtrl,
3923 + size, uMsgs);
3924 +#endif
3925 + IO_SetValue(pIOMgr->hWmdContext, struct MSG, pCtrl,
3926 + bufEmpty, false);
3927 + /* Set the post SWI flag */
3928 + IO_SetValue(pIOMgr->hWmdContext, struct MSG, pCtrl,
3929 + postSWI, true);
3930 + /* Tell the DSP we have written the output. */
3931 + IO_InterruptDSP(pIOMgr->hWmdContext);
3937 + * ======== registerSHMSegs ========
3938 + * purpose:
3939 + * Registers GPP SM segment with CMM.
3940 + */
3941 +static DSP_STATUS registerSHMSegs(struct IO_MGR *hIOMgr,
3942 + struct COD_MANAGER *hCodMan,
3943 + u32 dwGPPBasePA)
3945 + DSP_STATUS status = DSP_SOK;
3946 + u32 ulShm0_Base = 0;
3947 + u32 ulShm0_End = 0;
3948 + u32 ulShm0_RsrvdStart = 0;
3949 + u32 ulRsrvdSize = 0;
3950 + u32 ulGppPhys;
3951 + u32 ulDspVirt;
3952 + u32 ulShmSegId0 = 0;
3953 + u32 dwOffset, dwGPPBaseVA, ulDSPSize;
3955 + /* Read address and size info for first SM region.*/
3956 + /* Get start of 1st SM Heap region */
3957 + status = COD_GetSymValue(hCodMan, SHM0_SHARED_BASE_SYM, &ulShm0_Base);
3958 + DBC_Assert(ulShm0_Base != 0);
3959 + /* Get end of 1st SM Heap region */
3960 + if (DSP_SUCCEEDED(status)) {
3961 + /* Get start and length of message part of shared memory */
3962 + status = COD_GetSymValue(hCodMan, SHM0_SHARED_END_SYM,
3963 + &ulShm0_End);
3964 + DBC_Assert(ulShm0_End != 0);
3966 + /* start of Gpp reserved region */
3967 + if (DSP_SUCCEEDED(status)) {
3968 + /* Get start and length of message part of shared memory */
3969 + status = COD_GetSymValue(hCodMan, SHM0_SHARED_RESERVED_BASE_SYM,
3970 + &ulShm0_RsrvdStart);
3971 + DBG_Trace(DBG_LEVEL1, "***ulShm0_RsrvdStart 0x%x \n",
3972 + ulShm0_RsrvdStart);
3973 + DBC_Assert(ulShm0_RsrvdStart != 0);
3975 + /* Register with CMM */
3976 + if (DSP_SUCCEEDED(status)) {
3977 + status = DEV_GetCmmMgr(hIOMgr->hDevObject, &hIOMgr->hCmmMgr);
3978 + if (DSP_SUCCEEDED(status)) {
3979 + status = CMM_UnRegisterGPPSMSeg(hIOMgr->hCmmMgr,
3980 + CMM_ALLSEGMENTS);
3981 + if (DSP_FAILED(status)) {
3982 + DBG_Trace(DBG_LEVEL7, "ERROR - Unable to "
3983 + "Un-Register SM segments \n");
3985 + } else {
3986 + DBG_Trace(DBG_LEVEL7, "ERROR - Unable to get CMM "
3987 + "Handle \n");
3990 + /* Register new SM region(s) */
3991 + if (DSP_SUCCEEDED(status) && (ulShm0_End - ulShm0_Base) > 0) {
3992 + /* calc size (bytes) of SM the GPP can alloc from */
3993 + ulRsrvdSize = (ulShm0_End - ulShm0_RsrvdStart + 1) * hIOMgr->
3994 + uWordSize;
3995 + DBC_Assert(ulRsrvdSize > 0);
3996 + /* calc size of SM DSP can alloc from */
3997 + ulDSPSize = (ulShm0_RsrvdStart - ulShm0_Base) * hIOMgr->
3998 + uWordSize;
3999 + DBC_Assert(ulDSPSize > 0);
4000 + /* First TLB entry reserved for Bridge SM use.*/
4001 + ulGppPhys = hIOMgr->extProcInfo.tyTlb[0].ulGppPhys;
4002 + /* get size in bytes */
4003 + ulDspVirt = hIOMgr->extProcInfo.tyTlb[0].ulDspVirt * hIOMgr->
4004 + uWordSize;
4005 + /* Calc byte offset used to convert GPP phys <-> DSP byte
4006 + * address.*/
4007 + if (dwGPPBasePA > ulDspVirt)
4008 + dwOffset = dwGPPBasePA - ulDspVirt;
4009 + else
4010 + dwOffset = ulDspVirt - dwGPPBasePA;
4012 + DBC_Assert(ulShm0_RsrvdStart * hIOMgr->uWordSize >= ulDspVirt);
4013 + /* calc Gpp phys base of SM region */
4014 + /* Linux - this is actually uncached kernel virtual address*/
4015 + dwGPPBaseVA = ulGppPhys + ulShm0_RsrvdStart * hIOMgr->uWordSize
4016 + - ulDspVirt;
4017 + /* calc Gpp phys base of SM region */
4018 + /* Linux - this is the physical address*/
4019 + dwGPPBasePA = dwGPPBasePA + ulShm0_RsrvdStart * hIOMgr->
4020 + uWordSize - ulDspVirt;
4021 + /* Register SM Segment 0.*/
4022 + status = CMM_RegisterGPPSMSeg(hIOMgr->hCmmMgr, dwGPPBasePA,
4023 + ulRsrvdSize, dwOffset, (dwGPPBasePA > ulDspVirt) ?
4024 + CMM_ADDTODSPPA : CMM_SUBFROMDSPPA,
4025 + (u32)(ulShm0_Base * hIOMgr->uWordSize),
4026 + ulDSPSize, &ulShmSegId0, dwGPPBaseVA);
4027 + if (DSP_FAILED(status)) {
4028 + DBG_Trace(DBG_LEVEL7, "ERROR - Failed to register SM "
4029 + "Seg 0 \n");
4031 + /* first SM region is segId = 1 */
4032 + DBC_Assert(ulShmSegId0 == 1);
4034 + return status;
4038 + * ======== ReadData ========
4039 + * Copies buffers from the shared memory to the host buffer.
4040 + */
4041 +static u32 ReadData(struct WMD_DEV_CONTEXT *hDevContext, void *pDest,
4042 + void *pSrc, u32 uSize)
4044 + memcpy(pDest, pSrc, uSize);
4045 + return uSize;
4049 + * ======== WriteData ========
4050 + * Copies buffers from the host side buffer to the shared memory.
4051 + */
4052 +static u32 WriteData(struct WMD_DEV_CONTEXT *hDevContext, void *pDest,
4053 + void *pSrc, u32 uSize)
4055 + memcpy(pDest, pSrc, uSize);
4056 + return uSize;
4059 +/* ZCPY IO routines. */
4060 +void IO_IntrDSP2(IN struct IO_MGR *pIOMgr, IN u16 wMbVal)
4062 + IO_InterruptDSP2(pIOMgr->hWmdContext, wMbVal);
4066 + * ======== IO_SHMcontrol ========
4067 + * Sets the requested SHM setting.
4068 + */
4069 +DSP_STATUS IO_SHMsetting(IN struct IO_MGR *hIOMgr, IN enum SHM_DESCTYPE desc,
4070 + IN void *pArgs)
4072 +#ifndef CONFIG_DISABLE_BRIDGE_PM
4073 +#ifndef CONFIG_DISABLE_BRIDGE_DVFS
4074 + u32 i;
4076 + switch (desc) {
4077 + case SHM_CURROPP:
4078 + /* Update the shared memory with requested OPP information */
4079 + if (pArgs != NULL)
4080 + hIOMgr->pSharedMem->oppTableStruct.currOppPt =
4081 + *(u32 *)pArgs;
4082 + else
4083 + return DSP_EFAIL;
4084 + break;
4085 + case SHM_OPPINFO:
4086 + /* Update the shared memory with the voltage, frequency,
4087 + min and max frequency values for an OPP */
4088 + for (i = 0; i <= dsp_max_opps; i++) {
4089 + hIOMgr->pSharedMem->oppTableStruct.oppPoint[i].voltage =
4090 + vdd1_dsp_freq[i][0];
4091 + DBG_Trace(DBG_LEVEL5, "OPP shared memory -voltage: "
4092 + "%d\n", hIOMgr->pSharedMem->oppTableStruct.
4093 + oppPoint[i].voltage);
4094 + hIOMgr->pSharedMem->oppTableStruct.oppPoint[i].
4095 + frequency = vdd1_dsp_freq[i][1];
4096 + DBG_Trace(DBG_LEVEL5, "OPP shared memory -frequency: "
4097 + "%d\n", hIOMgr->pSharedMem->oppTableStruct.
4098 + oppPoint[i].frequency);
4099 + hIOMgr->pSharedMem->oppTableStruct.oppPoint[i].minFreq =
4100 + vdd1_dsp_freq[i][2];
4101 + DBG_Trace(DBG_LEVEL5, "OPP shared memory -min value: "
4102 + "%d\n", hIOMgr->pSharedMem->oppTableStruct.
4103 + oppPoint[i].minFreq);
4104 + hIOMgr->pSharedMem->oppTableStruct.oppPoint[i].maxFreq =
4105 + vdd1_dsp_freq[i][3];
4106 + DBG_Trace(DBG_LEVEL5, "OPP shared memory -max value: "
4107 + "%d\n", hIOMgr->pSharedMem->oppTableStruct.
4108 + oppPoint[i].maxFreq);
4110 + hIOMgr->pSharedMem->oppTableStruct.numOppPts = dsp_max_opps;
4111 + DBG_Trace(DBG_LEVEL5, "OPP shared memory - max OPP number: "
4112 + "%d\n", hIOMgr->pSharedMem->oppTableStruct.numOppPts);
4113 + /* Update the current OPP number */
4114 + i = constraint_get_level(dsp_constraint_handle);
4115 + hIOMgr->pSharedMem->oppTableStruct.currOppPt = i;
4116 + DBG_Trace(DBG_LEVEL7, "OPP value programmed to shared memory: "
4117 + "%d\n", i);
4118 + break;
4119 + case SHM_GETOPP:
4120 + /* Get the OPP that DSP has requested */
4121 + *(u32 *)pArgs = hIOMgr->pSharedMem->oppRequest.rqstOppPt;
4122 + break;
4123 + default:
4124 + break;
4127 +#endif
4128 +#endif
4129 + return DSP_SOK;
4133 + * ======== WMD_IO_GetProcLoad ========
4134 + * Gets the Processor's Load information
4135 + */
4136 +DSP_STATUS WMD_IO_GetProcLoad(IN struct IO_MGR *hIOMgr,
4137 + OUT struct DSP_PROCLOADSTAT *pProcStat)
4139 + pProcStat->uCurrLoad = hIOMgr->pSharedMem->loadMonInfo.currDspLoad;
4140 + pProcStat->uPredictedLoad = hIOMgr->pSharedMem->loadMonInfo.predDspLoad;
4141 + pProcStat->uCurrDspFreq = hIOMgr->pSharedMem->loadMonInfo.currDspFreq;
4142 + pProcStat->uPredictedFreq = hIOMgr->pSharedMem->loadMonInfo.predDspFreq;
4144 + DBG_Trace(DBG_LEVEL4, "Curr Load =%d, Pred Load = %d, Curr Freq = %d, "
4145 + "Pred Freq = %d\n", pProcStat->uCurrLoad,
4146 + pProcStat->uPredictedLoad, pProcStat->uCurrDspFreq,
4147 + pProcStat->uPredictedFreq);
4148 + return DSP_SOK;
4151 +#ifndef DSP_TRACEBUF_DISABLED
4152 +void PrintDSPDebugTrace(struct IO_MGR *hIOMgr)
4154 + u32 ulNewMessageLength = 0, ulGPPCurPointer;
4156 + while (true) {
4157 + /* Get the DSP current pointer */
4158 + ulGPPCurPointer = *(u32 *) (hIOMgr->ulTraceBufferCurrent);
4159 + ulGPPCurPointer = hIOMgr->ulGppVa + (ulGPPCurPointer -
4160 + hIOMgr->ulDspVa);
4162 + /* No new debug messages available yet */
4163 + if (ulGPPCurPointer == hIOMgr->ulGPPReadPointer)
4164 + break;
4166 + /* Continuous data */
4167 + else if (ulGPPCurPointer > hIOMgr->ulGPPReadPointer) {
4168 + ulNewMessageLength = ulGPPCurPointer - hIOMgr->
4169 + ulGPPReadPointer;
4171 + memcpy(hIOMgr->pMsg, (char *)hIOMgr->ulGPPReadPointer,
4172 + ulNewMessageLength);
4173 + hIOMgr->pMsg[ulNewMessageLength] = '\0';
4174 + /* Advance the GPP trace pointer to DSP current
4175 + * pointer */
4176 + hIOMgr->ulGPPReadPointer += ulNewMessageLength;
4177 + /* Print the trace messages */
4178 + DBG_Trace(DBG_LEVEL3, "hIOMgr->pMsg=0x%x",
4179 + hIOMgr->pMsg);
4181 + /* Handle trace buffer wraparound */
4182 + else if (ulGPPCurPointer < hIOMgr->ulGPPReadPointer) {
4183 + memcpy(hIOMgr->pMsg, (char *)hIOMgr->ulGPPReadPointer,
4184 + hIOMgr->ulTraceBufferEnd -
4185 + hIOMgr->ulGPPReadPointer);
4186 + ulNewMessageLength = ulGPPCurPointer -
4187 + hIOMgr->ulTraceBufferBegin;
4188 + memcpy(&hIOMgr->pMsg[hIOMgr->ulTraceBufferEnd -
4189 + hIOMgr->ulGPPReadPointer],
4190 + (char *)hIOMgr->ulTraceBufferBegin,
4191 + ulNewMessageLength);
4192 + hIOMgr->pMsg[hIOMgr->ulTraceBufferEnd -
4193 + hIOMgr->ulGPPReadPointer +
4194 + ulNewMessageLength] = '\0';
4195 + /* Advance the GPP trace pointer to DSP current
4196 + * pointer */
4197 + hIOMgr->ulGPPReadPointer = hIOMgr->ulTraceBufferBegin +
4198 + ulNewMessageLength;
4199 + /* Print the trace messages */
4200 + DBG_Trace(DBG_LEVEL3, "hIOMgr->pMsg=0x%x",
4201 + hIOMgr->pMsg);
4205 +#endif
4207 Index: lk/drivers/dsp/bridge/wmd/mmu_fault.c
4208 ===================================================================
4209 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
4210 +++ lk/drivers/dsp/bridge/wmd/mmu_fault.c 2008-08-18 10:38:38.000000000 +0300
4211 @@ -0,0 +1,171 @@
4213 + * linux/drivers/dsp/bridge/wmd/linux/omap/common/mmu_fault.c
4215 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
4217 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
4219 + * This package is free software; you can redistribute it and/or modify
4220 + * it under the terms of the GNU General Public License version 2 as
4221 + * published by the Free Software Foundation.
4223 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
4224 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
4225 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
4226 + */
4229 + * ======== mmu_fault.c ========
4230 + * Description:
4231 + * Implements DSP MMU fault handling functions.
4233 + *! Revision History:
4234 + *! ================
4235 + *! 26-Dec-2004 hn: Support for IVA MMU exception.
4236 + *! 06-Mar-2003 sb: Print MMU fault address. Cosmetic changes.
4237 + *! 16-Feb-2003 vp: Fixed warning in MMU_FaultIsr
4238 + *! 05-Jan-2004 vp: Updated support for 24xx silicon
4239 + *! 19-Feb-2003 vp: Code review updates.
4240 + *! - Cosmetic changes.
4241 + *! 18-Oct-2002 sb: Ported to Linux platform.
4242 + *! 10-Sep-2001 kc: created.
4243 + */
4245 +/* ----------------------------------- DSP/BIOS Bridge */
4246 +#include <std.h>
4247 +#include <dbdefs.h>
4248 +#include <errbase.h>
4250 +/* ----------------------------------- Trace & Debug */
4251 +#include <host_os.h>
4252 +#include <dbc.h>
4253 +#include <dbg.h>
4255 +/* ----------------------------------- OS Adaptation Layer */
4256 +#include <dpc.h>
4257 +#include <mem.h>
4258 +#include <drv.h>
4260 +/* ----------------------------------- Link Driver */
4261 +#include <wmddeh.h>
4263 +/* ------------------------------------ Hardware Abstraction Layer */
4264 +#include <hw_defs.h>
4265 +#include <hw_mmu.h>
4267 +/* ----------------------------------- This */
4268 +#include "_deh.h"
4269 +#include "_tiomap_mmu.h"
4270 +#include "_tiomap.h"
4271 +#include "mmu_fault.h"
4273 +u32 dmmuEventMask;
4274 +u32 faultAddr;
4276 +static bool MMU_CheckIfFault(struct WMD_DEV_CONTEXT *pDevContext);
4279 + * ======== MMU_FaultDpc ========
4280 + * Deferred procedure call to handle DSP MMU fault.
4281 + */
4282 +void MMU_FaultDpc(IN void *pRefData)
4284 + struct DEH_MGR *hDehMgr = (struct DEH_MGR *)pRefData;
4285 + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr;
4287 + DBG_Trace(DBG_LEVEL1, "MMU_FaultDpc Enter: 0x%x\n", pRefData);
4289 + if (pDehMgr)
4290 + WMD_DEH_Notify(hDehMgr, DSP_MMUFAULT, 0L);
4292 + DBG_Trace(DBG_LEVEL1, "MMU_FaultDpc Exit: 0x%x\n", pRefData);
4296 + * ======== MMU_FaultIsr ========
4297 + * ISR to be triggered by a DSP MMU fault interrupt.
4298 + */
4299 +void MMU_FaultIsr(IN void *pRefData)
4301 + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)pRefData;
4302 + struct WMD_DEV_CONTEXT *pDevContext;
4303 + struct CFG_HOSTRES resources;
4304 + DSP_STATUS status = DSP_SOK;
4307 + DBG_Trace(DBG_LEVEL1, "Entering DEH_DspMmuIsr: 0x%x\n", pRefData);
4309 + DBC_Require(MEM_IsValidHandle(pDehMgr, SIGNATURE));
4311 + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) {
4313 + pDevContext = (struct WMD_DEV_CONTEXT *)pDehMgr->hWmdContext;
4314 + status = CFG_GetHostResources(
4315 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(),
4316 + &resources);
4317 + if (DSP_FAILED(status))
4318 + DBG_Trace(DBG_LEVEL7,
4319 + "**Failed to get Host Resources "
4320 + "in MMU ISR **\n");
4321 + if (MMU_CheckIfFault(pDevContext)) {
4322 + printk(KERN_INFO "***** DSPMMU FAULT ***** IRQStatus "
4323 + "0x%x\n", dmmuEventMask);
4324 + printk(KERN_INFO "***** DSPMMU FAULT ***** faultAddr "
4325 + "0x%x\n", faultAddr);
4326 + /* Disable the MMU events, else once we clear it will
4327 + * start to raise INTs again */
4328 + /*
4329 + * Schedule a DPC directly. In the future, it may be
4330 + * necessary to check if DSP MMU fault is intended for
4331 + * Bridge.
4332 + */
4333 + DPC_Schedule(pDehMgr->hMmuFaultDpc);
4334 + /* Reset errInfo structure before use. */
4335 + pDehMgr->errInfo.dwErrMask = DSP_MMUFAULT;
4336 + pDehMgr->errInfo.dwVal1 = faultAddr >> 16;
4337 + pDehMgr->errInfo.dwVal2 = faultAddr & 0xFFFF;
4338 + pDehMgr->errInfo.dwVal3 = 0L;
4339 + /* Disable the MMU events, else once we clear it will
4340 + * start to raise INTs again */
4341 + HW_MMU_EventDisable(resources.dwDmmuBase,
4342 + HW_MMU_TRANSLATION_FAULT);
4343 + } else {
4344 + DBG_Trace(DBG_LEVEL7,
4345 + "***** MMU FAULT ***** faultcode 0x%x\n",
4346 + dmmuEventMask);
4347 + HW_MMU_EventDisable(resources.dwDmmuBase,
4348 + HW_MMU_ALL_INTERRUPTS);
4350 + PrintDspTraceBuffer(pDehMgr);
4356 + * ======== MMU_CheckIfFault ========
4357 + * Check to see if MMU Fault is valid TLB miss from DSP
4358 + * Note: This function is called from an ISR
4359 + */
4360 +static bool MMU_CheckIfFault(struct WMD_DEV_CONTEXT *pDevContext)
4364 + bool retVal = false;
4365 + DSP_STATUS status = DSP_SOK;
4366 + HW_STATUS hwStatus;
4367 + struct CFG_HOSTRES resources;
4368 + status = CFG_GetHostResources(
4369 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources);
4370 + if (DSP_FAILED(status))
4371 + DBG_Trace(DBG_LEVEL7, "**Failed to get Host Resources in "
4372 + "MMU_CheckIfFault **\n");
4374 + hwStatus = HW_MMU_EventStatus(resources.dwDmmuBase, &dmmuEventMask);
4375 + if (dmmuEventMask == HW_MMU_TRANSLATION_FAULT) {
4376 + HW_MMU_FaultAddrRead(resources.dwDmmuBase, &faultAddr);
4377 + DBG_Trace(DBG_LEVEL1, "WMD_DEH_Notify: DSP_MMUFAULT, fault "
4378 + "address = 0x%x\n", faultAddr);
4379 + retVal = true;
4381 + return retVal;
4383 Index: lk/drivers/dsp/bridge/wmd/mmu_fault.h
4384 ===================================================================
4385 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
4386 +++ lk/drivers/dsp/bridge/wmd/mmu_fault.h 2008-08-18 10:38:38.000000000 +0300
4387 @@ -0,0 +1,52 @@
4389 + * linux/drivers/dsp/bridge/wmd/linux/omap/common/mmu_fault.h
4391 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
4393 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
4395 + * This package is free software; you can redistribute it and/or modify
4396 + * it under the terms of the GNU General Public License version 2 as
4397 + * published by the Free Software Foundation.
4399 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
4400 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
4401 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
4402 + */
4406 + * ======== mmu_fault.h ========
4407 + * Description:
4408 + * Defines DSP MMU fault handling functions.
4410 + *! Revision History:
4411 + *! ================
4412 + *! 26-Dec-2004 hn: IVA MMU handlers.
4413 + *! 10-Sep-2001 kc: created.
4414 + */
4416 +#ifndef MMU_FAULT_
4417 +#define MMU_FAULT_
4420 + * ======== MMU_FaultDpc ========
4421 + * Deferred procedure call to handle DSP MMU fault.
4422 + */
4423 + void MMU_FaultDpc(IN void *pRefData);
4426 + * ======== MMU_FaultIsr ========
4427 + * ISR to be triggered by a DSP MMU fault interrupt.
4428 + */
4429 + void MMU_FaultIsr(IN void *pRefData);
4432 + * ========PrintDspTraceBuffer ========
4433 + * Print DSP tracebuffer.
4434 + */
4436 +extern DSP_STATUS PrintDspTraceBuffer(struct DEH_MGR *hDehMgr);
4438 +#endif /* MMU_FAULT_ */
4440 Index: lk/drivers/dsp/bridge/wmd/msg_sm.c
4441 ===================================================================
4442 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
4443 +++ lk/drivers/dsp/bridge/wmd/msg_sm.c 2008-08-18 10:38:38.000000000 +0300
4444 @@ -0,0 +1,599 @@
4446 + * linux/drivers/dsp/bridge/wmd/linux/omap/wmdchnl/common/msg_sm.c
4448 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
4450 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
4452 + * This package is free software; you can redistribute it and/or modify
4453 + * it under the terms of the GNU General Public License version 2 as
4454 + * published by the Free Software Foundation.
4456 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
4457 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
4458 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
4459 + */
4463 + * ======== msg_sm.c ========
4464 + * Description:
4465 + * Implements upper edge functions for WMD message module.
4467 + * Public Functions:
4468 + * WMD_MSG_Create
4469 + * WMD_MSG_CreateQueue
4470 + * WMD_MSG_Delete
4471 + * WMD_MSG_DeleteQueue
4472 + * WMD_MSG_Get
4473 + * WMD_MSG_Put
4474 + * WMD_MSG_RegisterNotify
4475 + * WMD_MSG_SetQueueId
4477 + *! Revision History:
4478 + *! =================
4479 + *! 24-Jul-2002 jeh Release critical section in WMD_MSG_Put() before
4480 + *! scheduling DPC.
4481 + *! 09-May-2001 jeh Free MSG queue NTFY object, remove unnecessary set/
4482 + *! reset of events.
4483 + *! 10-Jan-2001 jeh Set/Reset message manager and message queue events
4484 + *! correctly.
4485 + *! 04-Dec-2000 jeh Bug fixes.
4486 + *! 12-Sep-2000 jeh Created.
4487 + */
4489 +/* ----------------------------------- DSP/BIOS Bridge */
4490 +#include <std.h>
4491 +#include <dbdefs.h>
4492 +#include <errbase.h>
4494 +/* ----------------------------------- Trace & Debug */
4495 +#include <dbc.h>
4497 +/* ----------------------------------- OS Adaptation Layer */
4498 +#include <list.h>
4499 +#include <mem.h>
4500 +#include <sync.h>
4502 +/* ----------------------------------- Platform Manager */
4503 +#include <dev.h>
4505 +/* ----------------------------------- Others */
4506 +#include <io_sm.h>
4508 +/* ----------------------------------- This */
4509 +#include <_msg_sm.h>
4511 +/* ----------------------------------- Defines, Data Structures, Typedefs */
4512 +#define MSGQ_SIGNATURE 0x5147534d /* "QGSM" */
4514 +/* ----------------------------------- Function Prototypes */
4515 +static DSP_STATUS AddNewMsg(struct LST_LIST *msgList);
4516 +static void DeleteMsgMgr(struct MSG_MGR *hMsgMgr);
4517 +static void DeleteMsgQueue(struct MSG_QUEUE *hMsgQueue, u32 uNumToDSP);
4518 +static void FreeMsgList(struct LST_LIST *msgList);
4521 + * ======== WMD_MSG_Create ========
4522 + * Create an object to manage message queues. Only one of these objects
4523 + * can exist per device object.
4524 + */
4525 +DSP_STATUS WMD_MSG_Create(OUT struct MSG_MGR **phMsgMgr,
4526 + struct DEV_OBJECT *hDevObject, MSG_ONEXIT msgCallback)
4528 + struct MSG_MGR *pMsgMgr;
4529 + struct IO_MGR *hIOMgr;
4530 + DSP_STATUS status = DSP_SOK;
4532 + DBC_Require(phMsgMgr != NULL);
4533 + DBC_Require(msgCallback != NULL);
4534 + DBC_Require(hDevObject != NULL);
4535 + DEV_GetIOMgr(hDevObject, &hIOMgr);
4536 + DBC_Assert(hIOMgr != NULL);
4537 + *phMsgMgr = NULL;
4538 + /* Allocate MSG manager object */
4539 + MEM_AllocObject(pMsgMgr, struct MSG_MGR, MSGMGR_SIGNATURE);
4541 + if (pMsgMgr) {
4542 + pMsgMgr->onExit = msgCallback;
4543 + pMsgMgr->hIOMgr = hIOMgr;
4544 + /* List of MSG_QUEUEs */
4545 + pMsgMgr->queueList = LST_Create();
4546 + /* Queues of message frames for messages to the DSP. Message
4547 + * frames will only be added to the free queue when a
4548 + * MSG_QUEUE object is created. */
4549 + pMsgMgr->msgFreeList = LST_Create();
4550 + pMsgMgr->msgUsedList = LST_Create();
4551 + if (pMsgMgr->queueList == NULL ||
4552 + pMsgMgr->msgFreeList == NULL ||
4553 + pMsgMgr->msgUsedList == NULL)
4554 + status = DSP_EMEMORY;
4555 + if (DSP_SUCCEEDED(status))
4556 + status = SYNC_InitializeDPCCS(&pMsgMgr->hSyncCS);
4558 + /* Create an event to be used by WMD_MSG_Put() in waiting
4559 + * for an available free frame from the message manager. */
4560 + if (DSP_SUCCEEDED(status))
4561 + status = SYNC_OpenEvent(&pMsgMgr->hSyncEvent, NULL);
4563 + if (DSP_SUCCEEDED(status))
4564 + *phMsgMgr = pMsgMgr;
4565 + else
4566 + DeleteMsgMgr(pMsgMgr);
4568 + } else {
4569 + status = DSP_EMEMORY;
4571 + return status;
4575 + * ======== WMD_MSG_CreateQueue ========
4576 + * Create a MSG_QUEUE for sending/receiving messages to/from a node
4577 + * on the DSP.
4578 + */
4579 +DSP_STATUS WMD_MSG_CreateQueue(struct MSG_MGR *hMsgMgr,
4580 + OUT struct MSG_QUEUE **phMsgQueue,
4581 + u32 dwId, u32 uMaxMsgs, HANDLE hArg)
4583 + u32 i;
4584 + u32 uNumAllocated = 0;
4585 + struct MSG_QUEUE *pMsgQ;
4586 + DSP_STATUS status = DSP_SOK;
4588 + DBC_Require(MEM_IsValidHandle(hMsgMgr, MSGMGR_SIGNATURE));
4589 + DBC_Require(phMsgQueue != NULL);
4591 + *phMsgQueue = NULL;
4592 + /* Allocate MSG_QUEUE object */
4593 + MEM_AllocObject(pMsgQ, struct MSG_QUEUE, MSGQ_SIGNATURE);
4594 + if (!pMsgQ) {
4595 + status = DSP_EMEMORY;
4596 + goto func_end;
4598 + LST_InitElem((struct LST_ELEM *) pMsgQ);
4599 + pMsgQ->uMaxMsgs = uMaxMsgs;
4600 + pMsgQ->hMsgMgr = hMsgMgr;
4601 + pMsgQ->hArg = hArg; /* Node handle */
4602 + pMsgQ->dwId = dwId; /* Node env (not valid yet) */
4603 + /* Queues of Message frames for messages from the DSP */
4604 + pMsgQ->msgFreeList = LST_Create();
4605 + pMsgQ->msgUsedList = LST_Create();
4606 + if (pMsgQ->msgFreeList == NULL || pMsgQ->msgUsedList == NULL)
4607 + status = DSP_EMEMORY;
4609 + /* Create event that will be signalled when a message from
4610 + * the DSP is available. */
4611 + if (DSP_SUCCEEDED(status))
4612 + status = SYNC_OpenEvent(&pMsgQ->hSyncEvent, NULL);
4614 + /* Create a notification list for message ready notification. */
4615 + if (DSP_SUCCEEDED(status))
4616 + status = NTFY_Create(&pMsgQ->hNtfy);
4618 + /* Create events that will be used to synchronize cleanup
4619 + * when the object is deleted. hSyncDone will be set to
4620 + * unblock threads in MSG_Put() or MSG_Get(). hSyncDoneAck
4621 + * will be set by the unblocked thread to signal that it
4622 + * is unblocked and will no longer reference the object. */
4623 + if (DSP_SUCCEEDED(status))
4624 + status = SYNC_OpenEvent(&pMsgQ->hSyncDone, NULL);
4626 + if (DSP_SUCCEEDED(status))
4627 + status = SYNC_OpenEvent(&pMsgQ->hSyncDoneAck, NULL);
4629 + if (DSP_SUCCEEDED(status)) {
4630 + /* Enter critical section */
4631 + (void)SYNC_EnterCS(hMsgMgr->hSyncCS);
4632 + /* Initialize message frames and put in appropriate queues */
4633 + for (i = 0; i < uMaxMsgs && DSP_SUCCEEDED(status); i++) {
4634 + status = AddNewMsg(hMsgMgr->msgFreeList);
4635 + if (DSP_SUCCEEDED(status)) {
4636 + uNumAllocated++;
4637 + status = AddNewMsg(pMsgQ->msgFreeList);
4640 + if (DSP_FAILED(status)) {
4641 + /* Stay inside CS to prevent others from taking any
4642 + * of the newly allocated message frames. */
4643 + DeleteMsgQueue(pMsgQ, uNumAllocated);
4644 + } else {
4645 + LST_PutTail(hMsgMgr->queueList,
4646 + (struct LST_ELEM *)pMsgQ);
4647 + *phMsgQueue = pMsgQ;
4648 + /* Signal that free frames are now available */
4649 + if (!LST_IsEmpty(hMsgMgr->msgFreeList))
4650 + SYNC_SetEvent(hMsgMgr->hSyncEvent);
4653 + /* Exit critical section */
4654 + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS);
4655 + } else {
4656 + DeleteMsgQueue(pMsgQ, 0);
4658 +func_end:
4659 + return status;
4663 + * ======== WMD_MSG_Delete ========
4664 + * Delete a MSG manager allocated in WMD_MSG_Create().
4665 + */
4666 +void WMD_MSG_Delete(struct MSG_MGR *hMsgMgr)
4668 + DBC_Require(MEM_IsValidHandle(hMsgMgr, MSGMGR_SIGNATURE));
4670 + DeleteMsgMgr(hMsgMgr);
4674 + * ======== WMD_MSG_DeleteQueue ========
4675 + * Delete a MSG queue allocated in WMD_MSG_CreateQueue.
4676 + */
4677 +void WMD_MSG_DeleteQueue(struct MSG_QUEUE *hMsgQueue)
4679 + struct MSG_MGR *hMsgMgr = hMsgQueue->hMsgMgr;
4680 + u32 refCount;
4682 + DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE));
4683 + hMsgQueue->fDone = true;
4684 + /* Unblock all threads blocked in MSG_Get() or MSG_Put(). */
4685 + refCount = hMsgQueue->refCount;
4686 + while (refCount) {
4687 + /* Unblock thread */
4688 + SYNC_SetEvent(hMsgQueue->hSyncDone);
4689 + /* Wait for acknowledgement */
4690 + SYNC_WaitOnEvent(hMsgQueue->hSyncDoneAck, SYNC_INFINITE);
4691 + refCount = hMsgQueue->refCount;
4693 + /* Remove message queue from hMsgMgr->queueList */
4694 + (void)SYNC_EnterCS(hMsgMgr->hSyncCS);
4695 + LST_RemoveElem(hMsgMgr->queueList, (struct LST_ELEM *)hMsgQueue);
4696 + /* Free the message queue object */
4697 + DeleteMsgQueue(hMsgQueue, hMsgQueue->uMaxMsgs);
4698 + if (LST_IsEmpty(hMsgMgr->msgFreeList))
4699 + SYNC_ResetEvent(hMsgMgr->hSyncEvent);
4701 + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS);
4705 + * ======== WMD_MSG_Get ========
4706 + * Get a message from a MSG queue.
4707 + */
4708 +DSP_STATUS WMD_MSG_Get(struct MSG_QUEUE *hMsgQueue,
4709 + struct DSP_MSG *pMsg, u32 uTimeout)
4711 + struct MSG_FRAME *pMsgFrame;
4712 + struct MSG_MGR *hMsgMgr;
4713 + bool fGotMsg = false;
4714 + struct SYNC_OBJECT *hSyncs[2];
4715 + u32 uIndex;
4716 + DSP_STATUS status = DSP_SOK;
4718 + DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE));
4719 + DBC_Require(pMsg != NULL);
4721 + hMsgMgr = hMsgQueue->hMsgMgr;
4722 + /* Enter critical section */
4723 + (void)SYNC_EnterCS(hMsgMgr->hSyncCS);
4724 + /* If a message is already there, get it */
4725 + if (!LST_IsEmpty(hMsgQueue->msgUsedList)) {
4726 + pMsgFrame = (struct MSG_FRAME *)LST_GetHead(hMsgQueue->
4727 + msgUsedList);
4728 + if (pMsgFrame != NULL) {
4729 + *pMsg = pMsgFrame->msgData.msg;
4730 + LST_PutTail(hMsgQueue->msgFreeList,
4731 + (struct LST_ELEM *)pMsgFrame);
4732 + if (LST_IsEmpty(hMsgQueue->msgUsedList))
4733 + SYNC_ResetEvent(hMsgQueue->hSyncEvent);
4735 + fGotMsg = true;
4737 + } else {
4738 + if (hMsgQueue->fDone)
4739 + status = DSP_EFAIL;
4740 + else
4741 + hMsgQueue->refCount++;
4744 + /* Exit critical section */
4745 + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS);
4746 + if (DSP_SUCCEEDED(status) && !fGotMsg) {
4747 + /* Wait til message is available, timeout, or done. We don't
4748 + * have to schedule the DPC, since the DSP will send messages
4749 + * when they are available. */
4750 + hSyncs[0] = hMsgQueue->hSyncEvent;
4751 + hSyncs[1] = hMsgQueue->hSyncDone;
4752 + status = SYNC_WaitOnMultipleEvents(hSyncs, 2, uTimeout,
4753 + &uIndex);
4754 + /* Enter critical section */
4755 + (void)SYNC_EnterCS(hMsgMgr->hSyncCS);
4756 + if (hMsgQueue->fDone) {
4757 + hMsgQueue->refCount--;
4758 + /* Exit critical section */
4759 + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS);
4760 + /* Signal that we're not going to access hMsgQueue
4761 + * anymore, so it can be deleted. */
4762 + (void)SYNC_SetEvent(hMsgQueue->hSyncDoneAck);
4763 + status = DSP_EFAIL;
4764 + } else {
4765 + if (DSP_SUCCEEDED(status)) {
4766 + DBC_Assert(!LST_IsEmpty(hMsgQueue->
4767 + msgUsedList));
4768 + /* Get msg from used list */
4769 + pMsgFrame = (struct MSG_FRAME *)
4770 + LST_GetHead(hMsgQueue->msgUsedList);
4771 + /* Copy message into pMsg and put frame on the
4772 + * free list */
4773 + if (pMsgFrame != NULL) {
4774 + *pMsg = pMsgFrame->msgData.msg;
4775 + LST_PutTail(hMsgQueue->msgFreeList,
4776 + (struct LST_ELEM *)pMsgFrame);
4779 + hMsgQueue->refCount--;
4780 + /* Reset the event if there are still queued messages */
4781 + if (!LST_IsEmpty(hMsgQueue->msgUsedList))
4782 + SYNC_SetEvent(hMsgQueue->hSyncEvent);
4784 + /* Exit critical section */
4785 + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS);
4788 + return status;
4792 + * ======== WMD_MSG_Put ========
4793 + * Put a message onto a MSG queue.
4794 + */
4795 +DSP_STATUS WMD_MSG_Put(struct MSG_QUEUE *hMsgQueue,
4796 + IN CONST struct DSP_MSG *pMsg, u32 uTimeout)
4798 + struct MSG_FRAME *pMsgFrame;
4799 + struct MSG_MGR *hMsgMgr;
4800 + bool fPutMsg = false;
4801 + struct SYNC_OBJECT *hSyncs[2];
4802 + u32 uIndex;
4803 + DSP_STATUS status = DSP_SOK;
4805 + DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE));
4806 + DBC_Require(pMsg != NULL);
4808 + hMsgMgr = hMsgQueue->hMsgMgr;
4810 + (void) SYNC_EnterCS(hMsgMgr->hSyncCS);
4812 + /* If a message frame is available, use it */
4813 + if (!LST_IsEmpty(hMsgMgr->msgFreeList)) {
4814 + pMsgFrame = (struct MSG_FRAME *)LST_GetHead(hMsgMgr->
4815 + msgFreeList);
4816 + if (pMsgFrame != NULL) {
4817 + pMsgFrame->msgData.msg = *pMsg;
4818 + pMsgFrame->msgData.dwId = hMsgQueue->dwId;
4819 + LST_PutTail(hMsgMgr->msgUsedList, (struct LST_ELEM *)
4820 + pMsgFrame);
4821 + hMsgMgr->uMsgsPending++;
4822 + fPutMsg = true;
4824 + if (LST_IsEmpty(hMsgMgr->msgFreeList))
4825 + SYNC_ResetEvent(hMsgMgr->hSyncEvent);
4827 + /* Release critical section before scheduling DPC */
4828 + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS);
4829 + /* Schedule a DPC, to do the actual data transfer: */
4830 + IO_Schedule(hMsgMgr->hIOMgr);
4831 + } else {
4832 + if (hMsgQueue->fDone)
4833 + status = DSP_EFAIL;
4834 + else
4835 + hMsgQueue->refCount++;
4837 + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS);
4839 + if (DSP_SUCCEEDED(status) && !fPutMsg) {
4840 + /* Wait til a free message frame is available, timeout,
4841 + * or done */
4842 + hSyncs[0] = hMsgMgr->hSyncEvent;
4843 + hSyncs[1] = hMsgQueue->hSyncDone;
4844 + status = SYNC_WaitOnMultipleEvents(hSyncs, 2, uTimeout,
4845 + &uIndex);
4846 + /* Enter critical section */
4847 + (void)SYNC_EnterCS(hMsgMgr->hSyncCS);
4848 + if (hMsgQueue->fDone) {
4849 + hMsgQueue->refCount--;
4850 + /* Exit critical section */
4851 + (void)SYNC_LeaveCS(hMsgMgr->hSyncCS);
4852 + /* Signal that we're not going to access hMsgQueue
4853 + * anymore, so it can be deleted. */
4854 + (void)SYNC_SetEvent(hMsgQueue->hSyncDoneAck);
4855 + status = DSP_EFAIL;
4856 + } else {
4857 + if (DSP_SUCCEEDED(status)) {
4858 + DBC_Assert(!LST_IsEmpty(hMsgMgr->msgFreeList));
4859 + /* Get msg from free list */
4860 + pMsgFrame = (struct MSG_FRAME *)
4861 + LST_GetHead(hMsgMgr->msgFreeList);
4862 + /* Copy message into pMsg and put frame on the
4863 + * used list */
4864 + if (pMsgFrame != NULL) {
4865 + pMsgFrame->msgData.msg = *pMsg;
4866 + pMsgFrame->msgData.dwId =
4867 + hMsgQueue->dwId;
4868 + LST_PutTail(hMsgMgr->msgUsedList,
4869 + (struct LST_ELEM *)
4870 + pMsgFrame);
4871 + hMsgMgr->uMsgsPending++;
4872 + /* Schedule a DPC, to do the actual
4873 + * data transfer: */
4874 + IO_Schedule(hMsgMgr->hIOMgr);
4877 + hMsgQueue->refCount--;
4878 + /* Reset event if there are still frames available */
4879 + if (!LST_IsEmpty(hMsgMgr->msgFreeList))
4880 + SYNC_SetEvent(hMsgMgr->hSyncEvent);
4882 + /* Exit critical section */
4883 + (void) SYNC_LeaveCS(hMsgMgr->hSyncCS);
4886 + return status;
4890 + * ======== WMD_MSG_RegisterNotify ========
4891 + */
4892 +DSP_STATUS WMD_MSG_RegisterNotify(struct MSG_QUEUE *hMsgQueue, u32 uEventMask,
4893 + u32 uNotifyType,
4894 + struct DSP_NOTIFICATION *hNotification)
4896 + DSP_STATUS status = DSP_SOK;
4898 + DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE));
4899 + DBC_Require(hNotification != NULL);
4900 + DBC_Require(uEventMask == DSP_NODEMESSAGEREADY || uEventMask == 0);
4901 + DBC_Require(uNotifyType == DSP_SIGNALEVENT);
4903 + status = NTFY_Register(hMsgQueue->hNtfy, hNotification, uEventMask,
4904 + uNotifyType);
4906 + if (status == DSP_EVALUE) {
4907 + /* Not registered. Ok, since we couldn't have known. Node
4908 + * notifications are split between node state change handled
4909 + * by NODE, and message ready handled by MSG. */
4910 + status = DSP_SOK;
4913 + return status;
4917 + * ======== WMD_MSG_SetQueueId ========
4918 + */
4919 +void WMD_MSG_SetQueueId(struct MSG_QUEUE *hMsgQueue, u32 dwId)
4921 + DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE));
4922 + /* DBC_Require(dwId != 0); */
4924 + /*
4925 + * A message queue must be created when a node is allocated,
4926 + * so that NODE_RegisterNotify() can be called before the node
4927 + * is created. Since we don't know the node environment until the
4928 + * node is created, we need this function to set hMsgQueue->dwId
4929 + * to the node environment, after the node is created.
4930 + */
4931 + hMsgQueue->dwId = dwId;
4935 + * ======== AddNewMsg ========
4936 + * Must be called in message manager critical section.
4937 + */
4938 +static DSP_STATUS AddNewMsg(struct LST_LIST *msgList)
4940 + struct MSG_FRAME *pMsg;
4941 + DSP_STATUS status = DSP_SOK;
4943 + pMsg = (struct MSG_FRAME *)MEM_Calloc(sizeof(struct MSG_FRAME),
4944 + MEM_PAGED);
4945 + if (pMsg != NULL) {
4946 + LST_InitElem((struct LST_ELEM *) pMsg);
4947 + LST_PutTail(msgList, (struct LST_ELEM *) pMsg);
4948 + } else {
4949 + status = DSP_EMEMORY;
4952 + return status;
4956 + * ======== DeleteMsgMgr ========
4957 + */
4958 +static void DeleteMsgMgr(struct MSG_MGR *hMsgMgr)
4960 + DBC_Require(MEM_IsValidHandle(hMsgMgr, MSGMGR_SIGNATURE));
4962 + if (hMsgMgr->queueList) {
4963 + DBC_Assert(LST_IsEmpty(hMsgMgr->queueList));
4964 + LST_Delete(hMsgMgr->queueList);
4967 + if (hMsgMgr->msgFreeList)
4968 + FreeMsgList(hMsgMgr->msgFreeList);
4970 + if (hMsgMgr->msgUsedList)
4971 + FreeMsgList(hMsgMgr->msgUsedList);
4973 + if (hMsgMgr->hSyncEvent)
4974 + SYNC_CloseEvent(hMsgMgr->hSyncEvent);
4976 + if (hMsgMgr->hSyncCS)
4977 + SYNC_DeleteCS(hMsgMgr->hSyncCS);
4979 + MEM_FreeObject(hMsgMgr);
4983 + * ======== DeleteMsgQueue ========
4984 + */
4985 +static void DeleteMsgQueue(struct MSG_QUEUE *hMsgQueue, u32 uNumToDSP)
4987 + struct MSG_MGR *hMsgMgr = hMsgQueue->hMsgMgr;
4988 + struct MSG_FRAME *pMsg;
4989 + u32 i;
4991 + DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE));
4993 + /* Pull off uNumToDSP message frames from Msg manager and free */
4994 + for (i = 0; i < uNumToDSP; i++) {
4996 + if (!LST_IsEmpty(hMsgMgr->msgFreeList)) {
4997 + pMsg = (struct MSG_FRAME *)LST_GetHead(hMsgMgr->
4998 + msgFreeList);
4999 + MEM_Free(pMsg);
5000 + } else {
5001 + /* Cannot free all of the message frames */
5002 + break;
5006 + if (hMsgQueue->msgFreeList)
5007 + FreeMsgList(hMsgQueue->msgFreeList);
5009 + if (hMsgQueue->msgUsedList)
5010 + FreeMsgList(hMsgQueue->msgUsedList);
5012 + if (hMsgQueue->hNtfy)
5013 + NTFY_Delete(hMsgQueue->hNtfy);
5015 + if (hMsgQueue->hSyncEvent)
5016 + SYNC_CloseEvent(hMsgQueue->hSyncEvent);
5018 + if (hMsgQueue->hSyncDone)
5019 + SYNC_CloseEvent(hMsgQueue->hSyncDone);
5021 + if (hMsgQueue->hSyncDoneAck)
5022 + SYNC_CloseEvent(hMsgQueue->hSyncDoneAck);
5024 + MEM_FreeObject(hMsgQueue);
5028 + * ======== FreeMsgList ========
5029 + */
5030 +static void FreeMsgList(struct LST_LIST *msgList)
5032 + struct MSG_FRAME *pMsg;
5034 + DBC_Require(msgList != NULL);
5036 + while ((pMsg = (struct MSG_FRAME *)LST_GetHead(msgList)) != NULL)
5037 + MEM_Free(pMsg);
5039 + DBC_Assert(LST_IsEmpty(msgList));
5041 + LST_Delete(msgList);
5044 Index: lk/drivers/dsp/bridge/wmd/tiomap3430.c
5045 ===================================================================
5046 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
5047 +++ lk/drivers/dsp/bridge/wmd/tiomap3430.c 2008-08-18 10:38:38.000000000 +0300
5048 @@ -0,0 +1,2171 @@
5050 + * linux/drivers/dsp/bridge/wmd/linux/omap/3430/tiomap.c
5052 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5054 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
5056 + * This package is free software; you can redistribute it and/or modify
5057 + * it under the terms of the GNU General Public License version 2 as
5058 + * published by the Free Software Foundation.
5060 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
5061 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
5062 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
5063 + */
5066 + * ======== tiomap.c ========
5067 + * Processor Manager Driver for TI OMAP3430 EVM.
5069 + * Public Function:
5070 + * WMD_DRV_Entry
5072 + *! Revision History:
5073 + *! ================
5074 + * 26-March-2008 HK and AL: Added WMD_DEV_WalkTbl funciton.
5075 + */
5077 +/* ----------------------------------- Host OS */
5078 +#include <host_os.h>
5080 +/* ----------------------------------- DSP/BIOS Bridge */
5081 +#include <std.h>
5082 +#include <dbdefs.h>
5083 +#include <errbase.h>
5085 +/* ----------------------------------- Trace & Debug */
5086 +#include <dbc.h>
5087 +#include <dbg.h>
5089 +/* ----------------------------------- OS Adaptation Layer */
5090 +#include <mem.h>
5091 +#include <util.h>
5092 +#include <reg.h>
5093 +#include <dbreg.h>
5094 +#include <cfg.h>
5095 +#include <drv.h>
5096 +#include <csl.h>
5097 +#include <sync.h>
5099 +/* ------------------------------------ Hardware Abstraction Layer */
5100 +#include <hw_defs.h>
5101 +#include <hw_dspssC64P.h>
5102 +#include <hw_prcm.h>
5103 +#include <hw_mmu.h>
5104 +#include <hw_mbox.h>
5106 +/* ----------------------------------- Link Driver */
5107 +#include <wmd.h>
5108 +#include <wmdchnl.h>
5109 +#include <wmddeh.h>
5110 +#include <wmdio.h>
5111 +#include <wmdmsg.h>
5112 +#include <pwr.h>
5113 +#include <chnl_sm.h>
5114 +#include <io_sm.h>
5116 +/* ----------------------------------- Platform Manager */
5117 +#include <dev.h>
5118 +#include <wcd.h>
5119 +#include <dmm.h>
5121 +/* ----------------------------------- Local */
5122 +#include "_tiomap.h"
5123 +#include "_tiomap_pwr.h"
5124 +#include "_tiomap_mmu.h"
5125 +#include "_tiomap_util.h"
5126 +#include "tiomap_io.h"
5128 +/* Offset in shared mem to write to in order to synchronize start with DSP */
5129 +#define SHMSYNCOFFSET 4 /* GPP byte offset */
5131 +#define BUFFERSIZE 1024
5133 +#define MMU_SECTION_ADDR_MASK 0xFFF00000
5134 +#define MMU_SSECTION_ADDR_MASK 0xFF000000
5135 +#define MMU_LARGE_PAGE_MASK 0xFFFF0000
5136 +#define MMU_SMALL_PAGE_MASK 0xFFFFF000
5137 +#define PAGES_II_LVL_TABLE 512
5138 +/* Forward Declarations: */
5139 +static DSP_STATUS WMD_BRD_Monitor(struct WMD_DEV_CONTEXT *pDevContext);
5140 +static DSP_STATUS WMD_BRD_Read(struct WMD_DEV_CONTEXT *pDevContext,
5141 + OUT u8 *pbHostBuf,
5142 + u32 dwDSPAddr, u32 ulNumBytes, u32 ulMemType);
5143 +static DSP_STATUS WMD_BRD_Start(struct WMD_DEV_CONTEXT *pDevContext,
5144 + u32 dwDSPAddr);
5145 +static DSP_STATUS WMD_BRD_Status(struct WMD_DEV_CONTEXT *pDevContext,
5146 + OUT BRD_STATUS *pdwState);
5147 +static DSP_STATUS WMD_BRD_Stop(struct WMD_DEV_CONTEXT *pDevContext);
5148 +static DSP_STATUS WMD_BRD_Write(struct WMD_DEV_CONTEXT *pDevContext,
5149 + IN u8 *pbHostBuf,
5150 + u32 dwDSPAddr, u32 ulNumBytes, u32 ulMemType);
5151 +static DSP_STATUS WMD_BRD_SetState(struct WMD_DEV_CONTEXT *hDevContext,
5152 + u32 ulBrdState);
5153 +static DSP_STATUS WMD_BRD_MemCopy(struct WMD_DEV_CONTEXT *hDevContext,
5154 + u32 ulDspDestAddr, u32 ulDspSrcAddr,
5155 + u32 ulNumBytes, u32 ulMemType);
5156 +static DSP_STATUS WMD_BRD_MemWrite(struct WMD_DEV_CONTEXT *pDevContext,
5157 + IN u8 *pbHostBuf, u32 dwDSPAddr,
5158 + u32 ulNumBytes, u32 ulMemType);
5159 +static DSP_STATUS WMD_BRD_MemMap(struct WMD_DEV_CONTEXT *hDevContext,
5160 + u32 ulMpuAddr, u32 ulVirtAddr, u32 ulNumBytes,
5161 + u32 ulMapAttr);
5162 +static DSP_STATUS WMD_BRD_MemUnMap(struct WMD_DEV_CONTEXT *hDevContext,
5163 + u32 ulVirtAddr, u32 ulNumBytes);
5164 +static DSP_STATUS WMD_DEV_Create(OUT struct WMD_DEV_CONTEXT **ppDevContext,
5165 + struct DEV_OBJECT *hDevObject,
5166 + IN CONST struct CFG_HOSTRES *pConfig,
5167 + IN CONST struct CFG_DSPRES *pDspConfig);
5168 +static DSP_STATUS WMD_DEV_Ctrl(struct WMD_DEV_CONTEXT *pDevContext, u32 dwCmd,
5169 + IN OUT void *pArgs);
5170 +static DSP_STATUS WMD_DEV_Destroy(struct WMD_DEV_CONTEXT *pDevContext);
5171 +static DSP_STATUS TIOMAP_VirtToPhysical(struct mm_struct *mm, u32 ulMpuAddr,
5172 + u32 ulNumBytes, u32 *numOfTableEntries,
5173 + u32 *physicalAddrTable);
5174 +static DSP_STATUS PteUpdate(struct WMD_DEV_CONTEXT *hDevContext, u32 pa,
5175 + u32 va, u32 size,
5176 + struct HW_MMUMapAttrs_t *mapAttrs);
5177 +static DSP_STATUS PteSet(struct PgTableAttrs *pt, u32 pa, u32 va,
5178 + u32 size, struct HW_MMUMapAttrs_t *attrs);
5179 +static DSP_STATUS MemMapVmalloc(struct WMD_DEV_CONTEXT *hDevContext,
5180 + u32 ulMpuAddr, u32 ulVirtAddr,
5181 + u32 ulNumBytes, u32 ulMapAttr);
5182 +static DSP_STATUS run_IdleBoot(u32 prcm_base, u32 cm_base,
5183 + u32 sysctrl_base);
5184 +void GetHWRegs(u32 prcm_base, u32 cm_base);
5186 +/* ----------------------------------- Globals */
5187 +#ifndef DEBUG
5188 +u64 tiomap1510_liTicksPerSecond; /* Timer frequency */
5189 +#endif
5191 +/* Attributes of L2 page tables for DSP MMU */
5192 +struct PageInfo {
5193 + u32 numEntries; /* Number of valid PTEs in the L2 PT */
5194 +} ;
5196 +/* Attributes used to manage the DSP MMU page tables */
5197 +struct PgTableAttrs {
5198 + struct SYNC_CSOBJECT *hCSObj; /* Critical section object handle */
5200 + u32 L1BasePa; /* Physical address of the L1 PT */
5201 + u32 L1BaseVa; /* Virtual address of the L1 PT */
5202 + u32 L1size; /* Size of the L1 PT */
5203 + u32 L1TblAllocPa;
5204 + /* Physical address of Allocated mem for L1 table. May not be aligned */
5205 + u32 L1TblAllocVa;
5206 + /* Virtual address of Allocated mem for L1 table. May not be aligned */
5207 + u32 L1TblAllocSz;
5208 + /* Size of consistent memory allocated for L1 table.
5209 + * May not be aligned */
5211 + u32 L2BasePa; /* Physical address of the L2 PT */
5212 + u32 L2BaseVa; /* Virtual address of the L2 PT */
5213 + u32 L2size; /* Size of the L2 PT */
5214 + u32 L2TblAllocPa;
5215 + /* Physical address of Allocated mem for L2 table. May not be aligned */
5216 + u32 L2TblAllocVa;
5217 + /* Virtual address of Allocated mem for L2 table. May not be aligned */
5218 + u32 L2TblAllocSz;
5219 + /* Size of consistent memory allocated for L2 table.
5220 + * May not be aligned */
5222 + u32 L2NumPages; /* Number of allocated L2 PT */
5223 + struct PageInfo *pgInfo; /* Array [L2NumPages] of L2 PT info structs */
5224 +} ;
5227 + * If dsp_debug is true, do not branch to the DSP entry point and wait for DSP
5228 + * to boot
5229 + */
5230 +extern s32 dsp_debug;
5234 + * This mini driver's function interface table.
5235 + */
5236 +static struct WMD_DRV_INTERFACE drvInterfaceFxns = {
5237 + WCD_MAJOR_VERSION, /* WCD ver. for which this mini driver is built. */
5238 + WCD_MINOR_VERSION,
5239 + WMD_DEV_Create,
5240 + WMD_DEV_Destroy,
5241 + WMD_DEV_Ctrl,
5242 + WMD_BRD_Monitor,
5243 + WMD_BRD_Start,
5244 + WMD_BRD_Stop,
5245 + WMD_BRD_Status,
5246 + WMD_BRD_Read,
5247 + WMD_BRD_Write,
5248 + WMD_BRD_SetState,
5249 + WMD_BRD_MemCopy,
5250 + WMD_BRD_MemWrite,
5251 + WMD_BRD_MemMap,
5252 + WMD_BRD_MemUnMap,
5253 + /* The following CHNL functions are provided by chnl_io.lib: */
5254 + WMD_CHNL_Create,
5255 + WMD_CHNL_Destroy,
5256 + WMD_CHNL_Open,
5257 + WMD_CHNL_Close,
5258 + WMD_CHNL_AddIOReq,
5259 + WMD_CHNL_GetIOC,
5260 + WMD_CHNL_CancelIO,
5261 + WMD_CHNL_FlushIO,
5262 + WMD_CHNL_GetInfo,
5263 + WMD_CHNL_GetMgrInfo,
5264 + WMD_CHNL_Idle,
5265 + WMD_CHNL_RegisterNotify,
5266 + /* The following DEH functions are provided by tihelen_ue_deh.c */
5267 + WMD_DEH_Create,
5268 + WMD_DEH_Destroy,
5269 + WMD_DEH_Notify,
5270 + WMD_DEH_RegisterNotify,
5271 + WMD_DEH_GetInfo,
5272 + /* The following IO functions are provided by chnl_io.lib: */
5273 + WMD_IO_Create,
5274 + WMD_IO_Destroy,
5275 + WMD_IO_OnLoaded,
5276 + WMD_IO_GetProcLoad,
5277 + /* The following MSG functions are provided by chnl_io.lib: */
5278 + WMD_MSG_Create,
5279 + WMD_MSG_CreateQueue,
5280 + WMD_MSG_Delete,
5281 + WMD_MSG_DeleteQueue,
5282 + WMD_MSG_Get,
5283 + WMD_MSG_Put,
5284 + WMD_MSG_RegisterNotify,
5285 + WMD_MSG_SetQueueId,
5289 + * ======== WMD_DRV_Entry ========
5290 + * purpose:
5291 + * Mini Driver entry point.
5292 + */
5293 +void CDECL WMD_DRV_Entry(OUT struct WMD_DRV_INTERFACE **ppDrvInterface,
5294 + IN CONST char *pstrWMDFileName)
5297 + DBC_Require(pstrWMDFileName != NULL);
5298 + DBG_Trace(DBG_ENTER, "In the WMD_DRV_Entry \n");
5300 +#ifndef DEBUG
5301 + tiomap1510_liTicksPerSecond = HZ;
5302 +#endif
5304 + if (CSL_Strcmp(pstrWMDFileName, "UMA") == 0)
5305 + *ppDrvInterface = &drvInterfaceFxns;
5306 + else
5307 + DBG_Trace(DBG_LEVEL7, "WMD_DRV_Entry Unknown WMD file name");
5312 + * ======== WMD_BRD_Monitor ========
5313 + * purpose:
5314 + * This WMD_BRD_Monitor puts DSP into a Loadable state.
5315 + * i.e Application can load and start the device.
5317 + * Preconditions:
5318 + * Device in 'OFF' state.
5319 + */
5320 +static DSP_STATUS WMD_BRD_Monitor(struct WMD_DEV_CONTEXT *hDevContext)
5322 + DSP_STATUS status = DSP_SOK;
5323 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
5324 + struct CFG_HOSTRES resources;
5325 + u32 temp;
5326 + enum HW_PwrState_t pwrState;
5328 + DBG_Trace(DBG_ENTER, "Board in the monitor state \n");
5329 + status = CFG_GetHostResources(
5330 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources);
5331 + if (DSP_FAILED(status))
5332 + goto error_return;
5334 + GetHWRegs(resources.dwPrmBase, resources.dwCmBase);
5335 + HW_PWRST_IVA2RegGet(resources.dwPrmBase, &temp);
5336 + if ((temp & 0x03) != 0x03 || (temp & 0x03) != 0x02) {
5337 + /* IVA2 is not in ON state */
5338 + /* Read and set PM_PWSTCTRL_IVA2 to ON */
5339 + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP,
5340 + &pwrState);
5341 + HW_PWR_IVA2PowerStateSet(resources.dwPrmBase,
5342 + HW_PWR_DOMAIN_DSP,
5343 + HW_PWR_STATE_ON);
5344 + /* Set the SW supervised state transition */
5345 + HW_PWR_CLKCTRL_IVA2RegSet(resources.dwCmBase,
5346 + HW_SW_SUP_WAKEUP);
5347 + /* Wait until the state has moved to ON */
5348 + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP,
5349 + &pwrState);
5350 + /* Disable Automatic transition */
5351 + HW_PWR_CLKCTRL_IVA2RegSet(resources.dwCmBase, HW_AUTOTRANS_DIS);
5353 + DBG_Trace(DBG_LEVEL6, "WMD_BRD_Monitor - Middle ****** \n");
5354 + GetHWRegs(resources.dwPrmBase, resources.dwCmBase);
5355 + status = run_IdleBoot(resources.dwPrmBase, resources.dwCmBase,
5356 + resources.dwSysCtrlBase);
5357 + if (DSP_SUCCEEDED(status)) {
5358 + /* set the device state to IDLE */
5359 + pDevContext->dwBrdState = BRD_IDLE;
5362 +error_return:
5363 + DBG_Trace(DBG_LEVEL6, "WMD_BRD_Monitor - End ****** \n");
5364 + GetHWRegs(resources.dwPrmBase, resources.dwCmBase);
5365 + return status;
5369 + * ======== WMD_BRD_Read ========
5370 + * purpose:
5371 + * Reads buffers for DSP memory.
5372 + */
5373 +static DSP_STATUS WMD_BRD_Read(struct WMD_DEV_CONTEXT *hDevContext,
5374 + OUT u8 *pbHostBuf, u32 dwDSPAddr,
5375 + u32 ulNumBytes, u32 ulMemType)
5377 + DSP_STATUS status = DSP_SOK;
5378 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
5379 + u32 offset;
5380 + u32 dspBaseAddr = hDevContext->dwDspBaseAddr;
5382 + DBG_Trace(DBG_ENTER, "WMD_BRD_Read, pDevContext: 0x%x\n\t\tpbHostBuf:"
5383 + " 0x%x\n\t\tdwDSPAddr: 0x%x\n\t\tulNumBytes: 0x%x\n\t\t"
5384 + "ulMemType: 0x%x\n", pDevContext, pbHostBuf,
5385 + dwDSPAddr, ulNumBytes, ulMemType);
5386 + if (dwDSPAddr < pDevContext->dwDSPStartAdd) {
5387 + DBG_Trace(DBG_LEVEL7,
5388 + "WMD_BRD_Read: DSP address < start address \n ");
5389 + status = DSP_EFAIL;
5390 + return status;
5392 + /* change here to account for the 3 bands of the DSP internal memory */
5393 + if ((dwDSPAddr - pDevContext->dwDSPStartAdd) <
5394 + pDevContext->dwInternalSize) {
5395 + offset = dwDSPAddr - pDevContext->dwDSPStartAdd;
5396 + } else {
5397 + DBG_Trace(DBG_LEVEL1,
5398 + "**** Reading From external memory **** \n ");
5399 + status = ReadExtDspData(pDevContext, pbHostBuf, dwDSPAddr,
5400 + ulNumBytes, ulMemType);
5401 + return status;
5403 + /* copy the data from DSP memory, */
5404 + memcpy(pbHostBuf, (void *)(dspBaseAddr + offset), ulNumBytes);
5405 + return status;
5409 + * ======== WMD_BRD_SetState ========
5410 + * purpose:
5411 + * This routine updates the Board status.
5412 + */
5413 +static DSP_STATUS WMD_BRD_SetState(struct WMD_DEV_CONTEXT *hDevContext,
5414 + u32 ulBrdState)
5416 + DSP_STATUS status = DSP_SOK;
5417 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
5419 + DBG_Trace(DBG_ENTER, "WMD_BRD_SetState: Board State: 0x%x \n",
5420 + ulBrdState);
5421 + pDevContext->dwBrdState = ulBrdState;
5422 + return status;
5426 + * ======== WMD_BRD_Start ========
5427 + * purpose:
5428 + * Initializes DSP MMU and Starts DSP.
5430 + * Preconditions:
5431 + * a) DSP domain is 'ACTIVE'.
5432 + * b) DSP_RST1 is asserted.
5433 + * b) DSP_RST2 is released.
5434 + */
5435 +static DSP_STATUS WMD_BRD_Start(struct WMD_DEV_CONTEXT *hDevContext,
5436 + u32 dwDSPAddr)
5438 + DSP_STATUS status = DSP_SOK;
5439 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
5440 + u32 dwSyncAddr = 0;
5441 + u32 ulShmBase; /* Gpp Phys SM base addr(byte) */
5442 + u32 ulShmBaseVirt; /* Dsp Virt SM base addr */
5443 + u32 ulTLBBaseVirt; /* Base of MMU TLB entry */
5444 + u32 ulShmOffsetVirt; /* offset of ulShmBaseVirt from ulTLBBaseVirt */
5445 + s32 iEntryNdx;
5446 + s32 itmpEntryNdx = 0; /* DSP-MMU TLB entry base address */
5447 + struct CFG_HOSTRES resources;
5448 + u32 temp;
5449 + u32 ulDspClkRate;
5450 + u32 ulDspClkAddr;
5451 + u32 ulBiosGpTimer;
5452 + u32 uClkCmd;
5453 + struct IO_MGR *hIOMgr;
5454 + u32 ulLoadMonitorTimer;
5455 + u32 extClkId = 0;
5456 + u32 tmpIndex;
5457 + u32 clkIdIndex = MBX_PM_MAX_RESOURCES;
5459 + DBG_Trace(DBG_ENTER, "Entering WMD_BRD_Start:\n hDevContext: 0x%x\n\t "
5460 + "dwDSPAddr: 0x%x\n", hDevContext, dwDSPAddr);
5462 + /* The device context contains all the mmu setup info from when the
5463 + * last dsp base image was loaded. The first entry is always
5464 + * SHMMEM base. */
5465 + /* Get SHM_BEG - convert to byte address */
5466 + (void) DEV_GetSymbol(pDevContext->hDevObject, SHMBASENAME,
5467 + &ulShmBaseVirt);
5468 + ulShmBaseVirt *= DSPWORDSIZE;
5469 + DBC_Assert(ulShmBaseVirt != 0);
5470 + /* DSP Virtual address */
5471 + ulTLBBaseVirt = pDevContext->aTLBEntry[0].ulDspVa;
5472 + DBC_Assert(ulTLBBaseVirt <= ulShmBaseVirt);
5473 + ulShmOffsetVirt = ulShmBaseVirt - (ulTLBBaseVirt * DSPWORDSIZE);
5474 + /* Kernel logical address */
5475 + ulShmBase = pDevContext->aTLBEntry[0].ulGppVa + ulShmOffsetVirt;
5477 + DBC_Assert(ulShmBase != 0);
5478 + /* 2nd wd is used as sync field */
5479 + dwSyncAddr = ulShmBase + SHMSYNCOFFSET;
5480 + /* Write a signature into the SHM base + offset; this will
5481 + * get cleared when the DSP program starts. */
5482 + if ((ulShmBaseVirt == 0) || (ulShmBase == 0)) {
5483 + DBG_Trace(DBG_LEVEL6, "WMD_BRD_Start: Illegal SM base\n");
5484 + status = DSP_EFAIL;
5485 + } else
5486 + *((volatile u32 *)dwSyncAddr) = 0xffffffff;
5488 + if (DSP_SUCCEEDED(status)) {
5489 + status = CFG_GetHostResources(
5490 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(),
5491 + &resources);
5492 + /* Assert RST1 i.e only the RST only for DSP megacell */
5493 + /* HW_RST_Reset(resources.dwPrcmBase, HW_RST1_IVA2);*/
5494 + if (DSP_SUCCEEDED(status)) {
5495 + HW_RST_Reset(resources.dwPrmBase, HW_RST1_IVA2);
5496 + if (dsp_debug) {
5497 + /* Set the bootmode to self loop */
5498 + DBG_Trace(DBG_LEVEL7,
5499 + "Set boot mode to self loop"
5500 + " for IVA2 Device\n");
5501 + HW_DSPSS_BootModeSet(resources.dwSysCtrlBase,
5502 + HW_DSPSYSC_SELFLOOPBOOT, dwDSPAddr);
5503 + } else {
5504 + /* Set the bootmode to '0' - direct boot */
5505 + DBG_Trace(DBG_LEVEL7,
5506 + "Set boot mode to direct"
5507 + " boot for IVA2 Device \n");
5508 + HW_DSPSS_BootModeSet(resources.dwSysCtrlBase,
5509 + HW_DSPSYSC_DIRECTBOOT, dwDSPAddr);
5513 + if (DSP_SUCCEEDED(status)) {
5514 + /* Reset and Unreset the RST2, so that BOOTADDR is copied to
5515 + * IVA2 SYSC register */
5516 + HW_RST_Reset(resources.dwPrmBase, HW_RST2_IVA2);
5517 + UTIL_Wait(100);
5518 + HW_RST_UnReset(resources.dwPrmBase, HW_RST2_IVA2);
5519 + UTIL_Wait(100);
5520 + DBG_Trace(DBG_LEVEL6, "WMD_BRD_Start 0 ****** \n");
5521 + GetHWRegs(resources.dwPrmBase, resources.dwCmBase);
5522 + /* Disbale the DSP MMU */
5523 + HW_MMU_Disable(resources.dwDmmuBase);
5524 + /* Disable TWL */
5525 + HW_MMU_TWLDisable(resources.dwDmmuBase);
5527 + /* Only make TLB entry if both addresses are non-zero */
5528 + for (iEntryNdx = 0; iEntryNdx < WMDIOCTL_NUMOFMMUTLB;
5529 + iEntryNdx++) {
5530 + if ((pDevContext->aTLBEntry[iEntryNdx].ulGppPa != 0) &&
5531 + (pDevContext->aTLBEntry[iEntryNdx].ulDspVa != 0)) {
5532 + DBG_Trace(DBG_LEVEL4, "** (proc) MMU %d GppPa:"
5533 + " 0x%x DspVa 0x%x Size 0x%x\n",
5534 + itmpEntryNdx,
5535 + pDevContext->aTLBEntry[iEntryNdx].ulGppPa,
5536 + pDevContext->aTLBEntry[iEntryNdx].ulDspVa,
5537 + pDevContext->aTLBEntry[iEntryNdx].ulSize);
5538 + configureDspMmu(pDevContext,
5539 + pDevContext->aTLBEntry[iEntryNdx].ulGppPa,
5540 + pDevContext->aTLBEntry[iEntryNdx].ulDspVa *
5541 + DSPWORDSIZE,
5542 + pDevContext->aTLBEntry[iEntryNdx].ulSize,
5543 + itmpEntryNdx,
5544 + pDevContext->aTLBEntry[iEntryNdx].endianism,
5545 + pDevContext->aTLBEntry[iEntryNdx].elemSize,
5546 + pDevContext->aTLBEntry[iEntryNdx].
5547 + mixedMode);
5548 + itmpEntryNdx++;
5550 + } /* end for */
5553 + /* Lock the above TLB entries and get the BIOS and load monitor timer
5554 + * information*/
5555 + if (DSP_SUCCEEDED(status)) {
5556 + HW_MMU_NumLockedSet(resources.dwDmmuBase, itmpEntryNdx);
5557 + HW_MMU_VictimNumSet(resources.dwDmmuBase, itmpEntryNdx);
5558 + HW_MMU_TTBSet(resources.dwDmmuBase,
5559 + pDevContext->pPtAttrs->L1BasePa);
5560 + HW_MMU_TWLEnable(resources.dwDmmuBase);
5561 + /* Enable the SmartIdle and AutoIdle bit for MMU_SYSCONFIG */
5563 + temp = (u32) *((REG_UWORD32 *)
5564 + ((u32) (resources.dwDmmuBase) + 0x10));
5565 + temp = (temp & 0xFFFFFFEF) | 0x11;
5566 + *((REG_UWORD32 *) ((u32) (resources.dwDmmuBase) + 0x10)) =
5567 + (u32) temp;
5569 + /* Let the DSP MMU run */
5570 + HW_MMU_Enable(resources.dwDmmuBase);
5572 + /* Enable the BIOS clock */
5573 + (void)DEV_GetSymbol(pDevContext->hDevObject,
5574 + BRIDGEINIT_BIOSGPTIMER,
5575 + &ulBiosGpTimer);
5576 + DBG_Trace(DBG_LEVEL7, "BIOS GPTimer : 0x%x\n", ulBiosGpTimer);
5577 + (void)DEV_GetSymbol(pDevContext->hDevObject,
5578 + BRIDGEINIT_LOADMON_GPTIMER,
5579 + &ulLoadMonitorTimer);
5580 + DBG_Trace(DBG_LEVEL7, "Load Monitor Timer : 0x%x\n",
5581 + ulLoadMonitorTimer);
5584 + if (DSP_SUCCEEDED(status)) {
5585 + if (ulLoadMonitorTimer != 0xFFFF) {
5586 + uClkCmd = (BPWR_DisableClock << MBX_PM_CLK_CMDSHIFT) |
5587 + ulLoadMonitorTimer;
5588 + DBG_Trace(DBG_LEVEL7,
5589 + "encoded LoadMonitor cmd for Disable: 0x%x\n",
5590 + uClkCmd);
5591 + DSPPeripheralClkCtrl(pDevContext, &uClkCmd);
5593 + extClkId = uClkCmd & MBX_PM_CLK_IDMASK;
5594 + for (tmpIndex = 0; tmpIndex < MBX_PM_MAX_RESOURCES;
5595 + tmpIndex++) {
5596 + if (extClkId == BPWR_CLKID[tmpIndex]) {
5597 + clkIdIndex = tmpIndex;
5598 + break;
5602 + if (clkIdIndex < MBX_PM_MAX_RESOURCES)
5603 + status = CLK_Set_32KHz(
5604 + BPWR_Clks[clkIdIndex].funClk);
5605 + else
5606 + status = DSP_EFAIL;
5608 + if (DSP_FAILED(status)) {
5609 + DBG_Trace(DBG_LEVEL7, " Error while setting"
5610 + "LM Timer to 32KHz\n");
5612 + uClkCmd = (BPWR_EnableClock << MBX_PM_CLK_CMDSHIFT) |
5613 + ulLoadMonitorTimer;
5614 + DBG_Trace(DBG_LEVEL7,
5615 + "encoded LoadMonitor cmd for Enable : 0x%x\n",
5616 + uClkCmd);
5617 + DSPPeripheralClkCtrl(pDevContext, &uClkCmd);
5619 + } else {
5620 + DBG_Trace(DBG_LEVEL7,
5621 + "Not able to get the symbol for Load "
5622 + "Monitor Timer\n");
5626 + if (DSP_SUCCEEDED(status)) {
5627 + if (ulBiosGpTimer != 0xFFFF) {
5628 + uClkCmd = (BPWR_DisableClock << MBX_PM_CLK_CMDSHIFT) |
5629 + ulBiosGpTimer;
5630 + DBG_Trace(DBG_LEVEL7, "encoded BIOS GPTimer cmd for"
5631 + "Disable: 0x%x\n", uClkCmd);
5632 + DSPPeripheralClkCtrl(pDevContext, &uClkCmd);
5634 + extClkId = uClkCmd & MBX_PM_CLK_IDMASK;
5636 + for (tmpIndex = 0; tmpIndex < MBX_PM_MAX_RESOURCES;
5637 + tmpIndex++) {
5638 + if (extClkId == BPWR_CLKID[tmpIndex]) {
5639 + clkIdIndex = tmpIndex;
5640 + break;
5644 + if (clkIdIndex < MBX_PM_MAX_RESOURCES)
5645 + status = CLK_Set_32KHz(
5646 + BPWR_Clks[clkIdIndex].funClk);
5647 + else
5648 + status = DSP_EFAIL;
5650 + if (DSP_FAILED(status)) {
5651 + DBG_Trace(DBG_LEVEL7,
5652 + " Error while setting BIOS Timer to 32KHz\n");
5655 + uClkCmd = (BPWR_EnableClock << MBX_PM_CLK_CMDSHIFT) |
5656 + ulBiosGpTimer;
5657 + DBG_Trace(DBG_LEVEL7, "encoded BIOS GPTimer cmd :"
5658 + "0x%x\n", uClkCmd);
5659 + DSPPeripheralClkCtrl(pDevContext, &uClkCmd);
5661 + } else {
5662 + DBG_Trace(DBG_LEVEL7,
5663 + "Not able to get the symbol for BIOS Timer\n");
5667 + if (DSP_SUCCEEDED(status)) {
5668 + /* Set the DSP clock rate */
5669 + (void)DEV_GetSymbol(pDevContext->hDevObject,
5670 + "_BRIDGEINIT_DSP_FREQ", &ulDspClkAddr);
5671 + DBG_Trace(DBG_LEVEL5, "WMD_BRD_Start: _BRIDGE_DSP_FREQ Addr:"
5672 + "0x%x \n", ulDspClkAddr);
5673 + if ((unsigned int *)ulDspClkAddr != NULL) {
5674 + /* Get the clock rate */
5675 + status = CLK_GetRate(SERVICESCLK_iva2_ck,
5676 + &ulDspClkRate);
5677 + DBG_Trace(DBG_LEVEL5,
5678 + "WMD_BRD_Start: DSP clock rate (KHZ): 0x%x \n",
5679 + ulDspClkRate);
5680 + (void)WMD_BRD_Write(pDevContext, (u8 *)&ulDspClkRate,
5681 + ulDspClkAddr, sizeof(u32), 0);
5683 + /* Enable Mailbox events and also drain any pending
5684 + * stale messages */
5685 + (void)CHNLSM_EnableInterrupt(pDevContext);
5688 + if (DSP_SUCCEEDED(status)) {
5689 + HW_RSTCTRL_RegGet(resources.dwPrmBase, HW_RST1_IVA2, &temp);
5690 + DBG_Trace(DBG_LEVEL7, "BRD_Start: RM_RSTCTRL_DSP = 0x%x \n",
5691 + temp);
5692 + HW_RSTST_RegGet(resources.dwPrmBase, HW_RST1_IVA2, &temp);
5693 + DBG_Trace(DBG_LEVEL7, "BRD_Start0: RM_RSTST_DSP = 0x%x \n",
5694 + temp);
5696 + /* Let DSP go */
5697 + DBG_Trace(DBG_LEVEL7, "Unreset, WMD_BRD_Start\n");
5698 + /* Enable DSP MMU Interrupts */
5699 + HW_MMU_EventEnable(resources.dwDmmuBase,
5700 + HW_MMU_ALL_INTERRUPTS);
5701 + /* release the RST1, DSP starts executing now .. */
5702 + HW_RST_UnReset(resources.dwPrmBase, HW_RST1_IVA2);
5704 + HW_RSTST_RegGet(resources.dwPrmBase, HW_RST1_IVA2, &temp);
5705 + DBG_Trace(DBG_LEVEL7, "BRD_Start: RM_RSTST_DSP = 0x%x \n",
5706 + temp);
5707 + HW_RSTCTRL_RegGet(resources.dwPrmBase, HW_RST1_IVA2, &temp);
5708 + DBG_Trace(DBG_LEVEL5, "WMD_BRD_Start: CM_RSTCTRL_DSP: 0x%x \n",
5709 + temp);
5710 + DBG_Trace(DBG_LEVEL7, "Driver waiting for Sync @ 0x%x \n",
5711 + dwSyncAddr);
5712 + DBG_Trace(DBG_LEVEL7, "DSP c_int00 Address = 0x%x \n",
5713 + dwDSPAddr);
5714 + if (dsp_debug)
5715 + while (*((volatile u16 *)dwSyncAddr))
5716 + ;;
5719 + if (DSP_SUCCEEDED(status)) {
5720 + /* Wait for DSP to clear word in shared memory */
5721 + /* Read the Location */
5722 + if (!WaitForStart(pDevContext, dwSyncAddr)) {
5723 + status = WMD_E_TIMEOUT;
5724 + DBG_Trace(DBG_LEVEL7,
5725 + "WMD_BRD_Start Failed to Synchronize\n");
5727 + status = DEV_GetIOMgr(pDevContext->hDevObject, &hIOMgr);
5728 + if (DSP_SUCCEEDED(status)) {
5729 + IO_SHMsetting(hIOMgr, SHM_OPPINFO, NULL);
5730 + DBG_Trace(DBG_LEVEL7,
5731 + "WMD_BRD_Start: OPP information initialzed\n");
5732 + /* Write the synchronization bit to indicate the
5733 + * completion of OPP table update to DSP
5734 + */
5735 + *((volatile u32 *)dwSyncAddr) = 0XCAFECAFE;
5737 + if (DSP_SUCCEEDED(status)) {
5738 + /* update board state */
5739 + pDevContext->dwBrdState = BRD_RUNNING;
5740 + /* (void)CHNLSM_EnableInterrupt(pDevContext);*/
5741 + DBG_Trace(DBG_LEVEL7, "Device Started \n ");
5742 + } else {
5743 + pDevContext->dwBrdState = BRD_UNKNOWN;
5744 + DBG_Trace(DBG_LEVEL7, "Device not Started \n ");
5747 + return status;
5751 + * ======== WMD_BRD_Stop ========
5752 + * purpose:
5753 + * Puts DSP in self loop.
5755 + * Preconditions :
5756 + * a) None
5757 + */
5758 +static DSP_STATUS WMD_BRD_Stop(struct WMD_DEV_CONTEXT *hDevContext)
5760 + DSP_STATUS status = DSP_SOK;
5761 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
5762 + struct CFG_HOSTRES resources;
5763 + struct PgTableAttrs *pPtAttrs;
5764 + u32 dspPwrState;
5765 + enum HW_PwrState_t pwrState;
5766 + DSP_STATUS clk_status;
5768 + DBG_Trace(DBG_ENTER, "Entering WMD_BRD_Stop:\nhDevContext: 0x%x\n",
5769 + hDevContext);
5771 + /* Disable the mail box interrupts */
5772 + (void)CHNLSM_DisableInterrupt(pDevContext);
5774 + if (pDevContext->dwBrdState == BRD_STOPPED)
5775 + return status;
5777 + /* as per TRM, it is advised to first drive the IVA2 to 'Standby' mode,
5778 + * before turning off the clocks.. This is to ensure that there are no
5779 + * pending L3 or other transactons from IVA2 */
5780 + status = CFG_GetHostResources(
5781 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(),
5782 + &resources);
5783 + if (DSP_FAILED(status)) {
5784 + DBG_Trace(DBG_LEVEL7,
5785 + "WMD_BRD_Stop: Get Host resources failed \n");
5786 + DBG_Trace(DBG_LEVEL1, "Device Stopp failed \n ");
5787 + return DSP_EFAIL;
5790 + HW_PWRST_IVA2RegGet(resources.dwPrmBase, &dspPwrState);
5791 + if (dspPwrState != HW_PWR_STATE_OFF) {
5793 + IO_InterruptDSP2(pDevContext, MBX_PM_DSPIDLE);
5795 + UTIL_Wait(10000); /* 10 msec */
5797 + GetHWRegs(resources.dwPrmBase, resources.dwCmBase);
5799 + run_IdleBoot(resources.dwPrmBase, resources.dwCmBase,
5800 + resources.dwSysCtrlBase);
5802 + udelay(50);
5804 + clk_status = CLK_Disable(SERVICESCLK_iva2_ck);
5805 + if (DSP_FAILED(clk_status)) {
5806 + DBG_Trace(DBG_LEVEL6,
5807 + "\n WMD_BRD_Stop: CLK_Disable failed "
5808 + "for iva2_fck\n");
5810 + /* IVA2 is not in OFF state */
5811 + /* Read and set PM_PWSTCTRL_IVA2 to OFF */
5812 + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP,
5813 + &pwrState);
5814 + HW_PWR_IVA2PowerStateSet(resources.dwPrmBase,
5815 + HW_PWR_DOMAIN_DSP,
5816 + HW_PWR_STATE_OFF);
5817 + /* Set the SW supervised state transition for Sleep */
5818 + HW_PWR_CLKCTRL_IVA2RegSet(resources.dwCmBase,
5819 + HW_SW_SUP_SLEEP);
5820 + } else {
5821 + clk_status = CLK_Disable(SERVICESCLK_iva2_ck);
5822 + if (DSP_FAILED(clk_status)) {
5823 + DBG_Trace(DBG_LEVEL6,
5824 + "\n WMD_BRD_Stop: Else loop CLK_Disable failed"
5825 + " for iva2_fck\n");
5828 + udelay(10);
5829 + /* Release the Ext Base virtual Address as the next DSP Program
5830 + * may have a different load address */
5831 + if (pDevContext->dwDspExtBaseAddr)
5832 + pDevContext->dwDspExtBaseAddr = 0;
5834 + pDevContext->dwBrdState = BRD_STOPPED; /* update board state */
5835 + DBG_Trace(DBG_LEVEL1, "Device Stopped \n ");
5836 + /* This is a good place to clear the MMU page tables as well */
5837 + if (pDevContext->pPtAttrs) {
5838 + pPtAttrs = pDevContext->pPtAttrs;
5839 + memset((u8 *) pPtAttrs->L1BaseVa, 0x00, pPtAttrs->L1size);
5840 + memset((u8 *) pPtAttrs->L2BaseVa, 0x00, pPtAttrs->L2size);
5841 + memset((u8 *) pPtAttrs->pgInfo, 0x00,
5842 + (pPtAttrs->L2NumPages * sizeof(struct PageInfo)));
5845 + DBG_Trace(DBG_LEVEL6, "WMD_BRD_Stop - End ****** \n");
5847 + return status;
5852 + * ======== WMD_BRD_Delete ========
5853 + * purpose:
5854 + * Puts DSP in Low power mode
5856 + * Preconditions :
5857 + * a) None
5858 + */
5859 +static DSP_STATUS WMD_BRD_Delete(struct WMD_DEV_CONTEXT *hDevContext)
5861 + DSP_STATUS status = DSP_SOK;
5862 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
5863 + struct CFG_HOSTRES resources;
5864 + struct PgTableAttrs *pPtAttrs;
5865 + DSP_STATUS clk_status;
5867 + DBG_Trace(DBG_ENTER, "Entering WMD_BRD_Delete:\nhDevContext: 0x%x\n",
5868 + hDevContext);
5870 + /* Disable the mail box interrupts */
5871 + (void) CHNLSM_DisableInterrupt(pDevContext);
5873 + if (pDevContext->dwBrdState == BRD_STOPPED)
5874 + return status;
5876 + /* as per TRM, it is advised to first drive
5877 + * the IVA2 to 'Standby' mode, before turning off the clocks.. This is
5878 + * to ensure that there are no pending L3 or other transactons from
5879 + * IVA2 */
5880 + status = CFG_GetHostResources(
5881 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources);
5882 + if (DSP_FAILED(status)) {
5883 + DBG_Trace(DBG_LEVEL7,
5884 + "WMD_BRD_Stop: Get Host resources failed \n");
5885 + DBG_Trace(DBG_LEVEL1, "Device Delete failed \n ");
5886 + return DSP_EFAIL;
5888 + status = SleepDSP(pDevContext, PWR_EMERGENCYDEEPSLEEP, NULL);
5889 + clk_status = CLK_Disable(SERVICESCLK_iva2_ck);
5890 + if (DSP_FAILED(clk_status)) {
5891 + DBG_Trace(DBG_LEVEL6, "\n WMD_BRD_Stop: CLK_Disable failed for"
5892 + " iva2_fck\n");
5894 + /* Release the Ext Base virtual Address as the next DSP Program
5895 + * may have a different load address */
5896 + if (pDevContext->dwDspExtBaseAddr)
5897 + pDevContext->dwDspExtBaseAddr = 0;
5899 + pDevContext->dwBrdState = BRD_STOPPED; /* update board state */
5900 + DBG_Trace(DBG_LEVEL1, "Device Stopped \n ");
5901 + /* This is a good place to clear the MMU page tables as well */
5902 + if (pDevContext->pPtAttrs) {
5903 + pPtAttrs = pDevContext->pPtAttrs;
5904 + memset((u8 *)pPtAttrs->L1BaseVa, 0x00, pPtAttrs->L1size);
5905 + memset((u8 *)pPtAttrs->L2BaseVa, 0x00, pPtAttrs->L2size);
5906 + memset((u8 *)pPtAttrs->pgInfo, 0x00,
5907 + (pPtAttrs->L2NumPages * sizeof(struct PageInfo)));
5909 + DBG_Trace(DBG_LEVEL6, "WMD_BRD_Stop - End ****** \n");
5910 + return status;
5915 + * ======== WMD_BRD_Status ========
5916 + * Returns the board status.
5917 + */
5918 +static DSP_STATUS WMD_BRD_Status(struct WMD_DEV_CONTEXT *hDevContext,
5919 + OUT BRD_STATUS *pdwState)
5921 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
5922 + *pdwState = pDevContext->dwBrdState;
5923 + return DSP_SOK;
5927 + * ======== WMD_BRD_Write ========
5928 + * Copies the buffers to DSP internal or external memory.
5929 + */
5930 +static DSP_STATUS WMD_BRD_Write(struct WMD_DEV_CONTEXT *hDevContext,
5931 + IN u8 *pbHostBuf, u32 dwDSPAddr,
5932 + u32 ulNumBytes, u32 ulMemType)
5934 + DSP_STATUS status = DSP_SOK;
5935 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
5937 + DBG_Trace(DBG_ENTER, "WMD_BRD_Write, pDevContext: 0x%x\n\t\t "
5938 + "pbHostBuf: 0x%x\n\t\tdwDSPAddr: 0x%x\n\t\tulNumBytes: "
5939 + "0x%x\n \t\t ulMemtype: 0x%x\n", pDevContext, pbHostBuf,
5940 + dwDSPAddr, ulNumBytes, ulMemType);
5941 + if (dwDSPAddr < pDevContext->dwDSPStartAdd) {
5942 + DBG_Trace(DBG_LEVEL7,
5943 + "WMD_BRD_Write: DSP address < start address \n ");
5944 + status = DSP_EFAIL;
5945 + return status;
5947 + if ((dwDSPAddr - pDevContext->dwDSPStartAdd) <
5948 + pDevContext->dwInternalSize) {
5949 + status = WriteDspData(hDevContext, pbHostBuf, dwDSPAddr,
5950 + ulNumBytes, ulMemType);
5951 + } else {
5952 + status = WriteExtDspData(pDevContext, pbHostBuf, dwDSPAddr,
5953 + ulNumBytes, ulMemType, false);
5956 + DBG_Trace(DBG_ENTER, "WMD_BRD_Write, memcopy : DspLogicAddr=0x%x \n",
5957 + pDevContext->dwDspBaseAddr);
5958 + return status;
5962 + * ======== WMD_DEV_Create ========
5963 + * Creates a driver object. Puts DSP in self loop.
5964 + */
5965 +static DSP_STATUS WMD_DEV_Create(OUT struct WMD_DEV_CONTEXT **ppDevContext,
5966 + struct DEV_OBJECT *hDevObject,
5967 + IN CONST struct CFG_HOSTRES *pConfig,
5968 + IN CONST struct CFG_DSPRES *pDspConfig)
5970 + DSP_STATUS status = DSP_SOK;
5971 + struct WMD_DEV_CONTEXT *pDevContext = NULL;
5972 + s32 iEntryNdx;
5973 + s32 tcWordSwap;
5974 + u32 tcWordSwapSize = sizeof(tcWordSwap);
5975 + struct CFG_HOSTRES resources;
5976 + struct PgTableAttrs *pPtAttrs;
5977 + u32 pg_tbl_pa;
5978 + u32 pg_tbl_va;
5979 + u32 align_size;
5981 + DBG_Trace(DBG_ENTER, "WMD_DEV_Create, ppDevContext: 0x%x\n\t\t "
5982 + "hDevObject: 0x%x\n\t\tpConfig: 0x%x\n\t\tpDspConfig: 0x%x\n",
5983 + ppDevContext, hDevObject, pConfig, pDspConfig);
5984 + /* Allocate and initialize a data structure to contain the mini driver
5985 + * state, which becomes the context for later calls into this WMD. */
5986 + pDevContext = MEM_Calloc(sizeof(struct WMD_DEV_CONTEXT), MEM_NONPAGED);
5987 + if (!pDevContext) {
5988 + DBG_Trace(DBG_ENTER, "Failed to allocate mem \n");
5989 + status = DSP_EMEMORY;
5990 + goto func_end;
5992 + status = CFG_GetHostResources(
5993 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources);
5994 + if (DSP_FAILED(status)) {
5995 + DBG_Trace(DBG_ENTER, "Failed to get host resources \n");
5996 + status = DSP_EMEMORY;
5997 + goto func_end;
6000 + pDevContext->dwDSPStartAdd = (u32)OMAP_GEM_BASE;
6001 + pDevContext->dwSelfLoop = (u32)NULL;
6002 + pDevContext->uDspPerClks = 0;
6003 + pDevContext->dwInternalSize = OMAP_DSP_SIZE;
6004 + /* Clear dev context MMU table entries.
6005 + * These get set on WMD_BRD_IOCTL() call after program loaded. */
6006 + for (iEntryNdx = 0; iEntryNdx < WMDIOCTL_NUMOFMMUTLB; iEntryNdx++) {
6007 + pDevContext->aTLBEntry[iEntryNdx].ulGppPa =
6008 + pDevContext->aTLBEntry[iEntryNdx].ulDspVa = 0;
6010 + pDevContext->numTLBEntries = 0;
6011 + pDevContext->dwDspBaseAddr = (u32)MEM_LinearAddress((void *)
6012 + (pConfig->dwMemBase[3]), pConfig->dwMemLength[3]);
6013 + if (!pDevContext->dwDspBaseAddr) {
6014 + status = DSP_EFAIL;
6015 + DBG_Trace(DBG_LEVEL7,
6016 + "WMD_DEV_Create: failed to Map the API memory\n");
6018 + pPtAttrs = MEM_Calloc(sizeof(struct PgTableAttrs), MEM_NONPAGED);
6019 + if (pPtAttrs != NULL) {
6020 + /* Assuming that we use only DSP's memory map
6021 + * until 0x4000:0000 , we would need only 1024
6022 + * L1 enties i.e L1 size = 4K */
6023 + pPtAttrs->L1size = 0x1000;
6024 + align_size = pPtAttrs->L1size;
6025 + /* Align sizes are expected to be power of 2 */
6026 + /* we like to get aligned on L1 table size */
6027 + pg_tbl_va = (u32)MEM_AllocPhysMem(pPtAttrs->L1size,
6028 + align_size, &pg_tbl_pa);
6029 + /* Check if the PA is aligned for us */
6030 + if ((pg_tbl_pa) & (align_size-1)) {
6031 + /* PA not aligned to page table size ,
6032 + * try with more allocation and align */
6033 + MEM_FreePhysMem((void *)pg_tbl_va, pg_tbl_pa, pPtAttrs->L1size);
6034 + /* we like to get aligned on L1 table size */
6035 + pg_tbl_va = (u32) MEM_AllocPhysMem((pPtAttrs->L1size)*2,
6036 + align_size, &pg_tbl_pa);
6037 + /* We should be able to get aligned table now */
6038 + pPtAttrs->L1TblAllocPa = pg_tbl_pa;
6039 + pPtAttrs->L1TblAllocVa = pg_tbl_va;
6040 + pPtAttrs->L1TblAllocSz = pPtAttrs->L1size * 2;
6041 + /* Align the PA to the next 'align' boundary */
6042 + pPtAttrs->L1BasePa = ((pg_tbl_pa) + (align_size-1)) &
6043 + (~(align_size-1));
6044 + pPtAttrs->L1BaseVa = pg_tbl_va + (pPtAttrs->L1BasePa -
6045 + pg_tbl_pa);
6046 + } else {
6047 + /* We got aligned PA, cool */
6048 + pPtAttrs->L1TblAllocPa = pg_tbl_pa;
6049 + pPtAttrs->L1TblAllocVa = pg_tbl_va;
6050 + pPtAttrs->L1TblAllocSz = pPtAttrs->L1size;
6051 + pPtAttrs->L1BasePa = pg_tbl_pa;
6052 + pPtAttrs->L1BaseVa = pg_tbl_va;
6054 + if (pPtAttrs->L1BaseVa) {
6055 + memset((u8 *)pPtAttrs->L1BaseVa, 0x00,
6056 + pPtAttrs->L1size);
6058 + /* number of L2 page tables = DMM pool used + SHMMEM +EXTMEM +
6059 + * L4 pages */
6060 + pPtAttrs->L2NumPages = ((DMMPOOLSIZE >> 20) + 6);
6061 + pPtAttrs->L2size = HW_MMU_COARSE_PAGE_SIZE *
6062 + pPtAttrs->L2NumPages;
6063 + align_size = 4; /* Make it u32 aligned */
6064 + /* we like to get aligned on L1 table size */
6065 + pg_tbl_va = (u32)MEM_AllocPhysMem(pPtAttrs->L2size,
6066 + align_size, &pg_tbl_pa);
6067 + pPtAttrs->L2TblAllocPa = pg_tbl_pa;
6068 + pPtAttrs->L2TblAllocVa = pg_tbl_va;
6069 + pPtAttrs->L2TblAllocSz = pPtAttrs->L2size;
6070 + pPtAttrs->L2BasePa = pg_tbl_pa;
6071 + pPtAttrs->L2BaseVa = pg_tbl_va;
6072 + if (pPtAttrs->L2BaseVa) {
6073 + memset((u8 *)pPtAttrs->L2BaseVa, 0x00,
6074 + pPtAttrs->L2size);
6076 + pPtAttrs->pgInfo = MEM_Calloc(pPtAttrs->L2NumPages *
6077 + sizeof(struct PageInfo), MEM_NONPAGED);
6078 + DBG_Trace(DBG_LEVEL1, "L1 pa %x, va %x, size %x\n L2 pa %x, va "
6079 + "%x, size %x\n", pPtAttrs->L1BasePa,
6080 + pPtAttrs->L1BaseVa, pPtAttrs->L1size,
6081 + pPtAttrs->L2BasePa, pPtAttrs->L2BaseVa,
6082 + pPtAttrs->L2size);
6083 + DBG_Trace(DBG_LEVEL1, "pPtAttrs %x L2 NumPages %x pgInfo %x\n",
6084 + pPtAttrs, pPtAttrs->L2NumPages, pPtAttrs->pgInfo);
6086 + if ((pPtAttrs != NULL) && (pPtAttrs->L1BaseVa != 0) &&
6087 + (pPtAttrs->L2BaseVa != 0) && (pPtAttrs->pgInfo != NULL))
6088 + pDevContext->pPtAttrs = pPtAttrs;
6089 + else
6090 + status = DSP_EMEMORY;
6092 + if (DSP_SUCCEEDED(status))
6093 + status = SYNC_InitializeCS(&pPtAttrs->hCSObj);
6095 + if (DSP_SUCCEEDED(status)) {
6096 + /* Set the Endianism Register */ /* Need to set this */
6097 + /* default to Proc-copy */
6098 + pDevContext->wIntrVal2Dsp = MBX_PCPY_CLASS;
6099 + /* Retrieve the TC u16 SWAP Option */
6100 + status = REG_GetValue(NULL, CURRENTCONFIG, TCWORDSWAP,
6101 + (u8 *)&tcWordSwap, &tcWordSwapSize);
6102 + /* Save the value */
6103 + pDevContext->tcWordSwapOn = tcWordSwap;
6105 + if (DSP_SUCCEEDED(status)) {
6106 + /* Set the Clock Divisor for the DSP module */
6107 + DBG_Trace(DBG_LEVEL7, "WMD_DEV_create:Reset mail box and "
6108 + "enable the clock \n");
6109 + status = CLK_Enable(SERVICESCLK_mailbox_ick);
6110 + if (DSP_FAILED(status)) {
6111 + DBG_Trace(DBG_LEVEL7,
6112 + "WMD_DEV_create:Reset mail box and "
6113 + "enable the clock Fail\n");
6115 + UTIL_Wait(5);
6116 + /* 24xx-Linux MMU address is obtained from the host
6117 + * resources struct */
6118 + pDevContext->dwDSPMmuBase = resources.dwDmmuBase;
6120 + if (DSP_SUCCEEDED(status)) {
6121 + pDevContext->hDevObject = hDevObject;
6122 + pDevContext->ulIntMask = 0;
6123 + /* Store current board state. */
6124 + pDevContext->dwBrdState = BRD_STOPPED;
6125 + /* Return this ptr to our device state to the WCD for storage:*/
6126 + *ppDevContext = pDevContext;
6127 + DBG_Trace(DBG_ENTER, "Device Created \n");
6128 + } else {
6129 + if (pPtAttrs != NULL) {
6130 + if (pPtAttrs->hCSObj)
6131 + SYNC_DeleteCS(pPtAttrs->hCSObj);
6133 + if (pPtAttrs->pgInfo)
6134 + MEM_Free(pPtAttrs->pgInfo);
6136 + if (pPtAttrs->L2TblAllocVa) {
6137 + MEM_FreePhysMem((void *)pPtAttrs->L2TblAllocVa,
6138 + pPtAttrs->L2TblAllocPa,
6139 + pPtAttrs->L2TblAllocSz);
6141 + if (pPtAttrs->L1TblAllocVa) {
6142 + MEM_FreePhysMem((void *)pPtAttrs->L1TblAllocVa,
6143 + pPtAttrs->L1TblAllocPa,
6144 + pPtAttrs->L1TblAllocSz);
6147 + if (pPtAttrs)
6148 + MEM_Free(pPtAttrs);
6150 + if (pDevContext)
6151 + MEM_Free(pDevContext);
6153 + DBG_Trace(DBG_LEVEL7,
6154 + "WMD_DEV_Create Error Device not created\n");
6156 +func_end:
6157 + return status;
6161 + * ======== WMD_DEV_Ctrl ========
6162 + * Receives device specific commands.
6163 + */
6164 +static DSP_STATUS WMD_DEV_Ctrl(struct WMD_DEV_CONTEXT *pDevContext, u32 dwCmd,
6165 + IN OUT void *pArgs)
6167 + DSP_STATUS status = DSP_SOK;
6168 + struct WMDIOCTL_EXTPROC *paExtProc = (struct WMDIOCTL_EXTPROC *)pArgs;
6169 + s32 ndx;
6171 + DBG_Trace(DBG_ENTER, "WMD_DEV_Ctrl, pDevContext: 0x%x\n\t\t dwCmd: "
6172 + "0x%x\n\t\tpArgs: 0x%x\n", pDevContext, dwCmd, pArgs);
6173 + switch (dwCmd) {
6174 + case WMDIOCTL_CHNLREAD:
6175 + break;
6176 + case WMDIOCTL_CHNLWRITE:
6177 + break;
6178 + case WMDIOCTL_SETMMUCONFIG:
6179 + /* store away dsp-mmu setup values for later use */
6180 + for (ndx = 0; ndx < WMDIOCTL_NUMOFMMUTLB; ndx++, paExtProc++)
6181 + pDevContext->aTLBEntry[ndx] = *paExtProc;
6183 + break;
6184 + case WMDIOCTL_DEEPSLEEP:
6185 + case WMDIOCTL_EMERGENCYSLEEP:
6186 + /* Currently only DSP Idle is supported Need to update for
6187 + * later releases */
6188 + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_DEEPSLEEP\n");
6189 + status = SleepDSP(pDevContext, PWR_DEEPSLEEP, pArgs);
6190 + break;
6191 + case WMDIOCTL_WAKEUP:
6192 + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_WAKEUP\n");
6193 + status = WakeDSP(pDevContext, pArgs);
6194 + break;
6195 + case WMDIOCTL_CLK_CTRL:
6196 + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_CLK_CTRL\n");
6197 + status = DSP_SOK;
6198 + /* Looking For Baseport Fix for Clocks */
6199 + status = DSPPeripheralClkCtrl(pDevContext, pArgs);
6200 + break;
6201 + case WMDIOCTL_PWR_HIBERNATE:
6202 + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_PWR_HIBERNATE\n");
6203 + status = handle_hibernation_fromDSP(pDevContext);
6204 + break;
6205 +#ifndef CONFIG_DISABLE_BRIDGE_PM
6206 +#ifndef CONFIG_DISABLE_BRIDGE_DVFS
6207 + case WMDIOCTL_PRESCALE_NOTIFY:
6208 + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_PRESCALE_NOTIFY\n");
6209 + status = PreScale_DSP(pDevContext, pArgs);
6210 + break;
6211 + case WMDIOCTL_POSTSCALE_NOTIFY:
6212 + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_POSTSCALE_NOTIFY\n");
6213 + status = PostScale_DSP(pDevContext, pArgs);
6214 + break;
6215 + case WMDIOCTL_CONSTRAINT_REQUEST:
6216 + DBG_Trace(DBG_LEVEL5, "WMDIOCTL_CONSTRAINT_REQUEST\n");
6217 + status = handle_constraints_set(pDevContext, pArgs);
6218 + break;
6219 +#endif
6220 +#endif
6221 + default:
6222 + status = DSP_EFAIL;
6223 + DBG_Trace(DBG_LEVEL7, "Error in WMD_BRD_Ioctl \n");
6224 + break;
6226 + return status;
6230 + * ======== WMD_DEV_Destroy ========
6231 + * Destroys the driver object.
6232 + */
6233 +static DSP_STATUS WMD_DEV_Destroy(struct WMD_DEV_CONTEXT *hDevContext)
6235 + struct PgTableAttrs *pPtAttrs;
6236 + DSP_STATUS status = DSP_SOK;
6237 + struct WMD_DEV_CONTEXT *pDevContext = (struct WMD_DEV_CONTEXT *)
6238 + hDevContext;
6239 + DBG_Trace(DBG_ENTER, "Entering WMD_DEV_Destroy:n hDevContext ::0x%x\n",
6240 + hDevContext);
6241 + /* first put the device to stop state */
6242 + WMD_BRD_Delete(pDevContext);
6243 + if (pDevContext && pDevContext->pPtAttrs) {
6244 + pPtAttrs = pDevContext->pPtAttrs;
6245 + if (pPtAttrs->hCSObj)
6246 + SYNC_DeleteCS(pPtAttrs->hCSObj);
6248 + if (pPtAttrs->pgInfo)
6249 + MEM_Free(pPtAttrs->pgInfo);
6251 + if (pPtAttrs->L2TblAllocVa) {
6252 + MEM_FreePhysMem((void *)pPtAttrs->L2TblAllocVa,
6253 + pPtAttrs->L2TblAllocPa, pPtAttrs->
6254 + L2TblAllocSz);
6256 + if (pPtAttrs->L1TblAllocVa) {
6257 + MEM_FreePhysMem((void *)pPtAttrs->L1TblAllocVa,
6258 + pPtAttrs->L1TblAllocPa, pPtAttrs->
6259 + L1TblAllocSz);
6261 + if (pPtAttrs)
6262 + MEM_Free(pPtAttrs);
6265 + /* Free the driver's device context: */
6266 + MEM_Free((void *) hDevContext);
6267 + return status;
6270 +static DSP_STATUS WMD_BRD_MemCopy(struct WMD_DEV_CONTEXT *hDevContext,
6271 + u32 ulDspDestAddr, u32 ulDspSrcAddr,
6272 + u32 ulNumBytes, u32 ulMemType)
6274 + DSP_STATUS status = DSP_SOK;
6275 + u32 srcAddr = ulDspSrcAddr;
6276 + u32 destAddr = ulDspDestAddr;
6277 + u32 copyBytes = 0;
6278 + u32 totalBytes = ulNumBytes;
6279 + u8 hostBuf[BUFFERSIZE];
6280 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
6281 + while ((totalBytes > 0) && DSP_SUCCEEDED(status)) {
6282 + copyBytes = totalBytes > BUFFERSIZE ? BUFFERSIZE : totalBytes;
6283 + /* Read from External memory */
6284 + status = ReadExtDspData(hDevContext, hostBuf, srcAddr,
6285 + copyBytes, ulMemType);
6286 + if (DSP_SUCCEEDED(status)) {
6287 + if (destAddr < (pDevContext->dwDSPStartAdd +
6288 + pDevContext->dwInternalSize)) {
6289 + /* Write to Internal memory */
6290 + status = WriteDspData(hDevContext, hostBuf,
6291 + destAddr, copyBytes, ulMemType);
6292 + } else {
6293 + /* Write to External memory */
6294 + status = WriteExtDspData(hDevContext, hostBuf,
6295 + destAddr, copyBytes, ulMemType, false);
6298 + totalBytes -= copyBytes;
6299 + srcAddr += copyBytes;
6300 + destAddr += copyBytes;
6302 + return status;
6305 +/* Mem Write does not halt the DSP to write unlike WMD_BRD_Write */
6306 +static DSP_STATUS WMD_BRD_MemWrite(struct WMD_DEV_CONTEXT *hDevContext,
6307 + IN u8 *pbHostBuf, u32 dwDSPAddr,
6308 + u32 ulNumBytes, u32 ulMemType)
6310 + DSP_STATUS status = DSP_SOK;
6311 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
6312 + u32 ulRemainBytes = 0;
6313 + u32 ulBytes = 0;
6314 + ulRemainBytes = ulNumBytes;
6315 + while (ulRemainBytes > 0 && DSP_SUCCEEDED(status)) {
6316 + ulBytes =
6317 + ulRemainBytes > BUFFERSIZE ? BUFFERSIZE : ulRemainBytes;
6318 + if (dwDSPAddr < (pDevContext->dwDSPStartAdd +
6319 + pDevContext->dwInternalSize)) {
6320 + status = WriteDspData(hDevContext, pbHostBuf, dwDSPAddr,
6321 + ulBytes, ulMemType);
6322 + } else {
6323 + status = WriteExtDspData(hDevContext, pbHostBuf,
6324 + dwDSPAddr, ulBytes, ulMemType, true);
6326 + ulRemainBytes -= ulBytes;
6327 + dwDSPAddr += ulBytes;
6328 + pbHostBuf = pbHostBuf + ulBytes;
6330 + return status;
6334 + * ======== WMD_BRD_MemMap ========
6335 + * This function maps MPU buffer to the DSP address space. It performs
6336 + * linear to physical address translation if required. It translates each
6337 + * page since linear addresses can be physically non-contiguous
6338 + * All address & size arguments are assumed to be page aligned (in proc.c)
6340 + * TODO: Disable MMU while updating the page tables (but that'll stall DSP)
6341 + */
6342 +static DSP_STATUS WMD_BRD_MemMap(struct WMD_DEV_CONTEXT *hDevContext,
6343 + u32 ulMpuAddr, u32 ulVirtAddr,
6344 + u32 ulNumBytes, u32 ulMapAttr)
6346 + u32 attrs;
6347 + DSP_STATUS status = DSP_SOK;
6348 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
6349 + struct HW_MMUMapAttrs_t hwAttrs;
6350 + u32 numOfActualTabEntries = 0;
6351 + u32 temp = 0;
6352 + u32 *pPhysAddrPageTbl = NULL;
6353 + struct vm_area_struct *vma;
6354 + struct mm_struct *mm = current->mm;
6356 + DBG_Trace(DBG_ENTER, "> WMD_BRD_MemMap hDevContext %x, pa %x, va %x, "
6357 + "size %x, ulMapAttr %x\n", hDevContext, ulMpuAddr, ulVirtAddr,
6358 + ulNumBytes, ulMapAttr);
6359 + if (ulNumBytes == 0)
6360 + return DSP_EINVALIDARG;
6362 + if (ulMapAttr != 0) {
6363 + attrs = ulMapAttr;
6364 + } else {
6365 + /* Assign default attributes */
6366 + attrs = DSP_MAPVIRTUALADDR | DSP_MAPELEMSIZE16;
6368 + /* Take mapping properties */
6369 + if (attrs & DSP_MAPBIGENDIAN)
6370 + hwAttrs.endianism = HW_BIG_ENDIAN;
6371 + else
6372 + hwAttrs.endianism = HW_LITTLE_ENDIAN;
6374 + hwAttrs.mixedSize = (enum HW_MMUMixedSize_t)
6375 + ((attrs & DSP_MAPMIXEDELEMSIZE) >> 2);
6376 + /* Ignore elementSize if mixedSize is enabled */
6377 + if (hwAttrs.mixedSize == 0) {
6378 + if (attrs & DSP_MAPELEMSIZE8) {
6379 + /* Size is 8 bit */
6380 + hwAttrs.elementSize = HW_ELEM_SIZE_8BIT;
6381 + } else if (attrs & DSP_MAPELEMSIZE16) {
6382 + /* Size is 16 bit */
6383 + hwAttrs.elementSize = HW_ELEM_SIZE_16BIT;
6384 + } else if (attrs & DSP_MAPELEMSIZE32) {
6385 + /* Size is 32 bit */
6386 + hwAttrs.elementSize = HW_ELEM_SIZE_32BIT;
6387 + } else if (attrs & DSP_MAPELEMSIZE64) {
6388 + /* Size is 64 bit */
6389 + hwAttrs.elementSize = HW_ELEM_SIZE_64BIT;
6390 + } else {
6391 + /* Mixedsize isn't enabled, so size can't be
6392 + * zero here */
6393 + DBG_Trace(DBG_LEVEL7,
6394 + "WMD_BRD_MemMap: MMU element size is zero\n");
6395 + return DSP_EINVALIDARG;
6398 + if (attrs & DSP_MAPVMALLOCADDR) {
6399 + status = MemMapVmalloc(hDevContext, ulMpuAddr, ulVirtAddr,
6400 + ulNumBytes, ulMapAttr);
6401 + return status;
6403 + /* Do OS-specific user-va to pa translation.
6404 + * Combine physically contiguous regions to reduce TLBs.
6405 + * Pass the translated pa to PteUpdate. */
6406 + if ((attrs & DSP_MAPPHYSICALADDR)) {
6407 + status = PteUpdate(pDevContext, ulMpuAddr, ulVirtAddr,
6408 + ulNumBytes, &hwAttrs);
6409 + goto func_cont;
6412 + /* Important Note: ulMpuAddr is mapped from user application process
6413 + * to current process - it must lie completely within the current
6414 + * virtual memory address space in order to be of use to us here! */
6415 + down_read(&mm->mmap_sem);
6416 + vma = find_vma(mm, ulMpuAddr);
6417 + up_read(&mm->mmap_sem);
6418 + if (vma)
6419 + DBG_Trace(DBG_LEVEL6, "VMAfor UserBuf: ulMpuAddr=%x, "
6420 + "ulNumBytes=%x, vm_start=%x vm_end=%x vm_flags=%x \n",
6421 + ulMpuAddr, ulNumBytes, vma->vm_start,
6422 + vma->vm_end, vma->vm_flags);
6424 + /* It is observed that under some circumstances, the user buffer is
6425 + * spread across several VMAs. So loop through and check if the entire
6426 + * user buffer is covered */
6427 + while ((vma != NULL) && (ulMpuAddr + ulNumBytes > vma->vm_end)) {
6428 + /* jump to the next VMA region */
6429 + down_read(&mm->mmap_sem);
6430 + vma = find_vma(mm, vma->vm_end + 1);
6431 + up_read(&mm->mmap_sem);
6432 + DBG_Trace(DBG_LEVEL6, "VMAfor UserBuf ulMpuAddr=%x, "
6433 + "ulNumBytes=%x, vm_start=%x vm_end=%x vm_flags=%x\n",
6434 + ulMpuAddr, ulNumBytes, vma->vm_start,
6435 + vma->vm_end, vma->vm_flags);
6437 + if (vma == NULL) {
6438 + DBG_Trace(DBG_LEVEL7, "Failed to get the VMA region for "
6439 + "MPU Buffer !!! \n");
6440 + status = DSP_EINVALIDARG;
6442 + if (DSP_FAILED(status))
6443 + goto func_cont;
6444 + pPhysAddrPageTbl = DMM_GetPhysicalAddrTable();
6445 + /* Build the array with virtual to physical translations */
6446 + status = TIOMAP_VirtToPhysical(mm, ulMpuAddr, ulNumBytes,
6447 + &numOfActualTabEntries, pPhysAddrPageTbl);
6448 + if (DSP_FAILED(status)) {
6449 + DBG_Trace(DBG_LEVEL7,
6450 + "WMD_BRD_MemMap: TIOMAP_VirtToPhysical",
6451 + " failed\n");
6452 + return DSP_EFAIL;
6454 + temp = 0;
6455 + DBG_Trace(DBG_LEVEL4, "WMD_BRD_MemMap: numOfActualTabEntries=%d, "
6456 + "ulNumBytes= %d\n", numOfActualTabEntries, ulNumBytes);
6457 + /* Update the DSP MMU table with the physical addresses received from
6458 + from translation function */
6459 + while (temp < numOfActualTabEntries) {
6460 + status = PteSet(pDevContext->pPtAttrs, pPhysAddrPageTbl[temp++],
6461 + ulVirtAddr, HW_PAGE_SIZE_4KB, &hwAttrs);
6462 + if (DSP_FAILED(status)) {
6463 + DBG_Trace(DBG_LEVEL7,
6464 + "WMD_BRD_MemMap: FAILED IN PTESET \n");
6465 + return DSP_EFAIL;
6467 + ulVirtAddr += HW_PAGE_SIZE_4KB;
6469 + if (DSP_FAILED(status))
6470 + DBG_Trace(DBG_LEVEL5, "WMD_BRD_MemMap: PteSet failed \n");
6471 + else
6472 + DBG_Trace(DBG_LEVEL5, "WMD_BRD_MemMap: PteSet passed \n");
6474 +func_cont:
6475 + /* Don't propogate Linux or HW status to upper layers */
6476 + if (DSP_SUCCEEDED(status)) {
6477 + status = DSP_SOK;
6478 + } else {
6479 + DBG_Trace(DBG_LEVEL7, "< WMD_BRD_MemMap status %x\n", status);
6480 + status = DSP_EFAIL;
6482 + /* In any case, flush the TLB
6483 + * This is called from here instead from PteUpdate to avoid unnecessary
6484 + * repetition while mapping non-contiguous physical regions of a virtual
6485 + * region */
6486 + HW_MMU_TLBFlushAll(pDevContext->dwDSPMmuBase);
6487 + DBG_Trace(DBG_ENTER, "< WMD_BRD_MemMap status %x\n", status);
6488 + return status;
6492 + * ======== WMD_BRD_MemUnMap ========
6493 + * Invalidate the PTEs for the DSP VA block to be unmapped.
6495 + * PTEs of a mapped memory block are contiguous in any page table
6496 + * So, instead of looking up the PTE address for every 4K block,
6497 + * we clear consecutive PTEs until we unmap all the bytes
6498 + */
6499 +static DSP_STATUS WMD_BRD_MemUnMap(struct WMD_DEV_CONTEXT *hDevContext,
6500 + u32 ulVirtAddr, u32 ulNumBytes)
6502 + u32 L1BaseVa;
6503 + u32 L2BaseVa;
6504 + u32 L2BasePa;
6505 + u32 L2PageNum;
6506 + u32 pteVal;
6507 + u32 pteSize;
6508 + u32 pteCount;
6509 + u32 pteAddrL1;
6510 + u32 pteAddrL2 = 0;
6511 + u32 remBytes;
6512 + u32 remBytesL2;
6513 + u32 vaCurr;
6514 + DSP_STATUS status = DSP_SOK;
6515 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
6516 + struct PgTableAttrs *pt = pDevContext->pPtAttrs;
6518 + DBG_Trace(DBG_ENTER, "> WMD_BRD_MemUnMap hDevContext %x, va %x, "
6519 + "NumBytes %x\n", hDevContext, ulVirtAddr, ulNumBytes);
6520 + vaCurr = ulVirtAddr;
6521 + remBytes = ulNumBytes;
6522 + remBytesL2 = 0;
6523 + L1BaseVa = pt->L1BaseVa;
6524 + pteAddrL1 = HW_MMU_PteAddrL1(L1BaseVa, vaCurr);
6525 + DBG_Trace(DBG_ENTER, "WMD_BRD_MemUnMap L1BaseVa %x, pteAddrL1 %x "
6526 + "vaCurr %x remBytes %x\n", L1BaseVa, pteAddrL1,
6527 + vaCurr, remBytes);
6528 + while (remBytes && (DSP_SUCCEEDED(status))) {
6529 + u32 vaCurrOrig = vaCurr;
6530 + /* Find whether the L1 PTE points to a valid L2 PT */
6531 + pteAddrL1 = HW_MMU_PteAddrL1(L1BaseVa, vaCurr);
6532 + pteVal = *(u32 *)pteAddrL1;
6533 + pteSize = HW_MMU_PteSizeL1(pteVal);
6534 + if (pteSize == HW_MMU_COARSE_PAGE_SIZE) {
6535 + /* Get the L2 PA from the L1 PTE, and find
6536 + * corresponding L2 VA */
6537 + L2BasePa = HW_MMU_PteCoarseL1(pteVal);
6538 + L2BaseVa = L2BasePa - pt->L2BasePa + pt->L2BaseVa;
6539 + L2PageNum = (L2BasePa - pt->L2BasePa) /
6540 + HW_MMU_COARSE_PAGE_SIZE;
6541 + /* Find the L2 PTE address from which we will start
6542 + * clearing, the number of PTEs to be cleared on this
6543 + * page, and the size of VA space that needs to be
6544 + * cleared on this L2 page */
6545 + pteAddrL2 = HW_MMU_PteAddrL2(L2BaseVa, vaCurr);
6546 + pteCount = pteAddrL2 & (HW_MMU_COARSE_PAGE_SIZE - 1);
6547 + pteCount = (HW_MMU_COARSE_PAGE_SIZE - pteCount) /
6548 + sizeof(u32);
6549 + if (remBytes < (pteCount * PG_SIZE_4K))
6550 + pteCount = remBytes / PG_SIZE_4K;
6552 + remBytesL2 = pteCount * PG_SIZE_4K;
6553 + DBG_Trace(DBG_LEVEL1, "WMD_BRD_MemUnMap L2BasePa %x, "
6554 + "L2BaseVa %x pteAddrL2 %x, remBytesL2 %x\n",
6555 + L2BasePa, L2BaseVa, pteAddrL2, remBytesL2);
6556 + /* Unmap the VA space on this L2 PT. A quicker way
6557 + * would be to clear pteCount entries starting from
6558 + * pteAddrL2. However, below code checks that we don't
6559 + * clear invalid entries or less than 64KB for a 64KB
6560 + * entry. Similar checking is done for L1 PTEs too
6561 + * below */
6562 + while (remBytesL2 && (DSP_SUCCEEDED(status))) {
6563 + pteVal = *(u32 *)pteAddrL2;
6564 + pteSize = HW_MMU_PteSizeL2(pteVal);
6565 + /* vaCurr aligned to pteSize? */
6566 + if ((pteSize != 0) && (remBytesL2 >= pteSize) &&
6567 + !(vaCurr & (pteSize - 1))) {
6568 + HW_MMU_PteClear(pteAddrL2, vaCurr,
6569 + pteSize);
6570 + remBytesL2 -= pteSize;
6571 + vaCurr += pteSize;
6572 + pteAddrL2 += (pteSize >> 12) *
6573 + sizeof(u32);
6574 + } else {
6575 + status = DSP_EFAIL;
6578 + SYNC_EnterCS(pt->hCSObj);
6579 + if (remBytesL2 == 0) {
6580 + pt->pgInfo[L2PageNum].numEntries -= pteCount;
6581 + if (pt->pgInfo[L2PageNum].numEntries == 0) {
6582 + /* Clear the L1 PTE pointing to the
6583 + * L2 PT */
6584 + status = HW_MMU_PteClear(L1BaseVa,
6585 + vaCurrOrig,
6586 + HW_MMU_COARSE_PAGE_SIZE);
6588 + remBytes -= pteCount * PG_SIZE_4K;
6589 + } else {
6590 + status = DSP_EFAIL;
6592 + DBG_Trace(DBG_LEVEL1, "WMD_BRD_MemUnMap L2PageNum %x, "
6593 + "numEntries %x, pteCount %x, status: 0x%x\n",
6594 + L2PageNum, pt->pgInfo[L2PageNum].numEntries,
6595 + pteCount, status);
6596 + SYNC_LeaveCS(pt->hCSObj);
6597 + } else
6598 + /* vaCurr aligned to pteSize? */
6599 + /* pteSize = 1 MB or 16 MB */
6600 + if ((pteSize != 0) && (remBytes >= pteSize) &&
6601 + !(vaCurr & (pteSize - 1))) {
6602 + HW_MMU_PteClear(L1BaseVa, vaCurr, pteSize);
6603 + remBytes -= pteSize;
6604 + vaCurr += pteSize;
6605 + } else {
6606 + status = DSP_EFAIL;
6609 + /* It is better to flush the TLB here, so that any stale old entries
6610 + * get flushed */
6611 + HW_MMU_TLBFlushAll(pDevContext->dwDSPMmuBase);
6612 + DBG_Trace(DBG_LEVEL1, "WMD_BRD_MemUnMap vaCurr %x, pteAddrL1 %x "
6613 + "pteAddrL2 %x\n", vaCurr, pteAddrL1, pteAddrL2);
6614 + DBG_Trace(DBG_ENTER, "< WMD_BRD_MemUnMap status %x remBytes %x, "
6615 + "remBytesL2 %x\n", status, remBytes, remBytesL2);
6616 + return status;
6619 + * ========= TIOMAP_VirtToPhysical ==========
6620 + * Purpose:
6621 + * This function builds the array with virtual to physical
6622 + * address translation
6623 + */
6624 +static DSP_STATUS TIOMAP_VirtToPhysical(struct mm_struct *mm, u32 ulMpuAddr,
6625 + u32 ulNumBytes,
6626 + u32 *numOfTableEntries,
6627 + u32 *physicalAddrTable)
6629 + u32 pAddr;
6630 + u32 chunkSz;
6631 + DSP_STATUS status = DSP_SOK;
6632 + volatile u32 pteVal;
6633 + u32 pteSize;
6634 + pgd_t *pgd;
6635 + pmd_t *pmd;
6636 + volatile pte_t *ptep;
6637 + u32 numEntries = 0;
6638 + u32 numof4KPages = 0;
6639 + u32 phyEntryCounter = 0;
6640 + u32 temp = 0;
6641 + u32 numUsrPgs;
6642 + struct task_struct *curr_task = current;
6644 + DBG_Trace(DBG_ENTER, "TIOMAP_VirtToPhysical: START:ulMpuAddr=%x, "
6645 + "ulNumBytes=%x\n", ulMpuAddr, ulNumBytes);
6646 + if (physicalAddrTable == NULL)
6647 + return DSP_EMEMORY;
6648 + while (ulNumBytes) {
6649 + DBG_Trace(DBG_LEVEL4, "TIOMAP_VirtToPhysical:Read the next PGD "
6650 + "and PMD entry\n");
6651 + numEntries = 0;
6652 + /* Get the first level page table entry information */
6653 + /* Read the pointer to first level page table entry */
6654 + pgd = pgd_offset(mm, ulMpuAddr);
6655 + /* Read the value in the first level page table entry */
6656 + pteVal = *(u32 *)pgd;
6657 + /* Find the page size that is pointed by the first level page
6658 + * table entry */
6659 + pteSize = HW_MMU_PteSizeL1(pteVal); /* update 16 or 1 */
6660 + /* If pteSize is zero, then call the get_user_pages to create
6661 + * the page table entries for this buffer
6662 + */
6663 + if (!pteSize) {
6664 + down_read(&mm->mmap_sem);
6665 + /* This call invokes handle_mmu _fault call, which
6666 + *causes all pages to be created before we scan the
6667 + * page tables
6668 + */
6669 + numUsrPgs = get_user_pages(curr_task, mm, ulMpuAddr, 1,
6670 + true, 0, NULL, NULL);
6671 + up_read(&mm->mmap_sem);
6672 + /* Get the first level page table entry information */
6673 + /* Read the pointer to first level page table entry */
6674 + pgd = pgd_offset(mm, ulMpuAddr);
6675 + /* Read the value in the first level page table entry*/
6676 + pteVal = *(u32 *)pgd;
6677 + /* Find the page size that is pointed by the first level
6678 + * page table entry
6679 + */
6680 + pteSize = HW_MMU_PteSizeL1(pteVal);
6681 + DBG_Trace(DBG_LEVEL4, "First level get_user_pages "
6682 + "called\n");
6684 + /* If the page size is 4K or 64K, then we have to traverse to
6685 + * second level page table */
6686 + if (pteSize == HW_MMU_COARSE_PAGE_SIZE) {
6687 + DBG_Trace(DBG_LEVEL5, "Read the next PMD entry\n");
6688 + /* Get the second level page table information */
6689 + pmd = pmd_offset(pgd, ulMpuAddr);
6690 + ptep = pte_offset_map(pmd, ulMpuAddr);
6691 + do {
6692 + ptep = ptep+numEntries;
6693 + /* Read the value of second level page table
6694 + * entry */
6695 + pteVal = *(u32 *)ptep;
6696 + /* Find the size of page the second level
6697 + * table entry is pointing */
6698 + /* update 64 or 4 */
6699 + pteSize = HW_MMU_PteSizeL2(pteVal);
6700 + /* If pteSize is invalid, then call
6701 + * get_user_pages to create the
6702 + * page table entries
6703 + */
6704 + if (!pteSize) {
6705 + numUsrPgs =
6706 + (ulNumBytes/HW_PAGE_SIZE_4KB);
6707 + down_read(&mm->mmap_sem);
6708 + /* This call invokes
6709 + *handle_mmu _fault call, which causes
6710 + *all pages to be created before we scan
6711 + * the page tables */
6712 + if (numUsrPgs <= PAGES_II_LVL_TABLE) {
6713 + get_user_pages(curr_task, mm,
6714 + ulMpuAddr, numUsrPgs, true, 0,
6715 + NULL, NULL);
6716 + DBG_Trace(DBG_LEVEL4,
6717 + "get_user_pages, numUsrPgs"
6718 + "= %d\n", numUsrPgs);
6719 + } else {
6720 + get_user_pages(curr_task, mm,
6721 + ulMpuAddr, PAGES_II_LVL_TABLE,
6722 + true, 0, NULL, NULL);
6723 + DBG_Trace(DBG_LEVEL4,
6724 + "get_user_pages, numUsrPgs"
6725 + "= %d\n", PAGES_II_LVL_TABLE);
6727 + up_read(&mm->mmap_sem);
6728 + /* Read the value of second level page
6729 + * table entry */
6730 + pteVal = *(u32 *)ptep;
6731 + /* Find the size of page the second
6732 + * level table entry is pointing */
6733 + pteSize = HW_MMU_PteSizeL2(pteVal);
6735 + DBG_Trace(DBG_LEVEL4, "TIOMAP_VirtToPhysical:"
6736 + "*pmd=%x, *pgd=%x, ptep = %x, pteVal="
6737 + " %x, pteSize=%x\n", *pmd,
6738 + *(u32 *)pgd, (u32)ptep, pteVal,
6739 + pteSize);
6741 + /* Extract the physical Addresses */
6742 + switch (pteSize) {
6743 + case HW_PAGE_SIZE_64KB:
6744 + pAddr = pteVal & MMU_LARGE_PAGE_MASK;
6745 + chunkSz = HW_PAGE_SIZE_64KB;
6746 + numEntries = 16;
6747 + numof4KPages = 16;
6748 + break;
6749 + case HW_PAGE_SIZE_4KB:
6750 + pAddr = pteVal & MMU_SMALL_PAGE_MASK;
6751 + chunkSz = HW_PAGE_SIZE_4KB;
6752 + numEntries = 1;
6753 + numof4KPages = 1;
6754 + break;
6755 + default:
6756 + DBG_Trace(DBG_LEVEL7,
6757 + "TIOMAP_VirtToPhysical:"
6758 + "Descriptor"
6759 + "Format Fault-II level,"
6760 + " PTE size = %x\n",
6761 + pteSize);
6762 + return DSP_EFAIL;
6764 + temp = 0;
6765 + while (temp++ < numof4KPages) {
6766 + physicalAddrTable[phyEntryCounter++] =
6767 + pAddr;
6768 + DBG_Trace(DBG_LEVEL4,
6769 + "TIOMAP_VirtToPhysical:"
6770 + "physicalAddrTable[%d]= %x\n",
6771 + (phyEntryCounter-1), pAddr);
6772 + pAddr += HW_PAGE_SIZE_4KB;
6774 + if (DSP_SUCCEEDED(status)) {
6775 + /* Go to the next page */
6776 + ulMpuAddr += chunkSz;
6777 + /* Update the number of bytes that
6778 + * are copied */
6779 + ulNumBytes -= chunkSz;
6780 + DBG_Trace(DBG_LEVEL4,
6781 + "TIOMAP_VirtToPhysical: mpuCurr"
6782 + " = %x, pagesize = %x, "
6783 + "numBytesRem=%x\n",
6784 + ulMpuAddr, chunkSz, ulNumBytes);
6785 + } else {
6786 + DBG_Trace(DBG_LEVEL7,
6787 + " TIOMAP_VirtToPhysical:PTEupdate"
6788 + "failed\n");
6790 + /* It is observed that the pgd value (first level page
6791 + * table entry) is changed after reading the 512
6792 + * entries in second level table. So, call the pgd
6793 + * functions after reaching 512 entries in second
6794 + * level table */
6795 + } while ((ulMpuAddr & 0x001ff000) && (ulNumBytes));
6796 + } else {
6797 + /* Extract the Address to update the IVA MMU table
6798 + * with */
6799 + switch (pteSize) {
6800 + case HW_PAGE_SIZE_16MB:
6801 + pAddr = pteVal & MMU_SSECTION_ADDR_MASK;
6802 + chunkSz = HW_PAGE_SIZE_16MB;
6803 + numEntries = 16;
6804 + numof4KPages = 4096;
6805 + break;
6806 + case HW_PAGE_SIZE_1MB:
6807 + pAddr = pteVal & MMU_SECTION_ADDR_MASK;
6808 + chunkSz = HW_PAGE_SIZE_1MB;
6809 + numEntries = 1;
6810 + numof4KPages = 256;
6811 + break;
6812 + default:
6813 + DBG_Trace(DBG_LEVEL7,
6814 + "TIOMAP_VirtToPhysical:Descriptor"
6815 + "Format Faul-I level, PTE size = "
6816 + "%x\n", pteSize);
6817 + return DSP_EFAIL;
6819 + temp = 0;
6820 + while (temp++ < numof4KPages) {
6821 + physicalAddrTable[phyEntryCounter++] =
6822 + pAddr;
6823 + DBG_Trace(DBG_LEVEL4,
6824 + "TIOMAP_VirtToPhysical:"
6825 + "physicalAddrTable[%d]= %x\n",
6826 + (phyEntryCounter-1), pAddr);
6827 + pAddr += HW_PAGE_SIZE_4KB;
6829 + if (DSP_SUCCEEDED(status)) {
6830 + /* Go to the next page */
6831 + ulMpuAddr += chunkSz;
6832 + /* Update the number of bytes that are copied */
6833 + ulNumBytes -= chunkSz;
6834 + DBG_Trace(DBG_LEVEL4,
6835 + "TIOMAP_VirtToPhysical: mpuCurr = %x, "
6836 + "pagesize = %x, numBytesRem=%x\n",
6837 + ulMpuAddr, chunkSz, ulNumBytes);
6838 + } else {
6839 + DBG_Trace(DBG_LEVEL7,
6840 + " TIOMAP_VirtToPhysical:PTEupdate"
6841 + "failed\n");
6846 + *numOfTableEntries = phyEntryCounter;
6847 + DBG_Trace(DBG_LEVEL4, " TIOMAP_VirtToPhysical:numofTableEntries=%d\n",
6848 + phyEntryCounter);
6849 + return status;
6853 + * ======== PteUpdate ========
6854 + * This function calculates the optimum page-aligned addresses and sizes
6855 + * Caller must pass page-aligned values
6856 + */
6857 +static DSP_STATUS PteUpdate(struct WMD_DEV_CONTEXT *hDevContext, u32 pa,
6858 + u32 va, u32 size,
6859 + struct HW_MMUMapAttrs_t *mapAttrs)
6861 + u32 i;
6862 + u32 allBits;
6863 + u32 paCurr = pa;
6864 + u32 vaCurr = va;
6865 + u32 numBytes = size;
6866 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
6867 + DSP_STATUS status = DSP_SOK;
6868 + u32 pgSize[] = { HW_PAGE_SIZE_16MB, HW_PAGE_SIZE_1MB,
6869 + HW_PAGE_SIZE_64KB, HW_PAGE_SIZE_4KB };
6870 + DBG_Trace(DBG_ENTER, "> PteUpdate hDevContext %x, pa %x, va %x, "
6871 + "size %x, mapAttrs %x\n", hDevContext, pa, va, size, mapAttrs);
6872 + while (numBytes && DSP_SUCCEEDED(status)) {
6873 + /* To find the max. page size with which both PA & VA are
6874 + * aligned */
6875 + allBits = paCurr | vaCurr;
6876 + DBG_Trace(DBG_LEVEL1, "allBits %x, paCurr %x, vaCurr %x, "
6877 + "numBytes %x ", allBits, paCurr, vaCurr, numBytes);
6878 + for (i = 0; i < 4; i++) {
6879 + if ((numBytes >= pgSize[i]) && ((allBits &
6880 + (pgSize[i] - 1)) == 0)) {
6881 + DBG_Trace(DBG_LEVEL1, "pgSize %x\n", pgSize[i]);
6882 + status = PteSet(pDevContext->pPtAttrs, paCurr,
6883 + vaCurr, pgSize[i], mapAttrs);
6884 + paCurr += pgSize[i];
6885 + vaCurr += pgSize[i];
6886 + numBytes -= pgSize[i];
6887 + /* Don't try smaller sizes. Hopefully we have
6888 + * reached an address aligned to a bigger page
6889 + * size */
6890 + break;
6894 + DBG_Trace(DBG_ENTER, "< PteUpdate status %x numBytes %x\n", status,
6895 + numBytes);
6896 + return status;
6900 + * ======== PteSet ========
6901 + * This function calculates PTE address (MPU virtual) to be updated
6902 + * It also manages the L2 page tables
6903 + */
6904 +static DSP_STATUS PteSet(struct PgTableAttrs *pt, u32 pa, u32 va,
6905 + u32 size, struct HW_MMUMapAttrs_t *attrs)
6907 + u32 i;
6908 + u32 pteVal;
6909 + u32 pteAddrL1;
6910 + u32 pteSize;
6911 + u32 pgTblVa; /* Base address of the PT that will be updated */
6912 + u32 L1BaseVa;
6913 + /* Compiler warns that the next three variables might be used
6914 + * uninitialized in this function. Doesn't seem so. Working around,
6915 + * anyways. */
6916 + u32 L2BaseVa = 0;
6917 + u32 L2BasePa = 0;
6918 + u32 L2PageNum = 0;
6919 + DSP_STATUS status = DSP_SOK;
6920 + DBG_Trace(DBG_ENTER, "> PteSet pPgTableAttrs %x, pa %x, va %x, "
6921 + "size %x, attrs %x\n", pt, pa, va, size, attrs);
6922 + L1BaseVa = pt->L1BaseVa;
6923 + pgTblVa = L1BaseVa;
6924 + if ((size == HW_PAGE_SIZE_64KB) || (size == HW_PAGE_SIZE_4KB)) {
6925 + /* Find whether the L1 PTE points to a valid L2 PT */
6926 + pteAddrL1 = HW_MMU_PteAddrL1(L1BaseVa, va);
6927 + if (pteAddrL1 <= (pt->L1BaseVa + pt->L1size)) {
6928 + pteVal = *(u32 *)pteAddrL1;
6929 + pteSize = HW_MMU_PteSizeL1(pteVal);
6930 + } else {
6931 + return DSP_EFAIL;
6933 + SYNC_EnterCS(pt->hCSObj);
6934 + if (pteSize == HW_MMU_COARSE_PAGE_SIZE) {
6935 + /* Get the L2 PA from the L1 PTE, and find
6936 + * corresponding L2 VA */
6937 + L2BasePa = HW_MMU_PteCoarseL1(pteVal);
6938 + L2BaseVa = L2BasePa - pt->L2BasePa + pt->L2BaseVa;
6939 + L2PageNum = (L2BasePa - pt->L2BasePa) /
6940 + HW_MMU_COARSE_PAGE_SIZE;
6941 + } else if (pteSize == 0) {
6942 + /* L1 PTE is invalid. Allocate a L2 PT and
6943 + * point the L1 PTE to it */
6944 + /* Find a free L2 PT. */
6945 + for (i = 0; (i < pt->L2NumPages) &&
6946 + (pt->pgInfo[i].numEntries != 0); i++)
6947 + ;;
6948 + if (i < pt->L2NumPages) {
6949 + L2PageNum = i;
6950 + L2BasePa = pt->L2BasePa + (L2PageNum *
6951 + HW_MMU_COARSE_PAGE_SIZE);
6952 + L2BaseVa = pt->L2BaseVa + (L2PageNum *
6953 + HW_MMU_COARSE_PAGE_SIZE);
6954 + /* Endianness attributes are ignored for
6955 + * HW_MMU_COARSE_PAGE_SIZE */
6956 + status = HW_MMU_PteSet(L1BaseVa, L2BasePa, va,
6957 + HW_MMU_COARSE_PAGE_SIZE, attrs);
6958 + } else {
6959 + status = DSP_EMEMORY;
6961 + } else {
6962 + /* Found valid L1 PTE of another size.
6963 + * Should not overwrite it. */
6964 + status = DSP_EFAIL;
6966 + if (DSP_SUCCEEDED(status)) {
6967 + pgTblVa = L2BaseVa;
6968 + if (size == HW_PAGE_SIZE_64KB)
6969 + pt->pgInfo[L2PageNum].numEntries += 16;
6970 + else
6971 + pt->pgInfo[L2PageNum].numEntries++;
6973 + DBG_Trace(DBG_LEVEL1, "L2 BaseVa %x, BasePa %x, "
6974 + "PageNum %x numEntries %x\n", L2BaseVa,
6975 + L2BasePa, L2PageNum,
6976 + pt->pgInfo[L2PageNum].numEntries);
6978 + SYNC_LeaveCS(pt->hCSObj);
6980 + if (DSP_SUCCEEDED(status)) {
6981 + DBG_Trace(DBG_LEVEL1, "PTE pgTblVa %x, pa %x, va %x, size %x\n",
6982 + pgTblVa, pa, va, size);
6983 + DBG_Trace(DBG_LEVEL1, "PTE endianism %x, elementSize %x, "
6984 + "mixedSize %x\n", attrs->endianism,
6985 + attrs->elementSize, attrs->mixedSize);
6986 + status = HW_MMU_PteSet(pgTblVa, pa, va, size, attrs);
6988 + DBG_Trace(DBG_ENTER, "< PteSet status %x\n", status);
6989 + return status;
6992 +/* Memory map kernel VA -- memory allocated with vmalloc */
6993 +static DSP_STATUS MemMapVmalloc(struct WMD_DEV_CONTEXT *hDevContext,
6994 + u32 ulMpuAddr, u32 ulVirtAddr,
6995 + u32 ulNumBytes, u32 ulMapAttr)
6997 + u32 attrs = ulMapAttr;
6998 + DSP_STATUS status = DSP_SOK;
6999 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
7000 + struct HW_MMUMapAttrs_t hwAttrs;
7001 + struct page *pPage[1];
7002 + u32 i;
7003 + u32 paCurr;
7004 + u32 paNext;
7005 + u32 vaCurr;
7006 + u32 sizeCurr;
7007 + u32 numPages;
7009 + DBG_Trace(DBG_ENTER, "> MemMapVmalloc hDevContext %x, pa %x, va %x, "
7010 + "size %x, ulMapAttr %x\n", hDevContext, ulMpuAddr,
7011 + ulVirtAddr, ulNumBytes, ulMapAttr);
7012 + /* Take mapping properties */
7013 + if (attrs & DSP_MAPBIGENDIAN)
7014 + hwAttrs.endianism = HW_BIG_ENDIAN;
7015 + else
7016 + hwAttrs.endianism = HW_LITTLE_ENDIAN;
7018 + hwAttrs.mixedSize = (enum HW_MMUMixedSize_t)
7019 + ((attrs & DSP_MAPMIXEDELEMSIZE) >> 2);
7020 + /* Ignore elementSize if mixedSize is enabled */
7021 + if (hwAttrs.mixedSize == 0) {
7022 + if (attrs & DSP_MAPELEMSIZE8) {
7023 + /* Size is 8 bit */
7024 + hwAttrs.elementSize = HW_ELEM_SIZE_8BIT;
7025 + } else if (attrs & DSP_MAPELEMSIZE16) {
7026 + /* Size is 16 bit */
7027 + hwAttrs.elementSize = HW_ELEM_SIZE_16BIT;
7028 + } else if (attrs & DSP_MAPELEMSIZE32) {
7029 + /* Size is 32 bit */
7030 + hwAttrs.elementSize = HW_ELEM_SIZE_32BIT;
7031 + } else if (attrs & DSP_MAPELEMSIZE64) {
7032 + /* Size is 64 bit */
7033 + hwAttrs.elementSize = HW_ELEM_SIZE_64BIT;
7034 + } else {
7035 + /* Mixedsize isn't enabled, so size can't be zero
7036 + * here */
7037 + DBG_Trace(DBG_LEVEL7, "WMD_BRD_MemMap: MMU element "
7038 + "size is zero\n");
7039 + return DSP_EINVALIDARG;
7042 + /* Do Kernel va to pa translation.
7043 + * Combine physically contiguous regions to reduce TLBs.
7044 + * Pass the translated pa to PteUpdate. */
7045 + numPages = ulNumBytes / PAGE_SIZE; /* PAGE_SIZE = OS page size */
7046 + if (DSP_FAILED(status))
7047 + goto func_cont;
7049 + i = 0;
7050 + vaCurr = ulMpuAddr;
7051 + pPage[0] = vmalloc_to_page((void *)vaCurr);
7052 + paNext = page_to_phys(pPage[0]);
7053 + while (DSP_SUCCEEDED(status) && (i < numPages)) {
7054 + /* Reuse paNext from the previous iteraion to avoid
7055 + * an extra va2pa call */
7056 + paCurr = paNext;
7057 + sizeCurr = PAGE_SIZE;
7058 + /* If the next page is physically contiguous,
7059 + * map it with the current one by increasing
7060 + * the size of the region to be mapped */
7061 + while (++i < numPages) {
7062 + pPage[0] = vmalloc_to_page((void *)(vaCurr + sizeCurr));
7063 + paNext = page_to_phys(pPage[0]);
7064 + DBG_Trace(DBG_LEVEL5, "Xlate Vmalloc VA=0x%x , "
7065 + "PA=0x%x \n", (vaCurr + sizeCurr), paNext);
7066 + if (paNext == (paCurr + sizeCurr))
7067 + sizeCurr += PAGE_SIZE;
7068 + else
7069 + break;
7072 + if (paNext == 0) {
7073 + status = DSP_EMEMORY;
7074 + break;
7076 + status = PteUpdate(pDevContext, paCurr, ulVirtAddr +
7077 + (vaCurr - ulMpuAddr), sizeCurr, &hwAttrs);
7078 + vaCurr += sizeCurr;
7080 +func_cont:
7081 + /* Don't propogate Linux or HW status to upper layers */
7082 + if (DSP_SUCCEEDED(status)) {
7083 + status = DSP_SOK;
7084 + DBG_Trace(DBG_LEVEL7, "< WMD_BRD_MemMap succeeded %x\n",
7085 + status);
7086 + } else {
7087 + DBG_Trace(DBG_LEVEL7, "< WMD_BRD_MemMap status %x\n", status);
7088 + status = DSP_EFAIL;
7090 + /* In any case, flush the TLB
7091 + * This is called from here instead from PteUpdate to avoid unnecessary
7092 + * repetition while mapping non-contiguous physical regions of a virtual
7093 + * region */
7094 + /* Waking up DSP before calling TLB Flush */
7095 + HW_MMU_TLBFlushAll(pDevContext->dwDSPMmuBase);
7096 + DBG_Trace(DBG_LEVEL7, "< WMD_BRD_MemMap at end status %x\n", status);
7097 + return status;
7100 +static DSP_STATUS run_IdleBoot(u32 prm_base, u32 cm_base,
7101 + u32 sysctrl_base)
7103 + u32 temp;
7104 + DSP_STATUS status = DSP_SOK;
7105 + DSP_STATUS clk_status = DSP_SOK;
7106 + enum HW_PwrState_t pwrState;
7108 + /* Read PM_PWSTST_IVA2 */
7109 + HW_PWRST_IVA2RegGet(prm_base, &temp);
7110 + if ((temp & 0x03) != 0x03 || (temp & 0x03) != 0x02) {
7111 + /* IVA2 is not in ON state */
7112 + /* Read and set PM_PWSTCTRL_IVA2 to ON */
7113 + HW_PWR_IVA2StateGet(prm_base, HW_PWR_DOMAIN_DSP, &pwrState);
7114 + HW_PWR_IVA2PowerStateSet(prm_base, HW_PWR_DOMAIN_DSP,
7115 + HW_PWR_STATE_ON);
7116 + /* Set the SW supervised state transition */
7117 + HW_PWR_CLKCTRL_IVA2RegSet(cm_base, HW_SW_SUP_WAKEUP);
7118 + /* Wait until the state has moved to ON */
7119 + HW_PWR_IVA2StateGet(prm_base, HW_PWR_DOMAIN_DSP, &pwrState);
7121 + clk_status = CLK_Disable(SERVICESCLK_iva2_ck);
7122 + if (DSP_FAILED(clk_status)) {
7123 + DBG_Trace(DBG_LEVEL6, "CLK_Disbale failed for clk = 0x%x \n",
7124 + SERVICESCLK_iva2_ck);
7126 + udelay(10);
7127 + /* Assert IVA2-RST1 and IVA2-RST2 */
7128 + *((REG_UWORD32 *)((u32)(prm_base) + 0x50)) = (u32)0x07;
7129 + udelay(30);
7130 + /* set the SYSC for Idle Boot */
7131 + *((REG_UWORD32 *)((u32)(sysctrl_base) + 0x404)) = (u32)0x01;
7132 + clk_status = CLK_Enable(SERVICESCLK_iva2_ck);
7133 + if (DSP_FAILED(clk_status)) {
7134 + DBG_Trace(DBG_LEVEL6, "CLK_Enable failed for clk = 0x%x \n",
7135 + SERVICESCLK_iva2_ck);
7137 + udelay(20);
7138 + GetHWRegs(prm_base, cm_base);
7139 + /* Release Reset1 and Reset2 */
7140 + *((REG_UWORD32 *)((u32)(prm_base) + 0x50)) = (u32)0x05;
7141 + udelay(20);
7142 + *((REG_UWORD32 *)((u32)(prm_base) + 0x50)) = (u32)0x04;
7143 + udelay(30);
7144 + return status;
7148 +void GetHWRegs(u32 prm_base, u32 cm_base)
7150 + u32 temp;
7151 + temp = (u32)*((REG_UWORD32 *)((u32)(cm_base) + 0x00));
7152 + DBG_Trace(DBG_LEVEL6, "CM_FCLKEN_IVA2 = 0x%x \n", temp);
7153 + temp = (u32)*((REG_UWORD32 *)((u32)(cm_base) + 0x10));
7154 + DBG_Trace(DBG_LEVEL6, "CM_ICLKEN1_IVA2 = 0x%x \n", temp);
7155 + temp = (u32)*((REG_UWORD32 *)((u32)(cm_base) + 0x20));
7156 + DBG_Trace(DBG_LEVEL6, "CM_IDLEST_IVA2 = 0x%x \n", temp);
7157 + temp = (u32)*((REG_UWORD32 *)((u32)(cm_base) + 0x48));
7158 + DBG_Trace(DBG_LEVEL6, "CM_CLKSTCTRL_IVA2 = 0x%x \n", temp);
7159 + temp = (u32)*((REG_UWORD32 *)((u32)(cm_base) + 0x4c));
7160 + DBG_Trace(DBG_LEVEL6, "CM_CLKSTST_IVA2 = 0x%x \n", temp);
7161 + temp = (u32)*((REG_UWORD32 *)((u32)(prm_base) + 0x50));
7162 + DBG_Trace(DBG_LEVEL6, "RM_RSTCTRL_IVA2 = 0x%x \n", temp);
7163 + temp = (u32)*((REG_UWORD32 *)((u32)(prm_base) + 0x58));
7164 + DBG_Trace(DBG_LEVEL6, "RM_RSTST_IVA2 = 0x%x \n", temp);
7165 + temp = (u32)*((REG_UWORD32 *)((u32)(prm_base) + 0xE0));
7166 + DBG_Trace(DBG_LEVEL6, "PM_PWSTCTRL_IVA2 = 0x%x \n", temp);
7167 + temp = (u32)*((REG_UWORD32 *)((u32)(prm_base) + 0xE4));
7168 + DBG_Trace(DBG_LEVEL6, "PM_PWSTST_IVA2 = 0x%x \n", temp);
7169 + temp = (u32)*((REG_UWORD32 *)((u32)(cm_base) + 0xA10));
7170 + DBG_Trace(DBG_LEVEL6, "CM_ICLKEN1_CORE = 0x%x \n", temp);
7174 + * ======== configureDspMmu ========
7175 + * Make DSP MMU page table entries.
7176 + */
7177 +void configureDspMmu(struct WMD_DEV_CONTEXT *pDevContext, u32 dataBasePhys,
7178 + u32 dspBaseVirt, u32 sizeInBytes, s32 nEntryStart,
7179 + enum HW_Endianism_t endianism,
7180 + enum HW_ElementSize_t elemSize,
7181 + enum HW_MMUMixedSize_t mixedSize)
7183 + struct CFG_HOSTRES resources;
7184 + struct HW_MMUMapAttrs_t mapAttrs = { endianism, elemSize, mixedSize };
7185 + DSP_STATUS status = DSP_SOK;
7187 + DBC_Require(sizeInBytes > 0);
7188 + DBG_Trace(DBG_LEVEL1,
7189 + "configureDspMmu entry %x pa %x, va %x, bytes %x ",
7190 + nEntryStart, dataBasePhys, dspBaseVirt, sizeInBytes);
7192 + DBG_Trace(DBG_LEVEL1, "endianism %x, elemSize %x, mixedSize %x\n",
7193 + endianism, elemSize, mixedSize);
7194 + status = CFG_GetHostResources(
7195 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources);
7196 + status = HW_MMU_TLBAdd(pDevContext->dwDSPMmuBase, dataBasePhys,
7197 + dspBaseVirt, sizeInBytes, nEntryStart,
7198 + &mapAttrs, HW_SET, HW_SET);
7202 + * ======== WaitForStart ========
7203 + * Wait for the singal from DSP that it has started, or time out.
7204 + */
7205 +bool WaitForStart(struct WMD_DEV_CONTEXT *pDevContext, u32 dwSyncAddr)
7207 + u16 usCount = TIHELEN_ACKTIMEOUT;
7209 + /* Wait for response from board */
7210 + while (*((volatile u16 *)dwSyncAddr) && --usCount)
7211 + UTIL_Wait(TIHELEN_WRITE_DELAY);
7213 + /* If timed out: return FALSE */
7214 + if (!usCount) {
7215 + DBG_Trace(DBG_LEVEL7, "Timed out Waiting for DSP to Start\n");
7216 + return FALSE;
7218 + return TRUE;
7220 Index: lk/drivers/dsp/bridge/wmd/tiomap3430_pwr.c
7221 ===================================================================
7222 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
7223 +++ lk/drivers/dsp/bridge/wmd/tiomap3430_pwr.c 2008-08-18 10:38:38.000000000 +0300
7224 @@ -0,0 +1,568 @@
7226 + * linux/drivers/dsp/bridge/wmd/linux/omap/3430/tiomap_pwr.c
7228 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
7230 + * Copyright (C) 2007-2008 Texas Instruments, Inc.
7232 + * This package is free software; you can redistribute it and/or modify
7233 + * it under the terms of the GNU General Public License version 2 as
7234 + * published by the Free Software Foundation.
7236 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
7237 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
7238 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
7239 + */
7242 + * ======== _tiomap_pwr.c ========
7243 + * Description:
7244 + * Implementation of DSP wake/sleep routines.
7246 + *! Revision History
7247 + *! ================
7248 + *! 01-Nov-2007 HK: Added Off mode(Hibernation) support and DVFS support
7249 + *! 05-Jan-2004 vp: Moved the file to platform specific folder and commented the
7250 + *! code.
7251 + *! 27-Mar-2003 vp: Added support for DSP boot idle mode.
7252 + *! 06-Dec-2002 cring: Added Palm support.
7253 + *! 08-Oct-2002 rr: Created.
7254 + */
7256 +/* ----------------------------------- DSP/BIOS Bridge */
7257 +#include <dbdefs.h>
7258 +#include <errbase.h>
7259 +#include <cfg.h>
7260 +#include <drv.h>
7261 +#include <io_sm.h>
7262 +#include <chnl_sm.h>
7264 +/* ----------------------------------- Trace & Debug */
7265 +#include <dbg.h>
7267 +/* ----------------------------------- OS Adaptation Layer */
7268 +#include <mem.h>
7269 +#include <util.h>
7271 +/* ----------------------------------- Platform Manager */
7272 +#include <brddefs.h>
7273 +#include <dev.h>
7274 +#include <iodefs.h>
7276 +/* ------------------------------------ Hardware Abstraction Layer */
7277 +#include <hw_defs.h>
7278 +#include <hw_dspssC64P.h>
7279 +#include <hw_prcm.h>
7280 +#include <hw_mmu.h>
7282 +#include <pwr_sh.h>
7284 +/* ----------------------------------- specific to this file */
7285 +#include "_tiomap.h"
7286 +#include "_tiomap_pwr.h"
7287 +#include "_tiomap_util.h"
7288 +#ifndef CONFIG_DISABLE_BRIDGE_PM
7289 +#ifndef CONFIG_DISABLE_BRIDGE_DVFS
7290 +#include <asm/arch/resource.h>
7291 +#endif
7292 +#endif
7293 +extern s32 dsp_test_sleepstate;
7294 +#ifndef CONFIG_DISABLE_BRIDGE_PM
7295 +extern struct constraint_handle *dsp_constraint_handle;
7296 +#endif
7297 +extern struct MAILBOX_CONTEXT mboxsetting;
7299 +extern void GetHWRegs(u32 prm_base, u32 cm_base);
7300 +DSP_STATUS DSP_PeripheralClocks_Disable(struct WMD_DEV_CONTEXT *pDevContext,
7301 + IN void *pArgs);
7302 +DSP_STATUS DSP_PeripheralClocks_Enable(struct WMD_DEV_CONTEXT *pDevContext,
7303 + IN void *pArgs);
7306 + * ======== handle_constraints_set ========
7307 + * Sets new DSP constraint
7308 + */
7309 +DSP_STATUS handle_constraints_set(struct WMD_DEV_CONTEXT *pDevContext,
7310 + IN void *pArgs)
7312 +#ifndef CONFIG_DISABLE_BRIDGE_PM
7313 +#ifndef CONFIG_DISABLE_BRIDGE_DVFS
7314 + u32 *pConstraintVal;
7316 + pConstraintVal = (u32 *)(pArgs);
7317 + /* Read the target value requested by DSP */
7318 + DBG_Trace(DBG_LEVEL7, "handle_constraints_set: opp requested = 0x%x\n",
7319 + (u32)*(pConstraintVal+1));
7321 + /* Set the new constraint in resource framework */
7322 + if (constraint_set(dsp_constraint_handle,
7323 + (u32)*(pConstraintVal+1)) == 0)
7324 + return DSP_SOK;
7325 + else {
7326 + DBG_Trace(DBG_LEVEL7,
7327 + "handle_constraints_set: Constraint set failed\n");
7328 + return DSP_EFAIL;
7330 +#endif /*#ifndef CONFIG_DISABLE_BRIDGE_DVFS */
7331 +#endif /*#ifndef CONFIG_DISABLE_BRIDGE_PM */
7332 + return DSP_SOK;
7336 + * ======== handle_hibernation_fromDSP ========
7337 + * Handle Hibernation requested from DSP
7338 + */
7339 +DSP_STATUS handle_hibernation_fromDSP(struct WMD_DEV_CONTEXT *pDevContext)
7341 +#ifndef CONFIG_DISABLE_BRIDGE_PM
7342 + u16 usCount = TIHELEN_ACKTIMEOUT;
7343 + struct CFG_HOSTRES resources;
7344 + DSP_STATUS status = DSP_SOK;
7345 + enum HW_PwrState_t pwrState;
7346 + u32 opplevel;
7347 + struct IO_MGR *hIOMgr;
7349 + status = CFG_GetHostResources(
7350 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources);
7351 + if (DSP_FAILED(status))
7352 + return status;
7354 + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP,
7355 + &pwrState);
7356 + /* Wait for DSP to move into Off state, how much time should
7357 + * we wait? */
7358 + while ((pwrState != HW_PWR_STATE_OFF) && --usCount) {
7359 + UTIL_Wait(PWR_WAIT_USECS);
7360 + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP,
7361 + &pwrState);
7363 + if (usCount == 0) {
7364 + DBG_Trace(DBG_LEVEL7, "Timed out Waiting for DSP Off mode \n");
7365 + status = WMD_E_TIMEOUT;
7366 + return status;
7367 + } else {
7369 + /* Save mailbox settings */
7370 + status = HW_MBOX_saveSettings(resources.dwMboxBase);
7371 + DBG_Trace(DBG_LEVEL6, "MailBoxSettings: SYSCONFIG = 0x%x\n",
7372 + mboxsetting.sysconfig);
7373 + DBG_Trace(DBG_LEVEL6, "MailBoxSettings: IRQENABLE0 = 0x%x\n",
7374 + mboxsetting.irqEnable0);
7375 + DBG_Trace(DBG_LEVEL6, "MailBoxSettings: IRQENABLE1 = 0x%x\n",
7376 + mboxsetting.irqEnable1);
7377 + /* Turn off DSP Peripheral clocks and DSP Load monitor timer */
7378 + status = DSP_PeripheralClocks_Disable(pDevContext, NULL);
7380 + if (DSP_SUCCEEDED(status)) {
7381 + /* Update the Bridger Driver state */
7382 + pDevContext->dwBrdState = BRD_DSP_HIBERNATION;
7383 +#ifndef CONFIG_DISABLE_BRIDGE_DVFS
7384 + status = DEV_GetIOMgr(pDevContext->hDevObject, &hIOMgr);
7385 + if (DSP_FAILED(status))
7386 + return status;
7387 + IO_SHMsetting(hIOMgr, SHM_GETOPP, &opplevel);
7388 + /* Set the OPP to low level before moving to OFF mode */
7389 + if (opplevel != CO_VDD1_OPP1) {
7390 + DBG_Trace(DBG_LEVEL5,
7391 + "Tiomap_pwr.c - DSP requested"
7392 + " OPP = %d, MPU requesting low"
7393 + " OPP %d instead\n", opplevel,
7394 + CO_VDD1_OPP1);
7395 + if (constraint_set(dsp_constraint_handle,
7396 + CO_VDD1_OPP1) != 0) {
7397 + DBG_Trace(DBG_LEVEL7,
7398 + "handle_hibernation_fromDSP:"
7399 + "Constraint set failed\n");
7400 + status = DSP_EFAIL;
7403 +#endif
7404 + } else {
7405 + DBG_Trace(DBG_LEVEL7,
7406 + "handle_hibernation_fromDSP- FAILED\n");
7409 + return status;
7411 +#endif
7412 + return DSP_SOK;
7416 + * ======== SleepDSP ========
7417 + * Put DSP in low power consuming state.
7418 + */
7419 +DSP_STATUS SleepDSP(struct WMD_DEV_CONTEXT *pDevContext, IN u32 dwCmd,
7420 + IN void *pArgs)
7422 + DSP_STATUS status = DSP_SOK;
7423 +#ifndef CONFIG_DISABLE_BRIDGE_PM
7424 + struct CFG_HOSTRES resources;
7425 + u16 usCount = TIHELEN_ACKTIMEOUT;
7426 + enum HW_PwrState_t pwrState;
7427 + enum HW_PwrState_t targetPwrState;
7429 + status = CFG_GetHostResources(
7430 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources);
7431 + if (DSP_FAILED(status))
7432 + return status;
7433 + DBG_Trace(DBG_LEVEL7, "SleepDSP- Enter function \n");
7435 + /* next, check if sleep code is valid... */
7436 + if ((dwCmd != PWR_DEEPSLEEP) && (dwCmd != PWR_EMERGENCYDEEPSLEEP)) {
7437 + DBG_Trace(DBG_LEVEL7, "SleepDSP- Illegal sleep command\n");
7438 + return DSP_EINVALIDARG;
7440 + switch (pDevContext->dwBrdState) {
7441 + case BRD_RUNNING:
7442 + if (dsp_test_sleepstate == HW_PWR_STATE_OFF) {
7443 + IO_InterruptDSP2(pDevContext,
7444 + MBX_PM_DSPHIBERNATE);
7445 + DBG_Trace(DBG_LEVEL7,
7446 + "SleepDSP - Sent hibernate "
7447 + "command to DSP\n");
7448 + targetPwrState = HW_PWR_STATE_OFF;
7449 + } else {
7450 + IO_InterruptDSP2(pDevContext,
7451 + MBX_PM_DSPRETENTION);
7452 + targetPwrState = HW_PWR_STATE_RET;
7454 + break;
7455 + case BRD_RETENTION:
7456 + if (dsp_test_sleepstate == HW_PWR_STATE_OFF) {
7457 + IO_InterruptDSP2(pDevContext,
7458 + MBX_PM_DSPHIBERNATE);
7459 + targetPwrState = HW_PWR_STATE_OFF;
7460 + } else
7461 + return DSP_SOK;
7462 + break;
7463 + case BRD_HIBERNATION:
7464 + case BRD_DSP_HIBERNATION:
7465 + /* Already in Hibernation, so just return */
7466 + DBG_Trace(DBG_LEVEL7, "SleepDSP- DSP already in "
7467 + "hibernation\n");
7468 + return DSP_SOK;
7469 + case BRD_STOPPED:
7470 + DBG_Trace(DBG_LEVEL7,
7471 + "SleepDSP- Board in STOP state \n");
7472 + return DSP_SALREADYASLEEP;
7473 + default:
7474 + DBG_Trace(DBG_LEVEL7,
7475 + "SleepDSP- Bridge in Illegal state\n");
7476 + return DSP_EFAIL;
7478 + /* Get the PRCM DSP power domain status */
7479 + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP,
7480 + &pwrState);
7481 + /* Wait for DSP to move into Standby state, how much time
7482 + * should we wait?*/
7483 + while ((pwrState != targetPwrState) && --usCount) {
7484 + UTIL_Wait(PWR_WAIT_USECS);
7485 + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP,
7486 + &pwrState);
7488 + if (usCount == 0) {
7489 + DBG_Trace(DBG_LEVEL7, "SleepDSP: Timed out Waiting for DSP"
7490 + " STANDBY %x \n", pwrState);
7491 + return WMD_E_TIMEOUT;
7492 + } else {
7493 + DBG_Trace(DBG_LEVEL7, "SleepDSP: DSP STANDBY Pwr state %x \n",
7494 + pwrState);
7495 + /* Update the Bridger Driver state */
7496 + if (dsp_test_sleepstate == HW_PWR_STATE_OFF)
7497 + pDevContext->dwBrdState = BRD_HIBERNATION;
7498 + else
7499 + pDevContext->dwBrdState = BRD_RETENTION;
7500 + /* Turn off DSP Peripheral clocks */
7501 + status = DSP_PeripheralClocks_Disable(pDevContext, NULL);
7502 + if (DSP_FAILED(status))
7503 + DBG_Trace(DBG_LEVEL7, "SleepDSP- FAILED\n");
7505 +#endif
7506 + return status;
7511 + * ======== WakeDSP ========
7512 + * Wake up DSP from sleep.
7513 + */
7514 +DSP_STATUS WakeDSP(struct WMD_DEV_CONTEXT *pDevContext, IN void *pArgs)
7516 + DSP_STATUS status = DSP_SOK;
7517 +#ifndef CONFIG_DISABLE_BRIDGE_PM
7518 + struct CFG_HOSTRES resources;
7519 + enum HW_PwrState_t pwrState;
7521 + status = CFG_GetHostResources(
7522 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources);
7523 + if (DSP_FAILED(status))
7524 + return status;
7525 + /* check the BRD/WMD state, if it is not 'SLEEP' then return failure */
7526 + if (pDevContext->dwBrdState == BRD_RUNNING ||
7527 + pDevContext->dwBrdState == BRD_STOPPED ||
7528 + pDevContext->dwBrdState == BRD_DSP_HIBERNATION) {
7529 + /* The Device is in 'RET' or 'OFF' state and WMD state is not
7530 + * 'SLEEP', this means state inconsistency, so return */
7531 + status = DSP_SOK;
7532 + return status;
7534 + /* Enable the DSP peripheral clocks and load monitor timer
7535 + * before waking the DSP */
7536 + DBG_Trace(DBG_LEVEL6, "WakeDSP: enable DSP Peripheral Clks = 0x%x \n",
7537 + pDevContext->uDspPerClks);
7538 + status = DSP_PeripheralClocks_Enable(pDevContext, NULL);
7539 + udelay(10);
7540 + if (DSP_SUCCEEDED(status)) {
7541 + /* Send a message to DSP to wake up */
7542 + IO_InterruptDSP2(pDevContext, MBX_PM_DSPWAKEUP);
7543 + HW_PWR_IVA2StateGet(resources.dwPrmBase, HW_PWR_DOMAIN_DSP,
7544 + &pwrState);
7545 + DBG_Trace(DBG_LEVEL7,
7546 + "\nWakeDSP: Power State After sending Interrupt "
7547 + "to DSP %x\n", pwrState);
7548 + /* set the device state to RUNNIG */
7549 + pDevContext->dwBrdState = BRD_RUNNING;
7550 + } else {
7551 + DBG_Trace(DBG_LEVEL6, "WakeDSP: FAILED\n");
7553 +#endif
7554 + return status;
7558 + * ======== DSPPeripheralClkCtrl ========
7559 + * Enable/Disable the DSP peripheral clocks as needed..
7560 + */
7561 +DSP_STATUS DSPPeripheralClkCtrl(struct WMD_DEV_CONTEXT *pDevContext,
7562 + IN void *pArgs)
7564 + u32 extClk = 0;
7565 + u32 extClkId = 0;
7566 + u32 extClkCmd = 0;
7567 + u32 clkIdIndex = MBX_PM_MAX_RESOURCES;
7568 + u32 tmpIndex;
7569 + u32 dspPerClksBefore;
7570 + DSP_STATUS status = DSP_SOK;
7571 + DSP_STATUS status1 = DSP_SOK;
7573 + DBG_Trace(DBG_ENTER, "Entering DSPPeripheralClkCtrl \n");
7574 + dspPerClksBefore = pDevContext->uDspPerClks;
7575 + DBG_Trace(DBG_ENTER, "DSPPeripheralClkCtrl : uDspPerClks = 0x%x \n",
7576 + dspPerClksBefore);
7578 + extClk = (u32)*((u32 *)pArgs);
7580 + DBG_Trace(DBG_LEVEL3, "DSPPeripheralClkCtrl : extClk+Cmd = 0x%x \n",
7581 + extClk);
7583 + extClkId = extClk & MBX_PM_CLK_IDMASK;
7585 + /* process the power message -- TODO, keep it in a separate function */
7586 + for (tmpIndex = 0; tmpIndex < MBX_PM_MAX_RESOURCES; tmpIndex++) {
7587 + if (extClkId == BPWR_CLKID[tmpIndex]) {
7588 + clkIdIndex = tmpIndex;
7589 + break;
7592 + /* TODO -- Assert may be a too hard restriction here.. May be we should
7593 + * just return with failure when the CLK ID does not match */
7594 + /* DBC_Assert(clkIdIndex < MBX_PM_MAX_RESOURCES);*/
7595 + if (clkIdIndex == MBX_PM_MAX_RESOURCES) {
7596 + DBG_Trace(DBG_LEVEL7,
7597 + "DSPPeripheralClkCtrl : Could n't get clock Id for"
7598 + "clkid 0x%x \n", clkIdIndex);
7599 + /* return with a more meaningfull error code */
7600 + return DSP_EFAIL;
7602 + extClkCmd = (extClk >> MBX_PM_CLK_CMDSHIFT) & MBX_PM_CLK_CMDMASK;
7603 + switch (extClkCmd) {
7604 + case BPWR_DisableClock:
7605 + /* Call BP to disable the needed clock */
7606 + DBG_Trace(DBG_LEVEL3,
7607 + "DSPPeripheralClkCtrl : Disable CLK for \n");
7608 + status1 = CLK_Disable(BPWR_Clks[clkIdIndex].intClk);
7609 + status = CLK_Disable(BPWR_Clks[clkIdIndex].funClk);
7610 + if ((DSP_SUCCEEDED(status)) && (DSP_SUCCEEDED(status1))) {
7611 + (pDevContext->uDspPerClks) &=
7612 + (~((u32) (1 << clkIdIndex)));
7613 + } else {
7614 + DBG_Trace(DBG_LEVEL7, "DSPPeripheralClkCtrl : Failed "
7615 + "to disable clk\n");
7617 + break;
7618 + case BPWR_EnableClock:
7619 + DBG_Trace(DBG_LEVEL3,
7620 + "DSPPeripheralClkCtrl : Enable CLK for \n");
7621 + status1 = CLK_Enable(BPWR_Clks[clkIdIndex].intClk);
7622 + status = CLK_Enable(BPWR_Clks[clkIdIndex].funClk);
7623 + if ((DSP_SUCCEEDED(status)) && (DSP_SUCCEEDED(status1))) {
7624 + (pDevContext->uDspPerClks) |= (1 << clkIdIndex);
7625 + } else {
7626 + DBG_Trace(DBG_LEVEL7,
7627 + "DSPPeripheralClkCtrl:Failed to Enable clk\n");
7629 + break;
7630 + default:
7631 + DBG_Trace(DBG_LEVEL3,
7632 + "DSPPeripheralClkCtrl : Unsupported CMD \n");
7633 + /* unsupported cmd */
7634 + /* TODO -- provide support for AUTOIDLE Enable/Disable
7635 + * commands */
7637 + return status;
7641 + * ========PreScale_DSP========
7642 + * Sends prescale notification to DSP
7644 + */
7645 +DSP_STATUS PreScale_DSP(struct WMD_DEV_CONTEXT *pDevContext, IN void *pArgs)
7647 +#ifndef CONFIG_DISABLE_BRIDGE_PM
7648 +#ifndef CONFIG_DISABLE_BRIDGE_DVFS
7649 + u32 level;
7650 + u32 voltage_domain;
7652 + voltage_domain = *((u32 *)pArgs);
7653 + level = *((u32 *)pArgs + 1);
7655 + DBG_Trace(DBG_LEVEL7, "PreScale_DSP: voltage_domain = %x, level = "
7656 + "0x%x\n", voltage_domain, level);
7657 + if ((pDevContext->dwBrdState == BRD_HIBERNATION) ||
7658 + (pDevContext->dwBrdState == BRD_RETENTION) ||
7659 + (pDevContext->dwBrdState == BRD_DSP_HIBERNATION)) {
7660 + DBG_Trace(DBG_LEVEL7, "PreScale_DSP: IVA in sleep. "
7661 + "No notification to DSP\n");
7662 + return DSP_SOK;
7663 + } else if ((pDevContext->dwBrdState == BRD_RUNNING)) {
7664 + /* Send a prenotificatio to DSP */
7665 + DBG_Trace(DBG_LEVEL7,
7666 + "PreScale_DSP: Sent notification to DSP\n");
7667 + IO_InterruptDSP2(pDevContext, MBX_PM_SETPOINT_PRENOTIFY);
7668 + return DSP_SOK;
7669 + } else {
7670 + DBG_Trace(DBG_LEVEL7, "PreScale_DSP: Failed - DSP BRD"
7671 + " state in wrong state");
7672 + return DSP_EFAIL;
7674 +#endif /*#ifndef CONFIG_DISABLE_BRIDGE_DVFS */
7675 +#endif /*#ifndef CONFIG_DISABLE_BRIDGE_PM */
7676 + return DSP_SOK;
7680 + * ========PostScale_DSP========
7681 + * Sends postscale notification to DSP
7683 + */
7684 +DSP_STATUS PostScale_DSP(struct WMD_DEV_CONTEXT *pDevContext, IN void *pArgs)
7686 +#ifndef CONFIG_DISABLE_BRIDGE_PM
7687 +#ifndef CONFIG_DISABLE_BRIDGE_DVFS
7688 + u32 level;
7689 + u32 voltage_domain;
7690 + struct IO_MGR *hIOMgr;
7691 + DSP_STATUS status = DSP_SOK;
7693 + status = DEV_GetIOMgr(pDevContext->hDevObject, &hIOMgr);
7695 + voltage_domain = *((u32 *)pArgs);
7696 + level = *((u32 *)pArgs + 1);
7697 + DBG_Trace(DBG_LEVEL7,
7698 + "PostScale_DSP: voltage_domain = %x, level = 0x%x\n",
7699 + voltage_domain, level);
7700 + if ((pDevContext->dwBrdState == BRD_HIBERNATION) ||
7701 + (pDevContext->dwBrdState == BRD_RETENTION) ||
7702 + (pDevContext->dwBrdState == BRD_DSP_HIBERNATION)) {
7703 + /* Update the OPP value in shared memory */
7704 + IO_SHMsetting(hIOMgr, SHM_CURROPP, &level);
7705 + DBG_Trace(DBG_LEVEL7,
7706 + "PostScale_DSP: IVA in sleep. Wrote to shared "
7707 + "memory \n");
7708 + return DSP_SOK;
7709 + } else if ((pDevContext->dwBrdState == BRD_RUNNING)) {
7710 + /* Update the OPP value in shared memory */
7711 + IO_SHMsetting(hIOMgr, SHM_CURROPP, &level);
7712 + /* Send a post notification to DSP */
7713 + IO_InterruptDSP2(pDevContext, MBX_PM_SETPOINT_POSTNOTIFY);
7714 + DBG_Trace(DBG_LEVEL7,
7715 + "PostScale_DSP: Wrote to shared memory Sent post"
7716 + " notification to DSP\n");
7717 + return DSP_SOK;
7718 + } else {
7719 + DBG_Trace(DBG_LEVEL7, "PostScale_DSP: Failed - DSP BRD state "
7720 + "in wrong state");
7721 + return DSP_EFAIL;
7723 +#endif /* CONFIG_DISABLE_BRIDGE_DVFS */
7724 +#endif /* CONFIG_DISABLE_BRIDGE_PM */
7725 + return DSP_SOK;
7729 + * ========DSP_PeripheralClocks_Disable========
7730 + * Disables all the peripheral clocks that were requested by DSP
7731 + */
7732 +DSP_STATUS DSP_PeripheralClocks_Disable(struct WMD_DEV_CONTEXT *pDevContext,
7733 + IN void *pArgs)
7736 + u32 clkIdx;
7737 + DSP_STATUS status = DSP_SOK;
7739 + for (clkIdx = 0; clkIdx < MBX_PM_MAX_RESOURCES; clkIdx++) {
7740 + if (((pDevContext->uDspPerClks) >> clkIdx) & 0x01) {
7741 + /* Disables the interface clock of the peripheral */
7742 + status = CLK_Disable(BPWR_Clks[clkIdx].intClk);
7743 + if (DSP_FAILED(status)) {
7744 + DBG_Trace(DBG_LEVEL7,
7745 + "Failed to Enable the DSP Peripheral"
7746 + "Clk 0x%x \n", BPWR_Clks[clkIdx]);
7748 + /* Disables the functional clock of the periphearl */
7749 + status = CLK_Disable(BPWR_Clks[clkIdx].funClk);
7750 + if (DSP_FAILED(status)) {
7751 + DBG_Trace(DBG_LEVEL7,
7752 + "Failed to Enable the DSP Peripheral"
7753 + "Clk 0x%x \n", BPWR_Clks[clkIdx]);
7757 + return status;
7761 + * ========DSP_PeripheralClocks_Enable========
7762 + * Enables all the peripheral clocks that were requested by DSP
7763 + */
7764 +DSP_STATUS DSP_PeripheralClocks_Enable(struct WMD_DEV_CONTEXT *pDevContext,
7765 + IN void *pArgs)
7767 + u32 clkIdx;
7768 + DSP_STATUS status = DSP_SOK;
7770 + for (clkIdx = 0; clkIdx < MBX_PM_MAX_RESOURCES; clkIdx++) {
7771 + if (((pDevContext->uDspPerClks) >> clkIdx) & 0x01) {
7772 + /* Enable the interface clock of the peripheral */
7773 + status = CLK_Enable(BPWR_Clks[clkIdx].intClk);
7774 + if (DSP_FAILED(status)) {
7775 + DBG_Trace(DBG_LEVEL7,
7776 + "Failed to Enable the DSP Peripheral"
7777 + "Clk 0x%x \n", BPWR_Clks[clkIdx]);
7779 + /* Enable the functional clock of the periphearl */
7780 + status = CLK_Enable(BPWR_Clks[clkIdx].funClk);
7781 + if (DSP_FAILED(status)) {
7782 + DBG_Trace(DBG_LEVEL7,
7783 + "Failed to Enable the DSP Peripheral"
7784 + "Clk 0x%x \n", BPWR_Clks[clkIdx]);
7788 + return status;
7793 Index: lk/drivers/dsp/bridge/wmd/tiomap_io.c
7794 ===================================================================
7795 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
7796 +++ lk/drivers/dsp/bridge/wmd/tiomap_io.c 2008-08-18 10:38:38.000000000 +0300
7797 @@ -0,0 +1,430 @@
7799 + * linux/drivers/dsp/bridge/wmd/linux/omap/common/tiomap_io.c
7801 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
7803 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
7805 + * This package is free software; you can redistribute it and/or modify
7806 + * it under the terms of the GNU General Public License version 2 as
7807 + * published by the Free Software Foundation.
7809 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
7810 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
7811 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
7812 + */
7816 + * ======== _tiomap_io.c ========
7817 + * Description:
7818 + * Implementation for the io read/write routines.
7820 + *! Revision History
7821 + *! ================
7822 + *! 16-Feb-2004 vp: Fixed warning in WriteDspData function.
7823 + *! 16-Apr-2003 vp: Added support for TC word swap
7824 + *! 26-Feb-2003 vp: Fixed issue with EXT_BEG and EXT_END address.
7825 + *! 24-Feb-2003 vp: Ported to Linux platform
7826 + *! 08-Oct-2002 rr: Created.
7827 + */
7829 +/* ----------------------------------- DSP/BIOS Bridge */
7830 +#include <dbdefs.h>
7831 +#include <errbase.h>
7833 +/* ----------------------------------- Trace & Debug */
7834 +#include <dbc.h>
7835 +#include <dbg.h>
7837 +/* ----------------------------------- Platform Manager */
7838 +#include <dev.h>
7839 +#include <drv.h>
7841 +/* ----------------------------------- OS Adaptation Layer */
7842 +#include <mem.h>
7843 +#include <util.h>
7844 +#include <cfg.h>
7846 +/* ----------------------------------- specific to this file */
7847 +#include "_tiomap.h"
7848 +#include "_tiomap_pwr.h"
7849 +#include "tiomap_io.h"
7851 +static u32 ulExtBase;
7852 +static u32 ulExtEnd;
7854 +static u32 ulShm0End;
7855 +static u32 ulDynExtBase;
7856 +u32 ulTraceSecBeg;
7857 +u32 ulTraceSecEnd;
7858 +u32 ulShmBaseVirt;
7860 +bool bSymbolsReloaded = true;
7863 + * ======== ReadExtDspData ========
7864 + * Copies DSP external memory buffers to the host side buffers.
7865 + */
7866 +DSP_STATUS ReadExtDspData(struct WMD_DEV_CONTEXT *hDevContext,
7867 + OUT u8 *pbHostBuf, u32 dwDSPAddr,
7868 + u32 ulNumBytes, u32 ulMemType)
7870 + DSP_STATUS status = DSP_SOK;
7871 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
7872 + u32 offset;
7873 + static u32 ulShmBaseVirt;
7874 + u32 ulTLBBaseVirt = 0;
7875 + u32 ulShmOffsetVirt = 0;
7876 + static u32 ulTraceSecBeg;
7877 + static u32 ulTraceSecEnd;
7878 + u32 dwExtProgVirtMem;
7879 + u32 dwBaseAddr = pDevContext->dwDspExtBaseAddr;
7880 + bool bTraceRead = false;
7882 + DBG_Trace(DBG_ENTER, "ReadExtDspData,"
7883 + "hDevContext: 0x%x\n\t\tpbHostBuf: 0x%x"
7884 + "\n\t\tdwDSPAddr: 0x%x\n\t\tulNumBytes: 0x%x\n\t\t"
7885 + "ulMemType: 0x%x\n", pDevContext, pbHostBuf, dwDSPAddr,
7886 + ulNumBytes, ulMemType);
7888 + if (!ulShmBaseVirt) {
7889 + status = DEV_GetSymbol(pDevContext->hDevObject,
7890 + SHMBASENAME, &ulShmBaseVirt);
7892 + DBC_Assert(ulShmBaseVirt != 0);
7894 + /* Check if it is a read of Trace section */
7895 + if (!ulTraceSecBeg) {
7896 + status = DEV_GetSymbol(pDevContext->hDevObject,
7897 + DSP_TRACESEC_BEG, &ulTraceSecBeg);
7899 + DBC_Assert(ulTraceSecBeg != 0);
7901 + if (DSP_SUCCEEDED(status) && !ulTraceSecEnd) {
7902 + status = DEV_GetSymbol(pDevContext->hDevObject,
7903 + DSP_TRACESEC_END, &ulTraceSecEnd);
7905 + DBC_Assert(ulTraceSecEnd != 0);
7907 + if (DSP_SUCCEEDED(status)) {
7908 + if ((dwDSPAddr <= ulTraceSecEnd) &&
7909 + (dwDSPAddr >= ulTraceSecBeg)) {
7910 + DBG_Trace(DBG_LEVEL5, "Reading from DSP Trace"
7911 + "section 0x%x \n", dwDSPAddr);
7912 + bTraceRead = true;
7916 + /* If reading from TRACE, force remap/unmap */
7917 + if ((bTraceRead) && dwBaseAddr) {
7918 + dwBaseAddr = 0;
7919 + pDevContext->dwDspExtBaseAddr = 0;
7922 + if (!dwBaseAddr) {
7923 + /* Initialize ulExtBase and ulExtEnd */
7924 + ulExtBase = 0;
7925 + ulExtEnd = 0;
7927 + /* Get DYNEXT_BEG, EXT_BEG and EXT_END.*/
7928 + if (DSP_SUCCEEDED(status) && !ulDynExtBase) {
7929 + status = DEV_GetSymbol(pDevContext->hDevObject,
7930 + DYNEXTBASE, &ulDynExtBase);
7932 + DBC_Assert(ulDynExtBase != 0);
7934 + if (DSP_SUCCEEDED(status)) {
7935 + status = DEV_GetSymbol(pDevContext->hDevObject,
7936 + EXTBASE, &ulExtBase);
7938 + DBC_Assert(ulExtBase != 0);
7940 + if (DSP_SUCCEEDED(status)) {
7941 + status = DEV_GetSymbol(pDevContext->hDevObject,
7942 + EXTEND, &ulExtEnd);
7944 + DBC_Assert(ulExtEnd != 0);
7946 + /* Trace buffer is right after the SHM SEG0,
7947 + * so set the base address to SHMBASE */
7948 + if (bTraceRead) {
7949 + ulExtBase = ulShmBaseVirt;
7950 + ulExtEnd = ulTraceSecEnd;
7953 + DBC_Assert(ulExtEnd != 0);
7954 + DBC_Assert(ulExtEnd > ulExtBase);
7956 + if (ulExtEnd < ulExtBase)
7957 + status = DSP_EFAIL;
7959 + if (DSP_SUCCEEDED(status)) {
7960 + ulTLBBaseVirt =
7961 + pDevContext->aTLBEntry[0].ulDspVa * DSPWORDSIZE;
7962 + DBC_Assert(ulTLBBaseVirt <= ulShmBaseVirt);
7963 + dwExtProgVirtMem = pDevContext->aTLBEntry[0].ulGppVa;
7965 + if (bTraceRead) {
7966 + DBG_Trace(DBG_LEVEL7, "ReadExtDspData: "
7967 + "GPP VA pointing to SHMMEMBASE 0x%x \n",
7968 + dwExtProgVirtMem);
7969 + } else {
7970 + ulShmOffsetVirt = ulShmBaseVirt - ulTLBBaseVirt;
7971 + ulShmOffsetVirt += PG_ALIGN_HIGH(ulExtEnd -
7972 + ulDynExtBase + 1,
7973 + HW_PAGE_SIZE_64KB);
7974 + dwExtProgVirtMem -= ulShmOffsetVirt;
7975 + dwExtProgVirtMem += (ulExtBase - ulDynExtBase);
7976 + DBG_Trace(DBG_LEVEL7, "ReadExtDspData: "
7977 + "GPP VA pointing to EXTMEMBASE 0x%x \n",
7978 + dwExtProgVirtMem);
7979 + pDevContext->dwDspExtBaseAddr =
7980 + dwExtProgVirtMem;
7982 + /* This dwDspExtBaseAddr will get cleared only when the board is
7983 + * stopped. */
7984 + if (!pDevContext->dwDspExtBaseAddr) {
7985 + status = DSP_EFAIL;
7986 + DBG_Trace(DBG_LEVEL7, "ReadExtDspData: "
7987 + "failed to Map the program memory\n");
7991 + dwBaseAddr = dwExtProgVirtMem;
7995 + if (!dwBaseAddr || !ulExtBase || !ulExtEnd) {
7996 + DBG_Trace(DBG_LEVEL7,
7997 + "Symbols missing for Ext Prog reading \n");
7998 + status = DSP_EFAIL;
8001 + offset = dwDSPAddr - ulExtBase;
8003 + if (DSP_SUCCEEDED(status))
8004 + memcpy(pbHostBuf, (u8 *)dwBaseAddr+offset, ulNumBytes);
8006 + return status;
8009 + * ======== WriteDspData ========
8010 + * purpose:
8011 + * Copies buffers to the DSP internal/external memory.
8012 + */
8013 +DSP_STATUS WriteDspData(struct WMD_DEV_CONTEXT *hDevContext, IN u8 *pbHostBuf,
8014 + u32 dwDSPAddr, u32 ulNumBytes, u32 ulMemType)
8016 + u32 offset;
8017 + u32 dwBaseAddr = hDevContext->dwDspBaseAddr;
8018 + struct CFG_HOSTRES resources;
8019 + DSP_STATUS status;
8020 + u32 base1, base2, base3;
8021 + base1 = OMAP_DSP_MEM1_SIZE;
8022 + base2 = OMAP_DSP_MEM2_BASE - OMAP_DSP_MEM1_BASE;
8023 + base3 = OMAP_DSP_MEM3_BASE - OMAP_DSP_MEM1_BASE;
8024 + DBG_Trace(DBG_ENTER, "Entered WriteDspData \n");
8026 + status = CFG_GetHostResources(
8027 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources);
8029 + offset = dwDSPAddr - hDevContext->dwDSPStartAdd;
8030 + if (offset < base1) {
8031 + dwBaseAddr = MEM_LinearAddress(resources.dwMemBase[2],
8032 + resources.dwMemLength[2]);
8033 + } else if (offset > base1 && offset < base2+OMAP_DSP_MEM2_SIZE) {
8034 + dwBaseAddr = MEM_LinearAddress(resources.dwMemBase[3],
8035 + resources.dwMemLength[3]);
8036 + offset = offset - base2;
8037 + } else if (offset >= base2+OMAP_DSP_MEM2_SIZE &&
8038 + offset < base3 + OMAP_DSP_MEM3_SIZE) {
8039 + dwBaseAddr = MEM_LinearAddress(resources.dwMemBase[4],
8040 + resources.dwMemLength[4]);
8041 + offset = offset - base3;
8042 + } else{
8043 + status = DSP_EFAIL;
8044 + return status;
8046 + if (ulNumBytes)
8047 + memcpy((u8 *) (dwBaseAddr+offset), pbHostBuf, ulNumBytes);
8048 + else
8049 + *((u32 *) pbHostBuf) = dwBaseAddr+offset;
8051 + return status;
8055 + * ======== WriteExtDspData ========
8056 + * purpose:
8057 + * Copies buffers to the external memory.
8059 + */
8060 +DSP_STATUS WriteExtDspData(struct WMD_DEV_CONTEXT *pDevContext,
8061 + IN u8 *pbHostBuf, u32 dwDSPAddr, u32 ulNumBytes,
8062 + u32 ulMemType, bool bDynamicLoad)
8064 + u32 dwBaseAddr = pDevContext->dwDspExtBaseAddr;
8065 + u32 dwOffset = 0;
8066 + u8 bTempByte1, bTempByte2;
8067 + u8 remainByte[4];
8068 + s32 i;
8069 + DSP_STATUS retVal = DSP_SOK;
8070 + u32 dwExtProgVirtMem;
8071 + u32 ulTLBBaseVirt = 0;
8072 + u32 ulShmOffsetVirt = 0;
8073 + struct CFG_HOSTRES hostRes;
8074 + bool bTraceLoad = false;
8075 + bTempByte1 = 0x0;
8076 + bTempByte2 = 0x0;
8078 + DBG_Trace(DBG_ENTER, "Entered WriteExtDspData dwDSPAddr 0x%x "
8079 + "ulNumBytes 0x%x \n", dwDSPAddr, ulNumBytes);
8080 + if (bSymbolsReloaded) {
8081 + /* Check if it is a load to Trace section */
8082 + retVal = DEV_GetSymbol(pDevContext->hDevObject,
8083 + DSP_TRACESEC_BEG, &ulTraceSecBeg);
8084 + if (DSP_SUCCEEDED(retVal))
8085 + retVal = DEV_GetSymbol(pDevContext->hDevObject,
8086 + DSP_TRACESEC_END, &ulTraceSecEnd);
8088 + if (DSP_SUCCEEDED(retVal)) {
8089 + if ((dwDSPAddr <= ulTraceSecEnd) &&
8090 + (dwDSPAddr >= ulTraceSecBeg)) {
8091 + DBG_Trace(DBG_LEVEL5, "Writing to DSP Trace "
8092 + "section 0x%x \n", dwDSPAddr);
8093 + bTraceLoad = true;
8097 + /* If dynamic, force remap/unmap */
8098 + if ((bDynamicLoad || bTraceLoad) && dwBaseAddr) {
8099 + dwBaseAddr = 0;
8100 + MEM_UnmapLinearAddress((void *)pDevContext->dwDspExtBaseAddr);
8101 + pDevContext->dwDspExtBaseAddr = 0x0;
8103 + if (!dwBaseAddr) {
8104 + if (bSymbolsReloaded)
8105 + /* Get SHM_BEG EXT_BEG and EXT_END. */
8106 + retVal = DEV_GetSymbol(pDevContext->hDevObject,
8107 + SHMBASENAME, &ulShmBaseVirt);
8108 + DBC_Assert(ulShmBaseVirt != 0);
8109 + if (bDynamicLoad) {
8110 + if (DSP_SUCCEEDED(retVal)) {
8111 + if (bSymbolsReloaded)
8112 + retVal = DEV_GetSymbol(pDevContext->
8113 + hDevObject, DYNEXTBASE,
8114 + &ulExtBase);
8116 + DBC_Assert(ulExtBase != 0);
8117 + if (DSP_SUCCEEDED(retVal)) {
8118 + /* DR OMAPS00013235 : DLModules array may be
8119 + * in EXTMEM. It is expected that DYNEXTMEM and
8120 + * EXTMEM are contiguous, so checking for the
8121 + * upper bound at EXTEND should be Ok. */
8122 + if (bSymbolsReloaded)
8123 + retVal = DEV_GetSymbol(pDevContext->
8124 + hDevObject, EXTEND, &ulExtEnd);
8126 + } else {
8127 + if (bSymbolsReloaded) {
8128 + if (DSP_SUCCEEDED(retVal))
8129 + retVal = DEV_GetSymbol(pDevContext->
8130 + hDevObject, EXTBASE,
8131 + &ulExtBase);
8132 + DBC_Assert(ulExtBase != 0);
8133 + if (DSP_SUCCEEDED(retVal))
8134 + retVal = DEV_GetSymbol(pDevContext->
8135 + hDevObject, EXTEND, &ulExtEnd);
8138 + /* Trace buffer it right after the SHM SEG0, so set the
8139 + * base address to SHMBASE */
8140 + if (bTraceLoad)
8141 + ulExtBase = ulShmBaseVirt;
8143 + DBC_Assert(ulExtEnd != 0);
8144 + DBC_Assert(ulExtEnd > ulExtBase);
8145 + if (ulExtEnd < ulExtBase)
8146 + retVal = DSP_EFAIL;
8148 + if (DSP_SUCCEEDED(retVal)) {
8149 + ulTLBBaseVirt = pDevContext->aTLBEntry[0].ulDspVa *
8150 + DSPWORDSIZE;
8151 + DBC_Assert(ulTLBBaseVirt <= ulShmBaseVirt);
8153 + if (bSymbolsReloaded) {
8154 + if (DSP_SUCCEEDED(retVal)) {
8155 + retVal = DEV_GetSymbol(pDevContext->
8156 + hDevObject, DSP_TRACESEC_END,
8157 + &ulShm0End);
8159 + if (DSP_SUCCEEDED(retVal)) {
8160 + retVal = DEV_GetSymbol(pDevContext->
8161 + hDevObject, DYNEXTBASE,
8162 + &ulDynExtBase);
8165 + ulShmOffsetVirt = ulShmBaseVirt - ulTLBBaseVirt;
8166 + if (bTraceLoad) {
8167 + dwExtProgVirtMem = pDevContext->aTLBEntry[0].
8168 + ulGppVa;
8169 + } else {
8170 + CFG_GetHostResources(
8171 + (struct CFG_DEVNODE *)
8172 + DRV_GetFirstDevExtension(), &hostRes);
8173 + dwExtProgVirtMem = hostRes.dwMemBase[1];
8174 + dwExtProgVirtMem += (ulExtBase - ulDynExtBase);
8176 + DBG_Trace(DBG_LEVEL7, "WriteExtDspData: GPP VA "
8177 + "pointing to EXTMEMBASE 0x%x \n",
8178 + dwExtProgVirtMem);
8180 + pDevContext->dwDspExtBaseAddr =
8181 + (u32)MEM_LinearAddress((void *)
8182 + TO_VIRTUAL_UNCACHED(dwExtProgVirtMem), ulExtEnd
8183 + - ulExtBase);
8184 + dwBaseAddr += pDevContext->dwDspExtBaseAddr;
8185 + /* This dwDspExtBaseAddr will get cleared only when
8186 + * the board is stopped. */
8187 + if (!pDevContext->dwDspExtBaseAddr) {
8188 + retVal = DSP_EFAIL;
8189 + DBG_Trace(DBG_LEVEL7, "WriteExtDspData: failed "
8190 + "to Map the program memory\n");
8194 + if (!dwBaseAddr || !ulExtBase || !ulExtEnd) {
8195 + DBG_Trace(DBG_LEVEL7, "Symbols missing for Ext Prog loading\n");
8196 + retVal = DSP_EFAIL;
8198 + if (DSP_SUCCEEDED(retVal)) {
8199 + for (i = 0; i < 4; i++)
8200 + remainByte[i] = 0x0;
8202 + dwOffset = dwDSPAddr - ulExtBase;
8203 + /* Also make sure the dwDSPAddr is < ulExtEnd */
8204 + if (dwDSPAddr > ulExtEnd || dwOffset > dwDSPAddr) {
8205 + DBG_Trace(DBG_LEVEL7, "We can not load at this address "
8206 + "dwDSPAddr=0x%x, ulExt/DynBase=0x%x, "
8207 + "ulExtEnd=0x%x\n", dwDSPAddr, ulExtBase,
8208 + ulExtEnd);
8209 + retVal = DSP_EFAIL;
8212 + if (DSP_SUCCEEDED(retVal)) {
8213 + if (ulNumBytes)
8214 + memcpy((u8 *) dwBaseAddr + dwOffset, pbHostBuf,
8215 + ulNumBytes);
8216 + else
8217 + *((u32 *) pbHostBuf) = dwBaseAddr+dwOffset;
8219 + /* Unmap here to force remap for other Ext loads */
8220 + if ((bDynamicLoad || bTraceLoad) && pDevContext->dwDspExtBaseAddr) {
8221 + MEM_UnmapLinearAddress((void *) pDevContext->dwDspExtBaseAddr);
8222 + pDevContext->dwDspExtBaseAddr = 0x0;
8224 + bSymbolsReloaded = false;
8225 + return retVal;
8228 Index: lk/drivers/dsp/bridge/wmd/tiomap_io.h
8229 ===================================================================
8230 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
8231 +++ lk/drivers/dsp/bridge/wmd/tiomap_io.h 2008-08-18 10:38:38.000000000 +0300
8232 @@ -0,0 +1,112 @@
8234 + * linux/drivers/dsp/bridge/wmd/linux/omap/common/tiomap_io.h
8236 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
8238 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
8240 + * This package is free software; you can redistribute it and/or modify
8241 + * it under the terms of the GNU General Public License version 2 as
8242 + * published by the Free Software Foundation.
8244 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
8245 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
8246 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
8247 + */
8251 + * ======== _tiomap_io.h ========
8252 + * Description:
8253 + * Definitions, types and function prototypes for the io
8254 + * (r/w external mem).
8256 + *! Revision History
8257 + *! ================
8258 + *! 08-Oct-2002 rr: Created.
8259 + */
8261 +#ifndef _TIOMAP_IO_
8262 +#define _TIOMAP_IO_
8265 + * Symbol that defines beginning of shared memory.
8266 + * For OMAP (Helen) this is the DSP Virtual base address of SDRAM.
8267 + * This will be used to program DSP MMU to map DSP Virt to GPP phys.
8268 + * (see dspMmuTlbEntry()).
8269 + */
8270 +#define SHMBASENAME "SHM_BEG"
8271 +#define EXTBASE "EXT_BEG"
8272 +#define EXTEND "_EXT_END"
8273 +#define DYNEXTBASE "_DYNEXT_BEG"
8274 +#define DYNEXTEND "_DYNEXT_END"
8275 +#define IVAEXTMEMBASE "_IVAEXTMEM_BEG"
8276 +#define IVAEXTMEMEND "_IVAEXTMEM_END"
8279 +#define DSP_TRACESEC_BEG "_BRIDGE_TRACE_BEG"
8280 +#define DSP_TRACESEC_END "_BRIDGE_TRACE_END"
8282 +#define SYS_PUTCBEG "_SYS_PUTCBEG"
8283 +#define SYS_PUTCEND "_SYS_PUTCEND"
8284 +#define BRIDGE_SYS_PUTC_current "_BRIDGE_SYS_PUTC_current"
8287 +#define WORDSWAP_ENABLE 0x3 /* Enable word swap */
8290 + * ======== ReadExtDspData ========
8291 + * Reads it from DSP External memory. The external memory for the DSP
8292 + * is configured by the combination of DSP MMU and SHM Memory manager in the CDB
8293 + */
8294 +extern DSP_STATUS ReadExtDspData(struct WMD_DEV_CONTEXT *pDevContext,
8295 + OUT u8 *pbHostBuf, u32 dwDSPAddr,
8296 + u32 ulNumBytes, u32 ulMemType);
8299 + * ======== WriteDspData ========
8300 + */
8301 +extern DSP_STATUS WriteDspData(struct WMD_DEV_CONTEXT *pDevContext,
8302 + OUT u8 *pbHostBuf, u32 dwDSPAddr,
8303 + u32 ulNumBytes, u32 ulMemType);
8306 + * ======== WriteExtDspData ========
8307 + * Writes to the DSP External memory for external program.
8308 + * The ext mem for progra is configured by the combination of DSP MMU and
8309 + * SHM Memory manager in the CDB
8310 + */
8311 +extern DSP_STATUS WriteExtDspData(struct WMD_DEV_CONTEXT *pDevContext,
8312 + IN u8 *pbHostBuf, u32 dwDSPAddr,
8313 + u32 ulNumBytes, u32 ulMemType,
8314 + bool bDynamicLoad);
8317 + * ======== WriteExt32BitDspData ========
8318 + * Writes 32 bit data to the external memory
8319 + */
8320 +extern inline void WriteExt32BitDspData(IN const
8321 + struct WMD_DEV_CONTEXT *pDevContext, IN u32 dwDSPAddr,
8322 + IN u32 val)
8324 + *(u32 *)dwDSPAddr = ((pDevContext->tcWordSwapOn) ? (((val << 16) &
8325 + 0xFFFF0000) | ((val >> 16) & 0x0000FFFF)) : val);
8329 + * ======== ReadExt32BitDspData ========
8330 + * Reads 32 bit data from the external memory
8331 + */
8332 +extern inline u32 ReadExt32BitDspData(IN const struct WMD_DEV_CONTEXT
8333 + *pDevContext, IN u32 dwDSPAddr)
8335 + u32 retVal;
8336 + retVal = *(u32 *)dwDSPAddr;
8338 + retVal = ((pDevContext->tcWordSwapOn) ? (((retVal << 16)
8339 + & 0xFFFF0000) | ((retVal >> 16) & 0x0000FFFF)) : retVal);
8340 + return retVal;
8343 +#endif /* _TIOMAP_IO_ */
8345 Index: lk/drivers/dsp/bridge/wmd/tiomap_sm.c
8346 ===================================================================
8347 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
8348 +++ lk/drivers/dsp/bridge/wmd/tiomap_sm.c 2008-08-18 10:38:38.000000000 +0300
8349 @@ -0,0 +1,305 @@
8351 + * linux/drivers/dsp/bridge/wmd/linux/omap/2430/tiomap_sm.c
8353 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
8355 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
8357 + * This package is free software; you can redistribute it and/or modify
8358 + * it under the terms of the GNU General Public License version 2 as
8359 + * published by the Free Software Foundation.
8361 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
8362 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
8363 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
8364 + */
8367 + * ======== tiomap_sm.c ========
8368 + * Description:
8369 + * Implements lower edge channel class library functions.
8371 + *! Revision History:
8372 + *! ================
8373 + *! 05-Jan-2004 vp Updated for the new HW library for 24xx platform.
8374 + *! 12-Feb-2004 hp use 'CFG_GetHostResources' to fetch virtual addresses of
8375 + *! PRCM, dMMU components.
8376 + *! 08-Oct-2002 rr Renamed to tiomap1510_sm.c
8377 + *! 15-Feb-2002 ag Remove #include <pkfuncs.h> & util.h.
8378 + *! 07-Jan-2001 ag Set DSP MBX val (to DSP) contained in DEV context.
8379 + *! 05-Nov-2001 kc: Modified CHNLSM_ISR to read mailbox1 interrupt values
8380 + *! 26-Sep-2001 rr: InterruptDSP does not spin forever for retail build.
8381 + *! 29-Aug-2001 rr: Cleaned up the non referenced variables.
8382 + *! 26-Jul-2001 jeh Enable interrupt to DSP.
8383 + *! 28-Jun-2001 ag Disable INTR gen to DSP in CHNLSM_InterruptDSP().
8384 + *! 26-Jun-2001 ag Added INTR support.
8385 + *! 17-May-2000 ag Initial. No INTR support.
8386 + */
8388 +/* ----------------------------------- Host OS */
8389 +#include <host_os.h>
8390 +/* ----------------------------------- DSP/BIOS Bridge */
8391 +#include <std.h>
8392 +#include <dbdefs.h>
8393 +#include <errbase.h>
8395 +/* ----------------------------------- Trace & Debug */
8396 +#include <dbg.h>
8398 +/* ----------------------------------- OS Adaptation Layer */
8399 +#include <cfg.h>
8400 +#include <drv.h>
8401 +#include <isr.h>
8402 +#include <util.h>
8404 +/* ----------------------------------- Mini Driver */
8405 +#include <wmd.h>
8407 +/* ----------------------------------- Platform Manager */
8408 +#include <wcd.h>
8409 +#include <dev.h>
8411 +/* ------------------------------------ Hardware Abstraction Layer */
8412 +#include <hw_defs.h>
8413 +#include <hw_mbox.h>
8415 +/* ----------------------------------- This */
8416 +#include "_tiomap.h"
8417 +#include <chnl_sm.h>
8419 +#ifndef CONFIG_DISABLE_BRIDGE_PM
8420 +#ifndef CONFIG_DISABLE_BRIDGE_DVFS
8421 +#include <asm/arch/resource.h>
8422 +extern struct constraint_handle *dsp_constraint_handle;
8423 +#endif
8424 +#endif
8426 +/* ----------------------------------- Defines, Data Structures, Typedefs */
8427 +#ifndef DEBUG
8428 +#define TIHELEN_INT_TIMEOUT 1
8429 +#define LOOP_COUNT 1000000
8430 +extern u64 tiomap1510_liTicksPerSecond; /* Timer frequency */
8431 +#endif
8433 +extern struct MAILBOX_CONTEXT mboxsetting;
8434 +extern DSP_STATUS DSP_PeripheralClocks_Enable(struct WMD_DEV_CONTEXT
8435 + *pDevContext, IN void *pArgs);
8437 + * ======== CHNLSM_EnableInterrupt ========
8438 + * Enables interrupts from DSP.
8439 + */
8440 +DSP_STATUS CHNLSM_EnableInterrupt(struct WMD_DEV_CONTEXT *hDevContext)
8442 + DSP_STATUS status = DSP_SOK;
8443 + HW_STATUS hwStatus;
8444 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
8445 + u32 numMbxMsg;
8446 + u32 mbxValue;
8447 + struct CFG_HOSTRES resources;
8448 + u32 devType;
8449 + struct IO_MGR *hIOMgr;
8451 + DBG_Trace(DBG_ENTER, "CHNLSM_EnableInterrupt(0x%x)\n", pDevContext);
8453 + /* Read the messages in the mailbox until the message queue is empty */
8455 + status = CFG_GetHostResources(
8456 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(),
8457 + &resources);
8458 + status = DEV_GetDevType(pDevContext->hDevObject, &devType);
8459 + status = DEV_GetIOMgr(pDevContext->hDevObject, &hIOMgr);
8460 + if (devType == DSP_UNIT) {
8461 + hwStatus = HW_MBOX_NumMsgGet(resources.dwMboxBase,
8462 + MBOX_DSP2ARM, &numMbxMsg);
8463 + while (numMbxMsg != 0) {
8464 + hwStatus = HW_MBOX_MsgRead(resources.dwMboxBase,
8465 + MBOX_DSP2ARM,
8466 + &mbxValue);
8467 + numMbxMsg--;
8469 + /* clear the DSP mailbox as well...*/
8470 + hwStatus = HW_MBOX_NumMsgGet(resources.dwMboxBase,
8471 + MBOX_ARM2DSP, &numMbxMsg);
8472 + while (numMbxMsg != 0) {
8473 + hwStatus = HW_MBOX_MsgRead(resources.dwMboxBase,
8474 + MBOX_ARM2DSP, &mbxValue);
8475 + numMbxMsg--;
8476 + UTIL_Wait(10);
8478 + HW_MBOX_EventAck(resources.dwMboxBase, MBOX_ARM2DSP,
8479 + HW_MBOX_U1_DSP1,
8480 + HW_MBOX_INT_NEW_MSG);
8482 + /* Enable the new message events on this IRQ line */
8483 + hwStatus = HW_MBOX_EventEnable(resources.dwMboxBase,
8484 + MBOX_DSP2ARM,
8485 + MBOX_ARM,
8486 + HW_MBOX_INT_NEW_MSG);
8489 + return status;
8493 + * ======== CHNLSM_DisableInterrupt ========
8494 + * Disables interrupts from DSP.
8495 + */
8496 +DSP_STATUS CHNLSM_DisableInterrupt(struct WMD_DEV_CONTEXT *hDevContext)
8498 + DSP_STATUS status = DSP_SOK;
8499 + HW_STATUS hwStatus;
8500 + struct CFG_HOSTRES resources;
8502 + DBG_Trace(DBG_ENTER, "CHNLSM_DisableInterrupt(0x%x)\n", hDevContext);
8504 + status = CFG_GetHostResources(
8505 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(),
8506 + &resources);
8507 + hwStatus = HW_MBOX_EventDisable(resources.dwMboxBase, MBOX_DSP2ARM,
8508 + MBOX_ARM, HW_MBOX_INT_NEW_MSG);
8509 + return status;
8513 + * ======== CHNLSM_InterruptDSP ========
8514 + * Send an interrupt to the DSP processor(s).
8515 + */
8516 +DSP_STATUS CHNLSM_InterruptDSP(struct WMD_DEV_CONTEXT *hDevContext)
8518 + DSP_STATUS status = DSP_SOK;
8519 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
8521 +#ifndef CONFIG_DISABLE_BRIDGE_PM
8522 +#ifndef CONFIG_DISABLE_BRIDGE_DVFS
8523 + u32 opplevel;
8524 +#endif
8525 +#endif
8526 + HW_STATUS hwStatus;
8527 + u32 mbxFull;
8528 + struct CFG_HOSTRES resources;
8529 + u16 cnt = 10;
8530 + u32 temp;
8531 + /* We are waiting indefinitely here. This needs to be fixed in the
8532 + * second phase */
8533 + status = CFG_GetHostResources(
8534 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(),
8535 + &resources);
8537 + if (pDevContext->dwBrdState == BRD_DSP_HIBERNATION ||
8538 + pDevContext->dwBrdState == BRD_HIBERNATION) {
8539 + pDevContext->dwBrdState = BRD_RUNNING;
8540 +#ifndef CONFIG_DISABLE_BRIDGE_PM
8541 +#ifndef CONFIG_DISABLE_BRIDGE_DVFS
8542 + opplevel = constraint_get_level(dsp_constraint_handle);
8543 + /* If OPP is at minimum level, increase it before waking up
8544 + * the DSP */
8545 + if (opplevel == 1) {
8546 + if (constraint_set(dsp_constraint_handle,
8547 + (opplevel+1)) != 0) {
8548 + DBG_Trace(DBG_LEVEL7, "CHNLSM_InterruptDSP: "
8549 + "Constraint set failed\n");
8550 + return DSP_EFAIL;
8552 + DBG_Trace(DBG_LEVEL7, "CHNLSM_InterruptDSP:Setting "
8553 + "the vdd1 constraint level to %d before "
8554 + "waking DSP \n", (opplevel + 1));
8557 +#endif
8558 +#endif
8559 + /* Read MMU register to invoke short wakeup of DSP */
8560 + temp = (u32) *((REG_UWORD32 *) ((u32)
8561 + (resources.dwDmmuBase) + 0x10));
8563 + /* Restore mailbox settings */
8564 + status = HW_MBOX_restoreSettings(resources.dwMboxBase);
8565 + DBG_Trace(DBG_LEVEL6, "MailBoxSettings: SYSCONFIG = 0x%x\n",
8566 + mboxsetting.sysconfig);
8567 + DBG_Trace(DBG_LEVEL6, "MailBoxSettings: IRQENABLE0 = 0x%x\n",
8568 + mboxsetting.irqEnable0);
8569 + DBG_Trace(DBG_LEVEL6, "MailBoxSettings: IRQENABLE1 = 0x%x\n",
8570 + mboxsetting.irqEnable1);
8571 + /* Restart the peripheral clocks that were disabled */
8572 + DSP_PeripheralClocks_Enable(hDevContext, NULL);
8575 + while (--cnt) {
8576 + hwStatus = HW_MBOX_IsFull(resources.dwMboxBase,
8577 + MBOX_ARM2DSP, &mbxFull);
8578 + if (mbxFull)
8579 + UTIL_Wait(1000); /* wait for 1 ms) */
8580 + else
8581 + break;
8583 + if (!cnt) {
8584 + DBG_Trace(DBG_LEVEL7, "Timed out waiting for DSP mailbox \n");
8585 + status = WMD_E_TIMEOUT;
8586 + return status;
8588 + DBG_Trace(DBG_LEVEL3, "writing %x to Mailbox\n",
8589 + pDevContext->wIntrVal2Dsp);
8591 + hwStatus = HW_MBOX_MsgWrite(resources.dwMboxBase, MBOX_ARM2DSP,
8592 + pDevContext->wIntrVal2Dsp);
8593 + /* set the Mailbox interrupt to default value */
8594 + pDevContext->wIntrVal2Dsp = MBX_PCPY_CLASS;
8595 + return status;
8599 + * ======== CHNLSM_InterruptDSP2 ========
8600 + * Set MBX value & send an interrupt to the DSP processor(s).
8601 + */
8602 +DSP_STATUS CHNLSM_InterruptDSP2(struct WMD_DEV_CONTEXT *hDevContext,
8603 + u16 wMbVal)
8605 + struct WMD_DEV_CONTEXT *pDevContext = hDevContext;
8607 + pDevContext->wIntrVal2Dsp = wMbVal;
8609 + return CHNLSM_InterruptDSP(hDevContext);
8613 + * ======== CHNLSM_DPC ========
8614 + */
8615 +void CHNLSM_DPC(struct WMD_DEV_CONTEXT *hDevContext)
8617 + DBG_Trace(DBG_ENTER, "CHNLSM_DPC(0x%x)\n", hDevContext);
8621 + * ======== CHNLSM_ISR ========
8622 + */
8623 +bool CHNLSM_ISR(struct WMD_DEV_CONTEXT *hDevContext, OUT bool *pfSchedDPC,
8624 + OUT u16 *pwIntrVal)
8626 + bool fMyInterrupt = true; /*
8627 + * We own the mbx and
8628 + * we're not sharing it
8629 + */
8630 + struct CFG_HOSTRES resources;
8631 + u32 numMbxMsg;
8632 + u32 mbxValue;
8634 + DBG_Trace(DBG_ENTER, "CHNLSM_ISR(0x%x)\n", hDevContext);
8636 + CFG_GetHostResources(
8637 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(), &resources);
8639 + HW_MBOX_NumMsgGet(resources.dwMboxBase, MBOX_DSP2ARM, &numMbxMsg);
8641 + if (numMbxMsg > 0) {
8642 + HW_MBOX_MsgRead(resources.dwMboxBase, MBOX_DSP2ARM, &mbxValue);
8644 + HW_MBOX_EventAck(resources.dwMboxBase, MBOX_DSP2ARM,
8645 + HW_MBOX_U0_ARM, HW_MBOX_INT_NEW_MSG);
8647 + DBG_Trace(DBG_LEVEL3, "Read %x from Mailbox\n", mbxValue);
8648 + *pwIntrVal = (u16) mbxValue;
8650 + /* Set *pfSchedDPC to true; */
8651 + *pfSchedDPC = true;
8652 + return fMyInterrupt;
8655 Index: lk/drivers/dsp/bridge/wmd/ue_deh.c
8656 ===================================================================
8657 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
8658 +++ lk/drivers/dsp/bridge/wmd/ue_deh.c 2008-08-18 10:38:38.000000000 +0300
8659 @@ -0,0 +1,502 @@
8661 + * linux/drivers/dsp/bridge/wmd/linux/omap/common/ue_deh.c
8663 + * DSP-BIOS Bridge driver support functions for TI OMAP processors.
8665 + * Copyright (C) 2005-2006 Texas Instruments, Inc.
8667 + * This package is free software; you can redistribute it and/or modify
8668 + * it under the terms of the GNU General Public License version 2 as
8669 + * published by the Free Software Foundation.
8671 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
8672 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
8673 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
8674 + */
8678 + * ======== ue_deh.c ========
8679 + * Description:
8680 + * Implements upper edge DSP exception handling (DEH) functions.
8682 + *! Revision History:
8683 + *! ================
8684 + *! 03-Jan-2005 hn: Support for IVA DEH.
8685 + *! 05-Jan-2004 vp: Updated for the 24xx HW library.
8686 + *! 19-Feb-2003 vp: Code review updates.
8687 + *! - Cosmetic changes.
8688 + *! 18-Oct-2002 sb: Ported to Linux platform.
8689 + *! 10-Dec-2001 kc: Updated DSP error reporting in DEBUG mode.
8690 + *! 10-Sep-2001 kc: created.
8691 + */
8693 +/* ----------------------------------- Host OS */
8694 +#include <host_os.h>
8696 +/* ----------------------------------- DSP/BIOS Bridge */
8697 +#include <std.h>
8698 +#include <dbdefs.h>
8699 +#include <errbase.h>
8701 +/* ----------------------------------- Trace & Debug */
8702 +#include <dbc.h>
8703 +#include <dbg.h>
8705 +/* ----------------------------------- OS Adaptation Layer */
8706 +#include <csl.h>
8707 +#include <cfg.h>
8708 +#include <dpc.h>
8709 +#include <isr.h>
8710 +#include <mem.h>
8711 +#include <ntfy.h>
8712 +#include <drv.h>
8714 +/* ----------------------------------- Link Driver */
8715 +#include <wmddeh.h>
8717 +/* ----------------------------------- Platform Manager */
8718 +#include <dev.h>
8719 +#include <wcd.h>
8721 +/* ------------------------------------ Hardware Abstraction Layer */
8722 +#include <hw_defs.h>
8723 +#include <hw_mmu.h>
8725 +/* ----------------------------------- This */
8726 +#include "mmu_fault.h"
8727 +#include "_tiomap.h"
8728 +#include "_deh.h"
8729 +#include <_tiomap_mmu.h>
8731 +struct HW_MMUMapAttrs_t mapAttrs = { HW_LITTLE_ENDIAN, HW_ELEM_SIZE_16BIT,
8732 + HW_MMU_CPUES} ;
8733 +#define VirtToPhys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
8735 + * ======== WMD_DEH_Create ========
8736 + * Creates DEH manager object.
8737 + */
8738 +DSP_STATUS WMD_DEH_Create(OUT struct DEH_MGR **phDehMgr,
8739 + struct DEV_OBJECT *hDevObject)
8741 + DSP_STATUS status = DSP_SOK;
8742 + struct DEH_MGR *pDehMgr = NULL;
8743 + struct CFG_HOSTRES cfgHostRes;
8744 + struct CFG_DEVNODE *hDevNode;
8745 + struct WMD_DEV_CONTEXT *hWmdContext = NULL;
8747 + DBG_Trace(DBG_LEVEL1, "Entering DEH_Create: 0x%x\n", phDehMgr);
8748 + /* Message manager will be created when a file is loaded, since
8749 + * size of message buffer in shared memory is configurable in
8750 + * the base image. */
8751 + /* Get WMD context info. */
8752 + DEV_GetWMDContext(hDevObject, &hWmdContext);
8753 + DBC_Assert(hWmdContext);
8754 + /* Allocate IO manager object: */
8755 + MEM_AllocObject(pDehMgr, struct DEH_MGR, SIGNATURE);
8756 + if (pDehMgr == NULL) {
8757 + status = DSP_EMEMORY;
8758 + } else {
8759 + /* Create an NTFY object to manage notifications */
8760 + if (DSP_SUCCEEDED(status))
8761 + status = NTFY_Create(&pDehMgr->hNtfy);
8763 + /* Create a DPC object. */
8764 + status = DPC_Create(&pDehMgr->hMmuFaultDpc, MMU_FaultDpc,
8765 + (void *)pDehMgr);
8766 + if (DSP_SUCCEEDED(status))
8767 + status = DEV_GetDevNode(hDevObject, &hDevNode);
8769 + if (DSP_SUCCEEDED(status))
8770 + status = CFG_GetHostResources(hDevNode, &cfgHostRes);
8772 + if (DSP_SUCCEEDED(status)) {
8773 + /* Fill in context structure */
8774 + pDehMgr->hWmdContext = hWmdContext;
8775 + pDehMgr->errInfo.dwErrMask = 0L;
8776 + pDehMgr->errInfo.dwVal1 = 0L;
8777 + pDehMgr->errInfo.dwVal2 = 0L;
8778 + pDehMgr->errInfo.dwVal3 = 0L;
8779 + /* Install ISR function for DSP MMU fault */
8780 + status = ISR_Install(&pDehMgr->hMmuFaultIsr,
8781 + &cfgHostRes, (ISR_PROC)MMU_FaultIsr,
8782 + DSP_MMUFAULT, (void *)pDehMgr);
8785 + if (DSP_FAILED(status)) {
8786 + /* If create failed, cleanup */
8787 + WMD_DEH_Destroy((struct DEH_MGR *)pDehMgr);
8788 + *phDehMgr = NULL;
8789 + } else {
8790 + *phDehMgr = (struct DEH_MGR *)pDehMgr;
8792 + DBG_Trace(DBG_LEVEL1, "Exiting DEH_Create.\n");
8793 + return status;
8797 + * ======== WMD_DEH_Destroy ========
8798 + * Destroys DEH manager object.
8799 + */
8800 +DSP_STATUS WMD_DEH_Destroy(struct DEH_MGR *hDehMgr)
8802 + DSP_STATUS status = DSP_SOK;
8803 + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr;
8805 + DBG_Trace(DBG_LEVEL1, "Entering DEH_Destroy: 0x%x\n", pDehMgr);
8806 + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) {
8807 + /* If notification object exists, delete it */
8808 + if (pDehMgr->hNtfy)
8809 + (void)NTFY_Delete(pDehMgr->hNtfy);
8811 + /* Disable DSP MMU fault */
8812 + (void)ISR_Uninstall(pDehMgr->hMmuFaultIsr);
8813 + (void)DPC_Destroy(pDehMgr->hMmuFaultDpc);
8814 + /* Deallocate the DEH manager object */
8815 + MEM_FreeObject(pDehMgr);
8817 + DBG_Trace(DBG_LEVEL1, "Exiting DEH_Destroy.\n");
8818 + return status;
8822 + * ======== WMD_DEH_RegisterNotify ========
8823 + * Registers for DEH notifications.
8824 + */
8825 +DSP_STATUS WMD_DEH_RegisterNotify(struct DEH_MGR *hDehMgr, u32 uEventMask,
8826 + u32 uNotifyType,
8827 + struct DSP_NOTIFICATION *hNotification)
8829 + DSP_STATUS status = DSP_SOK;
8830 + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr;
8832 + DBG_Trace(DBG_LEVEL1, "Entering WMD_DEH_RegisterNotify: 0x%x\n",
8833 + pDehMgr);
8835 + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) {
8836 + status = NTFY_Register(pDehMgr->hNtfy, hNotification,
8837 + uEventMask, uNotifyType);
8839 + DBG_Trace(DBG_LEVEL1, "Exiting WMD_DEH_RegisterNotify.\n");
8840 + return status;
8845 + * ======== PackTraceBuffer ========
8846 + * Removes extra nulls from the trace buffer returned from the DSP.
8847 + * Works even on buffers that already are packed (null removed); but has
8848 + * one bug in that case -- loses the last character (replaces with '\0').
8849 + * Continues through conversion for full set of nBytes input characters.
8850 + * Parameters:
8851 + * lpBuf: Pointer to input/output buffer
8852 + * nBytes: Number of characters in the buffer
8853 + * ulNumWords: Number of DSP words in the buffer. Indicates potential
8854 + * number of extra carriage returns to generate.
8855 + * Returns:
8856 + * DSP_SOK: Success.
8857 + * DSP_EMEMORY: Unable to allocate memory.
8858 + * Requires:
8859 + * lpBuf must be a fully allocated writable block of at least nBytes.
8860 + * There are no more than ulNumWords extra characters needed (the number of
8861 + * linefeeds minus the number of NULLS in the input buffer).
8862 + */
8863 +#if ((defined DEBUG) || (defined DDSP_DEBUG_PRODUCT))\
8864 + && GT_TRACE
8865 +static DSP_STATUS PackTraceBuffer(char *lpBuf, u32 nBytes, u32 ulNumWords)
8867 + DSP_STATUS status = DSP_SOK;
8869 + char *lpTmpBuf;
8870 + char *lpBufStart;
8871 + char *lpTmpStart;
8872 + u32 nCnt;
8873 + char thisChar;
8875 + /* tmp workspace, 1 KB longer than input buf */
8876 + lpTmpBuf = MEM_Calloc((nBytes + ulNumWords), MEM_PAGED);
8877 + if (lpTmpBuf == NULL) {
8878 + DBG_Trace(DBG_LEVEL7, "PackTrace buffer:OutofMemory \n");
8879 + status = DSP_EMEMORY;
8882 + if (DSP_SUCCEEDED(status)) {
8883 + lpBufStart = lpBuf;
8884 + lpTmpStart = lpTmpBuf;
8885 + for (nCnt = nBytes; nCnt > 0; nCnt--) {
8886 + thisChar = *lpBuf++;
8887 + switch (thisChar) {
8888 + case '\0': /* Skip null bytes */
8889 + break;
8890 + case '\n': /* Convert \n to \r\n */
8891 + /* NOTE: do not reverse order; Some OS */
8892 + /* editors control doesn't understand "\n\r" */
8893 + *lpTmpBuf++ = '\r';
8894 + *lpTmpBuf++ = '\n';
8895 + break;
8896 + default: /* Copy in the actual ascii byte */
8897 + *lpTmpBuf++ = thisChar;
8898 + break;
8901 + *lpTmpBuf = '\0'; /* Make sure tmp buf is null terminated */
8902 + /* Cut output down to input buf size */
8903 + CSL_Strcpyn(lpBufStart, lpTmpStart, nBytes);
8904 + /*Make sure output is null terminated */
8905 + lpBufStart[nBytes - 1] = '\0';
8906 + MEM_Free(lpTmpStart);
8909 + return status;
8911 +#endif /* ((defined DEBUG) || (defined DDSP_DEBUG_PRODUCT)) && GT_TRACE */
8914 + * ======== PrintDspTraceBuffer ========
8915 + * Prints the trace buffer returned from the DSP (if DBG_Trace is enabled).
8916 + * Parameters:
8917 + * hDehMgr: Handle to DEH manager object
8918 + * number of extra carriage returns to generate.
8919 + * Returns:
8920 + * DSP_SOK: Success.
8921 + * DSP_EMEMORY: Unable to allocate memory.
8922 + * Requires:
8923 + * hDehMgr muse be valid. Checked in WMD_DEH_Notify.
8924 + */
8925 +DSP_STATUS PrintDspTraceBuffer(struct DEH_MGR *hDehMgr)
8927 + DSP_STATUS status = DSP_SOK;
8929 +#if ((defined DEBUG) || (defined DDSP_DEBUG_PRODUCT))\
8930 + && GT_TRACE
8932 + struct COD_MANAGER *hCodMgr;
8933 + u32 ulTraceEnd;
8934 + u32 ulTraceBegin;
8935 + u32 ulNumBytes = 0;
8936 + u32 ulNumWords = 0;
8937 + u32 ulWordSize = 2;
8938 + CONST u32 uMaxSize = 512;
8939 + char *pszBuf;
8940 + u16 *lpszBuf;
8941 + struct WMD_DRV_INTERFACE *pIntfFxns;
8942 + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr;
8943 + struct DEV_OBJECT *hDevObject = ((struct WMD_DEV_CONTEXT *)
8944 + pDehMgr->hWmdContext)->hDevObject;
8946 + status = DEV_GetCodMgr(hDevObject, &hCodMgr);
8947 + if (DSP_FAILED(status)) {
8948 + DBG_Trace(DBG_LEVEL7,
8949 + "PrintDspTraceBuffer: Failed on DEV_GetCodMgr.\n");
8952 + if (DSP_SUCCEEDED(status)) {
8953 + /* Look for SYS_PUTCBEG/SYS_PUTCEND: */
8954 + status = COD_GetSymValue(hCodMgr, COD_TRACEBEG, &ulTraceBegin);
8955 + DBG_Trace(DBG_LEVEL1,
8956 + "PrintDspTraceBuffer: ulTraceBegin Value 0x%x\n",
8957 + ulTraceBegin);
8958 + if (DSP_FAILED(status)) {
8959 + DBG_Trace(DBG_LEVEL7, "PrintDspTraceBuffer: Failed on "
8960 + "COD_GetSymValue.\n");
8963 + if (DSP_SUCCEEDED(status)) {
8964 + status = COD_GetSymValue(hCodMgr, COD_TRACEEND, &ulTraceEnd);
8965 + DBG_Trace(DBG_LEVEL1,
8966 + "PrintDspTraceBuffer: ulTraceEnd Value 0x%x\n",
8967 + ulTraceEnd);
8968 + if (DSP_FAILED(status)) {
8969 + DBG_Trace(DBG_LEVEL7, "PrintDspTraceBuffer: Failed on "
8970 + "COD_GetSymValue.\n");
8973 + if (DSP_SUCCEEDED(status)) {
8974 + ulNumBytes = (ulTraceEnd - ulTraceBegin) * ulWordSize;
8975 + /* If the chip type is 55 then the addresses will be
8976 + * byte addresses; convert them to word addresses. */
8977 + if (ulNumBytes > uMaxSize)
8978 + ulNumBytes = uMaxSize;
8980 + /* make sure the data we request fits evenly */
8981 + ulNumBytes = (ulNumBytes / ulWordSize) * ulWordSize;
8982 + DBG_Trace(DBG_LEVEL1, "PrintDspTraceBuffer: ulNumBytes 0x%x\n",
8983 + ulNumBytes);
8984 + ulNumWords = ulNumBytes * ulWordSize;
8985 + DBG_Trace(DBG_LEVEL1, "PrintDspTraceBuffer: ulNumWords 0x%x\n",
8986 + ulNumWords);
8987 + status = DEV_GetIntfFxns(hDevObject, &pIntfFxns);
8991 + if (DSP_SUCCEEDED(status)) {
8992 + pszBuf = MEM_Calloc(uMaxSize, MEM_NONPAGED);
8993 + lpszBuf = MEM_Calloc(ulNumBytes * 2, MEM_NONPAGED);
8994 + if (pszBuf != NULL) {
8995 + /* Read bytes from the DSP trace buffer... */
8996 + status = (*pIntfFxns->pfnBrdRead)(pDehMgr->hWmdContext,
8997 + (u8 *)pszBuf, (u32)ulTraceBegin,
8998 + ulNumBytes, 0);
8999 + if (DSP_FAILED(status)) {
9000 + DBG_Trace(DBG_LEVEL7, "PrintDspTraceBuffer: "
9001 + "Failed to Read Trace Buffer.\n");
9003 + if (DSP_SUCCEEDED(status)) {
9004 + /* Pack and do newline conversion */
9005 + DBG_Trace(DBG_LEVEL1, "PrintDspTraceBuffer: "
9006 + "before pack and unpack.\n");
9007 + PackTraceBuffer(pszBuf, ulNumBytes, ulNumWords);
9008 + DBG_Trace(DBG_LEVEL7, "DSP Trace Buffer:\n%s\n",
9009 + pszBuf);
9011 + MEM_Free(pszBuf);
9012 + MEM_Free(lpszBuf);
9013 + } else {
9014 + DBG_Trace(DBG_LEVEL7, "PrintDspTraceBuffer: Failed to "
9015 + "allocate trace buffer.\n");
9016 + status = DSP_EMEMORY;
9019 +#endif
9020 + return status;
9025 + * ======== WMD_DEH_Notify ========
9026 + * DEH error notification function. Informs user about the error.
9027 + */
9028 +void CDECL WMD_DEH_Notify(struct DEH_MGR *hDehMgr, u32 ulEventMask,
9029 + u32 dwErrInfo)
9031 + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr;
9032 + struct WMD_DEV_CONTEXT *pDevContext;
9033 + DSP_STATUS status = DSP_SOK;
9034 + u32 memPhysical = 0;
9035 + u32 HW_MMU_MAX_TLB_COUNT = 31;
9036 + u32 extern faultAddr;
9037 + struct CFG_HOSTRES resources;
9038 + u32 dummyVaAddr;
9039 + HW_STATUS hwStatus;
9041 + status = CFG_GetHostResources(
9042 + (struct CFG_DEVNODE *)DRV_GetFirstDevExtension(),
9043 + &resources);
9044 + if (DSP_FAILED(status))
9045 + DBG_Trace(DBG_LEVEL7,
9046 + "**Failed to get Host Resources in MMU ISR **\n");
9048 + DBG_Trace(DBG_LEVEL1, "Entering WMD_DEH_Notify: 0x%x, 0x%x\n", pDehMgr,
9049 + ulEventMask);
9050 + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) {
9051 + printk(KERN_INFO "WMD_DEH_Notify: ********** DEVICE EXCEPTION "
9052 + "**********\n");
9053 + switch (ulEventMask) {
9054 + case DSP_SYSERROR:
9055 + /* reset errInfo structure before use */
9056 + pDehMgr->errInfo.dwErrMask = DSP_SYSERROR;
9057 + pDehMgr->errInfo.dwVal1 = 0L;
9058 + pDehMgr->errInfo.dwVal2 = 0L;
9059 + pDehMgr->errInfo.dwVal3 = 0L;
9060 + pDehMgr->errInfo.dwVal1 = dwErrInfo;
9061 + printk(KERN_ERR "WMD_DEH_Notify: DSP_SYSERROR, errInfo "
9062 + "= 0x%x\n", dwErrInfo);
9063 + break;
9064 + case DSP_MMUFAULT:
9065 + /* MMU fault routine should have set err info
9066 + * structure */
9067 + pDevContext = (struct WMD_DEV_CONTEXT *)pDehMgr->hWmdContext;
9068 + pDehMgr->errInfo.dwErrMask = DSP_MMUFAULT;
9069 + printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT,"
9070 + "errInfo = 0x%x\n", dwErrInfo);
9071 + printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT, High "
9072 + "Address = 0x%x\n",
9073 + (unsigned int)pDehMgr->errInfo.dwVal1);
9074 + printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT, Low "
9075 + "Address = 0x%x\n",
9076 + (unsigned int)pDehMgr->errInfo.dwVal2);
9077 + printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT, fault "
9078 + "address = 0x%x\n", (unsigned int)faultAddr);
9079 + dummyVaAddr = (u32)MEM_Calloc(sizeof(char) * 0x1000,
9080 + MEM_PAGED);
9081 + memPhysical = (u32)MEM_Calloc(sizeof(char) * 0x1000,
9082 + MEM_PAGED);
9083 + dummyVaAddr = PG_ALIGN_LOW((u32)dummyVaAddr,
9084 + PG_SIZE_4K);
9085 + memPhysical = VirtToPhys(dummyVaAddr);
9086 + DBG_Trace(DBG_LEVEL6, "WMD_DEH_Notify: DSP_MMUFAULT, "
9087 + "mem Physical= 0x%x\n", memPhysical);
9088 + pDevContext = (struct WMD_DEV_CONTEXT *)
9089 + pDehMgr->hWmdContext;
9090 + /* Reset the dynamic mmu index to fixed count if it
9091 + * exceeds 31. So that the dynmmuindex is always
9092 + * between the range of standard/fixed entries
9093 + * and 31. */
9094 + if (pDevContext->numTLBEntries >
9095 + HW_MMU_MAX_TLB_COUNT) {
9096 + pDevContext->numTLBEntries = pDevContext->
9097 + fixedTLBEntries;
9099 + DBG_Trace(DBG_LEVEL6, "Adding TLB Entry %d: VA: 0x%x, "
9100 + "PA: 0x%x\n", pDevContext->
9101 + numTLBEntries, faultAddr, memPhysical);
9102 + if (DSP_SUCCEEDED(status)) {
9103 + hwStatus = HW_MMU_TLBAdd(resources.dwDmmuBase,
9104 + memPhysical, faultAddr,
9105 + HW_PAGE_SIZE_4KB, 1, &mapAttrs,
9106 + HW_SET, HW_SET);
9108 + /* send an interrupt to DSP */
9109 + HW_MBOX_MsgWrite(resources.dwMboxBase, MBOX_ARM2DSP,
9110 + MBX_DEH_CLASS | MBX_DEH_EMMU);
9111 + /* Clear MMU interrupt */
9112 + HW_MMU_EventAck(resources.dwDmmuBase,
9113 + HW_MMU_TRANSLATION_FAULT);
9114 + DBG_Trace(DBG_LEVEL6,
9115 + "***** PrintDspTraceBuffer: before\n");
9116 + PrintDspTraceBuffer(hDehMgr);
9117 + DBG_Trace(DBG_LEVEL6,
9118 + "***** PrintDspTraceBuffer: after \n");
9119 + break;
9120 + default:
9121 + DBG_Trace(DBG_LEVEL6,
9122 + "WMD_DEH_Notify: Unknown Error, errInfo = "
9123 + "0x%x\n", dwErrInfo);
9124 + break;
9126 + /* Signal DSP error/exception event. */
9127 + NTFY_Notify(pDehMgr->hNtfy, ulEventMask);
9129 + DBG_Trace(DBG_LEVEL1, "Exiting WMD_DEH_Notify\n");
9134 + * ======== WMD_DEH_GetInfo ========
9135 + * Retrieves error information.
9136 + */
9137 +DSP_STATUS WMD_DEH_GetInfo(struct DEH_MGR *hDehMgr,
9138 + struct DSP_ERRORINFO *pErrInfo)
9140 + DSP_STATUS status = DSP_SOK;
9141 + struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr;
9143 + DBC_Require(pDehMgr);
9144 + DBC_Require(pErrInfo);
9146 + DBG_Trace(DBG_LEVEL1, "Entering WMD_DEH_GetInfo: 0x%x\n", hDehMgr);
9148 + if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) {
9149 + /* Copy DEH error info structure to PROC error info
9150 + * structure. */
9151 + pErrInfo->dwErrMask = pDehMgr->errInfo.dwErrMask;
9152 + pErrInfo->dwVal1 = pDehMgr->errInfo.dwVal1;
9153 + pErrInfo->dwVal2 = pDehMgr->errInfo.dwVal2;
9154 + pErrInfo->dwVal3 = pDehMgr->errInfo.dwVal3;
9157 + DBG_Trace(DBG_LEVEL1, "Exiting WMD_DEH_GetInfo\n");
9159 + return status;