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