blob: 65cf32f4b8fb8f2ee0fdaa5e3475d4322bd4ce1f [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)) {
73 msg_cerr("Can't unlock block at 0x%x!\n", offset);
74 return -1;
75 } else {
76 msg_cdbg("Unlocking block at 0x%x\n", offset);
77 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
164int printlock_w39v040a(struct flashchip *flash)
165{
166 uint8_t lock;
167 int ret = 0;
168
169 /* The W39V040A datasheet contradicts itself on the lock register
170 * location: 0x00002 and 0x7fff2 are both mentioned. Pick the one
171 * which is similar to the other chips of the same family.
172 */
173 lock = w39_idmode_readb(flash, 0x7fff2);
174 msg_cdbg("Lockout bits:\n");
175
176 ret = printlock_w39_tblwp(lock);
177 ret |= printlock_w39_bootblock_64k16k(lock);
178
179 return ret;
180}
181
182int printlock_w39v040b(struct flashchip *flash)
183{
184 return printlock_w39_common(flash, 0x7fff2);
185}
186
187int printlock_w39v040c(struct flashchip *flash)
188{
189 /* Typo in the datasheet? The other chips use 0x7fff2. */
190 return printlock_w39_common(flash, 0xfff2);
191}
192
193int printlock_w39v040fa(struct flashchip *flash)
194{
195 int ret = 0;
196
197 ret = printlock_w39v040a(flash);
198 ret |= printlock_w39_fwh(flash);
199
200 return ret;
201}
202
203int printlock_w39v040fb(struct flashchip *flash)
204{
205 int ret = 0;
206
207 ret = printlock_w39v040b(flash);
208 ret |= printlock_w39_fwh(flash);
209
210 return ret;
211}
212
213int printlock_w39v040fc(struct flashchip *flash)
214{
215 int ret = 0;
216
217 /* W39V040C and W39V040FC use different WP/TBL offsets. */
218 ret = printlock_w39_common(flash, 0x7fff2);
219 ret |= printlock_w39_fwh(flash);
220
221 return ret;
222}
223
224int printlock_w39v080a(struct flashchip *flash)
225{
226 return printlock_w39_common(flash, 0xffff2);
227}
228
229int printlock_w39v080fa(struct flashchip *flash)
230{
231 int ret = 0;
232
233 ret = printlock_w39v080a(flash);
234 ret |= printlock_w39_fwh(flash);
235
236 return ret;
237}
238
239int printlock_w39v080fa_dual(struct flashchip *flash)
240{
241 msg_cinfo("Block locking for W39V080FA in dual mode is "
242 "undocumented.\n");
243 /* Better safe than sorry. */
244 return -1;
245}
246
247int unlock_w39v080fa(struct flashchip *flash)
248{
249 if (unlock_w39_fwh(flash))
250 return -1;
251 if (printlock_w39_common(flash, 0xffff2))
252 return -1;
253
254 return 0;
255}