Add CPUID processor name string support for Fam10 CPUs.
[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 void toggle_ready_jedec(volatile uint8_t *dst)
31 {
32         unsigned int i = 0;
33         uint8_t tmp1, tmp2;
34
35         tmp1 = *dst & 0x40;
36
37         while (i++ < 0xFFFFFFF) {
38                 tmp2 = *dst & 0x40;
39                 if (tmp1 == tmp2) {
40                         break;
41                 }
42                 tmp1 = tmp2;
43         }
44 }
45
46 void data_polling_jedec(volatile uint8_t *dst, uint8_t data)
47 {
48         unsigned int i = 0;
49         uint8_t tmp;
50
51         data &= 0x80;
52
53         while (i++ < 0xFFFFFFF) {
54                 tmp = *dst & 0x80;
55                 if (tmp == data) {
56                         break;
57                 }
58         }
59 }
60
61 void unprotect_jedec(volatile uint8_t *bios)
62 {
63         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
64         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
65         *(volatile uint8_t *)(bios + 0x5555) = 0x80;
66         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
67         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
68         *(volatile uint8_t *)(bios + 0x5555) = 0x20;
69
70         usleep(200);
71 }
72
73 void protect_jedec(volatile uint8_t *bios)
74 {
75         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
76         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
77         *(volatile uint8_t *)(bios + 0x5555) = 0xA0;
78
79         usleep(200);
80 }
81
82 int probe_jedec(struct flashchip *flash)
83 {
84         volatile uint8_t *bios = flash->virtual_memory;
85         uint8_t id1, id2;
86         uint32_t largeid1, largeid2;
87
88         /* Issue JEDEC Product ID Entry command */
89         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
90         myusec_delay(10);
91         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
92         myusec_delay(10);
93         *(volatile uint8_t *)(bios + 0x5555) = 0x90;
94         /* Older chips may need up to 100 us to respond. The ATMEL 29C020
95          * needs 10 ms according to the data sheet, but it has been tested
96          * to work reliably with 20 us. Allow a factor of 2 safety margin.
97          */
98         myusec_delay(40);
99
100         /* Read product ID */
101         id1 = *(volatile uint8_t *)bios;
102         id2 = *(volatile uint8_t *)(bios + 0x01);
103         largeid1 = id1;
104         largeid2 = id2;
105
106         /* Check if it is a continuation ID, this should be a while loop. */
107         if (id1 == 0x7F) {
108                 largeid1 <<= 8;
109                 id1 = *(volatile uint8_t *)(bios + 0x100);
110                 largeid1 |= id1;
111         }
112         if (id2 == 0x7F) {
113                 largeid2 <<= 8;
114                 id2 = *(volatile uint8_t *)(bios + 0x101);
115                 largeid2 |= id2;
116         }
117
118         /* Issue JEDEC Product ID Exit command */
119         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
120         myusec_delay(10);
121         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
122         myusec_delay(10);
123         *(volatile uint8_t *)(bios + 0x5555) = 0xF0;
124         myusec_delay(40);
125
126         printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, largeid1, largeid2);
127         if (largeid1 == flash->manufacture_id && largeid2 == flash->model_id)
128                 return 1;
129
130         return 0;
131 }
132
133 int erase_sector_jedec(volatile uint8_t *bios, unsigned int page)
134 {
135         /*  Issue the Sector Erase command   */
136         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
137         myusec_delay(10);
138         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
139         myusec_delay(10);
140         *(volatile uint8_t *)(bios + 0x5555) = 0x80;
141         myusec_delay(10);
142
143         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
144         myusec_delay(10);
145         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
146         myusec_delay(10);
147         *(volatile uint8_t *)(bios + page) = 0x30;
148         myusec_delay(10);
149
150         /* wait for Toggle bit ready         */
151         toggle_ready_jedec(bios);
152
153         return 0;
154 }
155
156 int erase_block_jedec(volatile uint8_t *bios, unsigned int block)
157 {
158         /*  Issue the Sector Erase command   */
159         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
160         myusec_delay(10);
161         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
162         myusec_delay(10);
163         *(volatile uint8_t *)(bios + 0x5555) = 0x80;
164         myusec_delay(10);
165
166         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
167         myusec_delay(10);
168         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
169         myusec_delay(10);
170         *(volatile uint8_t *)(bios + block) = 0x50;
171         myusec_delay(10);
172
173         /* wait for Toggle bit ready         */
174         toggle_ready_jedec(bios);
175
176         return 0;
177 }
178
179 int erase_chip_jedec(struct flashchip *flash)
180 {
181         volatile uint8_t *bios = flash->virtual_memory;
182
183         /*  Issue the JEDEC Chip Erase command   */
184         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
185         myusec_delay(10);
186         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
187         myusec_delay(10);
188         *(volatile uint8_t *)(bios + 0x5555) = 0x80;
189         myusec_delay(10);
190
191         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
192         myusec_delay(10);
193         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
194         myusec_delay(10);
195         *(volatile uint8_t *)(bios + 0x5555) = 0x10;
196         myusec_delay(10);
197
198         toggle_ready_jedec(bios);
199
200         return 0;
201 }
202
203 int write_page_write_jedec(volatile uint8_t *bios, uint8_t *src,
204                            volatile uint8_t *dst, int page_size)
205 {
206         int i, tried = 0, start_index = 0, ok;
207         volatile uint8_t *d = dst;
208         uint8_t *s = src;
209
210 retry:
211         /* Issue JEDEC Data Unprotect comand */
212         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
213         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
214         *(volatile uint8_t *)(bios + 0x5555) = 0xA0;
215
216         /* transfer data from source to destination */
217         for (i = start_index; i < page_size; i++) {
218                 /* If the data is 0xFF, don't program it */
219                 if (*src != 0xFF)
220                         *dst = *src;
221                 dst++;
222                 src++;
223         }
224
225         toggle_ready_jedec(dst - 1);
226
227         dst = d;
228         src = s;
229         ok = 1;
230         for (i = 0; i < page_size; i++) {
231                 if (*dst != *src) {
232                         ok = 0;
233                         break;
234                 }
235                 dst++;
236                 src++;
237         }
238
239         if (!ok && tried++ < MAX_REFLASH_TRIES) {
240                 start_index = i;
241                 goto retry;
242         }
243         if (!ok) {
244                 fprintf(stderr, " page %d failed!\n",
245                         (unsigned int)(d - bios) / page_size);
246         }
247         return !ok;
248 }
249
250 int write_byte_program_jedec(volatile uint8_t *bios, uint8_t *src,
251                              volatile uint8_t *dst)
252 {
253         int tried = 0, ok = 1;
254
255         /* If the data is 0xFF, don't program it */
256         if (*src == 0xFF) {
257                 return -1;
258         }
259
260 retry:
261         /* Issue JEDEC Byte Program command */
262         *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
263         *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
264         *(volatile uint8_t *)(bios + 0x5555) = 0xA0;
265
266         /* transfer data from source to destination */
267         *dst = *src;
268         toggle_ready_jedec(bios);
269
270         if (*dst != *src && tried++ < MAX_REFLASH_TRIES) {
271                 goto retry;
272         }
273
274         if (tried >= MAX_REFLASH_TRIES)
275                 ok = 0;
276
277         return !ok;
278 }
279
280 int write_sector_jedec(volatile uint8_t *bios, uint8_t *src,
281                        volatile uint8_t *dst, unsigned int page_size)
282 {
283         int i;
284
285         for (i = 0; i < page_size; i++) {
286                 write_byte_program_jedec(bios, src, dst);
287                 dst++, src++;
288         }
289
290         return 0;
291 }
292
293 int write_jedec(struct flashchip *flash, uint8_t *buf)
294 {
295         int i;
296         int total_size = flash->total_size * 1024;
297         int page_size = flash->page_size;
298         volatile uint8_t *bios = flash->virtual_memory;
299
300         erase_chip_jedec(flash);
301         // dumb check if erase was successful.
302         for (i = 0; i < total_size; i++) {
303                 if (bios[i] != (uint8_t) 0xff) {
304                         printf("ERASE FAILED @%d, val %02x!\n", i, bios[i]);
305                         return -1;
306                 }
307         }
308
309         printf("Programming page: ");
310         for (i = 0; i < total_size / page_size; i++) {
311                 printf("%04d at address: 0x%08x", i, i * page_size);
312                 write_page_write_jedec(bios, buf + i * page_size,
313                                        bios + i * page_size, page_size);
314                 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");
315         }
316         printf("\n");
317         protect_jedec(bios);
318
319         return 0;
320 }