1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - library - dsp
3   File:     dsp_if.c
4 
5   Copyright 2007-2009 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2009-06-04#$
14   $Rev: 10698 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 #include <twl.h>
18 #include <twl/dsp.h>
19 
20 #include <dsp_coff.h>
21 #include "dsp_process.h"
22 
23 /*---------------------------------------------------------------------------*
24     Constant Definitions
25  *---------------------------------------------------------------------------*/
26 
27 #define reg_CFG_DSP_RST             *(vu8*)REG_RST_ADDR
28 
29 #define REG_DSP_PCFG_RRIE_MASK      (REG_DSP_PCFG_PRIE0_MASK | REG_DSP_PCFG_PRIE1_MASK | REG_DSP_PCFG_PRIE2_MASK)
30 #define REG_DSP_PCFG_RRIE_SHIFT     REG_DSP_PCFG_PRIE0_SHIFT
31 #define REG_DSP_PSTS_RCOMIM_SHIFT   REG_DSP_PSTS_RCOMIM0_SHIFT
32 #define REG_DSP_PSTS_RRI_SHIFT      REG_DSP_PSTS_RRI0_SHIFT
33 
34 
35 #define DSP_DPRINTF(...)    ((void) 0)
36 //#define DSP_DPRINTF OS_TPrintf
37 
38 /*---------------------------------------------------------------------------*
39     Type Definitions
40  *---------------------------------------------------------------------------*/
41 typedef struct DSPData
42 {
43     u16 send;
44     u16 reserve1;
45     u16 recv;
46     u16 reserve2;
47 }
48 DSPData;
49 
50 
51 /*---------------------------------------------------------------------------*
52     Static Variable Definitions
53  *---------------------------------------------------------------------------*/
54 static volatile DSPData *const dspData = (DSPData*)REG_COM0_ADDR;
55 
56 /*---------------------------------------------------------------------------*
57     Internal Function Definitions
58  *---------------------------------------------------------------------------*/
59 
60 /*---------------------------------------------------------------------------*
61   Name:         DSP_PowerOn
62 
63   Description:  Turns on the DSP and configures it to be in the reset state.
64                 You must call DSP_ResetOff() to start the DSP.
65 
66   Arguments:    None.
67 
68   Returns:      None.
69  *---------------------------------------------------------------------------*/
DSP_PowerOnCore(void)70 void DSP_PowerOnCore(void)  // DSP_Init
71 {
72     SCFG_ResetDSP();                                // Confirms reset of DSP block
73     SCFG_SupplyClockToDSP(TRUE);                    // Power on for DSP block
74     OS_SpinWaitSysCycles(2);                        // Wait 8 cycles @ 134 MHz
75     SCFG_ReleaseResetDSP();                         // Release reset of DSP block
76     DSP_ResetOnCore();                                  // Set reset of DSP core
77 }
78 
79 /*---------------------------------------------------------------------------*
80   Name:         DSP_PowerOff
81 
82   Description:  Turns off the DSP.
83 
84   Arguments:    None.
85 
86   Returns:      None.
87  *---------------------------------------------------------------------------*/
DSP_PowerOffCore(void)88 void DSP_PowerOffCore(void) // DSP_End
89 {
90     SCFG_ResetDSP();                                // Sets reset of DSP block
91     SCFG_SupplyClockToDSP(FALSE);                   // Power off for DSP block
92 }
93 
94 /*---------------------------------------------------------------------------*
95   Name:         DSP_ResetOn
96 
97   Description:  Resets the DSP.
98 
99   Arguments:    None.
100 
101   Returns:      None.
102  *---------------------------------------------------------------------------*/
DSP_ResetOnCore(void)103 void DSP_ResetOnCore(void)
104 {
105     if ((reg_DSP_PCFG & REG_DSP_PCFG_DSPR_MASK) == 0)
106     {
107         reg_DSP_PCFG |= REG_DSP_PCFG_DSPR_MASK;
108         while ( reg_DSP_PSTS & REG_DSP_PSTS_PRST_MASK )
109         {
110         }
111     }
112 }
113 
114 /*---------------------------------------------------------------------------*
115   Name:         DSP_ResetOff
116 
117   Description:  Starts the DSP from the reset state.
118 
119   Arguments:    None.
120 
121   Returns:      None.
122  *---------------------------------------------------------------------------*/
DSP_ResetOffCore(void)123 void DSP_ResetOffCore(void)
124 {
125     while ( reg_DSP_PSTS & REG_DSP_PSTS_PRST_MASK )
126     {
127     }
128     DSP_ResetInterfaceCore();   // Initialize DSP-A9IF
129     reg_DSP_PCFG &= ~REG_DSP_PCFG_DSPR_MASK;
130 }
131 
132 /*---------------------------------------------------------------------------*
133   Name:         DSP_ResetOffEx
134 
135   Description:  Starts the DSP from the reset state.
136 
137   Arguments:    bitmap: Bitmap of the reply registers and semaphores that allow interrupts from the DSP to the ARM9.
138 
139   Returns:      None.
140  *---------------------------------------------------------------------------*/
DSP_ResetOffExCore(u16 bitmap)141 void DSP_ResetOffExCore(u16 bitmap)
142 {
143     SDK_ASSERT(bitmap >= 0 && bitmap <= 7);
144 
145     while ( reg_DSP_PSTS & REG_DSP_PSTS_PRST_MASK )
146     {
147     }
148     DSP_ResetInterfaceCore();   // Initialize DSP-A9IF
149     reg_DSP_PCFG |= (bitmap) << REG_DSP_PCFG_RRIE_SHIFT;
150     reg_DSP_PCFG &= ~REG_DSP_PCFG_DSPR_MASK;
151 }
152 
153 /*---------------------------------------------------------------------------*
154   Name:         DSP_ResetInterface
155 
156   Description:  Initializes the registers.
157                 You must call this function when the DSP is reset.
158 
159   Arguments:    None.
160 
161   Returns:      None.
162  *---------------------------------------------------------------------------*/
DSP_ResetInterfaceCore(void)163 void DSP_ResetInterfaceCore(void)
164 {
165     if (reg_DSP_PCFG & REG_DSP_PCFG_DSPR_MASK)
166     {
167         u16 dummy;
168         reg_DSP_PCFG &= ~REG_DSP_PCFG_RRIE_MASK;
169         reg_DSP_PSEM = 0;
170         reg_DSP_PCLEAR = 0xFFFF;
171         dummy = dspData[0].recv;
172         dummy = dspData[1].recv;
173         dummy = dspData[2].recv;
174     }
175 }
176 
177 /*---------------------------------------------------------------------------*
178   Name:         DSP_EnableRecvDataInterrupt
179 
180   Description:  Enables interrupts for the specified reply register.
181 
182   Arguments:    dataNo: Reply register number (0-2)
183 
184   Returns:      None.
185  *---------------------------------------------------------------------------*/
DSP_EnableRecvDataInterruptCore(u32 dataNo)186 void DSP_EnableRecvDataInterruptCore(u32 dataNo)
187 {
188     SDK_ASSERT(dataNo >= 0 && dataNo <= 2);
189     reg_DSP_PCFG |= (1 << dataNo) << REG_DSP_PCFG_RRIE_SHIFT;
190 }
191 
192 /*---------------------------------------------------------------------------*
193   Name:         DSP_DisableRecvDataInterrupt
194 
195   Description:  Disables interrupts for the specified reply register.
196 
197   Arguments:    dataNo: Reply register number (0-2)
198 
199   Returns:      None.
200  *---------------------------------------------------------------------------*/
DSP_DisableRecvDataInterruptCore(u32 dataNo)201 void DSP_DisableRecvDataInterruptCore(u32 dataNo)
202 {
203     SDK_ASSERT(dataNo >= 0 && dataNo <= 2);
204     reg_DSP_PCFG &= ~((1 << dataNo) << REG_DSP_PCFG_RRIE_SHIFT);
205 }
206 
207 /*---------------------------------------------------------------------------*
208   Name:         DSP_SendDataIsEmpty
209 
210   Description:  Checks whether the DSP has received data for the specified command register.
211 
212   Arguments:    dataNo: Command register number (0-2)
213 
214   Returns:      TRUE if the DSP has already received data.
215  *---------------------------------------------------------------------------*/
DSP_SendDataIsEmptyCore(u32 dataNo)216 BOOL DSP_SendDataIsEmptyCore(u32 dataNo)
217 {
218     SDK_ASSERT(dataNo >= 0 && dataNo <= 2);
219     return (reg_DSP_PSTS & ((1 << dataNo) << REG_DSP_PSTS_RCOMIM_SHIFT)) ? FALSE : TRUE;
220 }
221 
222 /*---------------------------------------------------------------------------*
223   Name:         DSP_RecvDataIsReady
224 
225   Description:  Checks whether data was sent from the DSP to the specified reply register.
226 
227   Arguments:    dataNo: Reply register number (0-2)
228 
229   Returns:      TRUE if the DSP has sent data.
230  *---------------------------------------------------------------------------*/
DSP_RecvDataIsReadyCore(u32 dataNo)231 BOOL DSP_RecvDataIsReadyCore(u32 dataNo)
232 {
233     SDK_ASSERT(dataNo >= 0 && dataNo <= 2);
234     return (reg_DSP_PSTS & ((1 << dataNo) << REG_DSP_PSTS_RRI_SHIFT)) ? TRUE : FALSE;
235 }
236 
237 /*---------------------------------------------------------------------------*
238   Name:         DSP_SendData
239 
240   Description:  Sends data to the DSP.
241 
242   Arguments:    dataNo: Command register number (0-2)
243                 data: The data to send
244 
245   Returns:      None.
246  *---------------------------------------------------------------------------*/
DSP_SendDataCore(u32 dataNo,u16 data)247 void DSP_SendDataCore(u32 dataNo, u16 data)
248 {
249     SDK_ASSERT(dataNo >= 0 && dataNo <= 2);
250     while (DSP_SendDataIsEmptyCore(dataNo) == FALSE)
251     {
252     }
253     dspData[dataNo].send = data;
254 }
255 
256 /*---------------------------------------------------------------------------*
257   Name:         DSP_RecvData
258 
259   Description:  Receives data from the DSP.
260 
261   Arguments:    dataNo: Reply register number (0-2)
262 
263   Returns:      The received data.
264  *---------------------------------------------------------------------------*/
DSP_RecvDataCore(u32 dataNo)265 u16 DSP_RecvDataCore(u32 dataNo)
266 {
267     SDK_ASSERT(dataNo >= 0 && dataNo <= 2);
268     while (DSP_RecvDataIsReadyCore(dataNo) == FALSE)
269     {
270     }
271     return dspData[dataNo].recv;
272 }
273 
274 /*---------------------------------------------------------------------------*
275   Name:         DSP_EnableFifoInterrupt
276 
277   Description:  Enables FIFO interrupts.
278 
279   Arguments:    type: The cause of the FIFO interrupt
280 
281   Returns:      None.
282  *---------------------------------------------------------------------------*/
DSP_EnableFifoInterruptCore(DSPFifoIntr type)283 void DSP_EnableFifoInterruptCore(DSPFifoIntr type)
284 {
285     reg_DSP_PCFG |= type;
286 }
287 
288 /*---------------------------------------------------------------------------*
289   Name:         DSP_DisableFifoInterrupt
290 
291   Description:  Disables FIFO interrupts.
292 
293   Arguments:    type: The cause of the FIFO interrupt
294 
295   Returns:      None.
296  *---------------------------------------------------------------------------*/
DSP_DisableFifoInterruptCore(DSPFifoIntr type)297 void DSP_DisableFifoInterruptCore(DSPFifoIntr type)
298 {
299     reg_DSP_PCFG &= ~type;
300 }
301 
302 /*---------------------------------------------------------------------------*
303   Name:         DSP_SendFifoEx
304 
305   Description:  Writes data in the DSP's memory space.
306 
307   Arguments:    memsel: Memory space in which to write data
308                 dest: Address to write to (half-word).
309                          If the most-significant 16 bits are set, values must be set in the DMA register in advance.
310 
311                 src: Data to write
312                 size: Length of the data to write (half-word)
313                 flags: You can select a write mode other than DSP_FIFO_FLAG_RECV_UNIT_* from DSPFifoFlag
314 
315 
316   Returns:      None.
317  *---------------------------------------------------------------------------*/
DSP_SendFifoExCore(DSPFifoMemSel memsel,u16 dest,const u16 * src,int size,u16 flags)318 void DSP_SendFifoExCore(DSPFifoMemSel memsel, u16 dest, const u16 *src, int size, u16 flags)
319 {
320     OSIntrMode  bak = OS_DisableInterrupts();
321     u16 incmode = (u16)((flags & DSP_FIFO_FLAG_DEST_FIX) ? 0 : REG_DSP_PCFG_AIM_MASK);
322 
323     reg_DSP_PADR = dest;
324     reg_DSP_PCFG = (u16)((reg_DSP_PCFG & ~(REG_DSP_PCFG_MEMSEL_MASK|REG_DSP_PCFG_AIM_MASK))
325                         | memsel | incmode);
326 
327     if (flags & DSP_FIFO_FLAG_SRC_FIX)
328     {
329         while (size-- > 0)
330         {
331             while (reg_DSP_PSTS & REG_DSP_PSTS_WFFI_MASK)
332             {
333             }
334             reg_DSP_PDATA = *src;
335         }
336     }
337     else
338     {
339         while (size-- > 0)
340         {
341             while (reg_DSP_PSTS & REG_DSP_PSTS_WFFI_MASK)
342             {
343             }
344             reg_DSP_PDATA = *src++;
345         }
346     }
347     (void)OS_RestoreInterrupts(bak);
348 }
349 
350 /*---------------------------------------------------------------------------*
351   Name:         DSP_RecvFifoEx
352 
353   Description:  Reads data from the DSP's memory space.
354 
355   Arguments:    memsel: Memory space to read data from (other than program memory)
356                 dest: Address at which to receive data
357                 src: Address from which the data was received (half-word)
358                          If the most-significant 16 bits are set, values must be set in the DMA register in advance.
359 
360                 size: Data size to read (half-word)
361                 flags: You can select the read mode from DSPFifoFlag
362 
363   Returns:      None.
364  *---------------------------------------------------------------------------*/
DSP_RecvFifoExCore(DSPFifoMemSel memsel,u16 * dest,u16 src,int size,u16 flags)365 void DSP_RecvFifoExCore(DSPFifoMemSel memsel, u16* dest, u16 src, int size, u16 flags)
366 {
367     OSIntrMode  bak = OS_DisableInterrupts();
368     DSPFifoRecvLength len;
369     u16 incmode = (u16)((flags & DSP_FIFO_FLAG_SRC_FIX) ? 0 : REG_DSP_PCFG_AIM_MASK);
370 
371     SDK_ASSERT(memsel != DSP_FIFO_MEMSEL_PROGRAM);
372 
373     switch (flags & DSP_FIFO_FLAG_RECV_MASK)
374     {
375     case DSP_FIFO_FLAG_RECV_UNIT_2B:
376         len = DSP_FIFO_RECV_2B;
377         size = 1;
378         break;
379     case DSP_FIFO_FLAG_RECV_UNIT_16B:
380         len = DSP_FIFO_RECV_16B;
381         size = 8;
382         break;
383     case DSP_FIFO_FLAG_RECV_UNIT_32B:
384         len = DSP_FIFO_RECV_32B;
385         size = 16;
386         break;
387     default:
388         len = DSP_FIFO_RECV_CONTINUOUS;
389         break;
390     }
391 
392     reg_DSP_PADR = src;
393     reg_DSP_PCFG = (u16)((reg_DSP_PCFG & ~(REG_DSP_PCFG_MEMSEL_MASK|REG_DSP_PCFG_DRS_MASK|REG_DSP_PCFG_AIM_MASK))
394                         | memsel | len | incmode | REG_DSP_PCFG_RS_MASK);
395 
396     if (flags & DSP_FIFO_FLAG_DEST_FIX)
397     {
398         while (size-- > 0)
399         {
400             while ((reg_DSP_PSTS & REG_DSP_PSTS_RFNEI_MASK) == 0)
401             {
402             }
403             *dest = reg_DSP_PDATA;
404         }
405     }
406     else
407     {
408         while (size-- > 0)
409         {
410             while ((reg_DSP_PSTS & REG_DSP_PSTS_RFNEI_MASK) == 0)
411             {
412             }
413             *dest++ = reg_DSP_PDATA;
414         }
415     }
416     reg_DSP_PCFG &= ~REG_DSP_PCFG_RS_MASK;
417     (void)OS_RestoreInterrupts(bak);
418 }
419 
420 /*---------------------------------------------------------------------------*
421   Name:         DSP_SetCommandReg
422 
423   Description:  Writes a value to a command register.
424 
425   Arguments:    regNo: Command register number (0-2)
426                 data: Data
427 
428   Returns:      None.
429  *---------------------------------------------------------------------------*/
DSP_SetCommandRegCore(u32 regNo,u16 data)430 void DSP_SetCommandRegCore(u32 regNo, u16 data)
431 {
432     SDK_ASSERT(regNo >= 0 && regNo <= 2);
433     dspData[regNo].send = data;
434 }
435 
436 /*---------------------------------------------------------------------------*
437   Name:         DSP_GetReplyReg
438 
439   Description:  Reads a value from a reply register.
440 
441   Arguments:    regNo: Reply register number (0-2)
442 
443   Returns:      The data read.
444  *---------------------------------------------------------------------------*/
DSP_GetReplyRegCore(u32 regNo)445 u16 DSP_GetReplyRegCore(u32 regNo)
446 {
447     SDK_ASSERT(regNo >= 0 && regNo <= 2);
448     return dspData[regNo].recv;
449 }
450 
451 /*---------------------------------------------------------------------------*
452   Name:         DSP_SetSemaphore
453 
454   Description:  Writes a value to the semaphore register for sending notifications from an ARM processor to the DSP.
455 
456   Arguments:    mask: Value to set
457 
458   Returns:      None.
459  *---------------------------------------------------------------------------*/
DSP_SetSemaphoreCore(u16 mask)460 void DSP_SetSemaphoreCore(u16 mask)
461 {
462     reg_DSP_PSEM = mask;
463 }
464 
465 /*---------------------------------------------------------------------------*
466   Name:         DSP_GetSemaphore
467 
468   Description:  Reads the value of the semaphore register for sending notifications from the DSP to an ARM processor.
469 
470   Arguments:    None.
471 
472   Returns:      The value written to the semaphore by the DSP.
473  *---------------------------------------------------------------------------*/
DSP_GetSemaphoreCore(void)474 u16 DSP_GetSemaphoreCore(void)
475 {
476     return reg_DSP_SEM;
477 }
478 
479 /*---------------------------------------------------------------------------*
480   Name:         DSP_ClearSemaphore
481 
482   Description:  Clears the value of the semaphore register for sending notifications from the DSP to an ARM processor.
483 
484   Arguments:    mask: The bits to clear.
485 
486   Returns:      None.
487  *---------------------------------------------------------------------------*/
DSP_ClearSemaphoreCore(u16 mask)488 void DSP_ClearSemaphoreCore(u16 mask)
489 {
490     reg_DSP_PCLEAR = mask;
491 }
492 
493 /*---------------------------------------------------------------------------*
494   Name:         DSP_MaskSemaphore
495 
496   Description:  Sets bits that correspond to interrupts to disable in the semaphore register for sending notifications from the DSP to an ARM processor.
497 
498   Arguments:    mask: Bits corresponding to interrupts to disable.
499 
500   Returns:      None.
501  *---------------------------------------------------------------------------*/
DSP_MaskSemaphoreCore(u16 mask)502 void DSP_MaskSemaphoreCore(u16 mask)
503 {
504     reg_DSP_PMASK = mask;
505 }
506 
507 /*---------------------------------------------------------------------------*
508   Name:         DSP_CheckSemaphoreRequest
509 
510   Description:  Checks whether there is an interrupt request from the semaphore register.
511 
512   Arguments:    None.
513 
514   Returns:      TRUE if there is a request.
515  *---------------------------------------------------------------------------*/
DSP_CheckSemaphoreRequestCore(void)516 BOOL DSP_CheckSemaphoreRequestCore(void)
517 {
518     return (reg_DSP_PSTS & REG_DSP_PSTS_PSEMI_MASK) >> REG_DSP_PSTS_PSEMI_SHIFT;
519 }
520 
521 
522 #if defined(DSP_SUPPORT_OBSOLETE_LOADER)
523 /*---------------------------------------------------------------------------*
524  * The following shows candidate interfaces for termination because they are considered not to be currently in use
525  *---------------------------------------------------------------------------*/
526 
527 /*---------------------------------------------------------------------------*
528  * Below is the old interface using a straight-mapping method
529  *---------------------------------------------------------------------------*/
530 
531 /*---------------------------------------------------------------------------*
532   Name:         DSPi_MapProcessSlotAsStraight
533 
534   Description:  Initializes the slot map so the segment number and the WRAM slot number match.
535                 (This method is used only with the initial load function that does not have Ex applied.)
536 
537   Arguments:    context: DSPProcessContext structure
538                 slotB: WRAM-B allowed for use for code memory
539                 slotC: WRAM-C allowed for use for data memory
540 
541   Returns:      None.
542  *---------------------------------------------------------------------------*/
DSPi_MapProcessSlotAsStraight(DSPProcessContext * context,int slotB,int slotC)543 static BOOL DSPi_MapProcessSlotAsStraight(DSPProcessContext *context, int slotB, int slotC)
544 {
545     int     segment;
546     for (segment = 0; segment < MI_WRAM_B_MAX_NUM; ++segment)
547     {
548         if (context->segmentCode & (1 << segment) != 0)
549         {
550             int     slot = segment;
551             if ((slotB & (1 << slot)) == 0)
552             {
553                 return FALSE;
554             }
555             context->slotOfSegmentCode[segment] = slot;
556         }
557     }
558     for (segment = 0; segment < MI_WRAM_C_MAX_NUM; ++segment)
559     {
560         if (context->segmentData & (1 << segment) != 0)
561         {
562             int     slot = segment;
563             if ((slotC & (1 << slot)) == 0)
564             {
565                 return FALSE;
566             }
567             context->slotOfSegmentData[segment] = slot;
568         }
569     }
570     return TRUE;
571 }
572 
573 /*---------------------------------------------------------------------------*
574   Name:         DSP_LoadFileAuto
575 
576   Description:  Loads a COFF format DSP program and assigns the necessary WRAM to DSP.
577 
578   Arguments:    image: COFF file
579 
580   Returns:      TRUE on success.
581  *---------------------------------------------------------------------------*/
DSP_LoadFileAutoCore(const void * image)582 BOOL DSP_LoadFileAutoCore(const void *image)
583 {
584     // Temporarily convert to a memory file
585     FSFile  memfile[1];
586     if(DSPi_CreateMemoryFile(memfile, image))
587     {
588         DSPProcessContext   context[1];
589         DSP_InitProcessContext(context, NULL);
590         return DSP_StartupProcess(context, memfile, 0xFF, 0xFF, DSPi_MapProcessSlotAsStraight);
591     }
592     return FALSE;
593 }
594 
595 
596 #endif
597 
598 /*---------------------------------------------------------------------------*
599   End of file
600  *---------------------------------------------------------------------------*/
601