xref: /aosp_15_r20/external/flashrom/board_enable.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
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