blob: a90d65faebc074a6520773cedad9c5141674d302 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation
*
* 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 disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL 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
*
* Implementation of norflash driver for AMD type.
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "memories.h"
#include <string.h>
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
/** Command for vendor command set CMD_SET_AMD. */
#define AMD_CMD_IDOUT 0x00F0
#define AMD_CMD_CFI 0x0098
#define AMD_CMD_IDIN 0x0090
#define AMD_CMD_UNLOCK_1 0x00AA
#define AMD_CMD_UNLOCK_2 0x0055
#define AMD_CMD_ERASE_SETUP 0x0080
#define AMD_CMD_ERASE_RESUME 0x0030
#define AMD_CMD_ERASE_CHIP 0x0010
#define AMD_CMD_ERASE_SECTOR 0x0030
#define AMD_CMD_PROGRAM 0x00A0
#define AMD_CMD_UNLOCK_BYPASS 0x0020
#define AMD_CMD_SECTOR_UNLOCK 0x0070
/** Command offset for vendor command set CMD_SET_AMD */
#define AMD_OFFSET_UNLOCK_1 0x05555
#define AMD_OFFSET_UNLOCK_2 0x0AAAA
/** Query command address. */
#define FLASH_ADDRESS_CFI 0x0055
/** AMD norflash device Identifier infomation address offset. */
#define AMD_MANU_ID 0x00
#define AMD_DEVIDE_ID 0x01
/** Data polling mask for vendor command set CMD_SET_AMD */
#define AMD_POLLING_DQ7 0x80
#define AMD_POLLING_DQ6 0x60
#define AMD_POLLING_DQ5 0x20
#define AMD_POLLING_DQ3 0x08
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
/**
* \brief It implements a RESET command.
*
* \param pNorFlashInfo Pointer to an NorFlashInfo instance.
* \param address Dummy data for AMD.
*/
static void amd_Reset( NorFlashInfo *pNorFlashInfo, uint32_t address )
{
uint8_t busWidth ;
/* remove warnings */
address = address;
busWidth = NorFlash_GetDataBusWidth( pNorFlashInfo ) ;
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_UNLOCK_1 ) ;
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2), AMD_CMD_UNLOCK_2 ) ;
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_IDOUT ) ;
}
/**
* \brief Read specified manufactory id or device id.
*
* \param pNorFlashInfo Pointer to an NorFlashInfo instance.
* \param index_ 0: manufactorid 1: device id.
*/
static uint32_t amd_ReadIdentification( NorFlashInfo *pNorFlashInfo, uint8_t index_ )
{
uint32_t id;
uint8_t busWidth;
uint32_t address;
busWidth = NorFlash_GetDataBusWidth( pNorFlashInfo ) ;
/* The amd_Read identification command sequence is initiated by first */
/* writing two unlock cycles. */
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_UNLOCK_1 ) ;
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2), AMD_CMD_UNLOCK_2 ) ;
/* Followed by a third write cycle that contains the autoselect command. */
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_IDIN);
/* The device then enters the autoselect mode. It may read at any address any */
/* number of times without initiating another autoselect command sequence. */
address = NorFlash_GetByteAddressInChip(pNorFlashInfo, index_);
ReadRawData( busWidth, address, (uint8_t*)&id ) ;
/* The system must write the exit command to return to the read mode */
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_UNLOCK_1 ) ;
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2), AMD_CMD_UNLOCK_2 ) ;
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_IDOUT ) ;
return id;
}
/**
* \brief It implement a program word command. Returns 0 if the operation was
* successful; otherwise returns an error code.
*
* \param pNorFlashInfo Pointer to an NorFlashInfo instance.
* \param address Start address offset to be wrote.
* \param data word to be written.
*/
static uint8_t amd_Program( NorFlashInfo *pNorFlashInfo, uint32_t address, uint32_t data )
{
uint32_t pollingData;
uint32_t busAddress;
uint8_t done = 0;
uint8_t busWidth;
busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
/* The program command sequence is initiated by writing two unlock write cycles. */
WriteCommand(busWidth,
NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
AMD_CMD_UNLOCK_1);
WriteCommand(busWidth,
NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2),
AMD_CMD_UNLOCK_2);
/* Followed by the program set-up command. */
WriteCommand(busWidth,
NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
AMD_CMD_PROGRAM);
/* The program address and data are written next, */
/* which in turn initiate the Embedded Program algorithm. */
busAddress = NorFlash_GetAddressInChip(pNorFlashInfo, address);
WriteRawData(busWidth, busAddress, (uint8_t*)&data);
/* Data polling */
do
{
ReadRawData(busWidth, busAddress, (uint8_t *)&pollingData);
/* Check if the chip program algorithm is completed. */
if ((pollingData & AMD_POLLING_DQ7) == (data & AMD_POLLING_DQ7))
{
/* Program operation successful. Device in read mode. */
done = 1;
}
else
{
/* check if chip Program algrithm exceeded timing limits */
if (pollingData & AMD_POLLING_DQ5 )
{
/* I/O should be rechecked. */
ReadRawData(busWidth, busAddress, (uint8_t *)&pollingData);
if ((pollingData & AMD_POLLING_DQ7) == (data & AMD_POLLING_DQ7))
{
/* Program operation successful. Device in read mode. */
done = 1;
}
else
{
/* Program operation not successful, write reset command. */
amd_Reset(pNorFlashInfo, 0);
return NorCommon_ERROR_CANNOTWRITE;
}
}
}
} while (!done);
return 0;
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief It implements a RESET command.
*
* \param pNorFlashInfo Pointer to an NorFlashInfo instance.
* \param address Dummy data for AMD.
*/
void AMD_Reset( NorFlashInfo *pNorFlashInfo, uint32_t address )
{
amd_Reset( pNorFlashInfo, address ) ;
}
/**
* \brief The Read Device Identifier command instructs the device to output
* manufacturer code.
*
* \param pNorFlashInfo Pointer to an NorFlashInfo instance.
*/
uint32_t AMD_ReadManufactoryId( NorFlashInfo *pNorFlashInfo )
{
return amd_ReadIdentification(pNorFlashInfo, AMD_MANU_ID);
}
/**
* \brief The Read Device Identifier command instructs the device to output device id.
*
* \param pNorFlashInfo Pointer to an NorFlashInfo instance.
*/
uint32_t AMD_ReadDeviceID( NorFlashInfo *pNorFlashInfo )
{
return amd_ReadIdentification(pNorFlashInfo, AMD_DEVIDE_ID);
}
/**
* \brief Erases the specified block of the device. Returns 0 if the operation was
* successful; otherwise returns an error code.
*
* \param pNorFlashInfo Pointer to an NorFlashInfo instance.
* \param address Address offset to be erase.
*/
uint8_t AMD_EraseSector( NorFlashInfo *pNorFlashInfo, uint32_t address )
{
uint32_t pollingData;
uint32_t busAddress;
uint8_t busWidth;
uint8_t done = 0;
busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
/*Programming is a six-bus-cycle operation. */
/* The erase command sequence is initiated by writing two unlock write cycles. */
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_UNLOCK_1);
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2), AMD_CMD_UNLOCK_2);
/* Followed by the program set-up command. */
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_ERASE_SETUP);
/* Two additional unlock cycles are written. */
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_UNLOCK_1);
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2), AMD_CMD_UNLOCK_2);
/* Followed by the address of the sector to be erased, and the sector erase command. */
busAddress = NorFlash_GetAddressInChip(pNorFlashInfo,address);
WriteCommand(busWidth, busAddress, AMD_CMD_ERASE_SECTOR);
/* Data polling */
do
{
ReadRawData(busWidth, busAddress, (uint8_t *)&pollingData);
/* Check if the chip erase algorithm is completed. */
if ((pollingData & AMD_POLLING_DQ7) == AMD_POLLING_DQ7 )
{
/* Erase operation successful. Device in read mode. */
done = 1;
}
else
{
/* check if sector earse algrithm exceeded timing limits */
if (pollingData & AMD_POLLING_DQ5 )
{
/* I/O should be rechecked. */
ReadRawData(busWidth, busAddress, (uint8_t *)&pollingData);
if ((pollingData & AMD_POLLING_DQ7) == AMD_POLLING_DQ7 )
{
/* Erase operation successful. Device in read mode. */
done = 1;
}
else
{
/* Erase operation not successful, write reset command. */
amd_Reset(pNorFlashInfo, 0);
return NorCommon_ERROR_CANNOTERASE;
}
}
}
} while (!done);
return 0;
}
/**
* \brief Erases all the block of the device. Returns 0 if the operation was successful;
* otherwise returns an error code.
*
* \param pNorFlashInfo Pointer to an NorFlashInfo instance.
*/
uint8_t AMD_EraseChip( NorFlashInfo *pNorFlashInfo )
{
uint32_t pollingData;
uint8_t busWidth;
uint32_t address;
uint8_t done = 0;
busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
/*Programming is a six-bus-cycle operation. */
/* The erase command sequence is initiated by writing two unlock write cycles. */
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_UNLOCK_1 ) ;
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2), AMD_CMD_UNLOCK_2 ) ;
/* Followed by the program set-up command. */
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_ERASE_SETUP);
/* Two additional unlock cycles are written. */
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_UNLOCK_1);
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2), AMD_CMD_UNLOCK_2 ) ;
/* Then followed by the chip erase command. */
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_ERASE_CHIP ) ;
address = NorFlash_GetByteAddressInChip(pNorFlashInfo, 0);
/* Data polling */
do
{
ReadRawData(busWidth , address, (uint8_t*)&pollingData);
/* Check if the chip erase algorithm is completed. */
if ((pollingData & AMD_POLLING_DQ7) == AMD_POLLING_DQ7 )
{
/* Erase operation successful. Device in read mode. */
done = 1;
}
else
{
/* When the time-out period is complete, DQ3 switches from a ¡°0¡± to a ¡°1.¡± */
if (pollingData & AMD_POLLING_DQ3 )
{
return NorCommon_ERROR_CANNOTERASE;
}
/* check if chip earse algrithm exceeded timing limits */
if (pollingData & AMD_POLLING_DQ5 )
{
/* I/O should be rechecked. */
ReadRawData(busWidth , address, (uint8_t*)&pollingData);
if ((pollingData & AMD_POLLING_DQ7) == AMD_POLLING_DQ7 )
{
/* Erase operation successful. Device in read mode. */
done = 1;
}
else
{
/* Erase operation not successful, write reset command. */
amd_Reset(pNorFlashInfo, 0);
return NorCommon_ERROR_CANNOTERASE;
}
}
}
} while (!done);
return 0;
}
/**
* \brief Unlock the specified block of the device.
*
* \param pNorFlashInfo Pointer to an NorFlashInfo instance.
* \param address Address offset to be unlock.
*/
void AMD_UnlockSector( NorFlashInfo *pNorFlashInfo, uint32_t address )
{
uint32_t busAddress;
uint8_t busWidth;
busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
busAddress = NorFlash_GetAddressInChip(pNorFlashInfo,address);
WriteCommand( busWidth, NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1), AMD_CMD_UNLOCK_1);
WriteCommand( busWidth,busAddress, AMD_CMD_SECTOR_UNLOCK);
}
/**
* \brief Sends data to the NorFlashInfo chip from the provided buffer.
*
* \param pNorFlashInfo Pointer to an NorFlashInfo instance.
* \param address Start address offset to be wrote.
* \param buffer Buffer where the data is stored.
* \param size Number of bytes that will be written.
*/
uint8_t AMD_Write_Data( NorFlashInfo *pNorFlashInfo, uint32_t address, uint8_t *buffer, uint32_t size )
{
uint32_t i;
uint8_t busWidth;
busWidth = pNorFlashInfo->deviceChipWidth;
if (busWidth == FLASH_CHIP_WIDTH_8BITS )
{
for(i=0; i < size; i++)
{
if(amd_Program(pNorFlashInfo, address, buffer[i]))
{
return NorCommon_ERROR_CANNOTWRITE;
}
address ++;
}
}
else
{
if( busWidth == FLASH_CHIP_WIDTH_16BITS )
{
uint16_t *buffer16 = (uint16_t *) (void *)buffer;
size = (size + 1) >> 1;
for(i=0; i < size; i++)
{
if(amd_Program(pNorFlashInfo, address, buffer16[i]))
{
return NorCommon_ERROR_CANNOTWRITE;
}
address+= 2;
}
}
else
{
if(busWidth == FLASH_CHIP_WIDTH_32BITS )
{
uint32_t *buffer32 = (uint32_t *)(void *) buffer;
size = (size + 3) >> 2;
for(i=0; i < size; i++)
{
if(amd_Program(pNorFlashInfo, address, buffer32[i]))
{
return NorCommon_ERROR_CANNOTWRITE;
}
address+= 4;
}
}
}
}
return 0;
}
const NorFlashOperations amdOperations =
{
AMD_Reset,
AMD_Write_Data,
AMD_ReadManufactoryId,
AMD_ReadDeviceID,
AMD_EraseChip,
AMD_EraseSector,
AMD_UnlockSector
} ;