Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:04

0001 /*
0002  * RTEMS Project (http://www.rtems.org/)
0003  *
0004  * Copyright 2007 Chris Johns (chrisj@rtems.org)
0005  */
0006 /**
0007  * Provide flash support for the AM26LV160 device.
0008  *
0009  * The M29W160D is the same device.
0010  */
0011 
0012 #include <stdio.h>
0013 #include <errno.h>
0014 #include <string.h>
0015 
0016 #include <rtems.h>
0017 
0018 #include <libchip/am29lv160.h>
0019 
0020 #ifndef AM26LV160_ERROR_TRACE
0021 #define AM26LV160_ERROR_TRACE (0)
0022 #endif
0023 
0024 /**
0025  * Boot blocks at the top
0026  */
0027 const rtems_fdisk_segment_desc rtems_am29lv160t_segments[4] =
0028 {
0029   {
0030     .count =   31,
0031     .segment = 0,
0032     .offset =  0x00000000,
0033     .size =    RTEMS_FDISK_KBYTES (64)
0034   },
0035   {
0036     .count =   1,
0037     .segment = 31,
0038     .offset =  0x001f0000,
0039     .size =    RTEMS_FDISK_KBYTES (32)
0040   },
0041   {
0042     .count =   2,
0043     .segment = 32,
0044     .offset =  0x001f8000,
0045     .size =    RTEMS_FDISK_KBYTES (8)
0046   },
0047   {
0048     .count =   1,
0049     .segment = 34,
0050     .offset =  0x001fc000,
0051     .size =    RTEMS_FDISK_KBYTES (16)
0052   }
0053 };
0054 
0055 /**
0056  * Boot blocks at the bottom.
0057  */
0058 const rtems_fdisk_segment_desc rtems_am29lv160b_segments[] =
0059 {
0060   {
0061     .count =   1,
0062     .segment = 0,
0063     .offset =  0x00000000,
0064     .size =    RTEMS_FDISK_KBYTES (16)
0065   },
0066   {
0067   .  count =   2,
0068     .segment = 1,
0069     .offset =  0x00004000,
0070     .size =    RTEMS_FDISK_KBYTES (8)
0071   },
0072   {
0073     .count =   1,
0074     .segment = 3,
0075     .offset =  0x00008000,
0076     .size =    RTEMS_FDISK_KBYTES (32)
0077   },
0078   {
0079     .count =   31,
0080     .segment = 4,
0081     .offset =  0x00010000,
0082     .size =    RTEMS_FDISK_KBYTES (64)
0083   }
0084 };
0085 
0086 static int
0087 rtems_am29lv160_blank (const rtems_fdisk_segment_desc* sd,
0088                        uint32_t                        device,
0089                        uint32_t                        segment,
0090                        uint32_t                        offset,
0091                        uint32_t                        size)
0092 {
0093   const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
0094   volatile uint8_t*             seg_8 = ac->base;
0095   volatile uint32_t*            seg_32;
0096   uint32_t                      count;
0097 
0098   offset += sd->offset + (segment - sd->segment) * sd->size;
0099 
0100   seg_8 += offset;
0101 
0102   count = offset & (sizeof (uint32_t) - 1);
0103   size -= count;
0104 
0105   while (count--)
0106     if (*seg_8++ != 0xff)
0107     {
0108 #if AM26LV160_ERROR_TRACE
0109       printf ("AM26LV160: blank check error: %p = 0x%02x\n",
0110               seg_8 - 1, *(seg_8 - 1));
0111 #endif
0112       return EIO;
0113     }
0114 
0115   seg_32 = (volatile uint32_t*) seg_8;
0116 
0117   count = size  / sizeof (uint32_t);
0118   size -= count * sizeof (uint32_t);
0119 
0120   while (count--)
0121     if (*seg_32++ != 0xffffffff)
0122     {
0123 #if AM26LV160_ERROR_TRACE
0124       printf ("AM26LV160: blank check error: %p = 0x%08lx\n",
0125               seg_32 - 1, *(seg_32 - 1));
0126 #endif
0127       return EIO;
0128     }
0129 
0130   seg_8 = (volatile uint8_t*) seg_32;
0131 
0132   while (size--)
0133     if (*seg_8++ != 0xff)
0134     {
0135 #if AM26LV160_ERROR_TRACE
0136       printf ("AM26LV160: blank check error: %p = 0x%02x\n",
0137               seg_8 - 1, *(seg_8 - 1));
0138 #endif
0139       return EIO;
0140     }
0141 
0142   return 0;
0143 }
0144 
0145 static int
0146 rtems_am29lv160_verify (const rtems_fdisk_segment_desc* sd,
0147                         uint32_t                        device,
0148                         uint32_t                        segment,
0149                         uint32_t                        offset,
0150                         const void*                     buffer,
0151                         uint32_t                        size)
0152 {
0153   const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
0154   const uint8_t*                addr = ac->base;
0155 
0156   addr += (sd->offset + (segment - sd->segment) * sd->size) + offset;
0157 
0158   if (memcmp (addr, buffer, size) != 0)
0159     return EIO;
0160 
0161   return 0;
0162 }
0163 
0164 static int
0165 rtems_am29lv160_toggle_wait_8 (volatile uint8_t* status)
0166 {
0167   while (1)
0168   {
0169     volatile uint8_t status1 = *status;
0170     volatile uint8_t status2 = *status;
0171 
0172     if (((status1 ^ status2) & (1 << 6)) == 0)
0173       return 0;
0174 
0175     if ((status1 & (1 << 5)) != 0)
0176     {
0177       status1 = *status;
0178       status2 = *status;
0179 
0180       if (((status1 ^ status2) & (1 << 6)) == 0)
0181         return 0;
0182 
0183 #if AM26LV160_ERROR_TRACE
0184       printf ("AM26LV160: error bit detected: %p = 0x%04x\n",
0185               status, status1);
0186 #endif
0187 
0188       *status = 0xf0;
0189       return EIO;
0190     }
0191   }
0192 }
0193 
0194 static int
0195 rtems_am29lv160_toggle_wait_16 (volatile uint16_t* status)
0196 {
0197   while (1)
0198   {
0199     volatile uint16_t status1 = *status;
0200     volatile uint16_t status2 = *status;
0201 
0202     if (((status1 ^ status2) & (1 << 6)) == 0)
0203       return 0;
0204 
0205     if ((status1 & (1 << 5)) != 0)
0206     {
0207       status1 = *status;
0208       status2 = *status;
0209 
0210       if (((status1 ^ status2) & (1 << 6)) == 0)
0211         return 0;
0212 
0213 #if AM26LV160_ERROR_TRACE
0214       printf ("AM26LV160: error bit detected: %p = 0x%04x/0x%04x\n",
0215               status, status1, status2);
0216 #endif
0217 
0218       *status = 0xf0;
0219       return EIO;
0220     }
0221   }
0222 }
0223 
0224 static int
0225 rtems_am29lv160_write_data_8 (volatile uint8_t* base,
0226                               uint32_t          offset,
0227                               const uint8_t*    data,
0228                               uint32_t          size)
0229 {
0230   volatile uint8_t*     seg = base + offset;
0231   rtems_interrupt_level level;
0232 
0233   /*
0234    * Issue a reset.
0235    */
0236   *base = 0xf0;
0237 
0238   while (size)
0239   {
0240     rtems_interrupt_disable (level);
0241     *(base + 0xaaa) = 0xaa;
0242     *(base + 0x555) = 0x55;
0243     *(base + 0xaaa) = 0xa0;
0244     *seg = *data++;
0245     rtems_interrupt_enable (level);
0246     if (rtems_am29lv160_toggle_wait_8 (seg++) != 0)
0247       return EIO;
0248     size--;
0249   }
0250 
0251   /*
0252    * Issue a reset.
0253    */
0254   *base = 0xf0;
0255 
0256   return 0;
0257 }
0258 
0259 static int
0260 rtems_am29lv160_write_data_16 (volatile uint16_t* base,
0261                                uint32_t           offset,
0262                                const uint16_t*    data,
0263                                uint32_t           size)
0264 {
0265   volatile uint16_t*    seg = base + (offset / 2);
0266   rtems_interrupt_level level;
0267 
0268   size /= 2;
0269 
0270   /*
0271    * Issue a reset.
0272    */
0273   *base = 0xf0;
0274 
0275   while (size)
0276   {
0277     rtems_interrupt_disable (level);
0278     *(base + 0x555) = 0xaa;
0279     *(base + 0x2aa) = 0x55;
0280     *(base + 0x555) = 0xa0;
0281     *seg = *data++;
0282     rtems_interrupt_enable (level);
0283     if (rtems_am29lv160_toggle_wait_16 (seg++) != 0)
0284       return EIO;
0285     size--;
0286   }
0287 
0288   /*
0289    * Issue a reset.
0290    */
0291   *base = 0xf0;
0292 
0293   return 0;
0294 }
0295 
0296 static int
0297 rtems_am29lv160_read (const rtems_fdisk_segment_desc* sd,
0298                       uint32_t                        device,
0299                       uint32_t                        segment,
0300                       uint32_t                        offset,
0301                       void*                           buffer,
0302                       uint32_t                        size)
0303 {
0304   unsigned char* addr =
0305     rtems_am29lv160_configuration[device].base +
0306     sd->offset + ((segment - sd->segment) * sd->size) + offset;
0307   memcpy (buffer, addr, size);
0308   return 0;
0309 }
0310 
0311 /*
0312  * @todo Fix the odd alignment and odd sizes.
0313  */
0314 static int
0315 rtems_am29lv160_write (const rtems_fdisk_segment_desc* sd,
0316                        uint32_t                        device,
0317                        uint32_t                        segment,
0318                        uint32_t                        offset,
0319                        const void*                     buffer,
0320                        uint32_t                        size)
0321 {
0322   int ret = rtems_am29lv160_verify (sd, device, segment, offset, buffer, size);
0323 
0324   if (ret != 0)
0325   {
0326     const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
0327     uint32_t                      soffset;
0328 
0329     soffset = offset + sd->offset + ((segment - sd->segment) * sd->size);
0330 
0331     if (offset & 1)
0332       printf ("rtems_am29lv160_write: offset is odd\n");
0333 
0334     if (size & 1)
0335       printf ("rtems_am29lv160_write: size is odd\n");
0336 
0337     if (ac->bus_8bit)
0338       ret = rtems_am29lv160_write_data_8 (ac->base, soffset, buffer, size);
0339     else
0340       ret = rtems_am29lv160_write_data_16 (ac->base, soffset, buffer, size);
0341 
0342     /*
0343      * Verify the write worked.
0344      */
0345     if (ret == 0)
0346     {
0347       ret = rtems_am29lv160_verify (sd, device, segment, offset, buffer, size);
0348 #if AM26LV160_ERROR_TRACE
0349       if (ret)
0350         printf ("AM26LV160: verify failed: %ld-%ld-%08lx: s=%ld\n",
0351                 device, segment, offset, size);
0352 #endif
0353     }
0354   }
0355 
0356   return ret;
0357 }
0358 
0359 static int
0360 rtems_am29lv160_erase (const rtems_fdisk_segment_desc* sd,
0361                        uint32_t                        device,
0362                        uint32_t                        segment)
0363 {
0364   int ret = rtems_am29lv160_blank (sd, device, segment, 0, sd->size);
0365   if (ret != 0)
0366   {
0367     const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
0368     uint32_t                      offset;
0369     rtems_interrupt_level         level;
0370 
0371     offset = sd->offset + ((segment - sd->segment) * sd->size);
0372 
0373     if (ac->bus_8bit)
0374     {
0375       volatile uint8_t* base = ac->base;
0376       volatile uint8_t* seg  = base + offset;
0377 
0378       /*
0379        * Issue a reset.
0380        */
0381       rtems_interrupt_disable (level);
0382       *base = 0xf0;
0383       *(base + 0xaaa) = 0xaa;
0384       *(base + 0x555) = 0x55;
0385       *(base + 0xaaa) = 0x80;
0386       *(base + 0xaaa) = 0xaa;
0387       *(base + 0x555) = 0x55;
0388       *seg = 0x30;
0389       rtems_interrupt_enable (level);
0390 
0391       ret = rtems_am29lv160_toggle_wait_8 (seg);
0392 
0393       /*
0394        * Issue a reset.
0395        */
0396       *base = 0xf0;
0397     }
0398     else
0399     {
0400       volatile uint16_t* base = ac->base;
0401       volatile uint16_t* seg  = base + (offset / 2);
0402 
0403       /*
0404        * Issue a reset.
0405        */
0406       rtems_interrupt_disable (level);
0407       *base = 0xf0;
0408       *(base + 0x555) = 0xaa;
0409       *(base + 0x2aa) = 0x55;
0410       *(base + 0x555) = 0x80;
0411       *(base + 0x555) = 0xaa;
0412       *(base + 0x2aa) = 0x55;
0413       *seg = 0x30;
0414       rtems_interrupt_enable (level);
0415 
0416       ret = rtems_am29lv160_toggle_wait_16 (seg);
0417 
0418       /*
0419        * Issue a reset.
0420        */
0421       *base = 0xf0;
0422     }
0423 
0424     /*
0425      * Check the erase worked.
0426      */
0427     if (ret == 0)
0428     {
0429       ret = rtems_am29lv160_blank (sd, device, segment, 0, sd->size);
0430 #if AM26LV160_ERROR_TRACE
0431       if (ret)
0432         printf ("AM26LV160: erase failed: %ld-%ld\n", device, segment);
0433 #endif
0434     }
0435   }
0436 
0437   return ret;
0438 }
0439 
0440 static int
0441 rtems_am29lv160_erase_device (const rtems_fdisk_device_desc* dd,
0442                               uint32_t                       device)
0443 {
0444   uint32_t segment;
0445 
0446   for (segment = 0; segment < dd->segment_count; segment++)
0447   {
0448     uint32_t seg_segment;
0449 
0450     for (seg_segment = 0;
0451          seg_segment < dd->segments[segment].count;
0452          seg_segment++)
0453     {
0454       int ret = rtems_am29lv160_erase (&dd->segments[segment],
0455                                        device,
0456                                        segment + seg_segment);
0457       if (ret)
0458         return ret;
0459     }
0460   }
0461 
0462   return 0;
0463 }
0464 
0465 const rtems_fdisk_driver_handlers rtems_am29lv160_handlers =
0466 {
0467   .read =         rtems_am29lv160_read,
0468   .write =        rtems_am29lv160_write,
0469   .blank =        rtems_am29lv160_blank,
0470   .verify =       rtems_am29lv160_verify,
0471   .erase =        rtems_am29lv160_erase,
0472   .erase_device = rtems_am29lv160_erase_device
0473 };