Ben Bodley <ben@teknique.com> non-CFI compliant flash (AMIC A29L800A)
[fw/openocd] / src / flash / non_cfi.c
1 /***************************************************************************
2  *   Copyright (C) 2007 by Dominic Rath                                    *
3  *   Dominic.Rath@gmx.de                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdlib.h>
25
26 #include "log.h"
27
28 #include "flash.h"
29 #include "cfi.h"
30 #include "non_cfi.h"
31
32 /* non-CFI compatible flashes */
33 non_cfi_t non_cfi_flashes[] = {
34         {
35                 .mfr = CFI_MFR_SST,
36                 .id = 0xd4,
37                 .pri_id = 0x02,
38                 .dev_size = 0x10,                       /* 2^16 = 64KB */
39                 .interface_desc = 0x0,          /* x8 only device */
40                 .max_buf_write_size = 0x0,
41                 .num_erase_regions = 1,
42                 .erase_region_info =
43                 {
44                         0x0010000f,                             /* 16x  4KB */
45                         0x00000000
46                 }
47         },
48         {
49                 .mfr = CFI_MFR_SST,
50                 .id = 0xd5,
51                 .pri_id = 0x02,
52                 .dev_size = 0x11,                       /* 2^17 = 128KB */
53                 .interface_desc = 0x0,          /* x8 only device */
54                 .max_buf_write_size = 0x0,
55                 .num_erase_regions = 1,
56                 .erase_region_info =
57                 {
58                         0x0010001f,
59                         0x00000000
60                 }
61         },
62         {
63                 .mfr = CFI_MFR_SST,
64                 .id = 0xd6,
65                 .pri_id = 0x02,
66                 .dev_size = 0x12,                       /* 2^18 = 256KB */
67                 .interface_desc = 0x0,          /* x8 only device */
68                 .max_buf_write_size = 0x0,
69                 .num_erase_regions = 1,
70                 .erase_region_info =
71                 {
72                         0x0010003f,
73                         0x00000000
74                 }
75         },
76         {
77                 .mfr = CFI_MFR_SST,
78                 .id = 0xd7,
79                 .pri_id = 0x02,
80                 .dev_size = 0x13,                       /* 2^19 = 512KB */
81                 .interface_desc = 0x0,          /* x8 only device */
82                 .max_buf_write_size = 0x0,
83                 .num_erase_regions = 1,
84                 .erase_region_info =
85                 {
86                         0x0010007f,
87                         0x00000000
88                 }
89         },
90         {
91                 .mfr = CFI_MFR_SST,
92                 .id = 0x2780,
93                 .pri_id = 0x02,
94                 .dev_size = 0x13,                       /* 2^19 = 512KB */
95                 .interface_desc = 0x2,          /* x8 or x16 device */
96                 .max_buf_write_size = 0x0,
97                 .num_erase_regions = 1,
98                 .erase_region_info =
99                 {
100                         0x0010007f,
101                         0x00000000
102                 }
103         },
104         {
105                 .mfr = CFI_MFR_ST,
106                 .id = 0xd6,                                     /* ST29F400BB */
107                 .pri_id = 0x02,
108                 .dev_size = 0x13,                       /* 2^19 = 512KB */
109                 .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
110                 .max_buf_write_size = 0x0,
111                 .num_erase_regions = 4,
112                 .erase_region_info =
113                 {
114                         0x00400000,             /* 1x 16KB */
115                         0x00200001,             /* 2x  8KB */
116                         0x00800000,             /* 1x 32KB */
117                         0x01000006,             /* 7x 64KB */
118                         0x00000000
119                 }
120         },
121         {
122                 .mfr = CFI_MFR_ST,
123                 .id = 0xd5,                                     /* ST29F400BT */
124                 .pri_id = 0x02,
125                 .dev_size = 0x13,                       /* 2^19 = 512KB */
126                 .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
127                 .max_buf_write_size = 0x0,
128                 .num_erase_regions = 4,
129                 .erase_region_info =
130                 {
131                         0x01000006,             /* 7x 64KB */
132                         0x00800000,             /* 1x 32KB */
133                         0x00200001,             /* 2x  8KB */
134                         0x00400000,             /* 1x 16KB */
135                         0x00000000
136                 }
137         },
138         {
139                 .mfr = CFI_MFR_AMD,
140                 .id = 0x22ab,                           /* AM29F400BB */
141                 .pri_id = 0x02,
142                 .dev_size = 0x13,                       /* 2^19 = 512KB */
143                 .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
144                 .max_buf_write_size = 0x0,
145                 .num_erase_regions = 4,
146                 .erase_region_info =
147                 {
148                         0x00400000,             /* 1x 16KB */
149                         0x00200001,             /* 2x  8KB */
150                         0x00800000,             /* 1x 32KB */
151                         0x01000006,             /* 7x 64KB */
152                         0x00000000
153                 }
154         },
155         {
156                 .mfr = CFI_MFR_AMD,
157                 .id = 0x2223,                           /* AM29F400BT */
158                 .pri_id = 0x02,
159                 .dev_size = 0x13,                       /* 2^19 = 512KB */
160                 .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
161                 .max_buf_write_size = 0x0,
162                 .num_erase_regions = 4,
163                 .erase_region_info =
164                 {
165                         0x01000006,             /* 7x 64KB */
166                         0x00800000,             /* 1x 32KB */
167                         0x00200001,             /* 2x  8KB */
168                         0x00400000,             /* 1x 16KB */
169                         0x00000000
170                 }
171         },
172         {
173                 .mfr = CFI_MFR_FUJITSU,
174                 .id = 0x226b,                           /* AM29SL800DB */
175                 .pri_id = 0x02,
176                 .dev_size = 0x14,                       /* 2^20 = 1MB */
177                 .interface_desc = 0x2,          /* x8 or x16 device with nBYTE */
178                 .max_buf_write_size = 0x0,
179                 .num_erase_regions = 4,
180                 .erase_region_info =
181                 {
182                         0x00400000,             /* 1x 16KB */
183                         0x00200001,             /* 2x 8KB */
184                         0x00800000,             /* 1x 32KB */
185                         0x0100000e,             /* 15x 64KB */
186                         0x00000000
187                 }
188         },
189         {
190                 .mfr = CFI_MFR_AMIC,
191             .id = 0xb31a,               /* A29L800A */
192                 .pri_id = 0x02,
193             .dev_size = 0x14,
194             .interface_desc = 0x2,
195             .max_buf_write_size = 0x0,
196             .num_erase_regions = 4,
197             .erase_region_info =
198                 {
199                         0x00400000,             /* 1x 16KB */
200                         0x00200001,             /* 2x 8KB */
201                         0x00800000,             /* 1x 32KB */
202                         0x0100000e,             /* 15x 64KB */
203                         0x00000000
204             }
205         },
206         {
207                 .mfr = 0,
208                 .id = 0,
209         }
210 };
211
212 void cfi_fixup_non_cfi(flash_bank_t *bank, void *param)
213 {
214         cfi_flash_bank_t *cfi_info = bank->driver_priv;
215         non_cfi_t *non_cfi = non_cfi_flashes;
216         
217         while (non_cfi->mfr)
218         {
219                 if ((cfi_info->manufacturer == non_cfi->mfr)
220                         && (cfi_info->device_id == non_cfi->id))
221                 {
222                         break;
223                 }
224                 non_cfi++;
225         }
226         
227         cfi_info->not_cfi = 1;
228         
229         /* fill in defaults for non-critical data */
230         cfi_info->vcc_min = 0x0;
231         cfi_info->vcc_max = 0x0;
232         cfi_info->vpp_min = 0x0;
233         cfi_info->vpp_max = 0x0;
234         cfi_info->word_write_timeout_typ = 0x0;
235         cfi_info->buf_write_timeout_typ = 0x0;
236         cfi_info->block_erase_timeout_typ = 0x0;
237         cfi_info->chip_erase_timeout_typ = 0x0;
238         cfi_info->word_write_timeout_max = 0x0;
239         cfi_info->buf_write_timeout_max = 0x0;
240         cfi_info->block_erase_timeout_max = 0x0;
241         cfi_info->chip_erase_timeout_max = 0x0;
242         
243         cfi_info->qry[0] = 'Q';
244         cfi_info->qry[1] = 'R';
245         cfi_info->qry[2] = 'Y';
246         
247         cfi_info->pri_id = non_cfi->pri_id;
248         cfi_info->pri_addr = 0x0;
249         cfi_info->alt_id = 0x0;
250         cfi_info->alt_addr = 0x0;
251         cfi_info->alt_ext = NULL;
252         
253         cfi_info->interface_desc = non_cfi->interface_desc;
254         cfi_info->max_buf_write_size = non_cfi->max_buf_write_size;
255         cfi_info->num_erase_regions = non_cfi->num_erase_regions;
256         cfi_info->erase_region_info = non_cfi->erase_region_info;
257         
258         if (cfi_info->pri_id == 0x2)
259         {
260                 cfi_spansion_pri_ext_t *pri_ext = malloc(sizeof(cfi_spansion_pri_ext_t));
261
262                 pri_ext->pri[0] = 'P';
263                 pri_ext->pri[1] = 'R';
264                 pri_ext->pri[2] = 'I';
265                 
266                 pri_ext->major_version = '1';
267                 pri_ext->minor_version = '0';
268                 
269                 pri_ext->SiliconRevision = 0x0;
270                 pri_ext->EraseSuspend = 0x0;
271                 pri_ext->EraseSuspend = 0x0;
272                 pri_ext->BlkProt = 0x0;
273                 pri_ext->TmpBlkUnprotect = 0x0;
274                 pri_ext->BlkProtUnprot = 0x0;
275                 pri_ext->SimultaneousOps = 0x0;
276                 pri_ext->BurstMode = 0x0;
277                 pri_ext->PageMode = 0x0;
278                 pri_ext->VppMin = 0x0;
279                 pri_ext->VppMax = 0x0;
280                 pri_ext->TopBottom = 0x0;
281         
282                 pri_ext->_reversed_geometry = 0;
283                 
284                 cfi_info->pri_ext = pri_ext;
285         } else if ((cfi_info->pri_id == 0x1) || (cfi_info->pri_id == 0x3))
286         {
287                 LOG_ERROR("BUG: non-CFI flashes using the Intel commandset are not yet supported");
288                 exit(-1);
289         }
290 }
291
292