blob: a68b9ad4e7cbdeea740b8162ab5c36c3815386cf [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
Peter Stuge5cafc332009-01-25 23:52:45 +000083 printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, 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 int j;
168
169 // clear status register
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000170 chip_writeb(0x50, bios);
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000171 printf_debug("Erase at 0x%lx\n", bios);
Claus Gindharta7b35512008-04-28 17:51:09 +0000172 // now start it
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000173 chip_writeb(0x20, bios);
174 chip_writeb(0xd0, bios);
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +0000175 programmer_delay(10);
Claus Gindharta7b35512008-04-28 17:51:09 +0000176
177 wait_stm50flw0x0x(flash->virtual_memory);
178
179 for (j = 0; j < flash->page_size; j++) {
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000180 if (chip_readb(bios + j) != 0xFF) {
Claus Gindharta7b35512008-04-28 17:51:09 +0000181 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
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000191int write_page_stm50flw0x0x(chipaddr bios, uint8_t *src,
192 chipaddr dst, int page_size)
Claus Gindharta7b35512008-04-28 17:51:09 +0000193{
Uwe Hermann394131e2008-10-18 21:14:13 +0000194 int i, rc = 0;
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000195 chipaddr d = dst;
Claus Gindharta7b35512008-04-28 17:51:09 +0000196 uint8_t *s = src;
197
198 /* transfer data from source to destination */
199 for (i = 0; i < page_size; i++) {
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000200 chip_writeb(0x40, dst);
201 chip_writeb(*src++, dst++);
Claus Gindharta7b35512008-04-28 17:51:09 +0000202 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++) {
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000213 if (chip_readb(dst) != *src) {
Claus Gindharta7b35512008-04-28 17:51:09 +0000214 rc = -1;
215 break;
216 }
217 dst++;
218 src++;
219 }
220
221 if (rc) {
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000222 fprintf(stderr, " page 0x%lx failed!\n",
223 (d - bios) / page_size);
Claus Gindharta7b35512008-04-28 17:51:09 +0000224 }
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 */
232int erase_stm50flw0x0x(struct flashchip *flash)
233{
Uwe Hermann394131e2008-10-18 21:14:13 +0000234 int i, rc = 0;
Claus Gindharta7b35512008-04-28 17:51:09 +0000235 int total_size = flash->total_size * 1024;
236 int page_size = flash->page_size;
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000237 chipaddr bios = flash->virtual_memory;
Claus Gindharta7b35512008-04-28 17:51:09 +0000238
239 printf("Erasing page:\n");
Uwe Hermann394131e2008-10-18 21:14:13 +0000240 for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
Claus Gindharta7b35512008-04-28 17:51:09 +0000241 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);
Uwe Hermann394131e2008-10-18 21:14:13 +0000245 if (!rc)
246 rc = erase_block_stm50flw0x0x(flash, i * page_size);
Claus Gindharta7b35512008-04-28 17:51:09 +0000247 }
248 printf("\n");
249 protect_stm50flw0x0x(bios);
250
251 return rc;
252}
253
254int write_stm50flw0x0x(struct flashchip *flash, uint8_t * buf)
255{
Uwe Hermann394131e2008-10-18 21:14:13 +0000256 int i, rc = 0;
Claus Gindharta7b35512008-04-28 17:51:09 +0000257 int total_size = flash->total_size * 1024;
258 int page_size = flash->page_size;
Carl-Daniel Hailfinger5820f422009-05-16 21:22:56 +0000259 chipaddr bios = flash->virtual_memory;
Carl-Daniel Hailfinger0bd2a2b2009-06-05 18:32:07 +0000260 uint8_t *tmpbuf = malloc(page_size);
Claus Gindharta7b35512008-04-28 17:51:09 +0000261
Carl-Daniel Hailfinger0bd2a2b2009-06-05 18:32:07 +0000262 if (!tmpbuf) {
263 printf("Could not allocate memory!\n");
264 exit(1);
265 }
Claus Gindharta7b35512008-04-28 17:51:09 +0000266 printf("Programming page: \n");
Uwe Hermann394131e2008-10-18 21:14:13 +0000267 for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
Claus Gindharta7b35512008-04-28 17:51:09 +0000268 printf
269 ("\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");
270 printf("%04d at address: 0x%08x ", i, i * page_size);
271
272 /* Auto Skip Blocks, which already contain the desired data
273 * Faster, because we only write, what has changed
274 * More secure, because blocks, which are excluded
275 * (with the exclude or layout feature)
276 * are not erased and rewritten; data is retained also
277 * in sudden power off situations
278 */
Carl-Daniel Hailfinger0bd2a2b2009-06-05 18:32:07 +0000279 chip_readn(tmpbuf, bios + i * page_size, page_size);
280 if (!memcmp((void *)(buf + i * page_size), tmpbuf, page_size)) {
Claus Gindharta7b35512008-04-28 17:51:09 +0000281 printf("SKIPPED\n");
282 continue;
283 }
284
285 rc = unlock_block_stm50flw0x0x(flash, i * page_size);
Uwe Hermann394131e2008-10-18 21:14:13 +0000286 if (!rc)
287 rc = erase_block_stm50flw0x0x(flash, i * page_size);
288 if (!rc)
289 write_page_stm50flw0x0x(bios, buf + i * page_size,
290 bios + i * page_size, page_size);
Claus Gindharta7b35512008-04-28 17:51:09 +0000291 }
292 printf("\n");
293 protect_stm50flw0x0x(bios);
Carl-Daniel Hailfinger0bd2a2b2009-06-05 18:32:07 +0000294 free(tmpbuf);
Claus Gindharta7b35512008-04-28 17:51:09 +0000295
296 return rc;
297}