File indexing completed on 2025-05-11 08:24:04
0001
0002
0003
0004
0005
0006
0007
0008
0009
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
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
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
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
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
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
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
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
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
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
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
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
0420
0421 *base = 0xf0;
0422 }
0423
0424
0425
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 };