/*

 *            Copyright (c) 1998-2004 by NETsilicon Inc.

 *

 *  This software is copyrighted by and is the sole property of

 *  NETsilicon.  All rights, title, ownership, or other interests

 *  in the software remain the property of NETsilicon.  This

 *  software may only be used in accordance with the corresponding

 *  license agreement.  Any unauthorized use, duplication, transmission,

 *  distribution, or disclosure of this software is expressly forbidden.

 *

 *  This Copyright notice may not be removed or modified without prior

 *  written consent of NETsilicon.

 *

 *  NETsilicon, reserves the right to modify this software

 *  without notice.

 *

 *  NETsilicon

 *  411 Waverley Oaks Road                  USA 781.647.1234

 *  Suite 227                               http://www.netsilicon.com

 *  Waltham, MA 02452                       AmericaSales@netsilicon.com

 *

 */



#include <string.h>

#include <stdlib.h>

#include <errno.h>

#include <tx_port.h>

#include <semaphore.h>

#include <ddi.h>

#include <netosIo.h>

#include <reg_def.h>



#include <serParam.h>



#include "netos_spi.h"

#include <NA_ISR.h>

#include <Dma_def.h>

#include <sysClock.h>

#include <reg_def.h>

#include <bool.h>

#include <tx_api.h>

#include <ncc_init.h>

#include "spi_mod.h"



static volatile fb_buffer_desc_t  ser_tx_buffer_des[NUM_NCC_SER_CHAN][NUM_DMA_SPI_BUF];  /* DMA transmission channel descriptor */

static volatile fb_buffer_desc_t  ser_rx_buffer_des[NUM_NCC_SER_CHAN][NUM_DMA_SPI_BUF];  /* DMA receiving channel descriptor */



/* #define EEPROM_SUPPORT   1 */



/*

 *  Function: spi_init_tx_dma

 *

 *  Description: initialized dma transmit buffer descriptor

 *  and started DMA operation

 *

 *

 *  called by: netos_spiwrite,netos_spiread sendWriteEnable, sendEEPROMCommand

 *

 *  Parameter:

 *

 *      channel      channel number as set in the channel's

 *                   device table entry

 *  Return Values:

 *

 *      EXIT_SUCCESS

 *	EAGAIN          the semaphore was already locked,

 *      EINVAL          'sem' is not a valid semaphore,

 *      ENOSYS          semaphores are not supported,

 *      EINTR           the function was interrupted by a signal,

 *      EDEADLK         a deadlock condition was detected.

 */



int spi_init_tx_dma(ONSPI_CHAN  *pch)  /* set up the dma for output and start it */

{

     

    int channel;

    SPIBUFFER volatile *q;

    DMA_CTRL_REG_TYPE *ptr_dmareg;

    int status;



    status = sem_trywait(pch->spi_int_sem);

    if (status != TX_SUCCESS)

    {

        /* something wrong */

    	sem_post(pch->spi_int_sem);

	    return status;

    }

    if (pch->ISRlevel != -1)

	NAEnableIsr(pch->ISRlevel);

    

    channel = pch->port;

    switch (channel)

    {

        case 0 :

	        ptr_dmareg = DMA_CONF_PTR(DMA8);

    	    break;

    	case 1:

	        ptr_dmareg = DMA_CONF_PTR(DMA10);

	        break;

    }



    q = &(spiDataBuffer[channel]);

    

#ifdef EEPROM_SUPPORT

    ser_tx_buffer_des[channel][0].lower_word.bits.wrap = 0;

    ser_tx_buffer_des[channel][0].lower_word.bits.intr = 0;

    ser_tx_buffer_des[channel][0].lower_word.bits.last = 0;

    ser_tx_buffer_des[channel][0].lower_word.bits.sbp =  (UINT32)q->ptrSerData;

    ser_tx_buffer_des[channel][0].upper_word.bits.status = 0;

    ser_tx_buffer_des[channel][0].upper_word.bits.full = 1;

    ser_tx_buffer_des[channel][0].upper_word.bits.buflen =

	(q->countServData & DMA_BUF_LEN_MSK);



    ser_tx_buffer_des[channel][1].lower_word.bits.wrap = 1;

    ser_tx_buffer_des[channel][1].lower_word.bits.intr = 0;

    ser_tx_buffer_des[channel][1].lower_word.bits.last = 0;

    ser_tx_buffer_des[channel][1].lower_word.bits.sbp =  (UINT32)q->ptrDataBuffer;

    ser_tx_buffer_des[channel][1].upper_word.bits.status = 0;

    if (q->countForBufferData == 0)

    {

    	ser_tx_buffer_des[channel][1].upper_word.bits.full = 0;

	    ser_tx_buffer_des[channel][0].lower_word.bits.wrap = 1;

    }

    else

    {

	    ser_tx_buffer_des[channel][1].upper_word.bits.full = 1;

    }



    ser_tx_buffer_des[channel][1].upper_word.bits.buflen =

	(q->countForBufferData & DMA_BUF_LEN_MSK);

#else

    ser_tx_buffer_des[channel][0].lower_word.bits.wrap = 1;

    ser_tx_buffer_des[channel][0].lower_word.bits.intr = 0;

    ser_tx_buffer_des[channel][0].lower_word.bits.last = 0;

    ser_tx_buffer_des[channel][0].lower_word.bits.sbp =  (UINT32)q->ptrDataBuffer;



    ser_tx_buffer_des[channel][0].upper_word.bits.status = 0;

    ser_tx_buffer_des[channel][0].upper_word.bits.buflen =

	    (q->countForBufferData & DMA_BUF_LEN_MSK);

	ser_tx_buffer_des[channel][0].upper_word.bits.full = 1;

#endif



    if (pch->SSport != NULL && !pch->slaveMode)

    {

	    *(pch->SSport) &= pch->SSsetLowMask;

    }

    

    /*now assign buffer descriptor to dma control register*/



    ptr_dmareg->ctrl_reg = 0;

    ptr_dmareg->bd_ptr = (UINT32)  &ser_tx_buffer_des[channel];

    ptr_dmareg->stat_reg =

	  (DMA_CLAER_ALL_INTERRUPTS | DMA_NORM_DONE_IE | DMA_ERR_DONE_IE | DMA_CHAN_ABORT_IE);

    ptr_dmareg->ctrl_reg = ( FLY_BY_READ | DMA_CHANNEL_ENABLE);

     

#if 0  

   printf(" After setup tx_upper_word[0] = %X, tx_lower_word[0] = %X\n",

	   ser_tx_buffer_des[channel][0].upper_word.reg,

	   ser_tx_buffer_des[channel][0].lower_word.reg );

   printf(" After  setup tx_upper_word[1] = %X, tx_lower_word[1] = %X\n",

	   ser_tx_buffer_des[channel][1].upper_word.reg,

	   ser_tx_buffer_des[channel][1].lower_word.reg );

#endif



#ifdef debug_spi

    /* PORTC2 used for timing set it LOW */

    *NARM_PORTC_ADDR &= 0xFEFFFFFB;

    intCount = 0;

#endif

    

    SER_REG(channel, CTRL_REGA) |= XMITR_DMA_ON; /* And start DMA */

    NAEnableIsr (pch->txDmalevel);

    return status;

}



/*

 *  Function: spi_init_rx_dma

 *

 *  Description: initialized dma receive buffer descriptor

 *  and started DMA operation

 *

 *

 *  called by:  betos_spiread, sendEEPROMCommand

 *

 *  Parameter:

 *

 *      channel      channel number as set in the channel's

 *                   device table entry

 *  Return Values:

 *

 *      EXIT_SUCCESS

 *	EAGAIN          the semaphore was already locked,

 *      EINVAL          'sem' is not a valid semaphore,

 *      ENOSYS          semaphores are not supported,

 *      EINTR           the function was interrupted by a signal,

 *      EDEADLK         a deadlock condition was detected.

 */

int spi_init_rx_dma(ONSPI_CHAN  *pch)  /* set up the dma for input and start it */

{

    int channel;

    SPIBUFFER volatile *q;

    DMA_CTRL_REG_TYPE *ptr_dmareg;

    int status;

    

    if (pch->slaveMode)

    {

	    status = sem_trywait(pch->spi_int_sem);

    	if (status != TX_SUCCESS)

	    {

            /* something is wrong */

    	    sem_post(pch->spi_int_sem);

	        return status;

    	}



    	if (pch->ISRlevel != -1)

        {

	        NAEnableIsr(pch->ISRlevel);

        }

    }

    else

    {

	    status = TX_SUCCESS;

    }



    channel = pch->port;

    switch (channel)

    {

        case 0 :

	        ptr_dmareg = DMA_CONF_PTR(DMA7);

	        break;

    	case 1:

	        ptr_dmareg = DMA_CONF_PTR(DMA9);

    	    break;

    }

     

    q = &(spiInBuffer[channel]);

    

#ifdef EEPROM_SUPPORT

    ser_rx_buffer_des[channel][0].lower_word.bits.wrap = 0;

    ser_rx_buffer_des[channel][0].lower_word.bits.intr = 0;

    ser_rx_buffer_des[channel][0].lower_word.bits.last = 0;

    ser_rx_buffer_des[channel][0].lower_word.bits.sbp =  (UINT32)q->ptrSerData;

    ser_rx_buffer_des[channel][0].upper_word.bits.status = 0;

    ser_rx_buffer_des[channel][0].upper_word.bits.full = 0;

    ser_rx_buffer_des[channel][0].upper_word.bits.buflen =

	(q->countServData & DMA_BUF_LEN_MSK) ; 



    ser_rx_buffer_des[channel][1].lower_word.bits.wrap = 1;

    ser_rx_buffer_des[channel][1].lower_word.bits.intr = 0;

    ser_rx_buffer_des[channel][1].lower_word.bits.last = 0;

    ser_rx_buffer_des[channel][1].lower_word.bits.sbp =  (UINT32)q->ptrDataBuffer;

    ser_rx_buffer_des[channel][1].upper_word.bits.status = 0;



    if (q->countForBufferData == 0)

    {

	    ser_rx_buffer_des[channel][1].upper_word.bits.full = 1;

	    ser_rx_buffer_des[channel][0].lower_word.bits.wrap = 1;

    }

    else

    {

	    ser_rx_buffer_des[channel][1].upper_word.bits.full = 0;

    }



    ser_rx_buffer_des[channel][1].upper_word.bits.buflen =

	(q->countForBufferData & DMA_BUF_LEN_MSK);



#else

    ser_rx_buffer_des[channel][0].lower_word.bits.wrap = 1;

    ser_rx_buffer_des[channel][0].lower_word.bits.intr = 0;

    ser_rx_buffer_des[channel][0].lower_word.bits.last = 0;

    ser_rx_buffer_des[channel][0].lower_word.bits.sbp =  (UINT32)q->ptrDataBuffer;



    ser_rx_buffer_des[channel][0].upper_word.bits.status = 0;

    ser_rx_buffer_des[channel][0].upper_word.bits.buflen =

	    (q->countForBufferData & DMA_BUF_LEN_MSK);

	ser_rx_buffer_des[channel][0].upper_word.bits.full = 0;



#endif



    if (pch->SSport != NULL && !pch->slaveMode)

    {

	   *(pch->SSport) &= pch->SSsetLowMask;

    }



     /*now assign buffer descriptor to dma control register*/



    ptr_dmareg->ctrl_reg = 0;

    ptr_dmareg->bd_ptr = (UINT32)ser_rx_buffer_des[channel];

    ptr_dmareg->stat_reg =

	  (DMA_CLAER_ALL_INTERRUPTS |  DMA_NORM_DONE_IE | DMA_ERR_DONE_IE | DMA_CHAN_ABORT_IE);

    ptr_dmareg->ctrl_reg = ( FLY_BY_WRITE | DMA_CHANNEL_ENABLE);

    

#if 0

    intCount = 0;

    printf(" After setup rx_upper_word[0] = %X, rx_lower_word[0] = %X\n",

	   ser_rx_buffer_des[channel][0].upper_word.reg,

	   ser_rx_buffer_des[channel][0].lower_word.reg );

    printf(" After  setup rx_upper_word[1] = %X, rx_lower_word[1] = %X\n",

	   ser_rx_buffer_des[channel][1].upper_word.reg,

	   ser_rx_buffer_des[channel][1].lower_word.reg );

#endif

    

    SER_REG(channel, CTRL_REGA) |= RECV_DMA_ON; /*  And start DMA */

    NAEnableIsr (pch->rxDmalevel);

    return status;

}





/**********************************************************************************

 **********************************************************************************

 ***                                                                            ***

 *** Function Name:  onspiDmaRd()                                                ***

 ***                                                                            ***

 *** Called by:                                                                 ***

 *** Function Calls: None                                                       ***

 ***                                                                            ***

 *** Comments: This routine handles Dma read interrupts from the NCC.           ***

 **********************************************************************************

 **********************************************************************************/



void onspiDmaRd (ONSPI_CHAN * pChan)                       /* interrupt function for DMA channel 9 which is for com1. */

{



   SPIBUFFER volatile *q;

   DMA_CTRL_REG_TYPE *ptr_dmareg;

   int channel;



   

    channel = pChan->port;

    

    switch (channel)

    {

        case 0 :

	    ptr_dmareg = DMA_CONF_PTR(DMA7);

	    break;

	case 1:

	     ptr_dmareg = DMA_CONF_PTR(DMA9);

	    break;

    }

    

#if 0

    /* PORTC2 used for timing set it HI */

    *NARM_PORTC_ADDR |= 4;

    reg9st[intCount] = ptr_dmareg->stat_reg;

    reg9cr[intCount++] = ptr_dmareg->ctrl_reg;

    rx_upper_word[0] = ser_rx_buffer_des[channel][0].upper_word.reg;

    rx_lower_word[0] = ser_rx_buffer_des[channel][0].lower_word.reg;

    rx_upper_word[1] = ser_rx_buffer_des[channel][1].upper_word.reg;

    rx_lower_word[1] = ser_rx_buffer_des[channel][1].lower_word.reg;

#endif



    

    

   if ( (ptr_dmareg->stat_reg & DMA_NORM_DONE_IP) == DMA_NORM_DONE_IP)  

    {

	ptr_dmareg->ctrl_reg = 0;



	q = &(spiInBuffer[channel]);



#ifdef EEPROM_SUPPORT

	if (ser_rx_buffer_des[channel][0].upper_word.bits.full == 1)

	    q->countServData -=

	      ser_rx_buffer_des[channel][0].upper_word.bits.buflen ;



	if (ser_rx_buffer_des[channel][1].upper_word.bits.full == 1)

	    q->countForBufferData -=

		ser_rx_buffer_des[channel][1].upper_word.bits.buflen;

#else

	if (ser_rx_buffer_des[channel][1].upper_word.bits.full == 1)

    {

	    q->countForBufferData -=

		    ser_rx_buffer_des[channel][0].upper_word.bits.buflen;

    }



#endif



	if (pChan->ISRlevel == -1)

	    tx_semaphore_put (&((pChan->spi_int_sem)->sem));

    }

   ptr_dmareg->stat_reg |= DMA_CLAER_ALL_INTERRUPTS;

   

#if 0

    /* PORTC2 used for timing set it LOW */

    *NARM_PORTC_ADDR &= 0xFEFFFFFB;

#endif

   

}





/**********************************************************************************

 **********************************************************************************

 ***                                                                            ***

 *** Function Name:  onspiDmaWr()                                                ***

 ***                                                                            ***

 *** Called by:                                                                 ***

 *** Function Calls: None                                                       ***

 ***                                                                            ***

 *** Comments: This routine handles Dma write interrupts from the NCC.          ***

 **********************************************************************************



 **********************************************************************************/



void onspiDmaWr (ONSPI_CHAN * pChan)

{

    

    SPIBUFFER volatile *q;

    DMA_CTRL_REG_TYPE *ptr_dmareg;

    int channel;



    channel = pChan->port;

    

    switch (channel)

    {

        case 0 :

	    ptr_dmareg = DMA_CONF_PTR(DMA8);

	    break;

	case 1:

	     ptr_dmareg = DMA_CONF_PTR(DMA10);

	    break;

    }

#ifdef debug_spi



    /*  PORTC0 used for timing set it HI */

    *NARM_PORTC_ADDR |= 4;

    

    reg10st = *NARM_DSIER10_ADDR;/* (*NCC_DMA).dmasr10.reg; */

    reg10cr = *NARM_DCR10_ADDR; /* (*NCC_DMA).dmacr10.reg;*/

   

    tx_upper_word[intCount] = ser_tx_buffer_des[channel][0].upper_word.reg;

    tx_lower_word[intCount] = ser_tx_buffer_des[channel][0].lower_word.reg;

    tx_upper_word[intCount+1] = ser_tx_buffer_des[channel][1].upper_word.reg;

    tx_lower_word[intCount+1] = ser_tx_buffer_des[channel][1].lower_word.reg;



    intCount += 2;

#endif

    

    if ( (ptr_dmareg->stat_reg & DMA_NORM_DONE_IP) == DMA_NORM_DONE_IP)

    {

	ptr_dmareg->ctrl_reg = 0;





	q = &(spiDataBuffer[channel]);



#ifdef EEPROM_SUPPORT

	if (ser_tx_buffer_des[channel][0].upper_word.bits.full == 0)

	    q->countServData -=

		ser_tx_buffer_des[channel][0].upper_word.bits.buflen ;



	if (ser_tx_buffer_des[channel][1].upper_word.bits.full == 0)

	    q->countForBufferData -=

		ser_tx_buffer_des[channel][1].upper_word.bits.buflen;

#else

	if (ser_tx_buffer_des[channel][0].upper_word.bits.full == 0)

    {

	    q->countForBufferData -=

    		ser_tx_buffer_des[channel][0].upper_word.bits.buflen;

    }

#endif



	/* if no read or slave - release samaphore */

	 if ((!pChan->readInProgres || pChan->slaveMode ) && (pChan->ISRlevel == -1))

	    tx_semaphore_put (&((pChan->spi_int_sem)->sem));

    }

   ptr_dmareg->stat_reg |= DMA_CLAER_ALL_INTERRUPTS;

   

#if 0

    /* PORTC2 used for timing set it LOW */

    *NARM_PORTC_ADDR &= 0xFEFFFFFB;

#endif

   

}



