blob: 3a90d6b0de6bfcd1b7e6a919d9007bec451b401f [file] [log] [blame]
Claus Gindharta7b35512008-04-28 17:51:09 +00001/*
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
Claus Gindharta7b35512008-04-28 17:51:09 +000019 */
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)
Claus Gindharta7b35512008-04-28 17:51:09 +000027 */
28
Claus Gindharta7b35512008-04-28 17:51:09 +000029#include <string.h>
Carl-Daniel Hailfinger0bd2a2b2009-06-05 18:32:07 +000030#include <stdlib.h>
Claus Gindharta7b35512008-04-28 17:51:09 +000031#include "flash.h"
Carl-Daniel Hailfinger08454642009-06-15 14:14:48 +000032#include "flashchips.h"
Claus Gindharta7b35512008-04-28 17:51:09 +000033
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +000034void protect_stm50flw0x0x(chipaddr bios)
Claus Gindharta7b35512008-04-28 17:51:09 +000035{
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000036 chip_writeb(0xAA, bios + 0x5555);
37 chip_writeb(0x55, bios + 0x2AAA);
38 chip_writeb(0xA0, bios + 0x5555);
Claus Gindharta7b35512008-04-28 17:51:09 +000039
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +000040 programmer_delay(200);
Claus Gindharta7b35512008-04-28 17:51:09 +000041}
42
43int probe_stm50flw0x0x(struct flashchip *flash)
44{
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +000045 chipaddr bios = flash->virtual_memory;
Claus Gindharta7b35512008-04-28 17:51:09 +000046 uint8_t id1, id2;
47 uint32_t largeid1, largeid2;
48
49 /* Issue JEDEC Product ID Entry command */
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000050 chip_writeb(0xAA, bios + 0x5555);
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +000051 programmer_delay(10);
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000052 chip_writeb(0x55, bios + 0x2AAA);
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +000053 programmer_delay(10);
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000054 chip_writeb(0x90, bios + 0x5555);
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +000055 programmer_delay(40);
Claus Gindharta7b35512008-04-28 17:51:09 +000056
57 /* Read product ID */
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000058 id1 = chip_readb(bios);
59 id2 = chip_readb(bios + 0x01);
Claus Gindharta7b35512008-04-28 17:51:09 +000060 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;
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000066 id1 = chip_readb(bios + 0x100);
Claus Gindharta7b35512008-04-28 17:51:09 +000067 largeid1 |= id1;
68 }
69 if (id2 == 0x7F) {
70 largeid2 <<= 8;
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000071 id2 = chip_readb(bios + 0x101);
Claus Gindharta7b35512008-04-28 17:51:09 +000072 largeid2 |= id2;
73 }
74
75 /* Issue JEDEC Product ID Exit command */
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000076 chip_writeb(0xAA, bios + 0x5555);
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +000077 programmer_delay(10);
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000078 chip_writeb(0x55, bios + 0x2AAA);
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +000079 programmer_delay(10);
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000080 chip_writeb(0xF0, bios + 0x5555);
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +000081 programmer_delay(40);
Claus Gindharta7b35512008-04-28 17:51:09 +000082
Uwe Hermann04aa59a2009-09-02 22:09:00 +000083 printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __func__, largeid1,
Claus Gindharta7b35512008-04-28 17:51:09 +000084 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
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +000094static void wait_stm50flw0x0x(chipaddr bios)
Claus Gindharta7b35512008-04-28 17:51:09 +000095{
96 uint8_t id1;
97 // id2;
98
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000099 chip_writeb(0x70, bios);
100 if ((chip_readb(bios) & 0x80) == 0) { // it's busy
101 while ((chip_readb(bios) & 0x80) == 0) ;
Claus Gindharta7b35512008-04-28 17:51:09 +0000102 }
103 // put another command to get out of status register mode
104
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000105 chip_writeb(0x90, bios);
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +0000106 programmer_delay(10);
Claus Gindharta7b35512008-04-28 17:51:09 +0000107
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000108 id1 = chip_readb(bios);
Claus Gindharta7b35512008-04-28 17:51:09 +0000109
110 // this is needed to jam it out of "read id" mode
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000111 chip_writeb(0xAA, bios + 0x5555);
112 chip_writeb(0x55, bios + 0x2AAA);
113 chip_writeb(0xF0, bios + 0x5555);
Claus Gindharta7b35512008-04-28 17:51:09 +0000114}
115
116/*
117 * claus.gindhart@kontron.com
118 * The ST M50FLW080B and STM50FLW080B chips have to be unlocked,
Uwe Hermann394131e2008-10-18 21:14:13 +0000119 * before you can erase them or write to them.
120 */
Claus Gindharta7b35512008-04-28 17:51:09 +0000121int unlock_block_stm50flw0x0x(struct flashchip *flash, int offset)
122{
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000123 chipaddr wrprotect = flash->virtual_registers + 2;
Claus Gindharta7b35512008-04-28 17:51:09 +0000124 const uint8_t unlock_sector = 0x00;
125 int j;
126
Uwe Hermann394131e2008-10-18 21:14:13 +0000127 /*
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 */
Claus Gindharta7b35512008-04-28 17:51:09 +0000135
Uwe Hermann394131e2008-10-18 21:14:13 +0000136 /* Check, if it's is a top/bottom-block with 4k-sectors. */
137 /* TODO: What about the other types? */
Claus Gindharta7b35512008-04-28 17:51:09 +0000138 if ((offset == 0) ||
Uwe Hermann394131e2008-10-18 21:14:13 +0000139 (offset == (flash->model_id == ST_M50FLW080A ? 0xE0000 : 0x10000))
140 || (offset == 0xF0000)) {
Claus Gindharta7b35512008-04-28 17:51:09 +0000141
142 // unlock each 4k-sector
143 for (j = 0; j < 0x10000; j += 0x1000) {
144 printf_debug("unlocking at 0x%x\n", offset + j);
Carl-Daniel Hailfingerd13775e2009-05-11 20:04:30 +0000145 chip_writeb(unlock_sector, wrprotect + offset + j);
146 if (chip_readb(wrprotect + offset + j) != unlock_sector) {
Uwe Hermann394131e2008-10-18 21:14:13 +0000147 printf("Cannot unlock sector @ 0x%x\n",
148 offset + j);
Claus Gindharta7b35512008-04-28 17:51:09 +0000149 return -1;
150 }
151 }
152 } else {
153 printf_debug("unlocking at 0x%x\n", offset);
Carl-Daniel Hailfingerd13775e2009-05-11 20:04:30 +0000154 chip_writeb(unlock_sector, wrprotect + offset);
155 if (chip_readb(wrprotect + offset) != unlock_sector) {
Claus Gindharta7b35512008-04-28 17:51:09 +0000156 printf("Cannot unlock sector @ 0x%x\n", offset);
157 return -1;
158 }
159 }
160
161 return 0;
162}
163
164int erase_block_stm50flw0x0x(struct flashchip *flash, int offset)
165{
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000166 chipaddr bios = flash->virtual_memory + offset;
Claus Gindharta7b35512008-04-28 17:51:09 +0000167
168 // clear status register
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000169 chip_writeb(0x50, bios);
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000170 printf_debug("Erase at 0x%lx\n", bios);
Claus Gindharta7b35512008-04-28 17:51:09 +0000171 // now start it
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000172 chip_writeb(0x20, bios);
173 chip_writeb(0xd0, bios);
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +0000174 programmer_delay(10);
Claus Gindharta7b35512008-04-28 17:51:09 +0000175
176 wait_stm50flw0x0x(flash->virtual_memory);
177
Carl-Daniel Hailfinger30f7cb22009-06-15 17:23:36 +0000178 if (check_erased_range(flash, offset, flash->page_size)) {
179 fprintf(stderr, "ERASE FAILED!\n");
180 return -1;
Claus Gindharta7b35512008-04-28 17:51:09 +0000181 }
Claus Gindharta7b35512008-04-28 17:51:09 +0000182 printf("DONE BLOCK 0x%x\n", offset);
183
184 return 0;
185}
186
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000187int write_page_stm50flw0x0x(chipaddr bios, uint8_t *src,
188 chipaddr dst, int page_size)
Claus Gindharta7b35512008-04-28 17:51:09 +0000189{
Uwe Hermann394131e2008-10-18 21:14:13 +0000190 int i, rc = 0;
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000191 chipaddr d = dst;
Claus Gindharta7b35512008-04-28 17:51:09 +0000192 uint8_t *s = src;
193
194 /* transfer data from source to destination */
195 for (i = 0; i < page_size; i++) {
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000196 chip_writeb(0x40, dst);
197 chip_writeb(*src++, dst++);
Claus Gindharta7b35512008-04-28 17:51:09 +0000198 wait_stm50flw0x0x(bios);
199 }
200
201/* claus.gindhart@kontron.com
202 * TODO
203 * I think, that verification is not required, but
204 * i leave it in anyway
205 */
206 dst = d;
207 src = s;
208 for (i = 0; i < page_size; i++) {
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000209 if (chip_readb(dst) != *src) {
Claus Gindharta7b35512008-04-28 17:51:09 +0000210 rc = -1;
211 break;
212 }
213 dst++;
214 src++;
215 }
216
217 if (rc) {
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000218 fprintf(stderr, " page 0x%lx failed!\n",
219 (d - bios) / page_size);
Claus Gindharta7b35512008-04-28 17:51:09 +0000220 }
221
222 return rc;
223}
224
225/* I simply erase block by block
226 * I Chip This is not the fastest way, but it works
227 */
228int erase_stm50flw0x0x(struct flashchip *flash)
229{
Carl-Daniel Hailfinger30f7cb22009-06-15 17:23:36 +0000230 int i;
Claus Gindharta7b35512008-04-28 17:51:09 +0000231 int total_size = flash->total_size * 1024;
232 int page_size = flash->page_size;
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000233 chipaddr bios = flash->virtual_memory;
Claus Gindharta7b35512008-04-28 17:51:09 +0000234
235 printf("Erasing page:\n");
Carl-Daniel Hailfinger30f7cb22009-06-15 17:23:36 +0000236 for (i = 0; i < total_size / page_size; i++) {
Claus Gindharta7b35512008-04-28 17:51:09 +0000237 printf
238 ("\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");
239 printf("%04d at address: 0x%08x ", i, i * page_size);
Carl-Daniel Hailfinger30f7cb22009-06-15 17:23:36 +0000240 if (unlock_block_stm50flw0x0x(flash, i * page_size)) {
241 fprintf(stderr, "UNLOCK FAILED!\n");
242 return -1;
243 }
244 if (erase_block_stm50flw0x0x(flash, i * page_size)) {
245 fprintf(stderr, "ERASE FAILED!\n");
246 return -1;
247 }
Claus Gindharta7b35512008-04-28 17:51:09 +0000248 }
249 printf("\n");
250 protect_stm50flw0x0x(bios);
251
Carl-Daniel Hailfinger30f7cb22009-06-15 17:23:36 +0000252 return 0;
Claus Gindharta7b35512008-04-28 17:51:09 +0000253}
254
255int write_stm50flw0x0x(struct flashchip *flash, uint8_t * buf)
256{
Uwe Hermann394131e2008-10-18 21:14:13 +0000257 int i, rc = 0;
Claus Gindharta7b35512008-04-28 17:51:09 +0000258 int total_size = flash->total_size * 1024;
259 int page_size = flash->page_size;
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000260 chipaddr bios = flash->virtual_memory;
Carl-Daniel Hailfinger0bd2a2b2009-06-05 18:32:07 +0000261 uint8_t *tmpbuf = malloc(page_size);
Claus Gindharta7b35512008-04-28 17:51:09 +0000262
Carl-Daniel Hailfinger0bd2a2b2009-06-05 18:32:07 +0000263 if (!tmpbuf) {
264 printf("Could not allocate memory!\n");
265 exit(1);
266 }
Claus Gindharta7b35512008-04-28 17:51:09 +0000267 printf("Programming page: \n");
Uwe Hermann394131e2008-10-18 21:14:13 +0000268 for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
Claus Gindharta7b35512008-04-28 17:51:09 +0000269 printf
270 ("\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");
271 printf("%04d at address: 0x%08x ", i, i * page_size);
272
273 /* Auto Skip Blocks, which already contain the desired data
274 * Faster, because we only write, what has changed
275 * More secure, because blocks, which are excluded
276 * (with the exclude or layout feature)
277 * are not erased and rewritten; data is retained also
278 * in sudden power off situations
279 */
Carl-Daniel Hailfinger0bd2a2b2009-06-05 18:32:07 +0000280 chip_readn(tmpbuf, bios + i * page_size, page_size);
281 if (!memcmp((void *)(buf + i * page_size), tmpbuf, page_size)) {
Claus Gindharta7b35512008-04-28 17:51:09 +0000282 printf("SKIPPED\n");
283 continue;
284 }
285
286 rc = unlock_block_stm50flw0x0x(flash, i * page_size);
Uwe Hermann394131e2008-10-18 21:14:13 +0000287 if (!rc)
288 rc = erase_block_stm50flw0x0x(flash, i * page_size);
289 if (!rc)
290 write_page_stm50flw0x0x(bios, buf + i * page_size,
291 bios + i * page_size, page_size);
Claus Gindharta7b35512008-04-28 17:51:09 +0000292 }
293 printf("\n");
294 protect_stm50flw0x0x(bios);
Carl-Daniel Hailfinger0bd2a2b2009-06-05 18:32:07 +0000295 free(tmpbuf);
Claus Gindharta7b35512008-04-28 17:51:09 +0000296
297 return rc;
298}