/*
 * Copyright (c) 2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/**
 * \file : nandflash.c
 *
 * \brief: Routines to initialize & Access the NAND flash
 *
 * \b \Descr: This file contains the routines for configuring and
 *            accessing the NAND Flash on the DM8127 EVM.
 */

/*
 *====================
 * Includes
 *====================
 */
#include "dm8127Board.h"
#include "dm8127_platform.h"
#include "dm8127_gpmc.h"
#include "dm8127_types.h"
#include "stdio.h"
#include "nandflash.h"
#include "gpio.h"
 
/*
 *====================
 * Defines
 *====================
 */

//#define NO_LONGER_VALID
/*! Manufacture ID for the Nand Flash  */
 #define NAND_MANF_ID	(0x2C)
/*! Buffer size for the device info  */
 #define READ_ID_BUFFER_SIZE (4u)

/*
 *====================
 * Function Definitions
 *====================
 */

/***
 * \brief: Routine to initialize the NAND Flash
 *
 * \b \Descr: This routine initialize the NAND flash by configuring GPMC.Reads
 * \n         the Manufacturer Id, Device Id and verifies the manufacture Id.
 *
 * \return: SUCCESS  on successful initialize.
 * \n       FAILED   Failed to initialized.
 * 
 */
#ifndef NAND_WRITE_ERASE_ENABLE


void GPIO_1_init(void)
{

	set_gpio_bank1 (BIT_SEL_GPIO, 1);
	delay(190000);
	set_gpio_bank1 (BIT_SEL_GPIO, 0);
	delay(190000);
	set_gpio_bank1 (BIT_SEL_GPIO, 1);
	delay(90000); /* settle down */

}

#endif
/***
 * \brief: NAND Flash initialization function.
 *
 * \b \descr: it initialize the NAND Flash chip to communicae with
 * \n         the user test.
 *
 * \param: VOID
 * \return: SUCCESS for successful initialize
 *          FAILED  Failed to initialize
 */

STATUS nand_init
(
	void
)
{

	STATUS u32RetVal;      /* function return val*/
    UINT16 mfgid, devid;   /* Device Info variable */

#ifdef NO_LONGER_VALID
	UINT16 u16Buff[READ_ID_BUFFER_SIZE] = { }; /* buffer for the manufacture ID read */
#endif

	/* variable initializaion */
	u32RetVal = FAILED;
	mfgid     = MANUFACTURE_INIT_VAL;
	devid     = MANUFACTURE_INIT_VAL;
#if 0
	NAND_config();
#endif
    /*-----  NAND Flash timing parameters  ------*
     *                                           *
     *  GPMC.CLK freq   =                      	 *
     *  GPMC.CLK period =                        *
     *-------------------------------------------*/
     
    /* Configure GPMC */
    GPMC_SYSCONFIG       = 0x0;
    GPMC_IRQENABLE       = 0x0;
    GPMC_TIMEOUT_CONTROL = 0x0;
    GPMC_CONFIG          = 0x10;

    /* Device size select here */
    GPMC_CONFIG1_0 = 0x00001800;
    /*
     *Chip-select signal timing parameter configuration.
     *CS# de-assertion time from start cycle time for write (8-12)/Read(16-20)
     *14 GPMC FCLK clock cycle */
    GPMC_CONFIG2_0 = 0x00141400;
    /* ADV# signal timing parameter configuration. */
    GPMC_CONFIG3_0 = 0x00141400;
    /* WE# and OE# signals timing parameter configuration.. */
    GPMC_CONFIG4_0 = 0x0F010F01;
    /* RdAccessTime and CycleTime timing parameters configuration. */
    GPMC_CONFIG5_0 = 0x010C1414;
    /* WrAccessTime, WrDataOnADmuxBus, Cycle2Cycle, and BusTurnAround params
     * configuration */
    GPMC_CONFIG6_0 = 0x1f0f0A80;
    /* Chip-select address mapping configuration. */
    GPMC_CONFIG7_0 = 0x00000C44;

    NANDFLASH_CLE = CMD_RESET;
    /* wait for reset command done */
    delay(100000);

    NANDFLASH_CLE = CMD_READID;
    NANDFLASH_ALE = 0x00;

    /* Wait until command completion or check the status register if it is available */
    delay(100);	//TO DO

    /* collect the Device Information of the NAND flash */
    mfgid = NANDFLASH_DATA;
    devid = NANDFLASH_DATA;
    
    if(mfgid == NAND_MANF_ID)
    {
#ifdef DEBUG
    	printf("\r\n NAND Flash initialize successfully ");
		printf(" MFGID = %02x\n \r DEVID = %02x\n", mfgid,devid);

#else
		Uart_stringSend("\r\nNAND Flash initialize successfully ");
		platform_write(" MFGID = %02x\n \rDEVID = %02x\n", mfgid,devid);
#endif
    	u32RetVal = SUCCESS;
    }
    else
    {
#ifdef DEBUG
    	printf (" Unsupported Manf ID.\r\n failed to initialized");
#else
    	Uart_stringSend (" Unsupported Manf ID.\r\n failed to initialized");
#endif
    }

#ifdef NO_LONGER_VALID
    /* Start erase operation */
    NANDFLASH_CLE = CMD_READID;
    NANDFLASH_ALE = 0x20;

    /* Gathering device info */
	u16Buff[0] = NANDFLASH_DATA;
	u16Buff[1] = NANDFLASH_DATA;
	u16Buff[2] = NANDFLASH_DATA;
	u16Buff[3] = NANDFLASH_DATA;

    /* Wait until command completion */
    delay(10);	//TO DO

	printf("u16Buff[0] = 0x%x\t,u16Buff[1] = 0x%x\tu16Buff[2] = 0x%x\tu16Buff[3] = 0x%x\t\r\n", \
			                                     u16Buff[0],u16Buff[1],u16Buff[2],u16Buff[3]);
#endif
    
    return (u32RetVal);
}
/***
 * \brief: Routine to Erase the Nand Flash
 *
 * \b \Descr: This routine Erases a block of Nand Flash .This function takes Block
 * \n         num as input parameter.Reads erase status and checks for successfull
 * \n         erase operation.
 *
 * \param:   blocknum 		[IN]		Block to be erased
 *
 * \return:  SUCCESS for success
 * \n        FAILED for error
 * 
 */
STATUS nand_eraseBlock
(
	UINT32 blocknum
)
{
	STATUS u32RetVal = SUCCESS;
    UINT32 status;
    status = 0;
    // Start erase operation
    NANDFLASH_CLE = CMD_ERASE; // cycle#1
    NANDFLASH_ALE = (blocknum & 0x0003) << 6;
    NANDFLASH_ALE = (blocknum & 0x03fc) >> 2;
    NANDFLASH_ALE = (blocknum & 0x0c00) >> 10;
    NANDFLASH_CLE = CMD_ERASE_CONFIRM; // cycle#2

    /*  Wait for erase completion */
    NANDFLASH_CLE = CMD_STATUS;

    delay(25);	//TO DO

    while ((NANDFLASH_DATA & 0x20) == 0); /* Waiting for 6th bit as high */

    /* Check erase status */
    NANDFLASH_CLE = CMD_STATUS;

    delay(50);
   status = NANDFLASH_DATA;

    NANDFLASH_CLE = CMD_RESET;
   // status = NANDFLASH_DATA;
    if (status & 0x01)
    {
#ifdef DEBUG
    	printf ("blocknum %d Failed to Erase.\r\n",blocknum);
#else
    	platform_write ("blocknum %d Failed to Erase.\r\n",blocknum);
#endif
    	u32RetVal = FAILED;
    }

    
	return u32RetVal;  // OK
}
/***
 * \brief: Routine to read from  Nand Flash
 *
 * \b \Descr: This routine Reads a page from Nand Flash .This function takes Page
 * \n         number as input parameter along with read buffer pointer and length
 * \n         of buffer.
 * 
 *
 * \param:  pagenum 	  [IN]		Pagenumber to read from
 * \n       *buffer       [IN]      Buffer pointer to copy read data
 * \n       len           [IN]      Length of the buffer
 *
 * 
 * \return: SUCCESS for success
 * \n       FAILED for error
 */

STATUS nand_readPage
(
	UINT32 pagenum,
	UINT16 *buf,
	UINT16 len
)
{
	STATUS u32RetVal = SUCCESS;
    UINT16 *dptr;
    UINT16 i;

    NANDFLASH_CLE = CMD_READ;
    NANDFLASH_ALE = 0x00;
    NANDFLASH_ALE = 0x00;
    NANDFLASH_ALE = pagenum & 0xff;
    NANDFLASH_ALE = (pagenum & 0x00ff00) >> 8;
    NANDFLASH_ALE = (pagenum & 0x030000) >> 16;
    NANDFLASH_CLE = CMD_READ_CONFIRM;

    /* Wait for read completion */
    NANDFLASH_CLE = CMD_STATUS;
    while ((NANDFLASH_DATA & 0x20) == 0);

    /* Read data */
    NANDFLASH_CLE = CMD_READ;
    delay(600);
    dptr = buf;
    for (i = 0; i < len/2; i++)
        *dptr++ = NANDFLASH_DATA;

    return u32RetVal;
}
/***
 * \brief: Routine to Write into  Nand Flash
 *
 * \b \Descr: This routine Writes a page to  Nand Flash. This function takes Page
 * \n         number as input parameter along with  buffer pointer and length of
 * \n         buffer.
 * 
 *
 * \param:   pagenum 	    [IN]       Page to be written
 * \n        *buffer        [IN]       Buffer pointer which contains data to be written
 * \n        len            [IN]       Length of the buffer
 *
 * 
 * \return:   SUCCESS for success
 * \n         FAILED for error
 */
STATUS nand_writePage
(
	UINT32 pagenum,
	UINT16 *buf,
	UINT16 len
)
{
	STATUS u32RetVal = SUCCESS;
    UINT16 *dptr;
    UINT16 i;
    UINT32 status;


      ///////////////////////////////////////////////////////////////
      /// The wite protect pin must and should be high to write into
      /// the pages. for write operaton GP1[10] pin shold be high.
      /// This pin should be LOW when not writing and Erasing the
      /// Pages.
      /////////////////////////////////////////////////////////////

    /* The command, data and the address is inserted 8bit per cycle.*/

    /*  Start program operation */
    NANDFLASH_CLE = CMD_PROGRAM; /// command cycle #1

    /* Address cycle, The total address cycle to write into
     * the flash is 5 */
    NANDFLASH_ALE = 0x00; /// cycle #1
    NANDFLASH_ALE = 0x00; /// cycle #2
    NANDFLASH_ALE = pagenum & 0xff; /// cycle #3
    NANDFLASH_ALE = (pagenum & 0x00ff00) >> 8; /// cycle #4
    NANDFLASH_ALE = (pagenum & 0x030000) >> 16; /// cycle #5

    /* address latching tome delay */
    delay(10);

    /* data to be written */
    dptr = buf;
    for (i = 0; i < len/2; i++)
        NANDFLASH_DATA = *dptr ++;

    NANDFLASH_CLE = CMD_PROGRAM_CONFIRM; /// command cycle #2

    delay(25);	//TO DO

    // Wait for program completion
    NANDFLASH_CLE = CMD_STATUS;
    while ((NANDFLASH_DATA & 0x20) == 0);

    /// Check program status
    NANDFLASH_CLE = CMD_STATUS;
    status = NANDFLASH_DATA;

    if (status & 0x01)
    {
    	u32RetVal = FAILED;
    }
    
    return u32RetVal;  // OK
}
