asm patches (tueidj)
[libogc.git] / libogc / aram.c
blob0f5252422e86776e992b14eb384ad8cf9380b052
1 /*-------------------------------------------------------------
3 aram.c -- ARAM subsystem
5 Copyright (C) 2004
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any
11 damages arising from the use of this software.
13 Permission is granted to anyone to use this software for any
14 purpose, including commercial applications, and to alter it and
15 redistribute it freely, subject to the following restrictions:
17 1. The origin of this software must not be misrepresented; you
18 must not claim that you wrote the original software. If you use
19 this software in a product, an acknowledgment in the product
20 documentation would be appreciated but is not required.
22 2. Altered source versions must be plainly marked as such, and
23 must not be misrepresented as being the original software.
25 3. This notice may not be removed or altered from any source
26 distribution.
28 -------------------------------------------------------------*/
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include "asm.h"
35 #include "processor.h"
36 #include "aram.h"
37 #include "irq.h"
38 #include "cache.h"
40 //#define _AR_DEBUG
42 // DSPCR bits
43 #define DSPCR_DSPRESET 0x0800 // Reset DSP
44 #define DSPCR_DSPDMA 0x0200 // ARAM dma in progress, if set
45 #define DSPCR_DSPINTMSK 0x0100 // * interrupt mask (RW)
46 #define DSPCR_DSPINT 0x0080 // * interrupt active (RWC)
47 #define DSPCR_ARINTMSK 0x0040
48 #define DSPCR_ARINT 0x0020
49 #define DSPCR_AIINTMSK 0x0010
50 #define DSPCR_AIINT 0x0008
51 #define DSPCR_HALT 0x0004 // halt DSP
52 #define DSPCR_PIINT 0x0002 // assert DSP PI interrupt
53 #define DSPCR_RES 0x0001 // reset DSP
55 #define AR_ARAMEXPANSION 2
57 #define _SHIFTL(v, s, w) \
58 ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s)))
59 #define _SHIFTR(v, s, w) \
60 ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
62 static vu16* const _dspReg = (u16*)0xCC005000;
64 static ARCallback __ARDmaCallback = NULL;
65 static u32 __ARInit_Flag = 0;
66 static u32 __ARStackPointer = 0;
67 static u32 __ARFreeBlocks = 0;
68 static u32 *__ARBlockLen = NULL;
70 static u32 __ARInternalSize = 0;
71 static u32 __ARExpansionSize = 0;
72 static u32 __ARSize = 0;
74 static void __ARHandler(u32 irq,void *ctx);
75 static void __ARCheckSize(void);
76 static void __ARClearArea(u32 aramaddr,u32 len);
78 ARCallback AR_RegisterCallback(ARCallback callback)
80 u32 level;
81 ARCallback old;
83 _CPU_ISR_Disable(level);
84 old = __ARDmaCallback;
85 __ARDmaCallback = callback;
86 _CPU_ISR_Restore(level);
87 return old;
90 u32 AR_GetDMAStatus()
92 u32 level,ret;
93 _CPU_ISR_Disable(level);
94 ret = ((_dspReg[5]&DSPCR_DSPDMA)==DSPCR_DSPDMA);
95 _CPU_ISR_Restore(level);
96 return ret;
99 u32 AR_Init(u32 *stack_idx_array,u32 num_entries)
101 #ifdef _AR_DEBUG
102 u32 freq;
103 #endif
104 u32 level;
105 u32 aram_base = 0x4000;
107 if(__ARInit_Flag) return aram_base;
109 _CPU_ISR_Disable(level);
111 __ARDmaCallback = NULL;
113 IRQ_Request(IRQ_DSP_ARAM,__ARHandler,NULL);
114 __UnmaskIrq(IRQMASK(IRQ_DSP_ARAM));
116 __ARStackPointer = aram_base;
117 __ARFreeBlocks = num_entries;
118 __ARBlockLen = stack_idx_array;
119 #ifdef _AR_DEBUG
120 freq = _dspReg[13]&0xff;
121 if(((f32)freq)!=156.0 && ((f32)freq)!=176.0) {
122 printf("AR_Init(): Illegal SDRAM refresh value(%f)\n",(f32)(freq));
123 abort();
125 #endif
126 _dspReg[13] = (_dspReg[13]&~0xff)|(_dspReg[13]&0xff);
128 __ARCheckSize();
129 __ARInit_Flag = 1;
131 _CPU_ISR_Restore(level);
132 return __ARStackPointer;
135 void AR_StartDMA(u32 dir,u32 memaddr,u32 aramaddr,u32 len)
137 u32 level;
139 _CPU_ISR_Disable(level);
141 // set main memory address
142 _dspReg[16] = (_dspReg[16]&~0x03ff)|_SHIFTR(memaddr,16,16);
143 _dspReg[17] = (_dspReg[17]&~0xffe0)|_SHIFTR(memaddr, 0,16);
145 // set aram address
146 _dspReg[18] = (_dspReg[18]&~0x03ff)|_SHIFTR(aramaddr,16,16);
147 _dspReg[19] = (_dspReg[19]&~0xffe0)|_SHIFTR(aramaddr, 0,16);
149 // set cntrl bits
150 _dspReg[20] = (_dspReg[20]&~0x8000)|_SHIFTL(dir,15,1);
151 _dspReg[20] = (_dspReg[20]&~0x03ff)|_SHIFTR(len,16,16);
152 _dspReg[21] = (_dspReg[21]&~0xffe0)|_SHIFTR(len, 0,16);
154 _CPU_ISR_Restore(level);
157 u32 AR_Alloc(u32 len)
159 u32 level;
160 u32 curraddr;
162 _CPU_ISR_Disable(level);
163 curraddr = __ARStackPointer;
164 __ARStackPointer += len;
165 *__ARBlockLen++ = len;
166 __ARFreeBlocks--;
167 _CPU_ISR_Restore(level);
169 return curraddr;
172 u32 AR_Free(u32 *len)
174 u32 level;
176 _CPU_ISR_Disable(level);
177 __ARBlockLen--;
178 if(len) *len = *__ARBlockLen;
179 __ARStackPointer -= *__ARBlockLen;
180 __ARFreeBlocks++;
181 _CPU_ISR_Restore(level);
183 return __ARStackPointer;
186 void AR_Clear(u32 flag)
188 switch(flag) {
189 case AR_ARAMINTALL:
190 if(__ARInternalSize)
191 __ARClearArea(0,__ARInternalSize);
192 break;
193 case AR_ARAMINTUSER:
194 if(__ARInternalSize)
195 __ARClearArea(0x4000,__ARInternalSize-0x4000);
196 break;
197 case AR_ARAMEXPANSION:
198 if(__ARInternalSize && __ARExpansionSize)
199 __ARClearArea(__ARInternalSize,__ARExpansionSize);
200 break;
201 default:
202 break;
206 BOOL AR_CheckInit()
208 return __ARInit_Flag;
211 void AR_Reset()
213 __ARInit_Flag = 0;
216 u32 AR_GetSize()
218 return __ARSize;
221 u32 AR_GetBaseAddress()
223 return 0x4000;
226 u32 AR_GetInternalSize()
228 return __ARInternalSize;
231 static __inline__ void __ARClearInterrupt()
233 u16 cause;
235 cause = _dspReg[5]&~(DSPCR_DSPINT|DSPCR_AIINT);
236 #ifdef _AR_DEBUG
237 printf("__ARClearInterrupt(0x%04x)\n",cause);
238 #endif
239 _dspReg[5] = (cause|DSPCR_ARINT);
242 static __inline__ void __ARWaitDma()
244 while(_dspReg[5]&DSPCR_DSPDMA);
247 static void __ARReadDMA(u32 memaddr,u32 aramaddr,u32 len)
249 #ifdef _AR_DEBUG
250 printf("__ARReadDMA(0x%08x,0x%08x,%d)\n",memaddr,aramaddr,len);
251 #endif
252 // set main memory address
253 _dspReg[16] = (_dspReg[16]&~0x03ff)|_SHIFTR(memaddr,16,16);
254 _dspReg[17] = (_dspReg[17]&~0xffe0)|_SHIFTR(memaddr, 0,16);
256 // set aram address
257 _dspReg[18] = (_dspReg[18]&~0x03ff)|_SHIFTR(aramaddr,16,16);
258 _dspReg[19] = (_dspReg[19]&~0xffe0)|_SHIFTR(aramaddr, 0,16);
260 // set cntrl bits
261 _dspReg[20] = (_dspReg[20]&~0x8000)|0x8000;
262 _dspReg[20] = (_dspReg[20]&~0x03ff)|_SHIFTR(len,16,16);
263 _dspReg[21] = (_dspReg[21]&~0xffe0)|_SHIFTR(len, 0,16);
265 __ARWaitDma();
266 __ARClearInterrupt();
270 static void __ARWriteDMA(u32 memaddr,u32 aramaddr,u32 len)
272 #ifdef _AR_DEBUG
273 printf("__ARWriteDMA(0x%08x,0x%08x,%d)\n",memaddr,aramaddr,len);
274 #endif
275 // set main memory address
276 _dspReg[16] = (_dspReg[16]&~0x03ff)|_SHIFTR(memaddr,16,16);
277 _dspReg[17] = (_dspReg[17]&~0xffe0)|_SHIFTR(memaddr, 0,16);
279 // set aram address
280 _dspReg[18] = (_dspReg[18]&~0x03ff)|_SHIFTR(aramaddr,16,16);
281 _dspReg[19] = (_dspReg[19]&~0xffe0)|_SHIFTR(aramaddr, 0,16);
283 // set cntrl bits
284 _dspReg[20] = (_dspReg[20]&~0x8000);
285 _dspReg[20] = (_dspReg[20]&~0x03ff)|_SHIFTR(len,16,16);
286 _dspReg[21] = (_dspReg[21]&~0xffe0)|_SHIFTR(len, 0,16);
288 __ARWaitDma();
289 __ARClearInterrupt();
292 static void __ARClearArea(u32 aramaddr,u32 len)
294 u32 currlen,curraddr,endaddr;
295 static u8 zero_buffer[2048] ATTRIBUTE_ALIGN(32);
297 while(!(_dspReg[11]&0x0001));
299 memset(zero_buffer,0,2048);
300 DCFlushRange(zero_buffer,2048);
302 curraddr = aramaddr;
303 endaddr = aramaddr+len;
305 currlen = 2048;
306 while(curraddr<endaddr) {
307 if((endaddr-curraddr)<currlen) currlen = ((endaddr-curraddr)+31)&~31;
308 __ARWriteDMA((u32)zero_buffer,curraddr,currlen);
309 curraddr += currlen;
313 static void __ARCheckSize()
315 u32 i,arsize,arszflag;
316 static u32 test_data[8] ATTRIBUTE_ALIGN(32);
317 static u32 dummy_data[8] ATTRIBUTE_ALIGN(32);
318 static u32 buffer[8] ATTRIBUTE_ALIGN(32);
320 #ifdef _AR_DEBUG
321 printf("__ARCheckSize()\n");
322 #endif
324 while(!(_dspReg[11]&0x0001));
326 __ARSize = __ARInternalSize = arsize = 0x1000000;
327 _dspReg[9] = (_dspReg[9]&~0x3f)|0x23;
329 for(i=0;i<8;i++) {
330 test_data[i] = 0xBAD1BAD0;
331 dummy_data[i] = 0xDEADBEEF;
333 DCFlushRange(test_data,32);
334 DCFlushRange(dummy_data,32);
336 __ARExpansionSize = 0;
337 __ARWriteDMA((u32)test_data,0x1000000,32);
338 __ARWriteDMA((u32)test_data,0x1200000,32);
339 __ARWriteDMA((u32)test_data,0x2000000,32);
340 __ARWriteDMA((u32)test_data,0x1000200,32);
341 __ARWriteDMA((u32)test_data,0x1400000,32);
343 memset(buffer,0,32);
344 DCFlushRange(buffer,32);
346 __ARWriteDMA((u32)dummy_data,0x1000000,32);
348 DCInvalidateRange(buffer,32);
349 __ARReadDMA((u32)buffer,0x1000000,32);
350 _nop();
352 arszflag = 0x03;
353 if(buffer[0]==dummy_data[0]) {
354 memset(buffer,0,32);
355 DCFlushRange(buffer,32);
356 __ARReadDMA((u32)buffer,0x1200000,32);
357 _nop();
358 if(buffer[0]==dummy_data[0]) {
359 __ARExpansionSize = 0x200000;
360 arsize += 0x200000;
361 goto end_check; //not nice but fast
364 memset(buffer,0,32);
365 DCFlushRange(buffer,32);
366 __ARReadDMA((u32)buffer,0x2000000,32);
367 _nop();
368 if(buffer[0]==dummy_data[0]) {
369 __ARExpansionSize = 0x400000;
370 arsize += 0x400000;
371 arszflag |= 0x08;
372 goto end_check; //not nice but fast
375 memset(buffer,0,32);
376 DCFlushRange(buffer,32);
377 __ARReadDMA((u32)buffer,0x1400000,32);
378 _nop();
379 if(buffer[0]==dummy_data[0]) {
380 __ARExpansionSize = 0x1000000;
381 arsize += 0x1000000;
382 arszflag |= 0x18;
383 } else {
384 __ARExpansionSize = 0x2000000;
385 arsize += 0x2000000;
386 arszflag |= 0x20;
388 end_check:
389 _dspReg[9] = (_dspReg[9]&~0x3f)|arszflag;
392 #ifdef _AR_DEBUG
393 printf("__ARCheckSize(%d)\n",arsize);
394 #endif
395 *(u32*)0x800000d0 = arsize;
396 __ARSize = arsize;
399 static void __ARHandler(u32 irq,void *ctx)
401 #ifdef _AR_DEBUG
402 printf("__ARHandler()\n");
403 #endif
404 __ARClearInterrupt();
406 if(__ARDmaCallback)
407 __ARDmaCallback();