URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [ecos-2.0/] [packages/] [devs/] [flash/] [atmel/] [at29cxxxx/] [v2_0/] [include/] [flash_at29cxxxx.inl] - Rev 1765
Compare with Previous | Blame | View Log
#ifndef CYGONCE_DEVS_FLASH_ATMEL_AT29CXXXX_INL
#define CYGONCE_DEVS_FLASH_ATMEL_AT29CXXXX_INL
//==========================================================================
//
// at29cxxxx.inl
//
// Atmel AT29Cxxxx series flash driver
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas, jskov
// Date: 2001-02-21
// Purpose:
// Description:
//
// Notes: FLASH_P2V is not properly used.
// Needs locking.
//####DESCRIPTIONEND####
//
//==========================================================================
#include <pkgconf/hal.h>
#include <cyg/hal/hal_arch.h>
#include <cyg/hal/hal_cache.h>
#include CYGHWR_MEMORY_LAYOUT_H
#define _FLASH_PRIVATE_
#include <cyg/io/flash.h>
//----------------------------------------------------------------------------
// Common device details.
#define FLASH_Read_ID FLASHWORD( 0x90 )
#define FLASH_Read_ID_Exit FLASHWORD( 0xF0 )
#define FLASH_Reset FLASHWORD( 0xFF )
#define FLASH_Program FLASHWORD( 0xA0 )
#define FLASH_Block_Erase FLASHWORD( 0x30 )
#define FLASH_Data FLASHWORD( 0x80 ) // Data complement
#define FLASH_Busy FLASHWORD( 0x40 ) // "Toggle" bit
#define FLASH_Err FLASHWORD( 0x20 )
#define FLASH_Sector_Erase_Timer FLASHWORD( 0x08 )
#define FLASH_Setup_Addr1 (0x5555)
#define FLASH_Setup_Addr2 (0x2AAA)
#define FLASH_Setup_Code1 FLASHWORD( 0xAA )
#define FLASH_Setup_Code2 FLASHWORD( 0x55 )
#define FLASH_Setup_Erase FLASHWORD( 0x80 )
// Platform code must define the below
// #define CYGNUM_FLASH_INTERLEAVE : Number of interleaved devices (in parallel)
// #define CYGNUM_FLASH_SERIES : Number of devices in series
// #define CYGNUM_FLASH_BASE : Address of first device
// And select one of the below device variants
#ifdef CYGPKG_DEVS_FLASH_ATMEL_AT29C040A
# define FLASH_BLOCK_SIZE (0x10000*CYGNUM_FLASH_INTERLEAVE)
# define FLASH_NUM_REGIONS (8)
# define CYGNUM_FLASH_BASE_MASK (0xFFF80000u) // 512kB devices
# define CYGNUM_FLASH_WIDTH (8)
# define CYGNUM_FLASH_BLANK (1)
# define CYGNUM_FLASH_ID_MANUFACTURER FLASHWORD(0x1F)
# define CYGNUM_FLASH_ID_DEVICE FLASHWORD(0xA4)
#endif
#ifdef CYGPKG_DEVS_FLASH_ATMEL_AT29LV1024
# define FLASH_BLOCK_SIZE (0x100*CYGNUM_FLASH_INTERLEAVE)
# define FLASH_NUM_REGIONS (512)
# define CYGNUM_FLASH_BASE_MASK (0xFFFe0000u) // 128kB devices
# define CYGNUM_FLASH_WIDTH (16)
# define CYGNUM_FLASH_BLANK (1)
# define CYGNUM_FLASH_ID_MANUFACTURER FLASHWORD(0x1F)
# define CYGNUM_FLASH_ID_DEVICE FLASHWORD(0x26)
#endif
#define FLASH_DEVICE_SIZE (FLASH_BLOCK_SIZE*FLASH_NUM_REGIONS)
#define CYGNUM_FLASH_DEVICES (CYGNUM_FLASH_INTERLEAVE*CYGNUM_FLASH_SERIES)
//----------------------------------------------------------------------------
// Now that device properties are defined, include magic for defining
// accessor type and constants.
#include <cyg/io/flash_dev.h>
//----------------------------------------------------------------------------
// Functions that put the flash device into non-read mode must reside
// in RAM.
void flash_query(void* data) __attribute__ ((section (".2ram.flash_query")));
int flash_erase_block(void* block, unsigned int size)
__attribute__ ((section (".2ram.flash_erase_block")));
int flash_program_buf(void* addr, void* data, int len)
__attribute__ ((section (".2ram.flash_program_buf")));
//----------------------------------------------------------------------------
// Initialize driver details
int
flash_hwr_init(void)
{
flash_data_t id[2];
flash_dev_query(id);
// Check that flash_id data is matching the one the driver was
// configured for.
if (id[0] != CYGNUM_FLASH_ID_MANUFACTURER
|| id[1] != CYGNUM_FLASH_ID_DEVICE)
return FLASH_ERR_DRV_WRONG_PART;
// Hard wired for now
flash_info.block_size = FLASH_BLOCK_SIZE;
flash_info.blocks = FLASH_NUM_REGIONS;
flash_info.start = (void *)CYGNUM_FLASH_BASE;
flash_info.end = (void *)(CYGNUM_FLASH_BASE+ (FLASH_NUM_REGIONS * FLASH_BLOCK_SIZE * CYGNUM_FLASH_SERIES));
return FLASH_ERR_OK;
}
//----------------------------------------------------------------------------
// Map a hardware status to a package error
int
flash_hwr_map_error(int e)
{
return e;
}
//----------------------------------------------------------------------------
// See if a range of FLASH addresses overlaps currently running code
bool
flash_code_overlaps(void *start, void *end)
{
extern unsigned char _stext[], _etext[];
return ((((unsigned long)&_stext >= (unsigned long)start) &&
((unsigned long)&_stext < (unsigned long)end)) ||
(((unsigned long)&_etext >= (unsigned long)start) &&
((unsigned long)&_etext < (unsigned long)end)));
}
//----------------------------------------------------------------------------
// Flash Query
//
// Only reads the manufacturer and part number codes for the first
// device(s) in series. It is assumed that any devices in series
// will be of the same type.
void
flash_query(void* data)
{
volatile flash_data_t *ROM;
flash_data_t* id = (flash_data_t*) data;
int i;
ROM = (volatile flash_data_t*) CYGNUM_FLASH_BASE;
ROM[FLASH_Setup_Addr1] = FLASH_Setup_Code1;
ROM[FLASH_Setup_Addr2] = FLASH_Setup_Code2;
ROM[FLASH_Setup_Addr1] = FLASH_Read_ID;
// FIXME: 10ms delay
for (i = 10000; i > 0; i--);
// Manufacturers' code
id[0] = ROM[0];
// Part number
id[1] = ROM[1];
ROM[FLASH_Setup_Addr1] = FLASH_Setup_Code1;
ROM[FLASH_Setup_Addr2] = FLASH_Setup_Code2;
ROM[FLASH_Setup_Addr1] = FLASH_Read_ID_Exit;
// FIXME: 10ms delay
for (i = 10000; i > 0; i--);
}
//----------------------------------------------------------------------------
// Erase Block
int
flash_erase_block(void* block, unsigned int len)
{
volatile flash_data_t* ROM;
volatile flash_data_t* addr_ptr = (volatile flash_data_t*) block;
volatile flash_data_t* addr_ptr2;
int res = FLASH_ERR_OK;
while ((FLASH_ERR_OK == res) && (len > 0)) {
int len2, i, timeout;
flash_data_t state, prev_state;
// Base address of device(s) being programmed.
ROM = (volatile flash_data_t*)((unsigned long)block & ~(FLASH_DEVICE_SIZE-1));
// Program data [byte] - 4 step sequence
ROM[FLASH_Setup_Addr1] = FLASH_Setup_Code1;
ROM[FLASH_Setup_Addr2] = FLASH_Setup_Code2;
ROM[FLASH_Setup_Addr1] = FLASH_Program;
addr_ptr2 = addr_ptr;
len2 = len;
// Always load 256 bytes
for (i = 0; i < 256;) {
*addr_ptr2++ = FLASH_BlankValue;
i += sizeof(*addr_ptr2);
}
// Wait for completion (bit 6 stops toggling)
timeout = 5000000;
prev_state = *addr_ptr & FLASH_Busy;
while (true) {
state = *addr_ptr & FLASH_Busy;
if (prev_state == state) {
break;
}
if (--timeout == 0) {
res = FLASH_ERR_DRV_TIMEOUT;
break;
}
prev_state = state;
}
// Verify loaded data bytes
for (i = 0; (len > 0) && (i < 256) ;) {
if (*addr_ptr != FLASH_BlankValue) {
// Only update return value if erase operation was OK
if (FLASH_ERR_OK == res) res = FLASH_ERR_DRV_VERIFY;
break;
}
addr_ptr++;
len -= sizeof(*addr_ptr);
i += sizeof(*addr_ptr);
}
}
return FLASH_ERR_OK;
}
//----------------------------------------------------------------------------
// Program Buffer
int
flash_program_buf(void* addr, void* data, int len)
{
volatile flash_data_t* ROM;
volatile flash_data_t* addr_ptr = (volatile flash_data_t*) addr;
volatile flash_data_t* data_ptr = (volatile flash_data_t*) data;
volatile flash_data_t* addr_ptr2;
volatile flash_data_t* data_ptr2;
int res = FLASH_ERR_OK;
#if 0
CYG_ASSERT((unsigned long)data_ptr & (sizeof(flash_data_t)-1) == 0,
"Data not properly aligned");
CYG_ASSERT((unsigned long)addr_ptr & (CYGNUM_FLASH_INTERLEAVE*sizeof(flash_data_t)-1) == 0,
"Addr not properly aligned (to first interleaved device)");
#endif
while ((FLASH_ERR_OK == res) && (len > 0)) {
int len2, i, timeout;
flash_data_t state, prev_state;
// Base address of device(s) being programmed.
ROM = (volatile flash_data_t*)((unsigned long)addr & ~(FLASH_DEVICE_SIZE-1));
// Program data [byte] - 4 step sequence
ROM[FLASH_Setup_Addr1] = FLASH_Setup_Code1;
ROM[FLASH_Setup_Addr2] = FLASH_Setup_Code2;
ROM[FLASH_Setup_Addr1] = FLASH_Program;
addr_ptr2 = addr_ptr;
data_ptr2 = data_ptr;
len2 = len;
// Always load 256 bytes
for (i = 0; i < 256;) {
if (len2 > 0) {
*addr_ptr2++ = *data_ptr2++;
len2 -= sizeof(*data_ptr2);
} else {
*addr_ptr2++ = FLASH_BlankValue;
}
i += sizeof(*data_ptr2);
}
// Wait for completion (bit 6 stops toggling)
timeout = 5000000;
prev_state = *addr_ptr & FLASH_Busy;
while (true) {
state = *addr_ptr & FLASH_Busy;
if (prev_state == state) {
break;
}
if (--timeout == 0) {
res = FLASH_ERR_DRV_TIMEOUT;
break;
}
prev_state = state;
}
// Verify loaded data bytes
for (i = 0; (len > 0) && (i < 256) ;) {
if (*addr_ptr != *data_ptr) {
// Only update return value if erase operation was OK
if (FLASH_ERR_OK == res) res = FLASH_ERR_DRV_VERIFY;
break;
}
addr_ptr++;
data_ptr++;
len -= sizeof(*data_ptr);
i += sizeof(*data_ptr);
}
}
// Ideally, we'd want to return not only the failure code, but also
// the address/device that reported the error.
return res;
}
#endif // CYGONCE_DEVS_FLASH_ATMEL_AT29CXXXX_INL