//  ____     ___ |    / _____ _____
// |  __    |    |___/    |     |
// |___| ___|    |    \ __|__   |     gsKit Open Source Project.
// ----------------------------------------------------------------------
// Copyright 2004 - Chris "Neovanglist" Gilbert <Neovanglist@LainOS.org>
// Licenced under Academic Free License version 2.0
// Review gsKit README & LICENSE files for further details.
//
// dmaCore.c - Core DMA Routines.
// Parts taken from emoon's BreakPoint Demo Library
//

#include "dmaKit.h"
#include "dmaArrays.h"

#include <stdio.h>
#include <kernel.h>

int dmaKit_wait(u16 channel, unsigned int timeout)
{
	#ifdef GSKIT_DEBUG
	printf("Waiting for DMA Channel %i - %s\n",channel, DMA_NAME[channel]);
	#endif

	while((*(volatile u32 *)DMA_CHCR[channel]) & 0x00000100)
	{
		if( timeout != 0)
		{
			if ( timeout == 1 )
			{
				printf("Timed out waiting for DMA Channel %i - %s to be clear.\n",channel, DMA_NAME[channel]);
				return -1;
			}
			timeout--;
		}
	}

	#ifdef GSKIT_DEBUG
	printf("DMA Channel %i - %s is now clear.\n",channel, DMA_NAME[channel]);
	#endif
	
	return 0;
}

void dmaKit_wait_fast(void)
{
	asm __volatile__("sync.l; sync.p;" \
			 "0:" \
			 "bc0t 0f; nop;" \
			 "bc0t 0f; nop;" \
			 "bc0t 0f; nop;" \
			 "bc0f 0b; nop;" \
			 "0:");
}

void dmaKit_send(u16 channel, void *data, unsigned int size)
{
	#ifdef GSKIT_DEBUG
	printf("Sending to DMA Channel %i - %s\n",channel, DMA_NAME[channel]);
	#endif

	DMA_SET_CIS(1 << channel);

	SyncDCache(data, data+size*16);

	if(DMA_QWC[channel])
		*(volatile u32 *)DMA_QWC[channel] = size;
	*(volatile u32 *)DMA_MADR[channel] = DMA_SET_MADR((u32)data, 0);
	*(volatile u32 *)DMA_CHCR[channel] = DMA_SET_CHCR(1,	// Direction
							  0,	// ChainMode
							  0,	// Address Stack Pointer
							  DMA_TAG_ENABLE[channel], // Transfer DMA Tag
							  0,    // Enable Interrupts
							  1,	// Start DMA
							  0 );	// Priority Control Enable??

	#ifdef GSKIT_DEBUG
	printf("Sent to DMA Channel\n");
	#endif

	return;
}

void dmaKit_send_ucab(u16 channel, void *data, unsigned int size)
{
        #ifdef GSKIT_DEBUG
        printf("Sending to DMA Channel %i - %s\n",channel, DMA_NAME[channel]);
        #endif

	DMA_SET_CIS(1 << channel);

        if(DMA_QWC[channel])
                *(volatile u32 *)DMA_QWC[channel] = size;
        *(volatile u32 *)DMA_MADR[channel] = DMA_SET_MADR((u32)data - 0x30000000, 0); 
        *(volatile u32 *)DMA_CHCR[channel] = DMA_SET_CHCR(1,    // Direction
                                                          0,    // ChainMode
                                                          0,    // Address Stack Pointer
                                                          DMA_TAG_ENABLE[channel], // Transfer DMA Tag
                                                          0,    // Enable Interrupts
                                                          1,    // Start DMA
                                                          0 );  // Priority Control Enable??

        #ifdef GSKIT_DEBUG
        printf("Sent to DMA Channel\n");
        #endif

        return;
}

void dmaKit_send_spr(u16 channel, void *data, unsigned int size)
{
	#ifdef GSKIT_DEBUG
	printf("Sending to DMA Channel w/ SPR %i - %s\n",channel, DMA_NAME[channel]);
	#endif

	DMA_SET_CIS(1 << channel);

	if(DMA_QWC[channel])
		*(volatile u32 *)DMA_QWC[channel] = size;
	*(volatile u32 *)DMA_MADR[channel] = DMA_SET_MADR((u32)data, 1);
	*(volatile u32 *)DMA_CHCR[channel] = DMA_SET_CHCR(1,    // Direction
							  0,    // ChainMode
							  0,    // Address Stack Pointer
							  DMA_TAG_ENABLE[channel], // Transfer DMA Tag
							  0,    // Enable Interrupts
							  1,    // Start DMA
							  0 );  // Priority Control Enable??
	#ifdef GSKIT_DEBUG
	printf("Sent to DMA Channel w/ SPR\n");
	#endif

	return;
}

void dmaKit_send_chain(u16 channel, void *data, unsigned int size)
{
	#ifdef GSKIT_DEBUG
	printf("Sending to DMA Channel in Chain Mode %i - %s\n",channel, DMA_NAME[channel]);
	#endif

	DMA_SET_CIS(1 << channel);

	SyncDCache(data, data+size*16);

	if(DMA_QWC[channel])
	       	*(volatile u32 *)DMA_QWC[channel] = 0;

	*(volatile u32 *)DMA_TADR[channel] = DMA_SET_TADR((u32)data, 0);
        *(volatile u32 *)DMA_CHCR[channel] = DMA_SET_CHCR(1,	// Direction
							  1,	// ChainMode
							  0,	// Address Stack Pointer
							  DMA_TAG_ENABLE[channel], // Transfer DMA Tag
							  0,    // Enable Interrupts
							  1,	// Start DMA
							  0 );	// Priority Control Enable??

	#ifdef GSKIT_DEBUG
	printf("Sent to DMA Channel in Chain Mode\n");
	#endif
        return;
}

void dmaKit_send_chain_ucab(u16 channel, void *data)
{
        #ifdef GSKIT_DEBUG
        printf("Sending to DMA Channel in Chain Mode from UCAB %i - %s\n",channel, DMA_NAME[channel]);
        #endif

	DMA_SET_CIS(1 << channel);

        if(DMA_QWC[channel])
                *(volatile u32 *)DMA_QWC[channel] = 0;

        *(volatile u32 *)DMA_TADR[channel] = DMA_SET_TADR((u32)data - 0x30000000, 0);
        *(volatile u32 *)DMA_CHCR[channel] = DMA_SET_CHCR(1,    // Direction
                                                          1,    // ChainMode
                                                          0,    // Address Stack Pointer
                                                          DMA_TAG_ENABLE[channel], // Transfer DMA Tag
                                                          0,    // Enable Interrupts
                                                          1,    // Start DMA
                                                          0 );  // Priority Control Enable??

        #ifdef GSKIT_DEBUG
        printf("Sent to DMA Channel in Chain Mode from UCAB\n");
        #endif
        return;
}

void dmaKit_send_chain_spr(u16 channel, void *data)
{
	#ifdef GSKIT_DEBUG
	printf("Sending to DMA Channel in Chain Mode w/Scratchpad %i - %s\n",channel, DMA_NAME[channel]);
	#endif

	DMA_SET_CIS(1 << channel);

	if(DMA_QWC[channel])
	        *(volatile u32 *)DMA_QWC[channel] = 0;
	*(volatile u32 *)DMA_TADR[channel] = DMA_SET_TADR((u32)data, 1);
	*(volatile u32 *)DMA_CHCR[channel] = DMA_SET_CHCR(1, 	// Direction
							  1, 	// ChainMode
							  0, 	// Address Stack Pointer
							  DMA_TAG_ENABLE[channel], // Transfer DMA Tag
							  0,    // Enable Interrupts
							  1, 	// Start DMA
							  0 );	// Priority Control Enable??

	#ifdef GSKIT_DEBUG
	printf("Sent to DMA Channel in Chain Mode w/Scratchpad\n");
	#endif
	return;
}

void dmaKit_get_spr(u16 channel, void *data, void *dest, unsigned int size)
{
        #ifdef GSKIT_DEBUG
        printf("Sending to DMA Channel %i - %s\n",channel, DMA_NAME[channel]);
        #endif

	DMA_SET_CIS(1 << channel);

	if(DMA_QWC[channel])
		*(volatile u32 *)DMA_QWC[channel] = size;

	*(volatile u32 *)DMA_SADR[channel] = DMA_SET_SADR((u32)data&0x3fff);
	*(volatile u32 *)DMA_MADR[channel] = DMA_SET_MADR((u32)dest&0x0fffffff, 0);
        *(volatile u32 *)DMA_CHCR[channel] = DMA_SET_CHCR(0,    // Direction
                                                          0,    // ChainMode
                                                          0,    // Address Stack Pointer
                                                          DMA_TAG_ENABLE[channel], // Transfer DMA Tag
                                                          0,    // Enable Interrupts
                                                          1,    // Start DMA
                                                          0 );  // Priority Control Enable??

        #ifdef GSKIT_DEBUG
        printf("Sent to DMA Channel\n");
        #endif

        return;
}

