diff options
author | Yinghai Lu <yinghai.lu@amd.com> | 2007-01-22 20:21:17 +0000 |
---|---|---|
committer | Uwe Hermann <uwe@hermann-uwe.de> | 2007-01-22 20:21:17 +0000 |
commit | c33cf4c3ad2bc23452db3ab4423745a13a2ba9f6 (patch) | |
tree | ed5db734462798ef86522fe09fe36fd10389d12b | |
parent | e03a512a3b3eba811ad963c0b9f96b311d7a7b12 (diff) | |
download | flashrom-c33cf4c3ad2bc23452db3ab4423745a13a2ba9f6.zip flashrom-c33cf4c3ad2bc23452db3ab4423745a13a2ba9f6.tar.gz |
Add support for the SST-49LF004C, SST-49LF008C, SST-49LF016C Also add suport for NVIDIA MCP55
Corresponding to flashrom svn r85 and coreboot v2 svn r2537.
Signed-off-by: Yinghai Lu <yinghai.lu@amd.com>
Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
Acked-by: Peter Stuge <peter@stuge.se>
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | README | 4 | ||||
-rw-r--r-- | flash.h | 3 | ||||
-rw-r--r-- | flash_enable.c | 44 | ||||
-rw-r--r-- | flashchips.c | 7 | ||||
-rw-r--r-- | sst49lfxxxc.c | 204 | ||||
-rw-r--r-- | sst49lfxxxc.h | 8 |
7 files changed, 272 insertions, 1 deletions
@@ -17,7 +17,8 @@ LDFLAGS = -lpci -lz -static OBJS = flash_enable.o udelay.o jedec.o sst28sf040.o am29f040b.o mx29f002.o \ sst39sf020.o m29f400bt.o w49f002u.o 82802ab.o msys_doc.o pm49fl004.o \ - sst49lf040.o sst_fwhub.o layout.o lbtable.o flashchips.o flash_rom.o sharplhf00l04.o + sst49lf040.o sst49lfxxxc.o sst_fwhub.o layout.o lbtable.o \ + flashchips.o flash_rom.o sharplhf00l04.o all: pciutils dep $(PROGRAM) @@ -114,6 +114,9 @@ SST SST-49LF002A/B SST SST-49LF003A/B SST SST-49LF004A/B SST SST-49LF008A +SST SST-49LF004C +SST SST-49LF008C +SST SST-49LF016C ST ST-M29F400BT ST ST-M29F040B SyncMOS S29C51001T/B @@ -140,6 +143,7 @@ Intel ICH0-ICH8 (all variations) Intel PIIX4/PIIX4E/PIIX4M NVIDIA CK804 NVIDIA MCP51 +NVIDIA MCP55 SiS 630 SiS 5595 VIA VT8231 @@ -56,6 +56,9 @@ extern struct flashchip flashchips[]; #define SST_49LF003A 0x1B /* SST 49LF003A device */ #define SST_49LF004A 0x60 /* SST 49LF004A device */ #define SST_49LF008A 0x5A /* SST 49LF008A device */ +#define SST_49LF004C 0x54 /* SST 49LF004C device */ +#define SST_49LF008C 0x59 /* SST 49LF008C device */ +#define SST_49LF016C 0x5C /* SST 49LF016C device */ #define PMC_ID 0x9D /* PMC Manufacturer ID code */ #define PMC_49FL002 0x6D /* PMC 49FL002 device code */ diff --git a/flash_enable.c b/flash_enable.c index 901144c..652fbcd 100644 --- a/flash_enable.c +++ b/flash_enable.c @@ -391,6 +391,46 @@ static int enable_flash_sb400(struct pci_dev *dev, char *name) return 0; } +//By yhlu +static int enable_flash_mcp55(struct pci_dev *dev, char *name) +{ + /* register 4e.b gets or'ed with one */ + unsigned char old, new, byte; + unsigned short word; + + /* if it fails, it fails. There are so many variations of broken mobos + * that it is hard to argue that we should quit at this point. + */ + + //dump_pci_device(dev); + + /* Set the 4MB enable bit bit */ + byte = pci_read_byte(dev, 0x88); + byte |= 0xff; //256K + pci_write_byte(dev, 0x88, byte); + byte = pci_read_byte(dev, 0x8c); + byte |= 0xff; //1M + pci_write_byte(dev, 0x8c, byte); + word = pci_read_word(dev, 0x90); + word |= 0x7fff; //15M + pci_write_word(dev, 0x90, word); + + old = pci_read_byte(dev, 0x6d); + new = old | 0x01; + if (new == old) + return 0; + pci_write_byte(dev, 0x6d, new); + + if (pci_read_byte(dev, 0x6d) != new) { + printf("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", + 0x6d, new, name); + return -1; + } + + return 0; + +} + typedef struct penable { unsigned short vendor, device; char *name; @@ -432,9 +472,13 @@ static FLASH_ENABLE enables[] = { {0x10de, 0x0260, "NVidia MCP51", enable_flash_ck804}, {0x10de, 0x0261, "NVidia MCP51", enable_flash_ck804}, + // {0x10de, 0x0261, "NVIDIA C51", enable_flash_ck804}, // YHLU {0x10de, 0x0262, "NVidia MCP51", enable_flash_ck804}, {0x10de, 0x0263, "NVidia MCP51", enable_flash_ck804}, + {0x10de, 0x0364, "NVIDIA MCP55", enable_flash_mcp55}, // LPC + {0x10de, 0x0367, "NVIDIA MCP55", enable_flash_mcp55}, // Pro + {0x1002, 0x4377, "ATI SB400", enable_flash_sb400}, // ATI Technologies Inc IXP SB400 PCI-ISA Bridge (rev 80) }; diff --git a/flashchips.c b/flashchips.c index e2a9173..541da09 100644 --- a/flashchips.c +++ b/flashchips.c @@ -31,6 +31,7 @@ #endif #include "am29f040b.h" #include "sst28sf040.h" +#include "sst49lfxxxc.h" #include "w49f002u.h" #include "sst39sf020.h" #include "sst49lf040.h" @@ -82,6 +83,12 @@ struct flashchip flashchips[] = { probe_sst_fwhub, erase_sst_fwhub, write_sst_fwhub, NULL}, {"Pm49FL002", PMC_ID, PMC_49FL002, NULL, 256, 16 * 1024, probe_jedec, erase_chip_jedec, write_49fl004,NULL}, + {"SST49LF004C", SST_ID, SST_49LF004C, NULL, 512, 4 * 1024, + probe_49lfxxxc, erase_49lfxxxc, write_49lfxxxc,NULL}, + {"SST49LF008C", SST_ID, SST_49LF008C, NULL, 1024, 4 * 1024 , + probe_49lfxxxc, erase_49lfxxxc, write_49lfxxxc, NULL}, + {"SST49LF016C", SST_ID, SST_49LF016C, NULL, 2048, 4 * 1024 , + probe_49lfxxxc, erase_49lfxxxc, write_49lfxxxc, NULL}, {"Pm49FL004", PMC_ID, PMC_49FL004, NULL, 512, 64 * 1024, probe_jedec, erase_chip_jedec, write_49fl004,NULL}, {"W29C011", WINBOND_ID, W_29C011, NULL, 128, 128, diff --git a/sst49lfxxxc.c b/sst49lfxxxc.c new file mode 100644 index 0000000..cd29d0b --- /dev/null +++ b/sst49lfxxxc.c @@ -0,0 +1,204 @@ +/* + * 49lfxxxc.c: driver for SST49LFXXXC flash models. + * + * + * Copyright 2000 Silicon Integrated System Corporation + * Copyright 2005 coresystems GmbH <stepan@openbios.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Reference: + * SST49LFxxxC data sheets + * + */ + +#include <errno.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/io.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include "flash.h" +#include "jedec.h" +#include "debug.h" + +#define SECTOR_ERASE 0x30 +#define BLOCK_ERASE 0x20 +#define ERASE 0xD0 +#define AUTO_PGRM 0x10 +#define RESET 0xFF +#define READ_ID 0x90 +#define READ_STATUS 0x70 +#define CLEAR_STATUS 0x50 + +#define STATUS_BPS (1 << 1) +#define STATUS_ESS (1 << 6) +#define STATUS_WSMS (1 << 7) + + +static __inline__ int write_lockbits_49lfxxxc(volatile uint8_t *bios, int size, + unsigned char bits) +{ + int i, left = size; + unsigned long address; + + //printf("bios=0x%08lx\n", (unsigned long)bios); + for (i = 0; left > 65536; i++, left -= 65536) { + //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFC00000 - size + (i * 65536) + 2, *(bios + (i * 65536) + 2) ); + *(bios + (i * 65536) + 2) = bits; + } + address = i * 65536; + //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) ); + *(bios + address + 2) = bits; + address += 32768; + //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) ); + *(bios + address + 2) = bits; + address += 8192; + //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) ); + *(bios + address + 2) = bits; + address += 8192; + //printf("lockbits at address=0x%08lx is 0x%01x\n", (unsigned long)0xFFc00000 - size + address + 2, *(bios + address + 2) ); + *(bios + address + 2) = bits; + + + return (0); +} + +static __inline__ int erase_sector_49lfxxxc(volatile uint8_t *bios, + unsigned long address) +{ + unsigned char status; + + *bios = SECTOR_ERASE; + *(bios + address) = ERASE; + + do { + status = *bios; + if (status & (STATUS_ESS | STATUS_BPS)) { + printf("sector erase FAILED at address=0x%08lx status=0x%01x\n", (unsigned long)bios + address, status); + *bios = CLEAR_STATUS; + return(-1); + } + } while (!(status & STATUS_WSMS)); + + return (0); +} + +static __inline__ int write_sector_49lfxxxc(volatile uint8_t *bios, + uint8_t *src, + volatile uint8_t *dst, + unsigned int page_size) +{ + int i; + unsigned char status; + + *bios = CLEAR_STATUS; + for (i = 0; i < page_size; i++) { + /* transfer data from source to destination */ + if (*src == 0xFF) { + dst++, src++; + /* If the data is 0xFF, don't program it */ + continue; + } + /*issue AUTO PROGRAM command */ + *bios = AUTO_PGRM; + *dst++ = *src++; + + do { + status = *bios; + if (status & (STATUS_ESS | STATUS_BPS)) { + printf("sector write FAILED at address=0x%08lx status=0x%01x\n", (unsigned long)dst, status); + *bios = CLEAR_STATUS; + return(-1); + } + } while (!(status & STATUS_WSMS)); + } + + return (0); +} + +int probe_49lfxxxc(struct flashchip *flash) +{ + volatile uint8_t *bios = flash->virt_addr; + uint8_t id1, id2; + size_t size = flash->total_size * 1024; + + *bios = RESET; + + *bios = READ_ID; + id1 = *(volatile uint8_t *) bios; + id2 = *(volatile uint8_t *) (bios + 0x01); + + *bios = RESET; + + printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2); + if (!(id1 == flash->manufacture_id && id2 == flash->model_id)) + return 0; + + bios = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED, + flash->fd_mem, (off_t) (0xFFFFFFFF - 0x400000 - size + 1)); + if (bios == MAP_FAILED) { + // it's this part but we can't map it ... + perror("Error MMAP /dev/mem"); + exit(1); + } + flash->virt_addr_2 = bios; + return 1; +} + +int erase_49lfxxxc(struct flashchip *flash) +{ + volatile uint8_t *bios = flash->virt_addr; + volatile uint8_t *bios2 = flash->virt_addr_2; + int i; + unsigned int total_size = flash->total_size * 1024; + + write_lockbits_49lfxxxc(bios2, total_size, 0); + for (i = 0; i < total_size; i += flash->page_size) + if (erase_sector_49lfxxxc(bios, i) != 0 ) + return (-1); + + *bios = RESET; + return (0); +} + +int write_49lfxxxc(struct flashchip *flash, uint8_t *buf) +{ + int i; + int total_size = flash->total_size * 1024, page_size = + flash->page_size; + volatile uint8_t *bios = flash->virt_addr; + + + write_lockbits_49lfxxxc(flash->virt_addr_2, total_size, 0); + printf("Programming Page: "); + for (i = 0; i < total_size / page_size; i++) { + /* erase the page before programming */ + erase_sector_49lfxxxc(bios, i * page_size); + + /* write to the sector */ + printf("%04d at address: 0x%08x", i, i * page_size); + write_sector_49lfxxxc(bios, buf + i * page_size, + bios + i * page_size, page_size); + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + } + printf("\n"); + + *bios = RESET; + return (0); +} diff --git a/sst49lfxxxc.h b/sst49lfxxxc.h new file mode 100644 index 0000000..8768b1f --- /dev/null +++ b/sst49lfxxxc.h @@ -0,0 +1,8 @@ +#ifndef __SST49LFXXXC_H__ +#define __SST49LFXXXC_H__ + +extern int probe_49lfxxxc(struct flashchip *flash); +extern int erase_49lfxxxc(struct flashchip *flash); +extern int write_49lfxxxc(struct flashchip *flash, uint8_t *buf); + +#endif /* !__SST49LFXXXC_H__ */ |