blob: c958f04559332fee6ce28463a720d33baa3cf951 [file] [log] [blame]
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +00001/*
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.
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +000015 */
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
Felix Singer2e003a02022-08-19 02:36:28 +020025#include <stdbool.h>
Nico Huber3a2a4d52026-03-01 12:15:23 +010026#include <stdlib.h>
27
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +000028#include "flash.h"
Nico Huber3a2a4d52026-03-01 12:15:23 +010029#include "programmer.h"
Nico Huber10337f72026-03-04 19:57:27 +010030#include "chipdrivers/memory_bus.h"
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +000031
Sean Nelson28accc22010-03-19 18:47:06 +000032void print_status_82802ab(uint8_t status)
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +000033{
Sean Nelsoned479d22010-03-24 23:14:32 +000034 msg_cdbg("%s", status & 0x80 ? "Ready:" : "Busy:");
35 msg_cdbg("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:");
36 msg_cdbg("%s", status & 0x20 ? "BE ERROR:" : "BE OK:");
37 msg_cdbg("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:");
38 msg_cdbg("%s", status & 0x8 ? "VP ERR:" : "VPP OK:");
39 msg_cdbg("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:");
40 msg_cdbg("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:");
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +000041}
42
Nico Huber3a2a4d52026-03-01 12:15:23 +010043static struct found_id *probe_82802ab_generic(
44 const struct par_master *par,
45 chipsize_t chip_size, feature_bits_t chip_features)
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +000046{
Nico Huber3a2a4d52026-03-01 12:15:23 +010047 const unsigned int addr_shift = chip_features & FEATURE_ADDR_SHIFTED ? 1 : 0;
48 uint8_t raw[2], flashcontent1, flashcontent2;
49
50 const chipaddr bios = (chipaddr)programmer_map_flash_data(par, chip_size, "");
51 if (bios == (chipaddr)ERROR_PTR)
52 return NULL;
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +000053
Carl-Daniel Hailfinger4e9cebb2009-09-05 01:16:30 +000054 /* Reset to get a clean state */
Nico Huber3a2a4d52026-03-01 12:15:23 +010055 par->chip_writeb(par, 0xFF, bios);
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +000056 programmer_delay(10);
Carl-Daniel Hailfinger4e9cebb2009-09-05 01:16:30 +000057
58 /* Enter ID mode */
Nico Huber3a2a4d52026-03-01 12:15:23 +010059 par->chip_writeb(par, 0x90, bios);
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +000060 programmer_delay(10);
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +000061
Nico Huber3a2a4d52026-03-01 12:15:23 +010062 raw[0] = par->chip_readb(par, bios + (0x00 << addr_shift));
63 raw[1] = par->chip_readb(par, bios + (0x01 << addr_shift));
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +000064
65 /* Leave ID mode */
Nico Huber3a2a4d52026-03-01 12:15:23 +010066 par->chip_writeb(par, 0xFF, bios);
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +000067
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +000068 programmer_delay(10);
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +000069
Uwe Hermann91f4afa2011-07-28 08:13:25 +000070 /*
71 * Read the product ID location again. We should now see normal
72 * flash contents.
73 */
Nico Huber3a2a4d52026-03-01 12:15:23 +010074 flashcontent1 = par->chip_readb(par, bios + (0x00 << addr_shift));
75 flashcontent2 = par->chip_readb(par, bios + (0x01 << addr_shift));
Carl-Daniel Hailfinger12aa0be2010-03-22 23:47:38 +000076
Nico Huber3a2a4d52026-03-01 12:15:23 +010077 programmer_unmap_flash_region(par, (void *)bios, chip_size);
78
79 if (flashprog_no_data(raw, sizeof(raw)))
80 return NULL;
81
82 msg_cdbg("%s (%uKiB, features: 0x%02x): id1 0x%02x, id2 0x%02x",
83 __func__, chip_size / KiB, chip_features, raw[0], raw[1]);
84
85 if (!oddparity(raw[0]))
86 msg_cdbg(", id1 parity violation");
87
88 if (raw[0] == flashcontent1)
Sean Nelsoned479d22010-03-24 23:14:32 +000089 msg_cdbg(", id1 is normal flash content");
Nico Huber3a2a4d52026-03-01 12:15:23 +010090 if (raw[1] == flashcontent2)
Sean Nelsoned479d22010-03-24 23:14:32 +000091 msg_cdbg(", id2 is normal flash content");
Sean Nelsoned479d22010-03-24 23:14:32 +000092 msg_cdbg("\n");
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +000093
Nico Huber3a2a4d52026-03-01 12:15:23 +010094 struct memory_found_id *const found = alloc_memory_found_id();
95 if (!found) {
96 msg_cerr("Out of memory!\n");
97 return NULL;
98 }
99
100 found->generic.info.id.manufacture = raw[0];
101 found->generic.info.id.model = raw[1];
102 found->generic.info.id.type = ID_82802AB;
103 found->memory_info.chip_size = chip_size;
104 found->memory_info.chip_features = chip_features;
105
106 return &found->generic;
107}
108
109struct found_id *probe_82802ab(const struct bus_probe *probe,
110 const struct master_common *mst,
111 const struct flashchip *chip)
112{
113 const struct par_master *const par = (const struct par_master *)mst;
114 struct found_id *ids = NULL, **next_ptr = &ids;
115 chipsize_t chip_size;
116
117 if (chip)
118 return probe_82802ab_generic(par, chip->total_size * KiB, chip->feature_bits);
119
120 for (chip_size = 256*KiB; chip_size <= 2*MiB; chip_size *= 2) {
121 *next_ptr = probe_82802ab_generic(par, chip_size, 0);
122 if (*next_ptr)
123 next_ptr = &(*next_ptr)->next;
124
125 *next_ptr = probe_82802ab_generic(par, chip_size, FEATURE_ADDR_SHIFTED);
126 if (*next_ptr)
127 next_ptr = &(*next_ptr)->next;
128 }
129
130 return ids;
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000131}
132
Stefan Tauner4404f732013-09-12 08:28:56 +0000133/* FIXME: needs timeout */
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000134uint8_t wait_82802ab(struct flashctx *flash)
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000135{
136 uint8_t status;
Carl-Daniel Hailfingerb30a5ed2010-10-10 14:02:27 +0000137 chipaddr bios = flash->virtual_memory;
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000138
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000139 chip_writeb(flash, 0x70, bios);
Angel Pons68c32db2020-01-31 11:16:42 +0100140
141 while ((chip_readb(flash, bios) & 0x80) == 0) // it's busy
142 ;
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000143
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000144 status = chip_readb(flash, bios);
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000145
Carl-Daniel Hailfinger4e9cebb2009-09-05 01:16:30 +0000146 /* Reset to get a clean state */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000147 chip_writeb(flash, 0xFF, bios);
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000148
149 return status;
150}
151
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000152int erase_block_82802ab(struct flashctx *flash, unsigned int page,
Uwe Hermann91f4afa2011-07-28 08:13:25 +0000153 unsigned int pagesize)
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000154{
Sean Nelson54596372010-01-09 05:30:14 +0000155 chipaddr bios = flash->virtual_memory;
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000156 uint8_t status;
157
158 // clear status register
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000159 chip_writeb(flash, 0x50, bios + page);
Stefan Reinauerab044b22009-09-16 08:26:59 +0000160
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000161 // now start it
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000162 chip_writeb(flash, 0x20, bios + page);
163 chip_writeb(flash, 0xd0, bios + page);
Carl-Daniel Hailfingerca8bfc62009-06-05 17:48:08 +0000164 programmer_delay(10);
Stefan Reinauerab044b22009-09-16 08:26:59 +0000165
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000166 // now let's see what the register is
Carl-Daniel Hailfingerb30a5ed2010-10-10 14:02:27 +0000167 status = wait_82802ab(flash);
Sean Nelson28accc22010-03-19 18:47:06 +0000168 print_status_82802ab(status);
Stefan Reinauerab044b22009-09-16 08:26:59 +0000169
Carl-Daniel Hailfingerb4061f62011-06-26 17:04:16 +0000170 /* FIXME: Check the status register for errors. */
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000171 return 0;
172}
173
Carl-Daniel Hailfinger75a58f92010-10-13 22:26:56 +0000174/* chunksize is 1 */
Mark Marshallf20b7be2014-05-09 21:16:21 +0000175int write_82802ab(struct flashctx *flash, const uint8_t *src, unsigned int start, unsigned int len)
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000176{
Nico Huber519be662018-12-23 20:03:35 +0100177 unsigned int i;
Carl-Daniel Hailfingerb30a5ed2010-10-10 14:02:27 +0000178 chipaddr dst = flash->virtual_memory + start;
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000179
Carl-Daniel Hailfingerb30a5ed2010-10-10 14:02:27 +0000180 for (i = 0; i < len; i++) {
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000181 /* transfer data from source to destination */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000182 chip_writeb(flash, 0x40, dst);
183 chip_writeb(flash, *src++, dst++);
Carl-Daniel Hailfingerb30a5ed2010-10-10 14:02:27 +0000184 wait_82802ab(flash);
Richard Hughes842d6782021-01-15 09:48:12 +0000185 flashprog_progress_add(flash, 1);
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000186 }
Carl-Daniel Hailfingerb30a5ed2010-10-10 14:02:27 +0000187
188 /* FIXME: Ignore errors for now. */
189 return 0;
Carl-Daniel Hailfingere7bcb192008-03-14 00:02:25 +0000190}
191
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000192int unlock_28f004s5(struct flashctx *flash)
Sean Nelsondee4a832010-03-22 04:39:31 +0000193{
194 chipaddr bios = flash->virtual_memory;
Felix Singer2e003a02022-08-19 02:36:28 +0200195 uint8_t mcfg, bcfg;
196 bool need_unlock = false, can_unlock = false;
Nico Huber519be662018-12-23 20:03:35 +0100197 unsigned int i;
Sean Nelsondee4a832010-03-22 04:39:31 +0000198
199 /* Clear status register */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000200 chip_writeb(flash, 0x50, bios);
Sean Nelsondee4a832010-03-22 04:39:31 +0000201
202 /* Read identifier codes */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000203 chip_writeb(flash, 0x90, bios);
Sean Nelsondee4a832010-03-22 04:39:31 +0000204
205 /* Read master lock-bit */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000206 mcfg = chip_readb(flash, bios + 0x3);
Sean Nelsoned479d22010-03-24 23:14:32 +0000207 msg_cdbg("master lock is ");
Sean Nelsondee4a832010-03-22 04:39:31 +0000208 if (mcfg) {
209 msg_cdbg("locked!\n");
210 } else {
211 msg_cdbg("unlocked!\n");
Felix Singer2e003a02022-08-19 02:36:28 +0200212 can_unlock = true;
Sean Nelsondee4a832010-03-22 04:39:31 +0000213 }
Uwe Hermann91f4afa2011-07-28 08:13:25 +0000214
Sean Nelsondee4a832010-03-22 04:39:31 +0000215 /* Read block lock-bits */
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000216 for (i = 0; i < flash->chip->total_size * 1024; i+= (64 * 1024)) {
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000217 bcfg = chip_readb(flash, bios + i + 2); // read block lock config
Sean Nelsondee4a832010-03-22 04:39:31 +0000218 msg_cdbg("block lock at %06x is %slocked!\n", i, bcfg ? "" : "un");
219 if (bcfg) {
Felix Singer2e003a02022-08-19 02:36:28 +0200220 need_unlock = true;
Sean Nelsondee4a832010-03-22 04:39:31 +0000221 }
222 }
223
224 /* Reset chip */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000225 chip_writeb(flash, 0xFF, bios);
Sean Nelsondee4a832010-03-22 04:39:31 +0000226
227 /* Unlock: clear block lock-bits, if needed */
228 if (can_unlock && need_unlock) {
Sean Nelsoned479d22010-03-24 23:14:32 +0000229 msg_cdbg("Unlock: ");
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000230 chip_writeb(flash, 0x60, bios);
231 chip_writeb(flash, 0xD0, bios);
232 chip_writeb(flash, 0xFF, bios);
Sean Nelsoned479d22010-03-24 23:14:32 +0000233 msg_cdbg("Done!\n");
Sean Nelsondee4a832010-03-22 04:39:31 +0000234 }
235
236 /* Error: master locked or a block is locked */
237 if (!can_unlock && need_unlock) {
238 msg_cerr("At least one block is locked and lockdown is active!\n");
239 return -1;
240 }
241
242 return 0;
243}
Mattias Mattssonfca3b012011-08-25 22:44:11 +0000244
Carl-Daniel Hailfinger63fd9022011-12-14 22:25:15 +0000245int unlock_lh28f008bjt(struct flashctx *flash)
Mattias Mattssonfca3b012011-08-25 22:44:11 +0000246{
247 chipaddr bios = flash->virtual_memory;
248 uint8_t mcfg, bcfg;
Felix Singer2e003a02022-08-19 02:36:28 +0200249 bool need_unlock = false, can_unlock = false;
Nico Huber519be662018-12-23 20:03:35 +0100250 unsigned int i;
Mattias Mattssonfca3b012011-08-25 22:44:11 +0000251
252 /* Wait if chip is busy */
253 wait_82802ab(flash);
254
255 /* Read identifier codes */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000256 chip_writeb(flash, 0x90, bios);
Mattias Mattssonfca3b012011-08-25 22:44:11 +0000257
258 /* Read master lock-bit */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000259 mcfg = chip_readb(flash, bios + 0x3);
Mattias Mattssonfca3b012011-08-25 22:44:11 +0000260 msg_cdbg("master lock is ");
261 if (mcfg) {
262 msg_cdbg("locked!\n");
263 } else {
264 msg_cdbg("unlocked!\n");
Felix Singer2e003a02022-08-19 02:36:28 +0200265 can_unlock = true;
Mattias Mattssonfca3b012011-08-25 22:44:11 +0000266 }
267
268 /* Read block lock-bits, 8 * 8 KB + 15 * 64 KB */
Carl-Daniel Hailfinger5a7cb842012-08-25 01:17:58 +0000269 for (i = 0; i < flash->chip->total_size * 1024;
Mattias Mattssonfca3b012011-08-25 22:44:11 +0000270 i += (i >= (64 * 1024) ? 64 * 1024 : 8 * 1024)) {
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000271 bcfg = chip_readb(flash, bios + i + 2); /* read block lock config */
Mattias Mattssonfca3b012011-08-25 22:44:11 +0000272 msg_cdbg("block lock at %06x is %slocked!\n", i,
273 bcfg ? "" : "un");
274 if (bcfg)
Felix Singer2e003a02022-08-19 02:36:28 +0200275 need_unlock = true;
Mattias Mattssonfca3b012011-08-25 22:44:11 +0000276 }
277
278 /* Reset chip */
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000279 chip_writeb(flash, 0xFF, bios);
Mattias Mattssonfca3b012011-08-25 22:44:11 +0000280
281 /* Unlock: clear block lock-bits, if needed */
282 if (can_unlock && need_unlock) {
283 msg_cdbg("Unlock: ");
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000284 chip_writeb(flash, 0x60, bios);
285 chip_writeb(flash, 0xD0, bios);
286 chip_writeb(flash, 0xFF, bios);
Mattias Mattssonfca3b012011-08-25 22:44:11 +0000287 wait_82802ab(flash);
288 msg_cdbg("Done!\n");
289 }
290
291 /* Error: master locked or a block is locked */
292 if (!can_unlock && need_unlock) {
293 msg_cerr("At least one block is locked and lockdown is active!\n");
294 return -1;
295 }
296
297 return 0;
298}