blob: d5622c44ddabbded38655bc5e6390bfec7fd5104 [file] [log] [blame]
Luc Verhaegen8e3a6002007-04-04 22:45:58 +00001/*
2 * flash rom utility: enable flash writes (board specific)
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 Luc Verhaegen <libv@skynet.be>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2
11 *
12 */
13
14/*
15 * Contains the board specific flash enables.
16 */
17
18#include <stdio.h>
19#include <pci/pci.h>
20#include <stdint.h>
21#include <string.h>
22
23#include "flash.h"
24#include "debug.h"
25
Mondrian Nuessleaef1c7c2007-05-03 10:09:23 +000026static int board_iwill_dk8_htx(const char *name)
27{
28 /* Extended function index register, either 0x2e or 0x4e. */
29#define EFIR 0x2e
30 /* Extended function data register, one plus the index reg. */
31#define EFDR EFIR + 1
32 char b;
33
34 /* Disable the flash write protect (which is connected to the
35 * Winbond W83627HF GPIOs).
36 */
37 outb(0x87, EFIR); /* Sequence to unlock extended functions */
38 outb(0x87, EFIR);
39
40 /* Activate logical device. */
41 outb(0x7, EFIR);
42 outb(8, EFDR);
43
44 /* Set GPIO regs. */
45 outb(0x2b, EFIR); /* GPIO multiplexed pin reg. */
46 b = inb(EFDR) | 0xd0;
47 outb(0x2b, EFIR);
48 outb(b, EFDR);
49
50 outb(0x30, EFIR); /* GPIO2 */
51 b = inb(EFDR) | 0x01;
52 outb(0x30, EFIR);
53 outb(b, EFDR);
54
55 outb(0xf0, EFIR); /* IO sel */
56 b = inb(EFDR) | 0xef;
57 outb(0xf0, EFIR);
58 outb(b, EFDR);
59
60 outb(0xf1, EFIR); /* GPIO data reg */
61 b = inb(EFDR) | 0x16;
62 outb(0xf1, EFIR);
63 outb(b, EFDR);
64
65 outb(0xf2, EFIR); /* GPIO inversion reg */
66 b = inb(EFDR) | 0x00;
67 outb(0xf2, EFIR);
68 outb(b, EFDR);
69
70 /* Lock extended functions again. */
71 outb(0xaa, EFIR); /* Command to exit extended functions */
72
73 return 0;
74}
75
Luc Verhaegen8e3a6002007-04-04 22:45:58 +000076/*
77 * Match on pci-ids, no report received, just data from the mainboard
78 * specific code:
79 * main: 0x1022:0x746B, which is the SMBUS controller.
80 * card: 0x1022:0x36C0...
81 */
82
83static int board_agami_aruma(char *name)
84{
85 /* Extended function index register, either 0x2e or 0x4e */
86#define EFIR 0x2e
87 /* Extended function data register, one plus the index reg. */
88#define EFDR EFIR + 1
89 char b;
90
91 /* Disable the flash write protect. The flash write protect is
92 * connected to the WinBond w83627hf GPIO 24.
93 */
94 outb(0x87, EFIR); /* sequence to unlock extended functions */
95 outb(0x87, EFIR);
96
97 outb(0x20, EFIR); /* SIO device ID register */
98 b = inb(EFDR);
99 printf_debug("\nW83627HF device ID = 0x%x\n",b);
100
101 if (b != 0x52) {
102 fprintf(stderr, "\nIncorrect device ID, aborting write protect disable\n");
103 return -1;
104 }
105
106 outb(0x2b, EFIR); /* GPIO multiplexed pin reg. */
107 b = inb(EFDR) | 0x10;
108 outb(0x2b, EFIR);
109 outb(b, EFDR); /* select GPIO 24 instead of WDTO */
110
111 outb(0x7, EFIR); /* logical device select */
112 outb(0x8, EFDR); /* point to device 8, GPIO port 2 */
113
114 outb(0x30, EFIR); /* logic device activation control */
115 outb(0x1, EFDR); /* activate */
116
117 outb(0xf0, EFIR); /* GPIO 20-27 I/O selection register */
118 b = inb(EFDR) & ~0x10;
119 outb(0xf0, EFIR);
120 outb(b, EFDR); /* set GPIO 24 as an output */
121
122 outb(0xf1, EFIR); /* GPIO 20-27 data register */
123 b = inb(EFDR) | 0x10;
124 outb(0xf1, EFIR);
125 outb(b, EFDR); /* set GPIO 24 */
126
127 outb(0xaa, EFIR); /* command to exit extended functions */
128
129 return 0;
130}
131
132/*
133 * Suited for VIAs EPIA M and MII, and maybe other CLE266 based EPIAs.
134 *
135 * We don't need to do this when using linuxbios, GPIO15 is never lowered there.
136 */
137
138static int board_via_epia_m(char *name)
139{
140 struct pci_dev *dev;
141 unsigned int base;
142 uint8_t val;
143
144 dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */
145 if (!dev) {
146 fprintf(stderr, "\nERROR: VT8235 ISA Bridge not found.\n");
147 return -1;
148 }
149
150 /* GPIO12-15 -> output */
151 val = pci_read_byte(dev, 0xE4);
152 val |= 0x10;
153 pci_write_byte(dev, 0xE4, val);
154
155 /* Get Power Management IO address. */
156 base = pci_read_word(dev, 0x88) & 0xFF80;
157
158 /* enable GPIO15 which is connected to write protect. */
159 val = inb(base + 0x4D);
160 val |= 0x80;
161 outb(val, base + 0x4D);
162
163 return 0;
164}
165
166/*
167 * Winbond LPC super IO.
168 *
169 * Raises the ROM MEMW# line.
170 */
171
172static void w83697_rom_memw_enable(void)
173{
174 uint8_t val;
175
176 outb(0x87, 0x2E); /* enable extended functions */
177 outb(0x87, 0x2E);
178
179 outb(0x24, 0x2E); /* rom bits live here */
180
181 val = inb(0x2F);
182 if (!(val & 0x02)) /* flash rom enabled? */
183 outb(val | 0x08, 0x2F); /* enable MEMW# */
184
185 outb(0xAA, 0x2E); /* disable extended functions */
186}
187
188/*
189 * Suited for Asus A7V8X-MX SE and A7V400-MX.
190 *
191 */
192
193static int board_asus_a7v8x_mx(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 fprintf(stderr, "\nERROR: VT8235 ISA Bridge not found.\n");
201 return -1;
202 }
203
204 /* This bit is marked reserved actually */
205 val = pci_read_byte(dev, 0x59);
206 val &= 0x7F;
207 pci_write_byte(dev, 0x59, val);
208
209 w83697_rom_memw_enable();
210
211 return 0;
212}
213
214/*
215 * We use 2 sets of ids here, you're free to choose which is which. This
216 * to provide a very high degree of certainty when matching a board on
217 * the basis of Subsystem/card ids. As not every vendor handles
218 * subsystem/card ids in a sane manner.
219 *
220 * Keep the second set nulled if it should be ignored.
221 *
222 */
223
224struct board_pciid_enable {
225 /* Any device, but make it sensible, like the isa bridge. */
226 uint16_t first_vendor;
227 uint16_t first_device;
228 uint16_t first_card_vendor;
229 uint16_t first_card_device;
230
231 /* Any device, but make it sensible, like
232 * the host bridge. May be NULL
233 */
234 uint16_t second_vendor;
235 uint16_t second_device;
236 uint16_t second_card_vendor;
237 uint16_t second_card_device;
238
239 /* From linuxbios table */
240 char *lb_vendor;
241 char *lb_part;
242
243 char *name;
244 int (*enable)(char *name);
245};
246
247struct board_pciid_enable board_pciid_enables[] = {
Mondrian Nuessleaef1c7c2007-05-03 10:09:23 +0000248 { 0x1022, 0x746B, 0x1022, 0x36C0, 0x0000, 0x0000, 0x0000, 0x0000,
249 "AGAMI", "ARUMA", "agami Aruma", board_agami_aruma },
250 { 0x1106, 0x3177, 0x1106, 0xAA01, 0x1106, 0x3123, 0x1106, 0xAA01,
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000251 NULL, NULL, "VIA EPIA M/MII/...", board_via_epia_m },
Mondrian Nuessleaef1c7c2007-05-03 10:09:23 +0000252 { 0x1106, 0x3177, 0x1043, 0x80A1, 0x1106, 0x3205, 0x1043, 0x8118,
253 NULL, NULL, "ASUS A7V8-MX SE", board_asus_a7v8x_mx },
254 { 0x1022, 0x7468, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
255 "iwill", "dk8_htx", "IWILL DK8-HTX", board_iwill_dk8_htx },
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000256
Mondrian Nuessleaef1c7c2007-05-03 10:09:23 +0000257 { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL } /* Keep this */
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000258};
259
260/*
261 * Match boards on linuxbios table gathered vendor and part name.
262 * Require main pci-ids to match too as extra safety.
263 *
264 */
265static struct board_pciid_enable *
266board_match_linuxbios_name(char *vendor, char *part)
267{
268 struct board_pciid_enable *board = board_pciid_enables;
269
270 for (; board->name; board++) {
271 if (!board->lb_vendor || strcmp(board->lb_vendor, vendor))
272 continue;
273
274 if (!board->lb_part || strcmp(board->lb_part, part))
275 continue;
276
277 if (!pci_dev_find(board->first_vendor, board->first_device))
278 continue;
279
280 if (board->second_vendor &&
281 !pci_dev_find(board->second_vendor, board->second_device))
282 continue;
283 return board;
284 }
285 return NULL;
286}
287
288/*
289 * Match boards on pci ids and subsystem ids.
290 * Second set of ids can be main only or missing completely.
291 */
292static struct board_pciid_enable *board_match_pci_card_ids(void)
293{
294 struct board_pciid_enable *board = board_pciid_enables;
295
296 for (; board->name; board++) {
297 if (!board->first_card_vendor || !board->first_card_device)
298 continue;
299
300 if (!pci_card_find(board->first_vendor, board->first_device,
301 board->first_card_vendor,
302 board->first_card_device))
303 continue;
304
305 if (board->second_vendor) {
306 if (board->second_card_vendor) {
307 if (!pci_card_find(board->second_vendor,
308 board->second_device,
309 board->second_card_vendor,
310 board->second_card_device))
311 continue;
312 } else {
313 if (!pci_dev_find(board->second_vendor,
314 board->second_device))
315 continue;
316 }
317 }
318
319 return board;
320 }
321
322 return NULL;
323}
324
325/*
326 *
327 */
328int board_flash_enable(char *vendor, char *part)
329{
330 struct board_pciid_enable *board = NULL;
331 int ret = 0;
332
333 if (vendor && part)
334 board = board_match_linuxbios_name(vendor, part);
335
336 if (!board)
337 board = board_match_pci_card_ids();
338
339 if (board) {
340 printf("Found board \"%s\": Enabling flash write... ",
341 board->name);
342
343 ret = board->enable(board->name);
344 if (ret)
345 printf("Failed!\n");
346 else
347 printf("OK.\n");
348 }
349
350 return ret;
351}