/*
 FX2 firmware: common setup functions
 
 
 Copyright (c) 2008-2012 Dimtel, Inc., All Rights Reserved

 $Id: common.c,v 1.3 2013/06/06 04:35:11 dim Exp $
 $Date: 2013/06/06 04:35:11 $
 $Author: dim $
 $Revision: 1.3 $
 $Log: common.c,v $
 Revision 1.3  2013/06/06 04:35:11  dim
 Added EP8 OUT to interface 0 for fast JTAG block loading

 Revision 1.2  2013/06/05 05:06:20  dim
 Autopointer config, zero wait state on external memory

 Revision 1.1  2012/11/11 01:24:32  dim
 Moved from BxB, adapted to compile for both LLRF4 and IGP12

 Revision 1.1  2011/12/27 19:31:45  dim
 Updated to remove deprecated constructs (at, sfr, xdata, sbit)


*/

#include "fx2regs.h"
#include "common.h"
#include "fifo.h"
#include "hwdef.h"
#include "../include/usb_defs.h"

void basic_init(void)
{
  CPUCS  = bmCLKSPD48MHZ; /* 48 MHz CPU clock*/
  SYNCDELAY;
  SYNCDELAY;
  
  CKCON  &= (~bmMD0 & ~bmMD1 & ~bmMD2); /* Set MOVX cycles to 2 */
  SYNCDELAY;

  REVCTL = bmDYN_OUT | bmENH_PKT; /* TRM strongly advises this */
  SYNCDELAY;

  /* Interface configuration:
     Internal clock source
     Enable IFCLK output
     48 MHz clock
     Set interface to slave FIFO mode
  */
  IFCONFIG = bmIFCLKSRC | bmIFCLKOE | bm3048MHZ | bmIFCFG0 | bmIFCFG1;
  SYNCDELAY;
  
  /* Endpoint configuration: turn on 2, 6, and 8 */
  EP2CFG = bmVALID | bmBULK | bmDOUBLEBUF;        SYNCDELAY;
  EP6CFG = bmVALID | bmIN | bmBULK | bmDOUBLEBUF; SYNCDELAY;
  EP4CFG = bmBULK | bmDOUBLEBUF;                  SYNCDELAY;
  EP8CFG = bmVALID | bmBULK | bmDOUBLEBUF;        SYNCDELAY;
  
  /* Set up port A bits used for JTAG communication */
  PORTACFG   = 0x00;   /* PA.7, PA.1, PA.0 - normal functions */
  SYNCDELAY;

  /* Initial output values set to 0 */
  IOA = 0x0;

  /* Direction setting */
  OEA = bmPORT_A_TCK | bmPORT_A_TMS | bmPORT_A_TDI;
  
  /* Autopointer setup */
  AUTOPTRSETUP = bmAPTREN | bmAPTR1INC | bmAPTR2INC;
}


void fpga_reset(void)
{
  /* Pulse FPGA reset. This function depends on EP4 FIFO being empty.
     fifo_init() sets up EP4 as an input FIFO. Since FPGA never drives
     FIFOADR[0], EP4 is never selected and remains empty.
     
     With active low polarity, normal state is 0x09 (EP4 EF, active, low).
     To pulse reset we select 0x0d (EP4 FF, inactive, high)
  */
  PINFLAGSCD = 0x0d;
  SYNCDELAY;
  
  /* Now clear EP2 and EP6 FIFOs */
  fifo_init();
  
  PINFLAGSCD = 0x09;
}

/* Perform the renumeration */
void renumerate(void)
{
  USBCS |= bmDISCON | bmRENUM;
  
  delay(500); /* Wait 0.5 seconds */
  
  /* Clear USB interrupts */
  USBIRQ = 0xff; EPIRQ = 0xff;
  
  /* Reset USB interrupt flag */
  EXIF &= ~bmEXIF_USBINT;
  
  /* Reconnect to USB */
  USBCS &= ~bmDISCON;
}

void reset_toggle(uchar ep)
{
  TOGCTL = (ep & USB_ENDPOINT_DIR_MASK) >> 3 | (ep & USB_ENDPOINT_NUMBER_MASK);
  TOGCTL |= bmRESETTOGGLE;
}

static void delay_1ms(void) __naked
{
  /* Inner loop: 248*4 = 992 cycles
     Outer loop: 12*(3 + 992 + 3) + 6 = 11982 cycles
     
     Call from delay() adds 22 cycles => 12004 cycles
  */
  __asm
        mov	r0, #12		/* 2 */
outer:  mov     r1, #249	/* 2 */
        nop			/* 1 */
inner:  nop			/* 1 */
        djnz    r1, inner	/* 3 */
        djnz	r0, outer	/* 3 */
        ret			/* 4 */
  __endasm;
}

void delay (ushort ms)
{
  while (ms--)
    delay_1ms();
}                                                            
                                                            
__xdata char *write_short(__xdata char *ptr, ushort value)
{
  *ptr++ = (uchar)(value >> 8);
  *ptr++ = (uchar)(value & 0xff);
  return ptr;
}

void poll_ep0(void)
{
  EP0BCL = 0; /* Set the busy bit */
  
  while (EP0CS & bmEPBUSY);
}
