OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [flash/] [amd/] [am29xxxxxv2/] [current/] [src/] [am29xxxxx_aux.c] - Blame information for rev 838

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      am29xxxxx_aux.c
4
//
5
//      Flash driver for the AMD family - implementation. 
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    bartv
43
// Contributors:
44
// Date:         2004-11-05
45
//              
46
//####DESCRIPTIONEND####
47
//
48
//==========================================================================
49
 
50
// This file is #include'd multiple times from the main am29xxxxx.c file,
51
// It serves to instantiate the various hardware operations in ways
52
// appropriate for all the bus configurations.
53
 
54
// The following macros are used to construct suitable function names
55
// for the current bus configuration. AM29_SUFFIX is #define'd before
56
// each #include of am29xxxxx_aux.c
57
 
58
#ifndef AM29_STR
59
# define AM29_STR1(_a_) # _a_
60
# define AM29_STR(_a_) AM29_STR1(_a_)
61
# define AM29_CONCAT3_AUX(_a_, _b_, _c_) _a_##_b_##_c_
62
# define AM29_CONCAT3(_a_, _b_, _c_) AM29_CONCAT3_AUX(_a_, _b_, _c_)
63
#endif
64
 
65
#define AM29_FNNAME(_base_) AM29_CONCAT3(_base_, _,  AM29_SUFFIX)
66
 
67
// Similarly construct a forward declaration, placing the function in
68
// the .2ram section. Each function must still be in a separate section
69
// for linker garbage collection.
70
 
71
# define AM29_RAMFNDECL(_base_, _args_) \
72
  AM29_FNNAME(_base_) _args_ __attribute__((section (".2ram." AM29_STR(_base_) "_" AM29_STR(AM29_SUFFIX))))
73
 
74
// Calculate the various offsets, based on the device count.
75
// The main code may override these settings for specific
76
// configurations, e.g. 16as8
77
#ifndef AM29_OFFSET_COMMAND
78
# define AM29_OFFSET_COMMAND            0x0555
79
#endif
80
#ifndef AM29_OFFSET_COMMAND2
81
# define AM29_OFFSET_COMMAND2           0x02AA
82
#endif
83
#ifndef AM29_OFFSET_MANUFACTURER_ID
84
# define AM29_OFFSET_MANUFACTURER_ID    0x0000
85
#endif
86
#ifndef AM29_OFFSET_DEVID
87
# define AM29_OFFSET_DEVID              0x0001
88
#endif
89
#ifndef AM29_OFFSET_DEVID2
90
# define AM29_OFFSET_DEVID2             0x000E
91
#endif
92
#ifndef AM29_OFFSET_DEVID3
93
# define AM29_OFFSET_DEVID3             0x000F
94
#endif
95
#ifndef AM29_OFFSET_CFI
96
# define AM29_OFFSET_CFI                0x0055
97
#endif
98
#ifndef AM29_OFFSET_CFI_DATA
99
# define AM29_OFFSET_CFI_DATA(_idx_)    _idx_
100
#endif
101
#ifndef AM29_OFFSET_AT49_LOCK_STATUS
102
# define AM29_OFFSET_AT49_LOCK_STATUS   0x02
103
#endif
104
 
105
// For parallel operation commands are issued in parallel and status
106
// bits are checked in parallel.
107
#ifndef AM29_PARALLEL
108
# define AM29_PARALLEL(_cmd_)    (_cmd_)
109
#endif
110
 
111
// ----------------------------------------------------------------------------
112
// Diagnostic routines.
113
 
114
#if 0
115
#define amd_diag( __fmt, ... ) diag_printf("AMD: %s[%d]: " __fmt, __FUNCTION__, __LINE__, ## __VA_ARGS__ );
116
#define amd_dump_buf( __addr, __size ) diag_dump_buf( __addr, __size )
117
#else
118
#define amd_diag( __fmt, ... )
119
#define amd_dump_buf( __addr, __size )
120
#endif
121
 
122
// ----------------------------------------------------------------------------
123
// When performing the various low-level operations like erase the flash
124
// chip can no longer support ordinary data reads. Obviously this is a
125
// problem if the current code is executing out of flash. The solution is
126
// to store the key functions in RAM rather than flash, via a special
127
// linker section .2ram which usually gets placed in the same area as
128
// .data.
129
//
130
// In a ROM startup application anything in .2ram will consume space
131
// in both the flash and RAM. Hence it is desirable to keep the .2ram
132
// functions as small as possible, responsible only for the actual
133
// hardware manipulation.
134
//
135
// All these .2ram functions should be invoked with interrupts
136
// disabled. Depending on the hardware it may also be necessary to
137
// have the data cache disabled. The .2ram functions must be
138
// self-contained, even macro invocations like HAL_DELAY_US() are
139
// banned because on some platforms those could be implemented as
140
// function calls.
141
 
142
// gcc requires forward declarations with the attributes, then the actual
143
// definitions.
144
static int  AM29_RAMFNDECL(am29_hw_query, (volatile AM29_TYPE*));
145
static int  AM29_RAMFNDECL(am29_hw_cfi, (struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*));
146
static int  AM29_RAMFNDECL(am29_hw_erase, (volatile AM29_TYPE*));
147
static int  AM29_RAMFNDECL(am29_hw_program, (volatile AM29_TYPE*, volatile AM29_TYPE*, const cyg_uint8*, cyg_uint32 count, int retries));
148
static int  AM29_RAMFNDECL(at49_hw_softlock,        (volatile AM29_TYPE*));
149
static int  AM29_RAMFNDECL(at49_hw_hardlock,        (volatile AM29_TYPE*));
150
static int  AM29_RAMFNDECL(at49_hw_unlock,          (volatile AM29_TYPE*));
151
 
152
 
153
// ----------------------------------------------------------------------------
154
 
155
#ifdef CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_RESET_NEEDS_RESUME
156
// With this flash component (e.g. AT49xxxxx), the reset does not
157
// cause a suspended erase/program to be aborted. Instead all we
158
// can do is resume any suspended operations. We do this on each
159
// block as some parts have different granularity.
160
 
161
static void
162
AM29_FNNAME(am29_hw_force_all_suspended_resume)(struct cyg_flash_dev* dev, cyg_am29xxxxx_dev* am29_dev, volatile AM29_TYPE* addr)
163
{
164
    cyg_ucount16 i,j;
165
    AM29_TYPE datum1, datum2;
166
 
167
    AM29_2RAM_ENTRY_HOOK();
168
 
169
    for (i=0; i<dev->num_block_infos; i++)
170
    {
171
        for (j=0; j<am29_dev->block_info[i].blocks; j++)
172
        {
173
            addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_ERASE_RESUME;
174
            HAL_MEMORY_BARRIER();
175
            // We don't know if the suspended operation was an erase or
176
            // program, so just compare the whole word to spot _any_ toggling.
177
            do {
178
                datum1  = addr[AM29_OFFSET_COMMAND];
179
                datum2  = addr[AM29_OFFSET_COMMAND];
180
            } while (datum1 != datum2);
181
 
182
            addr += am29_dev->block_info[i].block_size/sizeof(AM29_TYPE);
183
        }
184
    }
185
 
186
    AM29_2RAM_EXIT_HOOK();
187
}
188
#endif // ifdef CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_RESET_NEEDS_RESUME
189
 
190
// Read the device id. This involves a straightforward command
191
// sequence, followed by a reset to get back into array mode.
192
// All chips are accessed in parallel, but only the response
193
// from the least significant is used.
194
static int
195
AM29_FNNAME(am29_hw_query)(volatile AM29_TYPE* addr)
196
{
197
    int devid;
198
    cyg_uint32 onedevmask;
199
 
200
    AM29_2RAM_ENTRY_HOOK();
201
 
202
    // Fortunately the compiler should optimise the below
203
    // tests such that onedevmask is a constant.
204
    if ( 1 == (sizeof(AM29_TYPE) / AM29_DEVCOUNT) )
205
        onedevmask = 0xFF;
206
    else if ( 2 == (sizeof(AM29_TYPE) / AM29_DEVCOUNT) )
207
        onedevmask = 0xFFFF;
208
    else {
209
        CYG_ASSERT( 4 == (sizeof(AM29_TYPE) / AM29_DEVCOUNT),
210
                    "Unexpected flash width per device" );
211
        onedevmask = 0xFFFFFFFF;
212
    }
213
 
214
    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_SETUP1;
215
    HAL_MEMORY_BARRIER();
216
    addr[AM29_OFFSET_COMMAND2]  = AM29_COMMAND_SETUP2;
217
    HAL_MEMORY_BARRIER();
218
    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_AUTOSELECT;
219
    HAL_MEMORY_BARRIER();
220
 
221
    devid                       = AM29_UNSWAP(addr[AM29_OFFSET_DEVID]) & onedevmask;
222
 
223
//    amd_diag("devid %x\n", devid );
224
//    amd_dump_buf(addr, 64 );
225
 
226
    // The original AMD chips only used a single-byte device id, but
227
    // all codes have now been used up. Newer devices use a 3-byte
228
    // devid. The above devid read will have returned 0x007E. The
229
    // test allows for boards with a mixture of old and new chips.
230
    // The amount of code involved is too small to warrant a config
231
    // option.
232
    // FIXME by jifl: What happens when a single device is connected 16-bits
233
    // (or 32-bits) wide per device? Is the code still 0x7E, and all the
234
    // other devids are 8-bits only?
235
    if (0x007E == devid) {
236
        devid <<= 16;
237
        devid  |= ((AM29_UNSWAP(addr[AM29_OFFSET_DEVID2]) & 0x00FF) << 8);
238
        devid  |=  (AM29_UNSWAP(addr[AM29_OFFSET_DEVID3]) & 0x00FF);
239
    }
240
    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_RESET;
241
    HAL_MEMORY_BARRIER();
242
 
243
//    amd_diag("devid %x\n", devid );
244
 
245
    AM29_2RAM_EXIT_HOOK();
246
    return devid;
247
}
248
 
249
// Perform a CFI query. This involves placing the device(s) into CFI
250
// mode, checking that this has really happened, and then reading the
251
// size and block info. The address corresponds to the start of the
252
// flash.
253
static int
254
AM29_FNNAME(am29_hw_cfi)(struct cyg_flash_dev* dev, cyg_am29xxxxx_dev* am29_dev, volatile AM29_TYPE* addr)
255
{
256
    int     dev_size;
257
    int     i;
258
    int     erase_regions;
259
 
260
    AM29_2RAM_ENTRY_HOOK();
261
 
262
#ifdef CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CFI_BOGOSITY
263
    int     manufacturer_id;
264
    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_SETUP1;
265
    HAL_MEMORY_BARRIER();
266
    addr[AM29_OFFSET_COMMAND2]  = AM29_COMMAND_SETUP2;
267
    HAL_MEMORY_BARRIER();
268
    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_AUTOSELECT;
269
    HAL_MEMORY_BARRIER();
270
 
271
    manufacturer_id             = AM29_UNSWAP(addr[AM29_OFFSET_MANUFACTURER_ID]) & 0x00FF;
272
    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_RESET;
273
    HAL_MEMORY_BARRIER();
274
#endif
275
 
276
    // Just a single write is needed to put the device into CFI mode
277
    addr[AM29_OFFSET_CFI]   = AM29_COMMAND_CFI;
278
    HAL_MEMORY_BARRIER();
279
//    amd_diag("CFI data:\n");
280
//    amd_dump_buf( addr, 256 );
281
    // Now check that we really are in CFI mode. There should be a 'Q'
282
    // at a specific address. This test is not 100% reliable, but should
283
    // be good enough.
284
    if ('Q' != (AM29_UNSWAP(addr[AM29_OFFSET_CFI_Q]) & 0x00FF)) {
285
        addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_RESET;
286
        HAL_MEMORY_BARRIER();
287
        AM29_2RAM_EXIT_HOOK();
288
        return CYG_FLASH_ERR_PROTOCOL;
289
    }
290
    // Device sizes are always a power of 2, and the shift is encoded
291
    // in a single byte
292
    dev_size = 0x01 << (AM29_UNSWAP(addr[AM29_OFFSET_CFI_SIZE]) & 0x00FF);
293
    dev->end = dev->start + dev_size - 1;
294
 
295
    // The number of erase regions is also encoded in a single byte.
296
    // Usually this is no more than 4. A value of 0 indicates that
297
    // only chip erase is supported, but the driver does not cope
298
    // with that.
299
    erase_regions   = AM29_UNSWAP(addr[AM29_OFFSET_CFI_BLOCK_REGIONS]) & 0x00FF;
300
    if (erase_regions > CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_REGIONS) {
301
        addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_RESET;
302
        HAL_MEMORY_BARRIER();
303
        AM29_2RAM_EXIT_HOOK();
304
        return CYG_FLASH_ERR_PROTOCOL;
305
    }
306
    dev->num_block_infos    = erase_regions;
307
 
308
    for (i = 0; i < erase_regions; i++) {
309
        cyg_uint32 count, size;
310
        cyg_uint32 count_lsb   = AM29_UNSWAP(addr[AM29_OFFSET_CFI_BLOCK_COUNT_LSB(i)]) & 0x00FF;
311
        cyg_uint32 count_msb   = AM29_UNSWAP(addr[AM29_OFFSET_CFI_BLOCK_COUNT_MSB(i)]) & 0x00FF;
312
        cyg_uint32 size_lsb    = AM29_UNSWAP(addr[AM29_OFFSET_CFI_BLOCK_SIZE_LSB(i)]) & 0x00FF;
313
        cyg_uint32 size_msb    = AM29_UNSWAP(addr[AM29_OFFSET_CFI_BLOCK_SIZE_MSB(i)]) & 0x00FF;
314
 
315
        count = ((count_msb << 8) | count_lsb) + 1;
316
        size  = (size_msb << 16) | (size_lsb << 8);
317
        am29_dev->block_info[i].block_size  = (size_t) size * AM29_DEVCOUNT;
318
        am29_dev->block_info[i].blocks      = count;
319
    }
320
 
321
#ifdef CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_CFI_BOGOSITY
322
 
323
    // Some flash parts have a peculiar implementation of CFI. The
324
    // device erase regions may not be in the order specified in the
325
    // main CFI area. Instead the erase regions are given in a
326
    // manufacturer dependent fixed order, regardless of whether this
327
    // is a top or bottom boot block device. A vendor-specific
328
    // extended query block has an entry saying whether the boot
329
    // blocks are at the top or bottom. This code works out whether
330
    // the erase regions appear to be specified in the wrong order,
331
    // and then swaps them over.
332
 
333
    {
334
        enum { bottom, symmetric, top } boot_type = symmetric;
335
        cyg_uint32 vspec = AM29_SWAP(addr[AM29_OFFSET_CFI_DATA(0x15)]) & 0x00FF;
336
 
337
        // Take a look at the vendor specific area for the boot block
338
        // order.
339
 
340
        switch( manufacturer_id )
341
        {
342
            // Atmel appear to have their own layout for the vendor
343
            // specific area. Offset 0x06 of the vendor specific area
344
            // contains a single bit: 0x00 = top boot, 0x01 = bottom
345
            // boot. There appears to be no way of specifying
346
            // symmetric formats.
347
        case 0x1F:
348
            if( (addr[AM29_OFFSET_CFI_DATA(vspec+0x06)] & AM29_SWAP(0x1)) == AM29_SWAP(0x1) )
349
                boot_type = bottom;
350
            else boot_type = top;
351
            break;
352
 
353
            // Most other manufacturers seem to follow the same layout
354
            // and encoding. Offset 0xF of the vendor specific area
355
            // contains the boot sector layout: 0x00 = uniform, 0x01 =
356
            // 8x8k top and bottom, 0x02 = bottom boot, 0x03 = top
357
            // boot, 0x04 = both top and bottom.
358
            //
359
            // The following manufacturers support this layout:
360
            // AMD, Spansion, ST, Macronix.
361
        default:
362
            if( (addr[AM29_OFFSET_CFI_DATA(vspec+0xF)] == AM29_SWAP(0x2)) )
363
                boot_type = bottom;
364
            else if( (addr[AM29_OFFSET_CFI_DATA(vspec+0xF)] == AM29_SWAP(0x3)) )
365
                boot_type = top;
366
            // All other options are symmetric
367
            break;
368
        }
369
 
370
        // If the device is marked as top boot, but the erase region
371
        // list appears to be in bottom boot order, then reverse the
372
        // list. Also swap, if it is marked as bottom boot but the
373
        // erase regions appear to be in top boot order. This code
374
        // assumes that the first boot block is always smaller than
375
        // regular blocks; it is possible to imagine flash layouts for
376
        // which that is not true.
377
 
378
        if( ((boot_type == top) &&
379
             (am29_dev->block_info[0].block_size < am29_dev->block_info[erase_regions-1].block_size)) ||
380
            ((boot_type == bottom) &&
381
             (am29_dev->block_info[0].block_size > am29_dev->block_info[erase_regions-1].block_size)))
382
        {
383
            int lo, hi;
384
 
385
            for( lo = 0, hi = erase_regions-1 ; lo < hi ; lo++, hi-- )
386
            {
387
                size_t size                          = am29_dev->block_info[lo].block_size;
388
                cyg_uint32 count                     = am29_dev->block_info[lo].blocks;
389
                am29_dev->block_info[lo].block_size  = am29_dev->block_info[hi].block_size;
390
                am29_dev->block_info[lo].blocks      = am29_dev->block_info[hi].blocks;
391
                am29_dev->block_info[hi].block_size  = size;
392
                am29_dev->block_info[hi].blocks      = count;
393
            }
394
        }
395
    }
396
#endif
397
 
398
    // Get out of CFI mode
399
    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_RESET;
400
    HAL_MEMORY_BARRIER();
401
 
402
    AM29_2RAM_EXIT_HOOK();
403
    return CYG_FLASH_ERR_OK;
404
}
405
 
406
// Erase a single sector. There is no API support for chip-erase. The
407
// generic code operates one sector at a time, invoking the driver for
408
// each sector, so there is no opportunity inside the driver for
409
// erasing multiple sectors in a single call. The address argument
410
// points at the start of the sector.
411
static int
412
AM29_FNNAME(am29_hw_erase)(volatile AM29_TYPE* addr)
413
{
414
    int         retries;
415
    AM29_TYPE   datum;
416
 
417
    AM29_2RAM_ENTRY_HOOK();
418
 
419
    // Start the erase operation
420
    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_SETUP1;
421
    HAL_MEMORY_BARRIER();
422
    addr[AM29_OFFSET_COMMAND2]  = AM29_COMMAND_SETUP2;
423
    HAL_MEMORY_BARRIER();
424
    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_ERASE;
425
    HAL_MEMORY_BARRIER();
426
    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_SETUP1;
427
    HAL_MEMORY_BARRIER();
428
    addr[AM29_OFFSET_COMMAND2]  = AM29_COMMAND_SETUP2;
429
    HAL_MEMORY_BARRIER();
430
    addr[AM29_OFFSET_COMMAND]   = AM29_COMMAND_ERASE_SECTOR;
431
    HAL_MEMORY_BARRIER();
432
    // There is now a 50us window in which we could send additional
433
    // ERASE_SECTOR commands, but the driver API does not allow this
434
 
435
    // All chips are now erasing in parallel. Loop until all have
436
    // completed. This can be detected in a number of ways. The DQ7
437
    // bit will be 0 until the erase is complete, but there is a
438
    // problem if something went wrong (e.g. the sector is locked),
439
    // the erase has not actually started, and the relevant bit was 0
440
    // already. More useful is DQ6. This will toggle during the 50us
441
    // window and while the erase is in progress, then stop toggling.
442
    // If the erase does not actually start then the bit won't toggle
443
    // at all so the operation completes rather quickly.
444
    //
445
    // If at any time DQ5 is set (indicating a timeout inside the
446
    // chip) then a reset command must be issued and the erase is
447
    // aborted. It is not clear this can actually happen during an
448
    // erase, but just in case.
449
    for (retries = CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_ERASE_TIMEOUT;
450
         retries > 0;
451
         retries--) {
452
 
453
        datum  = addr[AM29_OFFSET_COMMAND];
454
        // The operation completes when all DQ7 bits are set.
455
        if ((datum & AM29_STATUS_DQ7) == AM29_STATUS_DQ7) {
456
            break;
457
        }
458
        // Otherwise, for any flash chips where DQ7 is still clear, it is
459
        // necessary to test DQ5.
460
        if (((datum ^ AM29_STATUS_DQ7) >> 2) & datum & AM29_STATUS_DQ5) {
461
            // DQ5 is set, indicating a hardware error. The calling code
462
            // will always verify that the erase really was successful
463
            // so we do not need to distinguish between error conditions.
464
            addr[AM29_OFFSET_COMMAND] = AM29_COMMAND_RESET;
465
            HAL_MEMORY_BARRIER();
466
            break;
467
        }
468
    }
469
 
470
    // A result of 0 indicates a timeout.
471
    // A non-zero result indicates
472
    // that the erase completed or there has been a fatal error.
473
    AM29_2RAM_EXIT_HOOK();
474
    return retries;
475
}
476
 
477
// Write data to flash. At most one block will be processed at a time,
478
// but the write may be for a subset of the write. The destination
479
// address will be aligned in a way suitable for the bus. The source
480
// address need not be aligned. The count is in AM29_TYPE's, i.e.
481
// as per the bus alignment, not in bytes.
482
static int
483
AM29_FNNAME(am29_hw_program)(volatile AM29_TYPE* block_start, volatile AM29_TYPE* addr, const cyg_uint8* buf, cyg_uint32 count, int retries)
484
{
485
    int     i;
486
 
487
    AM29_2RAM_ENTRY_HOOK();
488
 
489
    for (i = 0; (i < count) && (retries > 0); i++) {
490
        AM29_TYPE   datum, current, active_dq7s;
491
 
492
        // We can only clear bits, not set them, so any bits that were
493
        // already clear need to be preserved.
494
        current = addr[i];
495
        datum   = AM29_NEXT_DATUM(buf) & current;
496
        if (datum == current) {
497
            // No change, so just move on.
498
            continue;
499
        }
500
 
501
        block_start[AM29_OFFSET_COMMAND]    = AM29_COMMAND_SETUP1;
502
        HAL_MEMORY_BARRIER();
503
        block_start[AM29_OFFSET_COMMAND2]   = AM29_COMMAND_SETUP2;
504
        HAL_MEMORY_BARRIER();
505
        block_start[AM29_OFFSET_COMMAND]    = AM29_COMMAND_PROGRAM;
506
        HAL_MEMORY_BARRIER();
507
        addr[i] = datum;
508
        HAL_MEMORY_BARRIER();
509
 
510
        // The data is now being written. The official algorithm is
511
        // to poll either DQ7 or DQ6, checking DQ5 along the way for
512
        // error conditions. This gets complicated with parallel
513
        // flash chips because they may finish at different times.
514
        // The alternative approach is to ignore the status bits
515
        // completely and just look for current==datum until the
516
        // retry count is exceeded. However that does not cope
517
        // cleanly with cases where the flash chip reports an error
518
        // early on, e.g. because a flash block is locked.
519
 
520
        while (--retries > 0) {
521
#if CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_PROGRAM_DELAY > 0
522
            // Some chips want a delay between polling
523
            { int j; for( j = 0; j < CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_PROGRAM_DELAY; j++ ); }
524
#endif
525
            // While the program operation is in progress DQ7 will read
526
            // back inverted from datum.
527
            current = addr[i];
528
            if ((current & AM29_STATUS_DQ7) == (datum & AM29_STATUS_DQ7)) {
529
                // All DQ7 bits now match datum, so the operation has completed.
530
                // But not necessarily successfully. On some chips DQ7 may
531
                // toggle before DQ0-6 are valid, so we need to read the
532
                // data one more time.
533
                current = addr[i];
534
                if (current != datum) {
535
                    retries = 0;    // Abort this burst.
536
                }
537
                break;
538
            }
539
 
540
            // Now we want to check the DQ5 status bits, but only for those
541
            // chips which are still programming. ((current^datum) & DQ7) gives
542
            // ones for chips which are still programming, zeroes for chips when
543
            // the programming is complete.
544
            active_dq7s = (current ^ datum) & AM29_STATUS_DQ7;
545
 
546
            if (0 != (current & (active_dq7s >> 2))) {
547
                // Unfortunately this is not sufficient to prove an error. On
548
                // some chips DQ0-6 switch to the data while DQ7 is still a
549
                // status flag, so the set DQ5 bit detected above may be data
550
                // instead of an error. Check again, this time DQ7 may
551
                // indicate completion.
552
                //
553
                // Next problem. Suppose chip A gave a bogus DQ5 result earlier
554
                // because it was just finishing. For this read chip A gives
555
                // back datum, but now chip B is finishing and has reported a
556
                // bogus DQ5.
557
                //
558
                // Solution: if any of the DQ7 lines have changed since the last
559
                // time, go around the loop again. When an error occurs DQ5
560
                // remains set and DQ7 remains toggled, so there is no harm
561
                // in one more polling loop.
562
 
563
                current = addr[i];
564
                if (((current ^ datum) & AM29_STATUS_DQ7) != active_dq7s) {
565
                    continue;
566
                }
567
 
568
                // DQ5 has been set in a chip where DQ7 indicates an ongoing
569
                // program operation for two successive reads. That is an error.
570
                // The hardware is in a strange state so must be reset.
571
                block_start[AM29_OFFSET_COMMAND]    = AM29_COMMAND_RESET;
572
                HAL_MEMORY_BARRIER();
573
                retries = 0;
574
                break;
575
            }
576
            // No DQ5 bits set in chips which are still programming. Poll again.
577
        }   // Retry for current word
578
    }       // Next word
579
 
580
    // At this point retries holds the total number of retries left.
581
    //  0 indicates a timeout or fatal error.
582
    // >0 indicates success.
583
    AM29_2RAM_EXIT_HOOK();
584
    return retries;
585
}
586
 
587
// FIXME: implement a separate program routine for buffered writes. 
588
 
589
#if 0
590
// Unused for now, but might be useful later
591
static int
592
AM29_FNNAME(at49_hw_is_locked)(volatile AM29_TYPE* addr)
593
{
594
    int result;
595
    AM29_TYPE plane;
596
 
597
    AM29_2RAM_ENTRY_HOOK();
598
 
599
    // Plane is bits A21-A20 for AT49BV6416
600
    // A more generic formula is needed.
601
    plane = AM29_PARALLEL( ((((CYG_ADDRESS)addr)>>21) & 0x3) );
602
    addr[AM29_OFFSET_COMMAND]         = AM29_COMMAND_SETUP1;
603
    HAL_MEMORY_BARRIER();
604
    addr[AM29_OFFSET_COMMAND2]        = AM29_COMMAND_SETUP2;
605
    HAL_MEMORY_BARRIER();
606
    addr[AM29_OFFSET_COMMAND + plane] = AM29_COMMAND_AUTOSELECT;
607
    HAL_MEMORY_BARRIER();
608
    result          = addr[AM29_OFFSET_AT49_LOCK_STATUS];
609
    addr[0]         = AM29_COMMAND_RESET;
610
    HAL_MEMORY_BARRIER();
611
    // The bottom two bits hold the lock status, LSB indicates
612
    // soft lock, next bit indicates hard lock. We don't distinguish
613
    // in this function.
614
    AM29_2RAM_EXIT_HOOK();
615
    return (0 != (result & AM29_ID_LOCKED));
616
}
617
#endif
618
 
619
static int
620
AM29_FNNAME(at49_hw_softlock)(volatile AM29_TYPE* addr)
621
{
622
    int result  = CYG_FLASH_ERR_OK;
623
 
624
    AM29_2RAM_ENTRY_HOOK();
625
 
626
    addr[AM29_OFFSET_COMMAND]         = AM29_COMMAND_SETUP1;
627
    HAL_MEMORY_BARRIER();
628
    addr[AM29_OFFSET_COMMAND2]        = AM29_COMMAND_SETUP2;
629
    HAL_MEMORY_BARRIER();
630
    addr[AM29_OFFSET_COMMAND]         = AM29_COMMAND_AT49_SOFTLOCK_BLOCK_0;
631
    HAL_MEMORY_BARRIER();
632
    addr[AM29_OFFSET_COMMAND]         = AM29_COMMAND_SETUP1;
633
    HAL_MEMORY_BARRIER();
634
    addr[AM29_OFFSET_COMMAND2]        = AM29_COMMAND_SETUP2;
635
    HAL_MEMORY_BARRIER();
636
    addr[0]                           = AM29_COMMAND_AT49_SOFTLOCK_BLOCK_1;
637
    HAL_MEMORY_BARRIER();
638
    // not sure if this is required:
639
    addr[0]                           = AM29_COMMAND_RESET;
640
    HAL_MEMORY_BARRIER();
641
    AM29_2RAM_EXIT_HOOK();
642
    return result;
643
}
644
 
645
static int
646
AM29_FNNAME(at49_hw_hardlock)(volatile AM29_TYPE* addr)
647
{
648
    int result  = CYG_FLASH_ERR_OK;
649
 
650
    AM29_2RAM_ENTRY_HOOK();
651
 
652
    addr[AM29_OFFSET_COMMAND]         = AM29_COMMAND_SETUP1;
653
    HAL_MEMORY_BARRIER();
654
    addr[AM29_OFFSET_COMMAND2]        = AM29_COMMAND_SETUP2;
655
    HAL_MEMORY_BARRIER();
656
    addr[AM29_OFFSET_COMMAND]         = AM29_COMMAND_AT49_HARDLOCK_BLOCK_0;
657
    HAL_MEMORY_BARRIER();
658
    addr[AM29_OFFSET_COMMAND]         = AM29_COMMAND_SETUP1;
659
    HAL_MEMORY_BARRIER();
660
    addr[AM29_OFFSET_COMMAND2]        = AM29_COMMAND_SETUP2;
661
    HAL_MEMORY_BARRIER();
662
    addr[0]                           = AM29_COMMAND_AT49_HARDLOCK_BLOCK_1;
663
    HAL_MEMORY_BARRIER();
664
    // not sure if this is required:
665
    addr[0]                           = AM29_COMMAND_RESET;
666
    HAL_MEMORY_BARRIER();
667
    AM29_2RAM_EXIT_HOOK();
668
    return result;
669
}
670
 
671
static int
672
AM29_FNNAME(at49_hw_unlock)(volatile AM29_TYPE* addr)
673
{
674
    int result  = CYG_FLASH_ERR_OK;
675
 
676
    AM29_2RAM_ENTRY_HOOK();
677
 
678
    addr[AM29_OFFSET_COMMAND]         = AM29_COMMAND_SETUP1;
679
    HAL_MEMORY_BARRIER();
680
    addr[0]                           = AM29_COMMAND_AT49_UNLOCK_BLOCK;
681
    HAL_MEMORY_BARRIER();
682
    // not sure if this is required:
683
    addr[0]                           = AM29_COMMAND_RESET;
684
    HAL_MEMORY_BARRIER();
685
    AM29_2RAM_EXIT_HOOK();
686
    return result;
687
}
688
 
689
 
690
// ----------------------------------------------------------------------------
691
// Exported code, mostly for placing in a cyg_flash_dev_funs structure.
692
 
693
// Just read the device id, either for sanity checking that the system
694
// has been configured for the right device, or for filling in the
695
// block info by a platform-specific init routine if the platform may
696
// be manufactured with one of several different chips.
697
int
698
AM29_FNNAME(cyg_am29xxxxx_read_devid) (struct cyg_flash_dev* dev)
699
{
700
    int                 (*query_fn)(volatile AM29_TYPE*);
701
    int                 devid;
702
    volatile AM29_TYPE* addr;
703
    AM29_INTSCACHE_STATE;
704
 
705
    CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
706
 
707
    amd_diag("\n");
708
 
709
    addr     = AM29_UNCACHED_ADDRESS(dev->start);
710
    query_fn = (int (*)(volatile AM29_TYPE*)) cyg_flash_anonymizer( & AM29_FNNAME(am29_hw_query) );
711
    AM29_INTSCACHE_BEGIN();
712
    devid    = (*query_fn)(addr);
713
    AM29_INTSCACHE_END();
714
    return devid;
715
}
716
 
717
// Validate that the device statically configured is the one on the
718
// board.
719
int
720
AM29_FNNAME(cyg_am29xxxxx_init_check_devid)(struct cyg_flash_dev* dev)
721
{
722
    cyg_am29xxxxx_dev*  am29_dev;
723
    int                 devid;
724
 
725
    amd_diag("\n");
726
 
727
    am29_dev = (cyg_am29xxxxx_dev*) dev->priv;
728
    devid    = AM29_FNNAME(cyg_am29xxxxx_read_devid)(dev);
729
    if (devid != am29_dev->devid) {
730
        return CYG_FLASH_ERR_DRV_WRONG_PART;
731
    }
732
 
733
#ifdef CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_RESET_NEEDS_RESUME
734
    {
735
        volatile AM29_TYPE *addr = AM29_UNCACHED_ADDRESS(dev->start);
736
        void (*resume_fn)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*);
737
        resume_fn = (void (*)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*))
738
            cyg_flash_anonymizer( &AM29_FNNAME(am29_hw_force_all_suspended_resume) );
739
        AM29_INTSCACHE_STATE;
740
 
741
        AM29_INTSCACHE_BEGIN();
742
        (*resume_fn)(dev, am29_dev, addr);
743
        AM29_INTSCACHE_END();
744
    }
745
#endif
746
 
747
    // Successfully queried the device, and the id's match. That
748
    // should be a good enough indication that the flash is working.
749
    return CYG_FLASH_ERR_OK;
750
}
751
 
752
// Initialize via a CFI query, instead of statically specifying the
753
// boot block layout.
754
int
755
AM29_FNNAME(cyg_am29xxxxx_init_cfi)(struct cyg_flash_dev* dev)
756
{
757
    int                 (*cfi_fn)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*);
758
    volatile AM29_TYPE* addr;
759
    cyg_am29xxxxx_dev*  am29_dev;
760
    int                 result;
761
    AM29_INTSCACHE_STATE;
762
 
763
    amd_diag("\n");
764
 
765
    CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
766
    am29_dev    = (cyg_am29xxxxx_dev*) dev->priv;    // Remove const, only place where this is needed.
767
    addr        = AM29_UNCACHED_ADDRESS(dev->start);
768
    cfi_fn      = (int (*)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*))
769
        cyg_flash_anonymizer( & AM29_FNNAME(am29_hw_cfi));
770
 
771
    AM29_INTSCACHE_BEGIN();
772
    result      = (*cfi_fn)(dev, am29_dev, addr);
773
    AM29_INTSCACHE_END();
774
 
775
    // Now calculate the device size, and hence the end field.
776
    if (CYG_FLASH_ERR_OK == result) {
777
        int i;
778
        int size    = 0;
779
        for (i = 0; i < dev->num_block_infos; i++) {
780
            amd_diag("region %d: 0x%08x * %d\n", i, (int)dev->block_info[i].block_size, dev->block_info[i].blocks );
781
            size += (dev->block_info[i].block_size * dev->block_info[i].blocks);
782
        }
783
        dev->end = dev->start + size - 1;
784
 
785
#ifdef CYGHWR_DEVS_FLASH_AMD_AM29XXXXX_V2_RESET_NEEDS_RESUME
786
    {
787
        void (*resume_fn)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*);
788
        resume_fn = (void (*)(struct cyg_flash_dev*, cyg_am29xxxxx_dev*, volatile AM29_TYPE*))
789
            cyg_flash_anonymizer( &AM29_FNNAME(am29_hw_force_all_suspended_resume) );
790
 
791
        AM29_INTSCACHE_BEGIN();
792
        (*resume_fn)(dev, am29_dev, addr);
793
        AM29_INTSCACHE_END();
794
    }
795
#endif
796
    }
797
    return result;
798
}
799
 
800
// Erase a single block. The calling code will have supplied a pointer
801
// aligned to a block boundary.
802
int
803
AM29_FNNAME(cyg_am29xxxxx_erase)(struct cyg_flash_dev* dev, cyg_flashaddr_t addr)
804
{
805
    int                 (*erase_fn)(volatile AM29_TYPE*);
806
    volatile AM29_TYPE* block;
807
    cyg_flashaddr_t     block_start;
808
    size_t              block_size;
809
    int                 i;
810
    int                 result;
811
    AM29_INTSCACHE_STATE;
812
 
813
    CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
814
    CYG_ASSERT((addr >= dev->start) && (addr <= dev->end), "flash address out of device range");
815
 
816
    am29_get_block_info(dev, addr, &block_start, &block_size);
817
    CYG_ASSERT(addr == block_start, "erase address should be the start of a flash block");
818
 
819
    amd_diag("addr %p block %p[%d]\n", (void*)addr, (void*)block_start, (int)block_size );
820
 
821
    block       = AM29_UNCACHED_ADDRESS(addr);
822
    erase_fn    = (int (*)(volatile AM29_TYPE*)) cyg_flash_anonymizer( & AM29_FNNAME(am29_hw_erase) );
823
 
824
    AM29_INTSCACHE_BEGIN();
825
    result = (*erase_fn)(block);
826
    AM29_INTSCACHE_END();
827
 
828
    // The erase may have failed for a number of reasons, e.g. because
829
    // of a locked sector. The best thing to do here is to check that the
830
    // erase has succeeded.
831
    block = (AM29_TYPE*) addr;
832
    for (i = 0; i < (block_size / sizeof(AM29_TYPE)); i++) {
833
        if (block[i] != (AM29_TYPE)~0) {
834
            // There is no easy way of detecting the specific error,
835
            // e.g. locked flash block, timeout, ... So return a
836
            // useless catch-all error.
837
            return CYG_FLASH_ERR_ERASE;
838
        }
839
    }
840
    return CYG_FLASH_ERR_OK;
841
}
842
 
843
// Write some data to the flash. The destination must be aligned
844
// appropriately for the bus width (not the device width).
845
int
846
AM29_FNNAME(cyg_am29xxxxx_program)(struct cyg_flash_dev* dev, cyg_flashaddr_t dest, const void* src, size_t len)
847
{
848
    int                 (*program_fn)(volatile AM29_TYPE*, volatile AM29_TYPE*, const cyg_uint8*, cyg_uint32, int);
849
    volatile AM29_TYPE* block;
850
    volatile AM29_TYPE* addr;
851
    cyg_flashaddr_t     block_start;
852
    size_t              block_size;
853
    const cyg_uint8*    data;
854
    int                 retries;
855
    int                 i;
856
 
857
    AM29_INTSCACHE_STATE;
858
 
859
    CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
860
 
861
    amd_diag("dest %p src %p len %d\n", (void*)dest, (void*)src, (int)len );
862
 
863
    // Only support writes that are aligned to the bus boundary. This
864
    // may be more restrictive than what the hardware is capable of.
865
    // However it ensures that the hw_program routine can write as
866
    // much data as possible each iteration, and hence significantly
867
    // improves performance. The length had better be a multiple of
868
    // the bus width as well
869
    if ((0 != ((CYG_ADDRWORD)dest & (sizeof(AM29_TYPE) - 1))) ||
870
        (0 != (len & (sizeof(AM29_TYPE) - 1)))) {
871
        return CYG_FLASH_ERR_INVALID;
872
    }
873
 
874
    addr        = AM29_UNCACHED_ADDRESS(dest);
875
    CYG_ASSERT((dest >= dev->start) && (dest <= dev->end), "flash address out of device range");
876
 
877
    am29_get_block_info(dev, dest, &block_start, &block_size);
878
    CYG_ASSERT(((dest - block_start) + len) <= block_size, "write cannot cross block boundary");
879
 
880
    block       = AM29_UNCACHED_ADDRESS(block_start);
881
    data        = (const cyg_uint8*) src;
882
    retries     = CYGNUM_DEVS_FLASH_AMD_AM29XXXXX_V2_PROGRAM_TIMEOUT;
883
 
884
    program_fn  = (int (*)(volatile AM29_TYPE*, volatile AM29_TYPE*, const cyg_uint8*, cyg_uint32, int))
885
        cyg_flash_anonymizer( & AM29_FNNAME(am29_hw_program) );
886
 
887
    AM29_INTSCACHE_BEGIN();
888
    (*program_fn)(block, addr, data, len / sizeof(AM29_TYPE), retries);
889
    AM29_INTSCACHE_END();
890
 
891
    // Too many things can go wrong when manipulating the h/w, so
892
    // verify the operation by actually checking the data.
893
    addr = (volatile AM29_TYPE*) dest;
894
    data = (const cyg_uint8*) src;
895
    for (i = 0; i < (len / sizeof(AM29_TYPE)); i++) {
896
        AM29_TYPE   datum   = AM29_NEXT_DATUM(data);
897
        AM29_TYPE   current = addr[i];
898
        if ((datum & current) != current) {
899
            amd_diag("data %p addr[i] %p datum %08x current %08x\n", data-sizeof(AM29_TYPE), &addr[i], datum, current );
900
            return CYG_FLASH_ERR_PROGRAM;
901
        }
902
    }
903
    return CYG_FLASH_ERR_OK;
904
}
905
 
906
int
907
AM29_FNNAME(cyg_at49xxxx_softlock)(struct cyg_flash_dev* dev, const cyg_flashaddr_t dest)
908
{
909
    volatile AM29_TYPE*   uncached;
910
    int                     result;
911
    int (*lock_fn)(volatile AM29_TYPE*);
912
    AM29_INTSCACHE_STATE;
913
 
914
    amd_diag("\n");
915
 
916
    CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
917
    CYG_ASSERT((dest >= (cyg_flashaddr_t)dev->start) &&
918
               ((CYG_ADDRESS)dest <= dev->end), "flash address out of device range");
919
 
920
    uncached    = AM29_UNCACHED_ADDRESS(dest);
921
    lock_fn     = (int (*)(volatile AM29_TYPE*)) cyg_flash_anonymizer( & AM29_FNNAME(at49_hw_softlock) );
922
    AM29_INTSCACHE_BEGIN();
923
    result  = (*lock_fn)(uncached);
924
    AM29_INTSCACHE_END();
925
    return result;
926
}
927
 
928
int
929
AM29_FNNAME(cyg_at49xxxx_hardlock)(struct cyg_flash_dev* dev, const cyg_flashaddr_t dest)
930
{
931
    volatile AM29_TYPE*   uncached;
932
    int                     result;
933
    int (*lock_fn)(volatile AM29_TYPE*);
934
    AM29_INTSCACHE_STATE;
935
 
936
    amd_diag("\n");
937
 
938
    CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
939
    CYG_ASSERT((dest >= (cyg_flashaddr_t)dev->start) &&
940
               ((CYG_ADDRESS)dest <= dev->end), "flash address out of device range");
941
 
942
    uncached    = AM29_UNCACHED_ADDRESS(dest);
943
    lock_fn     = (int (*)(volatile AM29_TYPE*)) cyg_flash_anonymizer( & AM29_FNNAME(at49_hw_hardlock) );
944
    AM29_INTSCACHE_BEGIN();
945
    result  = (*lock_fn)(uncached);
946
    AM29_INTSCACHE_END();
947
    return result;
948
}
949
 
950
int
951
AM29_FNNAME(cyg_at49xxxx_unlock)(struct cyg_flash_dev* dev, const cyg_flashaddr_t dest)
952
{
953
    volatile AM29_TYPE* uncached;
954
    int                 result;
955
    int (*unlock_fn)(volatile AM29_TYPE*);
956
    AM29_INTSCACHE_STATE;
957
 
958
    amd_diag("\n");
959
 
960
    CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
961
    CYG_ASSERT((dest >= (cyg_flashaddr_t)dev->start) &&
962
               ((CYG_ADDRESS)dest <= dev->end), "flash address out of device range");
963
 
964
    uncached = AM29_UNCACHED_ADDRESS(dest);
965
    unlock_fn = (int (*)(volatile AM29_TYPE*)) cyg_flash_anonymizer( & AM29_FNNAME(at49_hw_unlock) );
966
 
967
    AM29_INTSCACHE_BEGIN();
968
    result  = (*unlock_fn)(uncached);
969
    AM29_INTSCACHE_END();
970
    return result;
971
}
972
 
973
// ----------------------------------------------------------------------------
974
// Clean up the various #define's so this file can be #include'd again
975
#undef AM29_FNNAME
976
#undef AM29_RAMFNDECL
977
#undef AM29_OFFSET_COMMAND
978
#undef AM29_OFFSET_COMMAND2
979
#undef AM29_OFFSET_DEVID
980
#undef AM29_OFFSET_DEVID2
981
#undef AM29_OFFSET_DEVID3
982
#undef AM29_OFFSET_CFI
983
#undef AM29_OFFSET_CFI_DATA
984
#undef AM29_OFFSET_AT49_LOCK_STATUS
985
#undef AM29_PARALLEL

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.