blob: 84c6e3afe7f747aff4d8675fb45a5d34bec26cc4 [file] [log] [blame]
Luc Verhaegen8e3a6002007-04-04 22:45:58 +00001/*
Uwe Hermannd1107642007-08-29 17:52:32 +00002 * This file is part of the flashrom project.
Luc Verhaegen8e3a6002007-04-04 22:45:58 +00003 *
Uwe Hermannd1107642007-08-29 17:52:32 +00004 * Copyright (C) 2005-2007 coresystems GmbH <stepan@coresystems.de>
5 * Copyright (C) 2006 Uwe Hermann <uwe@hermann-uwe.de>
6 * Copyright (C) 2007 Luc Verhaegen <libv@skynet.be>
Carl-Daniel Hailfinger92242622007-09-27 14:29:57 +00007 * Copyright (C) 2007 Carl-Daniel Hailfinger
Luc Verhaegen8e3a6002007-04-04 22:45:58 +00008 *
Uwe Hermannd1107642007-08-29 17:52:32 +00009 * 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.
Luc Verhaegen8e3a6002007-04-04 22:45:58 +000012 *
Uwe Hermannd1107642007-08-29 17:52:32 +000013 * 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
Luc Verhaegen8e3a6002007-04-04 22:45:58 +000021 */
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>
Luc Verhaegen8e3a6002007-04-04 22:45:58 +000031#include "flash.h"
Luc Verhaegen8e3a6002007-04-04 22:45:58 +000032
Carl-Daniel Hailfingere1514992007-10-02 15:49:25 +000033#define ITE_SUPERIO_PORT1 0x2e
34#define ITE_SUPERIO_PORT2 0x4e
35
36#define JEDEC_RDID {0x9f}
37#define JEDEC_RDID_OUTSIZE 0x01
38#define JEDEC_RDID_INSIZE 0x03
39
40static uint16_t it8716f_flashport = 0;
41
Carl-Daniel Hailfinger92242622007-09-27 14:29:57 +000042/* Generic Super I/O helper functions */
43uint8_t regval(uint16_t port, uint8_t reg)
44{
45 outb(reg, port);
46 return inb(port + 1);
47}
48
49void regwrite(uint16_t port, uint8_t reg, uint8_t val)
50{
51 outb(reg, port);
52 outb(val, port + 1);
53}
54
55/* Helper functions for most recent ITE IT87xx Super I/O chips */
56#define CHIP_ID_BYTE1_REG 0x20
57#define CHIP_ID_BYTE2_REG 0x21
58static void enter_conf_mode_ite(uint16_t port)
59{
60 outb(0x87, port);
61 outb(0x01, port);
62 outb(0x55, port);
Carl-Daniel Hailfingere1514992007-10-02 15:49:25 +000063 if (port == ITE_SUPERIO_PORT1)
Carl-Daniel Hailfinger92242622007-09-27 14:29:57 +000064 outb(0x55, port);
65 else
66 outb(0xaa, port);
67}
68
69static void exit_conf_mode_ite(uint16_t port)
70{
71 regwrite(port, 0x02, 0x02);
72}
73
74static uint16_t find_ite_serial_flash_port(uint16_t port)
75{
76 uint8_t tmp = 0;
77 uint16_t id, flashport = 0;
78
79 enter_conf_mode_ite(port);
80
81 id = regval(port, CHIP_ID_BYTE1_REG) << 8;
82 id |= regval(port, CHIP_ID_BYTE2_REG);
83
84 /* TODO: Handle more IT87xx if they support flash translation */
85 if (id == 0x8716) {
86 /* NOLDN, reg 0x24, mask out lowest bit (suspend) */
87 tmp = regval(port, 0x24) & 0xFE;
88 printf("Serial flash segment 0x%08x-0x%08x %sabled\n",
89 0xFFFE0000, 0xFFFFFFFF, (tmp & 1 << 1) ? "en" : "dis");
90 printf("Serial flash segment 0x%08x-0x%08x %sabled\n",
91 0x000E0000, 0x000FFFFF, (tmp & 1 << 1) ? "en" : "dis");
92 printf("Serial flash segment 0x%08x-0x%08x %sabled\n",
93 0xFFEE0000, 0xFFEFFFFF, (tmp & 1 << 2) ? "en" : "dis");
94 printf("Serial flash segment 0x%08x-0x%08x %sabled\n",
95 0xFFF80000, 0xFFFEFFFF, (tmp & 1 << 3) ? "en" : "dis");
96 printf("LPC write to serial flash %sabled\n",
97 (tmp & 1 << 4) ? "en" : "dis");
98 printf("serial flash pin %i\n", (tmp & 1 << 5) ? 87 : 29);
99 /* LDN 0x7, reg 0x64/0x65 */
100 regwrite(port, 0x07, 0x7);
101 flashport = regval(port, 0x64) << 8;
102 flashport |= regval(port, 0x65);
103 }
104 exit_conf_mode_ite(port);
105 return flashport;
106}
107
Carl-Daniel Hailfingere1514992007-10-02 15:49:25 +0000108/* The IT8716F only supports commands with length 1,2,4,5 bytes including
109 command byte and can not read more than 3 bytes from the device.
110 This function expects writearr[0] to be the first byte sent to the device,
111 whereas the IT8716F splits commands internally into address and non-address
112 commands with the address in inverse wire order. That's why the register
113 ordering in case 4 and 5 may seem strange. */
114static int it8716f_spi_command(uint16_t port, unsigned char writecnt, unsigned char readcnt, const unsigned char *writearr, unsigned char *readarr)
Carl-Daniel Hailfinger92242622007-09-27 14:29:57 +0000115{
Carl-Daniel Hailfingere1514992007-10-02 15:49:25 +0000116 uint8_t busy, writeenc;
Carl-Daniel Hailfinger92242622007-09-27 14:29:57 +0000117 do {
118 busy = inb(port) & 0x80;
119 } while (busy);
Carl-Daniel Hailfingere1514992007-10-02 15:49:25 +0000120 if (readcnt > 3) {
121 printf("%s called with unsupported readcnt %i\n",
122 __FUNCTION__, readcnt);
123 return 1;
124 }
125 switch (writecnt) {
126 case 1:
127 outb(writearr[0], port + 1);
128 writeenc = 0x0;
129 break;
130 case 2:
131 outb(writearr[0], port + 1);
132 outb(writearr[1], port + 7);
133 writeenc = 0x1;
134 break;
135 case 4:
136 outb(writearr[0], port + 1);
137 outb(writearr[1], port + 4);
138 outb(writearr[2], port + 3);
139 outb(writearr[3], port + 2);
140 writeenc = 0x2;
141 break;
142 case 5:
143 outb(writearr[0], port + 1);
144 outb(writearr[1], port + 4);
145 outb(writearr[2], port + 3);
146 outb(writearr[3], port + 2);
147 outb(writearr[4], port + 7);
148 writeenc = 0x3;
149 break;
150 default:
151 printf("%s called with unsupported writecnt %i\n",
152 __FUNCTION__, writecnt);
153 return 1;
154 }
155 /* Start IO, 33MHz, readcnt input bytes, writecnt output bytes. Note:
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000156 * We can't use writecnt directly, but have to use a strange encoding
157 */
Carl-Daniel Hailfingere1514992007-10-02 15:49:25 +0000158 outb((0x5 << 4) | ((readcnt & 0x3) << 2) | (writeenc), port);
Carl-Daniel Hailfinger92242622007-09-27 14:29:57 +0000159 do {
160 busy = inb(port) & 0x80;
161 } while (busy);
Carl-Daniel Hailfingere1514992007-10-02 15:49:25 +0000162 readarr[0] = inb(port + 5);
163 readarr[1] = inb(port + 6);
164 readarr[2] = inb(port + 7);
165 return 0;
166}
167
168static int it8716f_serial_rdid(uint16_t port, unsigned char *readarr)
169{
170 const unsigned char cmd[] = JEDEC_RDID;
171
172 if (it8716f_spi_command(port, JEDEC_RDID_OUTSIZE, JEDEC_RDID_INSIZE, cmd, readarr))
173 return 1;
174 printf("RDID returned %02x %02x %02x\n", readarr[0], readarr[1], readarr[2]);
175 return 0;
Carl-Daniel Hailfinger92242622007-09-27 14:29:57 +0000176}
177
178static int it87xx_probe_serial_flash(const char *name)
179{
Carl-Daniel Hailfingere1514992007-10-02 15:49:25 +0000180 it8716f_flashport = find_ite_serial_flash_port(ITE_SUPERIO_PORT1);
181 if (!it8716f_flashport)
182 it8716f_flashport = find_ite_serial_flash_port(ITE_SUPERIO_PORT2);
183 return (!it8716f_flashport);
184}
185
186int probe_spi(struct flashchip *flash)
187{
188 unsigned char readarr[3];
189 uint8_t manuf_id;
190 uint16_t model_id;
191 if (it8716f_flashport) {
192 it8716f_serial_rdid(it8716f_flashport, readarr);
193 manuf_id = readarr[0];
194 model_id = (readarr[1] << 8) | readarr[2];
195 printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, manuf_id, model_id);
196 if (manuf_id == flash->manufacture_id && model_id == flash->model_id)
197 return 1;
198 }
199
Carl-Daniel Hailfinger92242622007-09-27 14:29:57 +0000200 return 0;
201}
202
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000203/*
Uwe Hermannffec5f32007-08-23 16:08:21 +0000204 * Helper functions for many Winbond Super I/Os of the W836xx range.
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000205 */
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000206/* Enter extended functions */
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000207static void w836xx_ext_enter(uint16_t port)
Mondrian Nuessleaef1c7c2007-05-03 10:09:23 +0000208{
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000209 outb(0x87, port);
210 outb(0x87, port);
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000211}
Mondrian Nuessleaef1c7c2007-05-03 10:09:23 +0000212
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000213/* Leave extended functions */
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000214static void w836xx_ext_leave(uint16_t port)
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000215{
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000216 outb(0xAA, port);
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000217}
Mondrian Nuessleaef1c7c2007-05-03 10:09:23 +0000218
Uwe Hermannffec5f32007-08-23 16:08:21 +0000219/* General functions for reading/writing Winbond Super I/Os. */
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000220static unsigned char wbsio_read(uint16_t index, uint8_t reg)
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000221{
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000222 outb(reg, index);
223 return inb(index+1);
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000224}
Mondrian Nuessleaef1c7c2007-05-03 10:09:23 +0000225
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000226static void wbsio_write(uint16_t index, uint8_t reg, uint8_t data)
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000227{
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000228 outb(reg, index);
229 outb(data, index+1);
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000230}
Mondrian Nuessleaef1c7c2007-05-03 10:09:23 +0000231
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000232static void wbsio_mask(uint16_t index, uint8_t reg, uint8_t data, uint8_t mask)
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000233{
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000234 uint8_t tmp;
Mondrian Nuessleaef1c7c2007-05-03 10:09:23 +0000235
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000236 outb(reg, index);
237 tmp = inb(index+1) & ~mask;
238 outb(tmp | (data & mask), index+1);
Mondrian Nuessleaef1c7c2007-05-03 10:09:23 +0000239}
240
Uwe Hermannffec5f32007-08-23 16:08:21 +0000241/**
242 * Winbond W83627HF: Raise GPIO24.
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000243 *
244 * Suited for:
Uwe Hermannffec5f32007-08-23 16:08:21 +0000245 * - Agami Aruma
246 * - IWILL DK8-HTX
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000247 */
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000248static int w83627hf_gpio24_raise(uint16_t index, const char *name)
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000249{
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000250 w836xx_ext_enter(index);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000251
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000252 /* Is this the w83627hf? */
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000253 if (wbsio_read(index, 0x20) != 0x52) { /* Super I/O device ID register */
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000254 fprintf(stderr, "\nERROR: %s: W83627HF: Wrong ID: 0x%02X.\n",
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000255 name, wbsio_read(index, 0x20));
256 w836xx_ext_leave(index);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000257 return -1;
258 }
259
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000260 /* PIN89S: WDTO/GP24 multiplex -> GPIO24 */
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000261 wbsio_mask(index, 0x2B, 0x10, 0x10);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000262
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000263 wbsio_write(index, 0x07, 0x08); /* Select logical device 8: GPIO port 2 */
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000264
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000265 wbsio_mask(index, 0x30, 0x01, 0x01); /* Activate logical device. */
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000266
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000267 wbsio_mask(index, 0xF0, 0x00, 0x10); /* GPIO24 -> output */
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000268
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000269 wbsio_mask(index, 0xF2, 0x00, 0x10); /* Clear GPIO24 inversion */
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000270
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000271 wbsio_mask(index, 0xF1, 0x10, 0x10); /* Raise GPIO24 */
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000272
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000273 w836xx_ext_leave(index);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000274
275 return 0;
276}
277
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000278static int w83627hf_gpio24_raise_2e(const char *name)
279{
280 return w83627hf_gpio24_raise(0x2d, name);
281}
282
283/**
284 * Winbond W83627THF: GPIO 4, bit 4
285 *
286 * Suited for:
287 * - MSI K8N-NEO3
288 */
289static int w83627thf_gpio4_4_raise(uint16_t index, const char *name)
290{
291 w836xx_ext_enter(index);
292 /* Is this the w83627thf? */
293 if (wbsio_read(index, 0x20) != 0x82) { /* Super I/O device ID register */
294 fprintf(stderr, "\nERROR: %s: W83627THF: Wrong ID: 0x%02X.\n",
295 name, wbsio_read(index, 0x20));
296 w836xx_ext_leave(index);
297 return -1;
298 }
299
300 /* PINxxxxS: GPIO4/bit 4 multiplex -> GPIOXXX */
301
302 wbsio_write(index, 0x07, 0x09); /* Select logical device 9: GPIO port 4 */
303
304 wbsio_mask(index, 0x30, 0x02, 0x02); /* Activate logical device. */
305
306 wbsio_mask(index, 0xF4, 0x00, 0x10); /* GPIO4 bit 4 -> output */
307
308 wbsio_mask(index, 0xF6, 0x00, 0x10); /* Clear GPIO4 bit 4 inversion */
309
310 wbsio_mask(index, 0xF5, 0x10, 0x10); /* Raise GPIO4 bit 4 */
311
312 w836xx_ext_leave(index);
313
314 return 0;
315}
316
317static int w83627thf_gpio4_4_raise_4e(const char *name)
318{
319 return w83627thf_gpio4_4_raise(0x4E, name);
320}
Uwe Hermannffec5f32007-08-23 16:08:21 +0000321/**
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000322 * Suited for VIAs EPIA M and MII, and maybe other CLE266 based EPIAs.
323 *
Uwe Hermannffec5f32007-08-23 16:08:21 +0000324 * We don't need to do this when using LinuxBIOS, GPIO15 is never lowered there.
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000325 */
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000326static int board_via_epia_m(const char *name)
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000327{
Uwe Hermanna7e05482007-05-09 10:17:44 +0000328 struct pci_dev *dev;
329 unsigned int base;
330 uint8_t val;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000331
Uwe Hermanna7e05482007-05-09 10:17:44 +0000332 dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */
333 if (!dev) {
334 fprintf(stderr, "\nERROR: VT8235 ISA Bridge not found.\n");
335 return -1;
336 }
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000337
Uwe Hermanna7e05482007-05-09 10:17:44 +0000338 /* GPIO12-15 -> output */
339 val = pci_read_byte(dev, 0xE4);
340 val |= 0x10;
341 pci_write_byte(dev, 0xE4, val);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000342
Uwe Hermanna7e05482007-05-09 10:17:44 +0000343 /* Get Power Management IO address. */
344 base = pci_read_word(dev, 0x88) & 0xFF80;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000345
Uwe Hermanna7e05482007-05-09 10:17:44 +0000346 /* enable GPIO15 which is connected to write protect. */
347 val = inb(base + 0x4D);
348 val |= 0x80;
349 outb(val, base + 0x4D);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000350
Uwe Hermanna7e05482007-05-09 10:17:44 +0000351 return 0;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000352}
353
Uwe Hermannffec5f32007-08-23 16:08:21 +0000354/**
Luc Verhaegen32707542007-07-04 17:51:49 +0000355 * Suited for:
Uwe Hermannffec5f32007-08-23 16:08:21 +0000356 * - ASUS A7V8X-MX SE and A7V400-MX: AMD K7 + VIA KM400A + VT8235
357 * - Tyan Tomcat K7M: AMD Geode NX + VIA KM400 + VT8237.
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000358 */
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000359static int board_asus_a7v8x_mx(const char *name)
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000360{
Uwe Hermanna7e05482007-05-09 10:17:44 +0000361 struct pci_dev *dev;
362 uint8_t val;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000363
Uwe Hermanna7e05482007-05-09 10:17:44 +0000364 dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */
Luc Verhaegen32707542007-07-04 17:51:49 +0000365 if (!dev)
366 dev = pci_dev_find(0x1106, 0x3227); /* VT8237 ISA bridge */
Uwe Hermanna7e05482007-05-09 10:17:44 +0000367 if (!dev) {
Luc Verhaegen32707542007-07-04 17:51:49 +0000368 fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n");
Uwe Hermanna7e05482007-05-09 10:17:44 +0000369 return -1;
370 }
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000371
Uwe Hermanna7e05482007-05-09 10:17:44 +0000372 /* This bit is marked reserved actually */
373 val = pci_read_byte(dev, 0x59);
374 val &= 0x7F;
375 pci_write_byte(dev, 0x59, val);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000376
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000377 /* Raise ROM MEMW# line on Winbond w83697 SuperIO */
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000378 w836xx_ext_enter(0x2E);
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000379
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000380 if (!(wbsio_read(0x2E, 0x24) & 0x02)) /* flash rom enabled? */
381 wbsio_mask(0x2E, 0x24, 0x08, 0x08); /* enable MEMW# */
Luc Verhaegen7977f4e2007-05-04 04:47:04 +0000382
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000383 w836xx_ext_leave(0x2E);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000384
Uwe Hermanna7e05482007-05-09 10:17:44 +0000385 return 0;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000386}
387
Uwe Hermannffec5f32007-08-23 16:08:21 +0000388/**
Luc Verhaegen6b141752007-05-20 16:16:13 +0000389 * Suited for ASUS P5A.
390 *
391 * This is rather nasty code, but there's no way to do this cleanly.
392 * We're basically talking to some unknown device on SMBus, my guess
393 * is that it is the Winbond W83781D that lives near the DIP BIOS.
394 */
Luc Verhaegen6b141752007-05-20 16:16:13 +0000395static int board_asus_p5a(const char *name)
396{
397 uint8_t tmp;
398 int i;
399
400#define ASUSP5A_LOOP 5000
401
402 outb(0x00, 0xE807);
403 outb(0xEF, 0xE803);
404
405 outb(0xFF, 0xE800);
406
407 for (i = 0; i < ASUSP5A_LOOP; i++) {
408 outb(0xE1, 0xFF);
409 if (inb(0xE800) & 0x04)
410 break;
411 }
412
413 if (i == ASUSP5A_LOOP) {
414 printf("%s: Unable to contact device.\n", name);
415 return -1;
416 }
417
418 outb(0x20, 0xE801);
419 outb(0x20, 0xE1);
420
421 outb(0xFF, 0xE802);
422
423 for (i = 0; i < ASUSP5A_LOOP; i++) {
424 tmp = inb(0xE800);
425 if (tmp & 0x70)
426 break;
427 }
428
429 if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) {
430 printf("%s: failed to read device.\n", name);
431 return -1;
432 }
433
434 tmp = inb(0xE804);
435 tmp &= ~0x02;
436
437 outb(0x00, 0xE807);
438 outb(0xEE, 0xE803);
439
440 outb(tmp, 0xE804);
441
442 outb(0xFF, 0xE800);
443 outb(0xE1, 0xFF);
444
445 outb(0x20, 0xE801);
446 outb(0x20, 0xE1);
447
448 outb(0xFF, 0xE802);
449
450 for (i = 0; i < ASUSP5A_LOOP; i++) {
451 tmp = inb(0xE800);
452 if (tmp & 0x70)
453 break;
454 }
455
456 if ((i == ASUSP5A_LOOP) || !(tmp & 0x10)) {
457 printf("%s: failed to write to device.\n", name);
458 return -1;
459 }
460
461 return 0;
462}
463
Stefan Reinauer1c283f42007-06-05 12:51:52 +0000464static int board_ibm_x3455(const char *name)
465{
466 uint8_t byte;
467
Uwe Hermanne823ee02007-06-05 15:02:18 +0000468 /* Set GPIO lines in the Broadcom HT-1000 southbridge. */
Stefan Reinauer1c283f42007-06-05 12:51:52 +0000469 outb(0x45, 0xcd6);
470 byte = inb(0xcd7);
Uwe Hermanne823ee02007-06-05 15:02:18 +0000471 outb(byte | 0x20, 0xcd7);
Stefan Reinauer1c283f42007-06-05 12:51:52 +0000472
473 return 0;
474}
475
Luc Verhaegenfdd0c582007-08-11 16:59:11 +0000476/**
477 * Suited for EPoX EP-BX3, and maybe some other Intel 440BX based boards.
478 */
479static int board_epox_ep_bx3(const char *name)
480{
481 uint8_t tmp;
482
483 /* Raise GPIO22. */
484 tmp = inb(0x4036);
485 outb(tmp, 0xEB);
486
487 tmp |= 0x40;
488
489 outb(tmp, 0x4036);
490 outb(tmp, 0xEB);
491
492 return 0;
493}
494
Uwe Hermannffec5f32007-08-23 16:08:21 +0000495/**
496 * We use 2 sets of IDs here, you're free to choose which is which. This
497 * is to provide a very high degree of certainty when matching a board on
498 * the basis of subsystem/card IDs. As not every vendor handles
499 * subsystem/card IDs in a sane manner.
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000500 *
Uwe Hermannffec5f32007-08-23 16:08:21 +0000501 * Keep the second set NULLed if it should be ignored.
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000502 */
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000503struct board_pciid_enable {
Uwe Hermanna7e05482007-05-09 10:17:44 +0000504 /* Any device, but make it sensible, like the isa bridge. */
505 uint16_t first_vendor;
506 uint16_t first_device;
507 uint16_t first_card_vendor;
508 uint16_t first_card_device;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000509
Uwe Hermanna7e05482007-05-09 10:17:44 +0000510 /* Any device, but make it sensible, like
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000511 * the host bridge. May be NULL
512 */
Uwe Hermanna7e05482007-05-09 10:17:44 +0000513 uint16_t second_vendor;
514 uint16_t second_device;
515 uint16_t second_card_vendor;
516 uint16_t second_card_device;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000517
Uwe Hermanna7e05482007-05-09 10:17:44 +0000518 /* From linuxbios table */
519 char *lb_vendor;
520 char *lb_part;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000521
Uwe Hermanna7e05482007-05-09 10:17:44 +0000522 char *name;
523 int (*enable) (const char *name);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000524};
525
526struct board_pciid_enable board_pciid_enables[] = {
Carl-Daniel Hailfinger92242622007-09-27 14:29:57 +0000527 {0x10de, 0x0360, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
528 "gigabyte", "m57sli", "GIGABYTE GA-M57SLI", it87xx_probe_serial_flash},
Uwe Hermanna7e05482007-05-09 10:17:44 +0000529 {0x1022, 0x7468, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000530 "iwill", "dk8_htx", "IWILL DK8-HTX", w83627hf_gpio24_raise_2e},
531 {0x10de, 0x005e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
532 "msi", "k8n-neo3", "MSI K8N Neo3", w83627thf_gpio4_4_raise_4e},
Uwe Hermanna7e05482007-05-09 10:17:44 +0000533 {0x1022, 0x746B, 0x1022, 0x36C0, 0x0000, 0x0000, 0x0000, 0x0000,
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000534 "AGAMI", "ARUMA", "agami Aruma", w83627hf_gpio24_raise_2e},
Uwe Hermanna7e05482007-05-09 10:17:44 +0000535 {0x1106, 0x3177, 0x1106, 0xAA01, 0x1106, 0x3123, 0x1106, 0xAA01,
536 NULL, NULL, "VIA EPIA M/MII/...", board_via_epia_m},
537 {0x1106, 0x3177, 0x1043, 0x80A1, 0x1106, 0x3205, 0x1043, 0x8118,
538 NULL, NULL, "ASUS A7V8-MX SE", board_asus_a7v8x_mx},
Luc Verhaegen32707542007-07-04 17:51:49 +0000539 {0x8086, 0x1076, 0x8086, 0x1176, 0x1106, 0x3059, 0x10f1, 0x2498,
540 NULL, NULL, "Tyan Tomcat K7M", board_asus_a7v8x_mx},
Luc Verhaegen6b141752007-05-20 16:16:13 +0000541 {0x10B9, 0x1541, 0x0000, 0x0000, 0x10B9, 0x1533, 0x0000, 0x0000,
542 "asus", "p5a", "ASUS P5A", board_asus_p5a},
Stefan Reinauer1c283f42007-06-05 12:51:52 +0000543 {0x1166, 0x0205, 0x1014, 0x0347, 0x0000, 0x0000, 0x0000, 0x0000,
544 "ibm", "x3455", "IBM x3455", board_ibm_x3455},
Luc Verhaegenfdd0c582007-08-11 16:59:11 +0000545 {0x8086, 0x7110, 0x0000, 0x0000, 0x8086, 0x7190, 0x0000, 0x0000,
546 "epox", "ep-bx3", "EPoX EP-BX3", board_epox_ep_bx3},
Uwe Hermanna7e05482007-05-09 10:17:44 +0000547 {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL} /* Keep this */
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000548};
549
Uwe Hermannffec5f32007-08-23 16:08:21 +0000550/**
551 * Match boards on LinuxBIOS table gathered vendor and part name.
552 * Require main PCI IDs to match too as extra safety.
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000553 */
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000554static struct board_pciid_enable *board_match_linuxbios_name(char *vendor,
555 char *part)
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000556{
Uwe Hermanna7e05482007-05-09 10:17:44 +0000557 struct board_pciid_enable *board = board_pciid_enables;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000558
Uwe Hermanna7e05482007-05-09 10:17:44 +0000559 for (; board->name; board++) {
560 if (!board->lb_vendor || strcmp(board->lb_vendor, vendor))
561 continue;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000562
Uwe Hermanna7e05482007-05-09 10:17:44 +0000563 if (!board->lb_part || strcmp(board->lb_part, part))
564 continue;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000565
Uwe Hermanna7e05482007-05-09 10:17:44 +0000566 if (!pci_dev_find(board->first_vendor, board->first_device))
567 continue;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000568
Uwe Hermanna7e05482007-05-09 10:17:44 +0000569 if (board->second_vendor &&
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000570 !pci_dev_find(board->second_vendor, board->second_device))
Uwe Hermanna7e05482007-05-09 10:17:44 +0000571 continue;
572 return board;
573 }
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000574 printf("NOT FOUND %s:%s\n", vendor, part);
Uwe Hermanna7e05482007-05-09 10:17:44 +0000575 return NULL;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000576}
577
Uwe Hermannffec5f32007-08-23 16:08:21 +0000578/**
579 * Match boards on PCI IDs and subsystem IDs.
580 * Second set of IDs can be main only or missing completely.
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000581 */
582static struct board_pciid_enable *board_match_pci_card_ids(void)
583{
Uwe Hermanna7e05482007-05-09 10:17:44 +0000584 struct board_pciid_enable *board = board_pciid_enables;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000585
Uwe Hermanna7e05482007-05-09 10:17:44 +0000586 for (; board->name; board++) {
587 if (!board->first_card_vendor || !board->first_card_device)
588 continue;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000589
Uwe Hermanna7e05482007-05-09 10:17:44 +0000590 if (!pci_card_find(board->first_vendor, board->first_device,
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000591 board->first_card_vendor,
592 board->first_card_device))
Uwe Hermanna7e05482007-05-09 10:17:44 +0000593 continue;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000594
Uwe Hermanna7e05482007-05-09 10:17:44 +0000595 if (board->second_vendor) {
596 if (board->second_card_vendor) {
597 if (!pci_card_find(board->second_vendor,
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000598 board->second_device,
599 board->second_card_vendor,
600 board->second_card_device))
Uwe Hermanna7e05482007-05-09 10:17:44 +0000601 continue;
602 } else {
603 if (!pci_dev_find(board->second_vendor,
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000604 board->second_device))
Uwe Hermanna7e05482007-05-09 10:17:44 +0000605 continue;
606 }
607 }
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000608
Uwe Hermanna7e05482007-05-09 10:17:44 +0000609 return board;
610 }
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000611
Uwe Hermanna7e05482007-05-09 10:17:44 +0000612 return NULL;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000613}
614
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000615int board_flash_enable(char *vendor, char *part)
616{
Uwe Hermanna7e05482007-05-09 10:17:44 +0000617 struct board_pciid_enable *board = NULL;
618 int ret = 0;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000619
Uwe Hermanna7e05482007-05-09 10:17:44 +0000620 if (vendor && part)
621 board = board_match_linuxbios_name(vendor, part);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000622
Uwe Hermanna7e05482007-05-09 10:17:44 +0000623 if (!board)
624 board = board_match_pci_card_ids();
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000625
Uwe Hermanna7e05482007-05-09 10:17:44 +0000626 if (board) {
627 printf("Found board \"%s\": Enabling flash write... ",
Ronald G. Minnichfa496922007-10-12 21:22:40 +0000628 board->name);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000629
Uwe Hermanna7e05482007-05-09 10:17:44 +0000630 ret = board->enable(board->name);
631 if (ret)
632 printf("Failed!\n");
633 else
634 printf("OK.\n");
635 }
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000636
Uwe Hermanna7e05482007-05-09 10:17:44 +0000637 return ret;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000638}