trivial patch for abuild: allow powerpc-elf-gcc, too.
[coreboot.git] / util / flashrom / stm50flw0x0x.c
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2008 Claus Gindhart <claus.gindhart@kontron.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 /*
22  * This module is designed for supporting the devices
23  * ST M50FLW040A (not yet tested)
24  * ST M50FLW040B (not yet tested)
25  * ST M50FLW080A
26  * ST M50FLW080B (not yet tested)
27  */
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdint.h>
32 #include "flash.h"
33
34 void protect_stm50flw0x0x(volatile uint8_t *bios)
35 {
36         chip_writeb(0xAA, bios + 0x5555);
37         chip_writeb(0x55, bios + 0x2AAA);
38         chip_writeb(0xA0, bios + 0x5555);
39
40         usleep(200);
41 }
42
43 int probe_stm50flw0x0x(struct flashchip *flash)
44 {
45         volatile uint8_t *bios = flash->virtual_memory;
46         uint8_t id1, id2;
47         uint32_t largeid1, largeid2;
48
49         /* Issue JEDEC Product ID Entry command */
50         chip_writeb(0xAA, bios + 0x5555);
51         myusec_delay(10);
52         chip_writeb(0x55, bios + 0x2AAA);
53         myusec_delay(10);
54         chip_writeb(0x90, bios + 0x5555);
55         myusec_delay(40);
56
57         /* Read product ID */
58         id1 = chip_readb(bios);
59         id2 = chip_readb(bios + 0x01);
60         largeid1 = id1;
61         largeid2 = id2;
62
63         /* Check if it is a continuation ID, this should be a while loop. */
64         if (id1 == 0x7F) {
65                 largeid1 <<= 8;
66                 id1 = chip_readb(bios + 0x100);
67                 largeid1 |= id1;
68         }
69         if (id2 == 0x7F) {
70                 largeid2 <<= 8;
71                 id2 = chip_readb(bios + 0x101);
72                 largeid2 |= id2;
73         }
74
75         /* Issue JEDEC Product ID Exit command */
76         chip_writeb(0xAA, bios + 0x5555);
77         myusec_delay(10);
78         chip_writeb(0x55, bios + 0x2AAA);
79         myusec_delay(10);
80         chip_writeb(0xF0, bios + 0x5555);
81         myusec_delay(40);
82
83         printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, largeid1,
84                      largeid2);
85
86         if (largeid1 != flash->manufacture_id || largeid2 != flash->model_id)
87                 return 0;
88
89         map_flash_registers(flash);
90
91         return 1;
92 }
93
94 static void wait_stm50flw0x0x(volatile uint8_t *bios)
95 {
96         uint8_t id1;
97         // id2;
98
99         chip_writeb(0x70, bios);
100         if ((chip_readb(bios) & 0x80) == 0) {   // it's busy
101                 while ((chip_readb(bios) & 0x80) == 0) ;
102         }
103         // put another command to get out of status register mode
104
105         chip_writeb(0x90, bios);
106         myusec_delay(10);
107
108         id1 = chip_readb(bios);
109
110         // this is needed to jam it out of "read id" mode
111         chip_writeb(0xAA, bios + 0x5555);
112         chip_writeb(0x55, bios + 0x2AAA);
113         chip_writeb(0xF0, bios + 0x5555);
114 }
115
116 /*
117  * claus.gindhart@kontron.com
118  * The ST M50FLW080B and STM50FLW080B chips have to be unlocked,
119  * before you can erase them or write to them.
120  */
121 int unlock_block_stm50flw0x0x(struct flashchip *flash, int offset)
122 {
123         volatile uint8_t *flash_addr = flash->virtual_registers + 2;
124         const uint8_t unlock_sector = 0x00;
125         int j;
126
127         /*
128          * These chips have to be unlocked before you can erase them or write
129          * to them. The size of the locking sectors depends on the type
130          * of chip.
131          *
132          * Sometimes, the BIOS does this for you; so you propably
133          * don't need to worry about that.
134          */
135
136         /* Check, if it's is a top/bottom-block with 4k-sectors. */
137         /* TODO: What about the other types? */
138         if ((offset == 0) ||
139             (offset == (flash->model_id == ST_M50FLW080A ? 0xE0000 : 0x10000))
140             || (offset == 0xF0000)) {
141
142                 // unlock each 4k-sector
143                 for (j = 0; j < 0x10000; j += 0x1000) {
144                         printf_debug("unlocking at 0x%x\n", offset + j);
145                         chip_writeb(unlock_sector, flash_addr + offset + j);
146                         if (chip_readb(flash_addr + offset + j) != unlock_sector) {
147                                 printf("Cannot unlock sector @ 0x%x\n",
148                                        offset + j);
149                                 return -1;
150                         }
151                 }
152         } else {
153                 printf_debug("unlocking at 0x%x\n", offset);
154                 chip_writeb(unlock_sector, flash_addr + offset);
155                 if (chip_readb(flash_addr + offset) != unlock_sector) {
156                         printf("Cannot unlock sector @ 0x%x\n", offset);
157                         return -1;
158                 }
159         }
160
161         return 0;
162 }
163
164 int erase_block_stm50flw0x0x(struct flashchip *flash, int offset)
165 {
166         volatile uint8_t *bios = flash->virtual_memory + offset;
167         int j;
168
169         // clear status register
170         chip_writeb(0x50, bios);
171         printf_debug("Erase at %p\n", bios);
172         // now start it
173         chip_writeb(0x20, bios);
174         chip_writeb(0xd0, bios);
175         myusec_delay(10);
176
177         wait_stm50flw0x0x(flash->virtual_memory);
178
179         for (j = 0; j < flash->page_size; j++) {
180                 if (chip_readb(bios + j) != 0xFF) {
181                         printf("Erase failed at 0x%x\n", offset + j);
182                         return -1;
183                 }
184         }
185
186         printf("DONE BLOCK 0x%x\n", offset);
187
188         return 0;
189 }
190
191 int write_page_stm50flw0x0x(volatile uint8_t *bios, uint8_t *src,
192                             volatile uint8_t *dst, int page_size)
193 {
194         int i, rc = 0;
195         volatile uint8_t *d = dst;
196         uint8_t *s = src;
197
198         /* transfer data from source to destination */
199         for (i = 0; i < page_size; i++) {
200                 chip_writeb(0x40, dst);
201                 chip_writeb(*src++, dst++);
202                 wait_stm50flw0x0x(bios);
203         }
204
205 /* claus.gindhart@kontron.com
206  * TODO
207  * I think, that verification is not required, but
208  * i leave it in anyway
209  */
210         dst = d;
211         src = s;
212         for (i = 0; i < page_size; i++) {
213                 if (chip_readb(dst) != *src) {
214                         rc = -1;
215                         break;
216                 }
217                 dst++;
218                 src++;
219         }
220
221         if (rc) {
222                 fprintf(stderr, " page %d failed!\n",
223                         (unsigned int)(d - bios) / page_size);
224         }
225
226         return rc;
227 }
228
229 /* I simply erase block by block
230  * I Chip This is not the fastest way, but it works
231  */
232 int erase_stm50flw0x0x(struct flashchip *flash)
233 {
234         int i, rc = 0;
235         int total_size = flash->total_size * 1024;
236         int page_size = flash->page_size;
237         volatile uint8_t *bios = flash->virtual_memory;
238
239         printf("Erasing page:\n");
240         for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
241                 printf
242                     ("\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");
243                 printf("%04d at address: 0x%08x ", i, i * page_size);
244                 rc = unlock_block_stm50flw0x0x(flash, i * page_size);
245                 if (!rc)
246                         rc = erase_block_stm50flw0x0x(flash, i * page_size);
247         }
248         printf("\n");
249         protect_stm50flw0x0x(bios);
250
251         return rc;
252 }
253
254 int write_stm50flw0x0x(struct flashchip *flash, uint8_t * buf)
255 {
256         int i, rc = 0;
257         int total_size = flash->total_size * 1024;
258         int page_size = flash->page_size;
259         volatile uint8_t *bios = flash->virtual_memory;
260
261         printf("Programming page: \n");
262         for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
263                 printf
264                     ("\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");
265                 printf("%04d at address: 0x%08x ", i, i * page_size);
266
267                 /* Auto Skip Blocks, which already contain the desired data
268                  * Faster, because we only write, what has changed
269                  * More secure, because blocks, which are excluded
270                  * (with the exclude or layout feature)
271                  * are not erased and rewritten; data is retained also
272                  * in sudden power off situations
273                  */
274                 if (!memcmp((void *)(buf + i * page_size),
275                             (void *)(bios + i * page_size), page_size)) {
276                         printf("SKIPPED\n");
277                         continue;
278                 }
279
280                 rc = unlock_block_stm50flw0x0x(flash, i * page_size);
281                 if (!rc)
282                         rc = erase_block_stm50flw0x0x(flash, i * page_size);
283                 if (!rc)
284                         write_page_stm50flw0x0x(bios, buf + i * page_size,
285                                         bios + i * page_size, page_size);
286         }
287         printf("\n");
288         protect_stm50flw0x0x(bios);
289
290         return rc;
291 }