tinysmb devoptab fix - allow fread sizes > 7236
[libogc.git] / libogc / aram.c
blob233a69102aff22f60d2b4be896b89cbd43ed5780
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();
75 static void __ARCheckSize();
76 static void __ARClearArea(u32 aramaddr,u32 len);
78 extern void __UnmaskIrq(u32);
79 extern void __MaskIrq(u32);
81 ARCallback AR_RegisterCallback(ARCallback callback)
83 u32 level;
84 ARCallback old;
86 _CPU_ISR_Disable(level);
87 old = __ARDmaCallback;
88 __ARDmaCallback = callback;
89 _CPU_ISR_Restore(level);
90 return old;
93 u32 AR_GetDMAStatus()
95 u32 level,ret;
96 _CPU_ISR_Disable(level);
97 ret = ((_dspReg[5]&DSPCR_DSPDMA)==DSPCR_DSPDMA);
98 _CPU_ISR_Restore(level);
99 return ret;
102 u32 AR_Init(u32 *stack_idx_array,u32 num_entries)
104 #ifdef _AR_DEBUG
105 u32 freq;
106 #endif
107 u32 level;
108 u32 aram_base = 0x4000;
110 if(__ARInit_Flag) return aram_base;
112 _CPU_ISR_Disable(level);
114 __ARDmaCallback = NULL;
116 IRQ_Request(IRQ_DSP_ARAM,__ARHandler,NULL);
117 __UnmaskIrq(IRQMASK(IRQ_DSP_ARAM));
119 __ARStackPointer = aram_base;
120 __ARFreeBlocks = num_entries;
121 __ARBlockLen = stack_idx_array;
122 #ifdef _AR_DEBUG
123 freq = _dspReg[13]&0xff;
124 if(((f32)freq)!=156.0 && ((f32)freq)!=176.0) {
125 printf("AR_Init(): Illegal SDRAM refresh value(%f)\n",(f32)(freq));
126 abort();
128 #endif
129 _dspReg[13] = (_dspReg[13]&~0xff)|(_dspReg[13]&0xff);
131 __ARCheckSize();
132 __ARInit_Flag = 1;
134 _CPU_ISR_Restore(level);
135 return __ARStackPointer;
138 void AR_StartDMA(u32 dir,u32 memaddr,u32 aramaddr,u32 len)
140 u32 level;
142 _CPU_ISR_Disable(level);
144 // set main memory address
145 _dspReg[16] = (_dspReg[16]&~0x03ff)|_SHIFTR(memaddr,16,16);
146 _dspReg[17] = (_dspReg[17]&~0xffe0)|_SHIFTR(memaddr, 0,16);
148 // set aram address
149 _dspReg[18] = (_dspReg[18]&~0x03ff)|_SHIFTR(aramaddr,16,16);
150 _dspReg[19] = (_dspReg[19]&~0xffe0)|_SHIFTR(aramaddr, 0,16);
152 // set cntrl bits
153 _dspReg[20] = (_dspReg[20]&~0x8000)|_SHIFTL(dir,15,1);
154 _dspReg[20] = (_dspReg[20]&~0x03ff)|_SHIFTR(len,16,16);
155 _dspReg[21] = (_dspReg[21]&~0xffe0)|_SHIFTR(len, 0,16);
157 _CPU_ISR_Restore(level);
160 u32 AR_Alloc(u32 len)
162 u32 level;
163 u32 curraddr;
165 _CPU_ISR_Disable(level);
166 curraddr = __ARStackPointer;
167 __ARStackPointer += len;
168 *__ARBlockLen++ = len;
169 __ARFreeBlocks--;
170 _CPU_ISR_Restore(level);
172 return curraddr;
175 u32 AR_Free(u32 *len)
177 u32 level;
179 _CPU_ISR_Disable(level);
180 __ARBlockLen--;
181 if(len) *len = *__ARBlockLen;
182 __ARStackPointer -= *__ARBlockLen;
183 __ARFreeBlocks++;
184 _CPU_ISR_Restore(level);
186 return __ARStackPointer;
189 void AR_Clear(u32 flag)
191 switch(flag) {
192 case AR_ARAMINTALL:
193 if(__ARInternalSize)
194 __ARClearArea(0,__ARInternalSize);
195 break;
196 case AR_ARAMINTUSER:
197 if(__ARInternalSize)
198 __ARClearArea(0x4000,__ARInternalSize-0x4000);
199 break;
200 case AR_ARAMEXPANSION:
201 if(__ARInternalSize && __ARExpansionSize)
202 __ARClearArea(__ARInternalSize,__ARExpansionSize);
203 break;
204 default:
205 break;
209 BOOL AR_CheckInit()
211 return __ARInit_Flag;
214 void AR_Reset()
216 __ARInit_Flag = 0;
219 u32 AR_GetSize()
221 return __ARSize;
224 u32 AR_GetBaseAddress()
226 return 0x4000;
229 u32 AR_GetInternalSize()
231 return __ARInternalSize;
234 static __inline__ void __ARClearInterrupt()
236 u16 cause;
238 cause = _dspReg[5]&~(DSPCR_DSPINT|DSPCR_AIINT);
239 #ifdef _AR_DEBUG
240 printf("__ARClearInterrupt(0x%04x)\n",cause);
241 #endif
242 _dspReg[5] = (cause|DSPCR_ARINT);
245 static __inline__ void __ARWaitDma()
247 while(_dspReg[5]&DSPCR_DSPDMA);
250 static void __ARReadDMA(u32 memaddr,u32 aramaddr,u32 len)
252 #ifdef _AR_DEBUG
253 printf("__ARReadDMA(0x%08x,0x%08x,%d)\n",memaddr,aramaddr,len);
254 #endif
255 // set main memory address
256 _dspReg[16] = (_dspReg[16]&~0x03ff)|_SHIFTR(memaddr,16,16);
257 _dspReg[17] = (_dspReg[17]&~0xffe0)|_SHIFTR(memaddr, 0,16);
259 // set aram address
260 _dspReg[18] = (_dspReg[18]&~0x03ff)|_SHIFTR(aramaddr,16,16);
261 _dspReg[19] = (_dspReg[19]&~0xffe0)|_SHIFTR(aramaddr, 0,16);
263 // set cntrl bits
264 _dspReg[20] = (_dspReg[20]&~0x8000)|0x8000;
265 _dspReg[20] = (_dspReg[20]&~0x03ff)|_SHIFTR(len,16,16);
266 _dspReg[21] = (_dspReg[21]&~0xffe0)|_SHIFTR(len, 0,16);
268 __ARWaitDma();
269 __ARClearInterrupt();
273 static void __ARWriteDMA(u32 memaddr,u32 aramaddr,u32 len)
275 #ifdef _AR_DEBUG
276 printf("__ARWriteDMA(0x%08x,0x%08x,%d)\n",memaddr,aramaddr,len);
277 #endif
278 // set main memory address
279 _dspReg[16] = (_dspReg[16]&~0x03ff)|_SHIFTR(memaddr,16,16);
280 _dspReg[17] = (_dspReg[17]&~0xffe0)|_SHIFTR(memaddr, 0,16);
282 // set aram address
283 _dspReg[18] = (_dspReg[18]&~0x03ff)|_SHIFTR(aramaddr,16,16);
284 _dspReg[19] = (_dspReg[19]&~0xffe0)|_SHIFTR(aramaddr, 0,16);
286 // set cntrl bits
287 _dspReg[20] = (_dspReg[20]&~0x8000);
288 _dspReg[20] = (_dspReg[20]&~0x03ff)|_SHIFTR(len,16,16);
289 _dspReg[21] = (_dspReg[21]&~0xffe0)|_SHIFTR(len, 0,16);
291 __ARWaitDma();
292 __ARClearInterrupt();
295 static void __ARClearArea(u32 aramaddr,u32 len)
297 u32 currlen,curraddr,endaddr;
298 static u8 zero_buffer[2048] ATTRIBUTE_ALIGN(32);
300 while(!(_dspReg[11]&0x0001));
302 memset(zero_buffer,0,2048);
303 DCFlushRange(zero_buffer,2048);
305 curraddr = aramaddr;
306 endaddr = aramaddr+len;
308 currlen = 2048;
309 while(curraddr<endaddr) {
310 if((endaddr-curraddr)<currlen) currlen = ((endaddr-curraddr)+31)&~31;
311 __ARWriteDMA((u32)zero_buffer,curraddr,currlen);
312 curraddr += currlen;
316 static void __ARCheckSize()
318 u32 i,arsize,arszflag;
319 static u32 test_data[8] ATTRIBUTE_ALIGN(32);
320 static u32 dummy_data[8] ATTRIBUTE_ALIGN(32);
321 static u32 buffer[8] ATTRIBUTE_ALIGN(32);
323 #ifdef _AR_DEBUG
324 printf("__ARCheckSize()\n");
325 #endif
327 while(!(_dspReg[11]&0x0001));
329 __ARSize = __ARInternalSize = arsize = 0x1000000;
330 _dspReg[9] = (_dspReg[9]&~0x3f)|0x23;
332 for(i=0;i<8;i++) {
333 test_data[i] = 0xBAD1BAD0;
334 dummy_data[i] = 0xDEADBEEF;
336 DCFlushRange(test_data,32);
337 DCFlushRange(dummy_data,32);
339 __ARExpansionSize = 0;
340 __ARWriteDMA((u32)test_data,0x1000000,32);
341 __ARWriteDMA((u32)test_data,0x1200000,32);
342 __ARWriteDMA((u32)test_data,0x2000000,32);
343 __ARWriteDMA((u32)test_data,0x1000200,32);
344 __ARWriteDMA((u32)test_data,0x1400000,32);
346 memset(buffer,0,32);
347 DCFlushRange(buffer,32);
349 __ARWriteDMA((u32)dummy_data,0x1000000,32);
351 DCInvalidateRange(buffer,32);
352 __ARReadDMA((u32)buffer,0x1000000,32);
353 _nop();
355 arszflag = 0x03;
356 if(buffer[0]==dummy_data[0]) {
357 memset(buffer,0,32);
358 DCFlushRange(buffer,32);
359 __ARReadDMA((u32)buffer,0x1200000,32);
360 _nop();
361 if(buffer[0]==dummy_data[0]) {
362 __ARExpansionSize = 0x200000;
363 arsize += 0x200000;
364 goto end_check; //not nice but fast
367 memset(buffer,0,32);
368 DCFlushRange(buffer,32);
369 __ARReadDMA((u32)buffer,0x2000000,32);
370 _nop();
371 if(buffer[0]==dummy_data[0]) {
372 __ARExpansionSize = 0x400000;
373 arsize += 0x400000;
374 arszflag |= 0x08;
375 goto end_check; //not nice but fast
378 memset(buffer,0,32);
379 DCFlushRange(buffer,32);
380 __ARReadDMA((u32)buffer,0x1400000,32);
381 _nop();
382 if(buffer[0]==dummy_data[0]) {
383 __ARExpansionSize = 0x1000000;
384 arsize += 0x1000000;
385 arszflag |= 0x18;
386 } else {
387 __ARExpansionSize = 0x2000000;
388 arsize += 0x2000000;
389 arszflag |= 0x20;
391 end_check:
392 _dspReg[9] = (_dspReg[9]&~0x3f)|arszflag;
395 #ifdef _AR_DEBUG
396 printf("__ARCheckSize(%d)\n",arsize);
397 #endif
398 *(u32*)0x800000d0 = arsize;
399 __ARSize = arsize;
402 static void __ARHandler()
404 #ifdef _AR_DEBUG
405 printf("__ARHandler()\n");
406 #endif
407 __ARClearInterrupt();
409 if(__ARDmaCallback)
410 __ARDmaCallback();