flashrom: Export Winbond SuperIO register access functions in board_enable.c.
[coreboot.git] / util / flashrom / board_enable.c
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-2008 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 <stdio.h>
28 #include <pci/pci.h>
29 #include <stdint.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include "flash.h"
33
34 /*
35  * Helper functions for many Winbond Super I/Os of the W836xx range.
36  */
37 /* Enter extended functions */
38 void w836xx_ext_enter(uint16_t port)
39 {
40         OUTB(0x87, port);
41         OUTB(0x87, port);
42 }
43
44 /* Leave extended functions */
45 void w836xx_ext_leave(uint16_t port)
46 {
47         OUTB(0xAA, port);
48 }
49
50 /* General functions for reading/writing Winbond Super I/Os. */
51 unsigned char wbsio_read(uint16_t index, uint8_t reg)
52 {
53         OUTB(reg, index);
54         return INB(index + 1);
55 }
56
57 void wbsio_write(uint16_t index, uint8_t reg, uint8_t data)
58 {
59         OUTB(reg, index);
60         OUTB(data, index + 1);
61 }
62
63 void wbsio_mask(uint16_t index, uint8_t reg, uint8_t data, uint8_t mask)
64 {
65         uint8_t tmp;
66
67         OUTB(reg, index);
68         tmp = INB(index + 1) & ~mask;
69         OUTB(tmp | (data & mask), index + 1);
70 }
71
72 /**
73  * Winbond W83627HF: Raise GPIO24.
74  *
75  * Suited for:
76  *  - Agami Aruma
77  *  - IWILL DK8-HTX
78  */
79 static int w83627hf_gpio24_raise(uint16_t index, const char *name)
80 {
81         w836xx_ext_enter(index);
82
83         /* Is this the W83627HF? */
84         if (wbsio_read(index, 0x20) != 0x52) {  /* Super I/O device ID reg. */
85                 fprintf(stderr, "\nERROR: %s: W83627HF: Wrong ID: 0x%02X.\n",
86                         name, wbsio_read(index, 0x20));
87                 w836xx_ext_leave(index);
88                 return -1;
89         }
90
91         /* PIN89S: WDTO/GP24 multiplex -> GPIO24 */
92         wbsio_mask(index, 0x2B, 0x10, 0x10);
93
94         /* Select logical device 8: GPIO port 2 */
95         wbsio_write(index, 0x07, 0x08);
96
97         wbsio_mask(index, 0x30, 0x01, 0x01);    /* Activate logical device. */
98         wbsio_mask(index, 0xF0, 0x00, 0x10);    /* GPIO24 -> output */
99         wbsio_mask(index, 0xF2, 0x00, 0x10);    /* Clear GPIO24 inversion */
100         wbsio_mask(index, 0xF1, 0x10, 0x10);    /* Raise GPIO24 */
101
102         w836xx_ext_leave(index);
103
104         return 0;
105 }
106
107 static int w83627hf_gpio24_raise_2e(const char *name)
108 {
109         /* TODO: Typo? Shouldn't this be 0x2e? */
110         return w83627hf_gpio24_raise(0x2d, name);
111 }
112
113 /**
114  * Winbond W83627THF: GPIO 4, bit 4
115  *
116  * Suited for:
117  *  - MSI K8T Neo2-F
118  *  - MSI K8N-NEO3
119  */
120 static int w83627thf_gpio4_4_raise(uint16_t index, const char *name)
121 {
122         w836xx_ext_enter(index);
123
124         /* Is this the W83627THF? */
125         if (wbsio_read(index, 0x20) != 0x82) {  /* Super I/O device ID reg. */
126                 fprintf(stderr, "\nERROR: %s: W83627THF: Wrong ID: 0x%02X.\n",
127                         name, wbsio_read(index, 0x20));
128                 w836xx_ext_leave(index);
129                 return -1;
130         }
131
132         /* PINxxxxS: GPIO4/bit 4 multiplex -> GPIOXXX */
133
134         wbsio_write(index, 0x07, 0x09);      /* Select LDN 9: GPIO port 4 */
135         wbsio_mask(index, 0x30, 0x02, 0x02); /* Activate logical device. */
136         wbsio_mask(index, 0xF4, 0x00, 0x10); /* GPIO4 bit 4 -> output */
137         wbsio_mask(index, 0xF6, 0x00, 0x10); /* Clear GPIO4 bit 4 inversion */
138         wbsio_mask(index, 0xF5, 0x10, 0x10); /* Raise GPIO4 bit 4 */
139
140         w836xx_ext_leave(index);
141
142         return 0;
143 }
144
145 static int w83627thf_gpio4_4_raise_2e(const char *name)
146 {
147         return w83627thf_gpio4_4_raise(0x2e, name);
148 }
149
150 static int w83627thf_gpio4_4_raise_4e(const char *name)
151 {
152         return w83627thf_gpio4_4_raise(0x4e, name);
153 }
154
155 /**
156  * Suited for VIAs EPIA M and MII, and maybe other CLE266 based EPIAs.
157  *
158  * We don't need to do this when using coreboot, GPIO15 is never lowered there.
159  */
160 static int board_via_epia_m(const char *name)
161 {
162         struct pci_dev *dev;
163         uint16_t base;
164         uint8_t val;
165
166         dev = pci_dev_find(0x1106, 0x3177);     /* VT8235 ISA bridge */
167         if (!dev) {
168                 fprintf(stderr, "\nERROR: VT8235 ISA bridge not found.\n");
169                 return -1;
170         }
171
172         /* GPIO12-15 -> output */
173         val = pci_read_byte(dev, 0xE4);
174         val |= 0x10;
175         pci_write_byte(dev, 0xE4, val);
176
177         /* Get Power Management IO address. */
178         base = pci_read_word(dev, 0x88) & 0xFF80;
179
180         /* Enable GPIO15 which is connected to write protect. */
181         val = INB(base + 0x4D);
182         val |= 0x80;
183         OUTB(val, base + 0x4D);
184
185         return 0;
186 }
187
188 /**
189  * Suited for:
190  *   - ASUS A7V8X-MX SE and A7V400-MX: AMD K7 + VIA KM400A + VT8235
191  *   - Tyan Tomcat K7M: AMD Geode NX + VIA KM400 + VT8237.
192  */
193 static int board_asus_a7v8x_mx(const char *name)
194 {
195         struct pci_dev *dev;
196         uint8_t val;
197
198         dev = pci_dev_find(0x1106, 0x3177);     /* VT8235 ISA bridge */
199         if (!dev)
200                 dev = pci_dev_find(0x1106, 0x3227);     /* VT8237 ISA bridge */
201         if (!dev) {
202                 fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n");
203                 return -1;
204         }
205
206         /* This bit is marked reserved actually. */
207         val = pci_read_byte(dev, 0x59);
208         val &= 0x7F;
209         pci_write_byte(dev, 0x59, val);
210
211         /* Raise ROM MEMW# line on Winbond W83697 Super I/O. */
212         w836xx_ext_enter(0x2E);
213
214         if (!(wbsio_read(0x2E, 0x24) & 0x02))   /* Flash ROM enabled? */
215                 wbsio_mask(0x2E, 0x24, 0x08, 0x08);     /* Enable MEMW#. */
216
217         w836xx_ext_leave(0x2E);
218
219         return 0;
220 }
221
222 /**
223  * Suited for VIAs EPIA SP.
224  */
225 static int board_via_epia_sp(const char *name)
226 {
227         struct pci_dev *dev;
228         uint8_t val;
229
230         dev = pci_dev_find(0x1106, 0x3227);     /* VT8237R ISA bridge */
231         if (!dev) {
232                 fprintf(stderr, "\nERROR: VT8237R ISA bridge not found.\n");
233                 return -1;
234         }
235
236         /* All memory cycles, not just ROM ones, go to LPC */
237         val = pci_read_byte(dev, 0x59);
238         val &= ~0x80;
239         pci_write_byte(dev, 0x59, val);
240
241         return 0;
242 }
243
244 /**
245  * Suited for ASUS P5A.
246  *
247  * This is rather nasty code, but there's no way to do this cleanly.
248  * We're basically talking to some unknown device on SMBus, my guess
249  * is that it is the Winbond W83781D that lives near the DIP BIOS.
250  */
251 static int board_asus_p5a(const char *name)
252 {
253         uint8_t tmp;
254         int i;
255
256 #define ASUSP5A_LOOP 5000
257
258         OUTB(0x00, 0xE807);
259         OUTB(0xEF, 0xE803);
260
261         OUTB(0xFF, 0xE800);
262
263         for (i = 0; i < ASUSP5A_LOOP; i++) {
264                 OUTB(0xE1, 0xFF);
265                 if (INB(0xE800) & 0x04)
266                         break;
267         }
268
269         if (i == ASUSP5A_LOOP) {
270                 printf("%s: Unable to contact device.\n", name);
271                 return -1;
272         }
273
274         OUTB(0x20, 0xE801);
275         OUTB(0x20, 0xE1);
276
277         OUTB(0xFF, 0xE802);
278
279         for (i = 0; i < ASUSP5A_LOOP; i++) {
280                 tmp = INB(0xE800);
281                 if (tmp & 0x70)
282                         break;
283         }
284
285         if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) {
286                 printf("%s: failed to read device.\n", name);
287                 return -1;
288         }
289
290         tmp = INB(0xE804);
291         tmp &= ~0x02;
292
293         OUTB(0x00, 0xE807);
294         OUTB(0xEE, 0xE803);
295
296         OUTB(tmp, 0xE804);
297
298         OUTB(0xFF, 0xE800);
299         OUTB(0xE1, 0xFF);
300
301         OUTB(0x20, 0xE801);
302         OUTB(0x20, 0xE1);
303
304         OUTB(0xFF, 0xE802);
305
306         for (i = 0; i < ASUSP5A_LOOP; i++) {
307                 tmp = INB(0xE800);
308                 if (tmp & 0x70)
309                         break;
310         }
311
312         if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) {
313                 printf("%s: failed to write to device.\n", name);
314                 return -1;
315         }
316
317         return 0;
318 }
319
320 static int board_ibm_x3455(const char *name)
321 {
322         uint8_t byte;
323
324         /* Set GPIO lines in the Broadcom HT-1000 southbridge. */
325         OUTB(0x45, 0xcd6);
326         byte = INB(0xcd7);
327         OUTB(byte | 0x20, 0xcd7);
328
329         return 0;
330 }
331
332 /**
333  * Suited for EPoX EP-BX3, and maybe some other Intel 440BX based boards.
334  */
335 static int board_epox_ep_bx3(const char *name)
336 {
337         uint8_t tmp;
338
339         /* Raise GPIO22. */
340         tmp = INB(0x4036);
341         OUTB(tmp, 0xEB);
342
343         tmp |= 0x40;
344
345         OUTB(tmp, 0x4036);
346         OUTB(tmp, 0xEB);
347
348         return 0;
349 }
350
351 /**
352  * Suited for Acorp 6A815EPD.
353  */
354 static int board_acorp_6a815epd(const char *name)
355 {
356         struct pci_dev *dev;
357         uint16_t port;
358         uint8_t val;
359
360         dev = pci_dev_find(0x8086, 0x2440);     /* Intel ICH2 LPC */
361         if (!dev) {
362                 fprintf(stderr, "\nERROR: ICH2 LPC bridge not found.\n");
363                 return -1;
364         }
365
366         /* Use GPIOBASE register to find where the GPIO is mapped. */
367         port = (pci_read_word(dev, 0x58) & 0xFFC0) + 0xE;
368
369         val = INB(port);
370         val |= 0x80;            /* Top Block Lock -- pin 8 of PLCC32 */
371         val |= 0x40;            /* Lower Blocks Lock -- pin 7 of PLCC32 */
372         OUTB(val, port);
373
374         return 0;
375 }
376
377 /**
378  * Suited for Artec Group DBE61 and DBE62.
379  */
380 static int board_artecgroup_dbe6x(const char *name)
381 {
382 #define DBE6x_MSR_DIVIL_BALL_OPTS       0x51400015
383 #define DBE6x_PRI_BOOT_LOC_SHIFT        (2)
384 #define DBE6x_BOOT_OP_LATCHED_SHIFT     (8)
385 #define DBE6x_SEC_BOOT_LOC_SHIFT        (10)
386 #define DBE6x_PRI_BOOT_LOC              (3 << DBE6x_PRI_BOOT_LOC_SHIFT)
387 #define DBE6x_BOOT_OP_LATCHED           (3 << DBE6x_BOOT_OP_LATCHED_SHIFT)
388 #define DBE6x_SEC_BOOT_LOC              (3 << DBE6x_SEC_BOOT_LOC_SHIFT)
389 #define DBE6x_BOOT_LOC_FLASH            (2)
390 #define DBE6x_BOOT_LOC_FWHUB            (3)
391
392         unsigned long msr[2];
393         int msr_fd;
394         unsigned long boot_loc;
395
396         msr_fd = open("/dev/cpu/0/msr", O_RDWR);
397         if (msr_fd == -1) {
398                 perror("open /dev/cpu/0/msr");
399                 return -1;
400         }
401
402         if (lseek(msr_fd, DBE6x_MSR_DIVIL_BALL_OPTS, SEEK_SET) == -1) {
403                 perror("lseek");
404                 close(msr_fd);
405                 return -1;
406         }
407
408         if (read(msr_fd, (void *)msr, 8) != 8) {
409                 perror("read");
410                 close(msr_fd);
411                 return -1;
412         }
413
414         if ((msr[0] & (DBE6x_BOOT_OP_LATCHED)) ==
415             (DBE6x_BOOT_LOC_FWHUB << DBE6x_BOOT_OP_LATCHED_SHIFT))
416                 boot_loc = DBE6x_BOOT_LOC_FWHUB;
417         else
418                 boot_loc = DBE6x_BOOT_LOC_FLASH;
419
420         msr[0] &= ~(DBE6x_PRI_BOOT_LOC | DBE6x_SEC_BOOT_LOC);
421         msr[0] |= ((boot_loc << DBE6x_PRI_BOOT_LOC_SHIFT) |
422                    (boot_loc << DBE6x_SEC_BOOT_LOC_SHIFT));
423
424         if (lseek(msr_fd, DBE6x_MSR_DIVIL_BALL_OPTS, SEEK_SET) == -1) {
425                 perror("lseek");
426                 close(msr_fd);
427                 return -1;
428         }
429
430         if (write(msr_fd, (void *)msr, 8) != 8) {
431                 perror("write");
432                 close(msr_fd);
433                 return -1;
434         }
435
436         close(msr_fd);
437         return 0;
438 }
439
440 /**
441  * Set the specified GPIO on the specified ICHx southbridge to high.
442  *
443  * @param name The name of this board.
444  * @param ich_vendor PCI vendor ID of the specified ICHx southbridge.
445  * @param ich_device PCI device ID of the specified ICHx southbridge.
446  * @param gpiobase_reg GPIOBASE register offset in the LPC bridge.
447  * @param gp_lvl Offset of GP_LVL register in I/O space, relative to GPIOBASE.
448  * @param gp_lvl_bitmask GP_LVL bitmask (set GPIO bits to 1, all others to 0).
449  * @param gpio_bit The bit (GPIO) which shall be set to high.
450  * @return If the write-enable was successful return 0, otherwise return -1.
451  */
452 static int ich_gpio_raise(const char *name, uint16_t ich_vendor,
453                           uint16_t ich_device, uint8_t gpiobase_reg,
454                           uint8_t gp_lvl, uint32_t gp_lvl_bitmask,
455                           unsigned int gpio_bit)
456 {
457         struct pci_dev *dev;
458         uint16_t gpiobar;
459         uint32_t reg32;
460
461         dev = pci_dev_find(ich_vendor, ich_device);     /* Intel ICHx LPC */
462         if (!dev) {
463                 fprintf(stderr, "\nERROR: ICHx LPC dev %4x:%4x not found.\n",
464                         ich_vendor, ich_device);
465                 return -1;
466         }
467
468         /* Use GPIOBASE register to find the I/O space for GPIO. */
469         gpiobar = pci_read_word(dev, gpiobase_reg) & gp_lvl_bitmask;
470
471         /* Set specified GPIO to high. */
472         reg32 = INL(gpiobar + gp_lvl);
473         reg32 |= (1 << gpio_bit);
474         OUTL(reg32, gpiobar + gp_lvl);
475
476         return 0;
477 }
478
479 /**
480  * Suited for ASUS P4B266.
481  */
482 static int ich2_gpio22_raise(const char *name)
483 {
484         return ich_gpio_raise(name, 0x8086, 0x2440, 0x58, 0x0c, 0xffc0, 22);
485 }
486
487 static int board_kontron_986lcd_m(const char *name)
488 {
489         struct pci_dev *dev;
490         uint16_t gpiobar;
491         uint32_t val;
492
493 #define ICH7_GPIO_LVL2 0x38
494
495         dev = pci_dev_find(0x8086, 0x27b8);     /* Intel ICH7 LPC */
496         if (!dev) {
497                 // This will never happen on this board
498                 fprintf(stderr, "\nERROR: ICH7 LPC bridge not found.\n");
499                 return -1;
500         }
501
502         /* Use GPIOBASE register to find where the GPIO is mapped. */
503         gpiobar = pci_read_word(dev, 0x48) & 0xfffc;
504
505         val = INL(gpiobar + ICH7_GPIO_LVL2);    /* GP_LVL2 */
506         printf_debug("\nGPIOBAR=0x%04x GP_LVL: 0x%08x\n", gpiobar, val);
507
508         /* bit 2 (0x04) = 0 #TBL --> bootblock locking = 1
509          * bit 2 (0x04) = 1 #TBL --> bootblock locking = 0
510          * bit 3 (0x08) = 0 #WP --> block locking = 1
511          * bit 3 (0x08) = 1 #WP --> block locking = 0
512          *
513          * To enable full block locking, you would do:
514          *     val &= ~ ((1 << 2) | (1 << 3));
515          */
516         val |= (1 << 2) | (1 << 3);
517
518         OUTL(val, gpiobar + ICH7_GPIO_LVL2);
519
520         return 0;
521 }
522
523 /**
524  * Suited for:
525  *   - BioStar P4M80-M4: Intel P4 + VIA P4M800 + VT8237
526  *   - GIGABYTE GA-7VT600: AMD K7 + VIA KT600 + VT8237
527  */
528 static int board_biostar_p4m80_m4(const char *name)
529 {
530         /* enter IT87xx conf mode */
531         OUTB(0x87, 0x2e);
532         OUTB(0x01, 0x2e);
533         OUTB(0x55, 0x2e);
534         OUTB(0x55, 0x2e);
535
536         /* select right flash chip */
537         wbsio_mask(0x2e, 0x22, 0x80, 0x80);
538
539         /* bit 3: flash chip write enable
540          * bit 7: map flash chip at 1MB-128K (why though? ignoring this.)
541          */
542         wbsio_mask(0x2e, 0x24, 0x04, 0x04);
543
544         /* exit IT87xx conf mode */
545         wbsio_write(0x2, 0x2e, 0x2);
546
547         return 0;
548 }
549
550 /**
551  * Winbond W83697HF Super I/O + VIA VT8235 southbridge
552  *
553  * Suited for:
554  *   - MSI KT4V and KT4V-L: AMD K7 + VIA KT400 + VT8235
555  *   - MSI KT3 Ultra2: AMD K7 + VIA KT333 + VT8235
556  */
557 static int board_msi_kt4v(const char *name)
558 {
559         struct pci_dev *dev;
560         uint8_t val;
561         uint32_t val2;
562         uint16_t port;
563
564         dev = pci_dev_find(0x1106, 0x3177);     /* VT8235 ISA bridge */
565         if (!dev) {
566                 fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n");
567                 return -1;
568         }
569
570         val = pci_read_byte(dev, 0x59);
571         val &= 0x0c;
572         pci_write_byte(dev, 0x59, val);
573
574         /* We need the I/O Base Address for this board's flash enable. */
575         port = pci_read_word(dev, 0x88) & 0xff80;
576
577         /* Starting at 'I/O Base + 0x4c' is the GPO Port Output Value.
578          * We must assert GPO12 for our enable, which is in 0x4d.
579          */
580         val2 = INB(port + 0x4d);
581         val2 |= 0x10;
582         OUTB(val2, port + 0x4d);
583
584         /* Raise ROM MEMW# line on Winbond W83697 Super I/O. */
585         w836xx_ext_enter(0x2e);
586         if (!(wbsio_read(0x2e, 0x24) & 0x02)) { /* Flash ROM enabled? */
587                 /* Enable MEMW# and set ROM size select to max. (4M). */
588                 wbsio_mask(0x2e, 0x24, 0x28, 0x28);
589         }
590         w836xx_ext_leave(0x2e);
591
592         return 0;
593 }
594
595 /**
596  * We use 2 sets of IDs here, you're free to choose which is which. This
597  * is to provide a very high degree of certainty when matching a board on
598  * the basis of subsystem/card IDs. As not every vendor handles
599  * subsystem/card IDs in a sane manner.
600  *
601  * Keep the second set NULLed if it should be ignored.
602  *
603  * Keep the subsystem IDs NULLed if they don't identify the board fully.
604  */
605 struct board_pciid_enable {
606         /* Any device, but make it sensible, like the ISA bridge. */
607         uint16_t first_vendor;
608         uint16_t first_device;
609         uint16_t first_card_vendor;
610         uint16_t first_card_device;
611
612         /* Any device, but make it sensible, like 
613          * the host bridge. May be NULL.
614          */
615         uint16_t second_vendor;
616         uint16_t second_device;
617         uint16_t second_card_vendor;
618         uint16_t second_card_device;
619
620         /* The vendor / part name from the coreboot table. */
621         const char *lb_vendor;
622         const char *lb_part;
623
624         const char *name;
625         int (*enable) (const char *name);
626 };
627
628 struct board_pciid_enable board_pciid_enables[] = {
629         {
630                 .first_vendor           = 0x1106,
631                 .first_device           = 0x0571,
632                 .first_card_vendor      = 0x1462,
633                 .first_card_device      = 0x7120,
634                 .second_vendor          = 0x0000,
635                 .second_device          = 0x0000,
636                 .second_card_vendor     = 0x0000,
637                 .second_card_device     = 0x0000,
638                 .lb_vendor              = "msi",
639                 .lb_part                = "kt4v",
640                 .name                   = "MSI KT4V",
641                 .enable                 = board_msi_kt4v,
642         },
643         {
644                 .first_vendor           = 0x8086,
645                 .first_device           = 0x1a30,
646                 .first_card_vendor      = 0x1043,
647                 .first_card_device      = 0x8070,
648                 .second_vendor          = 0x8086,
649                 .second_device          = 0x244b,
650                 .second_card_vendor     = 0x1043,
651                 .second_card_device     = 0x8028,
652                 .lb_vendor              = NULL,
653                 .lb_part                = NULL,
654                 .name                   = "ASUS P4B266",
655                 .enable                 = ich2_gpio22_raise,
656         },
657         {
658                 .first_vendor           = 0x10de,
659                 .first_device           = 0x0360,
660                 .first_card_vendor      = 0x0000,
661                 .first_card_device      = 0x0000,
662                 .second_vendor          = 0x0000,
663                 .second_device          = 0x0000,
664                 .second_card_vendor     = 0x0000,
665                 .second_card_device     = 0x0000,
666                 .lb_vendor              = "gigabyte",
667                 .lb_part                = "m57sli",
668                 .name                   = "GIGABYTE GA-M57SLI-S4",
669                 .enable                 = it87xx_probe_spi_flash,
670         },
671         {
672                 .first_vendor           = 0x10de,
673                 .first_device           = 0x03e0,
674                 .first_card_vendor      = 0x0000,
675                 .first_card_device      = 0x0000,
676                 .second_vendor          = 0x0000,
677                 .second_device          = 0x0000,
678                 .second_card_vendor     = 0x0000,
679                 .second_card_device     = 0x0000,
680                 .lb_vendor              = "gigabyte",
681                 .lb_part                = "m61p",
682                 .name                   = "GIGABYTE GA-M61P-S3",
683                 .enable                 = it87xx_probe_spi_flash,
684         },
685         {
686                 .first_vendor           = 0x1002,
687                 .first_device           = 0x4398,
688                 .first_card_vendor      = 0x1458,
689                 .first_card_device      = 0x5004,
690                 .second_vendor          = 0x1002,
691                 .second_device          = 0x4385,
692                 .second_card_vendor     = 0x1458,
693                 .second_card_device     = 0x4385,
694                 .lb_vendor              = NULL,
695                 .lb_part                = NULL,
696                 .name                   = "GIGABYTE GA-MA78G-DS3H",
697                 .enable                 = it87xx_probe_spi_flash,
698         },
699         {
700                 .first_vendor           = 0x1039,
701                 .first_device           = 0x0761,
702                 .first_card_vendor      = 0x0000,
703                 .first_card_device      = 0x0000,
704                 .second_vendor          = 0x0000,
705                 .second_device          = 0x0000,
706                 .second_card_vendor     = 0x0000,
707                 .second_card_device     = 0x0000,
708                 .lb_vendor              = "gigabyte",
709                 .lb_part                = "2761gxdk",
710                 .name                   = "GIGABYTE GA-2761GXDK",
711                 .enable                 = it87xx_probe_spi_flash,
712         },
713         {
714                 .first_vendor           = 0x1022,
715                 .first_device           = 0x7468,
716                 .first_card_vendor      = 0x0000,
717                 .first_card_device      = 0x0000,
718                 .second_vendor          = 0x0000,
719                 .second_device          = 0x0000,
720                 .second_card_vendor     = 0x0000,
721                 .second_card_device     = 0x0000,
722                 .lb_vendor              = "iwill",
723                 .lb_part                = "dk8_htx",
724                 .name                   = "IWILL DK8-HTX",
725                 .enable                 = w83627hf_gpio24_raise_2e,
726         },
727         {
728                 .first_vendor           = 0x10de,
729                 .first_device           = 0x005e,
730                 .first_card_vendor      = 0x0000,
731                 .first_card_device      = 0x0000,
732                 .second_vendor          = 0x0000,
733                 .second_device          = 0x0000,
734                 .second_card_vendor     = 0x0000,
735                 .second_card_device     = 0x0000,
736                 .lb_vendor              = "msi",
737                 .lb_part                = "k8n-neo3",
738                 .name                   = "MSI K8N Neo3",
739                 .enable                 = w83627thf_gpio4_4_raise_4e,
740         },
741         {
742                 .first_vendor           = 0x1022,
743                 .first_device           = 0x746B,
744                 .first_card_vendor      = 0x1022,
745                 .first_card_device      = 0x36C0,
746                 .second_vendor          = 0x0000,
747                 .second_device          = 0x0000,
748                 .second_card_vendor     = 0x0000,
749                 .second_card_device     = 0x0000,
750                 .lb_vendor              = "AGAMI",
751                 .lb_part                = "ARUMA",
752                 .name                   = "agami Aruma",
753                 .enable                 = w83627hf_gpio24_raise_2e,
754         },
755         {
756                 .first_vendor           = 0x1106,
757                 .first_device           = 0x3177,
758                 .first_card_vendor      = 0x1106,
759                 .first_card_device      = 0xAA01,
760                 .second_vendor          = 0x1106,
761                 .second_device          = 0x3123,
762                 .second_card_vendor     = 0x1106,
763                 .second_card_device     = 0xAA01,
764                 .lb_vendor              = NULL,
765                 .lb_part                = NULL,
766                 .name                   = "VIA EPIA M/MII/...",
767                 .enable                 = board_via_epia_m,
768         },
769         {
770                 .first_vendor           = 0x1106,
771                 .first_device           = 0x3177,
772                 .first_card_vendor      = 0x1043,
773                 .first_card_device      = 0x80A1,
774                 .second_vendor          = 0x1106,
775                 .second_device          = 0x3205,
776                 .second_card_vendor     = 0x1043,
777                 .second_card_device     = 0x8118,
778                 .lb_vendor              = NULL,
779                 .lb_part                = NULL,
780                 .name                   = "ASUS A7V8-MX SE",
781                 .enable                 = board_asus_a7v8x_mx,
782         },
783         {
784                 .first_vendor           = 0x1106,
785                 .first_device           = 0x3227,
786                 .first_card_vendor      = 0x1106,
787                 .first_card_device      = 0xAA01,
788                 .second_vendor          = 0x1106,
789                 .second_device          = 0x0259,
790                 .second_card_vendor     = 0x1106,
791                 .second_card_device     = 0xAA01,
792                 .lb_vendor              = NULL,
793                 .lb_part                = NULL,
794                 .name                   = "VIA EPIA SP",
795                 .enable                 = board_via_epia_sp,
796         },
797         {
798                 .first_vendor           = 0x1106,
799                 .first_device           = 0x0314,
800                 .first_card_vendor      = 0x1106,
801                 .first_card_device      = 0xaa08,
802                 .second_vendor          = 0x1106,
803                 .second_device          = 0x3227,
804                 .second_card_vendor     = 0x1106,
805                 .second_card_device     = 0xAA08,
806                 .lb_vendor              = NULL,
807                 .lb_part                = NULL,
808                 .name                   = "VIA EPIA-CN",
809                 .enable                 = board_via_epia_sp,
810         },
811         {
812                 .first_vendor           = 0x8086,
813                 .first_device           = 0x1076,
814                 .first_card_vendor      = 0x8086,
815                 .first_card_device      = 0x1176,
816                 .second_vendor          = 0x1106,
817                 .second_device          = 0x3059,
818                 .second_card_vendor     = 0x10f1,
819                 .second_card_device     = 0x2498,
820                 .lb_vendor              = NULL,
821                 .lb_part                = NULL,
822                 .name                   = "Tyan Tomcat K7M",
823                 .enable                 = board_asus_a7v8x_mx,
824         },
825         {
826                 .first_vendor           = 0x10B9,
827                 .first_device           = 0x1541,
828                 .first_card_vendor      = 0x0000,
829                 .first_card_device      = 0x0000,
830                 .second_vendor          = 0x10B9,
831                 .second_device          = 0x1533,
832                 .second_card_vendor     = 0x0000,
833                 .second_card_device     = 0x0000,
834                 .lb_vendor              = "asus",
835                 .lb_part                = "p5a",
836                 .name                   = "ASUS P5A",
837                 .enable                 = board_asus_p5a,
838         },
839         {
840                 .first_vendor           = 0x1166,
841                 .first_device           = 0x0205,
842                 .first_card_vendor      = 0x1014,
843                 .first_card_device      = 0x0347,
844                 .second_vendor          = 0x0000,
845                 .second_device          = 0x0000,
846                 .second_card_vendor     = 0x0000,
847                 .second_card_device     = 0x0000,
848                 .lb_vendor              = "ibm",
849                 .lb_part                = "x3455",
850                 .name                   = "IBM x3455",
851                 .enable                 = board_ibm_x3455,
852         },
853         {
854                 .first_vendor           = 0x8086,
855                 .first_device           = 0x7110,
856                 .first_card_vendor      = 0x0000,
857                 .first_card_device      = 0x0000,
858                 .second_vendor          = 0x8086,
859                 .second_device          = 0x7190,
860                 .second_card_vendor     = 0x0000,
861                 .second_card_device     = 0x0000,
862                 .lb_vendor              = "epox",
863                 .lb_part                = "ep-bx3",
864                 .name                   = "EPoX EP-BX3",
865                 .enable                 = board_epox_ep_bx3,
866         },
867         {
868                 .first_vendor           = 0x8086,
869                 .first_device           = 0x1130,
870                 .first_card_vendor      = 0x0000,
871                 .first_card_device      = 0x0000,
872                 .second_vendor          = 0x105a,
873                 .second_device          = 0x0d30,
874                 .second_card_vendor     = 0x105a,
875                 .second_card_device     = 0x4d33,
876                 .lb_vendor              = "acorp",
877                 .lb_part                = "6a815epd",
878                 .name                   = "Acorp 6A815EPD",
879                 .enable                 = board_acorp_6a815epd,
880         },
881         {
882                 .first_vendor           = 0x1022,
883                 .first_device           = 0x2090,
884                 .first_card_vendor      = 0x0000,
885                 .first_card_device      = 0x0000,
886                 .second_vendor          = 0x1022,
887                 .second_device          = 0x2080,
888                 .second_card_vendor     = 0x0000,
889                 .second_card_device     = 0x0000,
890                 .lb_vendor              = "artecgroup",
891                 .lb_part                = "dbe61",
892                 .name                   = "Artec Group DBE61",
893                 .enable                 = board_artecgroup_dbe6x,
894         },
895         {
896                 .first_vendor           = 0x1022,
897                 .first_device           = 0x2090,
898                 .first_card_vendor      = 0x0000,
899                 .first_card_device      = 0x0000,
900                 .second_vendor          = 0x1022,
901                 .second_device          = 0x2080,
902                 .second_card_vendor     = 0x0000,
903                 .second_card_device     = 0x0000,
904                 .lb_vendor              = "artecgroup",
905                 .lb_part                = "dbe62",
906                 .name                   = "Artec Group DBE62",
907                 .enable                 = board_artecgroup_dbe6x,
908         },
909         /* Note: There are >= 2 version of the Kontron 986LCD-M/mITX! */
910         {
911                 .first_vendor           = 0x8086,
912                 .first_device           = 0x27b8,
913                 .first_card_vendor      = 0x0000,
914                 .first_card_device      = 0x0000,
915                 .second_vendor          = 0x0000,
916                 .second_device          = 0x0000,
917                 .second_card_vendor     = 0x0000,
918                 .second_card_device     = 0x0000,
919                 .lb_vendor              = "kontron",
920                 .lb_part                = "986lcd-m",
921                 .name                   = "Kontron 986LCD-M",
922                 .enable                 = board_kontron_986lcd_m,
923         },
924         {
925                 .first_vendor           = 0x10ec,
926                 .first_device           = 0x8168,
927                 .first_card_vendor      = 0x10ec,
928                 .first_card_device      = 0x8168,
929                 .second_vendor          = 0x104c,
930                 .second_device          = 0x8023,
931                 .second_card_vendor     = 0x104c,
932                 .second_card_device     = 0x8019,
933                 .lb_vendor              = "kontron",
934                 .lb_part                = "986lcd-m",
935                 .name                   = "Kontron 986LCD-M",
936                 .enable                 = board_kontron_986lcd_m,
937         },
938         {
939                 .first_vendor           = 0x1106,
940                 .first_device           = 0x3149,
941                 .first_card_vendor      = 0x1565,
942                 .first_card_device      = 0x3206,
943                 .second_vendor          = 0x1106,
944                 .second_device          = 0x3344,
945                 .second_card_vendor     = 0x1565,
946                 .second_card_device     = 0x1202,
947                 .lb_vendor              = NULL,
948                 .lb_part                = NULL,
949                 .name                   = "BioStar P4M80-M4",
950                 .enable                 = board_biostar_p4m80_m4,
951         },
952         {
953                 .first_vendor           = 0x1106,
954                 .first_device           = 0x3227,
955                 .first_card_vendor      = 0x1458,
956                 .first_card_device      = 0x5001,
957                 .second_vendor          = 0x10ec,
958                 .second_device          = 0x8139,
959                 .second_card_vendor     = 0x1458,
960                 .second_card_device     = 0xe000,
961                 .lb_vendor              = NULL,
962                 .lb_part                = NULL,
963                 .name                   = "GIGABYTE GA-7VT600",
964                 .enable                 = board_biostar_p4m80_m4,
965         },
966         {
967                 .first_vendor           = 0x1106,
968                 .first_device           = 0x3149,
969                 .first_card_vendor      = 0x1462,
970                 .first_card_device      = 0x7094,
971                 .second_vendor          = 0x10ec,
972                 .second_device          = 0x8167,
973                 .second_card_vendor     = 0x1462,
974                 .second_card_device     = 0x094c,
975                 .lb_vendor              = NULL,
976                 .lb_part                = NULL,
977                 .name                   = "MSI K8T Neo2",
978                 .enable                 = w83627thf_gpio4_4_raise_2e,
979         },
980         {
981                 .first_vendor           = 0,
982                 .first_device           = 0,
983                 .first_card_vendor      = 0,
984                 .first_card_device      = 0,
985                 .second_vendor          = 0,
986                 .second_device          = 0,
987                 .second_card_vendor     = 0,
988                 .second_card_device     = 0,
989                 .lb_vendor              = NULL,
990                 .lb_part                = NULL,
991         }       /* Keep this */
992 };
993
994 void print_supported_boards(void)
995 {
996         int i;
997
998         printf("\nSupported mainboards (this list is not exhaustive!):\n\n");
999
1000         for (i = 0; board_pciid_enables[i].name != NULL; i++) {
1001                 if (board_pciid_enables[i].lb_vendor != NULL) {
1002                         printf("%s (-m %s:%s)\n", board_pciid_enables[i].name,
1003                                board_pciid_enables[i].lb_vendor,
1004                                board_pciid_enables[i].lb_part);
1005                 } else {
1006                         printf("%s (autodetected)\n",
1007                                board_pciid_enables[i].name);
1008                 }
1009         }
1010
1011         printf("\nSee also: http://coreboot.org/Flashrom\n");
1012 }
1013
1014 /**
1015  * Match boards on coreboot table gathered vendor and part name.
1016  * Require main PCI IDs to match too as extra safety.
1017  */
1018 static struct board_pciid_enable *board_match_coreboot_name(const char *vendor,
1019                                                             const char *part)
1020 {
1021         struct board_pciid_enable *board = board_pciid_enables;
1022         struct board_pciid_enable *partmatch = NULL;
1023
1024         for (; board->name; board++) {
1025                 if (vendor && (!board->lb_vendor
1026                                || strcasecmp(board->lb_vendor, vendor)))
1027                         continue;
1028
1029                 if (!board->lb_part || strcasecmp(board->lb_part, part))
1030                         continue;
1031
1032                 if (!pci_dev_find(board->first_vendor, board->first_device))
1033                         continue;
1034
1035                 if (board->second_vendor &&
1036                     !pci_dev_find(board->second_vendor, board->second_device))
1037                         continue;
1038
1039                 if (vendor)
1040                         return board;
1041
1042                 if (partmatch) {
1043                         /* a second entry has a matching part name */
1044                         printf("AMBIGUOUS BOARD NAME: %s\n", part);
1045                         printf("At least vendors '%s' and '%s' match.\n",
1046                                partmatch->lb_vendor, board->lb_vendor);
1047                         printf("Please use the full -m vendor:part syntax.\n");
1048                         return NULL;
1049                 }
1050                 partmatch = board;
1051         }
1052
1053         if (partmatch)
1054                 return partmatch;
1055
1056         printf("\nUnknown vendor:board from coreboot table or -m option: %s:%s\n\n", vendor, part);
1057         return NULL;
1058 }
1059
1060 /**
1061  * Match boards on PCI IDs and subsystem IDs.
1062  * Second set of IDs can be main only or missing completely.
1063  */
1064 static struct board_pciid_enable *board_match_pci_card_ids(void)
1065 {
1066         struct board_pciid_enable *board = board_pciid_enables;
1067
1068         for (; board->name; board++) {
1069                 if (!board->first_card_vendor || !board->first_card_device)
1070                         continue;
1071
1072                 if (!pci_card_find(board->first_vendor, board->first_device,
1073                                    board->first_card_vendor,
1074                                    board->first_card_device))
1075                         continue;
1076
1077                 if (board->second_vendor) {
1078                         if (board->second_card_vendor) {
1079                                 if (!pci_card_find(board->second_vendor,
1080                                                    board->second_device,
1081                                                    board->second_card_vendor,
1082                                                    board->second_card_device))
1083                                         continue;
1084                         } else {
1085                                 if (!pci_dev_find(board->second_vendor,
1086                                                   board->second_device))
1087                                         continue;
1088                         }
1089                 }
1090
1091                 return board;
1092         }
1093
1094         return NULL;
1095 }
1096
1097 int board_flash_enable(const char *vendor, const char *part)
1098 {
1099         struct board_pciid_enable *board = NULL;
1100         int ret = 0;
1101
1102         if (part)
1103                 board = board_match_coreboot_name(vendor, part);
1104
1105         if (!board)
1106                 board = board_match_pci_card_ids();
1107
1108         if (board) {
1109                 printf("Found board \"%s\", enabling flash write... ",
1110                        board->name);
1111
1112                 ret = board->enable(board->name);
1113                 if (ret)
1114                         printf("FAILED!\n");
1115                 else
1116                         printf("OK.\n");
1117         }
1118
1119         return ret;
1120 }