Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:44

0001 /*  flash.c
0002  *
0003  *  Milkymist flash driver for RTEMS
0004  *
0005  *  The license and distribution terms for this file may be
0006  *  found in the file LICENSE in this distribution or at
0007  *  http://www.rtems.org/license/LICENSE.
0008  *
0009  *  COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq
0010  */
0011 
0012 #define RTEMS_STATUS_CHECKS_USE_PRINTK
0013 
0014 #include <rtems.h>
0015 #include <stdio.h>
0016 #include <bsp.h>
0017 #include <string.h>
0018 #include <rtems/libio.h>
0019 #include <rtems/status-checks.h>
0020 #include "../include/system_conf.h"
0021 #include <bsp/milkymist_flash.h>
0022 
0023 static struct flash_partition partitions[FLASH_PARTITION_COUNT]
0024   = FLASH_PARTITIONS;
0025 
0026 static rtems_id flash_lock;
0027 
0028 rtems_device_driver flash_initialize(
0029   rtems_device_major_number major,
0030   rtems_device_minor_number minor,
0031   void *arg
0032 )
0033 {
0034   rtems_status_code sc;
0035   int i;
0036   char devname[16];
0037 
0038   for (i=0;i<FLASH_PARTITION_COUNT;i++) {
0039     sprintf(devname, "/dev/flash%d", i+1);
0040     sc = rtems_io_register_name(devname, major, i);
0041     RTEMS_CHECK_SC(sc, "Create flash device");
0042   }
0043 
0044   sc = rtems_semaphore_create(
0045     rtems_build_name('F', 'L', 'S', 'H'),
0046     1,
0047     RTEMS_SIMPLE_BINARY_SEMAPHORE,
0048     0,
0049     &flash_lock
0050   );
0051   RTEMS_CHECK_SC(sc, "create semaphore");
0052 
0053   return RTEMS_SUCCESSFUL;
0054 }
0055 
0056 rtems_device_driver flash_read(
0057   rtems_device_major_number major,
0058   rtems_device_minor_number minor,
0059   void *arg
0060 )
0061 {
0062   rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
0063   void *startaddr;
0064   int len;
0065 
0066   if (minor >= FLASH_PARTITION_COUNT)
0067     return RTEMS_UNSATISFIED;
0068 
0069   startaddr = (void *)(partitions[minor].start_address
0070     + (unsigned int)rw_args->offset);
0071   len = partitions[minor].length - rw_args->offset;
0072   if (len > rw_args->count)
0073     len = rw_args->count;
0074   if (len <= 0) {
0075     rw_args->bytes_moved = 0;
0076     return RTEMS_SUCCESSFUL;
0077   }
0078   
0079   rtems_semaphore_obtain(flash_lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0080   memcpy(rw_args->buffer, startaddr, len);
0081   rtems_semaphore_release(flash_lock);
0082 
0083   rw_args->bytes_moved = len;
0084   return RTEMS_SUCCESSFUL;
0085 }
0086 
0087 rtems_device_driver flash_write(
0088   rtems_device_major_number major,
0089   rtems_device_minor_number minor,
0090   void *arg
0091 )
0092 {
0093   rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
0094   volatile unsigned short *startaddr;
0095   unsigned short *srcdata;
0096   int len;
0097   int this_time;
0098   int remaining;
0099   int i;
0100 
0101   if (minor >= FLASH_PARTITION_COUNT)
0102     return RTEMS_UNSATISFIED;
0103 
0104   startaddr = (unsigned short *)(partitions[minor].start_address
0105     + (unsigned int)rw_args->offset);
0106   len = partitions[minor].length - rw_args->offset;
0107   if (len > rw_args->count)
0108     len = rw_args->count;
0109   if (len <= 2) {
0110     rw_args->bytes_moved = 0;
0111     return RTEMS_SUCCESSFUL;
0112   }
0113   len /= 2;
0114   srcdata = (unsigned short *)rw_args->buffer;
0115   remaining = len;
0116 
0117   rtems_semaphore_obtain(flash_lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0118   while (remaining > 0) {
0119     this_time = remaining;
0120     if (this_time > 256)
0121       this_time = 256;
0122     /* Issue "Buffered Programming Setup" command
0123      * and wait for buffer available.
0124      */
0125     do {
0126       *startaddr = 0x00e8;
0127     } while (!(*startaddr & 0x0080));
0128     /* Load word count */
0129     *startaddr = this_time-1;
0130     /* Fill buffer */
0131     for(i=0;i<this_time;i++)
0132       startaddr[i] = srcdata[i];
0133     /* Issue "Buffer Programming Confirm" command */
0134     *startaddr = 0x00d0;
0135     while (!(*startaddr & 0x0080)); /* read status register, wait for ready */
0136     *startaddr = 0x0050; /* clear status register */
0137     /* update state */
0138     startaddr += this_time;
0139     srcdata += this_time;
0140     remaining -= this_time;
0141   }
0142   *startaddr = 0x00ff; /* back to read array mode */
0143   rtems_semaphore_release(flash_lock);
0144 
0145   rw_args->bytes_moved = 2*len;
0146   return RTEMS_SUCCESSFUL;
0147 }
0148 
0149 rtems_device_driver flash_control(
0150   rtems_device_major_number major,
0151   rtems_device_minor_number minor,
0152   void *arg
0153 )
0154 {
0155   rtems_libio_ioctl_args_t *args = arg;
0156   unsigned int eraseaddr_i;
0157   volatile unsigned short *eraseaddr;
0158 
0159   if (minor >= FLASH_PARTITION_COUNT) {
0160     args->ioctl_return = -1;
0161     return RTEMS_UNSATISFIED;
0162   }
0163 
0164   switch (args->command) {
0165     case FLASH_GET_SIZE:
0166       *((unsigned int *)args->buffer) = partitions[minor].length;
0167       break;
0168     case FLASH_GET_BLOCKSIZE:
0169       *((unsigned int *)args->buffer) = 128*1024;
0170       break;
0171     case FLASH_ERASE_BLOCK:
0172       eraseaddr_i = (unsigned int)args->buffer;
0173       if (eraseaddr_i >= partitions[minor].length) {
0174         args->ioctl_return = -1;
0175         return RTEMS_UNSATISFIED;
0176       }
0177       eraseaddr_i = eraseaddr_i + partitions[minor].start_address;
0178       eraseaddr = (unsigned short *)eraseaddr_i;
0179       rtems_semaphore_obtain(flash_lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0180       *eraseaddr = 0x0020; /* erase */
0181       *eraseaddr = 0x00d0;
0182       while(!(*eraseaddr & 0x0080)); /* read status register, wait for ready */
0183       *eraseaddr = 0x0050; /* clear status register */
0184       *eraseaddr = 0x00ff; /* back to read array mode */
0185       rtems_semaphore_release(flash_lock);
0186       break;
0187     default:
0188       args->ioctl_return = -1;
0189       return RTEMS_UNSATISFIED;
0190   }
0191   args->ioctl_return = 0;
0192   return RTEMS_SUCCESSFUL;
0193 }