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