OSDN Git Service

including help
[pf3gnuchains/urjtag.git] / jtag / src / flash / cfi.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2002, 2003 ETC s.r.o.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19  * 02111-1307, USA.
20  *
21  * Written by Marcel Telka <marcel@telka.sk>, 2002, 2003.
22  *
23  * Documentation:
24  * [1] JEDEC Solid State Technology Association, "Common Flash Interface (CFI)",
25  *     September 1999, Order Number: JESD68
26  * [2] Intel Corporation, "Common Flash Interface (CFI) and Command Sets
27  *     Application Note 646", April 2000, Order Number: 292204-004
28  *
29  */
30
31 #include "sysdep.h"
32
33 #include <stdint.h>
34 #include <stdlib.h>
35 #include <flash/cfi.h>
36
37 #include <jtag.h>
38 #include <flash.h>
39 #include <bus.h>
40
41 void
42 cfi_array_free( cfi_array_t *cfi_array )
43 {
44         if (!cfi_array)
45                 return;
46
47         if (cfi_array->cfi_chips) {
48                 int i;
49
50                 for (i = 0; i < cfi_array->bus_width; i++) {
51                         if (!cfi_array->cfi_chips[i])
52                                 continue;
53
54                         free( cfi_array->cfi_chips[i]->cfi.device_geometry.erase_block_regions );
55                         if (cfi_array->cfi_chips[i]->cfi.identification_string.pri_vendor_tbl)
56                                 free (cfi_array->cfi_chips[i]->cfi.identification_string.pri_vendor_tbl);
57                         free( cfi_array->cfi_chips[i] );
58                 }
59                 free( cfi_array->cfi_chips );
60         }
61
62         free( cfi_array );
63 }
64
65 int
66 cfi_detect( bus_t *bus, uint32_t adr, cfi_array_t **cfi_array )
67 {
68         unsigned int bw;                /* bus width */
69         unsigned int d;                 /* data offset */
70         int ba;                         /* bus width address multiplier */
71         int ma;                         /* flash mode address multiplier */
72         bus_area_t area;
73
74         if (!cfi_array || !bus)
75                 return -1;              /* invalid parameters */
76
77         *cfi_array = calloc( 1, sizeof (cfi_array_t) );
78         if (!*cfi_array)
79                 return -2;              /* out of memory */
80
81         (*cfi_array)->bus = bus;
82         (*cfi_array)->address = adr;
83         if (bus_area( bus, adr, &area ) != URJTAG_STATUS_OK)
84                 return -8;              /* bus width detection failed */
85         bw = area.width;
86         if (bw != 8 && bw != 16 && bw != 32)
87                 return -3;              /* invalid bus width */
88         (*cfi_array)->bus_width = ba = bw / 8;
89         (*cfi_array)->cfi_chips = calloc( ba, sizeof (cfi_chip_t *) );
90         if (!(*cfi_array)->cfi_chips)
91                 return -2;              /* out of memory */
92
93         for (d = 0; d < bw; d += 8) {
94 #define A(off)                  (adr + (off) * ba * ma)
95 #define D(data)                 ((data) << d)
96 #define gD(data)                (((data) >> d) & 0xFF)
97 #define read1(off)              gD(bus_read( bus, A(off) ))
98 #define read2(off)              (bus_read_start( bus, A(off) ), gD(bus_read_next( bus, A((off) + 1) )) | gD(bus_read_end( bus )) << 8)
99 #define write1(off,data)        bus_write( bus, A(off), D(data) )
100
101                 cfi_query_structure_t *cfi;
102                 uint32_t tmp;
103                 int ret = -4;           /* CFI not detected (Q) */
104                 uint16_t pri_vendor_tbl_adr;
105
106                 /* detect CFI capable devices - see Table 1 in [1] */
107                 for (ma = 1; ma <= 4; ma *= 2) {
108                         write1( CFI_CMD_QUERY_OFFSET, CFI_CMD_QUERY );
109
110                         if (read1(CFI_QUERY_ID_OFFSET) == 'Q') {
111                                 ret = -5;       /* CFI not detected (R) */
112                                 if (read1(CFI_QUERY_ID_OFFSET + 1) == 'R')
113                                         break;
114                         }
115
116                         write1( 0, CFI_CMD_READ_ARRAY1 );
117                 }
118
119                 if (ma > 4)
120                         return ret;     /* CFI not detected (Q or R) */
121
122                 if (read1(CFI_QUERY_ID_OFFSET + 2) != 'Y') {
123                         write1( 0, CFI_CMD_READ_ARRAY1 );
124                         return -6;      /* CFI not detected (Y) */
125                 }
126
127                 (*cfi_array)->cfi_chips[d / 8] = calloc( 1, sizeof (cfi_chip_t) );
128                 if (!(*cfi_array)->cfi_chips[d / 8]) {
129                         write1( 0, CFI_CMD_READ_ARRAY1 );
130                         return -2;      /* out of memory */
131                 }
132                 cfi = &(*cfi_array)->cfi_chips[d / 8]->cfi;
133
134                 /* Identification string - see Table 6 in [1] */
135                 cfi->identification_string.pri_id_code = read2(PRI_VENDOR_ID_OFFSET);
136                 cfi->identification_string.pri_vendor_tbl = NULL;
137                 cfi->identification_string.alt_id_code = read2(ALT_VENDOR_ID_OFFSET);
138                 cfi->identification_string.alt_vendor_tbl = NULL;
139
140                 /* System interface information - see Table 7 in [1] */
141                 tmp = read1(VCC_MIN_WEV_OFFSET);
142                 cfi->system_interface_info.vcc_min_wev = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100;
143                 tmp = read1(VCC_MAX_WEV_OFFSET);
144                 cfi->system_interface_info.vcc_max_wev = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100;
145                 tmp = read1(VPP_MIN_WEV_OFFSET);
146                 cfi->system_interface_info.vpp_min_wev = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100;
147                 tmp = read1(VPP_MAX_WEV_OFFSET);
148                 cfi->system_interface_info.vpp_max_wev = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100;
149
150                 /* TODO: Add out of range checks for timeouts */
151                 tmp = read1(TYP_SINGLE_WRITE_TIMEOUT_OFFSET);
152                 cfi->system_interface_info.typ_single_write_timeout = tmp ? (1 << tmp) : 0;
153
154                 tmp = read1(TYP_BUFFER_WRITE_TIMEOUT_OFFSET);
155                 cfi->system_interface_info.typ_buffer_write_timeout = tmp ? (1 << tmp) : 0;
156
157                 tmp = read1(TYP_BLOCK_ERASE_TIMEOUT_OFFSET);
158                 cfi->system_interface_info.typ_block_erase_timeout = tmp ? (1 << tmp) : 0;
159
160                 tmp = read1(TYP_CHIP_ERASE_TIMEOUT_OFFSET);
161                 cfi->system_interface_info.typ_chip_erase_timeout = tmp ? (1 << tmp) : 0;
162
163                 tmp = read1(MAX_SINGLE_WRITE_TIMEOUT_OFFSET);
164                 cfi->system_interface_info.max_single_write_timeout =
165                                 (tmp ? (1 << tmp) : 0) * cfi->system_interface_info.typ_single_write_timeout;
166
167                 tmp = read1(MAX_BUFFER_WRITE_TIMEOUT_OFFSET);
168                 cfi->system_interface_info.max_buffer_write_timeout =
169                                 (tmp ? (1 << tmp) : 0) * cfi->system_interface_info.typ_buffer_write_timeout;
170
171                 tmp = read1(MAX_BLOCK_ERASE_TIMEOUT_OFFSET);
172                 cfi->system_interface_info.max_block_erase_timeout =
173                                 (tmp ? (1 << tmp) : 0) * cfi->system_interface_info.typ_block_erase_timeout;
174
175                 tmp = read1(MAX_CHIP_ERASE_TIMEOUT_OFFSET);
176                 cfi->system_interface_info.max_chip_erase_timeout =
177                                 (tmp ? (1 << tmp) : 0) * cfi->system_interface_info.typ_chip_erase_timeout;
178
179                 /* Device geometry - see Table 8 in [1] */
180                 /* TODO: Add out of range check */
181                 cfi->device_geometry.device_size = 1 << read1(DEVICE_SIZE_OFFSET);
182
183                 cfi->device_geometry.device_interface = read2(FLASH_DEVICE_INTERFACE_OFFSET);
184
185                 /* TODO: Add out of range check */
186                 cfi->device_geometry.max_bytes_write = 1 << read2(MAX_BYTES_WRITE_OFFSET);
187
188                 tmp = cfi->device_geometry.number_of_erase_regions = read1(NUMBER_OF_ERASE_REGIONS_OFFSET);
189
190                 cfi->device_geometry.erase_block_regions = malloc( tmp * sizeof (cfi_erase_block_region_t) );
191                 if (!cfi->device_geometry.erase_block_regions) {
192                         write1( 0, CFI_CMD_READ_ARRAY1 );
193                         return -2;      /* out of memory */
194                 }
195                 
196                 {
197                         int a;
198                         int i;
199
200                         for (i = 0, a = ERASE_BLOCK_REGION_OFFSET; i < tmp; i++, a += 4) {
201                                 uint32_t y = read2(a);
202                                 uint32_t z = read2(a + 2) << 8;
203                                 if (z == 0)
204                                         z = 128;
205                                 cfi->device_geometry.erase_block_regions[i].erase_block_size = z;
206                                 cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks = y + 1;
207                         }
208                 }
209
210                 pri_vendor_tbl_adr = read2(PRI_VENDOR_TABLE_ADR_OFFSET);
211
212                 /* AMD CFI Primary Vendor-Specific Extended Query Table - see [3] and [4] */
213                 if (cfi->identification_string.pri_id_code == CFI_VENDOR_AMD_SCS
214                     && pri_vendor_tbl_adr != 0) {
215                         amd_pri_extened_query_structure_t *pri_vendor_tbl;
216                         uint8_t major_version;
217                         uint8_t minor_version;
218                         uint8_t num_of_banks;
219                         int i;
220 #undef A
221 #define A(off)                  (adr + (pri_vendor_tbl_adr + off) * ba * ma)
222
223                         if (read1 (0) != 'P' || read1 (1) != 'R' || read1 (2) != 'I') {
224                                 write1 (0, CFI_CMD_READ_ARRAY1);
225                                 return -9;      /* CFI primary vendor table not detected */
226                         }
227
228                         major_version = read1 (MAJOR_VERSION_OFFSET);
229                         minor_version = read1 (MINOR_VERSION_OFFSET);
230                         if (major_version > '1' || (major_version == '1' && minor_version >= '3'))
231                                 num_of_banks = read1 (BANK_ORGANIZATION_OFFSET);
232                         else
233                                 num_of_banks = 0;
234                         pri_vendor_tbl = (amd_pri_extened_query_structure_t *)
235                                 calloc (1, sizeof (amd_pri_extened_query_structure_t)
236                                         + num_of_banks * sizeof (uint8_t));
237                         if (!pri_vendor_tbl) {
238                                 write1 (0, CFI_CMD_READ_ARRAY1);
239                                 return -2;      /* out of memory */
240                         }
241
242                         if (major_version > '1' || (major_version == '1' && minor_version >= '0')) {
243                                 pri_vendor_tbl->major_version = major_version;
244                                 pri_vendor_tbl->minor_version = minor_version;
245                                 pri_vendor_tbl->address_sensitive_unlock = read1 (ADDRESS_SENSITIVE_UNLOCK_OFFSET);
246                                 pri_vendor_tbl->erase_suspend = read1 (ERASE_SUSPEND_OFFSET);
247                                 pri_vendor_tbl->sector_protect = read1 (SECTOR_PROTECT_OFFSET);
248                                 pri_vendor_tbl->sector_temporary_unprotect = read1 (SECTOR_TEMPORARY_UNPROTECT_OFFSET);
249                                 pri_vendor_tbl->sector_protect_scheme = read1 (SECTOR_PROTECT_SCHEME_OFFSET);
250                                 pri_vendor_tbl->simultaneous_operation = read1 (SIMULTANEOUS_OPERATION_OFFSET);
251                                 pri_vendor_tbl->burst_mode_type = read1 (BURST_MODE_TYPE_OFFSET);
252                                 pri_vendor_tbl->page_mode_type = read1 (PAGE_MODE_TYPE_OFFSET);
253                         }
254                         if (major_version > '1' || (major_version == '1' && minor_version >= '1')) {
255                                 tmp = read1 (ACC_MIN_OFFSET);
256                                 pri_vendor_tbl->acc_min = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100;
257                                 tmp = read1 (ACC_MAX_OFFSET);
258                                 pri_vendor_tbl->acc_max = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100;
259                                 pri_vendor_tbl->top_bottom_sector_flag = read1 (TOP_BOTTOM_SECTOR_FLAG_OFFSET);
260                         }
261                         if (major_version > '1' || (major_version == '1' && minor_version >= '2'))
262                                 pri_vendor_tbl->program_suspend = read1 (PROGRAM_SUSPEND_OFFSET);
263                         if (major_version > '1' || (major_version == '1' && minor_version >= '3')) {
264                                 if (pri_vendor_tbl->simultaneous_operation)
265                                         pri_vendor_tbl->bank_organization = read1 (BANK_ORGANIZATION_OFFSET);
266                                 else
267                                         pri_vendor_tbl->bank_organization = 0;
268                                 for (i = 0; i < pri_vendor_tbl->bank_organization; i++)
269                                         pri_vendor_tbl->bank_region_info[i] = read1 (BANK_REGION_INFO_OFFSET + i * sizeof (uint8_t));
270                         }
271                         if (major_version > '1' || (major_version == '1' && minor_version >= '4')) {
272                                 pri_vendor_tbl->unlock_bypass = read1 (UNLOCK_BYPASS_OFFSET);
273                                 tmp = read1 (SECSI_SECTOR_SIZE_OFFSET);
274                                 pri_vendor_tbl->secsi_sector_size = tmp ? (1 << tmp) : 0;
275                                 tmp = read1 (EMBEDDED_HWRST_TIMEOUT_MAX_OFFSET);
276                                 pri_vendor_tbl->embedded_hwrst_timeout_max = tmp ? (1 << tmp) : 0;
277                                 tmp = read1 (NON_EMBEDDED_HWRST_TIMEOUT_MAX_OFFSET);
278                                 pri_vendor_tbl->non_embedded_hwrst_timeout_max = tmp ? (1 << tmp) : 0;
279                                 tmp = read1 (ERASE_SUSPEND_TIMEOUT_MAX_OFFSET);
280                                 pri_vendor_tbl->erase_suspend_timeout_max = tmp ? (1 << tmp) : 0;
281                                 tmp = read1 (PROGRAM_SUSPEND_TIMEOUT_MAX_OFFSET);
282                                 pri_vendor_tbl->program_suspend_timeout_max = tmp ? (1 << tmp) : 0;
283                         }
284
285                         cfi->identification_string.pri_vendor_tbl = (void *) pri_vendor_tbl;
286
287 #undef A
288 #define A(off)                  (adr + (off) * ba * ma)
289
290                         /* Reverse the order of erase block region information for top boot devices.  */
291                         if ((major_version > '1' || (major_version == '1' && minor_version >= '1'))
292                             && pri_vendor_tbl->top_bottom_sector_flag == 0x3)
293                         {
294                                 uint32_t y, z;
295                                 uint32_t n = cfi->device_geometry.number_of_erase_regions;
296
297                                 for (i = 0; i < n / 2; i++) {
298                                         z = cfi->device_geometry.erase_block_regions[i].erase_block_size;
299                                         y = cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks;
300                                         cfi->device_geometry.erase_block_regions[i].erase_block_size
301                                                 = cfi->device_geometry.erase_block_regions[n - i - 1].erase_block_size;
302                                         cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks
303                                                 = cfi->device_geometry.erase_block_regions[n - i - 1].number_of_erase_blocks;
304                                         cfi->device_geometry.erase_block_regions[n - i - 1].erase_block_size = z;
305                                         cfi->device_geometry.erase_block_regions[n - i - 1].number_of_erase_blocks = y;
306                                 }
307                         }
308                 }
309
310                 /* TODO: Intel Primary Algorithm Extended Query Table - see Table 5. in [2] */
311
312                 /* Read Array */
313                 write1( 0, CFI_CMD_READ_ARRAY1 );
314
315 #undef A
316 #undef D
317 #undef gD
318 #undef read1
319 #undef read2
320 #undef write1
321
322                 switch (cfi->device_geometry.device_interface) {
323                         case CFI_INTERFACE_X8:
324                                 if (ma != 1)
325                                         return -7;              /* error in device detection */
326                                 (*cfi_array)->cfi_chips[d / 8]->width = 1;
327                                 break;
328                         case CFI_INTERFACE_X16:
329                                 if (ma != 1)
330                                         return -7;              /* error in device detection */
331                                 (*cfi_array)->cfi_chips[d / 8]->width = 2;
332                                 d += 8;
333                                 break;
334                         case CFI_INTERFACE_X8_X16:
335                                 if (ma != 1 && ma != 2)
336                                         return -7;              /* error in device detection */
337                                 (*cfi_array)->cfi_chips[d / 8]->width = 2 / ma;
338                                 if (ma == 1)
339                                         d += 8;
340                                 break;
341                         case CFI_INTERFACE_X32:
342                                 if (ma != 1)
343                                         return -7;              /* error in device detection */
344                                 (*cfi_array)->cfi_chips[d / 8]->width = 4;
345                                 d += 24;
346                                 break;
347                         case CFI_INTERFACE_X16_X32:
348                                 if (ma != 1 && ma != 2)
349                                         return -7;              /* error in device detection */
350                                 (*cfi_array)->cfi_chips[d / 8]->width = 4 / ma;
351                                 if (ma == 1)
352                                         d += 24;
353                                 else
354                                         d += 8;
355                                 break;
356                         default:
357                                 return -7;              /* error in device detection */
358                 }
359         }
360
361         return 0;
362 }