[ECOS] IO_Flash & DataFlash

Andrew Lunn andrew@lunn.ch
Thu Sep 9 13:17:00 GMT 2004


On Tue, Aug 31, 2004 at 12:06:20PM +0200, Savin Zlobec wrote:
> Hi,
> 
> I'am writing a DataFlash driver and I would like to use it also through 
> the io_flash API,
> but it seems that the io_flash only supports 2^n block sizes (judging by 
> the calculation
> and usage of block_mask). DataFlash memory array is divided into 3 
> levels - sectors,
> blocks and pages of wich none has 2^n size. 
> 
> Supporting this in io_flash is probably just a matter of some ifdefs in 
> read/program/erase
> functions - is this correct ? But does anything else (RedBoot, jffs2, 
> ...) also depend on
> 2^n block sizes ?

Hi Savin

I just committed these patches which means the the flash_v2 code
should not support arbitary size blocks. Please let me know if this
works for the DataFlash, i've only been able to test with a synthetic
flash driver.

Looking at the jffs2 mailling list it looks like jffs2 should be
ok. You will need to test to be sure. I've not looked at RedBoot yet.

        Andrew
-------------- next part --------------
Index: io/flash/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/ChangeLog,v
retrieving revision 1.38.2.6
diff -u -r1.38.2.6 ChangeLog
--- io/flash/current/ChangeLog	21 Aug 2004 13:47:55 -0000	1.38.2.6
+++ io/flash/current/ChangeLog	9 Sep 2004 13:03:56 -0000
@@ -1,3 +1,8 @@
+2004-09-09  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/flash.c: Support flash blocks of arbitary size. The
+	DataFlash devices for example have block of 528 bytes.
+
 2004-08-21  Andrew Lunn  <andrew.lunn@ascom.ch>
 
         * removed the functions cyg_flash_get_limits and
Index: io/flash/current/src/flash.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/io/flash/current/src/flash.c,v
retrieving revision 1.26.2.3
diff -u -r1.26.2.3 flash.c
--- io/flash/current/src/flash.c	21 Aug 2004 13:47:56 -0000	1.26.2.3
+++ io/flash/current/src/flash.c	9 Sep 2004 13:03:57 -0000
@@ -343,6 +343,22 @@
   return flash_block_size(dev, flash_base);
 }
 
+// Return the first address of a block. The flash might not be aligned
+// in terms of its block size. So we have to be careful and use
+// offsets.
+static inline cyg_flashaddr_t 
+flash_block_begin(cyg_flashaddr_t addr, struct cyg_flash_dev *dev)
+{
+  size_t block_size;
+  cyg_flashaddr_t offset;
+  
+  block_size = flash_block_size(dev, addr);
+  
+  offset = addr - dev->start;
+  offset = (offset / block_size) * block_size;
+  return offset + dev->start;
+}
+
 
 __externC int 
 cyg_flash_erase(const cyg_flashaddr_t flash_base, 
@@ -377,8 +393,7 @@
     end_addr = dev->end;
   }
   
-  block_size = flash_block_size(dev, addr);
-  block = (cyg_flashaddr_t)((size_t)addr & ~(block_size - 1));
+  block = flash_block_begin(addr, dev);
   
 #ifdef CYGSEM_IO_FLASH_CHATTER
   dev->pf("... Erase from %p-%p: ", (void*)block, (void*)end_addr);
@@ -391,6 +406,8 @@
     unsigned char *dp;
     bool erased = true;
 
+    block_size = flash_block_size(dev, addr);
+
     // If there is a read function it probably means the flash
     // cannot be read directly.
     if (!dev->funs->flash_read) {
@@ -412,7 +429,7 @@
       *err_address = block;
       break;
     }
-    block += flash_block_size(dev, block);
+    block += block_size;
 #ifdef CYGSEM_IO_FLASH_CHATTER
     dev->pf(".");
 #endif
@@ -488,7 +505,7 @@
     if (size > block_size) size = block_size;
     
     // Writing from the middle of a block?
-    offset = (size_t)addr & (block_size-1);
+    offset = (size_t)addr % block_size;
     if (offset)
       size = MIN(block_size - offset, size);
     stat = dev->funs->flash_program(dev, addr, ram, size);
@@ -576,7 +593,7 @@
     if (size > block_size) size = block_size;
     
     // Reading from the middle of a block?
-    offset = (size_t)addr & (block_size-1);
+    offset = (size_t)addr % block_size;
     if (offset)
       size = MIN(block_size - offset, size);
     if (dev->funs->flash_read) {
@@ -651,8 +668,7 @@
     end_addr = dev->end;
   }
   
-  block_size = flash_block_size(dev, addr);
-  block = (cyg_flashaddr_t)((size_t)addr & ~(block_size - 1));
+  block = flash_block_begin(addr, dev);
   
 #ifdef CYGSEM_IO_FLASH_CHATTER
   dev->pf("... Locking from %p-%p: ", (void*)block, (void*)end_addr);
@@ -685,7 +701,7 @@
     return stat;
   }
   
-  if (flash_base + len - 1 > dev->end) {        // Off by one?
+  if (flash_base + len - 1 > dev->end) {        
     // The region to erase if bigger than this driver handles. Recurse
     return cyg_flash_lock(dev->end+1, 
                           len - (dev->end - flash_base) - 1,
@@ -728,8 +744,7 @@
     end_addr = dev->end;
   }
   
-  block_size = flash_block_size(dev, addr);
-  block = (cyg_flashaddr_t)((size_t)addr & ~(block_size - 1));
+  block =   block = flash_block_begin(addr, dev);
   
 #ifdef CYGSEM_IO_FLASH_CHATTER
   dev->pf("... Unlocking from %p-%p: ", (void*)block, (void*)end_addr);
@@ -762,7 +777,7 @@
     return stat;
   }
   
-  if (flash_base + len - 1 > dev->end) {        // Off by one?
+  if (flash_base + len - 1 > dev->end) {        
     // The region to erase if bigger than this driver handles. Recurse
     return cyg_flash_lock(dev->end+1, 
                           len - (dev->end - flash_base) - 1,
-------------- next part --------------
Index: devs/flash/synthv2/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/flash/synthv2/current/Attic/ChangeLog,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 ChangeLog
--- devs/flash/synthv2/current/ChangeLog	21 Aug 2004 13:45:53 -0000	1.1.2.2
+++ devs/flash/synthv2/current/ChangeLog	9 Sep 2004 13:06:25 -0000
@@ -1,3 +1,8 @@
+2004-09-09  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/flash_synth.c: Allo the use of arbitary sized block.
+	* test/flash3.c: Allow the use of small blocks
+
 2004-08-21  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* tests/flash[23].c: Removed calls to cyg_flash_get_block_info()
Index: devs/flash/synthv2/current/cdl/flash_synth.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/flash/synthv2/current/cdl/Attic/flash_synth.cdl,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 flash_synth.cdl
--- devs/flash/synthv2/current/cdl/flash_synth.cdl	5 Aug 2004 13:25:33 -0000	1.1.2.1
+++ devs/flash/synthv2/current/cdl/flash_synth.cdl	9 Sep 2004 13:06:26 -0000
@@ -80,8 +80,7 @@
 	display        "Size of one block of synth flash"
 	flavor	       data
 	default_value  65536
-        legal_values   4096 to 999999
-        requires       { (CYGNUM_FLASH_SYNTH_V2_BLOCKSIZE % 4096) == 0 }
+        legal_values   512 to 999999
 	description    "
 	        This controls the size of one block of flash. This is 
 		the minimum size that can be erased."
Index: devs/flash/synthv2/current/src/synth.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/flash/synthv2/current/src/Attic/synth.c,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 synth.c
--- devs/flash/synthv2/current/src/synth.c	5 Aug 2004 13:25:34 -0000	1.1.2.1
+++ devs/flash/synthv2/current/src/synth.c	9 Sep 2004 13:06:26 -0000
@@ -60,6 +60,10 @@
 #include <cyg/io/flash.h>
 #include <cyg/flash/synth.h>
 
+#ifndef MIN
+#define MIN(x,y) ((x)<(y) ? (x) : (y))
+#endif
+
 /* Helper function. The Linux system call cannot pass 6 parameters. Instead
    a structure is filled in and passed as one parameter */
 static int 
@@ -208,8 +212,8 @@
 #endif
     struct cyg_flash_synth_priv *priv = dev->priv;
     int offset = (int)block_base;
-    size_t block_size;
-    int i;
+    size_t remaining;
+    int write_size;
 
     offset -= dev->start;
     
@@ -223,17 +227,15 @@
 
     CYG_ASSERT(sizeof(empty) < config->block_size,
                "Eckk! Can't work with such small blocks");
-    CYG_ASSERT((config->block_size % sizeof(empty)) == 0,
-               "Eckk! Can't work with that odd size block");
     CYG_ASSERT(config->boot_blocks && sizeof(empty) < config->boot_block_size,
                "Eckk! Can't work with such small blocks");
-    CYG_ASSERT((config->boot_blocks && config->block_size % sizeof(empty)) == 0,
-               "Eckk! Can't work with that odd size block");
     
-    block_size = flash_block_size(dev, block_base);
+    remaining = flash_block_size(dev, block_base);
 
-    for (i=0; (i * sizeof(empty)) < block_size; i++) {
-        cyg_hal_sys_write(priv->flashfd, empty, sizeof(empty));
+    while (remaining) {
+      write_size = MIN(remaining, sizeof(empty));
+      cyg_hal_sys_write(priv->flashfd, empty, write_size);
+      remaining -= write_size;
     }
     return CYG_FLASH_ERR_OK;
 }
Index: devs/flash/synthv2/current/tests/flash1.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/flash/synthv2/current/tests/Attic/flash1.c,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 flash1.c
--- devs/flash/synthv2/current/tests/flash1.c	5 Aug 2004 13:25:34 -0000	1.1.2.1
+++ devs/flash/synthv2/current/tests/flash1.c	9 Sep 2004 13:06:26 -0000
@@ -94,10 +94,12 @@
   
     CYG_TEST_PASS_FAIL((ret == FLASH_ERR_OK),"flash_init");
 
+#ifdef CYGSEM_IO_FLASH_LEGACY_DEVICE_API
+    //Strictly speaking, this is a device driver call, not a user API call.
     flash_dev_query(data);
     CYG_TEST_PASS_FAIL(!strncmp(data,"Linux Synthetic Flash",sizeof(data)),
                        "flash_query"); 
-
+#endif
     ret = flash_get_limits(NULL,&flash_start,&flash_end);
     CYG_TEST_PASS_FAIL((ret == FLASH_ERR_OK),"flash_get_limits");
 
Index: devs/flash/synthv2/current/tests/flash3.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/flash/synthv2/current/tests/Attic/flash3.c,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 flash3.c
--- devs/flash/synthv2/current/tests/flash3.c	21 Aug 2004 13:45:53 -0000	1.1.2.2
+++ devs/flash/synthv2/current/tests/flash3.c	9 Sep 2004 13:06:26 -0000
@@ -105,7 +105,8 @@
     int block_size=0, blocks=0;
     cyg_flashaddr_t prog_start;
     unsigned char * ptr;
-
+    size_t copyright_len;
+    
     CYG_TEST_INIT();
 
     // Reference the flash dev so the linker does not throw it away
@@ -151,16 +152,25 @@
   
     CYG_TEST_PASS_FAIL((ret == 0),"flash empty check");
 
-    ret = cyg_flash_program(flash_start,&copyright,sizeof(copyright),NULL);
+    // With small blocks we have to use less of the copyright messages
+    // Since we make assumptions about fitting the message into a
+    // block.
+    if (block_size < sizeof(copyright)*2/3) {
+      copyright_len = block_size / 3;
+    } else {
+      copyright_len = sizeof(copyright);
+    }
+    
+    ret = cyg_flash_program(flash_start,&copyright,copyright_len,NULL);
     CYG_TEST_PASS_FAIL((ret == CYG_FLASH_ERR_OK),"flash_program1");
   
     /* Check the contents made it into the flash */
     CYG_TEST_PASS_FAIL(!strncmp((void *)flash_start,
-                                copyright,sizeof(copyright)),
+                                copyright,copyright_len),
                        "flash program contents");
 
     /* .. and check nothing else changed */
-    for (ptr=(unsigned char *)flash_start+sizeof(copyright),ret=0; 
+    for (ptr=(unsigned char *)flash_start+copyright_len,ret=0; 
          ptr < (unsigned char *)flash_end; ptr++) {
         if (*ptr != 0xff) {
             ret++;
@@ -169,24 +179,23 @@
   
     CYG_TEST_PASS_FAIL((ret == 0),"flash program overrun check");
 
-    /* Program over a block boundary */
-    prog_start = flash_start + block_size - sizeof(copyright)/2;
-    ret = cyg_flash_program(prog_start,&copyright,sizeof(copyright),NULL);
+    prog_start = flash_start + block_size - copyright_len/2;
+    ret = cyg_flash_program(prog_start,&copyright,copyright_len,NULL);
     CYG_TEST_PASS_FAIL((ret == CYG_FLASH_ERR_OK),"flash_program2");
   
     /* Check the first version is still OK */
     CYG_TEST_PASS_FAIL(!strncmp((void *)flash_start,
                                 copyright,
-                                sizeof(copyright)),
+                                copyright_len),
                        "Original contents");
   
     CYG_TEST_PASS_FAIL(!strncmp((void *)prog_start,
                                 copyright,
-                                sizeof(copyright)),
+                                copyright_len),
                        "New program contents");
 
     /* Check the bit in between is still erased */
-    for (ptr=(unsigned char *)flash_start+sizeof(copyright),ret=0; 
+    for (ptr=(unsigned char *)flash_start+copyright_len,ret=0; 
          ptr < (unsigned char *)prog_start; ptr++) {
         if (*ptr != 0xff) {
             ret++;
@@ -212,7 +221,7 @@
     /* Lastly check the first half of the copyright message is still there */
     CYG_TEST_PASS_FAIL(!strncmp((void *)prog_start,
                                 copyright,
-                                sizeof(copyright)/2),
+                                copyright_len/2),
                        "Block 1 OK");
 
 #if 0


More information about the Ecos-patches mailing list