forked from Imagelibrary/rtems
194 lines
5.0 KiB
C
194 lines
5.0 KiB
C
/* flash.c
|
|
*
|
|
* Milkymist flash driver for RTEMS
|
|
*
|
|
* The license and distribution terms for this file may be
|
|
* found in the file LICENSE in this distribution or at
|
|
* http://www.rtems.org/license/LICENSE.
|
|
*
|
|
* COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq
|
|
*/
|
|
|
|
#define RTEMS_STATUS_CHECKS_USE_PRINTK
|
|
|
|
#include <rtems.h>
|
|
#include <stdio.h>
|
|
#include <bsp.h>
|
|
#include <string.h>
|
|
#include <rtems/libio.h>
|
|
#include <rtems/status-checks.h>
|
|
#include "../include/system_conf.h"
|
|
#include <bsp/milkymist_flash.h>
|
|
|
|
static struct flash_partition partitions[FLASH_PARTITION_COUNT]
|
|
= FLASH_PARTITIONS;
|
|
|
|
static rtems_id flash_lock;
|
|
|
|
rtems_device_driver flash_initialize(
|
|
rtems_device_major_number major,
|
|
rtems_device_minor_number minor,
|
|
void *arg
|
|
)
|
|
{
|
|
rtems_status_code sc;
|
|
int i;
|
|
char devname[16];
|
|
|
|
for (i=0;i<FLASH_PARTITION_COUNT;i++) {
|
|
sprintf(devname, "/dev/flash%d", i+1);
|
|
sc = rtems_io_register_name(devname, major, i);
|
|
RTEMS_CHECK_SC(sc, "Create flash device");
|
|
}
|
|
|
|
sc = rtems_semaphore_create(
|
|
rtems_build_name('F', 'L', 'S', 'H'),
|
|
1,
|
|
RTEMS_SIMPLE_BINARY_SEMAPHORE,
|
|
0,
|
|
&flash_lock
|
|
);
|
|
RTEMS_CHECK_SC(sc, "create semaphore");
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
rtems_device_driver flash_read(
|
|
rtems_device_major_number major,
|
|
rtems_device_minor_number minor,
|
|
void *arg
|
|
)
|
|
{
|
|
rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
|
|
void *startaddr;
|
|
int len;
|
|
|
|
if (minor >= FLASH_PARTITION_COUNT)
|
|
return RTEMS_UNSATISFIED;
|
|
|
|
startaddr = (void *)(partitions[minor].start_address
|
|
+ (unsigned int)rw_args->offset);
|
|
len = partitions[minor].length - rw_args->offset;
|
|
if (len > rw_args->count)
|
|
len = rw_args->count;
|
|
if (len <= 0) {
|
|
rw_args->bytes_moved = 0;
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
rtems_semaphore_obtain(flash_lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
|
memcpy(rw_args->buffer, startaddr, len);
|
|
rtems_semaphore_release(flash_lock);
|
|
|
|
rw_args->bytes_moved = len;
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
rtems_device_driver flash_write(
|
|
rtems_device_major_number major,
|
|
rtems_device_minor_number minor,
|
|
void *arg
|
|
)
|
|
{
|
|
rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
|
|
volatile unsigned short *startaddr;
|
|
unsigned short *srcdata;
|
|
int len;
|
|
int this_time;
|
|
int remaining;
|
|
int i;
|
|
|
|
if (minor >= FLASH_PARTITION_COUNT)
|
|
return RTEMS_UNSATISFIED;
|
|
|
|
startaddr = (unsigned short *)(partitions[minor].start_address
|
|
+ (unsigned int)rw_args->offset);
|
|
len = partitions[minor].length - rw_args->offset;
|
|
if (len > rw_args->count)
|
|
len = rw_args->count;
|
|
if (len <= 2) {
|
|
rw_args->bytes_moved = 0;
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
len /= 2;
|
|
srcdata = (unsigned short *)rw_args->buffer;
|
|
remaining = len;
|
|
|
|
rtems_semaphore_obtain(flash_lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
|
while (remaining > 0) {
|
|
this_time = remaining;
|
|
if (this_time > 256)
|
|
this_time = 256;
|
|
/* Issue "Buffered Programming Setup" command
|
|
* and wait for buffer available.
|
|
*/
|
|
do {
|
|
*startaddr = 0x00e8;
|
|
} while (!(*startaddr & 0x0080));
|
|
/* Load word count */
|
|
*startaddr = this_time-1;
|
|
/* Fill buffer */
|
|
for(i=0;i<this_time;i++)
|
|
startaddr[i] = srcdata[i];
|
|
/* Issue "Buffer Programming Confirm" command */
|
|
*startaddr = 0x00d0;
|
|
while (!(*startaddr & 0x0080)); /* read status register, wait for ready */
|
|
*startaddr = 0x0050; /* clear status register */
|
|
/* update state */
|
|
startaddr += this_time;
|
|
srcdata += this_time;
|
|
remaining -= this_time;
|
|
}
|
|
*startaddr = 0x00ff; /* back to read array mode */
|
|
rtems_semaphore_release(flash_lock);
|
|
|
|
rw_args->bytes_moved = 2*len;
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|
|
|
|
rtems_device_driver flash_control(
|
|
rtems_device_major_number major,
|
|
rtems_device_minor_number minor,
|
|
void *arg
|
|
)
|
|
{
|
|
rtems_libio_ioctl_args_t *args = arg;
|
|
unsigned int eraseaddr_i;
|
|
volatile unsigned short *eraseaddr;
|
|
|
|
if (minor >= FLASH_PARTITION_COUNT) {
|
|
args->ioctl_return = -1;
|
|
return RTEMS_UNSATISFIED;
|
|
}
|
|
|
|
switch (args->command) {
|
|
case FLASH_GET_SIZE:
|
|
*((unsigned int *)args->buffer) = partitions[minor].length;
|
|
break;
|
|
case FLASH_GET_BLOCKSIZE:
|
|
*((unsigned int *)args->buffer) = 128*1024;
|
|
break;
|
|
case FLASH_ERASE_BLOCK:
|
|
eraseaddr_i = (unsigned int)args->buffer;
|
|
if (eraseaddr_i >= partitions[minor].length) {
|
|
args->ioctl_return = -1;
|
|
return RTEMS_UNSATISFIED;
|
|
}
|
|
eraseaddr_i = eraseaddr_i + partitions[minor].start_address;
|
|
eraseaddr = (unsigned short *)eraseaddr_i;
|
|
rtems_semaphore_obtain(flash_lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
|
*eraseaddr = 0x0020; /* erase */
|
|
*eraseaddr = 0x00d0;
|
|
while(!(*eraseaddr & 0x0080)); /* read status register, wait for ready */
|
|
*eraseaddr = 0x0050; /* clear status register */
|
|
*eraseaddr = 0x00ff; /* back to read array mode */
|
|
rtems_semaphore_release(flash_lock);
|
|
break;
|
|
default:
|
|
args->ioctl_return = -1;
|
|
return RTEMS_UNSATISFIED;
|
|
}
|
|
args->ioctl_return = 0;
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|