source: trunk/board_enable.c

Last change on this file was 1653, checked in by stefanct, 3 months ago

Add (untested) board enable for ASUS P4PE-X/TE.

REed by roxfan and Michael Karcher, patch by Stefan Tauner.

Signed-off-by: Stefan Tauner <stefan.tauner@…>
Acked-by: Stefan Tauner <stefan.tauner@…>

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