mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-09-21 09:05:06 +08:00
2007-12-14 Chris Johns <chrisj@rtems.org>
* wrapup/Makefile.am: Add libflash.a to the libbsp library. * libchip/Makefile.am, libchip/preinstall.am: Add the flash chip support. * libchip/flash, libchip/flash/am29lv160.c, libchip/flash/am29lv160.h: New.
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
2007-12-14 Chris Johns <chrisj@rtems.org>
|
||||
|
||||
* wrapup/Makefile.am: Add libflash.a to the libbsp library.
|
||||
* libchip/Makefile.am, libchip/preinstall.am: Add the flash chip support.
|
||||
* libchip/flash, libchip/flash/am29lv160.c,
|
||||
libchip/flash/am29lv160.h: New.
|
||||
|
||||
2007-11-26 Joel Sherrill <joel.sherrill@oarcorp.com>
|
||||
|
||||
* libchip/network/if_fxp.c: Spacing.
|
||||
|
||||
@@ -13,6 +13,15 @@ EXTRA_DIST =
|
||||
noinst_LIBRARIES =
|
||||
noinst_PROGRAMS =
|
||||
|
||||
# flash
|
||||
if LIBCHIP
|
||||
include_libchip_HEADERS += flash/am29lv160.h
|
||||
|
||||
noinst_LIBRARIES += libflash.a
|
||||
libflash_a_SOURCES = flash/am29lv160.c
|
||||
libflash_a_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
endif
|
||||
|
||||
# ide
|
||||
if LIBCHIP
|
||||
include_libchip_HEADERS += ide/ata.h ide/ide_ctrl_cfg.h ide/ide_ctrl.h \
|
||||
|
||||
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* RTEMS Project (http://www.rtems.org/)
|
||||
*
|
||||
* Copyright 2007 Chris Johns (chrisj@rtems.org)
|
||||
*/
|
||||
/**
|
||||
* Provide flash support for the AM26LV160 device.
|
||||
*
|
||||
* The M29W160D is the same device.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
#include <libchip/am29lv160.h>
|
||||
|
||||
#define AM26LV160_ERROR_TRACE (0)
|
||||
|
||||
/**
|
||||
* Boot blocks at the top
|
||||
*/
|
||||
const rtems_fdisk_segment_desc rtems_am29lv160t_segments[4] =
|
||||
{
|
||||
{
|
||||
count: 31,
|
||||
segment: 0,
|
||||
offset: 0x00000000,
|
||||
size: RTEMS_FDISK_KBYTES (64)
|
||||
},
|
||||
{
|
||||
count: 1,
|
||||
segment: 31,
|
||||
offset: 0x001f0000,
|
||||
size: RTEMS_FDISK_KBYTES (32)
|
||||
},
|
||||
{
|
||||
count: 2,
|
||||
segment: 32,
|
||||
offset: 0x001f8000,
|
||||
size: RTEMS_FDISK_KBYTES (8)
|
||||
},
|
||||
{
|
||||
count: 1,
|
||||
segment: 34,
|
||||
offset: 0x001fc000,
|
||||
size: RTEMS_FDISK_KBYTES (16)
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Boot blocks at the bottom.
|
||||
*/
|
||||
const rtems_fdisk_segment_desc rtems_am29lv160b_segments[] =
|
||||
{
|
||||
{
|
||||
count: 1,
|
||||
segment: 0,
|
||||
offset: 0x00000000,
|
||||
size: RTEMS_FDISK_KBYTES (16)
|
||||
},
|
||||
{
|
||||
count: 2,
|
||||
segment: 1,
|
||||
offset: 0x00004000,
|
||||
size: RTEMS_FDISK_KBYTES (8)
|
||||
},
|
||||
{
|
||||
count: 1,
|
||||
segment: 3,
|
||||
offset: 0x00008000,
|
||||
size: RTEMS_FDISK_KBYTES (32)
|
||||
},
|
||||
{
|
||||
count: 31,
|
||||
segment: 4,
|
||||
offset: 0x00010000,
|
||||
size: RTEMS_FDISK_KBYTES (64)
|
||||
}
|
||||
};
|
||||
|
||||
static int
|
||||
rtems_am29lv160_blank (const rtems_fdisk_segment_desc* sd,
|
||||
uint32_t device,
|
||||
uint32_t segment,
|
||||
uint32_t offset,
|
||||
uint32_t size)
|
||||
{
|
||||
const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
|
||||
volatile uint8_t* seg_8 = ac->base;
|
||||
volatile uint32_t* seg_32;
|
||||
uint32_t count;
|
||||
|
||||
offset += sd->offset + (segment - sd->segment) * sd->size;
|
||||
|
||||
seg_8 += offset;
|
||||
|
||||
count = offset & (sizeof (uint32_t) - 1);
|
||||
size -= count;
|
||||
|
||||
while (count--)
|
||||
if (*seg_8++ != 0xff)
|
||||
{
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
printf ("AM26LV160: blank check: %p = 0x%02x\n",
|
||||
seg_8 - 1, *(seg_8 - 1));
|
||||
#endif
|
||||
return EIO;
|
||||
}
|
||||
|
||||
seg_32 = (volatile uint32_t*) seg_8;
|
||||
|
||||
count = size / sizeof (uint32_t);
|
||||
size -= count * sizeof (uint32_t);
|
||||
|
||||
while (count--)
|
||||
if (*seg_32++ != 0xffffffff)
|
||||
{
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
printf ("AM26LV160: blank check: %p = 0x%08lx\n",
|
||||
seg_32 - 1, *(seg_32 - 1));
|
||||
#endif
|
||||
return EIO;
|
||||
}
|
||||
|
||||
seg_8 = (volatile uint8_t*) seg_32;
|
||||
|
||||
while (size--)
|
||||
if (*seg_8++ != 0xff)
|
||||
{
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
printf ("AM26LV160: blank check: %p = 0x%02x\n",
|
||||
seg_8 - 1, *(seg_8 - 1));
|
||||
#endif
|
||||
return EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_verify (const rtems_fdisk_segment_desc* sd,
|
||||
uint32_t device,
|
||||
uint32_t segment,
|
||||
uint32_t offset,
|
||||
const void* buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
|
||||
const uint8_t* addr = ac->base;
|
||||
|
||||
addr += (sd->offset + (segment - sd->segment) * sd->size) + offset;
|
||||
|
||||
if (memcmp (addr, buffer, size) != 0)
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_toggle_wait_8 (volatile uint8_t* status)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
volatile uint8_t status1 = *status;
|
||||
volatile uint8_t status2 = *status;
|
||||
|
||||
if (((status1 ^ status2) & (1 << 6)) == 0)
|
||||
return 0;
|
||||
|
||||
if ((status1 & (1 << 5)) != 0)
|
||||
{
|
||||
status1 = *status;
|
||||
status2 = *status;
|
||||
|
||||
if (((status1 ^ status2) & (1 << 6)) == 0)
|
||||
return 0;
|
||||
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
printf ("AM26LV160: error bit detected: %p = 0x%04x\n",
|
||||
status, status1);
|
||||
#endif
|
||||
|
||||
*status = 0xf0;
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_toggle_wait_16 (volatile uint16_t* status)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
volatile uint16_t status1 = *status;
|
||||
volatile uint16_t status2 = *status;
|
||||
|
||||
if (((status1 ^ status2) & (1 << 6)) == 0)
|
||||
return 0;
|
||||
|
||||
if ((status1 & (1 << 5)) != 0)
|
||||
{
|
||||
status1 = *status;
|
||||
status2 = *status;
|
||||
|
||||
if (((status1 ^ status2) & (1 << 6)) == 0)
|
||||
return 0;
|
||||
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
printf ("AM26LV160: error bit detected: %p = 0x%04x/0x%04x\n",
|
||||
status, status1, status2);
|
||||
#endif
|
||||
|
||||
*status = 0xf0;
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_write_data_8 (volatile uint8_t* base,
|
||||
uint32_t offset,
|
||||
const uint8_t* data,
|
||||
uint32_t size)
|
||||
{
|
||||
volatile uint8_t* seg = base + offset;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
*base = 0xf0;
|
||||
|
||||
while (size)
|
||||
{
|
||||
rtems_interrupt_disable (level);
|
||||
*(base + 0xaaa) = 0xaa;
|
||||
*(base + 0x555) = 0x55;
|
||||
*(base + 0xaaa) = 0xa0;
|
||||
*seg = *data++;
|
||||
rtems_interrupt_enable (level);
|
||||
if (rtems_am29lv160_toggle_wait_8 (seg++) != 0)
|
||||
return EIO;
|
||||
size--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
*base = 0xf0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_write_data_16 (volatile uint16_t* base,
|
||||
uint32_t offset,
|
||||
const uint16_t* data,
|
||||
uint32_t size)
|
||||
{
|
||||
volatile uint16_t* seg = base + (offset / 2);
|
||||
rtems_interrupt_level level;
|
||||
|
||||
size /= 2;
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
*base = 0xf0;
|
||||
|
||||
while (size)
|
||||
{
|
||||
rtems_interrupt_disable (level);
|
||||
*(base + 0x555) = 0xaa;
|
||||
*(base + 0x2aa) = 0x55;
|
||||
*(base + 0x555) = 0xa0;
|
||||
*seg = *data++;
|
||||
rtems_interrupt_enable (level);
|
||||
if (rtems_am29lv160_toggle_wait_16 (seg++) != 0)
|
||||
return EIO;
|
||||
size--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
*base = 0xf0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_read (const rtems_fdisk_segment_desc* sd,
|
||||
uint32_t device,
|
||||
uint32_t segment,
|
||||
uint32_t offset,
|
||||
void* buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
unsigned char* addr =
|
||||
rtems_am29lv160_configuration[device].base +
|
||||
sd->offset + ((segment - sd->segment) * sd->size) + offset;
|
||||
memcpy (buffer, addr, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @todo Fix the odd alignment and odd sizes.
|
||||
*/
|
||||
static int
|
||||
rtems_am29lv160_write (const rtems_fdisk_segment_desc* sd,
|
||||
uint32_t device,
|
||||
uint32_t segment,
|
||||
uint32_t offset,
|
||||
const void* buffer,
|
||||
uint32_t size)
|
||||
{
|
||||
int ret = rtems_am29lv160_verify (sd, device, segment, offset, buffer, size);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
|
||||
uint32_t soffset;
|
||||
|
||||
soffset = offset + sd->offset + ((segment - sd->segment) * sd->size);
|
||||
|
||||
if (offset & 1)
|
||||
printf ("rtems_am29lv160_write: offset is odd\n");
|
||||
|
||||
if (size & 1)
|
||||
printf ("rtems_am29lv160_write: size is odd\n");
|
||||
|
||||
if (ac->bus_8bit)
|
||||
ret = rtems_am29lv160_write_data_8 (ac->base, soffset, buffer, size);
|
||||
else
|
||||
ret = rtems_am29lv160_write_data_16 (ac->base, soffset, buffer, size);
|
||||
|
||||
/*
|
||||
* Verify the write worked.
|
||||
*/
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = rtems_am29lv160_verify (sd, device, segment, offset, buffer, size);
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
if (ret)
|
||||
printf ("AM26LV160: verify failed: %ld-%ld-%08lx: s=%ld\n",
|
||||
device, segment, offset, size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_erase (const rtems_fdisk_segment_desc* sd,
|
||||
uint32_t device,
|
||||
uint32_t segment)
|
||||
{
|
||||
int ret = rtems_am29lv160_blank (sd, device, segment, 0, sd->size);
|
||||
if (ret != 0)
|
||||
{
|
||||
const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
|
||||
uint32_t offset;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
offset = sd->offset + ((segment - sd->segment) * sd->size);
|
||||
|
||||
if (ac->bus_8bit)
|
||||
{
|
||||
volatile uint8_t* base = ac->base;
|
||||
volatile uint8_t* seg = base + offset;
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
rtems_interrupt_disable (level);
|
||||
*base = 0xf0;
|
||||
*(base + 0xaaa) = 0xaa;
|
||||
*(base + 0x555) = 0x55;
|
||||
*(base + 0xaaa) = 0x80;
|
||||
*(base + 0xaaa) = 0xaa;
|
||||
*(base + 0x555) = 0x55;
|
||||
*seg = 0x30;
|
||||
rtems_interrupt_enable (level);
|
||||
|
||||
ret = rtems_am29lv160_toggle_wait_8 (seg);
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
*base = 0xf0;
|
||||
}
|
||||
else
|
||||
{
|
||||
volatile uint16_t* base = ac->base;
|
||||
volatile uint16_t* seg = base + (offset / 2);
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
rtems_interrupt_disable (level);
|
||||
*base = 0xf0;
|
||||
*(base + 0x555) = 0xaa;
|
||||
*(base + 0x2aa) = 0x55;
|
||||
*(base + 0x555) = 0x80;
|
||||
*(base + 0x555) = 0xaa;
|
||||
*(base + 0x2aa) = 0x55;
|
||||
*seg = 0x30;
|
||||
rtems_interrupt_enable (level);
|
||||
|
||||
ret = rtems_am29lv160_toggle_wait_16 (seg);
|
||||
|
||||
/*
|
||||
* Issue a reset.
|
||||
*/
|
||||
*base = 0xf0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the erase worked.
|
||||
*/
|
||||
if (ret == 0)
|
||||
{
|
||||
ret = rtems_am29lv160_blank (sd, device, segment, 0, sd->size);
|
||||
#if AM26LV160_ERROR_TRACE
|
||||
if (ret)
|
||||
printf ("AM26LV160: erase failed: %ld-%ld\n", device, segment);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_am29lv160_erase_device (const rtems_fdisk_device_desc* dd,
|
||||
uint32_t device)
|
||||
{
|
||||
uint32_t segment;
|
||||
|
||||
for (segment = 0; segment < dd->segment_count; segment++)
|
||||
{
|
||||
uint32_t seg_segment;
|
||||
|
||||
for (seg_segment = 0;
|
||||
seg_segment < dd->segments[segment].count;
|
||||
seg_segment++)
|
||||
{
|
||||
int ret = rtems_am29lv160_erase (&dd->segments[segment],
|
||||
device,
|
||||
segment + seg_segment);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const rtems_fdisk_driver_handlers rtems_am29lv160_handlers =
|
||||
{
|
||||
read: rtems_am29lv160_read,
|
||||
write: rtems_am29lv160_write,
|
||||
blank: rtems_am29lv160_blank,
|
||||
verify: rtems_am29lv160_verify,
|
||||
erase: rtems_am29lv160_erase,
|
||||
erase_device: rtems_am29lv160_erase_device
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* RTEMS Project (http://www.rtems.org/)
|
||||
*
|
||||
* Copyright 2007 Chris Johns (chrisj@rtems.org)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Flash Disk Device Driver.
|
||||
*
|
||||
* Am29LV160D 16 Megabit (2M x 8bit) 3.0 Volt-only
|
||||
* Boot Sctor Flash Memory.
|
||||
*/
|
||||
|
||||
#if !defined (_RTEMS_AM29LV160_H_)
|
||||
#define _RTEMS_AM29LV160_H_
|
||||
|
||||
#include <rtems/flashdisk.h>
|
||||
|
||||
/**
|
||||
* The segments in the AM29LV160 top boot block device.
|
||||
*/
|
||||
#define rtems_am29lv160t_segment_count (4)
|
||||
extern const rtems_fdisk_segment_desc rtems_am29lv160t_segments[4];
|
||||
|
||||
/**
|
||||
* The segments in the AM29LV160 bottom boot block device.
|
||||
*/
|
||||
#define rtems_am29lv160b_segment_count (4)
|
||||
extern const rtems_fdisk_segment_desc rtems_am29lv160b_segments[4];
|
||||
|
||||
/**
|
||||
* The segments in the AM29LV160 top boot block device.
|
||||
*/
|
||||
extern const rtems_fdisk_driver_handlers rtems_am29lv160_handlers;
|
||||
|
||||
/**
|
||||
* The device configuration.
|
||||
*/
|
||||
typedef struct rtems_am29lv160_config
|
||||
{
|
||||
int bus_8bit;
|
||||
void* base;
|
||||
} rtems_am29lv160_config;
|
||||
|
||||
/**
|
||||
* External reference to the configuration.
|
||||
*/
|
||||
extern const rtems_am29lv160_config rtems_am29lv160_configuration[];
|
||||
|
||||
/**
|
||||
* External reference to the configuration size
|
||||
*/
|
||||
extern uint32_t rtems_am29lv160_configuration_size;
|
||||
|
||||
#endif
|
||||
@@ -35,6 +35,11 @@ $(PROJECT_INCLUDE)/libchip/$(dirstamp):
|
||||
PREINSTALL_DIRS += $(PROJECT_INCLUDE)/libchip/$(dirstamp)
|
||||
endif
|
||||
if LIBCHIP
|
||||
$(PROJECT_INCLUDE)/libchip/am29lv160.h: flash/am29lv160.h $(PROJECT_INCLUDE)/libchip/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libchip/am29lv160.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/libchip/am29lv160.h
|
||||
endif
|
||||
if LIBCHIP
|
||||
$(PROJECT_INCLUDE)/libchip/ata.h: ide/ata.h $(PROJECT_INCLUDE)/libchip/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libchip/ata.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/libchip/ata.h
|
||||
|
||||
@@ -20,6 +20,7 @@ endif
|
||||
# SRCS += $(wildcard $(PROJECT_LIB)/libcpu.a)
|
||||
|
||||
if LIBCHIP
|
||||
SRCS += ../libchip/libflash.a
|
||||
SRCS += ../libchip/librtcio.a
|
||||
SRCS += ../libchip/libserialio.a
|
||||
SRCS += ../libchip/libide.a
|
||||
|
||||
Reference in New Issue
Block a user