]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/flash/sst/39vf400/v2_0/include/flash_sst_39vf400.inl
Initial revision
[karo-tx-redboot.git] / packages / devs / flash / sst / 39vf400 / v2_0 / include / flash_sst_39vf400.inl
1 #ifndef CYGONCE_DEVS_FLASH_SST_39VF400_INL
2 #define CYGONCE_DEVS_FLASH_SST_39VF400_INL
3 //==========================================================================
4 //
5 //      flash_sst_39vf4000.inl
6 //
7 //      SST SST39VF400 FLASH driver
8 //
9 //==========================================================================
10 //####ECOSGPLCOPYRIGHTBEGIN####
11 // -------------------------------------------
12 // This file is part of eCos, the Embedded Configurable Operating System.
13 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
14 // Copyright (C) 2002 Gary Thomas
15 //
16 // eCos is free software; you can redistribute it and/or modify it under
17 // the terms of the GNU General Public License as published by the Free
18 // Software Foundation; either version 2 or (at your option) any later version.
19 //
20 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
21 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23 // for more details.
24 //
25 // You should have received a copy of the GNU General Public License along
26 // with eCos; if not, write to the Free Software Foundation, Inc.,
27 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 //
29 // As a special exception, if other files instantiate templates or use macros
30 // or inline functions from this file, or you compile this file and link it
31 // with other works to produce a work based on this file, this file does not
32 // by itself cause the resulting work to be covered by the GNU General Public
33 // License. However the source code for this file must still be made available
34 // in accordance with section (3) of the GNU General Public License.
35 //
36 // This exception does not invalidate any other reasons why a work based on
37 // this file might be covered by the GNU General Public License.
38 //
39 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
40 // at http://sources.redhat.com/ecos/ecos-license/
41 // -------------------------------------------
42 //####ECOSGPLCOPYRIGHTEND####
43 //==========================================================================
44 //#####DESCRIPTIONBEGIN####
45 //
46 // Author(s):    Chris Garry <cgarry@sweeneydesign.co.uk>
47 // Contributors:
48 // Date:         2003-04-21
49 // Purpose:
50 // Description:  SST SST39VF400 flash driver
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 #include <pkgconf/hal.h>
57 #include <pkgconf/devs_flash_sst_39vf400.h>
58 #include <cyg/hal/hal_arch.h>
59 #include <cyg/hal/hal_cache.h>
60 #include <cyg/hal/hal_diag.h> /* HAL_DELAY_US */
61 #include <cyg/infra/diag.h>   /* Required for diag_printf */
62 #include CYGHWR_MEMORY_LAYOUT_H
63
64 #define  _FLASH_PRIVATE_
65 #include <cyg/io/flash.h>
66
67 //----------------------------------------------------------------------------
68 // Platform code must define the below
69 // #define CYGNUM_FLASH_INTERLEAVE      : Number of interleaved devices (in parallel)
70 // #define CYGNUM_FLASH_SERIES          : Number of devices in series
71 // #define CYGNUM_FLASH_BASE            : Base address of the FLASH
72 //
73 // Note:
74 // Currently the driver only supports CYGNUM_FLASH_INTERLEAVE = 1 and
75 // CYGNUM_FLASH_SERIES = 1
76
77
78 // Definitions for the SST 39VF400A part
79 #define SST_ID                    0x00BF          /* SST Manufacturer's ID code   */
80 #define SST_39VF400A              0x2780          /* SST39VF400/SST39VF400A device code */
81 #define CYGNUM_FLASH_SECTOR_SIZE (0x1000)         /* Size of physical sectors */
82 #define CYGNUM_FLASH_BLOCK_SIZE  (0x1000)         /* Driver 'blocks' may be a multiple of physical sectors */
83 #define CYGNUM_FLASH_BLOCK_NUM   (0x80000/CYGNUM_FLASH_BLOCK_SIZE) /* Number of blocks */
84 #define CYGNUM_FLASH_WIDTH       (16)             /* This part is always 16 bits wide */
85 #define CYGNUM_FLASH_BLANK       (1)
86
87
88 #ifndef FLASH_P2V
89 # define FLASH_P2V( _a_ ) ((volatile flash_data_t *)((CYG_ADDRWORD)(_a_)))
90 #endif
91 #ifndef CYGHWR_FLASH_AM29XXXXX_PLF_INIT
92 # define CYGHWR_FLASH_AM29XXXXX_PLF_INIT()
93 #endif
94
95 // Structure to hold device ID
96 typedef struct
97 {
98     cyg_uint16 man_id;
99     cyg_uint16 dev_id;
100 } device_id_t;
101
102 // FLASH registers
103 volatile cyg_uint16 *flash_data_add0 = (cyg_uint16 *)(CYGNUM_FLASH_BASE);
104 volatile cyg_uint16 *flash_data_add1 = (cyg_uint16 *)(CYGNUM_FLASH_BASE + (0x0001 << 1));
105 volatile cyg_uint16 *flash_cmd_add1 = (cyg_uint16 *)(CYGNUM_FLASH_BASE + (0x5555 << 1));
106 volatile cyg_uint16 *flash_cmd_add2 = (cyg_uint16 *)(CYGNUM_FLASH_BASE + (0x2AAA << 1));
107 volatile cyg_uint16 *flash_cmd_add3 = (cyg_uint16 *)(CYGNUM_FLASH_BASE + (0x5555 << 1));
108 volatile cyg_uint16 *flash_cmd_add4 = (cyg_uint16 *)(CYGNUM_FLASH_BASE + (0x5555 << 1));
109 volatile cyg_uint16 *flash_cmd_add5 = (cyg_uint16 *)(CYGNUM_FLASH_BASE + (0x2AAA << 1));
110
111
112 //----------------------------------------------------------------------------
113 // Now that device properties are defined, include magic for defining
114 // accessor type and constants.
115 #include <cyg/io/flash_dev.h>
116
117 //----------------------------------------------------------------------------
118 // Functions that put the flash device into non-read mode must reside
119 // in RAM.
120 static device_id_t get_device_id(void) __attribute__ ((section (".2ram.get_device_id")));
121 int  flash_erase_block(void* block, unsigned int size)
122     __attribute__ ((section (".2ram.flash_erase_block")));
123 int  flash_program_buf(void* addr, void* data, int len)
124     __attribute__ ((section (".2ram.flash_program_buf")));
125
126 //----------------------------------------------------------------------------
127 // Get Device ID
128 //
129 // Reads the manufacturer and part number codes for the device
130 //
131 static device_id_t get_device_id(void)
132 {
133     device_id_t device_id;
134     int i;
135
136     /*  Issue the Software ID command */
137     *flash_cmd_add1 = 0xAAAA;
138     *flash_cmd_add2 = 0x5555;
139     *flash_cmd_add3 = 0x9090;
140
141     /* Tida delay time, Tida = 150 ns */
142     /* Can use any function that is in ROM */
143     for (i = 0; i < 100; i++)
144     {
145         /* Do nothing */
146     }
147
148     /* Read the product ID */
149     device_id.man_id = *flash_data_add0 & 0xFF;
150     device_id.dev_id = *flash_data_add1;
151
152     /* Issue the Software ID EXIT command */
153     *flash_data_add0 = 0xF0F0;
154
155     /* Tida delay time, Tida = 150 ns */
156     /* Can use any function that is in ROM */
157     for (i = 0; i < 100; i++)
158     {
159         /* Do nothing */
160     }
161
162     return(device_id);
163 }
164
165
166 //----------------------------------------------------------------------------
167 // Initialize driver details
168 //
169 int flash_hwr_init(void)
170 {
171     device_id_t device_id;
172
173     /* Call the function to get the device ID */
174     device_id = get_device_id();
175
176     /* Determine whether there is a SST39VF400A installed or not */
177     if ((device_id.man_id != SST_ID) || (device_id.dev_id != SST_39VF400A))
178     {
179         return FLASH_ERR_DRV_WRONG_PART;
180     }
181
182     // Hard wired for now
183     flash_info.block_size = CYGNUM_FLASH_BLOCK_SIZE;
184     flash_info.blocks = CYGNUM_FLASH_BLOCK_NUM;
185     flash_info.start = (void *)CYGNUM_FLASH_BASE;
186     flash_info.end = (void *)(CYGNUM_FLASH_BASE + (flash_info.block_size * flash_info.blocks));
187
188     return FLASH_ERR_OK;
189 }
190
191 //----------------------------------------------------------------------------
192 // Map a hardware status to a package error
193 int flash_hwr_map_error(int e)
194 {
195     return e;
196 }
197
198
199 //----------------------------------------------------------------------------
200 // See if a range of FLASH addresses overlaps currently running code
201 bool flash_code_overlaps(void *start, void *end)
202 {
203     extern unsigned char _stext[], _etext[];
204
205     return ((((unsigned long)&_stext >= (unsigned long)start) &&
206              ((unsigned long)&_stext < (unsigned long)end)) ||
207             (((unsigned long)&_etext >= (unsigned long)start) &&
208              ((unsigned long)&_etext < (unsigned long)end)));
209 }
210
211 //----------------------------------------------------------------------------
212 // Erase Block
213 // This function actually uses the sector erase command instead of the block
214 // erase command. this allows for the effective block size to be smaller
215 // than 64K (as small as the 4K sector size)
216 int flash_erase_block(void* block, unsigned int size)
217 {
218
219     volatile cyg_uint16 *block_addr;
220     volatile cyg_uint16 *verify_addr;
221     int verify_failed;
222     cyg_uint32 i, timeout;
223     int j;
224     int retry;
225
226     block_addr = block;
227
228     for (j = 0; j < (size / CYGNUM_FLASH_SECTOR_SIZE); j++)
229     {
230         retry = 0;
231         while (retry < 16)
232         {
233             /* Issue the Sector-Erase command */
234             *flash_cmd_add1 = 0xAAAA;
235             *flash_cmd_add2 = 0x5555;
236             *flash_cmd_add3 = 0x8080;
237             *flash_cmd_add4 = 0xAAAA;
238             *flash_cmd_add5 = 0x5555;
239             *block_addr = 0x3030;  /* Sector Erase command */
240
241             /* Wait for the Erase operation to complete */
242             /* With a timeout to stop the board locking up with a H/W error*/
243             timeout = 0;
244             i = 0;
245             while (i < 5)
246             {
247                 if (*block_addr == 0xFFFF)
248                 {
249                     i++;
250                 }
251                 else
252                 {
253                     i = 0;
254                 }
255
256                 if (++timeout > 0x01000000)
257                 {
258                     /* Timeout - return with ERROR status */
259                     return (FLASH_ERR_DRV_TIMEOUT);
260                 }
261             }
262
263             /* Verify this sector has been erased */
264             verify_addr = block_addr;
265             verify_failed = 0;
266             while ((cyg_uint32)(verify_addr) < ((cyg_uint32)block_addr + (cyg_uint32)CYGNUM_FLASH_SECTOR_SIZE))
267             {
268                 if (*verify_addr != 0xFFFF)
269                 {
270                     /* Error verifying segment data */
271                     retry++;
272                     verify_failed = 1;
273                     break;
274                 }
275                 ++verify_addr;
276             }
277
278             if (verify_failed == 0)
279             {
280                 /* Sector erase verified */
281                 break;
282             }
283         }
284
285         /* Increment the block address by 1 sector */
286         (cyg_uint32)block_addr += CYGNUM_FLASH_SECTOR_SIZE;
287     }
288
289     /* Verify the entire block has been set to all 0xFFFFs */
290     block_addr = block;
291     while ((cyg_uint32)(block_addr) < ((cyg_uint32)block + (cyg_uint32)size))
292     {
293         if (*block_addr != 0xFFFF)
294         {
295             /* Error verifying data */
296             return (FLASH_ERR_DRV_VERIFY);
297         }
298
299         ++block_addr;
300     }
301
302     return (FLASH_ERR_OK);
303 }
304
305
306 //----------------------------------------------------------------------------
307 // Program Buffer
308 int
309 flash_program_buf(void* addr, void* data, int len)
310 {
311     volatile cyg_uint16 *write_ptr;
312     volatile cyg_uint16 *data_ptr;
313     int i;
314     cyg_uint32 timeout;
315     cyg_uint16 read_data1, read_data2;
316
317     write_ptr = addr;  /* Initialise local pointers */
318     data_ptr = data;
319
320     /* Loop for writing the data */
321     while ((cyg_uint32)write_ptr < ((cyg_uint32)addr + (cyg_uint32)len))
322     {
323         /* Write word of data to FLASH */
324         /* Issue the Word-Program command */
325         *flash_cmd_add1 = 0xAAAA;
326         *flash_cmd_add2 = 0x5555;
327         *flash_cmd_add3 = 0xA0A0;
328         /* Write data word to FLASH */
329         *write_ptr = *data_ptr;
330
331         /* Wait for the operation to complete */
332         /* Wait for the Erase operation to complete */
333         /* With a timeout to stop the board locking up with a H/W error*/
334         timeout = 0;
335         i = 0;
336         while (i < 5)
337         {
338             read_data1 = *write_ptr;
339             read_data2 = *write_ptr;
340             if (read_data1 == read_data2)
341             {
342                 /* Bit 6 can no longer be toggling */
343                 i++;
344             }
345             else
346             {
347                 i = 0;
348             }
349
350             if (++timeout > 0x01000000)
351             {
352                 /* Timeout - return with ERROR status */
353                 return (FLASH_ERR_DRV_TIMEOUT);
354             }
355         }
356
357         /* Increment pointers to next words */
358         ++write_ptr;
359         ++data_ptr;
360     }
361
362     /* Data write complete - verify the data */
363     write_ptr = addr;  /* Re-initialise local pointers */
364     data_ptr = data;
365
366     /* Loop for verifying the data */
367     while ((cyg_uint32)write_ptr < ((cyg_uint32)addr + (cyg_uint32)len))
368     {
369         if (*write_ptr != *data_ptr)
370         {
371             /* Error verifying data */
372             return (FLASH_ERR_DRV_VERIFY);
373         }
374
375         /* Increment pointers to next words */
376         ++write_ptr;
377         ++data_ptr;
378     }
379
380     return (FLASH_ERR_OK);
381 }
382
383 #endif // CYGONCE_DEVS_FLASH_SST_39VF400_INL
384
385
386
387
388
389
390