1 /*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2000 Silicon Integrated System Corporation
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
17 /*
18 * Datasheet:
19 * - Name: Intel 82802AB/82802AC Firmware Hub (FWH)
20 * - URL: http://www.intel.com/design/chipsets/datashts/290658.htm
21 * - PDF: http://download.intel.com/design/chipsets/datashts/29065804.pdf
22 * - Order number: 290658-004
23 */
24
25 #include <stdbool.h>
26 #include "flash.h"
27 #include "chipdrivers.h"
28
print_status_82802ab(uint8_t status)29 void print_status_82802ab(uint8_t status)
30 {
31 msg_cdbg("%s", status & 0x80 ? "Ready:" : "Busy:");
32 msg_cdbg("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:");
33 msg_cdbg("%s", status & 0x20 ? "BE ERROR:" : "BE OK:");
34 msg_cdbg("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:");
35 msg_cdbg("%s", status & 0x8 ? "VP ERR:" : "VPP OK:");
36 msg_cdbg("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:");
37 msg_cdbg("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:");
38 }
39
probe_82802ab(struct flashctx * flash)40 int probe_82802ab(struct flashctx *flash)
41 {
42 chipaddr bios = flash->virtual_memory;
43 uint8_t id1, id2, flashcontent1, flashcontent2;
44 int shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED) ? 1 : 0;
45
46 /* Reset to get a clean state */
47 chip_writeb(flash, 0xFF, bios);
48 programmer_delay(flash, 10);
49
50 /* Enter ID mode */
51 chip_writeb(flash, 0x90, bios);
52 programmer_delay(flash, 10);
53
54 id1 = chip_readb(flash, bios + (0x00 << shifted));
55 id2 = chip_readb(flash, bios + (0x01 << shifted));
56
57 /* Leave ID mode */
58 chip_writeb(flash, 0xFF, bios);
59
60 programmer_delay(flash, 10);
61
62 msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, id1, id2);
63
64 if (!oddparity(id1))
65 msg_cdbg(", id1 parity violation");
66
67 /*
68 * Read the product ID location again. We should now see normal
69 * flash contents.
70 */
71 flashcontent1 = chip_readb(flash, bios + (0x00 << shifted));
72 flashcontent2 = chip_readb(flash, bios + (0x01 << shifted));
73
74 if (id1 == flashcontent1)
75 msg_cdbg(", id1 is normal flash content");
76 if (id2 == flashcontent2)
77 msg_cdbg(", id2 is normal flash content");
78
79 msg_cdbg("\n");
80 if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id)
81 return 0;
82
83 return 1;
84 }
85
86 /* FIXME: needs timeout */
wait_82802ab(struct flashctx * flash)87 uint8_t wait_82802ab(struct flashctx *flash)
88 {
89 uint8_t status;
90 chipaddr bios = flash->virtual_memory;
91
92 chip_writeb(flash, 0x70, bios);
93
94 while ((chip_readb(flash, bios) & 0x80) == 0) // it's busy
95 ;
96
97 status = chip_readb(flash, bios);
98
99 /* Reset to get a clean state */
100 chip_writeb(flash, 0xFF, bios);
101
102 return status;
103 }
104
erase_block_82802ab(struct flashctx * flash,unsigned int page,unsigned int pagesize)105 int erase_block_82802ab(struct flashctx *flash, unsigned int page,
106 unsigned int pagesize)
107 {
108 chipaddr bios = flash->virtual_memory;
109 uint8_t status;
110
111 // clear status register
112 chip_writeb(flash, 0x50, bios + page);
113
114 // now start it
115 chip_writeb(flash, 0x20, bios + page);
116 chip_writeb(flash, 0xd0, bios + page);
117 programmer_delay(flash, 10);
118
119 // now let's see what the register is
120 status = wait_82802ab(flash);
121 print_status_82802ab(status);
122
123 /* FIXME: Check the status register for errors. */
124 return 0;
125 }
126
127 /* chunksize is 1 */
write_82802ab(struct flashctx * flash,const uint8_t * src,unsigned int start,unsigned int len)128 int write_82802ab(struct flashctx *flash, const uint8_t *src, unsigned int start, unsigned int len)
129 {
130 unsigned int i;
131 chipaddr dst = flash->virtual_memory + start;
132
133 for (i = 0; i < len; i++) {
134 /* transfer data from source to destination */
135 chip_writeb(flash, 0x40, dst);
136 chip_writeb(flash, *src++, dst++);
137 wait_82802ab(flash);
138 update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, len);
139 }
140
141 /* FIXME: Ignore errors for now. */
142 return 0;
143 }
144
unlock_28f004s5(struct flashctx * flash)145 static int unlock_28f004s5(struct flashctx *flash)
146 {
147 chipaddr bios = flash->virtual_memory;
148 uint8_t mcfg, bcfg;
149 bool need_unlock = false, can_unlock = false;
150 unsigned int i;
151
152 /* Clear status register */
153 chip_writeb(flash, 0x50, bios);
154
155 /* Read identifier codes */
156 chip_writeb(flash, 0x90, bios);
157
158 /* Read master lock-bit */
159 mcfg = chip_readb(flash, bios + 0x3);
160 msg_cdbg("master lock is ");
161 if (mcfg) {
162 msg_cdbg("locked!\n");
163 } else {
164 msg_cdbg("unlocked!\n");
165 can_unlock = true;
166 }
167
168 /* Read block lock-bits */
169 for (i = 0; i < flash->chip->total_size * 1024; i+= (64 * 1024)) {
170 bcfg = chip_readb(flash, bios + i + 2); // read block lock config
171 msg_cdbg("block lock at %06x is %slocked!\n", i, bcfg ? "" : "un");
172 if (bcfg) {
173 need_unlock = true;
174 }
175 }
176
177 /* Reset chip */
178 chip_writeb(flash, 0xFF, bios);
179
180 /* Unlock: clear block lock-bits, if needed */
181 if (can_unlock && need_unlock) {
182 msg_cdbg("Unlock: ");
183 chip_writeb(flash, 0x60, bios);
184 chip_writeb(flash, 0xD0, bios);
185 chip_writeb(flash, 0xFF, bios);
186 msg_cdbg("Done!\n");
187 }
188
189 /* Error: master locked or a block is locked */
190 if (!can_unlock && need_unlock) {
191 msg_cerr("At least one block is locked and lockdown is active!\n");
192 return -1;
193 }
194
195 return 0;
196 }
197
unlock_lh28f008bjt(struct flashctx * flash)198 static int unlock_lh28f008bjt(struct flashctx *flash)
199 {
200 chipaddr bios = flash->virtual_memory;
201 uint8_t mcfg, bcfg;
202 bool need_unlock = false, can_unlock = false;
203 unsigned int i;
204
205 /* Wait if chip is busy */
206 wait_82802ab(flash);
207
208 /* Read identifier codes */
209 chip_writeb(flash, 0x90, bios);
210
211 /* Read master lock-bit */
212 mcfg = chip_readb(flash, bios + 0x3);
213 msg_cdbg("master lock is ");
214 if (mcfg) {
215 msg_cdbg("locked!\n");
216 } else {
217 msg_cdbg("unlocked!\n");
218 can_unlock = true;
219 }
220
221 /* Read block lock-bits, 8 * 8 KB + 15 * 64 KB */
222 for (i = 0; i < flash->chip->total_size * 1024;
223 i += (i >= (64 * 1024) ? 64 * 1024 : 8 * 1024)) {
224 bcfg = chip_readb(flash, bios + i + 2); /* read block lock config */
225 msg_cdbg("block lock at %06x is %slocked!\n", i,
226 bcfg ? "" : "un");
227 if (bcfg)
228 need_unlock = true;
229 }
230
231 /* Reset chip */
232 chip_writeb(flash, 0xFF, bios);
233
234 /* Unlock: clear block lock-bits, if needed */
235 if (can_unlock && need_unlock) {
236 msg_cdbg("Unlock: ");
237 chip_writeb(flash, 0x60, bios);
238 chip_writeb(flash, 0xD0, bios);
239 chip_writeb(flash, 0xFF, bios);
240 wait_82802ab(flash);
241 msg_cdbg("Done!\n");
242 }
243
244 /* Error: master locked or a block is locked */
245 if (!can_unlock && need_unlock) {
246 msg_cerr("At least one block is locked and lockdown is active!\n");
247 return -1;
248 }
249
250 return 0;
251 }
252
lookup_82802ab_blockprotect_func_ptr(const struct flashchip * const chip)253 blockprotect_func_t *lookup_82802ab_blockprotect_func_ptr(const struct flashchip *const chip)
254 {
255 switch (chip->unlock) {
256 case UNLOCK_28F004S5: return unlock_28f004s5;
257 case UNLOCK_LH28F008BJT: return unlock_lh28f008bjt;
258 default: return NULL; /* fallthough */
259 };
260 }
261