1 /*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2005-2007 coresystems GmbH <[email protected]>
5 * Copyright (C) 2006 Uwe Hermann <[email protected]>
6 * Copyright (C) 2007-2009 Luc Verhaegen <[email protected]>
7 * Copyright (C) 2007 Carl-Daniel Hailfinger
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19 /*
20 * Contains the board specific flash enables.
21 */
22
23 #include <strings.h>
24 #include <string.h>
25 #include <stdbool.h>
26 #include <stdlib.h>
27 #include "flash.h"
28 #include "programmer.h"
29 #include "platform/pci.h"
30
31 #if defined(__i386__) || defined(__x86_64__)
32
33 #include "hwaccess_x86_io.h"
34 #include "hwaccess_x86_msr.h"
35
36 /*
37 * Helper functions for many Winbond Super I/Os of the W836xx range.
38 */
39 /* Enter extended functions */
w836xx_ext_enter(uint16_t port)40 void w836xx_ext_enter(uint16_t port)
41 {
42 OUTB(0x87, port);
43 OUTB(0x87, port);
44 }
45
46 /* Leave extended functions */
w836xx_ext_leave(uint16_t port)47 void w836xx_ext_leave(uint16_t port)
48 {
49 OUTB(0xAA, port);
50 }
51
52 /* Generic Super I/O helper functions */
sio_read(uint16_t port,uint8_t reg)53 uint8_t sio_read(uint16_t port, uint8_t reg)
54 {
55 OUTB(reg, port);
56 return INB(port + 1);
57 }
58
sio_write(uint16_t port,uint8_t reg,uint8_t data)59 void sio_write(uint16_t port, uint8_t reg, uint8_t data)
60 {
61 OUTB(reg, port);
62 OUTB(data, port + 1);
63 }
64
sio_mask(uint16_t port,uint8_t reg,uint8_t data,uint8_t mask)65 void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask)
66 {
67 uint8_t tmp;
68
69 OUTB(reg, port);
70 tmp = INB(port + 1) & ~mask;
71 OUTB(tmp | (data & mask), port + 1);
72 }
73
74 /* Winbond W83697 documentation indicates that the index register has to be written for each access. */
sio_mask_alzheimer(uint16_t port,uint8_t reg,uint8_t data,uint8_t mask)75 static void sio_mask_alzheimer(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask)
76 {
77 uint8_t tmp;
78
79 OUTB(reg, port);
80 tmp = INB(port + 1) & ~mask;
81 OUTB(reg, port);
82 OUTB(tmp | (data & mask), port + 1);
83 }
84
85 /* Not used yet. */
86 #if 0
87 static int enable_flash_decode_superio(void)
88 {
89 int ret;
90 uint8_t tmp;
91
92 switch (superio.vendor) {
93 case SUPERIO_VENDOR_NONE:
94 ret = -1;
95 break;
96 case SUPERIO_VENDOR_ITE:
97 enter_conf_mode_ite(superio.port);
98 /* Enable flash mapping. Works for most old ITE style Super I/O. */
99 tmp = sio_read(superio.port, 0x24);
100 tmp |= 0xfc;
101 sio_write(superio.port, 0x24, tmp);
102 exit_conf_mode_ite(superio.port);
103 ret = 0;
104 break;
105 default:
106 msg_pdbg("Unhandled Super I/O type!\n");
107 ret = -1;
108 break;
109 }
110 return ret;
111 }
112 #endif
113
114 /*
115 * SMSC FDC37B787: Raise GPIO50
116 */
fdc37b787_gpio50_raise(uint16_t port)117 static int fdc37b787_gpio50_raise(uint16_t port)
118 {
119 uint8_t id, val;
120
121 OUTB(0x55, port); /* enter conf mode */
122 id = sio_read(port, 0x20);
123 if (id != 0x44) {
124 msg_perr("\nERROR: FDC37B787: Wrong ID 0x%02X.\n", id);
125 OUTB(0xAA, port); /* leave conf mode */
126 return -1;
127 }
128
129 sio_write(port, 0x07, 0x08); /* Select Aux I/O subdevice */
130
131 val = sio_read(port, 0xC8); /* GP50 */
132 if ((val & 0x1B) != 0x10) /* output, no invert, GPIO */
133 {
134 msg_perr("\nERROR: GPIO50 mode 0x%02X unexpected.\n", val);
135 OUTB(0xAA, port);
136 return -1;
137 }
138
139 sio_mask(port, 0xF9, 0x01, 0x01);
140
141 OUTB(0xAA, port); /* Leave conf mode */
142 return 0;
143 }
144
145 /*
146 * Suited for:
147 * - Nokia IP530: Intel 440BX + PIIX4 + FDC37B787
148 */
fdc37b787_gpio50_raise_3f0(struct board_cfg * cfg)149 static int fdc37b787_gpio50_raise_3f0(struct board_cfg *cfg)
150 {
151 return fdc37b787_gpio50_raise(0x3f0);
152 }
153
154 struct winbond_mux {
155 uint8_t reg; /* 0 if the corresponding pin is not muxed */
156 uint8_t data; /* reg/data/mask may be directly ... */
157 uint8_t mask; /* ... passed to sio_mask */
158 };
159
160 struct winbond_port {
161 const struct winbond_mux *mux; /* NULL or pointer to mux info for the 8 bits */
162 uint8_t ldn; /* LDN this GPIO register is located in */
163 uint8_t enable_bit; /* bit in 0x30 of that LDN to enable
164 the GPIO port */
165 uint8_t base; /* base register in that LDN for the port */
166 };
167
168 struct winbond_chip {
169 uint8_t device_id; /* reg 0x20 of the expected w83626x */
170 uint8_t gpio_port_count;
171 const struct winbond_port *port;
172 };
173
174
175 #define UNIMPLEMENTED_PORT {NULL, 0, 0, 0}
176
177 enum winbond_id {
178 WINBOND_W83627HF_ID = 0x52,
179 WINBOND_W83627EHF_ID = 0x88,
180 WINBOND_W83627THF_ID = 0x82,
181 WINBOND_W83697HF_ID = 0x60,
182 };
183
184 static const struct winbond_mux w83627hf_port2_mux[8] = {
185 {0x2A, 0x01, 0x01}, /* or MIDI */
186 {0x2B, 0x80, 0x80}, /* or SPI */
187 {0x2B, 0x40, 0x40}, /* or SPI */
188 {0x2B, 0x20, 0x20}, /* or power LED */
189 {0x2B, 0x10, 0x10}, /* or watchdog */
190 {0x2B, 0x08, 0x08}, /* or infra red */
191 {0x2B, 0x04, 0x04}, /* or infra red */
192 {0x2B, 0x03, 0x03} /* or IRQ1 input */
193 };
194
195 static const struct winbond_port w83627hf[3] = {
196 UNIMPLEMENTED_PORT,
197 {w83627hf_port2_mux, 0x08, 0, 0xF0},
198 UNIMPLEMENTED_PORT,
199 };
200
201 static const struct winbond_mux w83627ehf_port2_mux[8] = {
202 {0x29, 0x06, 0x02}, /* or MIDI */
203 {0x29, 0x06, 0x02},
204 {0x24, 0x02, 0x00}, /* or SPI ROM interface */
205 {0x24, 0x02, 0x00},
206 {0x2A, 0x01, 0x01}, /* or keyboard/mouse interface */
207 {0x2A, 0x01, 0x01},
208 {0x2A, 0x01, 0x01},
209 {0x2A, 0x01, 0x01},
210 };
211
212 static const struct winbond_port w83627ehf[6] = {
213 UNIMPLEMENTED_PORT,
214 {w83627ehf_port2_mux, 0x09, 0, 0xE3},
215 UNIMPLEMENTED_PORT,
216 UNIMPLEMENTED_PORT,
217 UNIMPLEMENTED_PORT,
218 UNIMPLEMENTED_PORT,
219 };
220
221 static const struct winbond_mux w83627thf_port4_mux[8] = {
222 {0x2D, 0x01, 0x01}, /* or watchdog or VID level strap */
223 {0x2D, 0x02, 0x02}, /* or resume reset */
224 {0x2D, 0x04, 0x04}, /* or S3 input */
225 {0x2D, 0x08, 0x08}, /* or PSON# */
226 {0x2D, 0x10, 0x10}, /* or PWROK */
227 {0x2D, 0x20, 0x20}, /* or suspend LED */
228 {0x2D, 0x40, 0x40}, /* or panel switch input */
229 {0x2D, 0x80, 0x80}, /* or panel switch output */
230 };
231
232 static const struct winbond_port w83627thf[5] = {
233 UNIMPLEMENTED_PORT, /* GPIO1 */
234 UNIMPLEMENTED_PORT, /* GPIO2 */
235 UNIMPLEMENTED_PORT, /* GPIO3 */
236 {w83627thf_port4_mux, 0x09, 1, 0xF4},
237 UNIMPLEMENTED_PORT, /* GPIO5 */
238 };
239
240 static const struct winbond_chip winbond_chips[] = {
241 {WINBOND_W83627HF_ID, ARRAY_SIZE(w83627hf), w83627hf },
242 {WINBOND_W83627EHF_ID, ARRAY_SIZE(w83627ehf), w83627ehf},
243 {WINBOND_W83627THF_ID, ARRAY_SIZE(w83627thf), w83627thf},
244 };
245
246 #define WINBOND_SUPERIO_PORT1 0x2e
247 #define WINBOND_SUPERIO_PORT2 0x4e
248
249 /* We don't really care about the hardware monitor, but it offers better (more specific) device ID info than
250 * the simple device ID in the normal configuration registers.
251 * Note: This function expects to be called while the Super I/O is in config mode.
252 */
w836xx_deviceid_hwmon(uint16_t sio_port)253 static uint8_t w836xx_deviceid_hwmon(uint16_t sio_port)
254 {
255 uint16_t hwmport;
256 uint16_t hwm_vendorid;
257 uint8_t hwm_deviceid;
258
259 sio_write(sio_port, 0x07, 0x0b); /* Select LDN 0xb (HWM). */
260 if ((sio_read(sio_port, 0x30) & (1 << 0)) != (1 << 0)) {
261 msg_pinfo("W836xx hardware monitor disabled or does not exist.\n");
262 return 0;
263 }
264 /* Get HWM base address (stored in LDN 0xb, index 0x60/0x61). */
265 hwmport = sio_read(sio_port, 0x60) << 8;
266 hwmport |= sio_read(sio_port, 0x61);
267 /* HWM address register = HWM base address + 5. */
268 hwmport += 5;
269 msg_pdbg2("W836xx Hardware Monitor at port %04x\n", hwmport);
270 /* FIXME: This busy check should happen before each HWM access. */
271 if (INB(hwmport) & 0x80) {
272 msg_pinfo("W836xx hardware monitor busy, ignoring it.\n");
273 return 0;
274 }
275 /* Set HBACS=1. */
276 sio_mask_alzheimer(hwmport, 0x4e, 0x80, 0x80);
277 /* Read upper byte of vendor ID. */
278 hwm_vendorid = sio_read(hwmport, 0x4f) << 8;
279 /* Set HBACS=0. */
280 sio_mask_alzheimer(hwmport, 0x4e, 0x00, 0x80);
281 /* Read lower byte of vendor ID. */
282 hwm_vendorid |= sio_read(hwmport, 0x4f);
283 if (hwm_vendorid != 0x5ca3) {
284 msg_pinfo("W836xx hardware monitor vendor ID weirdness: expected 0x5ca3, got %04x\n",
285 hwm_vendorid);
286 return 0;
287 }
288 /* Set Bank=0. */
289 sio_mask_alzheimer(hwmport, 0x4e, 0x00, 0x07);
290 /* Read "chip" ID. We call this one the device ID. */
291 hwm_deviceid = sio_read(hwmport, 0x58);
292 return hwm_deviceid;
293 }
294
probe_superio_winbond(void)295 void probe_superio_winbond(void)
296 {
297 struct superio s = {0};
298 uint16_t winbond_ports[] = {WINBOND_SUPERIO_PORT1, WINBOND_SUPERIO_PORT2, 0};
299 uint16_t *i = winbond_ports;
300 uint8_t model;
301 uint8_t tmp;
302
303 s.vendor = SUPERIO_VENDOR_WINBOND;
304 for (; *i; i++) {
305 s.port = *i;
306 /* If we're already in Super I/O config more, the W836xx enter sequence won't hurt. */
307 w836xx_ext_enter(s.port);
308 model = sio_read(s.port, 0x20);
309 /* No response, no point leaving the config mode. */
310 if (model == 0xff)
311 continue;
312 /* Try to leave config mode. If the ID register is still readable, it's not a Winbond chip. */
313 w836xx_ext_leave(s.port);
314 if (model == sio_read(s.port, 0x20)) {
315 msg_pdbg("W836xx enter config mode worked or we were already in config mode. W836xx "
316 "leave config mode had no effect.\n");
317 if (model == 0x87) {
318 /* ITE IT8707F and IT8710F are special: They need the W837xx enter sequence,
319 * but they want the ITE exit sequence. Handle them here.
320 */
321 tmp = sio_read(s.port, 0x21);
322 switch (tmp) {
323 case 0x07:
324 case 0x10:
325 s.vendor = SUPERIO_VENDOR_ITE;
326 s.model = (0x87 << 8) | tmp ;
327 msg_pdbg("Found ITE Super I/O, ID 0x%04hx on port "
328 "0x%x\n", s.model, s.port);
329 register_superio(s);
330 /* Exit ITE config mode. */
331 exit_conf_mode_ite(s.port);
332 /* Restore vendor for next loop iteration. */
333 s.vendor = SUPERIO_VENDOR_WINBOND;
334 continue;
335 }
336 }
337 msg_pdbg("Active config mode, unknown reg 0x20 ID: %02x.\n", model);
338 continue;
339 }
340 /* The Super I/O reacts to W836xx enter and exit config mode, it's probably Winbond. */
341 w836xx_ext_enter(s.port);
342 s.model = sio_read(s.port, 0x20);
343 switch (s.model) {
344 case WINBOND_W83627HF_ID:
345 case WINBOND_W83627EHF_ID:
346 case WINBOND_W83627THF_ID:
347 msg_pdbg("Found Winbond Super I/O, id 0x%02hx\n", s.model);
348 register_superio(s);
349 break;
350 case WINBOND_W83697HF_ID:
351 /* This code is extremely paranoid. */
352 tmp = sio_read(s.port, 0x26) & 0x40;
353 if (((tmp == 0x00) && (s.port != WINBOND_SUPERIO_PORT1)) ||
354 ((tmp == 0x40) && (s.port != WINBOND_SUPERIO_PORT2))) {
355 msg_pdbg("Winbond Super I/O probe weirdness: Port mismatch for ID "
356 "0x%02x at port 0x%04x\n", s.model, s.port);
357 break;
358 }
359 tmp = w836xx_deviceid_hwmon(s.port);
360 /* FIXME: This might be too paranoid... */
361 if (!tmp) {
362 msg_pdbg("Probably not a Winbond Super I/O\n");
363 break;
364 }
365 if (tmp != s.model) {
366 msg_pinfo("W83 series hardware monitor device ID weirdness: expected 0x%02x, "
367 "got 0x%02x\n", WINBOND_W83697HF_ID, tmp);
368 break;
369 }
370 msg_pinfo("Found Winbond Super I/O, id 0x%02hx\n", s.model);
371 register_superio(s);
372 break;
373 }
374 w836xx_ext_leave(s.port);
375 }
376 return;
377 }
378
winbond_superio_chipdef(void)379 static const struct winbond_chip *winbond_superio_chipdef(void)
380 {
381 int i;
382 unsigned int j;
383
384 for (i = 0; i < superio_count; i++) {
385 if (superios[i].vendor != SUPERIO_VENDOR_WINBOND)
386 continue;
387 for (j = 0; j < ARRAY_SIZE(winbond_chips); j++)
388 if (winbond_chips[j].device_id == superios[i].model)
389 return &winbond_chips[j];
390 }
391 return NULL;
392 }
393
394 /*
395 * The chipid parameter goes away as soon as we have Super I/O matching in the
396 * board enable table. The call to winbond_superio_detect() goes away as
397 * soon as we have generic Super I/O detection code.
398 */
winbond_gpio_set(uint16_t base,enum winbond_id chipid,int pin,int raise)399 static int winbond_gpio_set(uint16_t base, enum winbond_id chipid,
400 int pin, int raise)
401 {
402 const struct winbond_chip *chip = NULL;
403 const struct winbond_port *gpio;
404 int port = pin / 10;
405 int bit = pin % 10;
406
407 chip = winbond_superio_chipdef();
408 if (!chip) {
409 msg_perr("\nERROR: No supported Winbond Super I/O found\n");
410 return -1;
411 }
412 if (chip->device_id != chipid) {
413 msg_perr("\nERROR: Found Winbond chip with ID 0x%x, "
414 "expected %x\n", chip->device_id, chipid);
415 return -1;
416 }
417 if (bit >= 8 || port == 0 || port > chip->gpio_port_count) {
418 msg_perr("\nERROR: winbond_gpio_set: Invalid GPIO number %d\n",
419 pin);
420 return -1;
421 }
422
423 gpio = &chip->port[port - 1];
424
425 if (gpio->ldn == 0) {
426 msg_perr("\nERROR: GPIO%d is not supported yet on this"
427 " winbond chip\n", port);
428 return -1;
429 }
430
431 w836xx_ext_enter(base);
432
433 /* Select logical device. */
434 sio_write(base, 0x07, gpio->ldn);
435
436 /* Activate logical device. */
437 sio_mask(base, 0x30, 1 << gpio->enable_bit, 1 << gpio->enable_bit);
438
439 /* Select GPIO function of that pin. */
440 if (gpio->mux && gpio->mux[bit].reg)
441 sio_mask(base, gpio->mux[bit].reg,
442 gpio->mux[bit].data, gpio->mux[bit].mask);
443
444 sio_mask(base, gpio->base + 0, 0, 1 << bit); /* Make pin output */
445 sio_mask(base, gpio->base + 2, 0, 1 << bit); /* Clear inversion */
446 sio_mask(base, gpio->base + 1, raise << bit, 1 << bit);
447
448 w836xx_ext_leave(base);
449
450 return 0;
451 }
452
453 /*
454 * Winbond W83627HF: Raise GPIO24.
455 *
456 * Suited for:
457 * - Agami Aruma
458 * - IWILL DK8-HTX
459 */
w83627hf_gpio24_raise_2e(struct board_cfg * cfg)460 static int w83627hf_gpio24_raise_2e(struct board_cfg *cfg)
461 {
462 return winbond_gpio_set(0x2e, WINBOND_W83627HF_ID, 24, 1);
463 }
464
465 /*
466 * Winbond W83627HF: Raise GPIO25.
467 *
468 * Suited for:
469 * - MSI MS-6577
470 */
w83627hf_gpio25_raise_2e(struct board_cfg * cfg)471 static int w83627hf_gpio25_raise_2e(struct board_cfg *cfg)
472 {
473 return winbond_gpio_set(0x2e, WINBOND_W83627HF_ID, 25, 1);
474 }
475
476 /*
477 * Winbond W83627EHF: Raise GPIO22.
478 *
479 * Suited for:
480 * - ASUS A8N-VM CSM: AMD Socket 939 + GeForce 6150 (C51) + MCP51
481 */
w83627ehf_gpio22_raise_2e(struct board_cfg * cfg)482 static int w83627ehf_gpio22_raise_2e(struct board_cfg *cfg)
483 {
484 return winbond_gpio_set(0x2e, WINBOND_W83627EHF_ID, 22, 1);
485 }
486
487 /*
488 * Winbond W83627THF: Raise GPIO 44.
489 *
490 * Suited for:
491 * - MSI K8T Neo2-F V2.0
492 */
w83627thf_gpio44_raise_2e(struct board_cfg * cfg)493 static int w83627thf_gpio44_raise_2e(struct board_cfg *cfg)
494 {
495 return winbond_gpio_set(0x2e, WINBOND_W83627THF_ID, 44, 1);
496 }
497
498 /*
499 * Winbond W83627THF: Raise GPIO 44.
500 *
501 * Suited for:
502 * - MSI K8N Neo3
503 */
w83627thf_gpio44_raise_4e(struct board_cfg * cfg)504 static int w83627thf_gpio44_raise_4e(struct board_cfg *cfg)
505 {
506 return winbond_gpio_set(0x4e, WINBOND_W83627THF_ID, 44, 1);
507 }
508
509 /*
510 * Enable MEMW# and set ROM size to max.
511 * Supported chips: W83L517D, W83697HF/F/HG, W83697SF/UF/UG
512 */
w836xx_memw_enable(uint16_t port)513 static void w836xx_memw_enable(uint16_t port)
514 {
515 w836xx_ext_enter(port);
516 if (!(sio_read(port, 0x24) & 0x02)) { /* Flash ROM enabled? */
517 /* Enable MEMW# and set ROM size select to max. (4M). */
518 sio_mask(port, 0x24, 0x28, 0x28);
519 }
520 w836xx_ext_leave(port);
521 }
522
523 /**
524 * Enable MEMW# and set ROM size to max.
525 * Supported chips:
526 * W83697HF/F/HG, W83697SF/UF/UG
527 */
w83697xx_memw_enable(uint16_t port)528 static void w83697xx_memw_enable(uint16_t port)
529 {
530 w836xx_ext_enter(port);
531 if (!(sio_read(port, 0x24) & 0x02)) { /* Flash ROM enabled? */
532 if((sio_read(port, 0x2A) & 0xF0) == 0xF0) {
533
534 /* CR24 Bits 7 & 2 must be set to 0 enable the flash ROM */
535 /* address segments 000E0000h ~ 000FFFFFh on W83697SF/UF/UG */
536 /* These bits are reserved on W83697HF/F/HG */
537 /* Shouldn't be needed though. */
538
539 /* CR28 Bit3 must be set to 1 to enable flash access to */
540 /* FFE80000h ~ FFEFFFFFh on W83697SF/UF/UG. */
541 /* This bit is reserved on W83697HF/F/HG which default to 0 */
542 sio_mask(port, 0x28, 0x08, 0x08);
543
544 /* Enable MEMW# and set ROM size select to max. (4M)*/
545 sio_mask(port, 0x24, 0x28, 0x38);
546
547 } else {
548 msg_pwarn("Warning: Flash interface in use by GPIO!\n");
549 }
550 } else {
551 msg_pinfo("BIOS ROM is disabled\n");
552 }
553 w836xx_ext_leave(port);
554 }
555
556 /*
557 * Suited for:
558 * - Biostar M7VIQ: VIA KM266 + VT8235
559 */
w83697xx_memw_enable_2e(struct board_cfg * cfg)560 static int w83697xx_memw_enable_2e(struct board_cfg *cfg)
561 {
562 w83697xx_memw_enable(0x2E);
563
564 return 0;
565 }
566
567
568 /*
569 * Suited for:
570 * - DFI AD77: VIA KT400 + VT8235 + W83697HF
571 * - EPoX EP-8K5A2: VIA KT333 + VT8235
572 * - Albatron PM266A Pro: VIA P4M266A + VT8235
573 * - Shuttle AK31 (all versions): VIA KT266 + VT8233
574 * - ASUS A7V8X-MX SE and A7V400-MX: AMD K7 + VIA KM400A + VT8235
575 * - Tyan S2498 (Tomcat K7M): AMD Geode NX + VIA KM400 + VT8237
576 * - MSI KM4M-V and KM4AM-V: VIA KM400/KM400A + VT8237
577 * - MSI MS-6561 (745 Ultra): SiS 745 + W83697HF
578 * - MSI MS-6787 (P4MAM-V/P4MAM-L): VIA P4M266 + VT8235
579 * - ASRock K7S41: SiS 741 + SiS 963 + W83697HF
580 * - ASRock K7S41GX: SiS 741GX + SiS 963L + W83697HF
581 */
w836xx_memw_enable_2e(struct board_cfg * cfg)582 static int w836xx_memw_enable_2e(struct board_cfg *cfg)
583 {
584 w836xx_memw_enable(0x2E);
585
586 return 0;
587 }
588
589 /*
590 * Suited for:
591 * - Termtek TK-3370 (rev. 2.5b)
592 */
w836xx_memw_enable_4e(struct board_cfg * cfg)593 static int w836xx_memw_enable_4e(struct board_cfg *cfg)
594 {
595 w836xx_memw_enable(0x4E);
596
597 return 0;
598 }
599
600 /*
601 * Suited for all boards with ITE IT8705F.
602 * The SIS950 Super I/O probably requires a similar flash write enable.
603 */
it8705f_write_enable(uint8_t port)604 int it8705f_write_enable(uint8_t port)
605 {
606 uint8_t tmp;
607 int ret = 0;
608
609 if (!(internal_buses_supported & BUS_PARALLEL))
610 return 1;
611
612 enter_conf_mode_ite(port);
613 tmp = sio_read(port, 0x24);
614 /* Check if at least one flash segment is enabled. */
615 if (tmp & 0xf0) {
616 /* The IT8705F will respond to LPC cycles and translate them. */
617 internal_buses_supported &= BUS_PARALLEL;
618 /* Flash ROM I/F Writes Enable */
619 tmp |= 0x04;
620 msg_pdbg("Enabling IT8705F flash ROM interface write.\n");
621 if (tmp & 0x02) {
622 /* The data sheet contradicts itself about max size. */
623 max_rom_decode.parallel = 1024 * 1024;
624 msg_pinfo("IT8705F with very unusual settings.\n"
625 "Please send the output of \"flashrom -V -p internal\" to [email protected]\n"
626 "with \"IT8705: your board name: flashrom -V\" as the subject to help us finish\n"
627 "support for your Super I/O. Thanks.\n");
628 ret = 1;
629 } else if (tmp & 0x08) {
630 max_rom_decode.parallel = 512 * 1024;
631 } else {
632 max_rom_decode.parallel = 256 * 1024;
633 }
634 /* Safety checks. The data sheet is unclear here: Segments 1+3
635 * overlap, no segment seems to cover top - 1MB to top - 512kB.
636 * We assume that certain combinations make no sense.
637 */
638 if (((tmp & 0x02) && !(tmp & 0x08)) || /* 1 MB en, 512 kB dis */
639 (!(tmp & 0x10)) || /* 128 kB dis */
640 (!(tmp & 0x40))) { /* 256/512 kB dis */
641 msg_perr("Inconsistent IT8705F decode size!\n");
642 ret = 1;
643 }
644 if (sio_read(port, 0x25) != 0) {
645 msg_perr("IT8705F flash data pins disabled!\n");
646 ret = 1;
647 }
648 if (sio_read(port, 0x26) != 0) {
649 msg_perr("IT8705F flash address pins 0-7 disabled!\n");
650 ret = 1;
651 }
652 if (sio_read(port, 0x27) != 0) {
653 msg_perr("IT8705F flash address pins 8-15 disabled!\n");
654 ret = 1;
655 }
656 if ((sio_read(port, 0x29) & 0x10) != 0) {
657 msg_perr("IT8705F flash write enable pin disabled!\n");
658 ret = 1;
659 }
660 if ((sio_read(port, 0x29) & 0x08) != 0) {
661 msg_perr("IT8705F flash chip select pin disabled!\n");
662 ret = 1;
663 }
664 if ((sio_read(port, 0x29) & 0x04) != 0) {
665 msg_perr("IT8705F flash read strobe pin disabled!\n");
666 ret = 1;
667 }
668 if ((sio_read(port, 0x29) & 0x03) != 0) {
669 msg_perr("IT8705F flash address pins 16-17 disabled!\n");
670 /* Not really an error if you use flash chips smaller
671 * than 256 kByte, but such a configuration is unlikely.
672 */
673 ret = 1;
674 }
675 msg_pdbg("Maximum IT8705F parallel flash decode size is %"PRIu32".\n",
676 max_rom_decode.parallel);
677 if (ret) {
678 msg_pinfo("Not enabling IT8705F flash write.\n");
679 } else {
680 sio_write(port, 0x24, tmp);
681 }
682 } else {
683 msg_pdbg("No IT8705F flash segment enabled.\n");
684 ret = 0;
685 }
686 exit_conf_mode_ite(port);
687
688 return ret;
689 }
690
691 /*
692 * The ITE IT8707F is a custom chip made by ITE exclusively for ASUS.
693 * It uses the Winbond command sequence to enter extended configuration
694 * mode and the ITE sequence to exit.
695 *
696 * Registers seems similar to the ones on ITE IT8710F.
697 */
it8707f_write_enable(uint8_t port)698 static int it8707f_write_enable(uint8_t port)
699 {
700 uint8_t tmp;
701
702 w836xx_ext_enter(port);
703
704 /* Set bit 3 (GLB_REG_WE) of reg 0x23: Makes reg 0x24-0x2A rw */
705 tmp = sio_read(port, 0x23);
706 tmp |= (1 << 3);
707 sio_write(port, 0x23, tmp);
708
709 /* Set bit 2 (FLASH_WE) and bit 3 (FLASH_IF_EN) of reg 0x24 */
710 tmp = sio_read(port, 0x24);
711 tmp |= (1 << 2) | (1 << 3);
712 sio_write(port, 0x24, tmp);
713
714 /* Clear bit 3 (GLB_REG_WE) of reg 0x23: Makes reg 0x24-0x2A ro */
715 tmp = sio_read(port, 0x23);
716 tmp &= ~(1 << 3);
717 sio_write(port, 0x23, tmp);
718
719 exit_conf_mode_ite(port);
720
721 return 0;
722 }
723
724 /*
725 * Suited for:
726 * - ASUS P4SC-E: SiS 651 + 962 + ITE IT8707F
727 */
it8707f_write_enable_2e(struct board_cfg * cfg)728 static int it8707f_write_enable_2e(struct board_cfg *cfg)
729 {
730 return it8707f_write_enable(0x2e);
731 }
732
733 #define PC87360_ID 0xE1
734 #define PC87364_ID 0xE4
735
pc8736x_gpio_set(uint8_t chipid,uint8_t gpio,int raise)736 static int pc8736x_gpio_set(uint8_t chipid, uint8_t gpio, int raise)
737 {
738 static const int bankbase[] = {0, 4, 8, 10, 12};
739 int gpio_bank = gpio / 8;
740 int gpio_pin = gpio % 8;
741 uint16_t baseport;
742 uint8_t id, val;
743
744 if (gpio_bank > 4) {
745 msg_perr("PC8736x: Invalid GPIO %d\n", gpio);
746 return -1;
747 }
748
749 id = sio_read(0x2E, 0x20);
750 if (id != chipid) {
751 msg_perr("PC8736x: unexpected ID %02x (expected %02x)\n",
752 id, chipid);
753 return -1;
754 }
755
756 sio_write(0x2E, 0x07, 0x07); /* Select GPIO device. */
757 baseport = (sio_read(0x2E, 0x60) << 8) | sio_read(0x2E, 0x61);
758 if ((baseport & 0xFFF0) == 0xFFF0 || baseport == 0) {
759 msg_perr("PC87360: invalid GPIO base address %04x\n",
760 baseport);
761 return -1;
762 }
763 sio_mask (0x2E, 0x30, 0x01, 0x01); /* Enable logical device. */
764 sio_write(0x2E, 0xF0, gpio_bank * 16 + gpio_pin);
765 sio_mask (0x2E, 0xF1, 0x01, 0x01); /* Make pin output. */
766
767 val = INB(baseport + bankbase[gpio_bank]);
768 if (raise)
769 val |= 1 << gpio_pin;
770 else
771 val &= ~(1 << gpio_pin);
772 OUTB(val, baseport + bankbase[gpio_bank]);
773
774 return 0;
775 }
776
777 /*
778 * VIA VT823x: Set one of the GPIO pins.
779 */
via_vt823x_gpio_set(uint8_t gpio,int raise)780 static int via_vt823x_gpio_set(uint8_t gpio, int raise)
781 {
782 struct pci_dev *dev;
783 uint16_t base;
784 uint8_t val, bit, offset;
785
786 dev = pcidev_find_vendorclass(0x1106, 0x0601);
787 switch (dev->device_id) {
788 case 0x3177: /* VT8235 */
789 case 0x3227: /* VT8237/VT8237R */
790 case 0x3337: /* VT8237A */
791 break;
792 default:
793 msg_perr("\nERROR: VT823x ISA bridge not found.\n");
794 return -1;
795 }
796
797 if ((gpio >= 12) && (gpio <= 15)) {
798 /* GPIO12-15 -> output */
799 val = pci_read_byte(dev, 0xE4);
800 val |= 0x10;
801 pci_write_byte(dev, 0xE4, val);
802 } else if (gpio == 9) {
803 /* GPIO9 -> Output */
804 val = pci_read_byte(dev, 0xE4);
805 val |= 0x20;
806 pci_write_byte(dev, 0xE4, val);
807 } else if (gpio == 5) {
808 val = pci_read_byte(dev, 0xE4);
809 val |= 0x01;
810 pci_write_byte(dev, 0xE4, val);
811 } else {
812 msg_perr("\nERROR: "
813 "VT823x GPIO%02d is not implemented.\n", gpio);
814 return -1;
815 }
816
817 /* We need the I/O Base Address for this board's flash enable. */
818 base = pci_read_word(dev, 0x88) & 0xff80;
819
820 offset = 0x4C + gpio / 8;
821 bit = 0x01 << (gpio % 8);
822
823 val = INB(base + offset);
824 if (raise)
825 val |= bit;
826 else
827 val &= ~bit;
828 OUTB(val, base + offset);
829
830 return 0;
831 }
832
833 /*
834 * Suited for:
835 * - ASUS M2V-MX: VIA K8M890 + VT8237A + IT8716F
836 */
via_vt823x_gpio5_raise(struct board_cfg * cfg)837 static int via_vt823x_gpio5_raise(struct board_cfg *cfg)
838 {
839 /* On M2V-MX: GPO5 is connected to WP# and TBL#. */
840 return via_vt823x_gpio_set(5, 1);
841 }
842
843 /*
844 * Suited for:
845 * - VIA EPIA EK & N & NL
846 */
via_vt823x_gpio9_raise(struct board_cfg * cfg)847 static int via_vt823x_gpio9_raise(struct board_cfg *cfg)
848 {
849 return via_vt823x_gpio_set(9, 1);
850 }
851
852 /*
853 * Suited for:
854 * - VIA EPIA M and MII (and maybe other CLE266 based EPIAs)
855 *
856 * We don't need to do this for EPIA M when using coreboot, GPIO15 is never
857 * lowered there.
858 */
via_vt823x_gpio15_raise(struct board_cfg * cfg)859 static int via_vt823x_gpio15_raise(struct board_cfg *cfg)
860 {
861 return via_vt823x_gpio_set(15, 1);
862 }
863
864 /*
865 * Winbond W83697HF Super I/O + VIA VT8235 southbridge
866 *
867 * Suited for:
868 * - MSI KT4V and KT4V-L: AMD K7 + VIA KT400 + VT8235
869 * - MSI KT4 Ultra: AMD K7 + VIA KT400 + VT8235
870 */
board_msi_kt4v(struct board_cfg * cfg)871 static int board_msi_kt4v(struct board_cfg *cfg)
872 {
873 int ret;
874
875 ret = via_vt823x_gpio_set(12, 1);
876 w836xx_memw_enable(0x2E);
877
878 return ret;
879 }
880
881 /*
882 * Suited for:
883 * - ASUS P3B-F
884 *
885 * We are talking to a proprietary device on SMBus: the AS99127F which does
886 * much more than the Winbond W83781D it tries to be compatible with.
887 */
board_asus_p3b_f(struct board_cfg * cfg)888 static int board_asus_p3b_f(struct board_cfg *cfg)
889 {
890 /*
891 * Find where the SMBus host is. ASUS sets it to 0xE800; coreboot sets it to 0x0F00.
892 */
893 struct pci_dev *dev;
894 uint16_t smbba;
895 uint8_t b;
896
897 dev = pcidev_find(0x8086, 0x7113); /* Intel PIIX4, PM/SMBus function. */
898 if (!dev) {
899 msg_perr("\nERROR: Intel PIIX4 PM not found.\n");
900 return -1;
901 }
902
903 smbba = pci_read_word(dev, 0x90) & 0xfff0;
904
905 OUTB(0xFF, smbba); /* Clear previous SMBus status. */
906 OUTB(0x48 << 1, smbba + 4);
907 OUTB(0x80, smbba + 3);
908 OUTB(0x80, smbba + 5);
909 OUTB(0x48, smbba + 2);
910
911 /* Wait until SMBus transaction is complete. */
912 b = 0x1;
913 while (b & 0x01) {
914 INB(0x80);
915 b = INB(smbba);
916 }
917
918 /* Write failed if any status is set. */
919 if (b & 0x1e) {
920 msg_perr("Failed to write to device.\n");
921 return -1;
922 }
923
924 return 0;
925 }
926
927 /*
928 * Suited for:
929 * - ASUS P5A
930 *
931 * This is rather nasty code, but there's no way to do this cleanly.
932 * We're basically talking to some unknown device on SMBus, my guess
933 * is that it is the Winbond W83781D that lives near the DIP BIOS.
934 */
board_asus_p5a(struct board_cfg * cfg)935 static int board_asus_p5a(struct board_cfg *cfg)
936 {
937 uint8_t tmp;
938 int i;
939
940 #define ASUSP5A_LOOP 5000
941
942 OUTB(0x00, 0xE807);
943 OUTB(0xEF, 0xE803);
944
945 OUTB(0xFF, 0xE800);
946
947 for (i = 0; i < ASUSP5A_LOOP; i++) {
948 OUTB(0xE1, 0xFF);
949 if (INB(0xE800) & 0x04)
950 break;
951 }
952
953 if (i == ASUSP5A_LOOP) {
954 msg_perr("Unable to contact device.\n");
955 return -1;
956 }
957
958 OUTB(0x20, 0xE801);
959 OUTB(0x20, 0xE1);
960
961 OUTB(0xFF, 0xE802);
962
963 for (i = 0; i < ASUSP5A_LOOP; i++) {
964 tmp = INB(0xE800);
965 if (tmp & 0x70)
966 break;
967 }
968
969 if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) {
970 msg_perr("Failed to read device.\n");
971 return -1;
972 }
973
974 tmp = INB(0xE804);
975 tmp &= ~0x02;
976
977 OUTB(0x00, 0xE807);
978 OUTB(0xEE, 0xE803);
979
980 OUTB(tmp, 0xE804);
981
982 OUTB(0xFF, 0xE800);
983 OUTB(0xE1, 0xFF);
984
985 OUTB(0x20, 0xE801);
986 OUTB(0x20, 0xE1);
987
988 OUTB(0xFF, 0xE802);
989
990 for (i = 0; i < ASUSP5A_LOOP; i++) {
991 tmp = INB(0xE800);
992 if (tmp & 0x70)
993 break;
994 }
995
996 if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) {
997 msg_perr("Failed to write to device.\n");
998 return -1;
999 }
1000
1001 return 0;
1002 }
1003
1004 /*
1005 * Set GPIO lines in the Broadcom HT-1000 southbridge.
1006 *
1007 * It's not a Super I/O but it uses the same index/data port method.
1008 */
board_hp_dl145_g3_enable(struct board_cfg * cfg)1009 static int board_hp_dl145_g3_enable(struct board_cfg *cfg)
1010 {
1011 /* GPIO 0 reg from PM regs */
1012 /* Set GPIO 2 and 5 high, connected to flash WP# and TBL# pins. */
1013 sio_mask(0xcd6, 0x44, 0x24, 0x24);
1014
1015 return 0;
1016 }
1017
1018 /*
1019 * Set GPIO lines in the Broadcom HT-1000 southbridge.
1020 *
1021 * It's not a Super I/O but it uses the same index/data port method.
1022 */
board_hp_dl165_g6_enable(struct board_cfg * cfg)1023 static int board_hp_dl165_g6_enable(struct board_cfg *cfg)
1024 {
1025 /* Variant of DL145, with slightly different pin placement. */
1026 sio_mask(0xcd6, 0x44, 0x80, 0x80); /* TBL# */
1027 sio_mask(0xcd6, 0x46, 0x04, 0x04); /* WP# */
1028
1029 return 0;
1030 }
1031
board_ibm_x3455(struct board_cfg * cfg)1032 static int board_ibm_x3455(struct board_cfg *cfg)
1033 {
1034 /* Raise GPIO13. */
1035 sio_mask(0xcd6, 0x45, 0x20, 0x20);
1036
1037 return 0;
1038 }
1039
1040 /*
1041 * Suited for:
1042 * - Elitegroup GeForce6100SM-M: NVIDIA MCP61 + ITE IT8726F
1043 */
board_ecs_geforce6100sm_m(struct board_cfg * cfg)1044 static int board_ecs_geforce6100sm_m(struct board_cfg *cfg)
1045 {
1046 struct pci_dev *dev;
1047 uint32_t tmp;
1048
1049 dev = pcidev_find(0x10DE, 0x03EB); /* NVIDIA MCP61 SMBus. */
1050 if (!dev) {
1051 msg_perr("\nERROR: NVIDIA MCP61 SMBus not found.\n");
1052 return -1;
1053 }
1054
1055 tmp = pci_read_byte(dev, 0xE0);
1056 tmp &= ~(1 << 3);
1057 pci_write_byte(dev, 0xE0, tmp);
1058
1059 return 0;
1060 }
1061
1062 /*
1063 * Very similar to AMD 8111 IO Hub.
1064 */
nvidia_mcp_gpio_set(int gpio,int raise)1065 static int nvidia_mcp_gpio_set(int gpio, int raise)
1066 {
1067 struct pci_dev *dev;
1068 uint16_t base, devclass;
1069 uint8_t tmp;
1070
1071 if ((gpio < 0) || (gpio >= 0x40)) {
1072 msg_perr("\nERROR: unsupported GPIO: %d.\n", gpio);
1073 return -1;
1074 }
1075
1076 /* Check for the ISA bridge first. */
1077 dev = pcidev_find_vendorclass(0x10DE, 0x0601);
1078 switch (dev->device_id) {
1079 case 0x0030: /* CK804 */
1080 case 0x0050: /* MCP04 */
1081 case 0x0060: /* MCP2 */
1082 case 0x00E0: /* CK8 */
1083 break;
1084 case 0x0260: /* MCP51 */
1085 case 0x0261: /* MCP51 */
1086 case 0x0360: /* MCP55 */
1087 case 0x0364: /* MCP55 */
1088 /* find SMBus controller on *this* southbridge */
1089 /* The infamous Tyan S2915-E has two south bridges; they are
1090 easily told apart from each other by the class of the
1091 LPC bridge, but have the same SMBus bridge IDs */
1092 if (dev->func != 0) {
1093 msg_perr("MCP LPC bridge at unexpected function"
1094 " number %d\n", dev->func);
1095 return -1;
1096 }
1097
1098 dev = pcidev_getdevfn(dev, 1);
1099 if (!dev) {
1100 msg_perr("MCP SMBus controller could not be found\n");
1101 return -1;
1102 }
1103 devclass = pci_read_word(dev, PCI_CLASS_DEVICE);
1104 if (devclass != 0x0C05) {
1105 msg_perr("Unexpected device class %04x for SMBus"
1106 " controller\n", devclass);
1107 return -1;
1108 }
1109 break;
1110 default:
1111 msg_perr("\nERROR: no NVIDIA LPC/SMBus controller found.\n");
1112 return -1;
1113 }
1114
1115 base = pci_read_long(dev, 0x64) & 0x0000FF00; /* System control area */
1116 base += 0xC0;
1117
1118 tmp = INB(base + gpio);
1119 tmp &= ~0x0F; /* null lower nibble */
1120 tmp |= 0x04; /* gpio -> output. */
1121 if (raise)
1122 tmp |= 0x01;
1123 OUTB(tmp, base + gpio);
1124
1125 return 0;
1126 }
1127
1128 /*
1129 * Suited for:
1130 * - ASUS A8M2N-LA (HP OEM "NodusM3-GL8E"): NVIDIA MCP51
1131 * - ASUS A8N-LA (HP OEM "Nagami-GL8E"): NVIDIA MCP51
1132 * - ASUS M2NBP-VM CSM: NVIDIA MCP51
1133 */
nvidia_mcp_gpio0_raise(struct board_cfg * cfg)1134 static int nvidia_mcp_gpio0_raise(struct board_cfg *cfg)
1135 {
1136 return nvidia_mcp_gpio_set(0x00, 1);
1137 }
1138
1139 /*
1140 * Suited for:
1141 * - abit KN8 Ultra: NVIDIA CK804
1142 * - abit KN9 Ultra: NVIDIA MCP55
1143 */
nvidia_mcp_gpio2_lower(struct board_cfg * cfg)1144 static int nvidia_mcp_gpio2_lower(struct board_cfg *cfg)
1145 {
1146 return nvidia_mcp_gpio_set(0x02, 0);
1147 }
1148
1149 /*
1150 * Suited for:
1151 * - Foxconn 6150K8MD-8EKRSH: Socket 939 + NVIDIA MCP51
1152 * - MSI K8N Neo4(-F/-FI/-FX/Platinum): NVIDIA CK804
1153 * - MSI K8NGM2-L: NVIDIA MCP51
1154 * - MSI K9N SLI: NVIDIA MCP55
1155 */
nvidia_mcp_gpio2_raise(struct board_cfg * cfg)1156 static int nvidia_mcp_gpio2_raise(struct board_cfg *cfg)
1157 {
1158 return nvidia_mcp_gpio_set(0x02, 1);
1159 }
1160
1161 /*
1162 * Suited for:
1163 * - EPoX EP-8NPA7I: Socket 754 + NVIDIA nForce4 4X
1164 */
nvidia_mcp_gpio4_raise(struct board_cfg * cfg)1165 static int nvidia_mcp_gpio4_raise(struct board_cfg *cfg)
1166 {
1167 return nvidia_mcp_gpio_set(0x04, 1);
1168 }
1169
1170 /*
1171 * Suited for:
1172 * - HP xw9400 (Tyan S2915-E OEM): Dual(!) NVIDIA MCP55
1173 *
1174 * Notes: a) There are two MCP55 chips, so also two SMBus bridges on that
1175 * board. We can't tell the SMBus logical devices apart, but we
1176 * can tell the LPC bridge functions apart.
1177 * We need to choose the SMBus bridge next to the LPC bridge with
1178 * ID 0x364 and the "LPC bridge" class.
1179 * b) #TBL is hardwired on that board to a pull-down. It can be
1180 * overridden by connecting the two solder points next to F2.
1181 */
nvidia_mcp_gpio5_raise(struct board_cfg * cfg)1182 static int nvidia_mcp_gpio5_raise(struct board_cfg *cfg)
1183 {
1184 return nvidia_mcp_gpio_set(0x05, 1);
1185 }
1186
1187 /*
1188 * Suited for:
1189 * - abit NF7-S: NVIDIA CK804
1190 */
nvidia_mcp_gpio8_raise(struct board_cfg * cfg)1191 static int nvidia_mcp_gpio8_raise(struct board_cfg *cfg)
1192 {
1193 return nvidia_mcp_gpio_set(0x08, 1);
1194 }
1195
1196 /*
1197 * Suited for:
1198 * - GIGABYTE GA-K8NS Pro-939: Socket 939 + NVIDIA nForce3 + CK8
1199 * - Probably other versions of the GA-K8NS
1200 */
nvidia_mcp_gpio0a_raise(struct board_cfg * cfg)1201 static int nvidia_mcp_gpio0a_raise(struct board_cfg *cfg)
1202 {
1203 return nvidia_mcp_gpio_set(0x0a, 1);
1204 }
1205
1206 /*
1207 * Suited for:
1208 * - MSI K8N Neo Platinum: Socket 754 + nForce3 Ultra + CK8
1209 * - MSI K8N Neo2 Platinum: Socket 939 + nForce3 Ultra + CK8
1210 */
nvidia_mcp_gpio0c_raise(struct board_cfg * cfg)1211 static int nvidia_mcp_gpio0c_raise(struct board_cfg *cfg)
1212 {
1213 return nvidia_mcp_gpio_set(0x0c, 1);
1214 }
1215
1216 /*
1217 * Suited for:
1218 * - abit NF-M2 nView: Socket AM2 + NVIDIA MCP51
1219 */
nvidia_mcp_gpio4_lower(struct board_cfg * cfg)1220 static int nvidia_mcp_gpio4_lower(struct board_cfg *cfg)
1221 {
1222 return nvidia_mcp_gpio_set(0x04, 0);
1223 }
1224
1225 /*
1226 * Suited for:
1227 * - ASUS P5ND2-SLI Deluxe: LGA775 + nForce4 SLI + MCP04
1228 */
nvidia_mcp_gpio10_raise(struct board_cfg * cfg)1229 static int nvidia_mcp_gpio10_raise(struct board_cfg *cfg)
1230 {
1231 return nvidia_mcp_gpio_set(0x10, 1);
1232 }
1233
1234 /*
1235 * Suited for:
1236 * - GIGABYTE GA-K8N-SLI: AMD socket 939 + NVIDIA CK804 + ITE IT8712F
1237 */
nvidia_mcp_gpio21_raise(struct board_cfg * cfg)1238 static int nvidia_mcp_gpio21_raise(struct board_cfg *cfg)
1239 {
1240 return nvidia_mcp_gpio_set(0x21, 0x01);
1241 }
1242
1243 /*
1244 * Suited for:
1245 * - EPoX EP-8RDA3+: Socket A + nForce2 Ultra 400 + MCP2
1246 */
nvidia_mcp_gpio31_raise(struct board_cfg * cfg)1247 static int nvidia_mcp_gpio31_raise(struct board_cfg *cfg)
1248 {
1249 return nvidia_mcp_gpio_set(0x31, 0x01);
1250 }
1251
1252 /*
1253 * Suited for:
1254 * - GIGABYTE GA-K8N51GMF: Socket 754 + Geforce 6100 + MCP51
1255 * - GIGABYTE GA-K8N51GMF-9: Socket 939 + Geforce 6100 + MCP51
1256 */
nvidia_mcp_gpio3b_raise(struct board_cfg * cfg)1257 static int nvidia_mcp_gpio3b_raise(struct board_cfg *cfg)
1258 {
1259 return nvidia_mcp_gpio_set(0x3b, 1);
1260 }
1261
1262 /*
1263 * Suited for:
1264 * - Sun Ultra 40 M2: Dual Socket F (1207) + MCP55
1265 */
board_sun_ultra_40_m2(struct board_cfg * cfg)1266 static int board_sun_ultra_40_m2(struct board_cfg *cfg)
1267 {
1268 int ret;
1269 uint8_t reg;
1270 uint16_t base;
1271 struct pci_dev *dev;
1272
1273 ret = nvidia_mcp_gpio4_lower(cfg);
1274 if (ret)
1275 return ret;
1276
1277 dev = pcidev_find(0x10de, 0x0364); /* NVIDIA MCP55 LPC bridge */
1278 if (!dev) {
1279 msg_perr("\nERROR: NVIDIA MCP55 LPC bridge not found.\n");
1280 return -1;
1281 }
1282
1283 base = pci_read_word(dev, 0xb4); /* some IO BAR? */
1284 if (!base)
1285 return -1;
1286
1287 reg = INB(base + 0x4b);
1288 reg |= 0x10;
1289 OUTB(reg, base + 0x4b);
1290
1291 return 0;
1292 }
1293
1294 /*
1295 * Suited for:
1296 * - Artec Group DBE61 and DBE62
1297 */
board_artecgroup_dbe6x(struct board_cfg * cfg)1298 static int board_artecgroup_dbe6x(struct board_cfg *cfg)
1299 {
1300 #define DBE6x_MSR_DIVIL_BALL_OPTS 0x51400015
1301 #define DBE6x_PRI_BOOT_LOC_SHIFT 2
1302 #define DBE6x_BOOT_OP_LATCHED_SHIFT 8
1303 #define DBE6x_SEC_BOOT_LOC_SHIFT 10
1304 #define DBE6x_PRI_BOOT_LOC (3 << DBE6x_PRI_BOOT_LOC_SHIFT)
1305 #define DBE6x_BOOT_OP_LATCHED (3 << DBE6x_BOOT_OP_LATCHED_SHIFT)
1306 #define DBE6x_SEC_BOOT_LOC (3 << DBE6x_SEC_BOOT_LOC_SHIFT)
1307 #define DBE6x_BOOT_LOC_FLASH 2
1308 #define DBE6x_BOOT_LOC_FWHUB 3
1309
1310 msr_t msr;
1311 unsigned long boot_loc;
1312
1313 /* Geode only has a single core */
1314 if (msr_setup(0))
1315 return -1;
1316
1317 msr = msr_read(DBE6x_MSR_DIVIL_BALL_OPTS);
1318
1319 if ((msr.lo & (DBE6x_BOOT_OP_LATCHED)) ==
1320 (DBE6x_BOOT_LOC_FWHUB << DBE6x_BOOT_OP_LATCHED_SHIFT))
1321 boot_loc = DBE6x_BOOT_LOC_FWHUB;
1322 else
1323 boot_loc = DBE6x_BOOT_LOC_FLASH;
1324
1325 msr.lo &= ~(DBE6x_PRI_BOOT_LOC | DBE6x_SEC_BOOT_LOC);
1326 msr.lo |= ((boot_loc << DBE6x_PRI_BOOT_LOC_SHIFT) |
1327 (boot_loc << DBE6x_SEC_BOOT_LOC_SHIFT));
1328
1329 msr_write(DBE6x_MSR_DIVIL_BALL_OPTS, msr);
1330
1331 msr_cleanup();
1332
1333 return 0;
1334 }
1335
1336 /*
1337 * Suited for:
1338 * - ASUS A8AE-LE (Codename AmberineM; used in Compaq Presario 061)
1339 * Datasheet(s) used:
1340 * - AMD document 43009 "AMD SB700/710/750 Register Reference Guide" rev. 1.00
1341 */
amd_sbxxx_gpio9_raise(struct board_cfg * cfg)1342 static int amd_sbxxx_gpio9_raise(struct board_cfg *cfg)
1343 {
1344 struct pci_dev *dev;
1345 uint32_t reg;
1346
1347 dev = pcidev_find(0x1002, 0x4372); /* AMD SMBus controller */
1348 if (!dev) {
1349 msg_perr("\nERROR: AMD SMBus Controller (0x4372) not found.\n");
1350 return -1;
1351 }
1352
1353 reg = pci_read_long(dev, 0xA8); /* GPIO_12_to_4_Cntrl CI_Reg: A8h-ABh */
1354 /* enable output (0: enable, 1: tristate):
1355 GPIO9 output enable is at bit 5 in 0xA9 */
1356 reg &= ~((uint32_t)1<<(8+5));
1357 /* raise:
1358 GPIO9 output register is at bit 5 in 0xA8 */
1359 reg |= (1<<5);
1360 pci_write_long(dev, 0xA8, reg);
1361
1362 return 0;
1363 }
1364
1365 /*
1366 * Helper function to raise/drop a given gpo line on Intel PIIX4{,E,M}.
1367 */
intel_piix4_gpo_set(unsigned int gpo,int raise)1368 static int intel_piix4_gpo_set(unsigned int gpo, int raise)
1369 {
1370 unsigned int gpo_byte, gpo_bit;
1371 struct pci_dev *dev;
1372 uint32_t tmp, base;
1373
1374 /* GPO{0,8,27,28,30} are always available. */
1375 static const uint32_t nonmuxed_gpos = 0x58000101;
1376
1377 static const struct {unsigned int reg, mask, value; } piix4_gpo[] = {
1378 {0},
1379 {0xB0, 0x0001, 0x0000}, /* GPO1... */
1380 {0xB0, 0x0001, 0x0000},
1381 {0xB0, 0x0001, 0x0000},
1382 {0xB0, 0x0001, 0x0000},
1383 {0xB0, 0x0001, 0x0000},
1384 {0xB0, 0x0001, 0x0000},
1385 {0xB0, 0x0001, 0x0000}, /* ...GPO7: GENCFG bit 0 */
1386 {0},
1387 {0xB0, 0x0100, 0x0000}, /* GPO9: GENCFG bit 8 */
1388 {0xB0, 0x0200, 0x0000}, /* GPO10: GENCFG bit 9 */
1389 {0xB0, 0x0400, 0x0000}, /* GPO11: GENCFG bit 10 */
1390 {0x4E, 0x0100, 0x0000}, /* GPO12... */
1391 {0x4E, 0x0100, 0x0000},
1392 {0x4E, 0x0100, 0x0000}, /* ...GPO14: XBCS bit 8 */
1393 {0xB2, 0x0002, 0x0002}, /* GPO15... */
1394 {0xB2, 0x0002, 0x0002}, /* ...GPO16: GENCFG bit 17 */
1395 {0xB2, 0x0004, 0x0004}, /* GPO17: GENCFG bit 18 */
1396 {0xB2, 0x0008, 0x0008}, /* GPO18: GENCFG bit 19 */
1397 {0xB2, 0x0010, 0x0010}, /* GPO19: GENCFG bit 20 */
1398 {0xB2, 0x0020, 0x0020}, /* GPO20: GENCFG bit 21 */
1399 {0xB2, 0x0040, 0x0040}, /* GPO21: GENCFG bit 22 */
1400 {0xB2, 0x1000, 0x1000}, /* GPO22... */
1401 {0xB2, 0x1000, 0x1000}, /* ...GPO23: GENCFG bit 28 */
1402 {0xB2, 0x2000, 0x2000}, /* GPO24: GENCFG bit 29 */
1403 {0xB2, 0x4000, 0x4000}, /* GPO25: GENCFG bit 30 */
1404 {0xB2, 0x8000, 0x8000}, /* GPO26: GENCFG bit 31 */
1405 {0},
1406 {0},
1407 {0x4E, 0x0100, 0x0000}, /* ...GPO29: XBCS bit 8 */
1408 {0}
1409 };
1410
1411 dev = pcidev_find(0x8086, 0x7110); /* Intel PIIX4 ISA bridge */
1412 if (!dev) {
1413 msg_perr("\nERROR: Intel PIIX4 ISA bridge not found.\n");
1414 return -1;
1415 }
1416
1417 /* Sanity check. */
1418 if (gpo > 30) {
1419 msg_perr("\nERROR: Intel PIIX4 has no GPO%d.\n", gpo);
1420 return -1;
1421 }
1422
1423 if ((((1 << gpo) & nonmuxed_gpos) == 0) &&
1424 ((pci_read_word(dev, piix4_gpo[gpo].reg) & piix4_gpo[gpo].mask) !=
1425 piix4_gpo[gpo].value)) {
1426 msg_perr("\nERROR: PIIX4 GPO%d not programmed for output.\n", gpo);
1427 return -1;
1428 }
1429
1430 dev = pcidev_find(0x8086, 0x7113); /* Intel PIIX4 PM */
1431 if (!dev) {
1432 msg_perr("\nERROR: Intel PIIX4 PM not found.\n");
1433 return -1;
1434 }
1435
1436 /* PM IO base */
1437 base = pci_read_long(dev, 0x40) & 0x0000FFC0;
1438
1439 gpo_byte = gpo >> 3;
1440 gpo_bit = gpo & 7;
1441 tmp = INB(base + 0x34 + gpo_byte); /* GPO register */
1442 if (raise)
1443 tmp |= 0x01 << gpo_bit;
1444 else
1445 tmp &= ~(0x01 << gpo_bit);
1446 OUTB(tmp, base + 0x34 + gpo_byte);
1447
1448 return 0;
1449 }
1450
1451 /*
1452 * Suited for:
1453 * - ASUS OPLX-M
1454 * - ASUS P2B-N
1455 */
intel_piix4_gpo18_lower(struct board_cfg * cfg)1456 static int intel_piix4_gpo18_lower(struct board_cfg *cfg)
1457 {
1458 return intel_piix4_gpo_set(18, 0);
1459 }
1460
1461 /*
1462 * Suited for:
1463 * - MSI MS-6163 v2 (MS-6163 Pro): Intel 440BX + PIIX4E + Winbond W83977EF
1464 */
intel_piix4_gpo14_raise(struct board_cfg * cfg)1465 static int intel_piix4_gpo14_raise(struct board_cfg *cfg)
1466 {
1467 return intel_piix4_gpo_set(14, 1);
1468 }
1469
1470 /*
1471 * Suited for:
1472 * - EPoX EP-BX3
1473 */
intel_piix4_gpo22_raise(struct board_cfg * cfg)1474 static int intel_piix4_gpo22_raise(struct board_cfg *cfg)
1475 {
1476 return intel_piix4_gpo_set(22, 1);
1477 }
1478
1479 /*
1480 * Suited for:
1481 * - abit BM6
1482 */
intel_piix4_gpo26_lower(struct board_cfg * cfg)1483 static int intel_piix4_gpo26_lower(struct board_cfg *cfg)
1484 {
1485 return intel_piix4_gpo_set(26, 0);
1486 }
1487
1488 /*
1489 * Suited for:
1490 * - Intel SE440BX-2
1491 */
intel_piix4_gpo27_lower(struct board_cfg * cfg)1492 static int intel_piix4_gpo27_lower(struct board_cfg *cfg)
1493 {
1494 return intel_piix4_gpo_set(27, 0);
1495 }
1496
1497 /*
1498 * Suited for:
1499 * - Dell OptiPlex GX1
1500 */
intel_piix4_gpo30_lower(struct board_cfg * cfg)1501 static int intel_piix4_gpo30_lower(struct board_cfg *cfg)
1502 {
1503 return intel_piix4_gpo_set(30, 0);
1504 }
1505
1506 /*
1507 * Set a GPIO line on a given Intel ICH LPC controller.
1508 */
intel_ich_gpio_set(int gpio,int raise)1509 static int intel_ich_gpio_set(int gpio, int raise)
1510 {
1511 /* Table mapping the different Intel ICH LPC chipsets. */
1512 static struct {
1513 uint16_t id;
1514 uint8_t base_reg;
1515 uint32_t bank0;
1516 uint32_t bank1;
1517 uint32_t bank2;
1518 } intel_ich_gpio_table[] = {
1519 {0x2410, 0x58, 0x0FE30000, 0, 0}, /* 82801AA (ICH) */
1520 {0x2420, 0x58, 0x0FE30000, 0, 0}, /* 82801AB (ICH0) */
1521 {0x2440, 0x58, 0x1BFF391B, 0, 0}, /* 82801BA (ICH2) */
1522 {0x244C, 0x58, 0x1A23399B, 0, 0}, /* 82801BAM (ICH2M) */
1523 {0x2450, 0x58, 0x1BFF0000, 0, 0}, /* 82801E (C-ICH) */
1524 {0x2480, 0x58, 0x1BFF0000, 0x00000FFF, 0}, /* 82801CA (ICH3-S) */
1525 {0x248C, 0x58, 0x1A230000, 0x00000FFF, 0}, /* 82801CAM (ICH3-M) */
1526 {0x24C0, 0x58, 0x1BFF0000, 0x00000FFF, 0}, /* 82801DB/DBL (ICH4/ICH4-L) */
1527 {0x24CC, 0x58, 0x1A030000, 0x00000FFF, 0}, /* 82801DBM (ICH4-M) */
1528 {0x24D0, 0x58, 0x1BFF0000, 0x00030305, 0}, /* 82801EB/ER (ICH5/ICH5R) */
1529 {0x2640, 0x48, 0x1BFF0000, 0x00030307, 0}, /* 82801FB/FR (ICH6/ICH6R) */
1530 {0x2641, 0x48, 0x1BFF0000, 0x00030307, 0}, /* 82801FBM (ICH6M) */
1531 {0x27B0, 0x48, 0xFFFFFFFF, 0x000300FF, 0}, /* 82801GDH (ICH7 DH) */
1532 {0x27B8, 0x48, 0xFFFFFFFF, 0x000300FF, 0}, /* 82801GB/GR (ICH7 Family) */
1533 {0x27B9, 0x48, 0xFFEBFFFE, 0x000300FE, 0}, /* 82801GBM (ICH7-M) */
1534 {0x27BD, 0x48, 0xFFEBFFFE, 0x000300FE, 0}, /* 82801GHM (ICH7-M DH) */
1535 {0x2810, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HB/HR (ICH8/R) */
1536 {0x2811, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HBM (ICH8M-E) */
1537 {0x2812, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HH (ICH8DH) */
1538 {0x2814, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HO (ICH8DO) */
1539 {0x2815, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HEM (ICH8M) */
1540 {0x2912, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IH (ICH9DH) */
1541 {0x2914, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IO (ICH9DO) */
1542 {0x2916, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IR (ICH9R) */
1543 {0x2917, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IEM (ICH9M-E) */
1544 {0x2918, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IB (ICH9) */
1545 {0x2919, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IBM (ICH9M) */
1546 {0x3A14, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JDO (ICH10DO) */
1547 {0x3A16, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JIR (ICH10R) */
1548 {0x3A18, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JIB (ICH10) */
1549 {0x3A1A, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JD (ICH10D) */
1550 {0, 0, 0, 0, 0} /* end marker */
1551 };
1552
1553 struct pci_dev *dev;
1554 uint16_t base;
1555 uint32_t tmp;
1556 int i, allowed;
1557
1558 /* First, look for a known LPC bridge */
1559 dev = pcidev_find_vendorclass(0x8086, 0x0601); /* ISA bridge */
1560 if (!dev) {
1561 msg_perr("\nERROR: No known Intel LPC bridge found.\n");
1562 return -1;
1563 }
1564 /* Is this device in our list? */
1565 for (i = 0; intel_ich_gpio_table[i].id; i++)
1566 if (dev->device_id == intel_ich_gpio_table[i].id)
1567 break;
1568
1569 if (!intel_ich_gpio_table[i].id) {
1570 msg_perr("\nERROR: No known Intel LPC bridge found.\n");
1571 return -1;
1572 }
1573
1574 /*
1575 * According to the datasheets, all Intel ICHs have the GPIO bar 5:1
1576 * strapped to zero. From some mobile ICH9 version on, this becomes
1577 * 6:1. The mask below catches all.
1578 */
1579 base = pci_read_word(dev, intel_ich_gpio_table[i].base_reg) & 0xFFC0;
1580
1581 /* Check whether the line is allowed. */
1582 if (gpio < 32)
1583 allowed = (intel_ich_gpio_table[i].bank0 >> gpio) & 0x01;
1584 else if (gpio < 64)
1585 allowed = (intel_ich_gpio_table[i].bank1 >> (gpio - 32)) & 0x01;
1586 else
1587 allowed = (intel_ich_gpio_table[i].bank2 >> (gpio - 64)) & 0x01;
1588
1589 if (!allowed) {
1590 msg_perr("\nERROR: This Intel LPC bridge does not allow"
1591 " setting GPIO%02d\n", gpio);
1592 return -1;
1593 }
1594
1595 msg_pdbg("\nIntel ICH LPC bridge: %sing GPIO%02d.\n",
1596 raise ? "Rais" : "Dropp", gpio);
1597
1598 if (gpio < 32) {
1599 /* Set line to GPIO. */
1600 tmp = INL(base);
1601 /* ICH/ICH0 multiplexes 27/28 on the line set. */
1602 if ((gpio == 28) &&
1603 ((dev->device_id == 0x2410) || (dev->device_id == 0x2420)))
1604 tmp |= 1 << 27;
1605 else
1606 tmp |= 1 << gpio;
1607 OUTL(tmp, base);
1608
1609 /* As soon as we are talking to ICH8 and above, this register
1610 decides whether we can set the gpio or not. */
1611 if (dev->device_id > 0x2800) {
1612 tmp = INL(base);
1613 if (!(tmp & (1 << gpio))) {
1614 msg_perr("\nERROR: This Intel LPC bridge"
1615 " does not allow setting GPIO%02d\n",
1616 gpio);
1617 return -1;
1618 }
1619 }
1620
1621 /* Set GPIO to OUTPUT. */
1622 tmp = INL(base + 0x04);
1623 tmp &= ~(1 << gpio);
1624 OUTL(tmp, base + 0x04);
1625
1626 /* Raise GPIO line. */
1627 tmp = INL(base + 0x0C);
1628 if (raise)
1629 tmp |= 1 << gpio;
1630 else
1631 tmp &= ~(1 << gpio);
1632 OUTL(tmp, base + 0x0C);
1633 } else if (gpio < 64) {
1634 gpio -= 32;
1635
1636 /* Set line to GPIO. */
1637 tmp = INL(base + 0x30);
1638 tmp |= 1 << gpio;
1639 OUTL(tmp, base + 0x30);
1640
1641 /* As soon as we are talking to ICH8 and above, this register
1642 decides whether we can set the gpio or not. */
1643 if (dev->device_id > 0x2800) {
1644 tmp = INL(base + 30);
1645 if (!(tmp & (1 << gpio))) {
1646 msg_perr("\nERROR: This Intel LPC bridge"
1647 " does not allow setting GPIO%02d\n",
1648 gpio + 32);
1649 return -1;
1650 }
1651 }
1652
1653 /* Set GPIO to OUTPUT. */
1654 tmp = INL(base + 0x34);
1655 tmp &= ~(1 << gpio);
1656 OUTL(tmp, base + 0x34);
1657
1658 /* Raise GPIO line. */
1659 tmp = INL(base + 0x38);
1660 if (raise)
1661 tmp |= 1 << gpio;
1662 else
1663 tmp &= ~(1 << gpio);
1664 OUTL(tmp, base + 0x38);
1665 } else {
1666 gpio -= 64;
1667
1668 /* Set line to GPIO. */
1669 tmp = INL(base + 0x40);
1670 tmp |= 1 << gpio;
1671 OUTL(tmp, base + 0x40);
1672
1673 tmp = INL(base + 40);
1674 if (!(tmp & (1 << gpio))) {
1675 msg_perr("\nERROR: This Intel LPC bridge does "
1676 "not allow setting GPIO%02d\n", gpio + 64);
1677 return -1;
1678 }
1679
1680 /* Set GPIO to OUTPUT. */
1681 tmp = INL(base + 0x44);
1682 tmp &= ~(1 << gpio);
1683 OUTL(tmp, base + 0x44);
1684
1685 /* Raise GPIO line. */
1686 tmp = INL(base + 0x48);
1687 if (raise)
1688 tmp |= 1 << gpio;
1689 else
1690 tmp &= ~(1 << gpio);
1691 OUTL(tmp, base + 0x48);
1692 }
1693
1694 return 0;
1695 }
1696
1697 /*
1698 * Suited for:
1699 * - abit IP35: Intel P35 + ICH9R
1700 * - abit IP35 Pro: Intel P35 + ICH9R
1701 * - ASUS P5LD2
1702 * - ASUS P5LD2-MQ
1703 * - ASUS P5LD2-VM
1704 * - ASUS P5LD2-VM DH
1705 * - ASUS P5W DH Deluxe
1706 */
intel_ich_gpio16_raise(struct board_cfg * cfg)1707 static int intel_ich_gpio16_raise(struct board_cfg *cfg)
1708 {
1709 return intel_ich_gpio_set(16, 1);
1710 }
1711
1712 /*
1713 * Suited for:
1714 * - HP Puffer2-UL8E (ASUS PTGD-LA OEM): LGA775 + 915 + ICH6
1715 */
intel_ich_gpio18_raise(struct board_cfg * cfg)1716 static int intel_ich_gpio18_raise(struct board_cfg *cfg)
1717 {
1718 return intel_ich_gpio_set(18, 1);
1719 }
1720
1721 /*
1722 * Suited for:
1723 * - MSI MS-7046: LGA775 + 915P + ICH6
1724 */
intel_ich_gpio19_raise(struct board_cfg * cfg)1725 static int intel_ich_gpio19_raise(struct board_cfg *cfg)
1726 {
1727 return intel_ich_gpio_set(19, 1);
1728 }
1729
1730 /*
1731 * Suited for:
1732 * - ASUS P5BV-R: LGA775 + 3200 + ICH7
1733 * - AOpen i965GMt-LA: Intel Socket479 + 965GM + ICH8M
1734 */
intel_ich_gpio20_raise(struct board_cfg * cfg)1735 static int intel_ich_gpio20_raise(struct board_cfg *cfg)
1736 {
1737 return intel_ich_gpio_set(20, 1);
1738 }
1739
1740 /*
1741 * Suited for:
1742 * - ASUS CUSL2-C: Intel socket370 + 815 + ICH2
1743 * - ASUS P4B266LM (Sony Vaio PCV-RX650): socket478 + 845D + ICH2
1744 * - ASUS P4C800-E Deluxe: socket478 + 875P + ICH5
1745 * - ASUS P4P800: Intel socket478 + 865PE + ICH5R
1746 * - ASUS P4P800-E Deluxe: Intel socket478 + 865PE + ICH5R
1747 * - ASUS P4P800-VM: Intel socket478 + 865PE + ICH5R
1748 * - ASUS P4P800-X: Intel socket478 + 865PE + ICH5R
1749 * - ASUS P4P800SE: Intel socket478 + 865PE + ICH5R
1750 * - ASUS P5GD1 Pro: Intel LGA 775 + 915P + ICH6R
1751 * - ASUS P5GD2 Premium: Intel LGA775 + 915G + ICH6R
1752 * - ASUS P5GDC Deluxe: Intel socket775 + 915P + ICH6R
1753 * - ASUS P5PE-VM: Intel LGA775 + 865G + ICH5
1754 * - ASUS TUSL2-C: Intel socket370 + 815 + ICH2
1755 * - Samsung Polaris 32: socket478 + 865P + ICH5
1756 */
intel_ich_gpio21_raise(struct board_cfg * cfg)1757 static int intel_ich_gpio21_raise(struct board_cfg *cfg)
1758 {
1759 return intel_ich_gpio_set(21, 1);
1760 }
1761
1762 /*
1763 * Suited for:
1764 * - ASUS P4B266: socket478 + Intel 845D + ICH2
1765 * - ASUS P4B533-E: socket478 + 845E + ICH4
1766 * - ASUS P4B-MX variant in HP Vectra VL420 SFF: socket478 + 845D + ICH2
1767 * - TriGem Anaheim-3: socket370 + Intel 810 + ICH
1768 */
intel_ich_gpio22_raise(struct board_cfg * cfg)1769 static int intel_ich_gpio22_raise(struct board_cfg *cfg)
1770 {
1771 return intel_ich_gpio_set(22, 1);
1772 }
1773
1774 /*
1775 * Suited for:
1776 * - ASUS A8Jm (laptop): Intel 945 + ICH7
1777 * - ASUS P5LP-LE used in ...
1778 * - HP Media Center m7270.fr Desktop PC as "Lithium-UL8E"
1779 * - Epson Endeavor MT7700
1780 */
intel_ich_gpio34_raise(struct board_cfg * cfg)1781 static int intel_ich_gpio34_raise(struct board_cfg *cfg)
1782 {
1783 return intel_ich_gpio_set(34, 1);
1784 }
1785
1786 /*
1787 * Suited for:
1788 * - AOpen i945GMx-VFX: Intel 945GM + ICH7-M used in ...
1789 * - FSC ESPRIMO Q5010 (SMBIOS: D2544-B1)
1790 */
intel_ich_gpio38_raise(struct board_cfg * cfg)1791 static int intel_ich_gpio38_raise(struct board_cfg *cfg)
1792 {
1793 return intel_ich_gpio_set(38, 1);
1794 }
1795
1796 /*
1797 * Suited for:
1798 * - ASUS M6Ne (laptop): socket 479M (guessed) + Intel 855PM + ICH4-M
1799 */
intel_ich_gpio43_raise(struct board_cfg * cfg)1800 static int intel_ich_gpio43_raise(struct board_cfg *cfg)
1801 {
1802 return intel_ich_gpio_set(43, 1);
1803 }
1804
1805 /*
1806 * Suited for:
1807 * - HP Vectra VL400: 815 + ICH + PC87360
1808 */
board_hp_vl400(struct board_cfg * cfg)1809 static int board_hp_vl400(struct board_cfg *cfg)
1810 {
1811 int ret;
1812 ret = intel_ich_gpio_set(25, 1); /* Master write enable ? */
1813 if (!ret)
1814 ret = pc8736x_gpio_set(PC87360_ID, 0x09, 1); /* #WP ? */
1815 if (!ret)
1816 ret = pc8736x_gpio_set(PC87360_ID, 0x27, 1); /* #TBL */
1817 return ret;
1818 }
1819
1820 /*
1821 * Suited for:
1822 * - HP e-Vectra P2706T: 810E + ICH + PC87364
1823 */
board_hp_p2706t(struct board_cfg * cfg)1824 static int board_hp_p2706t(struct board_cfg *cfg)
1825 {
1826 int ret;
1827 ret = pc8736x_gpio_set(PC87364_ID, 0x25, 1);
1828 if (!ret)
1829 ret = pc8736x_gpio_set(PC87364_ID, 0x26, 1);
1830 return ret;
1831 }
1832
1833 /*
1834 * Suited for:
1835 * - Dell PowerEdge 1850: Intel PPGA604 + E7520 + ICH5R
1836 * - ASRock P4i65GV: Intel Socket478 + 865GV + ICH5R
1837 * - ASRock 775i65G: Intel LGA 775 + 865G + ICH5
1838 * - MSI MS-6391 (845 Pro4): Intel Socket478 + 845 + ICH2
1839 */
intel_ich_gpio23_raise(struct board_cfg * cfg)1840 static int intel_ich_gpio23_raise(struct board_cfg *cfg)
1841 {
1842 return intel_ich_gpio_set(23, 1);
1843 }
1844
1845 /*
1846 * Suited for:
1847 * - GIGABYTE GA-6IEM: Intel Socket370 + i815 + ICH2
1848 * - GIGABYTE GA-8IRML: Intel Socket478 + i845 + ICH2
1849 */
intel_ich_gpio25_raise(struct board_cfg * cfg)1850 static int intel_ich_gpio25_raise(struct board_cfg *cfg)
1851 {
1852 return intel_ich_gpio_set(25, 1);
1853 }
1854
1855 /*
1856 * Suited for:
1857 * - IBASE MB899: i945GM + ICH7
1858 */
intel_ich_gpio26_raise(struct board_cfg * cfg)1859 static int intel_ich_gpio26_raise(struct board_cfg *cfg)
1860 {
1861 return intel_ich_gpio_set(26, 1);
1862 }
1863
1864 /*
1865 * Suited for:
1866 * - ASUS DSAN-DX
1867 * - P4SD-LA (HP OEM): i865 + ICH5
1868 * - GIGABYTE GA-8IP775: 865P + ICH5
1869 * - GIGABYTE GA-8PE667 Ultra 2: socket 478 + i845PE + ICH4
1870 * - MSI MS-6788-40 (aka 848P Neo-V)
1871 */
intel_ich_gpio32_raise(struct board_cfg * cfg)1872 static int intel_ich_gpio32_raise(struct board_cfg *cfg)
1873 {
1874 return intel_ich_gpio_set(32, 1);
1875 }
1876
1877 /*
1878 * Suited for:
1879 * - AOpen i975Xa-YDG: i975X + ICH7 + W83627EHF
1880 */
board_aopen_i975xa_ydg(struct board_cfg * cfg)1881 static int board_aopen_i975xa_ydg(struct board_cfg *cfg)
1882 {
1883 int ret;
1884
1885 /* Vendor BIOS ends up in LDN6... maybe the board enable is wrong,
1886 * or perhaps it's not needed at all?
1887 * The regs it tries to touch are 0xF0, 0xF1, 0xF2 which means if it
1888 * were in the right LDN, it would have to be GPIO1 or GPIO3.
1889 */
1890 /*
1891 ret = winbond_gpio_set(0x2e, WINBOND_W83627EHF_ID, x, 0)
1892 if (!ret)
1893 */
1894 ret = intel_ich_gpio_set(33, 1);
1895
1896 return ret;
1897 }
1898
1899 /*
1900 * Suited for:
1901 * - Acorp 6A815EPD: socket 370 + intel 815 + ICH2
1902 */
board_acorp_6a815epd(struct board_cfg * cfg)1903 static int board_acorp_6a815epd(struct board_cfg *cfg)
1904 {
1905 int ret;
1906
1907 /* Lower Blocks Lock -- pin 7 of PLCC32 */
1908 ret = intel_ich_gpio_set(22, 1);
1909 if (!ret) /* Top Block Lock -- pin 8 of PLCC32 */
1910 ret = intel_ich_gpio_set(23, 1);
1911
1912 return ret;
1913 }
1914
1915 /*
1916 * Suited for:
1917 * - Kontron 986LCD-M: Socket478 + 915GM + ICH7R
1918 */
board_kontron_986lcd_m(struct board_cfg * cfg)1919 static int board_kontron_986lcd_m(struct board_cfg *cfg)
1920 {
1921 int ret;
1922
1923 ret = intel_ich_gpio_set(34, 1); /* #TBL */
1924 if (!ret)
1925 ret = intel_ich_gpio_set(35, 1); /* #WP */
1926
1927 return ret;
1928 }
1929
1930 /*
1931 * Suited for:
1932 * - Soyo SY-7VCA: Pro133A + VT82C686
1933 */
via_apollo_gpo_set(int gpio,int raise)1934 static int via_apollo_gpo_set(int gpio, int raise)
1935 {
1936 struct pci_dev *dev;
1937 uint32_t base, tmp;
1938
1939 /* VT82C686 power management */
1940 dev = pcidev_find(0x1106, 0x3057);
1941 if (!dev) {
1942 msg_perr("\nERROR: VT82C686 PM device not found.\n");
1943 return -1;
1944 }
1945
1946 msg_pdbg("\nVIA Apollo ACPI: %sing GPIO%02d.\n",
1947 raise ? "Rais" : "Dropp", gpio);
1948
1949 /* Select GPO function on multiplexed pins. */
1950 tmp = pci_read_byte(dev, 0x54);
1951 switch (gpio) {
1952 case 0:
1953 tmp &= ~0x03;
1954 break;
1955 case 1:
1956 tmp |= 0x04;
1957 break;
1958 case 2:
1959 tmp |= 0x08;
1960 break;
1961 case 3:
1962 tmp |= 0x10;
1963 break;
1964 }
1965 pci_write_byte(dev, 0x54, tmp);
1966
1967 /* PM IO base */
1968 base = pci_read_long(dev, 0x48) & 0x0000FF00;
1969
1970 /* Drop GPO0 */
1971 tmp = INL(base + 0x4C);
1972 if (raise)
1973 tmp |= 1U << gpio;
1974 else
1975 tmp &= ~(1U << gpio);
1976 OUTL(tmp, base + 0x4C);
1977
1978 return 0;
1979 }
1980
1981 /*
1982 * Suited for:
1983 * - abit VT6X4: Pro133x + VT82C686A
1984 * - abit VA6: Pro133x + VT82C686A
1985 */
via_apollo_gpo4_lower(struct board_cfg * cfg)1986 static int via_apollo_gpo4_lower(struct board_cfg *cfg)
1987 {
1988 return via_apollo_gpo_set(4, 0);
1989 }
1990
1991 /*
1992 * Suited for:
1993 * - Soyo SY-7VCA: Pro133A + VT82C686
1994 */
via_apollo_gpo0_lower(struct board_cfg * cfg)1995 static int via_apollo_gpo0_lower(struct board_cfg *cfg)
1996 {
1997 return via_apollo_gpo_set(0, 0);
1998 }
1999
2000 /*
2001 * Enable some GPIO pin on SiS southbridge and enables SIO flash writes.
2002 *
2003 * Suited for:
2004 * - MSI 651M-L: SiS651 / SiS962
2005 * - GIGABYTE GA-8SIMLFS 2.0
2006 * - GIGABYTE GA-8SIMLH
2007 */
sis_gpio0_raise_and_w836xx_memw(struct board_cfg * cfg)2008 static int sis_gpio0_raise_and_w836xx_memw(struct board_cfg *cfg)
2009 {
2010 struct pci_dev *dev;
2011 uint16_t base, temp;
2012
2013 dev = pcidev_find(0x1039, 0x0962);
2014 if (!dev) {
2015 msg_perr("Expected south bridge not found\n");
2016 return 1;
2017 }
2018
2019 base = pci_read_word(dev, 0x74);
2020 temp = INW(base + 0x68);
2021 temp &= ~(1 << 0); /* Make pin output? */
2022 OUTW(temp, base + 0x68);
2023
2024 temp = INW(base + 0x64);
2025 temp |= (1 << 0); /* Raise output? */
2026 OUTW(temp, base + 0x64);
2027
2028 w836xx_memw_enable(0x2E);
2029
2030 return 0;
2031 }
2032
2033 /*
2034 * Find the runtime registers of an SMSC Super I/O, after verifying its
2035 * chip ID.
2036 *
2037 * Returns the base port of the runtime register block, or 0 on error.
2038 */
smsc_find_runtime(uint16_t sio_port,uint16_t chip_id,uint8_t logical_device)2039 static uint16_t smsc_find_runtime(uint16_t sio_port, uint16_t chip_id,
2040 uint8_t logical_device)
2041 {
2042 uint16_t rt_port = 0;
2043
2044 /* Verify the chip ID. */
2045 OUTB(0x55, sio_port); /* Enable configuration. */
2046 if (sio_read(sio_port, 0x20) != chip_id) {
2047 msg_perr("\nERROR: SMSC Super I/O not found.\n");
2048 goto out;
2049 }
2050
2051 /* If the runtime block is active, get its address. */
2052 sio_write(sio_port, 0x07, logical_device);
2053 if (sio_read(sio_port, 0x30) & 1) {
2054 rt_port = (sio_read(sio_port, 0x60) << 8)
2055 | sio_read(sio_port, 0x61);
2056 }
2057
2058 if (rt_port == 0) {
2059 msg_perr("\nERROR: "
2060 "Super I/O runtime interface not available.\n");
2061 }
2062 out:
2063 OUTB(0xaa, sio_port); /* Disable configuration. */
2064 return rt_port;
2065 }
2066
2067 /*
2068 * Disable write protection on the Mitac 6513WU. WP# on the FWH is
2069 * connected to GP30 on the Super I/O, and TBL# is always high.
2070 */
board_mitac_6513wu(struct board_cfg * cfg)2071 static int board_mitac_6513wu(struct board_cfg *cfg)
2072 {
2073 struct pci_dev *dev;
2074 uint16_t rt_port;
2075 uint8_t val;
2076
2077 dev = pcidev_find(0x8086, 0x2410); /* Intel 82801AA ISA bridge */
2078 if (!dev) {
2079 msg_perr("\nERROR: Intel 82801AA ISA bridge not found.\n");
2080 return -1;
2081 }
2082
2083 rt_port = smsc_find_runtime(0x4e, 0x54 /* LPC47U33x */, 0xa);
2084 if (rt_port == 0)
2085 return -1;
2086
2087 /* Configure the GPIO pin. */
2088 val = INB(rt_port + 0x33); /* GP30 config */
2089 val &= ~0x87; /* Output, non-inverted, GPIO, push/pull */
2090 OUTB(val, rt_port + 0x33);
2091
2092 /* Disable write protection. */
2093 val = INB(rt_port + 0x4d); /* GP3 values */
2094 val |= 0x01; /* Set GP30 high. */
2095 OUTB(val, rt_port + 0x4d);
2096
2097 return 0;
2098 }
2099
2100 /*
2101 * Suited for:
2102 * - abit AV8: Socket939 + K8T800Pro + VT8237
2103 */
board_abit_av8(struct board_cfg * cfg)2104 static int board_abit_av8(struct board_cfg *cfg)
2105 {
2106 uint8_t val;
2107
2108 /* Raise GPO pins GP22 & GP23 */
2109 val = INB(0x404E);
2110 val |= 0xC0;
2111 OUTB(val, 0x404E);
2112
2113 return 0;
2114 }
2115
2116 /*
2117 * Suited for:
2118 * - ASUS A7V333: VIA KT333 + VT8233A + IT8703F
2119 * - ASUS A7V8X: VIA KT400 + VT8235 + IT8703F
2120 */
it8703f_gpio51_raise(struct board_cfg * cfg)2121 static int it8703f_gpio51_raise(struct board_cfg *cfg)
2122 {
2123 uint16_t id, base;
2124 uint8_t tmp;
2125
2126 /* Find the IT8703F. */
2127 w836xx_ext_enter(0x2E);
2128 id = (sio_read(0x2E, 0x20) << 8) | sio_read(0x2E, 0x21);
2129 w836xx_ext_leave(0x2E);
2130
2131 if (id != 0x8701) {
2132 msg_perr("\nERROR: IT8703F Super I/O not found.\n");
2133 return -1;
2134 }
2135
2136 /* Get the GP567 I/O base. */
2137 w836xx_ext_enter(0x2E);
2138 sio_write(0x2E, 0x07, 0x0C);
2139 base = (sio_read(0x2E, 0x60) << 8) | sio_read(0x2E, 0x61);
2140 w836xx_ext_leave(0x2E);
2141
2142 if (!base) {
2143 msg_perr("\nERROR: Failed to read IT8703F Super I/O GPIO"
2144 " Base.\n");
2145 return -1;
2146 }
2147
2148 /* Raise GP51. */
2149 tmp = INB(base);
2150 tmp |= 0x02;
2151 OUTB(tmp, base);
2152
2153 return 0;
2154 }
2155
2156 /*
2157 * General routine for raising/dropping GPIO lines on the ITE IT87xx.
2158 */
it87_gpio_set(unsigned int gpio,int raise)2159 static int it87_gpio_set(unsigned int gpio, int raise)
2160 {
2161 int allowed, sio;
2162 unsigned int port;
2163 uint16_t base, sioport;
2164 uint8_t tmp;
2165
2166 /* IT87 GPIO configuration table */
2167 static const struct it87cfg {
2168 uint16_t id;
2169 uint8_t base_reg;
2170 uint32_t bank0;
2171 uint32_t bank1;
2172 uint32_t bank2;
2173 } it87_gpio_table[] = {
2174 {0x8712, 0x62, 0xCFF3FC00, 0x00FCFF3F, 0},
2175 {0x8718, 0x62, 0xCFF37C00, 0xF3FCDF3F, 0x0000000F},
2176 {0, 0, 0, 0, 0} /* end marker */
2177 };
2178 const struct it87cfg *cfg = NULL;
2179
2180 /* Find the Super I/O in the probed list */
2181 for (sio = 0; sio < superio_count; sio++) {
2182 int i;
2183 if (superios[sio].vendor != SUPERIO_VENDOR_ITE)
2184 continue;
2185
2186 /* Is this device in our list? */
2187 for (i = 0; it87_gpio_table[i].id; i++)
2188 if (superios[sio].model == it87_gpio_table[i].id) {
2189 cfg = &it87_gpio_table[i];
2190 goto found;
2191 }
2192 }
2193
2194 if (cfg == NULL) {
2195 msg_perr("\nERROR: No IT87 Super I/O GPIO configuration "
2196 "found.\n");
2197 return -1;
2198 }
2199
2200 found:
2201 /* Check whether the gpio is allowed. */
2202 if (gpio < 32)
2203 allowed = (cfg->bank0 >> gpio) & 0x01;
2204 else if (gpio < 64)
2205 allowed = (cfg->bank1 >> (gpio - 32)) & 0x01;
2206 else if (gpio < 96)
2207 allowed = (cfg->bank2 >> (gpio - 64)) & 0x01;
2208 else
2209 allowed = 0;
2210
2211 if (!allowed) {
2212 msg_perr("\nERROR: IT%02X does not allow setting GPIO%02u.\n",
2213 cfg->id, gpio);
2214 return -1;
2215 }
2216
2217 /* Read the Simple I/O Base Address Register */
2218 sioport = superios[sio].port;
2219 enter_conf_mode_ite(sioport);
2220 sio_write(sioport, 0x07, 0x07);
2221 base = (sio_read(sioport, cfg->base_reg) << 8) |
2222 sio_read(sioport, cfg->base_reg + 1);
2223 exit_conf_mode_ite(sioport);
2224
2225 if (!base) {
2226 msg_perr("\nERROR: Failed to read IT87 Super I/O GPIO Base.\n");
2227 return -1;
2228 }
2229
2230 msg_pdbg("Using IT87 GPIO base 0x%04x\n", base);
2231
2232 port = gpio / 10 - 1;
2233 gpio %= 10;
2234
2235 /* set GPIO. */
2236 tmp = INB(base + port);
2237 if (raise)
2238 tmp |= 1 << gpio;
2239 else
2240 tmp &= ~(1 << gpio);
2241 OUTB(tmp, base + port);
2242
2243 return 0;
2244 }
2245
2246 /*
2247 * Suited for:
2248 * - ASUS A7N8X-VM/400: NVIDIA nForce2 IGP2 + IT8712F
2249 */
it8712f_gpio12_raise(struct board_cfg * cfg)2250 static int it8712f_gpio12_raise(struct board_cfg *cfg)
2251 {
2252 return it87_gpio_set(12, 1);
2253 }
2254
2255 /*
2256 * Suited for:
2257 * - ASUS A7V600-X: VIA KT600 + VT8237 + IT8712F
2258 * - ASUS A7V8X-X: VIA KT400 + VT8235 + IT8712F
2259 */
it8712f_gpio31_raise(struct board_cfg * cfg)2260 static int it8712f_gpio31_raise(struct board_cfg *cfg)
2261 {
2262 return it87_gpio_set(32, 1);
2263 }
2264
2265 /*
2266 * Suited for:
2267 * - ASUS P5N-D: NVIDIA MCP51 + IT8718F
2268 * - ASUS P5N-E SLI: NVIDIA MCP51 + IT8718F
2269 */
it8718f_gpio63_raise(struct board_cfg * cfg)2270 static int it8718f_gpio63_raise(struct board_cfg *cfg)
2271 {
2272 return it87_gpio_set(63, 1);
2273 }
2274
2275 /*
2276 * Suited for all boards with ambiguous DMI chassis information, which should be
2277 * whitelisted because they are known to work:
2278 * - ASRock IMB-A180(-H)
2279 * - Intel D945GCNL
2280 * - MSC Q7 Tunnel Creek Module (Q7-TCTC)
2281 */
p2_not_a_laptop(struct board_cfg * cfg)2282 static int p2_not_a_laptop(struct board_cfg *cfg)
2283 {
2284 /* label this board as not a laptop */
2285 cfg->is_laptop = 0;
2286 msg_pdbg("Laptop detection overridden by P2 board enable.\n");
2287 return 0;
2288 }
2289
2290 /*
2291 * Suited for all laptops, which are known to *not* have interfering embedded controllers.
2292 */
p2_whitelist_laptop(struct board_cfg * cfg)2293 static int p2_whitelist_laptop(struct board_cfg *cfg)
2294 {
2295 cfg->is_laptop = 1;
2296 cfg->laptop_ok = true;
2297 msg_pdbg("Whitelisted laptop detected.\n");
2298 return 0;
2299 }
2300
2301 #endif
2302
2303 /*
2304 * Below is the list of boards which need a special "board enable" code in
2305 * flashrom before their ROM chip can be accessed/written to.
2306 *
2307 * NOTE: Please add boards that _don't_ need such enables or don't work yet
2308 * to the respective tables in print.c. Thanks!
2309 *
2310 * We use 2 sets of PCI IDs here, you're free to choose which is which. This
2311 * is to provide a very high degree of certainty when matching a board on
2312 * the basis of subsystem/card IDs. As not every vendor handles
2313 * subsystem/card IDs in a sane manner.
2314 *
2315 * Keep the second set NULLed if it should be ignored. Keep the subsystem IDs
2316 * and the dmi identifier NULLed if they don't identify the board fully to disable autodetection.
2317 * But please take care to provide an as complete set of pci ids as possible;
2318 * autodetection is the preferred behaviour and we would like to make sure that
2319 * matches are unique.
2320 *
2321 * If PCI IDs are not sufficient for board matching, the match can be further
2322 * constrained by a string that has to be present in the DMI database for
2323 * the baseboard or the system entry. The pattern is matched by case sensitive
2324 * substring match, unless it is anchored to the beginning (with a ^ in front)
2325 * or the end (with a $ at the end). Both anchors may be specified at the
2326 * same time to match the full field.
2327 *
2328 * When a board is matched through DMI, the first and second main PCI IDs
2329 * and the first subsystem PCI ID have to match as well. If you specify the
2330 * first subsystem ID as 0x0:0x0, the DMI matching code expects that the
2331 * subsystem ID of that device is indeed zero.
2332 *
2333 * The coreboot ids are used two fold. When running with a coreboot firmware,
2334 * the ids uniquely matches the coreboot board identification string. When a
2335 * legacy bios is installed and when autodetection is not possible, these ids
2336 * can be used to identify the board through the -p internal:mainboard=
2337 * programmer parameter.
2338 *
2339 * When a board is identified through its coreboot ids (in both cases), the
2340 * main pci ids are still required to match, as a safeguard.
2341 */
2342
2343 /* Please keep this list alphabetically ordered by vendor/board name. */
2344 const struct board_match board_matches[] = {
2345
2346 /* first pci-id set [4], second pci-id set [4], dmi identifier, coreboot id [2], phase, vendor name, board name max_rom_... OK? flash enable */
2347 #if defined(__i386__) || defined(__x86_64__)
2348 {0x10DE, 0x0547, 0x147B, 0x1C2F, 0x10DE, 0x0548, 0x147B, 0x1C2F, NULL, NULL, NULL, P3, "abit", "AN-M2", 0, NT, nvidia_mcp_gpio2_raise},
2349 {0x1106, 0x0282, 0x147B, 0x1415, 0x1106, 0x3227, 0x147B, 0x1415, "^AV8 ", NULL, NULL, P3, "abit", "AV8", 0, OK, board_abit_av8},
2350 {0x8086, 0x7190, 0, 0, 0x8086, 0x7110, 0, 0, NULL /* "^I440BX-W977$" */, "abit", "bf6", P3, "abit", "BF6", 0, OK, intel_piix4_gpo26_lower},
2351 {0x8086, 0x7190, 0, 0, 0x8086, 0x7110, 0, 0, "^i440BX-W977 (BM6)$", NULL, NULL, P3, "abit", "BM6", 0, OK, intel_piix4_gpo26_lower},
2352 {0x8086, 0x24d3, 0x147b, 0x1014, 0x8086, 0x2578, 0x147b, 0x1014, NULL, NULL, NULL, P3, "abit", "IC7", 0, NT, intel_ich_gpio23_raise},
2353 {0x8086, 0x2930, 0x147b, 0x1084, 0x11ab, 0x4364, 0x147b, 0x1084, NULL, NULL, NULL, P3, "abit", "IP35", 0, OK, intel_ich_gpio16_raise},
2354 {0x8086, 0x2930, 0x147b, 0x1083, 0x10ec, 0x8167, 0x147b, 0x1083, NULL, NULL, NULL, P3, "abit", "IP35 Pro", 0, OK, intel_ich_gpio16_raise},
2355 {0x10de, 0x0050, 0x147b, 0x1c1a, 0x10de, 0x0052, 0x147b, 0x1c1a, NULL, NULL, NULL, P3, "abit", "KN8 Ultra", 0, NT, nvidia_mcp_gpio2_lower},
2356 {0x10de, 0x0369, 0x147b, 0x1c20, 0x10de, 0x0360, 0x147b, 0x1c20, "^KN9(NF-MCP55 series)$", NULL, NULL, P3, "abit", "KN9 Ultra", 0, OK, nvidia_mcp_gpio2_lower},
2357 {0x10de, 0x01e0, 0x147b, 0x1c00, 0x10de, 0x0060, 0x147B, 0x1c00, NULL, NULL, NULL, P3, "abit", "NF7-S", 0, OK, nvidia_mcp_gpio8_raise},
2358 {0x10de, 0x02f0, 0x147b, 0x1c26, 0x10de, 0x0260, 0x147b, 0x1c26, NULL, NULL, NULL, P3, "abit", "NF-M2 nView", 0, OK, nvidia_mcp_gpio4_lower},
2359 {0x1106, 0x0691, 0, 0, 0x1106, 0x3057, 0, 0, "(VA6)$", NULL, NULL, P3, "abit", "VA6", 0, OK, via_apollo_gpo4_lower},
2360 {0x1106, 0x0691, 0, 0, 0x1106, 0x3057, 0, 0, NULL, "abit", "vt6x4", P3, "abit", "VT6X4", 0, OK, via_apollo_gpo4_lower},
2361 {0x105a, 0x0d30, 0x105a, 0x4d33, 0x8086, 0x1130, 0x8086, 0, NULL, NULL, NULL, P3, "Acorp", "6A815EPD", 0, OK, board_acorp_6a815epd},
2362 {0x1022, 0x746B, 0, 0, 0x1022, 0x7460, 0, 0, NULL, "AGAMI", "ARUMA", P3, "agami", "Aruma", 0, OK, w83627hf_gpio24_raise_2e},
2363 {0x1106, 0x3177, 0x17F2, 0x3177, 0x1106, 0x3148, 0x17F2, 0x3148, NULL, NULL, NULL, P3, "Albatron", "PM266A Pro", 0, OK, w836xx_memw_enable_2e},
2364 {0x1022, 0x2090, 0, 0, 0x1022, 0x2080, 0, 0, NULL, "artecgroup", "dbe61", P3, "Artec Group", "DBE61", 0, OK, board_artecgroup_dbe6x},
2365 {0x1022, 0x2090, 0, 0, 0x1022, 0x2080, 0, 0, NULL, "artecgroup", "dbe62", P3, "Artec Group", "DBE62", 0, OK, board_artecgroup_dbe6x},
2366 {0x8086, 0x27b9, 0xa0a0, 0x0632, 0x8086, 0x27da, 0xa0a0, 0x0632, NULL, NULL, NULL, P3, "AOpen", "i945GMx-VFX", 0, OK, intel_ich_gpio38_raise},
2367 {0x8086, 0x2a00, 0xa0a0, 0x063e, 0x8086, 0x2815, 0xa0a0, 0x063e, NULL, NULL, NULL, P3, "AOpen", "i965GMt-LA", 0, OK, intel_ich_gpio20_raise},
2368 {0x8086, 0x277c, 0xa0a0, 0x060b, 0x8086, 0x27da, 0xa0a0, 0x060b, NULL, NULL, NULL, P3, "AOpen", "i975Xa-YDG", 0, OK, board_aopen_i975xa_ydg},
2369 {0x8086, 0x27A0, 0x8086, 0x7270, 0x8086, 0x27B9, 0x8086, 0x7270, "^iMac5,2$", NULL, NULL, P2, "Apple", "iMac5,2", 0, OK, p2_whitelist_laptop},
2370 {0x8086, 0x27A0, 0x8086, 0x7270, 0x8086, 0x27B9, 0x8086, 0x7270, "^MacBook2,1$", NULL, NULL, P2, "Apple", "MacBook2,1", 0, OK, p2_whitelist_laptop},
2371 {0x8086, 0x27b8, 0x1849, 0x27b8, 0x8086, 0x27da, 0x1849, 0x27da, "^ConRoeXFire-eSATA2", NULL, NULL, P3, "ASRock", "ConRoeXFire-eSATA2", 0, OK, intel_ich_gpio16_raise},
2372 {0x1022, 0x1536, 0x1849, 0x1536, 0x1022, 0x780e, 0x1849, 0x780e, "^Kabini CRB$", NULL, NULL, P2, "ASRock", "IMB-A180(-H)", 0, OK, p2_not_a_laptop},
2373 {0x1039, 0x0741, 0x1849, 0x0741, 0x1039, 0x5513, 0x1849, 0x5513, "^K7S41 $", NULL, NULL, P3, "ASRock", "K7S41", 0, OK, w836xx_memw_enable_2e},
2374 {0x1039, 0x0741, 0x1849, 0x0741, 0x1039, 0x5513, 0x1849, 0x5513, "^K7S41GX$", NULL, NULL, P3, "ASRock", "K7S41GX", 0, OK, w836xx_memw_enable_2e},
2375 {0x8086, 0x24D4, 0x1849, 0x24D0, 0x8086, 0x24D5, 0x1849, 0x9739, NULL, NULL, NULL, P3, "ASRock", "P4i65GV", 0, OK, intel_ich_gpio23_raise},
2376 {0x8086, 0x2570, 0x1849, 0x2570, 0x8086, 0x24d3, 0x1849, 0x24d0, NULL, NULL, NULL, P3, "ASRock", "775i65G", 0, OK, intel_ich_gpio23_raise},
2377 {0x10DE, 0x0060, 0x1043, 0x80AD, 0x10DE, 0x01E0, 0x1043, 0x80C0, NULL, NULL, NULL, P3, "ASUS", "A7N8X-VM/400", 0, OK, it8712f_gpio12_raise},
2378 {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3065, 0x1043, 0x80ED, NULL, NULL, NULL, P3, "ASUS", "A7V600-X", 0, OK, it8712f_gpio31_raise},
2379 {0x1106, 0x3177, 0x1043, 0x80F9, 0x1106, 0x3205, 0x1043, 0x80F9, NULL, NULL, NULL, P3, "ASUS", "A7V8X-MX", 0, OK, w836xx_memw_enable_2e},
2380 {0x1106, 0x3177, 0x1043, 0x80A1, 0x1106, 0x3205, 0x1043, 0x8118, NULL, NULL, NULL, P3, "ASUS", "A7V8X-MX SE", 0, OK, w836xx_memw_enable_2e},
2381 {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3177, 0x1043, 0x808C, NULL, NULL, NULL, P3, "ASUS", "A7V8X", 0, OK, it8703f_gpio51_raise},
2382 {0x1106, 0x3099, 0x1043, 0x807F, 0x1106, 0x3147, 0x1043, 0x808C, NULL, NULL, NULL, P3, "ASUS", "A7V333", 0, OK, it8703f_gpio51_raise},
2383 {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3177, 0x1043, 0x80A1, NULL, NULL, NULL, P3, "ASUS", "A7V8X-X", 0, OK, it8712f_gpio31_raise},
2384 {0x1002, 0x4372, 0x103c, 0x2a26, 0x1002, 0x4377, 0x103c, 0x2a26, NULL, NULL, NULL, P3, "ASUS", "A8AE-LE", 0, OK, amd_sbxxx_gpio9_raise},
2385 {0x8086, 0x27A0, 0x1043, 0x1287, 0x8086, 0x27DF, 0x1043, 0x1287, "^A8J", NULL, NULL, P3, "ASUS", "A8Jm", 0, NT, intel_ich_gpio34_raise},
2386 {0x10DE, 0x0260, 0x103C, 0x2A34, 0x10DE, 0x0264, 0x103C, 0x2A34, "NODUSM3", NULL, NULL, P3, "ASUS", "A8M2N-LA (NodusM3-GL8E)", 0, OK, nvidia_mcp_gpio0_raise},
2387 {0x10DE, 0x0260, 0x103c, 0x2a3e, 0x10DE, 0x0264, 0x103c, 0x2a3e, "NAGAMI2L", NULL, NULL, P3, "ASUS", "A8N-LA (Nagami-GL8E)", 0, OK, nvidia_mcp_gpio0_raise},
2388 {0x10de, 0x0264, 0x1043, 0x81bc, 0x10de, 0x02f0, 0x1043, 0x81cd, NULL, NULL, NULL, P3, "ASUS", "A8N-VM CSM", 0, OK, w83627ehf_gpio22_raise_2e},
2389 {0x8086, 0x65c0, 0x1043, 0x8301, 0x8086, 0x2916, 0x1043, 0x82a6, "^DSAN-DX$", NULL, NULL, P3, "ASUS", "DSAN-DX", 0, NT, intel_ich_gpio32_raise},
2390 {0x10DE, 0x0264, 0x1043, 0x81C0, 0x10DE, 0x0260, 0x1043, 0x81C0, NULL, NULL, NULL, P3, "ASUS", "M2NBP-VM CSM", 0, OK, nvidia_mcp_gpio0_raise},
2391 {0x1106, 0x1336, 0x1043, 0x80ed, 0x1106, 0x3288, 0x1043, 0x8249, NULL, NULL, NULL, P3, "ASUS", "M2V-MX", 0, OK, via_vt823x_gpio5_raise},
2392 {0x8086, 0x24cc, 0, 0, 0x8086, 0x24c3, 0x1043, 0x1869, "^M6Ne$", NULL, NULL, P3, "ASUS", "M6Ne", 0, NT, intel_ich_gpio43_raise},
2393 {0x8086, 0x7180, 0, 0, 0x8086, 0x7110, 0, 0, "^OPLX-M$", NULL, NULL, P3, "ASUS", "OPLX-M", 0, NT, intel_piix4_gpo18_lower},
2394 {0x8086, 0x7190, 0, 0, 0x8086, 0x7110, 0, 0, "^P2B-N$", NULL, NULL, P3, "ASUS", "P2B-N", 0, OK, intel_piix4_gpo18_lower},
2395 {0x8086, 0x7190, 0x1043, 0x8024, 0x8086, 0x7110, 0, 0, "P3B-F", "asus", "p3b-f", P3, "ASUS", "P3B-F", 0, OK, board_asus_p3b_f},
2396 {0x8086, 0x1A30, 0x1043, 0x8025, 0x8086, 0x244B, 0x104D, 0x80F0, NULL, NULL, NULL, P3, "ASUS", "P4B266-LM", 0, OK, intel_ich_gpio21_raise},
2397 {0x8086, 0x1a30, 0x1043, 0x8070, 0x8086, 0x244b, 0x1043, 0x8028, NULL, NULL, NULL, P3, "ASUS", "P4B266", 0, OK, intel_ich_gpio22_raise},
2398 {0x8086, 0x1A30, 0x1043, 0x8088, 0x8086, 0x24C3, 0x1043, 0x8089, NULL, NULL, NULL, P3, "ASUS", "P4B533-E", 0, NT, intel_ich_gpio22_raise},
2399 {0x8086, 0x2560, 0x103C, 0x2A00, 0x8086, 0x24C3, 0x103C, 0x2A01, "^Guppy", NULL, NULL, P3, "ASUS", "P4GV-LA (Guppy)", 0, OK, intel_ich_gpio21_raise},
2400 {0x8086, 0x24D3, 0x1043, 0x80A6, 0x8086, 0x2578, 0x1043, 0x80F6, NULL, NULL, NULL, P3, "ASUS", "P4C800-E Deluxe", 0, OK, intel_ich_gpio21_raise},
2401 {0x8086, 0x2570, 0x1043, 0x80F2, 0x8086, 0x24D5, 0x1043, 0x80F3, NULL, NULL, NULL, P3, "ASUS", "P4P800", 0, NT, intel_ich_gpio21_raise},
2402 {0x8086, 0x2570, 0x1043, 0x80f2, 0x8086, 0x24d3, 0x1043, 0x80a6, "^P4P800-E$", NULL, NULL, P3, "ASUS", "P4P800-E Deluxe", 0, OK, intel_ich_gpio21_raise},
2403 {0x8086, 0x2570, 0x1043, 0x80a5, 0x8086, 0x24d3, 0x1043, 0x80a6, "^P4P800-VM$", NULL, NULL, P3, "ASUS", "P4P800-VM", 0, OK, intel_ich_gpio21_raise},
2404 {0x8086, 0x2570, 0x1043, 0x80f2, 0x8086, 0x24d3, 0x1043, 0x80a6, "^P4P800-X$", NULL, NULL, P3, "ASUS", "P4P800-X", 0, OK, intel_ich_gpio21_raise},
2405 {0x8086, 0x2570, 0x1043, 0x80f2, 0x8086, 0x24d3, 0, 0, "^P4P800SE$", NULL, NULL, P3, "ASUS", "P4P800SE", 0, OK, intel_ich_gpio21_raise},
2406 {0x8086, 0x2570, 0x1043, 0x80b2, 0x8086, 0x24c3, 0x1043, 0x8089, "^P4PE-X/TE$",NULL, NULL, P3, "ASUS", "P4PE-X/TE", 0, NT, intel_ich_gpio21_raise},
2407 {0x1039, 0x0651, 0x1043, 0x8081, 0x1039, 0x0962, 0, 0, NULL, NULL, NULL, P3, "ASUS", "P4SC-E", 0, OK, it8707f_write_enable_2e},
2408 {0x8086, 0x2570, 0x1043, 0x80A5, 0x105A, 0x24D3, 0x1043, 0x80A6, NULL, NULL, NULL, P3, "ASUS", "P4SD-LA", 0, NT, intel_ich_gpio32_raise},
2409 {0x1039, 0x0661, 0x1043, 0x8113, 0x1039, 0x5513, 0x1043, 0x8087, NULL, NULL, NULL, P3, "ASUS", "P4S800-MX", 512, OK, w836xx_memw_enable_2e},
2410 {0x10B9, 0x1541, 0, 0, 0x10B9, 0x1533, 0, 0, "^P5A$", "asus", "p5a", P3, "ASUS", "P5A", 0, OK, board_asus_p5a},
2411 {0x8086, 0x27b8, 0x1043, 0x819e, 0x8086, 0x29f0, 0x1043, 0x82a5, "^P5BV-R$", NULL, NULL, P3, "ASUS", "P5BV-R", 0, OK, intel_ich_gpio20_raise},
2412 {0x8086, 0x266a, 0x1043, 0x80a6, 0x8086, 0x2668, 0x1043, 0x814e, "^P5GD1 PRO$", NULL, NULL, P3, "ASUS", "P5GD1 Pro", 0, OK, intel_ich_gpio21_raise},
2413 {0x8086, 0x266a, 0x1043, 0x80a6, 0x8086, 0x2668, 0x1043, 0x814e, "^P5GD1-VM$", NULL, NULL, P3, "ASUS", "P5GD1-VM/S", 0, OK, intel_ich_gpio21_raise},
2414 {0x8086, 0x266a, 0x1043, 0x80a6, 0x8086, 0x2668, 0x1043, 0x814e, NULL, NULL, NULL, P3, "ASUS", "P5GD1(-VM)", 0, NT, intel_ich_gpio21_raise},
2415 {0x8086, 0x266a, 0x1043, 0x80a6, 0x8086, 0x2668, 0x1043, 0x813d, "^P5GD2-Premium$", NULL, NULL, P3, "ASUS", "P5GD2 Premium", 0, OK, intel_ich_gpio21_raise},
2416 {0x8086, 0x266a, 0x1043, 0x80a6, 0x8086, 0x2668, 0x1043, 0x81a6, "^P5GD2-X$", NULL, NULL, P3, "ASUS", "P5GD2-X", 0, OK, intel_ich_gpio21_raise},
2417 {0x8086, 0x266a, 0x1043, 0x80a6, 0x8086, 0x2668, 0x1043, 0x813d, "^P5GDC-V$", NULL, NULL, P3, "ASUS", "P5GDC-V Deluxe", 0, OK, intel_ich_gpio21_raise},
2418 {0x8086, 0x266a, 0x1043, 0x80a6, 0x8086, 0x2668, 0x1043, 0x813d, "^P5GDC$", NULL, NULL, P3, "ASUS", "P5GDC Deluxe", 0, OK, intel_ich_gpio21_raise},
2419 {0x8086, 0x266a, 0x1043, 0x80a6, 0x8086, 0x2668, 0x1043, 0x813d, NULL, NULL, NULL, P3, "ASUS", "P5GD2/C variants", 0, NT, intel_ich_gpio21_raise},
2420 {0x8086, 0x27b8, 0x103c, 0x2a22, 0x8086, 0x2770, 0x103c, 0x2a22, "^LITHIUM$", NULL, NULL, P3, "ASUS", "P5LP-LE (Lithium-UL8E)",0, OK, intel_ich_gpio34_raise},
2421 {0x8086, 0x27b8, 0x1043, 0x2a22, 0x8086, 0x2770, 0x1043, 0x2a22, "^P5LP-LE$", NULL, NULL, P3, "ASUS", "P5LP-LE (Epson OEM)", 0, OK, intel_ich_gpio34_raise},
2422 {0x8086, 0x27da, 0x1043, 0x8179, 0x8086, 0x27b8, 0x1043, 0x8179, "^P5LD2$", NULL, NULL, P3, "ASUS", "P5LD2", 0, OK, intel_ich_gpio16_raise},
2423 {0x8086, 0x27da, 0x1043, 0x8179, 0x8086, 0x27b0, 0x1043, 0x8179, "^P5LD2-MQ$", NULL, NULL, P3, "ASUS", "P5LD2-MQ", 0, OK, intel_ich_gpio16_raise},
2424 {0x8086, 0x27da, 0x1043, 0x8179, 0x8086, 0x27b8, 0x1043, 0x8179, "^P5LD2-VM$", NULL, NULL, P3, "ASUS", "P5LD2-VM", 0, OK, intel_ich_gpio16_raise},
2425 {0x8086, 0x27b0, 0x1043, 0x8179, 0x8086, 0x2770, 0x1043, 0x817a, "^P5LD2-VM DH$", NULL, NULL, P3, "ASUS", "P5LD2-VM DH", 0, OK, intel_ich_gpio16_raise},
2426 {0x10DE, 0x0030, 0x1043, 0x818a, 0x8086, 0x100E, 0x1043, 0x80EE, NULL, NULL, NULL, P3, "ASUS", "P5ND2-SLI Deluxe", 0, OK, nvidia_mcp_gpio10_raise},
2427 {0x10DE, 0x0260, 0x1043, 0x81BC, 0x10DE, 0x026C, 0x1043, 0x829E, "^P5N-D$", NULL, NULL, P3, "ASUS", "P5N-D", 0, OK, it8718f_gpio63_raise},
2428 {0x10DE, 0x0260, 0x1043, 0x81BC, 0x10DE, 0x026C, 0x1043, 0x8249, "^P5N-E SLI$",NULL, NULL, P3, "ASUS", "P5N-E SLI", 0, NT, it8718f_gpio63_raise},
2429 {0x8086, 0x24dd, 0x1043, 0x80a6, 0x8086, 0x2570, 0x1043, 0x8157, NULL, NULL, NULL, P3, "ASUS", "P5PE-VM", 0, OK, intel_ich_gpio21_raise},
2430 {0x8086, 0x27da, 0x1043, 0x8179, 0x8086, 0x27b8, 0x1043, 0x8179, "^P5W DH Deluxe$", NULL, NULL, P3, "ASUS", "P5W DH Deluxe", 0, OK, intel_ich_gpio16_raise},
2431 {0x8086, 0x2443, 0x1043, 0x8027, 0x8086, 0x1130, 0x1043, 0x8027, "^CUSL2-C", NULL, NULL, P3, "ASUS", "CUSL2-C", 0, OK, intel_ich_gpio21_raise},
2432 {0x8086, 0x2443, 0x1043, 0x8027, 0x8086, 0x1130, 0x1043, 0x8027, "^TUSL2-C", NULL, NULL, P3, "ASUS", "TUSL2-C", 0, NT, intel_ich_gpio21_raise},
2433 {0x1022, 0x780E, 0x1043, 0x1437, 0x1022, 0x780B, 0x1043, 0x1437, "^U38N$", NULL, NULL, P2, "ASUS", "U38N", 0, OK, p2_whitelist_laptop},
2434 {0x1106, 0x3059, 0x1106, 0x4161, 0x1106, 0x3065, 0x1106, 0x0102, NULL, NULL, NULL, P3, "Bcom/Clientron", "WinNET P680", 0, OK, w836xx_memw_enable_2e},
2435 {0x1106, 0x3177, 0x1106, 0x3177, 0x1106, 0x3116, 0x1106, 0x3116, "^KM266-8235$", "biostar", "m7viq", P3, "Biostar", "M7VIQ", 0, NT, w83697xx_memw_enable_2e},
2436 {0x8086, 0x283e, 0x1028, 0x01f9, 0x8086, 0x2a01, 0, 0, "^Latitude D630", NULL, NULL, P2, "Dell", "Latitude D630", 0, OK, p2_whitelist_laptop},
2437 {0x10b7, 0x9055, 0x1028, 0x0082, 0x8086, 0x7190, 0, 0, NULL, NULL, NULL, P3, "Dell", "OptiPlex GX1", 0, OK, intel_piix4_gpo30_lower},
2438 {0x8086, 0x3590, 0x1028, 0x016c, 0x1000, 0x0030, 0x1028, 0x016c, NULL, NULL, NULL, P3, "Dell", "PowerEdge 1850", 0, OK, intel_ich_gpio23_raise},
2439 {0x1106, 0x3189, 0x1106, 0x3189, 0x1106, 0x3177, 0x1106, 0x3177, "^AD77", "dfi", "ad77", P3, "DFI", "AD77", 0, NT, w836xx_memw_enable_2e},
2440 {0x1039, 0x6325, 0x1019, 0x0f05, 0x1039, 0x0016, 0, 0, NULL, NULL, NULL, P2, "Elitegroup", "A928", 0, OK, p2_whitelist_laptop},
2441 {0x10de, 0x03ea, 0x1019, 0x2602, 0x10de, 0x03e0, 0x1019, 0x2602, NULL, NULL, NULL, P3, "Elitegroup", "GeForce6100SM-M", 0, OK, board_ecs_geforce6100sm_m},
2442 {0x1106, 0x3038, 0x1019, 0x0996, 0x1106, 0x3177, 0x1019, 0x0996, NULL, NULL, NULL, P3, "Elitegroup", "K7VTA3", 256, OK, NULL},
2443 {0x1106, 0x3177, 0x1106, 0x3177, 0x1106, 0x3059, 0x1695, 0x3005, NULL, NULL, NULL, P3, "EPoX", "EP-8K5A2", 0, OK, w836xx_memw_enable_2e},
2444 {0x10DE, 0x005E, 0x1695, 0x1010, 0x10DE, 0x0050, 0x1695, 0x1010, "8NPA7I", NULL, NULL, P3, "EPoX", "EP-8NPA7I", 0, OK, nvidia_mcp_gpio4_raise},
2445 {0x10DE, 0x005E, 0x1695, 0x1010, 0x10DE, 0x0050, 0x1695, 0x1010, "9NPA7I", NULL, NULL, P3, "EPoX", "EP-9NPA7I", 0, OK, nvidia_mcp_gpio4_raise},
2446 {0x10EC, 0x8139, 0x1695, 0x9001, 0x11C1, 0x5811, 0x1695, 0x9015, NULL, NULL, NULL, P3, "EPoX", "EP-8RDA3+", 0, OK, nvidia_mcp_gpio31_raise},
2447 {0x8086, 0x7110, 0, 0, 0x8086, 0x7190, 0, 0, NULL, "epox", "ep-bx3", P3, "EPoX", "EP-BX3", 0, NT, intel_piix4_gpo22_raise},
2448 {0x10de, 0x02f0, 0x105b, 0x0d01, 0x10de, 0x0264, 0x105b, 0x0d01, NULL, NULL, NULL, P3, "Foxconn", "6150K8MD-8EKRSH", 0, NT, nvidia_mcp_gpio2_raise},
2449 {0x8086, 0x2A40, 0x1734, 0x1148, 0x8086, 0x2930, 0x1734, 0x1148, "^XY680", NULL, NULL, P2, "Fujitsu", "Amilo Xi 3650", 0, OK, p2_whitelist_laptop},
2450 {0x8086, 0x2443, 0x8086, 0x2442, 0x8086, 0x1130, 0x8086, 0x1130, "^6IEM ", NULL, NULL, P3, "GIGABYTE", "GA-6IEM", 0, NT, intel_ich_gpio25_raise},
2451 {0x1106, 0x0686, 0x1106, 0x0686, 0x1106, 0x3058, 0x1458, 0xa000, NULL, NULL, NULL, P3, "GIGABYTE", "GA-7ZM", 512, OK, NULL},
2452 {0x8086, 0x2570, 0x1458, 0x2570, 0x8086, 0x24d0, 0, 0, "^8IP775/-G$",NULL, NULL, P3, "GIGABYTE", "GA-8IP775", 0, OK, intel_ich_gpio32_raise},
2453 {0x8086, 0x244b, 0x8086, 0x2442, 0x8086, 0x2445, 0x1458, 0xa002, NULL, NULL, NULL, P3, "GIGABYTE", "GA-8IRML", 0, OK, intel_ich_gpio25_raise},
2454 {0x8086, 0x24c3, 0x1458, 0x24c2, 0x8086, 0x24cd, 0x1458, 0x5004, NULL, NULL, NULL, P3, "GIGABYTE", "GA-8PE667 Ultra 2", 0, OK, intel_ich_gpio32_raise},
2455 {0x1039, 0x0650, 0x1039, 0x0650, 0x1039, 0x7012, 0x1458, 0xA002, "^GA-8SIMLFS20$", NULL, NULL, P3, "GIGABYTE", "GA-8SIMLFS 2.0", 0, OK, sis_gpio0_raise_and_w836xx_memw},
2456 {0x1039, 0x0651, 0x1039, 0x0651, 0x1039, 0x7002, 0x1458, 0x5004, "^GA-8SIMLH$",NULL, NULL, P3, "GIGABYTE", "GA-8SIMLH", 0, OK, sis_gpio0_raise_and_w836xx_memw},
2457 {0x10DE, 0x02F1, 0x1458, 0x5000, 0x10DE, 0x0261, 0x1458, 0x5001, NULL, NULL, NULL, P3, "GIGABYTE", "GA-K8N51GMF", 0, OK, nvidia_mcp_gpio3b_raise},
2458 {0x10DE, 0x026C, 0x1458, 0xA102, 0x10DE, 0x0260, 0x1458, 0x5001, NULL, NULL, NULL, P3, "GIGABYTE", "GA-K8N51GMF-9", 0, OK, nvidia_mcp_gpio3b_raise},
2459 {0x10DE, 0x00E4, 0x1458, 0x0C11, 0x10DE, 0x00E0, 0x1458, 0x0C11, NULL, NULL, NULL, P3, "GIGABYTE", "GA-K8NS", 0, OK, nvidia_mcp_gpio0a_raise},
2460 {0x10DE, 0x0050, 0x1458, 0x0C11, 0x10DE, 0x005e, 0x1458, 0x5000, NULL, NULL, NULL, P3, "GIGABYTE", "GA-K8N-SLI", 0, OK, nvidia_mcp_gpio21_raise},
2461 {0x8086, 0x2415, 0x103c, 0x1250, 0x10b7, 0x9200, 0x103c, 0x1247, NULL, NULL, NULL, P3, "HP", "e-Vectra P2706T", 0, OK, board_hp_p2706t},
2462 {0x1166, 0x0223, 0x103c, 0x320d, 0x14e4, 0x1678, 0x103c, 0x703e, NULL, "hp", "dl145_g3", P3, "HP", "ProLiant DL145 G3", 0, OK, board_hp_dl145_g3_enable},
2463 {0x1166, 0x0223, 0x103c, 0x320d, 0x14e4, 0x1648, 0x103c, 0x310f, NULL, "hp", "dl165_g6", P3, "HP", "ProLiant DL165 G6", 0, OK, board_hp_dl165_g6_enable},
2464 {0x8086, 0x2580, 0x103c, 0x2a08, 0x8086, 0x2640, 0x103c, 0x2a0a, NULL, NULL, NULL, P3, "HP", "Puffer2-UL8E", 0, OK, intel_ich_gpio18_raise},
2465 {0x8086, 0x2415, 0x103c, 0x1249, 0x10b7, 0x9200, 0x103c, 0x1246, NULL, NULL, NULL, P3, "HP", "Vectra VL400", 0, OK, board_hp_vl400},
2466 {0x8086, 0x1a30, 0x103c, 0x1a30, 0x8086, 0x2443, 0x103c, 0x2440, "^VL420$", NULL, NULL, P3, "HP", "Vectra VL420 SFF", 0, OK, intel_ich_gpio22_raise},
2467 {0x10de, 0x0369, 0x103c, 0x12fe, 0x10de, 0x0364, 0x103c, 0x12fe, NULL, "hp", "xw9400", P3, "HP", "xw9400", 0, OK, nvidia_mcp_gpio5_raise},
2468 {0x8086, 0x27A0, 0, 0, 0x8086, 0x27B9, 0, 0, NULL, "ibase", "mb899", P3, "IBASE", "MB899", 0, OK, intel_ich_gpio26_raise},
2469 {0x1166, 0x0205, 0x1014, 0x0347, 0x1002, 0x515E, 0x1014, 0x0325, NULL, NULL, NULL, P3, "IBM", "x3455", 0, OK, board_ibm_x3455},
2470 {0x1039, 0x5513, 0x8086, 0xd61f, 0x1039, 0x6330, 0x8086, 0xd61f, NULL, NULL, NULL, P3, "Intel", "D201GLY", 0, OK, wbsio_check_for_spi},
2471 {0x8086, 0x27b8, 0x8086, 0xd606, 0x8086, 0x2770, 0x8086, 0xd606, "^D945GCNL$", NULL, NULL, P2, "Intel", "D945GCNL", 0, OK, p2_not_a_laptop},
2472 {0x8086, 0x7190, 0, 0, 0x8086, 0x7110, 0, 0, "^SE440BX-2$", NULL, NULL, P3, "Intel", "SE440BX-2", 0, NT, intel_piix4_gpo27_lower},
2473 {0x1022, 0x7468, 0, 0, 0x1022, 0x7460, 0, 0, NULL, "iwill", "dk8_htx", P3, "IWILL", "DK8-HTX", 0, OK, w83627hf_gpio24_raise_2e},
2474 {0x5333, 0x8d04, 0x1106, 0x3065, 0x1106, 0x3059, 0x1106, 0x0571, "P4M266-8235", NULL, NULL, P3, "Jetway", "P4MDPT", 0, OK, w836xx_memw_enable_2e},
2475 {0x8086, 0x27A0, 0x8086, 0x27a0, 0x8086, 0x27b8, 0x8086, 0x27b8, NULL, "kontron", "986lcd-m", P3, "Kontron", "986LCD-M", 0, OK, board_kontron_986lcd_m},
2476 {0x8086, 0x2917, 0x17AA, 0x20F5, 0x8086, 0x2930, 0x17AA, 0x20F9, "^ThinkPad R400", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad R400", 0, OK, p2_whitelist_laptop},
2477 {0x8086, 0x2917, 0x17AA, 0x20F5, 0x8086, 0x2930, 0x17AA, 0x20F9, "^ThinkPad T400", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad T400", 0, OK, p2_whitelist_laptop},
2478 {0x8086, 0x2917, 0x17AA, 0x20F5, 0x8086, 0x2930, 0x17AA, 0x20F9, "^ThinkPad T500", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad T500", 0, OK, p2_whitelist_laptop},
2479 {0x8086, 0x1E22, 0x17AA, 0x21F6, 0x8086, 0x1E55, 0x17AA, 0x21F6, "^ThinkPad T530", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad T530", 0, OK, p2_whitelist_laptop},
2480 {0x8086, 0x27a0, 0x17aa, 0x2015, 0x8086, 0x27b9, 0x17aa, 0x2009, "^ThinkPad T60", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad T60", 0, OK, p2_whitelist_laptop},
2481 {0x8086, 0x27a0, 0x17aa, 0x2017, 0x8086, 0x27b9, 0x17aa, 0x2009, "^ThinkPad T60", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad T60(s)", 0, OK, p2_whitelist_laptop},
2482 {0x8086, 0x2917, 0x17AA, 0x20F5, 0x8086, 0x2930, 0x17AA, 0x20F9, "^ThinkPad W500", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad W500", 0, OK, p2_whitelist_laptop},
2483 {0x8086, 0x2917, 0x17AA, 0x20F5, 0x8086, 0x2930, 0x17AA, 0x20F9, "^ThinkPad X200", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad X200", 0, OK, p2_whitelist_laptop},
2484 {0x8086, 0x3B07, 0x17AA, 0x2166, 0x8086, 0x3B30, 0x17AA, 0x2167, "^ThinkPad X201", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad X201", 0, OK, p2_whitelist_laptop},
2485 {0x8086, 0x1C22, 0x17AA, 0x21DB, 0x8086, 0x1C4F, 0x17AA, 0x21DB, NULL, "lenovo", "x220", P2, "IBM/Lenovo", "ThinkPad X220", 0, OK, p2_whitelist_laptop},
2486 {0x8086, 0x1E22, 0x17AA, 0x21FA, 0x8086, 0x1E55, 0x17AA, 0x21FA, "^ThinkPad X230", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad X230", 0, OK, p2_whitelist_laptop},
2487 {0x8086, 0x27A0, 0x17AA, 0x2017, 0x8086, 0x27B9, 0x17AA, 0x2009, "^ThinkPad X60", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad X60(s)", 0, OK, p2_whitelist_laptop},
2488 {0x8086, 0x2917, 0x17AA, 0x20F5, 0x8086, 0x2930, 0x17AA, 0x20F9, "^Taurinus X200", "Libiquity", "Taurinus X200", P2, "Libiquity", "ThinkPad X200", 0, OK, p2_whitelist_laptop},
2489 {0x8086, 0x2411, 0x8086, 0x2411, 0x8086, 0x7125, 0x0e11, 0xb165, NULL, NULL, NULL, P3, "Mitac", "6513WU", 0, OK, board_mitac_6513wu},
2490 {0x8086, 0x8186, 0x8086, 0x8186, 0x8086, 0x8800, 0, 0, "^MSC Vertriebs GmbH$", NULL, NULL, P2, "MSC", "Q7-TCTC", 0, OK, p2_not_a_laptop},
2491 {0x8086, 0x7190, 0, 0, 0x8086, 0x7110, 0, 0, "^MS-6163 (i440BX)$", NULL, NULL, P3, "MSI", "MS-6163 (MS-6163 Pro)", 0, OK, intel_piix4_gpo14_raise},
2492 {0x8086, 0x244b, 0x1462, 0x3910, 0x8086, 0x2442, 0x1462, 0x3910, NULL, NULL, NULL, P3, "MSI", "MS-6391 (845 Pro4)", 0, OK, intel_ich_gpio23_raise},
2493 {0x1039, 0x0745, 0, 0, 0x1039, 0x0018, 0, 0, "^MS-6561", NULL, NULL, P3, "MSI", "MS-6561 (745 Ultra)", 0, OK, w836xx_memw_enable_2e},
2494 {0x8086, 0x2560, 0x1462, 0x5770, 0x8086, 0x24C3, 0x1462, 0x5770, NULL, NULL, NULL, P3, "MSI", "MS-6577 (Xenon)", 0, OK, w83627hf_gpio25_raise_2e},
2495 {0x13f6, 0x0111, 0x1462, 0x5900, 0x1106, 0x3177, 0x1106, 0, NULL, NULL, NULL, P3, "MSI", "MS-6590 (KT4 Ultra)", 0, OK, board_msi_kt4v},
2496 {0x1106, 0x0282, 0x1106, 0x0282, 0x1106, 0x3227, 0x1106, 0x3227, "^MS-7094$", NULL, NULL, P3, "MSI", "MS-7094 (K8T Neo2-F V2.0)", 0, OK, w83627thf_gpio44_raise_2e},
2497 {0x1106, 0x0571, 0x1462, 0x7120, 0x1106, 0x3065, 0x1462, 0x7120, NULL, NULL, NULL, P3, "MSI", "MS-6712 (KT4V)", 0, OK, board_msi_kt4v},
2498 {0x1106, 0x3148, 0 , 0 , 0x1106, 0x3177, 0 , 0 , NULL, "msi", "ms6787", P3, "MSI", "MS-6787 (P4MAM-V/P4MAM-L)", 0, OK, w836xx_memw_enable_2e},
2499 {0x8086, 0x24d3, 0x1462, 0x7880, 0x8086, 0x2570, 0, 0, NULL, NULL, NULL, P3, "MSI", "MS-6788-040 (848P NeoV)", 0, OK, intel_ich_gpio32_raise},
2500 {0x1039, 0x7012, 0x1462, 0x0050, 0x1039, 0x6325, 0x1462, 0x0058, NULL, NULL, NULL, P3, "MSI", "MS-7005 (651M-L)", 0, OK, sis_gpio0_raise_and_w836xx_memw},
2501 {0x10DE, 0x00E0, 0x1462, 0x0250, 0x10DE, 0x00E1, 0x1462, 0x0250, NULL, NULL, NULL, P3, "MSI", "MS-7025 (K8N Neo2 Platinum)", 0, OK, nvidia_mcp_gpio0c_raise},
2502 {0x10DE, 0x00E0, 0x1462, 0x0300, 0x10DE, 0x00E1, 0x1462, 0x0300, NULL, NULL, NULL, P3, "MSI", "MS-7030 (K8N Neo Platinum)", 0, OK, nvidia_mcp_gpio0c_raise},
2503 {0x8086, 0x2658, 0x1462, 0x7046, 0x1106, 0x3044, 0x1462, 0x046d, NULL, NULL, NULL, P3, "MSI", "MS-7046", 0, OK, intel_ich_gpio19_raise},
2504 {0x1106, 0x3149, 0x1462, 0x7061, 0x1106, 0x3227, 0, 0, NULL, NULL, NULL, P3, "MSI", "MS-7061 (KM4M-V/KM4AM-V)", 0, OK, w836xx_memw_enable_2e},
2505 {0x10DE, 0x005E, 0x1462, 0x7125, 0x10DE, 0x0052, 0x1462, 0x7125, NULL, NULL, NULL, P3, "MSI", "MS-7125 (K8N Neo4(-F/-FI/-FX/Platinum))", 0, OK, nvidia_mcp_gpio2_raise},
2506 {0x10DE, 0x005E, 0x1462, 0x7135, 0x10DE, 0x0050, 0x1462, 0x7135, NULL, "msi", "k8n-neo3", P3, "MSI", "MS-7135 (K8N Neo3)", 0, OK, w83627thf_gpio44_raise_4e},
2507 {0x10DE, 0x0270, 0x1462, 0x7207, 0x10DE, 0x0264, 0x1462, 0x7207, NULL, NULL, NULL, P3, "MSI", "MS-7207 (K8NGM2-L)", 0, NT, nvidia_mcp_gpio2_raise},
2508 {0x10DE, 0x0360, 0x1462, 0x7250, 0x10DE, 0x0368, 0x1462, 0x7250, NULL, NULL, NULL, P3, "MSI", "MS-7250 (K9N SLI)", 0, OK, nvidia_mcp_gpio2_raise},
2509 {0x1011, 0x0019, 0xaa55, 0xaa55, 0x8086, 0x7190, 0, 0, NULL, NULL, NULL, P3, "Nokia", "IP530", 0, OK, fdc37b787_gpio50_raise_3f0},
2510 {0x8086, 0x3B30, 0x1025, 0x0379, 0x8086, 0x3B09, 0x1025, 0x0379, "^EasyNote LM85$", NULL, NULL, P2, "Packard Bell","EasyNote LM85", 0, OK, p2_whitelist_laptop},
2511 {0x8086, 0x0154, 0x8086, 0x0154, 0x8086, 0x1e55, 0x8086, 0x1e55, "RV11$", "Roda", "Lizard RV11", P2, "Roda", "RV11", 0, OK, p2_whitelist_laptop},
2512 {0x8086, 0x24d3, 0x144d, 0xb025, 0x8086, 0x1050, 0x144d, 0xb025, NULL, NULL, NULL, P3, "Samsung", "Polaris 32", 0, OK, intel_ich_gpio21_raise},
2513 {0x1106, 0x3099, 0, 0, 0x1106, 0x3074, 0, 0, NULL, "shuttle", "ak31", P3, "Shuttle", "AK31", 0, OK, w836xx_memw_enable_2e},
2514 {0x1106, 0x3104, 0x1297, 0xa238, 0x1106, 0x3059, 0x1297, 0xc063, NULL, NULL, NULL, P3, "Shuttle", "AK38N", 256, OK, NULL},
2515 {0x1106, 0x3038, 0x0925, 0x1234, 0x1106, 0x3058, 0x15DD, 0x7609, NULL, NULL, NULL, P3, "Soyo", "SY-7VCA", 0, OK, via_apollo_gpo0_lower},
2516 {0x10de, 0x0364, 0x108e, 0x6676, 0x10de, 0x0369, 0x108e, 0x6676, "^Sun Ultra 40 M2", NULL, NULL, P3, "Sun", "Ultra 40 M2", 0, OK, board_sun_ultra_40_m2},
2517 {0x1106, 0x3038, 0x0925, 0x1234, 0x1106, 0x0596, 0x1106, 0, NULL, NULL, NULL, P3, "Tekram", "P6Pro-A5", 256, OK, NULL},
2518 {0x1106, 0x3123, 0x1106, 0x3123, 0x1106, 0x3059, 0x1106, 0x4161, NULL, NULL, NULL, P3, "Termtek", "TK-3370 (Rev:2.5B)", 0, OK, w836xx_memw_enable_4e},
2519 {0x8086, 0x7120, 0x109f, 0x3157, 0x8086, 0x2410, 0, 0, NULL, NULL, NULL, P3, "TriGem", "Anaheim-3", 0, OK, intel_ich_gpio22_raise},
2520 {0x8086, 0x1076, 0x8086, 0x1176, 0x1106, 0x3059, 0x10f1, 0x2498, NULL, NULL, NULL, P3, "Tyan", "S2498 (Tomcat K7M)", 0, OK, w836xx_memw_enable_2e},
2521 {0x1106, 0x0259, 0x1106, 0xAA07, 0x1106, 0x3227, 0x1106, 0xAA07, NULL, NULL, NULL, P3, "VIA", "EPIA EK", 0, NT, via_vt823x_gpio9_raise},
2522 {0x1106, 0x3177, 0x1106, 0xAA01, 0x1106, 0x3123, 0x1106, 0xAA01, NULL, NULL, NULL, P3, "VIA", "EPIA M/MII/...", 0, OK, via_vt823x_gpio15_raise},
2523 {0x1106, 0x0259, 0x1106, 0x3227, 0x1106, 0x3065, 0x1106, 0x3149, NULL, NULL, NULL, P3, "VIA", "EPIA-N/NL", 0, OK, via_vt823x_gpio9_raise},
2524 #endif
2525 { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, P3, NULL, NULL, 0, NT, NULL}, /* end marker */
2526 };
2527 const size_t board_matches_size = ARRAY_SIZE(board_matches);
2528
selfcheck_board_enables(void)2529 int selfcheck_board_enables(void)
2530 {
2531 if (board_matches[ARRAY_SIZE(board_matches) - 1].vendor_name != NULL) {
2532 msg_gerr("Board enables table miscompilation!\n");
2533 return 1;
2534 }
2535
2536 int ret = 0;
2537 unsigned int i;
2538 for (i = 0; i + 1 < ARRAY_SIZE(board_matches); i++) {
2539 const struct board_match *b = &board_matches[i];
2540 if (b->vendor_name == NULL || b->board_name == NULL) {
2541 msg_gerr("ERROR: Board enable #%d does not define a vendor and board name.\n"
2542 "Please report a bug at [email protected]\n", i);
2543 ret = 1;
2544 continue;
2545 }
2546 if ((b->first_vendor == 0 || b->first_device == 0 ||
2547 b->second_vendor == 0 || b->second_device == 0) ||
2548 ((b->lb_vendor == NULL) ^ (b->lb_part == NULL)) ||
2549 (b->max_rom_decode_parallel == 0 && b->enable == NULL)) {
2550 msg_gerr("ERROR: Board enable for %s %s is misdefined.\n"
2551 "Please report a bug at [email protected]\n",
2552 b->vendor_name, b->board_name);
2553 ret = 1;
2554 }
2555 }
2556 return ret;
2557 }
2558
2559 /* Parse the <vendor>:<board> string specified by the user as part of -p internal:mainboard=<vendor>:<board>.
2560 * Parameters vendor and model will be overwritten. Returns 0 on success.
2561 * Note: strtok modifies the original string, so we work on a copy and allocate memory for the results.
2562 */
board_parse_parameter(const char * boardstring,char ** vendor,char ** model)2563 int board_parse_parameter(const char *boardstring, char **vendor, char **model)
2564 {
2565 /* strtok may modify the original string. */
2566 char *tempstr = strdup(boardstring);
2567 char *tempstr2 = NULL;
2568 strtok(tempstr, ":");
2569 tempstr2 = strtok(NULL, ":");
2570 if (tempstr == NULL || tempstr2 == NULL) {
2571 free(tempstr);
2572 msg_pinfo("Please supply the board vendor and model name with the "
2573 "-p internal:mainboard=<vendor>:<model> option.\n");
2574 return 1;
2575 }
2576 *vendor = strdup(tempstr);
2577 *model = strdup(tempstr2);
2578 msg_pspew("-p internal:mainboard: vendor=\"%s\", model=\"%s\"\n", tempstr, tempstr2);
2579 free(tempstr);
2580 return 0;
2581 }
2582
2583 /*
2584 * Match boards on vendor and model name.
2585 * The string parameters can come either from the coreboot table or the command line (i.e. the user).
2586 * The boolean needs to be set accordingly to compare them to the right entries of the board enables table.
2587 * Require main PCI IDs to match too as extra safety.
2588 * Parameters vendor and model must be non-NULL!
2589 */
board_match_name(const char * vendor,const char * model,bool cb)2590 static const struct board_match *board_match_name(const char *vendor, const char *model, bool cb)
2591 {
2592 const struct board_match *board = board_matches;
2593 const struct board_match *partmatch = NULL;
2594
2595 for (; board->vendor_name; board++) {
2596 const char *cur_vendor = cb ? board->lb_vendor : board->vendor_name;
2597 const char *cur_model = cb ? board->lb_part : board->board_name;
2598
2599 if (!cur_vendor || strcasecmp(cur_vendor, vendor))
2600 continue;
2601
2602 if (!cur_model || strcasecmp(cur_model, model))
2603 continue;
2604
2605 if (!pcidev_find(board->first_vendor, board->first_device)) {
2606 msg_pdbg("Odd. Board name \"%s\":\"%s\" matches, but first PCI device %04x:%04x "
2607 "doesn't.\n", vendor, model, board->first_vendor, board->first_device);
2608 continue;
2609 }
2610
2611 if (!pcidev_find(board->second_vendor, board->second_device)) {
2612 msg_pdbg("Odd. Board name \"%s\":\"%s\" matches, but second PCI device %04x:%04x "
2613 "doesn't.\n", vendor, model, board->second_vendor, board->second_device);
2614 continue;
2615 }
2616
2617 if (partmatch) {
2618 /* More than one entry has a matching name. */
2619 msg_perr("Board name \"%s\":\"%s\" and PCI IDs matched more than one board enable "
2620 "entry. Please report a bug at [email protected]\n", vendor, model);
2621 return NULL;
2622 }
2623 partmatch = board;
2624 }
2625
2626 if (partmatch)
2627 return partmatch;
2628
2629 return NULL;
2630 }
2631
2632 /*
2633 * Match boards on PCI IDs and subsystem IDs.
2634 * Second set of IDs can be either main+subsystem IDs, main IDs or no IDs.
2635 */
board_match_pci_ids(enum board_match_phase phase)2636 static const struct board_match *board_match_pci_ids(enum board_match_phase phase)
2637 {
2638 const struct board_match *board = board_matches;
2639
2640 for (; board->vendor_name; board++) {
2641 if ((!board->first_card_vendor || !board->first_card_device) &&
2642 !board->dmi_pattern)
2643 continue;
2644 if (board->phase != phase)
2645 continue;
2646
2647 if (!pcidev_card_find(board->first_vendor, board->first_device,
2648 board->first_card_vendor,
2649 board->first_card_device))
2650 continue;
2651
2652 if (board->second_vendor) {
2653 if (board->second_card_vendor) {
2654 if (!pcidev_card_find(board->second_vendor,
2655 board->second_device,
2656 board->second_card_vendor,
2657 board->second_card_device))
2658 continue;
2659 } else {
2660 if (!pcidev_find(board->second_vendor,
2661 board->second_device))
2662 continue;
2663 }
2664 }
2665
2666 #if defined(__i386__) || defined(__x86_64__)
2667 if (board->dmi_pattern) {
2668 if (!dmi_is_supported()) {
2669 msg_pwarn("Warning: Can't autodetect %s %s, DMI info unavailable.\n",
2670 board->vendor_name, board->board_name);
2671 msg_pinfo("Please supply the board vendor and model name with the "
2672 "-p internal:mainboard=<vendor>:<model> option.\n");
2673 continue;
2674 } else {
2675 if (!dmi_match(board->dmi_pattern))
2676 continue;
2677 }
2678 }
2679 #endif // defined(__i386__) || defined(__x86_64__)
2680 return board;
2681 }
2682
2683 return NULL;
2684 }
2685
board_enable_safetycheck(const struct board_match * board,bool force_boardenable)2686 static int board_enable_safetycheck(const struct board_match *board, bool force_boardenable)
2687 {
2688 if (!board)
2689 return 1;
2690
2691 if (board->status == OK)
2692 return 0;
2693
2694 if (!force_boardenable) {
2695 msg_pwarn("Warning: The mainboard-specific code for %s %s has not been tested,\n"
2696 "and thus will not be executed by default. Depending on your hardware,\n"
2697 "erasing, writing or even probing can fail without running this code.\n\n"
2698 "Please see the man page (section PROGRAMMER SPECIFIC INFO, subsection\n"
2699 "\"internal programmer\") for details.\n", board->vendor_name, board->board_name);
2700 return 1;
2701 }
2702 msg_pwarn("NOTE: Running an untested board enable procedure.\n"
2703 "Please report success/failure to [email protected].\n");
2704 return 0;
2705 }
2706
2707 /* FIXME: Should this be identical to board_flash_enable? */
board_handle_phase(struct board_cfg * cfg,enum board_match_phase phase,bool force_boardenable)2708 static int board_handle_phase(struct board_cfg *cfg,
2709 enum board_match_phase phase, bool force_boardenable)
2710 {
2711 const struct board_match *board = board_match_pci_ids(phase);
2712
2713 if (board_enable_safetycheck(board, force_boardenable))
2714 return 0;
2715
2716 if (!board->enable) {
2717 /* Not sure if there is a valid case for this. */
2718 msg_perr("Board match found, but nothing to do?\n");
2719 return 0;
2720 }
2721
2722 return board->enable(cfg);
2723 }
2724
board_handle_before_superio(struct board_cfg * cfg,bool force_boardenable)2725 void board_handle_before_superio(struct board_cfg *cfg, bool force_boardenable)
2726 {
2727 board_handle_phase(cfg, P1, force_boardenable);
2728 }
2729
board_handle_before_laptop(struct board_cfg * cfg,bool force_boardenable)2730 void board_handle_before_laptop(struct board_cfg *cfg, bool force_boardenable)
2731 {
2732 board_handle_phase(cfg, P2, force_boardenable);
2733 }
2734
board_flash_enable(struct board_cfg * cfg,const char * vendor,const char * model,const char * cb_vendor,const char * cb_model,bool force_boardenable)2735 int board_flash_enable(struct board_cfg *cfg,
2736 const char *vendor, const char *model, const char *cb_vendor, const char *cb_model,
2737 bool force_boardenable)
2738 {
2739 const struct board_match *board = NULL;
2740 int ret = 0;
2741
2742 if (vendor && model) {
2743 board = board_match_name(vendor, model, false);
2744 if (!board) { /* If a board was given by the user it has to match, else we abort here. */
2745 msg_perr("No suitable board enable found for vendor=\"%s\", model=\"%s\".\n",
2746 vendor, model);
2747 return 1;
2748 }
2749 }
2750 if (!board && cb_vendor && cb_model) {
2751 board = board_match_name(cb_vendor, cb_model, true);
2752 if (!board) { /* Failure is an option here, because many cb boards don't require an enable. */
2753 msg_pdbg2("No board enable found matching coreboot IDs vendor=\"%s\", model=\"%s\".\n",
2754 cb_vendor, cb_model);
2755 }
2756 }
2757 if (!board) {
2758 board = board_match_pci_ids(P3);
2759 if (!board) /* i.e. there is just no board enable available for this board */
2760 return 0;
2761 }
2762
2763 if (board_enable_safetycheck(board, force_boardenable))
2764 return 1;
2765
2766 /* limit the maximum size of the parallel bus */
2767 if (board->max_rom_decode_parallel)
2768 max_rom_decode.parallel = board->max_rom_decode_parallel * 1024;
2769
2770 if (board->enable) {
2771 msg_pinfo("Enabling full flash access for board \"%s %s\"... ",
2772 board->vendor_name, board->board_name);
2773
2774 ret = board->enable(cfg);
2775 if (ret)
2776 msg_pinfo("FAILED!\n");
2777 else
2778 msg_pinfo("OK.\n");
2779 }
2780
2781 return ret;
2782 }
2783