flashrom: Update to TEST_OK for Winbond W39V040FA PROBE READ
[coreboot.git] / util / flashrom / jedec.c
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2000 Silicon Integrated System Corporation
5  * Copyright (C) 2006 Giampiero Giancipoli <gianci@email.it>
6  * Copyright (C) 2006 coresystems GmbH <info@coresystems.de>
7  * Copyright (C) 2007 Carl-Daniel Hailfinger
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
22  */
23
24 #include <stdio.h>
25 #include <stdint.h>
26 #include "flash.h"
27
28 #define MAX_REFLASH_TRIES 0x10
29
30 /* Check one byte for odd parity */
31 uint8_t oddparity(uint8_t val)
32 {
33         val = (val ^ (val >> 4)) & 0xf;
34         val = (val ^ (val >> 2)) & 0x3;
35         return (val ^ (val >> 1)) & 0x1;
36 }
37
38 void toggle_ready_jedec(volatile uint8_t *dst)
39 {
40         unsigned int i = 0;
41         uint8_t tmp1, tmp2;
42
43         tmp1 = *dst & 0x40;
44
45         while (i++ < 0xFFFFFFF) {
46                 tmp2 = *dst & 0x40;
47                 if (tmp1 == tmp2) {
48                         break;
49                 }
50                 tmp1 = tmp2;
51         }
52 }
53
54 void data_polling_jedec(volatile uint8_t *dst, uint8_t data)
55 {
56         unsigned int i = 0;
57         uint8_t tmp;
58
59         data &= 0x80;
60
61         while (i++ < 0xFFFFFFF) {
62                 tmp = *dst & 0x80;
63                 if (tmp == data) {
64                         break;
65                 }
66         }
67 }
68
69 void unprotect_jedec(volatile uint8_t *bios)
70 {
71         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
72         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
73         *(volatile uint8_t *)(bios + 0x5555) = 0x80;
74         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
75         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
76         *(volatile uint8_t *)(bios + 0x5555) = 0x20;
77
78         usleep(200);
79 }
80
81 void protect_jedec(volatile uint8_t *bios)
82 {
83         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
84         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
85         *(volatile uint8_t *)(bios + 0x5555) = 0xA0;
86
87         usleep(200);
88 }
89
90 int probe_jedec(struct flashchip *flash)
91 {
92         volatile uint8_t *bios = flash->virtual_memory;
93         uint8_t id1, id2;
94         uint32_t largeid1, largeid2;
95
96         /* Issue JEDEC Product ID Entry command */
97         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
98         myusec_delay(10);
99         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
100         myusec_delay(10);
101         *(volatile uint8_t *)(bios + 0x5555) = 0x90;
102         /* Older chips may need up to 100 us to respond. The ATMEL 29C020
103          * needs 10 ms according to the data sheet.
104          */
105         myusec_delay(10000);
106
107         /* Read product ID */
108         id1 = *(volatile uint8_t *)bios;
109         id2 = *(volatile uint8_t *)(bios + 0x01);
110         largeid1 = id1;
111         largeid2 = id2;
112
113         /* Check if it is a continuation ID, this should be a while loop. */
114         if (id1 == 0x7F) {
115                 largeid1 <<= 8;
116                 id1 = *(volatile uint8_t *)(bios + 0x100);
117                 largeid1 |= id1;
118         }
119         if (id2 == 0x7F) {
120                 largeid2 <<= 8;
121                 id2 = *(volatile uint8_t *)(bios + 0x101);
122                 largeid2 |= id2;
123         }
124
125         /* Issue JEDEC Product ID Exit command */
126         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
127         myusec_delay(10);
128         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
129         myusec_delay(10);
130         *(volatile uint8_t *)(bios + 0x5555) = 0xF0;
131         myusec_delay(40);
132
133         printf_debug("%s: id1 0x%x, id2 0x%x", __FUNCTION__, largeid1, largeid2);
134         if (!oddparity(id1))
135                 printf_debug(", id1 parity violation");
136         printf_debug("\n");
137         if (largeid1 == flash->manufacture_id && largeid2 == flash->model_id)
138                 return 1;
139
140         return 0;
141 }
142
143 int erase_sector_jedec(volatile uint8_t *bios, unsigned int page)
144 {
145         /*  Issue the Sector Erase command   */
146         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
147         myusec_delay(10);
148         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
149         myusec_delay(10);
150         *(volatile uint8_t *)(bios + 0x5555) = 0x80;
151         myusec_delay(10);
152
153         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
154         myusec_delay(10);
155         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
156         myusec_delay(10);
157         *(volatile uint8_t *)(bios + page) = 0x30;
158         myusec_delay(10);
159
160         /* wait for Toggle bit ready         */
161         toggle_ready_jedec(bios);
162
163         return 0;
164 }
165
166 int erase_block_jedec(volatile uint8_t *bios, unsigned int block)
167 {
168         /*  Issue the Sector Erase command   */
169         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
170         myusec_delay(10);
171         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
172         myusec_delay(10);
173         *(volatile uint8_t *)(bios + 0x5555) = 0x80;
174         myusec_delay(10);
175
176         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
177         myusec_delay(10);
178         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
179         myusec_delay(10);
180         *(volatile uint8_t *)(bios + block) = 0x50;
181         myusec_delay(10);
182
183         /* wait for Toggle bit ready         */
184         toggle_ready_jedec(bios);
185
186         return 0;
187 }
188
189 int erase_chip_jedec(struct flashchip *flash)
190 {
191         volatile uint8_t *bios = flash->virtual_memory;
192
193         /*  Issue the JEDEC Chip Erase command   */
194         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
195         myusec_delay(10);
196         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
197         myusec_delay(10);
198         *(volatile uint8_t *)(bios + 0x5555) = 0x80;
199         myusec_delay(10);
200
201         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
202         myusec_delay(10);
203         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
204         myusec_delay(10);
205         *(volatile uint8_t *)(bios + 0x5555) = 0x10;
206         myusec_delay(10);
207
208         toggle_ready_jedec(bios);
209
210         return 0;
211 }
212
213 int write_page_write_jedec(volatile uint8_t *bios, uint8_t *src,
214                            volatile uint8_t *dst, int page_size)
215 {
216         int i, tried = 0, start_index = 0, ok;
217         volatile uint8_t *d = dst;
218         uint8_t *s = src;
219
220 retry:
221         /* Issue JEDEC Data Unprotect comand */
222         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
223         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
224         *(volatile uint8_t *)(bios + 0x5555) = 0xA0;
225
226         /* transfer data from source to destination */
227         for (i = start_index; i < page_size; i++) {
228                 /* If the data is 0xFF, don't program it */
229                 if (*src != 0xFF)
230                         *dst = *src;
231                 dst++;
232                 src++;
233         }
234
235         toggle_ready_jedec(dst - 1);
236
237         dst = d;
238         src = s;
239         ok = 1;
240         for (i = 0; i < page_size; i++) {
241                 if (*dst != *src) {
242                         ok = 0;
243                         break;
244                 }
245                 dst++;
246                 src++;
247         }
248
249         if (!ok && tried++ < MAX_REFLASH_TRIES) {
250                 start_index = i;
251                 goto retry;
252         }
253         if (!ok) {
254                 fprintf(stderr, " page %d failed!\n",
255                         (unsigned int)(d - bios) / page_size);
256         }
257         return !ok;
258 }
259
260 int write_byte_program_jedec(volatile uint8_t *bios, uint8_t *src,
261                              volatile uint8_t *dst)
262 {
263         int tried = 0, ok = 1;
264
265         /* If the data is 0xFF, don't program it */
266         if (*src == 0xFF) {
267                 return -1;
268         }
269
270 retry:
271         /* Issue JEDEC Byte Program command */
272         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
273         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
274         *(volatile uint8_t *)(bios + 0x5555) = 0xA0;
275
276         /* transfer data from source to destination */
277         *dst = *src;
278         toggle_ready_jedec(bios);
279
280         if (*dst != *src && tried++ < MAX_REFLASH_TRIES) {
281                 goto retry;
282         }
283
284         if (tried >= MAX_REFLASH_TRIES)
285                 ok = 0;
286
287         return !ok;
288 }
289
290 int write_sector_jedec(volatile uint8_t *bios, uint8_t *src,
291                        volatile uint8_t *dst, unsigned int page_size)
292 {
293         int i;
294
295         for (i = 0; i < page_size; i++) {
296                 write_byte_program_jedec(bios, src, dst);
297                 dst++, src++;
298         }
299
300         return 0;
301 }
302
303 int write_jedec(struct flashchip *flash, uint8_t *buf)
304 {
305         int i;
306         int total_size = flash->total_size * 1024;
307         int page_size = flash->page_size;
308         volatile uint8_t *bios = flash->virtual_memory;
309
310         erase_chip_jedec(flash);
311         // dumb check if erase was successful.
312         for (i = 0; i < total_size; i++) {
313                 if (bios[i] != (uint8_t) 0xff) {
314                         printf("ERASE FAILED @%d, val %02x!\n", i, bios[i]);
315                         return -1;
316                 }
317         }
318
319         printf("Programming page: ");
320         for (i = 0; i < total_size / page_size; i++) {
321                 printf("%04d at address: 0x%08x", i, i * page_size);
322                 write_page_write_jedec(bios, buf + i * page_size,
323                                        bios + i * page_size, page_size);
324                 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
325         }
326         printf("\n");
327         protect_jedec(bios);
328
329         return 0;
330 }