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