source: rtems/c/src/libchip/flash/am29lv160.c @ 06a36cd1

4.11
Last change on this file since 06a36cd1 was 06a36cd1, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 7, 2011 at 10:15:25 PM

2011-07-07 Joel Sherrill <joel.sherrill@…>

  • libchip/display/disp_hcms29xx.c, libchip/flash/am29lv160.c, libchip/i2c/i2c-2b-eeprom.c, libchip/i2c/i2c-ds1621.c, libchip/i2c/spi-flash-m25p40.c, libchip/i2c/spi-fram-fm25l256.c, libchip/i2c/spi-memdrv.c, libchip/rtc/ds1375.c: Eliminate use of GNU old-style field designator extension as recommended by clang.
  • Property mode set to 100644
File size: 10.7 KB
Line 
1/*
2 *  $Id$
3 *
4 * RTEMS Project (http://www.rtems.org/)
5 *
6 * Copyright 2007 Chris Johns (chrisj@rtems.org)
7 */
8/**
9 * Provide flash support for the AM26LV160 device.
10 *
11 * The M29W160D is the same device.
12 */
13
14#include <stdio.h>
15#include <errno.h>
16
17#include <rtems.h>
18
19#include <libchip/am29lv160.h>
20
21#ifndef AM26LV160_ERROR_TRACE
22#define AM26LV160_ERROR_TRACE (0)
23#endif
24
25/**
26 * Boot blocks at the top
27 */
28const rtems_fdisk_segment_desc rtems_am29lv160t_segments[4] =
29{
30  {
31    .count =   31,
32    .segment = 0,
33    .offset =  0x00000000,
34    .size =    RTEMS_FDISK_KBYTES (64)
35  },
36  {
37    .count =   1,
38    .segment = 31,
39    .offset =  0x001f0000,
40    .size =    RTEMS_FDISK_KBYTES (32)
41  },
42  {
43    .count =   2,
44    .segment = 32,
45    .offset =  0x001f8000,
46    .size =    RTEMS_FDISK_KBYTES (8)
47  },
48  {
49    .count =   1,
50    .segment = 34,
51    .offset =  0x001fc000,
52    .size =    RTEMS_FDISK_KBYTES (16)
53  }
54};
55
56/**
57 * Boot blocks at the bottom.
58 */
59const rtems_fdisk_segment_desc rtems_am29lv160b_segments[] =
60{
61  {
62    .count =   1,
63    .segment = 0,
64    .offset =  0x00000000,
65    .size =    RTEMS_FDISK_KBYTES (16)
66  },
67  {
68  .  count =   2,
69    .segment = 1,
70    .offset =  0x00004000,
71    .size =    RTEMS_FDISK_KBYTES (8)
72  },
73  {
74    .count =   1,
75    .segment = 3,
76    .offset =  0x00008000,
77    .size =    RTEMS_FDISK_KBYTES (32)
78  },
79  {
80    .count =   31,
81    .segment = 4,
82    .offset =  0x00010000,
83    .size =    RTEMS_FDISK_KBYTES (64)
84  }
85};
86
87static int
88rtems_am29lv160_blank (const rtems_fdisk_segment_desc* sd,
89                       uint32_t                        device,
90                       uint32_t                        segment,
91                       uint32_t                        offset,
92                       uint32_t                        size)
93{
94  const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
95  volatile uint8_t*             seg_8 = ac->base;
96  volatile uint32_t*            seg_32;
97  uint32_t                      count;
98
99  offset += sd->offset + (segment - sd->segment) * sd->size;
100
101  seg_8 += offset;
102
103  count = offset & (sizeof (uint32_t) - 1);
104  size -= count;
105
106  while (count--)
107    if (*seg_8++ != 0xff)
108    {
109#if AM26LV160_ERROR_TRACE
110      printf ("AM26LV160: blank check error: %p = 0x%02x\n",
111              seg_8 - 1, *(seg_8 - 1));
112#endif
113      return EIO;
114    }
115
116  seg_32 = (volatile uint32_t*) seg_8;
117
118  count = size  / sizeof (uint32_t);
119  size -= count * sizeof (uint32_t);
120
121  while (count--)
122    if (*seg_32++ != 0xffffffff)
123    {
124#if AM26LV160_ERROR_TRACE
125      printf ("AM26LV160: blank check error: %p = 0x%08lx\n",
126              seg_32 - 1, *(seg_32 - 1));
127#endif
128      return EIO;
129    }
130
131  seg_8 = (volatile uint8_t*) seg_32;
132
133  while (size--)
134    if (*seg_8++ != 0xff)
135    {
136#if AM26LV160_ERROR_TRACE
137      printf ("AM26LV160: blank check error: %p = 0x%02x\n",
138              seg_8 - 1, *(seg_8 - 1));
139#endif
140      return EIO;
141    }
142
143  return 0;
144}
145
146static int
147rtems_am29lv160_verify (const rtems_fdisk_segment_desc* sd,
148                        uint32_t                        device,
149                        uint32_t                        segment,
150                        uint32_t                        offset,
151                        const void*                     buffer,
152                        uint32_t                        size)
153{
154  const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
155  const uint8_t*                addr = ac->base;
156
157  addr += (sd->offset + (segment - sd->segment) * sd->size) + offset;
158
159  if (memcmp (addr, buffer, size) != 0)
160    return EIO;
161
162  return 0;
163}
164
165static int
166rtems_am29lv160_toggle_wait_8 (volatile uint8_t* status)
167{
168  while (1)
169  {
170    volatile uint8_t status1 = *status;
171    volatile uint8_t status2 = *status;
172
173    if (((status1 ^ status2) & (1 << 6)) == 0)
174      return 0;
175
176    if ((status1 & (1 << 5)) != 0)
177    {
178      status1 = *status;
179      status2 = *status;
180
181      if (((status1 ^ status2) & (1 << 6)) == 0)
182        return 0;
183
184#if AM26LV160_ERROR_TRACE
185      printf ("AM26LV160: error bit detected: %p = 0x%04x\n",
186              status, status1);
187#endif
188
189      *status = 0xf0;
190      return EIO;
191    }
192  }
193}
194
195static int
196rtems_am29lv160_toggle_wait_16 (volatile uint16_t* status)
197{
198  while (1)
199  {
200    volatile uint16_t status1 = *status;
201    volatile uint16_t status2 = *status;
202
203    if (((status1 ^ status2) & (1 << 6)) == 0)
204      return 0;
205
206    if ((status1 & (1 << 5)) != 0)
207    {
208      status1 = *status;
209      status2 = *status;
210
211      if (((status1 ^ status2) & (1 << 6)) == 0)
212        return 0;
213
214#if AM26LV160_ERROR_TRACE
215      printf ("AM26LV160: error bit detected: %p = 0x%04x/0x%04x\n",
216              status, status1, status2);
217#endif
218
219      *status = 0xf0;
220      return EIO;
221    }
222  }
223}
224
225static int
226rtems_am29lv160_write_data_8 (volatile uint8_t* base,
227                              uint32_t          offset,
228                              const uint8_t*    data,
229                              uint32_t          size)
230{
231  volatile uint8_t*     seg = base + offset;
232  rtems_interrupt_level level;
233
234  /*
235   * Issue a reset.
236   */
237  *base = 0xf0;
238
239  while (size)
240  {
241    rtems_interrupt_disable (level);
242    *(base + 0xaaa) = 0xaa;
243    *(base + 0x555) = 0x55;
244    *(base + 0xaaa) = 0xa0;
245    *seg = *data++;
246    rtems_interrupt_enable (level);
247    if (rtems_am29lv160_toggle_wait_8 (seg++) != 0)
248      return EIO;
249    size--;
250  }
251
252  /*
253   * Issue a reset.
254   */
255  *base = 0xf0;
256
257  return 0;
258}
259
260static int
261rtems_am29lv160_write_data_16 (volatile uint16_t* base,
262                               uint32_t           offset,
263                               const uint16_t*    data,
264                               uint32_t           size)
265{
266  volatile uint16_t*    seg = base + (offset / 2);
267  rtems_interrupt_level level;
268
269  size /= 2;
270
271  /*
272   * Issue a reset.
273   */
274  *base = 0xf0;
275
276  while (size)
277  {
278    rtems_interrupt_disable (level);
279    *(base + 0x555) = 0xaa;
280    *(base + 0x2aa) = 0x55;
281    *(base + 0x555) = 0xa0;
282    *seg = *data++;
283    rtems_interrupt_enable (level);
284    if (rtems_am29lv160_toggle_wait_16 (seg++) != 0)
285      return EIO;
286    size--;
287  }
288
289  /*
290   * Issue a reset.
291   */
292  *base = 0xf0;
293
294  return 0;
295}
296
297static int
298rtems_am29lv160_read (const rtems_fdisk_segment_desc* sd,
299                      uint32_t                        device,
300                      uint32_t                        segment,
301                      uint32_t                        offset,
302                      void*                           buffer,
303                      uint32_t                        size)
304{
305  unsigned char* addr =
306    rtems_am29lv160_configuration[device].base +
307    sd->offset + ((segment - sd->segment) * sd->size) + offset;
308  memcpy (buffer, addr, size);
309  return 0;
310}
311
312/*
313 * @todo Fix the odd alignment and odd sizes.
314 */
315static int
316rtems_am29lv160_write (const rtems_fdisk_segment_desc* sd,
317                       uint32_t                        device,
318                       uint32_t                        segment,
319                       uint32_t                        offset,
320                       const void*                     buffer,
321                       uint32_t                        size)
322{
323  int ret = rtems_am29lv160_verify (sd, device, segment, offset, buffer, size);
324
325  if (ret != 0)
326  {
327    const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
328    uint32_t                      soffset;
329
330    soffset = offset + sd->offset + ((segment - sd->segment) * sd->size);
331
332    if (offset & 1)
333      printf ("rtems_am29lv160_write: offset is odd\n");
334
335    if (size & 1)
336      printf ("rtems_am29lv160_write: size is odd\n");
337
338    if (ac->bus_8bit)
339      ret = rtems_am29lv160_write_data_8 (ac->base, soffset, buffer, size);
340    else
341      ret = rtems_am29lv160_write_data_16 (ac->base, soffset, buffer, size);
342
343    /*
344     * Verify the write worked.
345     */
346    if (ret == 0)
347    {
348      ret = rtems_am29lv160_verify (sd, device, segment, offset, buffer, size);
349#if AM26LV160_ERROR_TRACE
350      if (ret)
351        printf ("AM26LV160: verify failed: %ld-%ld-%08lx: s=%ld\n",
352                device, segment, offset, size);
353#endif
354    }
355  }
356
357  return ret;
358}
359
360static int
361rtems_am29lv160_erase (const rtems_fdisk_segment_desc* sd,
362                       uint32_t                        device,
363                       uint32_t                        segment)
364{
365  int ret = rtems_am29lv160_blank (sd, device, segment, 0, sd->size);
366  if (ret != 0)
367  {
368    const rtems_am29lv160_config* ac = &rtems_am29lv160_configuration[device];
369    uint32_t                      offset;
370    rtems_interrupt_level         level;
371
372    offset = sd->offset + ((segment - sd->segment) * sd->size);
373
374    if (ac->bus_8bit)
375    {
376      volatile uint8_t* base = ac->base;
377      volatile uint8_t* seg  = base + offset;
378
379      /*
380       * Issue a reset.
381       */
382      rtems_interrupt_disable (level);
383      *base = 0xf0;
384      *(base + 0xaaa) = 0xaa;
385      *(base + 0x555) = 0x55;
386      *(base + 0xaaa) = 0x80;
387      *(base + 0xaaa) = 0xaa;
388      *(base + 0x555) = 0x55;
389      *seg = 0x30;
390      rtems_interrupt_enable (level);
391
392      ret = rtems_am29lv160_toggle_wait_8 (seg);
393
394      /*
395       * Issue a reset.
396       */
397      *base = 0xf0;
398    }
399    else
400    {
401      volatile uint16_t* base = ac->base;
402      volatile uint16_t* seg  = base + (offset / 2);
403
404      /*
405       * Issue a reset.
406       */
407      rtems_interrupt_disable (level);
408      *base = 0xf0;
409      *(base + 0x555) = 0xaa;
410      *(base + 0x2aa) = 0x55;
411      *(base + 0x555) = 0x80;
412      *(base + 0x555) = 0xaa;
413      *(base + 0x2aa) = 0x55;
414      *seg = 0x30;
415      rtems_interrupt_enable (level);
416
417      ret = rtems_am29lv160_toggle_wait_16 (seg);
418
419      /*
420       * Issue a reset.
421       */
422      *base = 0xf0;
423    }
424
425    /*
426     * Check the erase worked.
427     */
428    if (ret == 0)
429    {
430      ret = rtems_am29lv160_blank (sd, device, segment, 0, sd->size);
431#if AM26LV160_ERROR_TRACE
432      if (ret)
433        printf ("AM26LV160: erase failed: %ld-%ld\n", device, segment);
434#endif
435    }
436  }
437
438  return ret;
439}
440
441static int
442rtems_am29lv160_erase_device (const rtems_fdisk_device_desc* dd,
443                              uint32_t                       device)
444{
445  uint32_t segment;
446
447  for (segment = 0; segment < dd->segment_count; segment++)
448  {
449    uint32_t seg_segment;
450
451    for (seg_segment = 0;
452         seg_segment < dd->segments[segment].count;
453         seg_segment++)
454    {
455      int ret = rtems_am29lv160_erase (&dd->segments[segment],
456                                       device,
457                                       segment + seg_segment);
458      if (ret)
459        return ret;
460    }
461  }
462
463  return 0;
464}
465
466const rtems_fdisk_driver_handlers rtems_am29lv160_handlers =
467{
468  .read =         rtems_am29lv160_read,
469  .write =        rtems_am29lv160_write,
470  .blank =        rtems_am29lv160_blank,
471  .verify =       rtems_am29lv160_verify,
472  .erase =        rtems_am29lv160_erase,
473  .erase_device = rtems_am29lv160_erase_device
474};
Note: See TracBrowser for help on using the repository browser.