/*
 * phyConfig.c
 *
 *  Created on: 11-Jan-2018
 *      Author: balasubramani.c
 */
#include <string.h>
#include <stdbool.h>

#include <stdint.h>
#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/knl/Task.h>

#include "Board.h"
#include "phyConfig.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/ssi.h"
#include "driverlib/emac.h"

#include <inc/hw_memmap.h>
#include <inc/hw_types.h>
#include <inc/hw_emac.h>

uint32_t ui16TxBufData[6], ui16RxBufData[6];
uint8_t uiRange = 1;

Semaphore_Params Sem_spi_Params;
Semaphore_Struct Sem_spi_Struct;
Semaphore_Handle Sem_spi_Handle;


void ioc_SpiEthWriteRead(SpiStructType *pspiData)
{
    uint32_t ui32Index;

    SSIConfigSetExpClk(pspiData->ui32SpiBus, 120000000, SSI_FRF_MOTO_MODE_0,
                       SSI_MODE_MASTER, SPI_PERIPHERAL_CLOCK, SPIETH_DATA_LENGTH);



    /* Checks the SPI Rx FIFO is empty */
    while(SSIDataGetNonBlocking(pspiData->ui32SpiBus,pspiData->pui8DataRx+0))
    {

    }


#ifdef SPI_FLAG
    UARTprintf("Transferred Data :\n\r\t\t");
#endif
   for(ui32Index = 0; ui32Index < pspiData->ui32TransferCount; ui32Index++)
   {

#ifdef SPI_FLAG
       UARTprintf("Data %d : 0x%x\n\r\t\t", ui32Index+1,
                               *(pspiData->pui8DataTx+ui32Index));
#endif

       SSIDataPut(pspiData->ui32SpiBus, *(pspiData->pui8DataTx+ui32Index));
   }

   GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, 0x00);
   SSIEnable(pspiData->ui32SpiBus);

   while(SSIBusy(pspiData->ui32SpiBus))
   {

   }
   GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, GPIO_PIN_2);

#ifdef SPI_FLAG
   UARTprintf("Received: \n\r\t\t");
#endif
   for(ui32Index = 0; ui32Index < pspiData->ui32TransferCount; ui32Index++)
   {

       SSIDataGet(pspiData->ui32SpiBus, (pspiData->pui8DataRx+ui32Index));

       *(pspiData->pui8DataRx+ui32Index) &= 0x00FF;

#ifdef SPI_FLAG
       UARTprintf("Data %d : 0x%x\n\r\t\t",ui32Index+1,
               *(pspiData->pui8DataRx+ui32Index));
#endif
   }
}

void iocDefaultConfig(void)
{

   /* MDIO and MDC as Input pins */
   SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
   SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
   GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_2);
   GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_3);
   GPIOPinTypeGPIOInput(GPIO_PORTC_BASE, GPIO_PIN_6);
   GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_6, GPIO_PIN_6);

   /* SPI-2 DATA2 and DATA3 pins as input */
   SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
   GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_6);
   GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_7);

   SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2);
   SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
   GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_2);
   GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, GPIO_PIN_2);
   GPIOPinConfigure(GPIO_PD3_SSI2CLK);
   GPIOPinConfigure(GPIO_PD1_SSI2XDAT0);
   GPIOPinConfigure(GPIO_PD0_SSI2XDAT1);
   GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_3 |
                              GPIO_PIN_1 | GPIO_PIN_0 );
   GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_6, 0X00);
   GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_6, GPIO_PIN_6);

   Semaphore_Params_init(&Sem_spi_Params);
   Semaphore_construct(&Sem_spi_Struct, 1, &Sem_spi_Params);
   Sem_spi_Handle = Semaphore_handle(&Sem_spi_Struct);

    System_printf("\nMII and SPI configured for Ethernet Switch\n");
    System_flush();
}

void iocEthernetSwitchConfig_ksz8765(void)
{
//    UARTprintf("%s() : iocEthernetSwitchConfig : Configuring...\n",__FUNCTION__);

    // This "MII BYPASS" is actually txer5 from the ksz8765,
    // and therefore must be set to an input, since it's not used.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG);
    GPIOPinTypeGPIOInput(GPIO_PORTG_BASE, GPIO_PIN_6);      // U45-55     MII_BYPASS     U46-28_MII_BP

    // PME is an output from the ksz8765, and must be set as input.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
    GPIOPinTypeGPIOInput(GPIO_PORTK_BASE, GPIO_PIN_1);

    // TODO why does OLD eth chip have this set as input here?  this is driving its rst input.
//    GPIOPinTypeGPIOInput(GPIO_PORTK_BASE, GPIO_PIN_1);
    GPIOPinTypeGPIOOutput(GPIO_PORTK_BASE, GPIO_PIN_1);

    /* MDIO and MDC as Input pins */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_2); // PF2 PIN 44 NC
    GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_3); // CAN'T FIND
    GPIOPinTypeGPIOInput(GPIO_PORTC_BASE, GPIO_PIN_6); // rst_n to ksz8765
    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_6, GPIO_PIN_6);

    /* SPI-2 DATA2 and DATA3 pins as input */
    // U45 TM4C1292NCPDTI3 to U21 LAN9252
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_6);       // CONT_ECAT_QSPI_DATA3
    GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_7);       // CONT_ECAT_QSPI_DATA2

    // U45 TM4C1292NCPDTI3 to U46 KSZ8463FMLI
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_2);      // U45-3    CONT_QSPI_CS     CONT_ETHSW_CS_N     U46-42_SPI_CSn
    GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, GPIO_PIN_2);   // Set CS HI
    GPIOPinConfigure(GPIO_PD3_SSI2CLK);                      // U45-4    CLK_QSPI_CONT    CLK_CONT_ETHSW      U46-44_SPI_SCLK
    GPIOPinConfigure(GPIO_PD1_SSI2XDAT0);                    // U45-2    CONT_QSPI_DATA0  CONT_ETHSW_MOSI     U46-45_SPI_DI
    GPIOPinConfigure(GPIO_PD0_SSI2XDAT1);                    // U45-1    CONT_QSPI_DATA1  ETHSW_CONT_MISO     U46-41_SPI_DO
    GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_3 | GPIO_PIN_1 | GPIO_PIN_0 );

//    UARTprintf("%s() : iocEthernetSwitchConfig : Resetting...\n",__FUNCTION__);

    /* Ethernet Switch Reset */
    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_6, 0X00);
    SysCtlDelay(10000);
    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_6, GPIO_PIN_6);

//    UARTprintf("%s() : iocEthernetSwitchConfig : Reset done\n",__FUNCTION__);


    /* Reset Ethernet Switch */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    GPIOPinTypeGPIOOutput(GPIO_PORTC_BASE, GPIO_PIN_6);
    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_6, GPIO_PIN_6);

 //    System_printf("\nMII and SPI configured for Ethernet Switch\n");
 //    System_flush();

}

uint32_t ioc_PhyReadOperation(uint16_t ui16RegAddr)
{
     SpiStructType stspiData;

     Semaphore_pend(Sem_spi_Handle, BIOS_WAIT_FOREVER);
     stspiData.ui32TransferCount = 6;
     stspiData.ui32SpiBus = SSI2_BASE;

     ui16RegAddr = (ui16RegAddr & (~(0x3))) << 4;
     ui16RegAddr = ui16RegAddr | 0x3C;

     ui16TxBufData[0] = (ui16RegAddr >> 8);
     ui16TxBufData[1] = (ui16RegAddr & 0xFF);
     stspiData.pui8DataTx = ui16TxBufData;
     stspiData.pui8DataRx = ui16RxBufData;
     ioc_SpiEthWriteRead(&stspiData);

     Semaphore_post(Sem_spi_Handle);

     return stspiData.pui8DataRx[2];
}

uint16_t ioc_PhyReadOperation_ksz8765(uint16_t ui16RegAddr, bool bMode, bool dbg)
{
     // rd 0 1 1 A11 A10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A0 TR D7 D6 D5 D4 D3 D2 D1 D0
    SpiStructType stspiData;
//    uint16_t ui16RegAddrDummy;
    stspiData.ui32TransferCount = 3;
    stspiData.ui32SpiBus = SSI2_BASE;

//    ui16RegAddrDummy = ui16RegAddr;
    ui16RegAddr  = ui16RegAddr | 0x3000; // Add rd cmd prefix bits
    ui16RegAddr  = ui16RegAddr << 1;     // Add tr suffix bit

    ui16TxBufData[0] = (ui16RegAddr >> 8) & 0xFF;
    ui16TxBufData[1] = ui16RegAddr & 0xFF;
    ui16TxBufData[2] = 0;

    stspiData.pui8DataTx = ui16TxBufData;
    stspiData.pui8DataRx = ui16RxBufData;

    ioc_SpiEthWriteRead(&stspiData);
    //Semaphore_post(Sem_spi_Handle);
    /*if(bMode == TIVA)
        ioc_EthernetTivaSpiTransfer(&stspiData);
    else
        ioc_EthernetRtosSpiTransfer(&stspiData);*/

//    if(bMode == TIVA)
//        if(dbg)UARTprintf("%s() : 0x%x => 0x%x\n",__FUNCTION__,ui16RegAddrDummy,stspiData.pui8DataRx[2]);
//    else
//        if(dbg)ioc_UartPrint("%s() : 0x%x => 0x%x\n",__FUNCTION__,ui16RegAddrDummy,stspiData.pui8DataRx[2]);

    return stspiData.pui8DataRx[2];
}


void ioc_PhyWriteOperation(uint16_t ui16RegAddr, uint16_t ui8Data)
{
    SpiStructType stspiData;
//    uint16_t ui8Byte;
    uint16_t ui16RegDummy;

    Semaphore_pend(Sem_spi_Handle, BIOS_WAIT_FOREVER);
#ifdef EVAL_FLAG
    stspiData.ui32SpiBus = SSI0_BASE;
    stspiData.CSBaseaddr = GPIO_PORTA_BASE;
    stspiData.CSpinNum = GPIO_PIN_3;
    ioc_spi0Config();
#else
    stspiData.ui32TransferCount = 6;
    stspiData.ui32SpiBus = SSI2_BASE;
#endif

    ui16RegDummy = ui16RegAddr;
    ui16RegAddr = (ui16RegAddr & (~(0x3))) << 4;
    ui16RegAddr = ui16RegAddr | 0x3C;

    ui16TxBufData[0] = (ui16RegAddr >> 8);
    ui16TxBufData[1] = (ui16RegAddr & 0xFF);
    stspiData.pui8DataTx = ui16TxBufData;
    stspiData.pui8DataRx = ui16RxBufData;
    ioc_SpiEthWriteRead(&stspiData);

//    ui8Byte = (ui16RegAddr & 0x3) & 0xFF;

    ui16RegAddr = ui16RegAddr | 0x3C;

    if((ui16RegDummy % 4) == 0)
    {
        stspiData.pui8DataRx[2] = ui8Data & 0xFF;
        stspiData.pui8DataRx[3] = (ui8Data >> 8) & 0xFF;
    }
    else
    if((ui16RegDummy % 4) == 2)
    {
        stspiData.pui8DataRx[4] = (ui8Data & 0xFF);
        stspiData.pui8DataRx[5] = (ui8Data >> 8) & 0xFF;
    }

    ui16TxBufData[0] = ((ui16RegAddr >> 8) | (1 << 7)) & 0xFF;
    ui16TxBufData[1] = (ui16RegAddr & 0xFF);
    ui16TxBufData[2] = stspiData.pui8DataRx[2];
    ui16TxBufData[3] = stspiData.pui8DataRx[3];
    ui16TxBufData[4] = stspiData.pui8DataRx[4];
    ui16TxBufData[5] = stspiData.pui8DataRx[5];

    stspiData.pui8DataTx = ui16TxBufData;
    stspiData.pui8DataRx = ui16RxBufData;
    ioc_SpiEthWriteRead(&stspiData);
    Semaphore_post(Sem_spi_Handle);

}

void ioc_PhyWriteOperation_ksz8765(uint16_t ui16RegAddr, uint16_t ui8Data, bool bMode,bool dbg)
{
//    if(dbg)UARTprintf("%s() : 0x%x <= 0x%x\n",__FUNCTION__,ui16RegAddr,ui8Data);
    SpiStructType stspiData;
    // SPI wr frame per datasheet
    // 0 1 0 A11 A10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A0 TR D7 D6 D5 D4 D3 D2 D1 D0
    ui16RegAddr  = ui16RegAddr | 0x2000; // Add wr cmd prefix bits per datasheet
    ui16RegAddr  = ui16RegAddr << 1;     // Add tr suffix bit per datasheet

    // 3-byte SPI frame per datasheet
    stspiData.ui32TransferCount = 3;
    stspiData.ui32SpiBus = SSI2_BASE;
    ui16TxBufData[0] = (ui16RegAddr >> 8) & 0xFF;
    ui16TxBufData[1] = ui16RegAddr & 0xFF;
    ui16TxBufData[2] = ui8Data;

    // Send/recv SPI bytes
    stspiData.pui8DataTx = ui16TxBufData;
    stspiData.pui8DataRx = ui16RxBufData;

    ioc_SpiEthWriteRead(&stspiData);
    //Semaphore_post(Sem_spi_Handle);

    /*if(bMode == TIVA)
        ioc_EthernetTivaSpiTransfer(&stspiData);
    else
        ioc_EthernetRtosSpiTransfer(&stspiData);*/
}




void ioc_EthernetPortConfig(void)
{
    /* Reset Ethernet Switch */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    GPIOPinTypeGPIOOutput(GPIO_PORTC_BASE, GPIO_PIN_6);
    GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_6, GPIO_PIN_6);
    SysCtlDelay(1000000);

    /* MII_BYPASS Disable */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG);
    GPIOPinTypeGPIOOutput(GPIO_PORTG_BASE, GPIO_PIN_6);
    GPIOPinWrite(GPIO_PORTG_BASE, GPIO_PIN_6, 0x00);

    /* Configuration Status Serial bus */
    ioc_PhyWriteOperation(CONFIGSTATUS_SERIALBUS, CONFIGSTATUS_DATA);

    /* DSP control Register one */
    ioc_PhyWriteOperation(DSPCONTROLREG_ONE, DSPCONTROLREG_DATA);

    /* PORT one control register one */
    ioc_PhyWriteOperation(PORTONE_CONTROLREGONE, PORTONE_CONTROLDATA);

    /* PORT two control register one*/
    ioc_PhyWriteOperation(PORTTWO_CONTROLREGONE, PORTTWO_CONTROLDATA);

    /* Global switch control register */
    ioc_PhyWriteOperation(SWITCHGLOBALCONTROLREGSEVEN, SWITCHGLOBALCONTROLDATA);

    /* Enable interrupt register*/
    ioc_PhyWriteOperation(INT_ENABLEREG, INT_ENABLEDATA);

    System_printf("Ethernet Switch is Configured\n");
    System_flush();
}

void ioc_EthernetPortConfig_ksz8765(bool bMode,bool dbg)
{

//    if(bMode == TIVA)
//        UARTprintf("%s() : Starting...\n",__FUNCTION__);
//    else
//        ioc_UartPrint("%s() : Starting...\n",__FUNCTION__);

    // Global registers


    // LED Mode
    // OLD (ks8463)
    //  IOCNAME  bits [9:8] in SGCR7      00          01          10          11
    //  LINKx    P1LED1/P2LED1            Speed       ACT         Duplex      Duplex
    //  100Mx    P1LED0/P2LED0            Link/ACT    Link        Link/ACT    Link
    // NEW (ksz8765)
    //  IOCNAME  bits[5:4]                00          01          10          11
    //  LINKx    LEDx_1                   Speed       ACT         Duplex      Duplex
    //  100Mx    LEDx_0                   Link/ACT    Link        Link/Act    Link
    ioc_PhyWriteOperation_ksz8765(0x0B,0x10,bMode,dbg);

    // Force 100-full, since autonegotiation is not supported in 100Base-FX (Fiber)
    // 0b11111111 = 0xFF
    ioc_PhyWriteOperation_ksz8765(0x1C,0xFF,bMode,dbg);
    //ioc_PhyWriteOperation_ksz8765(0x2C,0xFF,bMode,dbg);

//    // Disable Auto MDX
//    // 0b00000110 = 0x06
//    ioc_PhyWriteOperation_ksz8765(0x1D,0x06,bMode,dbg);
//    ioc_PhyWriteOperation_ksz8765(0x2D,0x06,bMode,dbg);

    // Port registers
    // Register 86 (0x56): Port 5 Interface Control 6
    ioc_PhyWriteOperation_ksz8765(0x56,0xA8,bMode,dbg);
    System_printf("Ethernet Switch is Configured\n");
       System_flush();
//    ioc_ksz8765_rdall(0,1);
}
