Some flashrom documentation fixes, and removal of duplicated info (trivial).
[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, but it has been tested
104          * to work reliably with 2 ms.
105          */
106         myusec_delay(2000);
107
108         /* Read product ID */
109         id1 = *(volatile uint8_t *)bios;
110         id2 = *(volatile uint8_t *)(bios + 0x01);
111         largeid1 = id1;
112         largeid2 = id2;
113
114         /* Check if it is a continuation ID, this should be a while loop. */
115         if (id1 == 0x7F) {
116                 largeid1 <<= 8;
117                 id1 = *(volatile uint8_t *)(bios + 0x100);
118                 largeid1 |= id1;
119         }
120         if (id2 == 0x7F) {
121                 largeid2 <<= 8;
122                 id2 = *(volatile uint8_t *)(bios + 0x101);
123                 largeid2 |= id2;
124         }
125
126         /* Issue JEDEC Product ID Exit command */
127         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
128         myusec_delay(10);
129         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
130         myusec_delay(10);
131         *(volatile uint8_t *)(bios + 0x5555) = 0xF0;
132         myusec_delay(40);
133
134         printf_debug("%s: id1 0x%x, id2 0x%x", __FUNCTION__, largeid1, largeid2);
135         if (!oddparity(id1))
136                 printf_debug(", id1 parity violation");
137         printf_debug("\n");
138         if (largeid1 == flash->manufacture_id && largeid2 == flash->model_id)
139                 return 1;
140
141         return 0;
142 }
143
144 int erase_sector_jedec(volatile uint8_t *bios, unsigned int page)
145 {
146         /*  Issue the Sector Erase command   */
147         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
148         myusec_delay(10);
149         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
150         myusec_delay(10);
151         *(volatile uint8_t *)(bios + 0x5555) = 0x80;
152         myusec_delay(10);
153
154         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
155         myusec_delay(10);
156         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
157         myusec_delay(10);
158         *(volatile uint8_t *)(bios + page) = 0x30;
159         myusec_delay(10);
160
161         /* wait for Toggle bit ready         */
162         toggle_ready_jedec(bios);
163
164         return 0;
165 }
166
167 int erase_block_jedec(volatile uint8_t *bios, unsigned int block)
168 {
169         /*  Issue the Sector Erase command   */
170         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
171         myusec_delay(10);
172         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
173         myusec_delay(10);
174         *(volatile uint8_t *)(bios + 0x5555) = 0x80;
175         myusec_delay(10);
176
177         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
178         myusec_delay(10);
179         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
180         myusec_delay(10);
181         *(volatile uint8_t *)(bios + block) = 0x50;
182         myusec_delay(10);
183
184         /* wait for Toggle bit ready         */
185         toggle_ready_jedec(bios);
186
187         return 0;
188 }
189
190 int erase_chip_jedec(struct flashchip *flash)
191 {
192         volatile uint8_t *bios = flash->virtual_memory;
193
194         /*  Issue the JEDEC Chip Erase command   */
195         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
196         myusec_delay(10);
197         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
198         myusec_delay(10);
199         *(volatile uint8_t *)(bios + 0x5555) = 0x80;
200         myusec_delay(10);
201
202         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
203         myusec_delay(10);
204         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
205         myusec_delay(10);
206         *(volatile uint8_t *)(bios + 0x5555) = 0x10;
207         myusec_delay(10);
208
209         toggle_ready_jedec(bios);
210
211         return 0;
212 }
213
214 int write_page_write_jedec(volatile uint8_t *bios, uint8_t *src,
215                            volatile uint8_t *dst, int page_size)
216 {
217         int i, tried = 0, start_index = 0, ok;
218         volatile uint8_t *d = dst;
219         uint8_t *s = src;
220
221 retry:
222         /* Issue JEDEC Data Unprotect comand */
223         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
224         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
225         *(volatile uint8_t *)(bios + 0x5555) = 0xA0;
226
227         /* transfer data from source to destination */
228         for (i = start_index; i < page_size; i++) {
229                 /* If the data is 0xFF, don't program it */
230                 if (*src != 0xFF)
231                         *dst = *src;
232                 dst++;
233                 src++;
234         }
235
236         toggle_ready_jedec(dst - 1);
237
238         dst = d;
239         src = s;
240         ok = 1;
241         for (i = 0; i < page_size; i++) {
242                 if (*dst != *src) {
243                         ok = 0;
244                         break;
245                 }
246                 dst++;
247                 src++;
248         }
249
250         if (!ok && tried++ < MAX_REFLASH_TRIES) {
251                 start_index = i;
252                 goto retry;
253         }
254         if (!ok) {
255                 fprintf(stderr, " page %d failed!\n",
256                         (unsigned int)(d - bios) / page_size);
257         }
258         return !ok;
259 }
260
261 int write_byte_program_jedec(volatile uint8_t *bios, uint8_t *src,
262                              volatile uint8_t *dst)
263 {
264         int tried = 0, ok = 1;
265
266         /* If the data is 0xFF, don't program it */
267         if (*src == 0xFF) {
268                 return -1;
269         }
270
271 retry:
272         /* Issue JEDEC Byte Program command */
273         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
274         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
275         *(volatile uint8_t *)(bios + 0x5555) = 0xA0;
276
277         /* transfer data from source to destination */
278         *dst = *src;
279         toggle_ready_jedec(bios);
280
281         if (*dst != *src && tried++ < MAX_REFLASH_TRIES) {
282                 goto retry;
283         }
284
285         if (tried >= MAX_REFLASH_TRIES)
286                 ok = 0;
287
288         return !ok;
289 }
290
291 int write_sector_jedec(volatile uint8_t *bios, uint8_t *src,
292                        volatile uint8_t *dst, unsigned int page_size)
293 {
294         int i;
295
296         for (i = 0; i < page_size; i++) {
297                 write_byte_program_jedec(bios, src, dst);
298                 dst++, src++;
299         }
300
301         return 0;
302 }
303
304 int write_jedec(struct flashchip *flash, uint8_t *buf)
305 {
306         int i;
307         int total_size = flash->total_size * 1024;
308         int page_size = flash->page_size;
309         volatile uint8_t *bios = flash->virtual_memory;
310
311         erase_chip_jedec(flash);
312         // dumb check if erase was successful.
313         for (i = 0; i < total_size; i++) {
314                 if (bios[i] != (uint8_t) 0xff) {
315                         printf("ERASE FAILED @%d, val %02x!\n", i, bios[i]);
316                         return -1;
317                 }
318         }
319
320         printf("Programming page: ");
321         for (i = 0; i < total_size / page_size; i++) {
322                 printf("%04d at address: 0x%08x", i, i * page_size);
323                 write_page_write_jedec(bios, buf + i * page_size,
324                                        bios + i * page_size, page_size);
325                 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");
326         }
327         printf("\n");
328         protect_jedec(bios);
329
330         return 0;
331 }