/* -------------------------------------------------------------------------- 
 * Copyright (c) 2013-2016 ARM Limited. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *      Name:    main.c
 *      Purpose: RTX for Kneron
 *
 *---------------------------------------------------------------------------*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


#include "cmsis_os2.h"                    // ARM::CMSIS:RTOS2:Keil RTX5
#include "project.h"

#include "kdrv_uart.h"
#include "kdrv_gpio.h"
#include "kdrv_system.h"
#include "rtc.h"
#include "io.h"
#include "kdrv_pwm.h"
#include "kdrv_ddr.h"
#include "kdrv_pinmux.h"
#include "kdrv_ssp.h"
#include "kdrv_pinmux.h"
#include "kdrv_clock.h"

#include "kmdw_console.h"

#define DDR1_DST    0x60000000
#define FLASH_SRC   0x00
#define LENGTH      (1024*1024*5)
#define DDR2_DST    (DDR1_DST+LENGTH)

#undef err_msg
#define err_msg kmdw_printf
#define _get_min(x,y) ( x < y ? x: y )

static uint32_t pinmux_array[PIN_NUM] = PINMUX_ARRAY; 
extern struct st_ssp_spi	driver_ssp_ctx;
#if(SSP_SPI_MASTER_DEV==COM_BUS_TYPE_SSP1 || SSP_SPI_MASTER_DEV==COM_BUS_TYPE_SSP0)
extern struct st_ssp_spi driver_ssp_master_ctx;
#endif
//---
uint8_t kmdw_ssp_api_spi_init(kdrv_ssp_spi_dev_id_t handle, enum e_spi edata)
{
    if( kdrv_ssp_statemachine( handle, &driver_ssp_ctx, edata, NULL ) == e_spi_ret_init_done ){
        return 1;
    }
    return 0;
}

uint8_t kmdw_ssp_api_spi_enable(kdrv_ssp_spi_dev_id_t handle, struct st_ssp_spi *stspi)
{
    if( kdrv_ssp_statemachine( handle, stspi, e_spi_enable, NULL ) == e_spi_ret_enable_done ){
        return 1;
    }
    return 0;
}

uint8_t kmdw_ssp_api_spi_disable(kdrv_ssp_spi_dev_id_t handle, struct st_ssp_spi *stspi)
{
    if( kdrv_ssp_statemachine( handle, stspi, e_spi_disable, NULL ) == e_spi_ret_disableDone ){
        return 1;
    }
    return 0;
}

uint8_t kmdw_ssp_api_spi_receive(kdrv_ssp_spi_dev_id_t handle, struct st_ssp_spi *stspi)
{
    if( kdrv_ssp_statemachine( handle, stspi, e_spi_rx, NULL ) == e_spi_ret_rxbusy ){
        return 0;		//rx on-going
    }
    else{
        return 1;		//rx done
    }
}

uint8_t kmdw_ssp_api_spi_receive_xor(kdrv_ssp_spi_dev_id_t handle)
{
    if( kdrv_ssp_statemachine( handle, &driver_ssp_ctx, e_spi_rx_check, NULL ) == e_spi_ret_rx_xor_OK ){
            return 1;		//rx data correct
    }
    else{
            return 0;		//rx data fail
    }
}

uint8_t kmdw_ssp_api_spi_transfer(kdrv_ssp_spi_dev_id_t handle)
{
    if( kdrv_ssp_statemachine( handle, &driver_ssp_ctx, e_spi_tx, NULL ) == e_spi_ret_txbusy ){
            return 1;		//rx data correct
    }
    else{
            return 0;		//rx data fail
    }
}

uint8_t kmdw_ssp_api_spi_transfer_checks(kdrv_ssp_spi_dev_id_t handle)
{
    if( kdrv_ssp_statemachine( handle, &driver_ssp_ctx, e_spi_tx_status_check, NULL ) == e_spi_ret_txbusy )
    {
            return 0;
    }
    else
    {
            return 1;
    }
}

void kmdw_ssp_api_spi_write_tx_buff( uint8_t *src, uint16_t nlen )
{
    kdrv_ssp_write_buff( &driver_ssp_ctx, src, nlen );
}

uint8_t kmdw_ssp_api_spi_tx_xor(kdrv_ssp_spi_dev_id_t handle)
{
    if( kdrv_ssp_statemachine( handle, &driver_ssp_ctx, e_spi_tx_xor, NULL ) == e_spi_ret_tx_xor_done )
    {
            return 0;
    }
    else
    {
            return 1;
    }
}

/* This is a spi master tx/rx loopback test example 
 * regSSP0_ctrl(driver_ssp_ctx.port_no)->st.bf.kdrv_ssp_sspcr0.LBM to enable loopback mode
*/
uint8_t nsize = 0;
uint8_t ssp_spi_master_test(void)
{
    #define	tx_temp_size (16)
    //uint16_t	ncount = 0;
    uint16_t i = 0;
    uint8_t  temp_buffer[tx_temp_size];
    uint16_t temp_buffer_index = 0;

    for( i=0; i< tx_temp_size; i++ )
    {
        temp_buffer[i] = 0x90+i;
        temp_buffer_index++;
    }

    err_msg(" ssp_spi_master_test : Init\n");
    if( kmdw_ssp_api_spi_init(DEBUG_SPI_PORT, e_spi_init_master) != 1 )
    {
        return 0;
    }
    kdrv_ssp_spi_loopback_test(0); //for loop back test

    err_msg(" ssp_spi_master_test : Start\n");
    while(1)
    {
        //control GPIO
        kdrv_ssp_spi_CS_set(chip_select_pin, SPI_CS_LOW);

		kmdw_ssp_api_spi_write_tx_buff( temp_buffer, temp_buffer_index );
        kmdw_ssp_api_spi_transfer(DEBUG_SPI_PORT);

        //kdrv_delay_us( 30 );
        while(!kmdw_ssp_api_spi_transfer_checks(DEBUG_SPI_PORT));

        //control GPIO
        kdrv_ssp_spi_CS_set(chip_select_pin, SPI_CS_HI);
        
        nsize = kdrv_ssp_rxfifo_valid_entries( driver_ssp_ctx.port_no );
        if(nsize)
        {
            driver_ssp_ctx.Rx_buffer_index=0;
            kdrv_ssp_rx_polling_receive_all(&driver_ssp_ctx);
            uint32_t k = driver_ssp_ctx.Rx_buffer_index;
            if(k == nsize)
            {
                //ssp_write_word(SSP_REG_BASE_S, &driver_ssp_ctx.Rx_buffer ,k);
                kmdw_printf("\nrx data ");
                for(uint32_t i=0; i<nsize; i++)
                {
                    kmdw_printf(" 0x%X",*( driver_ssp_ctx.Rx_buffer+ i ));
                }
                kmdw_printf("\n");
                if ( memcmp((const void *)temp_buffer, (const void *)driver_ssp_ctx.Rx_buffer, tx_temp_size) != 0)
                    kmdw_printf("SPI MASTER LOOPBACK TEST FAIL!\r\n");
                else
                    kmdw_printf("SPI MASTER LOOPBACK TEST PASS.\r\n");
            }
        }

    }
}


/**
 * @brief main, main dispatch function
 */
int main(void) 
{
    uint32_t data;
    SystemCoreClockUpdate();            // System Initialization
    osKernelInitialize();               // Initialize CMSIS-RTOS

    /* below is some primiary system init settings */
    kdrv_system_init(); // primary system init
    /* below is to enable SSP0/1 clock settings */
    kdrv_clock_enable(CLK_SSP1_1_SSPCLK);
    kdrv_clock_enable(CLK_SSP1_0_SSPCLK);
    kdrv_clock_enable(CLK_SSP0_1_SSPCLK);
    kdrv_clock_enable(CLK_SSP0_0_SSPCLK);

    kdrv_system_init_ncpu(); // this is a must for ddr
    kdrv_ddr_system_init(DDR_INIT_ALL); // enable ddr
    kmdw_ddr_init(DDR2_DST,DDR1_DST);

    /* below is some middleware init settings */
    kdrv_uart_initialize(); // for log printing
    kdrv_uart_console_init(MSG_PORT, MSG_PORT_BAUDRATE, NULL);   // enable console mdw for printing
    kdrv_pinmux_initialize(PIN_NUM, pinmux_array);
    if( DEBUG_SPI_PORT == SSP_SPI_PORT0 ) {
        data = ( inw(SCU_EXTREG_PA_BASE + 0x14C) &0xFFFFFFF8) | (1<< 6) | 1<<3;
        outw(SCU_EXTREG_PA_BASE + 0x14C, data | 0x4) ;
        data = ( inw(SCU_EXTREG_PA_BASE + 0x150) &0xFFFFFFF8) | (1<< 6) | 1<<3;
        outw(SCU_EXTREG_PA_BASE + 0x150, data | 0x4);
        data = ( inw(SCU_EXTREG_PA_BASE + 0x154) &0xFFFFFFF8) | (1<< 6) | 1<<3;
        outw(SCU_EXTREG_PA_BASE + 0x154, data | 0x4);
        data = ( inw(SCU_EXTREG_PA_BASE + 0x158) &0xFFFFFFF8) | (1<< 6) | 1<<3;
        outw(SCU_EXTREG_PA_BASE + 0x158, data | 0x4);
    }
    else if ( DEBUG_SPI_PORT == SSP_SPI_PORT1 ) {
        data = (inw(SCU_EXTREG_PA_BASE + 0x15c)&0xFFFFFFF8) | (1<< 6) | 1<<3;
        outw(SCU_EXTREG_PA_BASE + 0x15c, data | 0x2) ;
        //cs pin as GPIO output
        data = ( inw(SCU_EXTREG_PA_BASE + 0x160)&0xFFFFFFF8) | (1<< 6) | 1<<3;
        outw(SCU_EXTREG_PA_BASE + 0x160, data | 0x3); //as gpio
        //kdrv_gpio_set_attribute( GPIO_PIN_20, GPIO_DIR_OUTPUT );
        //kdrv_ssp_spi_CS_set(chip_select_pin, 1);
        data = ( inw(SCU_EXTREG_PA_BASE + 0x164)&0xFFFFFFF8) | (1<< 6) | 1<<3;
        outw(SCU_EXTREG_PA_BASE + 0x164, data | 0x2);
        data = (inw(SCU_EXTREG_PA_BASE + 0x168) &0xFFFFFFF8) | (1<< 6) | 1<<3;
        outw(SCU_EXTREG_PA_BASE + 0x168, data | 0x2);
    }
    
    ssp_spi_master_test();

    while(1);
}


