blob: c06bab97914541122d114209e8c7137d854f9496 [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{
36 *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
37 *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
38 *(volatile uint8_t *)(bios + 0x5555) = 0xA0;
39
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 */
50 *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
51 myusec_delay(10);
52 *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
53 myusec_delay(10);
54 *(volatile uint8_t *)(bios + 0x5555) = 0x90;
55 myusec_delay(40);
56
57 /* Read product ID */
58 id1 = *(volatile uint8_t *)bios;
59 id2 = *(volatile uint8_t *)(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 = *(volatile uint8_t *)(bios + 0x100);
67 largeid1 |= id1;
68 }
69 if (id2 == 0x7F) {
70 largeid2 <<= 8;
71 id2 = *(volatile uint8_t *)(bios + 0x101);
72 largeid2 |= id2;
73 }
74
75 /* Issue JEDEC Product ID Exit command */
76 *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
77 myusec_delay(10);
78 *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
79 myusec_delay(10);
80 *(volatile uint8_t *)(bios + 0x5555) = 0xF0;
81 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
99 *bios = 0x70;
100 if ((*bios & 0x80) == 0) { // it's busy
101 while ((*bios & 0x80) == 0) ;
102 }
103 // put another command to get out of status register mode
104
105 *bios = 0x90;
106 myusec_delay(10);
107
108 id1 = *(volatile uint8_t *)bios;
109
110 // this is needed to jam it out of "read id" mode
111 *(volatile uint8_t *)(bios + 0x5555) = 0xAA;
112 *(volatile uint8_t *)(bios + 0x2AAA) = 0x55;
113 *(volatile uint8_t *)(bios + 0x5555) = 0xF0;
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);
145 *(flash_addr + offset + j) = unlock_sector;
Uwe Hermann394131e2008-10-18 21:14:13 +0000146 if (*(flash_addr + offset + j) != unlock_sector) {
147 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);
154 *(flash_addr + offset) = unlock_sector;
Uwe Hermann394131e2008-10-18 21:14:13 +0000155 if (*(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
170 *bios = 0x50;
171 printf_debug("Erase at %p\n", bios);
172 // now start it
173 *(volatile uint8_t *)(bios) = 0x20;
174 *(volatile uint8_t *)(bios) = 0xd0;
175 myusec_delay(10);
176
177 wait_stm50flw0x0x(flash->virtual_memory);
178
179 for (j = 0; j < flash->page_size; j++) {
180 if (*(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
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++) {
200 *dst = 0x40;
201 *dst++ = *src++;
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 (*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 */
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}