blob: 87929f58f4c2f838ae3d02d4fa5d6772007b3448 [file] [log] [blame]
Ollie Lho184a4042005-11-26 21:55:36 +00001/*
Uwe Hermannd1107642007-08-29 17:52:32 +00002 * This file is part of the flashrom project.
Ollie Lho184a4042005-11-26 21:55:36 +00003 *
Uwe Hermannd1107642007-08-29 17:52:32 +00004 * Copyright (C) 2000 Silicon Integrated System Corporation
5 * Copyright (C) 2005-2007 coresystems GmbH <stepan@coresystems.de>
6 * Copyright (C) 2006 Uwe Hermann <uwe@hermann-uwe.de>
Ollie Lho184a4042005-11-26 21:55:36 +00007 *
Uwe Hermannd1107642007-08-29 17:52:32 +00008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
Ollie Lho184a4042005-11-26 21:55:36 +000011 *
Uwe Hermannd1107642007-08-29 17:52:32 +000012 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22/*
23 * Contains the chipset specific flash enables.
Ollie Lho184a4042005-11-26 21:55:36 +000024 */
25
Lane Brooksd54958a2007-11-13 16:45:22 +000026#define _LARGEFILE64_SOURCE
27
Ollie Lhocbbf1252004-03-17 22:22:08 +000028#include <stdio.h>
29#include <pci/pci.h>
30#include <stdlib.h>
Lane Brooksd54958a2007-11-13 16:45:22 +000031#include <sys/types.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <unistd.h>
Luc Verhaegen8e3a6002007-04-04 22:45:58 +000035#include "flash.h"
Stefan Reinauer86de2832006-03-31 11:26:55 +000036
Luc Verhaegen6b141752007-05-20 16:16:13 +000037static int enable_flash_ali_m1533(struct pci_dev *dev, char *name)
38{
39 uint8_t tmp;
40
41 /* ROM Write enable, 0xFFFC0000-0xFFFDFFFF and
42 0xFFFE0000-0xFFFFFFFF ROM select enable. */
43 tmp = pci_read_byte(dev, 0x47);
44 tmp |= 0x46;
45 pci_write_byte(dev, 0x47, tmp);
46
47 return 0;
48}
49
Ollie Lho761bf1b2004-03-20 16:46:10 +000050static int enable_flash_sis630(struct pci_dev *dev, char *name)
Ollie Lhocbbf1252004-03-17 22:22:08 +000051{
52 char b;
53
Ollie Lhocbbf1252004-03-17 22:22:08 +000054 /* Enable 0xFFF8000~0xFFFF0000 decoding on SiS 540/630 */
Alex Beregszaszic9fb5d92007-09-11 15:58:18 +000055 b = pci_read_byte(dev, 0x40);
56 pci_write_byte(dev, 0x40, b | 0xb);
Ollie Lhocbbf1252004-03-17 22:22:08 +000057 /* Flash write enable on SiS 540/630 */
Alex Beregszaszic9fb5d92007-09-11 15:58:18 +000058 b = pci_read_byte(dev, 0x45);
59 pci_write_byte(dev, 0x45, b | 0x40);
Ollie Lhocbbf1252004-03-17 22:22:08 +000060
61 /* The same thing on SiS 950 SuperIO side */
62 outb(0x87, 0x2e);
63 outb(0x01, 0x2e);
64 outb(0x55, 0x2e);
65 outb(0x55, 0x2e);
66
67 if (inb(0x2f) != 0x87) {
68 outb(0x87, 0x4e);
69 outb(0x01, 0x4e);
70 outb(0x55, 0x4e);
71 outb(0xaa, 0x4e);
72 if (inb(0x4f) != 0x87) {
73 printf("Can not access SiS 950\n");
74 return -1;
75 }
76 outb(0x24, 0x4e);
77 b = inb(0x4f) | 0xfc;
78 outb(0x24, 0x4e);
79 outb(b, 0x4f);
80 outb(0x02, 0x4e);
Ollie Lho761bf1b2004-03-20 16:46:10 +000081 outb(0x02, 0x4f);
Ollie Lhocbbf1252004-03-17 22:22:08 +000082 }
83
84 outb(0x24, 0x2e);
85 printf("2f is %#x\n", inb(0x2f));
86 b = inb(0x2f) | 0xfc;
87 outb(0x24, 0x2e);
88 outb(b, 0x2f);
89
90 outb(0x02, 0x2e);
91 outb(0x02, 0x2f);
92
93 return 0;
94}
95
Uwe Hermann987942d2006-11-07 11:16:21 +000096/* Datasheet:
97 * - Name: 82371AB PCI-TO-ISA / IDE XCELERATOR (PIIX4)
98 * - URL: http://www.intel.com/design/intarch/datashts/290562.htm
99 * - PDF: http://www.intel.com/design/intarch/datashts/29056201.pdf
100 * - Order Number: 290562-001
101 */
Uwe Hermannea2c66d2006-11-05 18:26:08 +0000102static int enable_flash_piix4(struct pci_dev *dev, char *name)
103{
104 uint16_t old, new;
Uwe Hermanna7e05482007-05-09 10:17:44 +0000105 uint16_t xbcs = 0x4e; /* X-Bus Chip Select register. */
Uwe Hermannea2c66d2006-11-05 18:26:08 +0000106
107 old = pci_read_word(dev, xbcs);
108
109 /* Set bit 9: 1-Meg Extended BIOS Enable (PCI master accesses to
Uwe Hermanna7e05482007-05-09 10:17:44 +0000110 * FFF00000-FFF7FFFF are forwarded to ISA).
111 * Set bit 7: Extended BIOS Enable (PCI master accesses to
112 * FFF80000-FFFDFFFF are forwarded to ISA).
113 * Set bit 6: Lower BIOS Enable (PCI master, or ISA master accesses to
114 * the lower 64-Kbyte BIOS block (E0000-EFFFF) at the top
115 * of 1 Mbyte, or the aliases at the top of 4 Gbyte
116 * (FFFE0000-FFFEFFFF) result in the generation of BIOSCS#.
117 * Note: Accesses to FFFF0000-FFFFFFFF are always forwarded to ISA.
118 * Set bit 2: BIOSCS# Write Enable (1=enable, 0=disable).
119 */
Uwe Hermannea2c66d2006-11-05 18:26:08 +0000120 new = old | 0x2c4;
121
122 if (new == old)
123 return 0;
124
125 pci_write_word(dev, xbcs, new);
126
127 if (pci_read_word(dev, xbcs) != new) {
128 printf("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", xbcs, new, name);
129 return -1;
130 }
Uwe Hermannffec5f32007-08-23 16:08:21 +0000131
Uwe Hermannea2c66d2006-11-05 18:26:08 +0000132 return 0;
133}
134
Stefan Reinauer86de2832006-03-31 11:26:55 +0000135static int enable_flash_ich(struct pci_dev *dev, char *name, int bios_cntl)
Ronald G. Minnich6a967412004-09-28 20:09:06 +0000136{
137 /* register 4e.b gets or'ed with one */
Ollie Lho184a4042005-11-26 21:55:36 +0000138 uint8_t old, new;
Stefan Reinauereb366472006-09-06 15:48:48 +0000139
Ronald G. Minnich6a967412004-09-28 20:09:06 +0000140 /* if it fails, it fails. There are so many variations of broken mobos
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000141 * that it is hard to argue that we should quit at this point.
Ronald G. Minnich6a967412004-09-28 20:09:06 +0000142 */
143
Stefan Reinauereb366472006-09-06 15:48:48 +0000144 /* Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, but
Uwe Hermanna7e05482007-05-09 10:17:44 +0000145 * just treating it as 8 bit wide seems to work fine in practice.
Stefan Reinauereb366472006-09-06 15:48:48 +0000146 */
147
148 /* see ie. page 375 of "Intel ICH7 External Design Specification"
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000149 * http://download.intel.com/design/chipsets/datashts/30701302.pdf
Stefan Reinauereb366472006-09-06 15:48:48 +0000150 */
151
Stefan Reinauer86de2832006-03-31 11:26:55 +0000152 old = pci_read_byte(dev, bios_cntl);
Ronald G. Minnich6a967412004-09-28 20:09:06 +0000153
154 new = old | 1;
155
156 if (new == old)
157 return 0;
158
Stefan Reinauer86de2832006-03-31 11:26:55 +0000159 pci_write_byte(dev, bios_cntl, new);
Ronald G. Minnich6a967412004-09-28 20:09:06 +0000160
Stefan Reinauer86de2832006-03-31 11:26:55 +0000161 if (pci_read_byte(dev, bios_cntl) != new) {
Uwe Hermanna7e05482007-05-09 10:17:44 +0000162 printf("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", bios_cntl, new, name);
Ronald G. Minnich6a967412004-09-28 20:09:06 +0000163 return -1;
164 }
Uwe Hermannffec5f32007-08-23 16:08:21 +0000165
Ronald G. Minnich6a967412004-09-28 20:09:06 +0000166 return 0;
167}
168
Stefan Reinauereb366472006-09-06 15:48:48 +0000169static int enable_flash_ich_4e(struct pci_dev *dev, char *name)
Stefan Reinauer86de2832006-03-31 11:26:55 +0000170{
Stefan Reinauereb366472006-09-06 15:48:48 +0000171 return enable_flash_ich(dev, name, 0x4e);
Stefan Reinauer86de2832006-03-31 11:26:55 +0000172}
173
Stefan Reinauereb366472006-09-06 15:48:48 +0000174static int enable_flash_ich_dc(struct pci_dev *dev, char *name)
Stefan Reinauer86de2832006-03-31 11:26:55 +0000175{
Stefan Reinauereb366472006-09-06 15:48:48 +0000176 return enable_flash_ich(dev, name, 0xdc);
Stefan Reinauer86de2832006-03-31 11:26:55 +0000177}
178
Uwe Hermanna7e05482007-05-09 10:17:44 +0000179static int enable_flash_vt823x(struct pci_dev *dev, char *name)
Ollie Lhocbbf1252004-03-17 22:22:08 +0000180{
Ollie Lho184a4042005-11-26 21:55:36 +0000181 uint8_t val;
Ollie Lho761bf1b2004-03-20 16:46:10 +0000182
Uwe Hermannffec5f32007-08-23 16:08:21 +0000183 /* ROM write enable */
Ollie Lhocbbf1252004-03-17 22:22:08 +0000184 val = pci_read_byte(dev, 0x40);
185 val |= 0x10;
186 pci_write_byte(dev, 0x40, val);
187
188 if (pci_read_byte(dev, 0x40) != val) {
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000189 printf("\nWARNING: Failed to enable ROM Write on \"%s\"\n",
Uwe Hermanna7e05482007-05-09 10:17:44 +0000190 name);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000191 return -1;
Ollie Lhocbbf1252004-03-17 22:22:08 +0000192 }
Luc Verhaegen6382b442007-03-02 22:16:38 +0000193
Uwe Hermanna7e05482007-05-09 10:17:44 +0000194 return 0;
Ollie Lhocbbf1252004-03-17 22:22:08 +0000195}
196
197static int enable_flash_cs5530(struct pci_dev *dev, char *name)
198{
Uwe Hermannf4a673b2007-06-06 21:35:45 +0000199 uint8_t reg8;
Ollie Lho761bf1b2004-03-20 16:46:10 +0000200
Uwe Hermannf4a673b2007-06-06 21:35:45 +0000201 #define DECODE_CONTROL_REG2 0x5b /* F0 index 0x5b */
202 #define ROM_AT_LOGIC_CONTROL_REG 0x52 /* F0 index 0x52 */
Ollie Lhocbbf1252004-03-17 22:22:08 +0000203
Uwe Hermannf4a673b2007-06-06 21:35:45 +0000204 #define LOWER_ROM_ADDRESS_RANGE (1 << 0)
205 #define ROM_WRITE_ENABLE (1 << 1)
206 #define UPPER_ROM_ADDRESS_RANGE (1 << 2)
207 #define BIOS_ROM_POSITIVE_DECODE (1 << 5)
Ollie Lhocbbf1252004-03-17 22:22:08 +0000208
Uwe Hermannf4a673b2007-06-06 21:35:45 +0000209 /* Decode 0x000E0000-0x000FFFFF (128 KB), not just 64 KB, and
210 * decode 0xFF000000-0xFFFFFFFF (16 MB), not just 256 KB.
211 * Make the configured ROM areas writable.
212 */
213 reg8 = pci_read_byte(dev, ROM_AT_LOGIC_CONTROL_REG);
214 reg8 |= LOWER_ROM_ADDRESS_RANGE;
215 reg8 |= UPPER_ROM_ADDRESS_RANGE;
216 reg8 |= ROM_WRITE_ENABLE;
217 pci_write_byte(dev, ROM_AT_LOGIC_CONTROL_REG, reg8);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000218
Uwe Hermannf4a673b2007-06-06 21:35:45 +0000219 /* Set positive decode on ROM. */
220 reg8 = pci_read_byte(dev, DECODE_CONTROL_REG2);
221 reg8 |= BIOS_ROM_POSITIVE_DECODE;
222 pci_write_byte(dev, DECODE_CONTROL_REG2, reg8);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000223
Ollie Lhocbbf1252004-03-17 22:22:08 +0000224 return 0;
225}
226
Lane Brooksd54958a2007-11-13 16:45:22 +0000227static int enable_flash_cs5536(struct pci_dev *dev, char *name)
228{
229 int fd_msr;
230 unsigned char buf[8];
231 unsigned int addr = 0x1808;
232
233 /* Geode systems write protect the BIOS via RCONFs (cache
234 * settings similar to MTRRs). To unlock, change MSR 0x1808
235 * top byte to 0x22. Reading and writing to msr, however
236 * requires instrucitons rdmsr/wrmsr, which are ring0 privileged
237 * instructions so only the kernel can do the read/write. This
238 * function, therefore, requires that the msr kernel module be
239 * loaded to access these instructions from user space using
240 * device /dev/cpu/0/msr. This hard-coded driver location
241 * could have potential problems on SMP machines since it
242 * assumes cpu0, but it is safe on the geode which is not SMP.
243 *
244 * This is probably not portable beyond linux.
245 */
246
247 fd_msr = open("/dev/cpu/0/msr", O_RDONLY);
248 if (!fd_msr) {
249 perror("open msr");
250 return -1;
251 }
252 lseek64(fd_msr, (off64_t) addr, SEEK_SET);
253 read(fd_msr, buf, 8);
254 close(fd_msr);
255 if (buf[7] != 0x22) {
256 printf("Enabling Geode MSR to write to flash.\n");
257 buf[7] = 0x22;
258 fd_msr = open("/dev/cpu/0/msr", O_WRONLY);
259 if (!fd_msr) {
260 perror("open msr");
261 return -1;
262 }
263 lseek64(fd_msr, (off64_t) addr, SEEK_SET);
264 if (write(fd_msr, buf, 8) < 0) {
265 perror("msr write");
266 printf
267 ("Cannot write to MSR. Make sure msr kernel is loaded: 'modprobe msr'\n");
268 return -1;
269 }
270 close(fd_msr);
271 }
272 return 0;
273}
274
Ollie Lhocbbf1252004-03-17 22:22:08 +0000275static int enable_flash_sc1100(struct pci_dev *dev, char *name)
276{
Ollie Lho184a4042005-11-26 21:55:36 +0000277 uint8_t new;
Ollie Lho761bf1b2004-03-20 16:46:10 +0000278
Ollie Lhocbbf1252004-03-17 22:22:08 +0000279 pci_write_byte(dev, 0x52, 0xee);
280
281 new = pci_read_byte(dev, 0x52);
282
283 if (new != 0xee) {
Uwe Hermanna7e05482007-05-09 10:17:44 +0000284 printf("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x52, new, name);
Ollie Lhocbbf1252004-03-17 22:22:08 +0000285 return -1;
286 }
Uwe Hermannffec5f32007-08-23 16:08:21 +0000287
Ollie Lhocbbf1252004-03-17 22:22:08 +0000288 return 0;
289}
290
291static int enable_flash_sis5595(struct pci_dev *dev, char *name)
292{
Ollie Lho184a4042005-11-26 21:55:36 +0000293 uint8_t new, newer;
Ollie Lho761bf1b2004-03-20 16:46:10 +0000294
Ollie Lhocbbf1252004-03-17 22:22:08 +0000295 new = pci_read_byte(dev, 0x45);
296
297 /* clear bit 5 */
Ollie Lho761bf1b2004-03-20 16:46:10 +0000298 new &= (~0x20);
Ollie Lhocbbf1252004-03-17 22:22:08 +0000299 /* set bit 2 */
300 new |= 0x4;
301
302 pci_write_byte(dev, 0x45, new);
303
304 newer = pci_read_byte(dev, 0x45);
305 if (newer != new) {
Uwe Hermanna7e05482007-05-09 10:17:44 +0000306 printf("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x45, new, name);
Ollie Lhocbbf1252004-03-17 22:22:08 +0000307 printf("Stuck at 0x%x\n", newer);
308 return -1;
309 }
Uwe Hermannffec5f32007-08-23 16:08:21 +0000310
Ollie Lhocbbf1252004-03-17 22:22:08 +0000311 return 0;
312}
313
Ollie Lho761bf1b2004-03-20 16:46:10 +0000314static int enable_flash_amd8111(struct pci_dev *dev, char *name)
315{
Ollie Lhocbbf1252004-03-17 22:22:08 +0000316 /* register 4e.b gets or'ed with one */
Ollie Lho184a4042005-11-26 21:55:36 +0000317 uint8_t old, new;
Uwe Hermanna7e05482007-05-09 10:17:44 +0000318
Ollie Lhocbbf1252004-03-17 22:22:08 +0000319 /* if it fails, it fails. There are so many variations of broken mobos
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000320 * that it is hard to argue that we should quit at this point.
Ollie Lhocbbf1252004-03-17 22:22:08 +0000321 */
322
Ollie Lhod11f3612004-12-07 17:19:04 +0000323 /* enable decoding at 0xffb00000 to 0xffffffff */
Ollie Lhocbbf1252004-03-17 22:22:08 +0000324 old = pci_read_byte(dev, 0x43);
Ollie Lhod11f3612004-12-07 17:19:04 +0000325 new = old | 0xC0;
Ollie Lhocbbf1252004-03-17 22:22:08 +0000326 if (new != old) {
327 pci_write_byte(dev, 0x43, new);
328 if (pci_read_byte(dev, 0x43) != new) {
Uwe Hermanna7e05482007-05-09 10:17:44 +0000329 printf("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x43, new, name);
Ollie Lhocbbf1252004-03-17 22:22:08 +0000330 }
331 }
332
Ollie Lho761bf1b2004-03-20 16:46:10 +0000333 old = pci_read_byte(dev, 0x40);
Ollie Lhocbbf1252004-03-17 22:22:08 +0000334 new = old | 0x01;
335 if (new == old)
336 return 0;
337 pci_write_byte(dev, 0x40, new);
338
339 if (pci_read_byte(dev, 0x40) != new) {
Uwe Hermanna7e05482007-05-09 10:17:44 +0000340 printf("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x40, new, name);
Ollie Lhocbbf1252004-03-17 22:22:08 +0000341 return -1;
342 }
Uwe Hermannffec5f32007-08-23 16:08:21 +0000343
Ollie Lhocbbf1252004-03-17 22:22:08 +0000344 return 0;
345}
346
Yinghai Lu952dfce2005-07-06 17:13:46 +0000347static int enable_flash_ck804(struct pci_dev *dev, char *name)
348{
Uwe Hermanna7e05482007-05-09 10:17:44 +0000349 /* register 4e.b gets or'ed with one */
350 uint8_t old, new;
Yinghai Lu952dfce2005-07-06 17:13:46 +0000351
Uwe Hermanna7e05482007-05-09 10:17:44 +0000352 /* if it fails, it fails. There are so many variations of broken mobos
353 * that it is hard to argue that we should quit at this point.
354 */
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000355
Uwe Hermanna7e05482007-05-09 10:17:44 +0000356 /* dump_pci_device(dev); */
Yinghai Lu952dfce2005-07-06 17:13:46 +0000357
Uwe Hermanna7e05482007-05-09 10:17:44 +0000358 old = pci_read_byte(dev, 0x88);
359 new = old | 0xc0;
360 if (new != old) {
361 pci_write_byte(dev, 0x88, new);
362 if (pci_read_byte(dev, 0x88) != new) {
363 printf("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x88, new, name);
364 }
365 }
Yinghai Lu952dfce2005-07-06 17:13:46 +0000366
Uwe Hermanna7e05482007-05-09 10:17:44 +0000367 old = pci_read_byte(dev, 0x6d);
368 new = old | 0x01;
369 if (new == old)
370 return 0;
371 pci_write_byte(dev, 0x6d, new);
372
373 if (pci_read_byte(dev, 0x6d) != new) {
374 printf("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x6d, new, name);
375 return -1;
376 }
Uwe Hermannffec5f32007-08-23 16:08:21 +0000377
Uwe Hermanna7e05482007-05-09 10:17:44 +0000378 return 0;
Yinghai Lu952dfce2005-07-06 17:13:46 +0000379}
380
Stefan Reinauer86de2832006-03-31 11:26:55 +0000381static int enable_flash_sb400(struct pci_dev *dev, char *name)
382{
Uwe Hermanna7e05482007-05-09 10:17:44 +0000383 uint8_t tmp;
Stefan Reinauer86de2832006-03-31 11:26:55 +0000384
385 struct pci_filter f;
386 struct pci_dev *smbusdev;
387
Stefan Reinauer86de2832006-03-31 11:26:55 +0000388 /* then look for the smbus device */
Uwe Hermanna7e05482007-05-09 10:17:44 +0000389 pci_filter_init((struct pci_access *)0, &f);
Stefan Reinauer86de2832006-03-31 11:26:55 +0000390 f.vendor = 0x1002;
391 f.device = 0x4372;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000392
Stefan Reinauer86de2832006-03-31 11:26:55 +0000393 for (smbusdev = pacc->devices; smbusdev; smbusdev = smbusdev->next) {
394 if (pci_filter_match(&f, smbusdev)) {
395 break;
396 }
397 }
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000398
Uwe Hermanna7e05482007-05-09 10:17:44 +0000399 if (!smbusdev) {
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000400 fprintf(stderr, "ERROR: SMBus device not found. aborting\n");
Stefan Reinauer86de2832006-03-31 11:26:55 +0000401 exit(1);
402 }
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000403
404 /* enable some smbus stuff */
Uwe Hermanna7e05482007-05-09 10:17:44 +0000405 tmp = pci_read_byte(smbusdev, 0x79);
406 tmp |= 0x01;
Stefan Reinauer86de2832006-03-31 11:26:55 +0000407 pci_write_byte(smbusdev, 0x79, tmp);
408
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000409 /* change southbridge */
Uwe Hermanna7e05482007-05-09 10:17:44 +0000410 tmp = pci_read_byte(dev, 0x48);
411 tmp |= 0x21;
Stefan Reinauer86de2832006-03-31 11:26:55 +0000412 pci_write_byte(dev, 0x48, tmp);
413
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000414 /* now become a bit silly. */
Uwe Hermanna7e05482007-05-09 10:17:44 +0000415 tmp = inb(0xc6f);
Stefan Reinauer86de2832006-03-31 11:26:55 +0000416 outb(tmp, 0xeb);
Uwe Hermanna7e05482007-05-09 10:17:44 +0000417 outb(tmp, 0xeb);
418 tmp |= 0x40;
Stefan Reinauer86de2832006-03-31 11:26:55 +0000419 outb(tmp, 0xc6f);
420 outb(tmp, 0xeb);
421 outb(tmp, 0xeb);
422
423 return 0;
424}
425
Yinghai Luca782972007-01-22 20:21:17 +0000426static int enable_flash_mcp55(struct pci_dev *dev, char *name)
427{
Uwe Hermanna7e05482007-05-09 10:17:44 +0000428 /* register 4e.b gets or'ed with one */
429 unsigned char old, new, byte;
430 unsigned short word;
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000431
Uwe Hermanna7e05482007-05-09 10:17:44 +0000432 /* if it fails, it fails. There are so many variations of broken mobos
433 * that it is hard to argue that we should quit at this point.
434 */
Yinghai Luca782972007-01-22 20:21:17 +0000435
Uwe Hermanna7e05482007-05-09 10:17:44 +0000436 /* dump_pci_device(dev); */
Yinghai Luca782972007-01-22 20:21:17 +0000437
Carl-Daniel Hailfingerdca0ab12007-10-17 22:30:07 +0000438 /* Set the 0-16 MB enable bits */
Uwe Hermanna7e05482007-05-09 10:17:44 +0000439 byte = pci_read_byte(dev, 0x88);
440 byte |= 0xff; /* 256K */
441 pci_write_byte(dev, 0x88, byte);
442 byte = pci_read_byte(dev, 0x8c);
443 byte |= 0xff; /* 1M */
444 pci_write_byte(dev, 0x8c, byte);
445 word = pci_read_word(dev, 0x90);
Carl-Daniel Hailfingerdca0ab12007-10-17 22:30:07 +0000446 word |= 0x7fff; /* 16M */
Uwe Hermanna7e05482007-05-09 10:17:44 +0000447 pci_write_word(dev, 0x90, word);
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000448
Uwe Hermanna7e05482007-05-09 10:17:44 +0000449 old = pci_read_byte(dev, 0x6d);
450 new = old | 0x01;
451 if (new == old)
452 return 0;
453 pci_write_byte(dev, 0x6d, new);
Yinghai Luca782972007-01-22 20:21:17 +0000454
Uwe Hermanna7e05482007-05-09 10:17:44 +0000455 if (pci_read_byte(dev, 0x6d) != new) {
456 printf
457 ("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n",
458 0x6d, new, name);
459 return -1;
460 }
Yinghai Luca782972007-01-22 20:21:17 +0000461
462 return 0;
Yinghai Luca782972007-01-22 20:21:17 +0000463}
464
Stefan Reinauerc868b9e2007-06-05 10:28:39 +0000465static int enable_flash_ht1000(struct pci_dev *dev, char *name)
466{
Uwe Hermanne823ee02007-06-05 15:02:18 +0000467 uint8_t byte;
Stefan Reinauerc868b9e2007-06-05 10:28:39 +0000468
Uwe Hermanne823ee02007-06-05 15:02:18 +0000469 /* Set the 4MB enable bit. */
Stefan Reinauerc868b9e2007-06-05 10:28:39 +0000470 byte = pci_read_byte(dev, 0x41);
471 byte |= 0x0e;
472 pci_write_byte(dev, 0x41, byte);
473
474 byte = pci_read_byte(dev, 0x43);
Uwe Hermannffec5f32007-08-23 16:08:21 +0000475 byte |= (1 << 4);
Stefan Reinauerc868b9e2007-06-05 10:28:39 +0000476 pci_write_byte(dev, 0x43, byte);
477
Stefan Reinauerc868b9e2007-06-05 10:28:39 +0000478 return 0;
479}
480
Ollie Lhocbbf1252004-03-17 22:22:08 +0000481typedef struct penable {
Ollie Lho761bf1b2004-03-20 16:46:10 +0000482 unsigned short vendor, device;
Ollie Lhocbbf1252004-03-17 22:22:08 +0000483 char *name;
Ollie Lho761bf1b2004-03-20 16:46:10 +0000484 int (*doit) (struct pci_dev * dev, char *name);
Ollie Lhocbbf1252004-03-17 22:22:08 +0000485} FLASH_ENABLE;
486
487static FLASH_ENABLE enables[] = {
Stefan Reinauereb366472006-09-06 15:48:48 +0000488 {0x1039, 0x0630, "SIS630", enable_flash_sis630},
Uwe Hermannea2c66d2006-11-05 18:26:08 +0000489 {0x8086, 0x7110, "PIIX4/PIIX4E/PIIX4M", enable_flash_piix4},
Uwe Hermann97a64702007-10-30 00:56:50 +0000490 {0x8086, 0x7198, "Intel 440MX", enable_flash_piix4},
Stefan Reinauereb366472006-09-06 15:48:48 +0000491 {0x8086, 0x2410, "ICH", enable_flash_ich_4e},
492 {0x8086, 0x2420, "ICH0", enable_flash_ich_4e},
493 {0x8086, 0x2440, "ICH2", enable_flash_ich_4e},
494 {0x8086, 0x244c, "ICH2-M", enable_flash_ich_4e},
495 {0x8086, 0x2480, "ICH3-S", enable_flash_ich_4e},
496 {0x8086, 0x248c, "ICH3-M", enable_flash_ich_4e},
497 {0x8086, 0x24c0, "ICH4/ICH4-L", enable_flash_ich_4e},
498 {0x8086, 0x24cc, "ICH4-M", enable_flash_ich_4e},
499 {0x8086, 0x24d0, "ICH5/ICH5R", enable_flash_ich_4e},
500 {0x8086, 0x2640, "ICH6/ICH6R", enable_flash_ich_dc},
501 {0x8086, 0x2641, "ICH6-M", enable_flash_ich_dc},
Uwe Hermann3ad25182007-03-31 19:48:38 +0000502 {0x8086, 0x27b0, "ICH7DH", enable_flash_ich_dc},
Stefan Reinauereb366472006-09-06 15:48:48 +0000503 {0x8086, 0x27b8, "ICH7/ICH7R", enable_flash_ich_dc},
504 {0x8086, 0x27b9, "ICH7M", enable_flash_ich_dc},
505 {0x8086, 0x27bd, "ICH7MDH", enable_flash_ich_dc},
506 {0x8086, 0x2810, "ICH8/ICH8R", enable_flash_ich_dc},
507 {0x8086, 0x2812, "ICH8DH", enable_flash_ich_dc},
508 {0x8086, 0x2814, "ICH8DO", enable_flash_ich_dc},
Luc Verhaegen6382b442007-03-02 22:16:38 +0000509 {0x1106, 0x8231, "VT8231", enable_flash_vt823x},
510 {0x1106, 0x3177, "VT8235", enable_flash_vt823x},
511 {0x1106, 0x3227, "VT8237", enable_flash_vt823x},
Uwe Hermanna7e05482007-05-09 10:17:44 +0000512 {0x1106, 0x8324, "CX700", enable_flash_vt823x},
Stefan Reinauerc6b5f492006-11-07 10:22:20 +0000513 {0x1106, 0x0686, "VT82C686", enable_flash_amd8111},
Uwe Hermannf4a673b2007-06-06 21:35:45 +0000514 {0x1078, 0x0100, "CS5530/CS5530A", enable_flash_cs5530},
Ollie Lho761bf1b2004-03-20 16:46:10 +0000515 {0x100b, 0x0510, "SC1100", enable_flash_sc1100},
Ollie Lhocbbf1252004-03-17 22:22:08 +0000516 {0x1039, 0x0008, "SIS5595", enable_flash_sis5595},
Lane Brooksd54958a2007-11-13 16:45:22 +0000517 {0x1022, 0x2080, "AMD GEODE CS5536", enable_flash_cs5536},
Ollie Lhocbbf1252004-03-17 22:22:08 +0000518 {0x1022, 0x7468, "AMD8111", enable_flash_amd8111},
Luc Verhaegen6b141752007-05-20 16:16:13 +0000519 {0x10B9, 0x1533, "ALi M1533", enable_flash_ali_m1533},
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000520 /* this fallthrough looks broken. */
Uwe Hermanna7e05482007-05-09 10:17:44 +0000521 {0x10de, 0x0050, "NVIDIA CK804", enable_flash_ck804}, /* LPC */
522 {0x10de, 0x0051, "NVIDIA CK804", enable_flash_ck804}, /* Pro */
523 {0x10de, 0x00d3, "NVIDIA CK804", enable_flash_ck804}, /* Slave, should not be here, to fix known bug for A01. */
Stefan Reinauer219b61e2006-10-14 21:04:49 +0000524
Uwe Hermanna7e05482007-05-09 10:17:44 +0000525 {0x10de, 0x0260, "NVidia MCP51", enable_flash_ck804},
526 {0x10de, 0x0261, "NVidia MCP51", enable_flash_ck804},
527 {0x10de, 0x0262, "NVidia MCP51", enable_flash_ck804},
528 {0x10de, 0x0263, "NVidia MCP51", enable_flash_ck804},
Stefan Reinauer219b61e2006-10-14 21:04:49 +0000529
Uwe Hermanna7e05482007-05-09 10:17:44 +0000530 {0x10de, 0x0360, "NVIDIA MCP55", enable_flash_mcp55}, /* Gigabyte m57sli-s4 */
531 {0x10de, 0x0361, "NVIDIA MCP55", enable_flash_mcp55}, /* LPC */
532 {0x10de, 0x0362, "NVIDIA MCP55", enable_flash_mcp55}, /* LPC */
533 {0x10de, 0x0363, "NVIDIA MCP55", enable_flash_mcp55}, /* LPC */
534 {0x10de, 0x0364, "NVIDIA MCP55", enable_flash_mcp55}, /* LPC */
535 {0x10de, 0x0365, "NVIDIA MCP55", enable_flash_mcp55}, /* LPC */
536 {0x10de, 0x0366, "NVIDIA MCP55", enable_flash_mcp55}, /* LPC */
537 {0x10de, 0x0367, "NVIDIA MCP55", enable_flash_mcp55}, /* Pro */
Yinghai Luca782972007-01-22 20:21:17 +0000538
Uwe Hermanna7e05482007-05-09 10:17:44 +0000539 {0x1002, 0x4377, "ATI SB400", enable_flash_sb400}, /* ATI Technologies Inc IXP SB400 PCI-ISA Bridge (rev 80) */
Stefan Reinauerc868b9e2007-06-05 10:28:39 +0000540
Uwe Hermanne823ee02007-06-05 15:02:18 +0000541 {0x1166, 0x0205, "Broadcom HT-1000", enable_flash_ht1000},
Ollie Lhocbbf1252004-03-17 22:22:08 +0000542};
Ollie Lho761bf1b2004-03-20 16:46:10 +0000543
Uwe Hermanna7e05482007-05-09 10:17:44 +0000544int chipset_flash_enable(void)
Ollie Lhocbbf1252004-03-17 22:22:08 +0000545{
Uwe Hermanna7e05482007-05-09 10:17:44 +0000546 struct pci_dev *dev = 0;
547 int ret = -2; /* nothing! */
548 int i;
Ollie Lhocbbf1252004-03-17 22:22:08 +0000549
Ollie Lhocbbf1252004-03-17 22:22:08 +0000550 /* now let's try to find the chipset we have ... */
Luc Verhaegen8e3a6002007-04-04 22:45:58 +0000551 for (i = 0; i < sizeof(enables) / sizeof(enables[0]); i++) {
Uwe Hermanna7e05482007-05-09 10:17:44 +0000552 dev = pci_dev_find(enables[i].vendor, enables[i].device);
553 if (dev)
554 break;
Ollie Lhocbbf1252004-03-17 22:22:08 +0000555 }
556
Uwe Hermanna7e05482007-05-09 10:17:44 +0000557 if (dev) {
Uwe Hermanna502dce2007-10-17 23:55:15 +0000558 printf("Found chipset \"%s\", enabling flash write... ",
Uwe Hermanna7e05482007-05-09 10:17:44 +0000559 enables[i].name);
560
561 ret = enables[i].doit(dev, enables[i].name);
562 if (ret)
Uwe Hermanna502dce2007-10-17 23:55:15 +0000563 printf("FAILED!\n");
Uwe Hermanna7e05482007-05-09 10:17:44 +0000564 else
Uwe Hermannac309342007-10-10 17:42:20 +0000565 printf("OK.\n");
Uwe Hermanna7e05482007-05-09 10:17:44 +0000566 }
567
568 return ret;
Ollie Lhocbbf1252004-03-17 22:22:08 +0000569}