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:
Chris Johns
2007-12-14 04:54:57 +00:00
parent 2199d748f5
commit f3bf21f2cf
6 changed files with 551 additions and 0 deletions
+7
View File
@@ -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.
+9
View File
@@ -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 \
+472
View File
@@ -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
};
+57
View File
@@ -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
+5
View File
@@ -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
+1
View File
@@ -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