/************************************************************************************
* This file contains necessary functions to access the SPI from Phy to Abel.
*
* Author(s):
*
* (c) Copyright 2004, Freescale, Inc.  All rights reserved.
*
* Freescale Confidential Proprietary
* Digianswer Confidential
*
* No part of this document must be reproduced in any form - including copied,
* transcribed, printed or by any electronic means - without specific written
* permission from Freescale.
*
* Last Inspected: 19-aug-2003
* Last Tested:
*
* Revision history:
*   date      Author    Comments
*   ------    ------    --------
*   200803     FFJ      Created
*   271003     TRL      Optimized phy_read_spi_1 and phy_write_spi_1
*   200904      JT      Optimized functions for Speed, Space and readability 
*   261004  JT/FFJ      Fixed BDM/SPI issue. (BDM is now allowed to cycle steal, while SPI is running) Optimized as well
************************************************************************************/
#include "gb60_io.h"

#include "DigiType.h"
#include "abelreg.h"
#include "phy_spi.h"
#include "Target.h"

/************************************************************************************
* Local defines
************************************************************************************/
#define AssertCE                PTED &= ~0x04;
#define DeAssertCE              PTED |= 0x04;

#define WaitSPITxHoldingEmpty   while (!(SPIS & 0x20));  //Check if it is legal to write into TX Double buffer register
#define WaitSPITransferDone     Wait_8_BitClks(); SPIS; //__asm nop; while (!(SPIS & 0x80));  //Using RXDone flag to check all transfer done (tx followed by rx)
#define WaitSPITransmitterEmpty WaitSPITxHoldingEmpty; \
                                Wait_6_BitClks(); SPIS; SPID;

void Wait_8_BitClks(void);
/************************************************************************************
* Local macros
************************************************************************************/
/*
*** Easy to read versions (slow and safe) for read core macros  ***
#define SPIDummyWrite           __asm STA 0x2D ! {}, {};

#define phy_read_spi_int_core_macro(addr, pb) \
  AssertCE                              \
                                        \
  SPID = addr;                          \
  WaitSPITransferDone                   \
  SPID;                                 \
                                        \
  SPIDummyWrite                         \
  WaitSPITransferDone                   \
  pb[0] = SPID;                         \
                                        \
  SPIDummyWrite                         \
  WaitSPITransferDone                   \
  pb[1] = SPID;                         \
                                        \
  DeAssertCE
*/


/*
#define phy_read_spi_int_core_macro(addr, pb) \
                                              \
  AssertCE                                    \
                                              \
  SPID = addr;                                \
  WaitSPITransferDone                         \
  SPID=SPID;                                  \
                                              \
  WaitSPITransferDone                         \
  tmpAccum = SPID;                            \
  SPID = tmpAccum;                            \
  pb[0] = tmpAccum;                           \
                                              \
  WaitSPITransferDone                         \
  pb[1] = SPID;                               \
  DeAssertCE 
*/

/************************************************************************************
* Local macros
************************************************************************************/
#define phy_read_spi_int_core_macro()               \
{   asm BSR   Wait_8_BitClks;                       \
    asm LDA   43;                                   \
    asm MOV   45,45;                                \
    asm BSR   Wait_8_BitClks;                       \
    asm LDA   43;                                   \
    asm LDA   45;                                   \
    asm STA   45;                                   \
    asm STA   ,X;                                   \
    asm BSR   Wait_6_BitClks;                       \
    asm LDA   43;                                   \
    asm LDA   45;                                   \
    asm STA   1,X;                                  \
}

#define phy_read_spi_int_core_swap_macro()          \
{   asm BSR   Wait_8_BitClks;                       \
    asm LDA   43;                                   \
    asm MOV   45,45;                                \
    asm BSR   Wait_8_BitClks;                       \
    asm LDA   43;                                   \
    asm LDA   45;                                   \
    asm STA   45;                                   \
    asm STA   1,X;                                  \
    asm BSR   Wait_6_BitClks;                       \
    asm LDA   43;                                   \
    asm LDA   45;                                   \
    asm STA   ,X;                                   \
}



/*************************************************************************
*           HardCore HCS08 Delay Helper Functions                        *
*************************************************************************/
void Wait_6_BitClks(void)       // Duration : BRA/BSR/JSR to here: 3/5/6 mcuCycles 
{                               //            2xNOP+RTS          :     8 mcuCycles
  __asm nop;
  __asm nop;
}

void Wait_8_BitClks(void) 
{                               // Duration : BSR/JSR to here: 5/6 mcuCycles
  Wait_6_BitClks();             // Uses BRA (3 mcuCyc) to above function (so it really only takes 5,5 bitclks)
}

/*************************************************************************
*                       SPI Read functions                               *
*************************************************************************/

/*****************************************************************
* This function reads 1 16bit Abel Register at address "addr"    *
* This read may be called from anywhere. (Async and sync context)*
*****************************************************************/
void phy_read_spi(uint8_t addr, uint8_t *pb)
{
  uint8_t   CCR;
  uint8_t *dummy=pb;

  STOREINTERRUPTS(CCR)
  DISABLE_ALL_INTERRUPTS;
  AssertCE
  SPID=addr;
  phy_read_spi_int_core_macro(); // Macro
  DeAssertCE
  RESTOREINTERRUPTS(CCR)
}

/****************************************************************
* This function reads 1 16bit Abel Register at address "addr"   *
* This read is only to be used from Abel interrupt context      *
****************************************************************/
void phy_read_spi_int(uint8_t addr, uint8_t * pb)
{
  uint8_t *dummy=pb;

  DISABLE_ALL_INTERRUPTS;
  AssertCE
  SPID=addr;
  phy_read_spi_int_core_macro(); // Macro
  DeAssertCE
  ENABLE_ALL_INTERRUPTS;
}

/****************************************************************
* This function reads 1 16bit Abel Register at address "addr"   *
* This read is only to be used from Abel interrupt context      *
* Note: Reversed Endianess!                                     *
****************************************************************/
void phy_read_spi_int_swap(uint8_t addr, uint8_t *pb)
{
  uint8_t *dummy=pb;

  DISABLE_ALL_INTERRUPTS;
  AssertCE
  SPID=addr;
  phy_read_spi_int_core_swap_macro(); // Macro
  DeAssertCE
  ENABLE_ALL_INTERRUPTS;
}


/*************************************************************************
*                      SPI Write functions                               *
*************************************************************************/

#pragma INLINE_NEXT_FUNCTION
/********************************************************************
* Write one 16bit data-location into Abel at address "addr"         *
* without monitoring SPSCR. Data is transferred to this routine     *
* over the stack.                                                   *
* Unprotected - only to be called with disabled interrupts          *
* Function inlined in below functions                               *
********************************************************************/
void phy_write_spi_int_core(uint8_t addr, uint16_t pb)
{
  AssertCE
  SPID = addr;            // Write Addr byte

  WaitSPITxHoldingEmpty   // Wait for room in holding register 
  SPID =(uint8_t)(pb>>8); // Write MSB data byte 

  WaitSPITxHoldingEmpty   // Wait for room in holding register
  SPID = (uint8_t) pb;    // Write LSB data byte

  WaitSPITransmitterEmpty // Wait for transmit queue empty
  DeAssertCE
}


#pragma DISABLE_WARNING(InlineFunctionCall_c)
/********************************************************************
* Write one 16bit data-location into Abel at address "addr"         *
* without monitoring SPSCR.                                         *
* This write is only to be used from Abel interrupt context         *
* Protected!                                                        *
********************************************************************/
void phy_write_spi_int(uint8_t addr, uint16_t content)
{
  DISABLE_ALL_INTERRUPTS;
  phy_write_spi_int_core(addr, content); // Inline Expansion
  ENABLE_ALL_INTERRUPTS;
}

/********************************************************************
* Write one 16bit data-location into Abel at address "addr"         *
* without monitoring SPSCR.                                         *
* This write is only to be used from Abel interrupt context         *
* Not Protected!                                                    *
********************************************************************/
void phy_write_spi_int_fast(uint8_t addr, uint16_t content)
{
  phy_write_spi_int_core(addr, content); // Inline Expansion
}

#pragma RESTORE_WARNING(InlineFunctionCall_c)


/********************************************************************
* Write one 16bit data-location into Abel at address "addr"         *
* without monitoring SPSCR. Data is transferred to this routine     *
* over the stack.                                                   *
********************************************************************/
void phy_write_spi(uint8_t addr, uint16_t content){
  uint8_t CCR;
  STOREINTERRUPTS(CCR)
  DISABLE_ALL_INTERRUPTS;
  phy_write_spi_int_fast(addr, content); // Normal Function call
  RESTOREINTERRUPTS(CCR)
}

