blob: 920a43f5163ef03be88c2170b077284ac7d3ea33 [file] [log] [blame]
Carl-Daniel Hailfinger91882402010-12-05 16:33:59 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2008 coresystems GmbH
5 * Copyright (C) 2010 Carl-Daniel Hailfinger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "flash.h"
23#include "chipdrivers.h"
24
25static int printlock_w39_fwh_block(struct flashchip *flash, int offset)
26{
27 chipaddr wrprotect = flash->virtual_registers + offset + 2;
28 uint8_t locking;
29
30 locking = chip_readb(wrprotect);
31 msg_cdbg("Lock status of block at 0x%08x is ", offset);
32 switch (locking & 0x7) {
33 case 0:
34 msg_cdbg("Full Access.\n");
35 break;
36 case 1:
37 msg_cdbg("Write Lock (Default State).\n");
38 break;
39 case 2:
40 msg_cdbg("Locked Open (Full Access, Lock Down).\n");
41 break;
42 case 3:
43 msg_cerr("Error: Write Lock, Locked Down.\n");
44 break;
45 case 4:
46 msg_cdbg("Read Lock.\n");
47 break;
48 case 5:
49 msg_cdbg("Read/Write Lock.\n");
50 break;
51 case 6:
52 msg_cerr("Error: Read Lock, Locked Down.\n");
53 break;
54 case 7:
55 msg_cerr("Error: Read/Write Lock, Locked Down.\n");
56 break;
57 }
58
59 /* Read or write lock present? */
60 return (locking & ((1 << 2) | (1 << 0))) ? -1 : 0;
61}
62
63static int unlock_w39_fwh_block(struct flashchip *flash, int offset)
64{
65 chipaddr wrprotect = flash->virtual_registers + offset + 2;
66 uint8_t locking;
67
68 locking = chip_readb(wrprotect);
69 /* Read or write lock present? */
70 if (locking & ((1 << 2) | (1 << 0))) {
71 /* Lockdown active? */
72 if (locking & (1 << 1)) {
Stefan Tauner716e0982011-07-25 20:38:52 +000073 msg_cerr("Can't unlock block at 0x%08x!\n", offset);
Carl-Daniel Hailfinger91882402010-12-05 16:33:59 +000074 return -1;
75 } else {
Stefan Tauner716e0982011-07-25 20:38:52 +000076 msg_cdbg("Unlocking block at 0x%08x\n", offset);
Carl-Daniel Hailfinger91882402010-12-05 16:33:59 +000077 chip_writeb(0, wrprotect);
78 }
79 }
80
81 return 0;
82}
83
84static uint8_t w39_idmode_readb(struct flashchip *flash, int offset)
85{
86 chipaddr bios = flash->virtual_memory;
87 uint8_t val;
88
89 /* Product Identification Entry */
90 chip_writeb(0xAA, bios + 0x5555);
91 chip_writeb(0x55, bios + 0x2AAA);
92 chip_writeb(0x90, bios + 0x5555);
93 programmer_delay(10);
94
95 /* Read something, maybe hardware lock bits */
96 val = chip_readb(bios + offset);
97
98 /* Product Identification Exit */
99 chip_writeb(0xAA, bios + 0x5555);
100 chip_writeb(0x55, bios + 0x2AAA);
101 chip_writeb(0xF0, bios + 0x5555);
102 programmer_delay(10);
103
104 return val;
105}
106
107static int printlock_w39_tblwp(uint8_t lock)
108{
109 msg_cdbg("Hardware bootblock locking (#TBL) is %sactive.\n",
110 (lock & (1 << 2)) ? "" : "not ");
111 msg_cdbg("Hardware remaining chip locking (#WP) is %sactive..\n",
112 (lock & (1 << 3)) ? "" : "not ");
113 if (lock & ((1 << 2) | (1 << 3)))
114 return -1;
115
116 return 0;
117}
118
119static int printlock_w39_bootblock_64k16k(uint8_t lock)
120{
121 msg_cdbg("Software 64 kB bootblock locking is %sactive.\n",
122 (lock & (1 << 0)) ? "" : "not ");
123 msg_cdbg("Software 16 kB bootblock locking is %sactive.\n",
124 (lock & (1 << 1)) ? "" : "not ");
125 if (lock & ((1 << 1) | (1 << 0)))
126 return -1;
127
128 return 0;
129}
130
131static int printlock_w39_common(struct flashchip *flash, int offset)
132{
133 uint8_t lock;
134
135 lock = w39_idmode_readb(flash, offset);
136 msg_cdbg("Lockout bits:\n");
137 return printlock_w39_tblwp(lock);
138}
139
140static int printlock_w39_fwh(struct flashchip *flash)
141{
142 int i, total_size = flash->total_size * 1024;
143 int ret = 0;
144
145 /* Print lock status of the complete chip */
146 for (i = 0; i < total_size; i += flash->page_size)
147 ret |= printlock_w39_fwh_block(flash, i);
148
149 return ret;
150}
151
152static int unlock_w39_fwh(struct flashchip *flash)
153{
154 int i, total_size = flash->total_size * 1024;
155
156 /* Unlock the complete chip */
157 for (i = 0; i < total_size; i += flash->page_size)
158 if (unlock_w39_fwh_block(flash, i))
159 return -1;
160
161 return 0;
162}
163
Michael Karcher19e0aac2011-03-06 17:58:05 +0000164int printlock_w39l040(struct flashchip * flash)
165{
166 uint8_t lock;
167 int ret;
168
169 lock = w39_idmode_readb(flash, 0x00002);
170 msg_cdbg("Bottom boot block:\n");
171 ret = printlock_w39_bootblock_64k16k(lock);
172
173 lock = w39_idmode_readb(flash, 0x7fff2);
174 msg_cdbg("Top boot block:\n");
175 ret |= printlock_w39_bootblock_64k16k(lock);
176
177 return ret;
178}
179
Carl-Daniel Hailfinger91882402010-12-05 16:33:59 +0000180int printlock_w39v040a(struct flashchip *flash)
181{
182 uint8_t lock;
183 int ret = 0;
184
185 /* The W39V040A datasheet contradicts itself on the lock register
186 * location: 0x00002 and 0x7fff2 are both mentioned. Pick the one
187 * which is similar to the other chips of the same family.
188 */
189 lock = w39_idmode_readb(flash, 0x7fff2);
190 msg_cdbg("Lockout bits:\n");
191
192 ret = printlock_w39_tblwp(lock);
193 ret |= printlock_w39_bootblock_64k16k(lock);
194
195 return ret;
196}
197
198int printlock_w39v040b(struct flashchip *flash)
199{
200 return printlock_w39_common(flash, 0x7fff2);
201}
202
203int printlock_w39v040c(struct flashchip *flash)
204{
205 /* Typo in the datasheet? The other chips use 0x7fff2. */
206 return printlock_w39_common(flash, 0xfff2);
207}
208
209int printlock_w39v040fa(struct flashchip *flash)
210{
211 int ret = 0;
212
213 ret = printlock_w39v040a(flash);
214 ret |= printlock_w39_fwh(flash);
215
216 return ret;
217}
218
219int printlock_w39v040fb(struct flashchip *flash)
220{
221 int ret = 0;
222
223 ret = printlock_w39v040b(flash);
224 ret |= printlock_w39_fwh(flash);
225
226 return ret;
227}
228
229int printlock_w39v040fc(struct flashchip *flash)
230{
231 int ret = 0;
232
233 /* W39V040C and W39V040FC use different WP/TBL offsets. */
234 ret = printlock_w39_common(flash, 0x7fff2);
235 ret |= printlock_w39_fwh(flash);
236
237 return ret;
238}
239
240int printlock_w39v080a(struct flashchip *flash)
241{
242 return printlock_w39_common(flash, 0xffff2);
243}
244
245int printlock_w39v080fa(struct flashchip *flash)
246{
247 int ret = 0;
248
249 ret = printlock_w39v080a(flash);
250 ret |= printlock_w39_fwh(flash);
251
252 return ret;
253}
254
255int printlock_w39v080fa_dual(struct flashchip *flash)
256{
257 msg_cinfo("Block locking for W39V080FA in dual mode is "
258 "undocumented.\n");
259 /* Better safe than sorry. */
260 return -1;
261}
262
Idwer Volleringecc67072010-12-26 23:55:12 +0000263int unlock_w39v040fb(struct flashchip *flash)
264{
265 if (unlock_w39_fwh(flash))
266 return -1;
267 if (printlock_w39_common(flash, 0x7fff2))
268 return -1;
269
270 return 0;
271}
272
Carl-Daniel Hailfinger91882402010-12-05 16:33:59 +0000273int unlock_w39v080fa(struct flashchip *flash)
274{
275 if (unlock_w39_fwh(flash))
276 return -1;
277 if (printlock_w39_common(flash, 0xffff2))
278 return -1;
279
280 return 0;
281}