blob: cf00b83a09bd50a2c2c119b1b74f7918b1aefab1 [file] [log] [blame]
hailfingerf8993012010-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 *
hailfingerf8993012010-12-05 16:33:59 +000017 */
18
19#include "flash.h"
hailfingerf8993012010-12-05 16:33:59 +000020
Souvik Ghoshd75cd672016-06-17 14:21:39 -070021static int printlock_w39_fwh_block(struct flashctx *flash, unsigned int offset)
hailfingerf8993012010-12-05 16:33:59 +000022{
23 chipaddr wrprotect = flash->virtual_registers + offset + 2;
24 uint8_t locking;
25
Souvik Ghoshd75cd672016-06-17 14:21:39 -070026 locking = chip_readb(flash, wrprotect);
hailfingerf8993012010-12-05 16:33:59 +000027 msg_cdbg("Lock status of block at 0x%08x is ", offset);
28 switch (locking & 0x7) {
29 case 0:
30 msg_cdbg("Full Access.\n");
31 break;
32 case 1:
33 msg_cdbg("Write Lock (Default State).\n");
34 break;
35 case 2:
36 msg_cdbg("Locked Open (Full Access, Lock Down).\n");
37 break;
38 case 3:
39 msg_cerr("Error: Write Lock, Locked Down.\n");
40 break;
41 case 4:
42 msg_cdbg("Read Lock.\n");
43 break;
44 case 5:
45 msg_cdbg("Read/Write Lock.\n");
46 break;
47 case 6:
48 msg_cerr("Error: Read Lock, Locked Down.\n");
49 break;
50 case 7:
51 msg_cerr("Error: Read/Write Lock, Locked Down.\n");
52 break;
53 }
54
55 /* Read or write lock present? */
56 return (locking & ((1 << 2) | (1 << 0))) ? -1 : 0;
57}
58
Souvik Ghoshd75cd672016-06-17 14:21:39 -070059static int unlock_w39_fwh_block(struct flashctx *flash, unsigned int offset)
hailfingerf8993012010-12-05 16:33:59 +000060{
61 chipaddr wrprotect = flash->virtual_registers + offset + 2;
62 uint8_t locking;
63
Souvik Ghoshd75cd672016-06-17 14:21:39 -070064 locking = chip_readb(flash, wrprotect);
hailfingerf8993012010-12-05 16:33:59 +000065 /* Read or write lock present? */
66 if (locking & ((1 << 2) | (1 << 0))) {
67 /* Lockdown active? */
68 if (locking & (1 << 1)) {
stefanctdfd58832011-07-25 20:38:52 +000069 msg_cerr("Can't unlock block at 0x%08x!\n", offset);
hailfingerf8993012010-12-05 16:33:59 +000070 return -1;
71 } else {
stefanctdfd58832011-07-25 20:38:52 +000072 msg_cdbg("Unlocking block at 0x%08x\n", offset);
Souvik Ghoshd75cd672016-06-17 14:21:39 -070073 chip_writeb(flash, 0, wrprotect);
hailfingerf8993012010-12-05 16:33:59 +000074 }
75 }
76
77 return 0;
78}
79
Souvik Ghoshd75cd672016-06-17 14:21:39 -070080static uint8_t w39_idmode_readb(struct flashctx *flash, unsigned int offset)
hailfingerf8993012010-12-05 16:33:59 +000081{
82 chipaddr bios = flash->virtual_memory;
83 uint8_t val;
84
85 /* Product Identification Entry */
Souvik Ghoshd75cd672016-06-17 14:21:39 -070086 chip_writeb(flash, 0xAA, bios + 0x5555);
87 chip_writeb(flash, 0x55, bios + 0x2AAA);
88 chip_writeb(flash, 0x90, bios + 0x5555);
hailfingerf8993012010-12-05 16:33:59 +000089 programmer_delay(10);
90
91 /* Read something, maybe hardware lock bits */
Souvik Ghoshd75cd672016-06-17 14:21:39 -070092 val = chip_readb(flash, bios + offset);
hailfingerf8993012010-12-05 16:33:59 +000093
94 /* Product Identification Exit */
Souvik Ghoshd75cd672016-06-17 14:21:39 -070095 chip_writeb(flash, 0xAA, bios + 0x5555);
96 chip_writeb(flash, 0x55, bios + 0x2AAA);
97 chip_writeb(flash, 0xF0, bios + 0x5555);
hailfingerf8993012010-12-05 16:33:59 +000098 programmer_delay(10);
99
100 return val;
101}
102
103static int printlock_w39_tblwp(uint8_t lock)
104{
105 msg_cdbg("Hardware bootblock locking (#TBL) is %sactive.\n",
106 (lock & (1 << 2)) ? "" : "not ");
107 msg_cdbg("Hardware remaining chip locking (#WP) is %sactive..\n",
108 (lock & (1 << 3)) ? "" : "not ");
109 if (lock & ((1 << 2) | (1 << 3)))
110 return -1;
111
112 return 0;
113}
114
115static int printlock_w39_bootblock_64k16k(uint8_t lock)
116{
117 msg_cdbg("Software 64 kB bootblock locking is %sactive.\n",
118 (lock & (1 << 0)) ? "" : "not ");
119 msg_cdbg("Software 16 kB bootblock locking is %sactive.\n",
120 (lock & (1 << 1)) ? "" : "not ");
121 if (lock & ((1 << 1) | (1 << 0)))
122 return -1;
123
124 return 0;
125}
126
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700127static int printlock_w39_common(struct flashctx *flash, unsigned int offset)
hailfingerf8993012010-12-05 16:33:59 +0000128{
129 uint8_t lock;
130
131 lock = w39_idmode_readb(flash, offset);
132 msg_cdbg("Lockout bits:\n");
133 return printlock_w39_tblwp(lock);
134}
135
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700136static int printlock_w39_fwh(struct flashctx *flash)
hailfingerf8993012010-12-05 16:33:59 +0000137{
Patrick Georgif3fa2992017-02-02 16:24:44 +0100138 unsigned int i, total_size = flash->chip->total_size * 1024;
hailfingerf8993012010-12-05 16:33:59 +0000139 int ret = 0;
140
141 /* Print lock status of the complete chip */
Patrick Georgif3fa2992017-02-02 16:24:44 +0100142 for (i = 0; i < total_size; i += flash->chip->page_size)
hailfingerf8993012010-12-05 16:33:59 +0000143 ret |= printlock_w39_fwh_block(flash, i);
144
145 return ret;
146}
147
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700148static int unlock_w39_fwh(struct flashctx *flash)
hailfingerf8993012010-12-05 16:33:59 +0000149{
Patrick Georgif3fa2992017-02-02 16:24:44 +0100150 unsigned int i, total_size = flash->chip->total_size * 1024;
hailfingerf8993012010-12-05 16:33:59 +0000151
152 /* Unlock the complete chip */
Patrick Georgif3fa2992017-02-02 16:24:44 +0100153 for (i = 0; i < total_size; i += flash->chip->page_size)
hailfingerf8993012010-12-05 16:33:59 +0000154 if (unlock_w39_fwh_block(flash, i))
155 return -1;
156
157 return 0;
158}
159
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700160int printlock_w39l040(struct flashctx *flash)
mkarcherb8f55a62011-03-06 17:58:05 +0000161{
162 uint8_t lock;
163 int ret;
164
165 lock = w39_idmode_readb(flash, 0x00002);
166 msg_cdbg("Bottom boot block:\n");
167 ret = printlock_w39_bootblock_64k16k(lock);
168
169 lock = w39_idmode_readb(flash, 0x7fff2);
170 msg_cdbg("Top boot block:\n");
171 ret |= printlock_w39_bootblock_64k16k(lock);
172
173 return ret;
174}
175
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700176int printlock_w39v040a(struct flashctx *flash)
hailfingerf8993012010-12-05 16:33:59 +0000177{
178 uint8_t lock;
179 int ret = 0;
180
181 /* The W39V040A datasheet contradicts itself on the lock register
182 * location: 0x00002 and 0x7fff2 are both mentioned. Pick the one
183 * which is similar to the other chips of the same family.
184 */
185 lock = w39_idmode_readb(flash, 0x7fff2);
186 msg_cdbg("Lockout bits:\n");
187
188 ret = printlock_w39_tblwp(lock);
189 ret |= printlock_w39_bootblock_64k16k(lock);
190
191 return ret;
192}
193
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700194int printlock_w39v040b(struct flashctx *flash)
hailfingerf8993012010-12-05 16:33:59 +0000195{
196 return printlock_w39_common(flash, 0x7fff2);
197}
198
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700199int printlock_w39v040c(struct flashctx *flash)
hailfingerf8993012010-12-05 16:33:59 +0000200{
201 /* Typo in the datasheet? The other chips use 0x7fff2. */
202 return printlock_w39_common(flash, 0xfff2);
203}
204
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700205int printlock_w39v040fa(struct flashctx *flash)
hailfingerf8993012010-12-05 16:33:59 +0000206{
207 int ret = 0;
208
209 ret = printlock_w39v040a(flash);
210 ret |= printlock_w39_fwh(flash);
211
212 return ret;
213}
214
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700215int printlock_w39v040fb(struct flashctx *flash)
hailfingerf8993012010-12-05 16:33:59 +0000216{
217 int ret = 0;
218
219 ret = printlock_w39v040b(flash);
220 ret |= printlock_w39_fwh(flash);
221
222 return ret;
223}
224
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700225int printlock_w39v040fc(struct flashctx *flash)
hailfingerf8993012010-12-05 16:33:59 +0000226{
227 int ret = 0;
228
229 /* W39V040C and W39V040FC use different WP/TBL offsets. */
230 ret = printlock_w39_common(flash, 0x7fff2);
231 ret |= printlock_w39_fwh(flash);
232
233 return ret;
234}
235
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700236int printlock_w39v080a(struct flashctx *flash)
hailfingerf8993012010-12-05 16:33:59 +0000237{
238 return printlock_w39_common(flash, 0xffff2);
239}
240
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700241int printlock_w39v080fa(struct flashctx *flash)
hailfingerf8993012010-12-05 16:33:59 +0000242{
243 int ret = 0;
244
245 ret = printlock_w39v080a(flash);
246 ret |= printlock_w39_fwh(flash);
247
248 return ret;
249}
250
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700251int printlock_w39v080fa_dual(struct flashctx *flash)
hailfingerf8993012010-12-05 16:33:59 +0000252{
253 msg_cinfo("Block locking for W39V080FA in dual mode is "
254 "undocumented.\n");
255 /* Better safe than sorry. */
256 return -1;
257}
258
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700259int unlock_w39v040fb(struct flashctx *flash)
mkarcher64dbd922010-12-26 23:55:12 +0000260{
261 if (unlock_w39_fwh(flash))
262 return -1;
263 if (printlock_w39_common(flash, 0x7fff2))
264 return -1;
265
266 return 0;
267}
268
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700269int unlock_w39v080fa(struct flashctx *flash)
hailfingerf8993012010-12-05 16:33:59 +0000270{
271 if (unlock_w39_fwh(flash))
272 return -1;
273 if (printlock_w39_common(flash, 0xffff2))
274 return -1;
275
276 return 0;
277}
Alan Greenebbee922019-09-02 11:36:59 +1000278
279int printlock_at49f(struct flashctx *flash)
280{
281 uint8_t lock = w39_idmode_readb(flash, 0x00002);
282 msg_cdbg("Hardware bootblock lockout is %sactive.\n",
283 (lock & 0x01) ? "" : "not ");
284 return 0;
285}