ColdFire: Add M5373EVB platform support - 1
[oweals/u-boot.git] / board / at91rm9200dk / flash.c
index 6497f11ca47066d2ad753d23db6e45c9260ba075..0513d61d73f2df9d211c39bbf0e2b481e85aef57 100644 (file)
 ulong myflush(void);
 
 
-#define FLASH_BANK_SIZE 0x200000       /* 2 MB */
-#define MAIN_SECT_SIZE  0x10000                /* 64 KB */
+/* Flash Organization Structure */
+typedef struct OrgDef
+{
+       unsigned int sector_number;
+       unsigned int sector_size;
+} OrgDef;
+
+
+/* Flash Organizations */
+OrgDef OrgAT49BV16x4[] =
+{
+       {  8,  8*1024 },        /*   8 *  8 kBytes sectors */
+       {  2, 32*1024 },        /*   2 * 32 kBytes sectors */
+       { 30, 64*1024 },        /*  30 * 64 kBytes sectors */
+};
+
+OrgDef OrgAT49BV16x4A[] =
+{
+       {  8,  8*1024 },        /*   8 *  8 kBytes sectors */
+       { 31, 64*1024 },        /*  31 * 64 kBytes sectors */
+};
+
+OrgDef OrgAT49BV6416[] =
+{
+       {   8,  8*1024 },       /*   8 *  8 kBytes sectors */
+       { 127, 64*1024 },       /* 127 * 64 kBytes sectors */
+};
 
 flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
 
+/* AT49BV1614A Codes */
+#define FLASH_CODE1            0xAA
+#define FLASH_CODE2            0x55
+#define ID_IN_CODE             0x90
+#define ID_OUT_CODE            0xF0
+
 
 #define CMD_READ_ARRAY         0x00F0
 #define CMD_UNLOCK1            0x00AA
@@ -44,6 +75,7 @@ flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
 #define CMD_ERASE_CONFIRM      0x0030
 #define CMD_PROGRAM            0x00A0
 #define CMD_UNLOCK_BYPASS      0x0020
+#define CMD_SECTOR_UNLOCK      0x0070
 
 #define MEM_FLASH_ADDR1                (*(volatile u16 *)(CFG_FLASH_BASE + (0x00005555<<1)))
 #define MEM_FLASH_ADDR2                (*(volatile u16 *)(CFG_FLASH_BASE + (0x00002AAA<<1)))
@@ -59,339 +91,412 @@ flash_info_t    flash_info[CFG_MAX_FLASH_BANKS];
 
 /*-----------------------------------------------------------------------
  */
-
-ulong flash_init(void)
+void flash_identification (flash_info_t * info)
 {
-    int i, j;
-    ulong size = 0;
-
-    for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
-    {
-       ulong flashbase = 0;
-       flash_info[i].flash_id =
-         (ATM_MANUFACT & FLASH_VENDMASK) |
-         (ATM_ID_BV1614 & FLASH_TYPEMASK);
-       flash_info[i].size = FLASH_BANK_SIZE;
-       flash_info[i].sector_count = CFG_MAX_FLASH_SECT;
-       memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
-       if (i == 0)
-         flashbase = PHYS_FLASH_1;
-       else
-         panic("configured to many flash banks!\n");
-       for (j = 0; j < flash_info[i].sector_count; j++)
-       {
-
-           if (j <= 9)
-           {
-               /* 1st to 8th are 8 KB */
-               if (j <= 7)
-               {
-                   flash_info[i].start[j] = flashbase + j*0x2000;
-               }
+       volatile u16 manuf_code, device_code, add_device_code;
+
+       MEM_FLASH_ADDR1 = FLASH_CODE1;
+       MEM_FLASH_ADDR2 = FLASH_CODE2;
+       MEM_FLASH_ADDR1 = ID_IN_CODE;
+
+       manuf_code = *(volatile u16 *) CFG_FLASH_BASE;
+       device_code = *(volatile u16 *) (CFG_FLASH_BASE + 2);
+       add_device_code = *(volatile u16 *) (CFG_FLASH_BASE + (3 << 1));
+
+       MEM_FLASH_ADDR1 = FLASH_CODE1;
+       MEM_FLASH_ADDR2 = FLASH_CODE2;
+       MEM_FLASH_ADDR1 = ID_OUT_CODE;
+
+       /* Vendor type */
+       info->flash_id = ATM_MANUFACT & FLASH_VENDMASK;
+       printf ("Atmel: ");
 
-               /* 9th and 10th are both 32 KB */
-               if ((j == 8) || (j == 9))
-               {
-                       flash_info[i].start[j] = flashbase + 0x10000 + (j-8)*0x8000;
+       if ((device_code & FLASH_TYPEMASK) == (ATM_ID_BV1614 & FLASH_TYPEMASK)) {
+
+               if ((add_device_code & FLASH_TYPEMASK) ==
+                       (ATM_ID_BV1614A & FLASH_TYPEMASK)) {
+                       info->flash_id |= ATM_ID_BV1614A & FLASH_TYPEMASK;
+                       printf ("AT49BV1614A (16Mbit)\n");
+               } else {                                /* AT49BV1614 Flash */
+                       info->flash_id |= ATM_ID_BV1614 & FLASH_TYPEMASK;
+                       printf ("AT49BV1614 (16Mbit)\n");
                }
-           }
-           else
-           {
-               flash_info[i].start[j] = flashbase + (j-8)*MAIN_SECT_SIZE;
-           }
+
+       } else if ((device_code & FLASH_TYPEMASK) == (ATM_ID_BV6416 & FLASH_TYPEMASK)) {
+               info->flash_id |= ATM_ID_BV6416 & FLASH_TYPEMASK;
+               printf ("AT49BV6416 (64Mbit)\n");
        }
-       size += flash_info[i].size;
-    }
+}
 
-    flash_protect(FLAG_PROTECT_SET,
-                 CFG_FLASH_BASE,
-                 CFG_ENV_ADDR - 1,
-                 &flash_info[0]);
+ushort flash_number_sector(OrgDef *pOrgDef, unsigned int nb_blocks)
+{
+       int i, nb_sectors = 0;
 
-    flash_protect(FLAG_PROTECT_SET,
-                 CFG_ENV_ADDR,
-                 CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
-                 &flash_info[0]);
+       for (i=0; i<nb_blocks; i++){
+               nb_sectors += pOrgDef[i].sector_number;
+       }
 
-    return size;
+       return nb_sectors;
 }
 
-/*-----------------------------------------------------------------------
- */
-void flash_print_info  (flash_info_t *info)
+void flash_unlock_sector(flash_info_t * info, unsigned int sector)
 {
-    int i;
-
-    switch (info->flash_id & FLASH_VENDMASK)
-    {
-    case (ATM_MANUFACT & FLASH_VENDMASK):
-       printf("Atmel: ");
-       break;
-    default:
-       printf("Unknown Vendor ");
-       break;
-    }
-
-    switch (info->flash_id & FLASH_TYPEMASK)
-    {
-    case (ATM_ID_BV1614 & FLASH_TYPEMASK):
-       printf("AT49BV1614 (16Mbit)\n");
-       break;
-    default:
-       printf("Unknown Chip Type\n");
-       goto Done;
-       break;
-    }
-
-    printf("  Size: %ld MB in %d Sectors\n",
-          info->size >> 20, info->sector_count);
-
-    printf("  Sector Start Addresses:");
-    for (i = 0; i < info->sector_count; i++)
-    {
-       if ((i % 5) == 0)
-       {
-           printf ("\n   ");
-       }
-       printf (" %08lX%s", info->start[i],
-               info->protect[i] ? " (RO)" : "     ");
-    }
-    printf ("\n");
+       volatile u16 *addr = (volatile u16 *) (info->start[sector]);
 
-Done:
+       MEM_FLASH_ADDR1 = CMD_UNLOCK1;
+       *addr = CMD_SECTOR_UNLOCK;
 }
 
-/*-----------------------------------------------------------------------
- */
 
-int    flash_erase (flash_info_t *info, int s_first, int s_last)
+ulong flash_init (void)
 {
-    ulong result;
-    int iflag, cflag, prot, sect;
-    int rc = ERR_OK;
-    int chip1;
+       int i, j, k;
+       unsigned int flash_nb_blocks, sector;
+       unsigned int start_address;
+       OrgDef *pOrgDef;
+
+       ulong size = 0;
+
+       for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
+               ulong flashbase = 0;
+
+               flash_identification (&flash_info[i]);
 
-    /* first look for protection bits */
+               if ((flash_info[i].flash_id & FLASH_TYPEMASK) ==
+                       (ATM_ID_BV1614 & FLASH_TYPEMASK)) {
 
-    if (info->flash_id == FLASH_UNKNOWN)
-       return ERR_UNKNOWN_FLASH_TYPE;
+                       pOrgDef = OrgAT49BV16x4;
+                       flash_nb_blocks = sizeof (OrgAT49BV16x4) / sizeof (OrgDef);
+               } else if ((flash_info[i].flash_id & FLASH_TYPEMASK) ==
+                       (ATM_ID_BV1614A & FLASH_TYPEMASK)){     /* AT49BV1614A Flash */
 
-    if ((s_first < 0) || (s_first > s_last)) {
-       return ERR_INVAL;
-    }
+                       pOrgDef = OrgAT49BV16x4A;
+                       flash_nb_blocks = sizeof (OrgAT49BV16x4A) / sizeof (OrgDef);
+               } else if ((flash_info[i].flash_id & FLASH_TYPEMASK) ==
+                       (ATM_ID_BV6416 & FLASH_TYPEMASK)){      /* AT49BV6416 Flash */
 
-    if ((info->flash_id & FLASH_VENDMASK) !=
-       (ATM_MANUFACT & FLASH_VENDMASK)) {
-       return ERR_UNKNOWN_FLASH_VENDOR;
-    }
+                       pOrgDef = OrgAT49BV6416;
+                       flash_nb_blocks = sizeof (OrgAT49BV6416) / sizeof (OrgDef);
+               } else {
+                       flash_nb_blocks = 0;
+                       pOrgDef = OrgAT49BV16x4;
+               }
+
+               flash_info[i].sector_count = flash_number_sector(pOrgDef, flash_nb_blocks);
+               memset (flash_info[i].protect, 0, flash_info[i].sector_count);
+
+               if (i == 0)
+                       flashbase = PHYS_FLASH_1;
+               else
+                       panic ("configured too many flash banks!\n");
 
-    prot = 0;
-    for (sect=s_first; sect<=s_last; ++sect) {
-       if (info->protect[sect]) {
-           prot++;
+               sector = 0;
+               start_address = flashbase;
+               flash_info[i].size = 0;
+
+               for (j = 0; j < flash_nb_blocks; j++) {
+                       for (k = 0; k < pOrgDef[j].sector_number; k++) {
+                               flash_info[i].start[sector++] = start_address;
+                               start_address += pOrgDef[j].sector_size;
+                               flash_info[i].size += pOrgDef[j].sector_size;
+                       }
+               }
+
+               size += flash_info[i].size;
+
+               if ((flash_info[i].flash_id & FLASH_TYPEMASK) ==
+                       (ATM_ID_BV6416 & FLASH_TYPEMASK)){      /* AT49BV6416 Flash */
+
+                       /* Unlock all sectors at reset */
+                       for (j=0; j<flash_info[i].sector_count; j++){
+                               flash_unlock_sector(&flash_info[i], j);
+                       }
+               }
        }
-    }
-    if (prot)
-       return ERR_PROTECTED;
-
-    /*
-     * Disable interrupts which might cause a timeout
-     * here. Remember that our exception vectors are
-     * at address 0 in the flash, and we don't want a
-     * (ticker) exception to happen while the flash
-     * chip is in programming mode.
-     */
-    cflag = icache_status();
-    icache_disable();
-    iflag = disable_interrupts();
-
-    /* Start erase on unprotected sectors */
-    for (sect = s_first; sect<=s_last && !ctrlc(); sect++)
-    {
-       printf("Erasing sector %2d ... ", sect);
 
-       /* arm simple, non interrupt dependent timer */
-       reset_timer_masked();
+       /* Protect binary boot image */
+       flash_protect (FLAG_PROTECT_SET,
+                      CFG_FLASH_BASE,
+                      CFG_FLASH_BASE + CFG_BOOT_SIZE - 1, &flash_info[0]);
+
+       /* Protect environment variables */
+       flash_protect (FLAG_PROTECT_SET,
+                      CFG_ENV_ADDR,
+                      CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
 
-       if (info->protect[sect] == 0)
-       {       /* not protected */
-           volatile u16 *addr = (volatile u16 *)(info->start[sect]);
+       /* Protect U-Boot gzipped image */
+       flash_protect (FLAG_PROTECT_SET,
+                      CFG_U_BOOT_BASE,
+                      CFG_U_BOOT_BASE + CFG_U_BOOT_SIZE - 1, &flash_info[0]);
 
-           MEM_FLASH_ADDR1 = CMD_UNLOCK1;
-           MEM_FLASH_ADDR2 = CMD_UNLOCK2;
-           MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
+       return size;
+}
 
-           MEM_FLASH_ADDR1 = CMD_UNLOCK1;
-           MEM_FLASH_ADDR2 = CMD_UNLOCK2;
-           *addr = CMD_ERASE_CONFIRM;
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t * info)
+{
+       int i;
+
+       switch (info->flash_id & FLASH_VENDMASK) {
+       case (ATM_MANUFACT & FLASH_VENDMASK):
+               printf ("Atmel: ");
+               break;
+       default:
+               printf ("Unknown Vendor ");
+               break;
+       }
 
-           /* wait until flash is ready */
-           chip1 = 0;
+       switch (info->flash_id & FLASH_TYPEMASK) {
+       case (ATM_ID_BV1614 & FLASH_TYPEMASK):
+               printf ("AT49BV1614 (16Mbit)\n");
+               break;
+       case (ATM_ID_BV1614A & FLASH_TYPEMASK):
+               printf ("AT49BV1614A (16Mbit)\n");
+               break;
+       case (ATM_ID_BV6416 & FLASH_TYPEMASK):
+               printf ("AT49BV6416 (64Mbit)\n");
+               break;
+       default:
+               printf ("Unknown Chip Type\n");
+               return;
+       }
 
-           do
-           {
-               result = *addr;
+       printf ("  Size: %ld MB in %d Sectors\n",
+               info->size >> 20, info->sector_count);
 
-               /* check timeout */
-               if (get_timer_masked() > CFG_FLASH_ERASE_TOUT)
-               {
-                   MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
-                   chip1 = TMO;
-                   break;
+       printf ("  Sector Start Addresses:");
+       for (i = 0; i < info->sector_count; i++) {
+               if ((i % 5) == 0) {
+                       printf ("\n   ");
                }
+               printf (" %08lX%s", info->start[i],
+                       info->protect[i] ? " (RO)" : "     ");
+       }
+       printf ("\n");
+}
 
-               if (!chip1 && (result & 0xFFFF) & BIT_ERASE_DONE)
-                       chip1 = READY;
+/*-----------------------------------------------------------------------
+ */
 
-           }  while (!chip1);
+int flash_erase (flash_info_t * info, int s_first, int s_last)
+{
+       ulong result;
+       int iflag, cflag, prot, sect;
+       int rc = ERR_OK;
+       int chip1;
 
-           MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
+       /* first look for protection bits */
 
-           if (chip1 == ERR)
-           {
-               rc = ERR_PROG_ERROR;
-               goto outahere;
-           }
-           if (chip1 == TMO)
-           {
-               rc = ERR_TIMOUT;
-               goto outahere;
-           }
-
-           printf("ok.\n");
+       if (info->flash_id == FLASH_UNKNOWN)
+               return ERR_UNKNOWN_FLASH_TYPE;
+
+       if ((s_first < 0) || (s_first > s_last)) {
+               return ERR_INVAL;
        }
-       else /* it was protected */
-       {
-           printf("protected!\n");
+
+       if ((info->flash_id & FLASH_VENDMASK) !=
+               (ATM_MANUFACT & FLASH_VENDMASK)) {
+               return ERR_UNKNOWN_FLASH_VENDOR;
        }
-    }
 
-    if (ctrlc())
-      printf("User Interrupt!\n");
+       prot = 0;
+       for (sect = s_first; sect <= s_last; ++sect) {
+               if (info->protect[sect]) {
+                       prot++;
+               }
+       }
+       if (prot)
+               return ERR_PROTECTED;
+
+       /*
+        * Disable interrupts which might cause a timeout
+        * here. Remember that our exception vectors are
+        * at address 0 in the flash, and we don't want a
+        * (ticker) exception to happen while the flash
+        * chip is in programming mode.
+        */
+       cflag = icache_status ();
+       icache_disable ();
+       iflag = disable_interrupts ();
+
+       /* Start erase on unprotected sectors */
+       for (sect = s_first; sect <= s_last && !ctrlc (); sect++) {
+               printf ("Erasing sector %2d ... ", sect);
+
+               /* arm simple, non interrupt dependent timer */
+               reset_timer_masked ();
+
+               if (info->protect[sect] == 0) { /* not protected */
+                       volatile u16 *addr = (volatile u16 *) (info->start[sect]);
+
+                       MEM_FLASH_ADDR1 = CMD_UNLOCK1;
+                       MEM_FLASH_ADDR2 = CMD_UNLOCK2;
+                       MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
+
+                       MEM_FLASH_ADDR1 = CMD_UNLOCK1;
+                       MEM_FLASH_ADDR2 = CMD_UNLOCK2;
+                       *addr = CMD_ERASE_CONFIRM;
+
+                       /* wait until flash is ready */
+                       chip1 = 0;
+
+                       do {
+                               result = *addr;
+
+                               /* check timeout */
+                               if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) {
+                                       MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
+                                       chip1 = TMO;
+                                       break;
+                               }
+
+                               if (!chip1 && (result & 0xFFFF) & BIT_ERASE_DONE)
+                                       chip1 = READY;
+
+                       } while (!chip1);
+
+                       MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
+
+                       if (chip1 == ERR) {
+                               rc = ERR_PROG_ERROR;
+                               goto outahere;
+                       }
+                       if (chip1 == TMO) {
+                               rc = ERR_TIMOUT;
+                               goto outahere;
+                       }
+
+                       printf ("ok.\n");
+               } else {                        /* it was protected */
+                       printf ("protected!\n");
+               }
+       }
+
+       if (ctrlc ())
+               printf ("User Interrupt!\n");
 
 outahere:
-    /* allow flash to settle - wait 10 ms */
-    udelay_masked(10000);
+       /* allow flash to settle - wait 10 ms */
+       udelay_masked (10000);
 
-    if (iflag)
-      enable_interrupts();
+       if (iflag)
+               enable_interrupts ();
 
-    if (cflag)
-      icache_enable();
+       if (cflag)
+               icache_enable ();
 
-    return rc;
+       return rc;
 }
 
 /*-----------------------------------------------------------------------
  * Copy memory to flash
  */
 
-volatile static int write_word (flash_info_t *info, ulong dest, ulong data)
+static int write_word (flash_info_t * info, ulong dest, ulong data)
 {
-    volatile u16 *addr = (volatile u16 *)dest;
-    ulong result;
-    int rc = ERR_OK;
-    int cflag, iflag;
-    int chip1;
-
-    /*
-     * Check if Flash is (sufficiently) erased
-     */
-    result = *addr;
-    if ((result & data) != data)
-        return ERR_NOT_ERASED;
-
-
-    /*
-     * Disable interrupts which might cause a timeout
-     * here. Remember that our exception vectors are
-     * at address 0 in the flash, and we don't want a
-     * (ticker) exception to happen while the flash
-     * chip is in programming mode.
-     */
-    cflag = icache_status();
-    icache_disable();
-    iflag = disable_interrupts();
-
-    MEM_FLASH_ADDR1 = CMD_UNLOCK1;
-    MEM_FLASH_ADDR2 = CMD_UNLOCK2;
-    MEM_FLASH_ADDR1 = CMD_PROGRAM;
-    *addr = data;
-
-    /* arm simple, non interrupt dependent timer */
-    reset_timer_masked();
-
-    /* wait until flash is ready */
-    chip1 = 0;
-    do
-    {
+       volatile u16 *addr = (volatile u16 *) dest;
+       ulong result;
+       int rc = ERR_OK;
+       int cflag, iflag;
+       int chip1;
+
+       /*
+        * Check if Flash is (sufficiently) erased
+        */
        result = *addr;
+       if ((result & data) != data)
+               return ERR_NOT_ERASED;
+
+       /*
+        * Disable interrupts which might cause a timeout
+        * here. Remember that our exception vectors are
+        * at address 0 in the flash, and we don't want a
+        * (ticker) exception to happen while the flash
+        * chip is in programming mode.
+        */
+       cflag = icache_status ();
+       icache_disable ();
+       iflag = disable_interrupts ();
+
+       MEM_FLASH_ADDR1 = CMD_UNLOCK1;
+       MEM_FLASH_ADDR2 = CMD_UNLOCK2;
+       MEM_FLASH_ADDR1 = CMD_PROGRAM;
+       *addr = data;
 
-       /* check timeout */
-       if (get_timer_masked() > CFG_FLASH_ERASE_TOUT)
-       {
-           chip1 = ERR | TMO;
-           break;
-       }
-       if (!chip1 && ((result & 0x80) == (data & 0x80)))
-               chip1 = READY;
+       /* arm simple, non interrupt dependent timer */
+       reset_timer_masked ();
+
+       /* wait until flash is ready */
+       chip1 = 0;
+       do {
+               result = *addr;
 
-    }  while (!chip1);
+               /* check timeout */
+               if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) {
+                       chip1 = ERR | TMO;
+                       break;
+               }
+               if (!chip1 && ((result & 0x80) == (data & 0x80)))
+                       chip1 = READY;
 
-    *addr = CMD_READ_ARRAY;
+       } while (!chip1);
 
-    if (chip1 == ERR || *addr != data)
-        rc = ERR_PROG_ERROR;
+       *addr = CMD_READ_ARRAY;
+
+       if (chip1 == ERR || *addr != data)
+               rc = ERR_PROG_ERROR;
 
-    if (iflag)
-      enable_interrupts();
+       if (iflag)
+               enable_interrupts ();
 
-    if (cflag)
-      icache_enable();
+       if (cflag)
+               icache_enable ();
 
-    return rc;
+       return rc;
 }
 
 /*-----------------------------------------------------------------------
  * Copy memory to flash.
  */
 
-int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
 {
-    ulong wp, data;
-    int rc;
+       ulong wp, data;
+       int rc;
 
-    if(addr & 1) {
-      printf("unaligned destination not supported\n");
-      return ERR_ALIGN;
-    };
+       if (addr & 1) {
+               printf ("unaligned destination not supported\n");
+               return ERR_ALIGN;
+       };
 
-    if((int)src & 1) {
-      printf("unaligned source not supported\n");
-      return ERR_ALIGN;
-    };
+       if ((int) src & 1) {
+               printf ("unaligned source not supported\n");
+               return ERR_ALIGN;
+       };
 
-    wp = addr;
+       wp = addr;
 
-    while (cnt >= 2) {
-       data = *((volatile u16*)src);
-       if ((rc = write_word(info, wp, data)) != 0) {
-           return (rc);
-       }
-       src += 2;
-       wp  += 2;
-       cnt -= 2;
-    }
-
-    if(cnt == 1) {
-      data =  (*((volatile u8*)src)) | (*((volatile u8*)(wp+1)) << 8);
-       if ((rc = write_word(info, wp, data)) != 0) {
-           return (rc);
+       while (cnt >= 2) {
+               data = *((volatile u16 *) src);
+               if ((rc = write_word (info, wp, data)) != 0) {
+                       return (rc);
+               }
+               src += 2;
+               wp += 2;
+               cnt -= 2;
        }
-       src += 1;
-       wp  += 1;
-       cnt -= 1;
-    };
 
-    return ERR_OK;
+       if (cnt == 1) {
+               data = (*((volatile u8 *) src)) | (*((volatile u8 *) (wp + 1)) <<
+                                                                                  8);
+               if ((rc = write_word (info, wp, data)) != 0) {
+                       return (rc);
+               }
+               src += 1;
+               wp += 1;
+               cnt -= 1;
+       };
+
+       return ERR_OK;
 }