/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2018 NXP
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "fsl_flexspi.h"
#include "app.h"
#include "fsl_debug_console.h"
#include "fsl_cache.h"

#include "pin_mux.h"
#include "board.h"
#include "clock_config.h"
#include "fsl_common.h"
/*******************************************************************************
* Definitions
******************************************************************************/

#define FIRMWARE_ADDRESS_START    			0x20000
#define FIRMWARE_LENGTH									0x10000
#define NEW_FIRMWARE_ADDRESS_START			0x10000
#define SECTOR_SIZE											4096
#define PAGE_SIZE												256
/*******************************************************************************
* Prototypes
******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/
static uint8_t s_nor_program_buffer[256];
static uint8_t s_nor_read_buffer[256];

extern AT_QUICKACCESS_SECTION_CODE(void AHBPrefetchDisable(FLEXSPI_Type *base));
extern AT_QUICKACCESS_SECTION_CODE(void AHBPrefetchEnable(FLEXSPI_Type *base));
extern AT_QUICKACCESS_SECTION_CODE(void FLEXSPI_SoftwareReset_RAM(FLEXSPI_Type *base));
extern AT_QUICKACCESS_SECTION_CODE(status_t flexspi_nor_flash_page_program_byte(FLEXSPI_Type *base, uint32_t dstAddr, uint8_t *src,uint32_t size));
extern AT_QUICKACCESS_SECTION_CODE(status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address));
extern AT_QUICKACCESS_SECTION_CODE(status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, uint32_t *src,uint32_t size));
extern status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId);
extern status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base);
extern status_t flexspi_nor_erase_chip(FLEXSPI_Type *base);
extern void flexspi_nor_flash_init(FLEXSPI_Type *base);
extern AT_QUICKACCESS_SECTION_CODE(void FLEXSPI_UpdateLUT_RAM(FLEXSPI_Type *base, uint32_t index, const uint32_t *cmd, uint32_t count));
/*******************************************************************************
 * Code
 ******************************************************************************/
flexspi_device_config_t deviceconfig = {
    .flexspiRootClk = 120000000,
    .flashSize = FLASH_SIZE,
    .CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle,
    .CSInterval = 2,
    .CSHoldTime = 3,
    .CSSetupTime = 3,
    .dataValidTime = 0,
    .columnspace = 0,
    .enableWordAddress = 0,
    .AWRSeqIndex = 0,
    .AWRSeqNumber = 0,
    .ARDSeqIndex = NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD,
    .ARDSeqNumber = 1,
    .AHBWriteWaitUnit = kFLEXSPI_AhbWriteWaitUnit2AhbCycle,
    .AHBWriteWaitInterval = 0,
};

uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
        /* Normal read mode -SDR */

        [4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x03, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
        [4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 1] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

        /* Fast read mode - SDR */
        [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x0B, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
        [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST + 1] = FLEXSPI_LUT_SEQ(
            kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x08, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),

        /* Fast read quad mode - SDR */
        [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xEB, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x18),
        [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 1] = FLEXSPI_LUT_SEQ(
            kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x06, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04),

        /* Read extend parameters */
        [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x81, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),

        /* Write Enable */
        [4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

        /* Erase Sector  */
        [4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x20, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),

        /* Page Program - single mode */
        [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x02, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
        [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE + 1] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

        /* Page Program - quad mode */
        [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x32, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),
        [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD + 1] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

        /* Read ID */
        [4 * NOR_CMD_LUT_SEQ_IDX_READID] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xAB, kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x18),
        [4 * NOR_CMD_LUT_SEQ_IDX_READID + 1] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

        /* Enable Quad mode */
        [4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x01, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),

        /* Enter QPI mode */
        [4 * NOR_CMD_LUT_SEQ_IDX_ENTERQPI] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

        /* Exit QPI mode */
        [4 * NOR_CMD_LUT_SEQ_IDX_EXITQPI] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xF5, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

        /* Read status register */
        [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x05, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),

        /* Erase whole chip */
        [4 * NOR_CMD_LUT_SEQ_IDX_ERASECHIP] =
            FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xC7, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
};
#if (defined(__CC_ARM))
__asm void JumpToApps(void)
{
		LDR     R0, =0x60012000
		LDR     R2, [R0]
		MSR     MSP, R2
		LDR     R1, =0x60012004
		LDR     R0, [R1]
		BLX     R0
}
#endif
int main(void)
{
    uint32_t i = 0;
    status_t status;
    uint8_t vendorID = 0;

    BOARD_ConfigMPU();
    BOARD_InitPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();

	  PRINTF("FlexSPI Program test start-mdk(boot Loader)\r\n");

          AHBPrefetchDisable(EXAMPLE_FLEXSPI);
	  FLEXSPI_UpdateLUT_RAM(EXAMPLE_FLEXSPI, 0, customLUT, CUSTOM_LUT_LENGTH);  
	  	
	  uint32_t FirmwareAddress_start = EXAMPLE_FLEXSPI_AMBA_BASE + FIRMWARE_ADDRESS_START;
	  for(uint32_t i=0;i<(FIRMWARE_LENGTH+SECTOR_SIZE-1)/SECTOR_SIZE;i++)
		{
				flexspi_nor_flash_erase_sector(EXAMPLE_FLEXSPI,NEW_FIRMWARE_ADDRESS_START+i*SECTOR_SIZE);
			  for(uint32_t j=0;j<16;j++)
				{
					  memcpy((void *)s_nor_read_buffer,(void *)FirmwareAddress_start,256);
						flexspi_nor_flash_page_program(EXAMPLE_FLEXSPI,NEW_FIRMWARE_ADDRESS_START+i*SECTOR_SIZE+j*PAGE_SIZE,
					               (uint8_t *)s_nor_read_buffer,256);
					  //DCACHE_CleanInvalidateByRange(EXAMPLE_FLEXSPI_AMBA_BASE+NEW_FIRMWARE_ADDRESS_START+i*SECTOR_SIZE+j*PAGE_SIZE,PAGE_SIZE);
					  FirmwareAddress_start+= 256;
				}
		}
	 // DCACHE_CleanInvalidateByRange(EXAMPLE_FLEXSPI_AMBA_BASE + FIRMWARE_ADDRESS_START, FLASH_PAGE_SIZE);
    AHBPrefetchEnable(EXAMPLE_FLEXSPI);
			
		PRINTF("now copy the firmware to new address:0x%x\r\n",EXAMPLE_FLEXSPI_AMBA_BASE + FIRMWARE_ADDRESS_START);
			
	  PRINTF("Was going to jump to new firmware now!\r\n");
		
		#if (defined(__CC_ARM))
	  JumpToApps();
		#endif
		while(1);
	 
}
