blob: a40da76885650a7a37d79c75782736ff75aa42d7 [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
29#include <stdio.h>
30#include <string.h>
31#include <stdint.h>
32#include "flash.h"
33
34void protect_stm50flw0x0x(volatile uint8_t *bios)
35{
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
40 usleep(200);
41}
42
43int 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 */
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000050 chip_writeb(0xAA, bios + 0x5555);
Claus Gindharta7b35512008-04-28 17:51:09 +000051 myusec_delay(10);
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000052 chip_writeb(0x55, bios + 0x2AAA);
Claus Gindharta7b35512008-04-28 17:51:09 +000053 myusec_delay(10);
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000054 chip_writeb(0x90, bios + 0x5555);
Claus Gindharta7b35512008-04-28 17:51:09 +000055 myusec_delay(40);
56
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);
Claus Gindharta7b35512008-04-28 17:51:09 +000077 myusec_delay(10);
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000078 chip_writeb(0x55, bios + 0x2AAA);
Claus Gindharta7b35512008-04-28 17:51:09 +000079 myusec_delay(10);
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +000080 chip_writeb(0xF0, bios + 0x5555);
Claus Gindharta7b35512008-04-28 17:51:09 +000081 myusec_delay(40);
82
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
Claus Gindharta7b35512008-04-28 17:51:09 +000094static void wait_stm50flw0x0x(volatile uint8_t *bios)
95{
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);
Claus Gindharta7b35512008-04-28 17:51:09 +0000106 myusec_delay(10);
107
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{
123 volatile uint8_t *flash_addr = flash->virtual_registers + 2;
124 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 Hailfinger0472f3d2009-03-06 22:26:00 +0000145 chip_writeb(unlock_sector, flash_addr + offset + j);
146 if (chip_readb(flash_addr + 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 Hailfinger0472f3d2009-03-06 22:26:00 +0000154 chip_writeb(unlock_sector, flash_addr + offset);
155 if (chip_readb(flash_addr + 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{
166 volatile uint8_t *bios = flash->virtual_memory + offset;
167 int j;
168
169 // clear status register
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000170 chip_writeb(0x50, bios);
Claus Gindharta7b35512008-04-28 17:51:09 +0000171 printf_debug("Erase at %p\n", bios);
172 // now start it
Carl-Daniel Hailfinger0472f3d2009-03-06 22:26:00 +0000173 chip_writeb(0x20, bios);
174 chip_writeb(0xd0, bios);
Claus Gindharta7b35512008-04-28 17:51:09 +0000175 myusec_delay(10);
176
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
191int write_page_stm50flw0x0x(volatile uint8_t *bios, uint8_t *src,
Uwe Hermann394131e2008-10-18 21:14:13 +0000192 volatile uint8_t *dst, int page_size)
Claus Gindharta7b35512008-04-28 17:51:09 +0000193{
Uwe Hermann394131e2008-10-18 21:14:13 +0000194 int i, rc = 0;
Claus Gindharta7b35512008-04-28 17:51:09 +0000195 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++) {
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) {
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 */
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;
237 volatile uint8_t *bios = flash->virtual_memory;
238
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;
259 volatile uint8_t *bios = flash->virtual_memory;
260
261 printf("Programming page: \n");
Uwe Hermann394131e2008-10-18 21:14:13 +0000262 for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
Claus Gindharta7b35512008-04-28 17:51:09 +0000263 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);
Uwe Hermann394131e2008-10-18 21:14:13 +0000281 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);
Claus Gindharta7b35512008-04-28 17:51:09 +0000286 }
287 printf("\n");
288 protect_stm50flw0x0x(bios);
289
290 return rc;
291}