Check availability of GPO lines on Intel PIIX4

This patch changes the intel_piix4_gpo_set() function to always check
the GENCFG and XBCS registers for the availability of the
requested GPO line before raising/lowering it and fails otherwise. It
makes no attempt to bypass the values in these configuration
registers.

The old flashrom code did consider it safe to reprogram (multiplexed)
GPO:s 22-26 without checking the value of the controlling register
(GENCFG). I do not really know why.

I have tested this patch on an Asus P2B-N (needs GPO18 low) and MSI
MS-6163 Pro (needs GPO14 high).

The information for these registers are from the Intel "82371AB
PCI-TO-ISA / IDE XCELERATOR (PIIX4)" datasheet available here:
http://www.intel.com/design/intarch/datashts/29056201.pdf

Corresponding to flashrom svn r1142.

Signed-off-by: Mattias Mattsson <vitplister@gmail.com>
Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
diff --git a/board_enable.c b/board_enable.c
index 49ee6ff..0491a37 100644
--- a/board_enable.c
+++ b/board_enable.c
@@ -997,6 +997,43 @@
 	struct pci_dev *dev;
 	uint32_t tmp, base;
 
+	static const uint32_t nonmuxed_gpos  = 0x58000101; /* GPPO {0,8,27,28,30} are always available */
+
+	static const struct {unsigned int reg, mask, value; } piix4_gpo[] = {
+	  {0},
+	  {0xB0, 0x0001, 0x0000},        /* GPO1... */
+	  {0xB0, 0x0001, 0x0000},
+	  {0xB0, 0x0001, 0x0000},
+	  {0xB0, 0x0001, 0x0000},
+	  {0xB0, 0x0001, 0x0000},
+	  {0xB0, 0x0001, 0x0000},
+	  {0xB0, 0x0001, 0x0000},        /* ...GPO7: GENCFG bit 0 */
+	  {0},
+	  {0xB0, 0x0100, 0x0000},        /* GPO9:  GENCFG bit 8 */
+	  {0xB0, 0x0200, 0x0000},        /* GPO10: GENCFG bit 9 */
+	  {0xB0, 0x0400, 0x0000},        /* GPO11: GENCFG bit 10 */
+	  {0x4E, 0x0100, 0x0000},        /* GPO12... */
+	  {0x4E, 0x0100, 0x0000},
+	  {0x4E, 0x0100, 0x0000},        /* ...GPO14: XBCS bit 8 */
+	  {0xB2, 0x0002, 0x0002},        /* GPO15... */
+	  {0xB2, 0x0002, 0x0002},        /* ...GPO16: GENCFG bit 17 */
+	  {0xB2, 0x0004, 0x0004},        /* GPO17: GENCFG bit 18 */
+	  {0xB2, 0x0008, 0x0008},        /* GPO18: GENCFG bit 19 */
+	  {0xB2, 0x0010, 0x0010},        /* GPO19: GENCFG bit 20 */
+	  {0xB2, 0x0020, 0x0020},        /* GPO20: GENCFG bit 21 */
+	  {0xB2, 0x0040, 0x0040},        /* GPO21: GENCFG bit 22 */
+	  {0xB2, 0x1000, 0x1000},        /* GPO22... */
+	  {0xB2, 0x1000, 0x1000},        /* ...GPO23: GENCFG bit 28 */
+	  {0xB2, 0x2000, 0x2000},        /* GPO24: GENCFG bit 29 */
+	  {0xB2, 0x4000, 0x4000},        /* GPO25: GENCFG bit 30 */
+	  {0xB2, 0x8000, 0x8000},        /* GPO26: GENCFG bit 31 */
+	  {0},
+	  {0},
+	  {0x4E, 0x0100, 0x0000},        /* ...GPO29: XBCS bit 8 */
+	  {0}
+	};
+
+
 	dev = pci_dev_find(0x8086, 0x7110);	/* Intel PIIX4 ISA bridge */
 	if (!dev) {
 		msg_perr("\nERROR: Intel PIIX4 ISA bridge not found.\n");
@@ -1009,36 +1046,12 @@
 		return -1;
 	}
 
-	/* These are dual function pins which are most likely in use already. */
-	if (((gpo >= 1) && (gpo <= 7)) ||
-	    ((gpo >= 9) && (gpo <= 21)) || (gpo == 29)) {
-		msg_perr("\nERROR: Unsupported PIIX4 GPO%d.\n", gpo);
-		return -1;
+	if ( (((1 << gpo) & nonmuxed_gpos) == 0) &&
+	     (pci_read_word(dev, piix4_gpo[gpo].reg) & piix4_gpo[gpo].mask) != piix4_gpo[gpo].value ) {
+	  msg_perr("\nERROR: PIIX4 GPO\%d not programmed for output.\n", gpo);
+	  return -1;
 	}
 
-	/* Dual function that need special enable. */
-	if ((gpo >= 22) && (gpo <= 26)) {
-		tmp = pci_read_long(dev, 0xB0); /* GENCFG */
-		switch (gpo) {
-		case 22: /* XBUS: XDIR#/GPO22 */
-		case 23: /* XBUS: XOE#/GPO23 */
-			tmp |= 1 << 28;
-			break;
-		case 24: /* RTCSS#/GPO24 */
-			tmp |= 1 << 29;
-			break;
-		case 25: /* RTCALE/GPO25 */
-			tmp |= 1 << 30;
-			break;
-		case 26: /* KBCSS#/GPO26 */
-			tmp |= 1 << 31;
-			break;
-		}
-		pci_write_long(dev, 0xB0, tmp);
-	}
-
-	/* GPO {0,8,27,28,30} are always available. */
-
 	dev = pci_dev_find(0x8086, 0x7113);	/* Intel PIIX4 PM */
 	if (!dev) {
 		msg_perr("\nERROR: Intel PIIX4 PM not found.\n");
@@ -1064,7 +1077,7 @@
  * Suited for:
  *  - EPoX EP-BX3
  */
-static int board_epox_ep_bx3(void)
+static int intel_piix4_gpo22_raise(void)
 {
 	return intel_piix4_gpo_set(22, 1);
 }
@@ -1778,7 +1791,7 @@
 	{0x1106, 0x3038, 0x1019, 0x0996,  0x1106, 0x3177, 0x1019, 0x0996, NULL,          NULL,         NULL,          "Elitegroup",  "K7VTA3",                256, OK, NULL},
 	{0x1106, 0x3177, 0x1106, 0x3177,  0x1106, 0x3059, 0x1695, 0x3005, NULL,          NULL,         NULL,          "EPoX",        "EP-8K5A2",              0,   OK, w836xx_memw_enable_2e},
 	{0x10EC, 0x8139, 0x1695, 0x9001,  0x11C1, 0x5811, 0x1695, 0x9015, NULL,          NULL,         NULL,          "EPoX",        "EP-8RDA3+",             0,   OK, nvidia_mcp_gpio31_raise},
-	{0x8086, 0x7110,      0,      0,  0x8086, 0x7190,      0,      0, NULL,          "epox",       "ep-bx3",      "EPoX",        "EP-BX3",                0,   OK, board_epox_ep_bx3},
+	{0x8086, 0x7110,      0,      0,  0x8086, 0x7190,      0,      0, NULL,          "epox",       "ep-bx3",      "EPoX",        "EP-BX3",                0,   NT, intel_piix4_gpo22_raise},
 	{0x1106, 0x0686, 0x1106, 0x0686,  0x1106, 0x3058, 0x1458, 0xa000, NULL,          NULL,         NULL,          "GIGABYTE",    "GA-7ZM",                512, OK, NULL},
 	{0x8086, 0x244b, 0x8086, 0x2442,  0x8086, 0x2445, 0x1458, 0xa002, NULL,          NULL,         NULL,          "GIGABYTE",    "GA-8IRML",              0,   OK, intel_ich_gpio25_raise},
 	{0x8086, 0x24c3, 0x1458, 0x24c2,  0x8086, 0x24cd, 0x1458, 0x5004, NULL,          NULL,         NULL,          "GIGABYTE",    "GA-8PE667 Ultra 2",     0,   OK, intel_ich_gpio32_raise},