From gerrit at coreboot.org Tue May 1 00:00:21 2012 From: gerrit at coreboot.org (Patrick Georgi (patrick@georgi-clan.de)) Date: Tue, 1 May 2012 00:00:21 +0200 Subject: [coreboot] New patch to review for coreboot: 88e6526 abuild: Add option to use binary files References: Message-ID: Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/958 -gerrit commit 88e65268cac4b433bc7dbd9b428d8b971f62b3df Author: Patrick Georgi Date: Mon Apr 30 22:55:28 2012 +0200 abuild: Add option to use binary files abuild -B enables the use of the blob repository. Change-Id: I2dd823d3b024ad249d72d668657bf6a6e92145cf Signed-off-by: Patrick Georgi --- util/abuild/abuild | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/util/abuild/abuild b/util/abuild/abuild index 5b8d73d..e514db6 100755 --- a/util/abuild/abuild +++ b/util/abuild/abuild @@ -218,6 +218,11 @@ function create_config echo "CONFIG_CCACHE=y" >> ${build_dir}/config.build fi + if [ "$enable_blobs" = "true" ]; then + printf "(blobs enabled) " + echo "CONFIG_USE_BLOBS=y" >> ${build_dir}/config.build + fi + if [ "$scanbuild" = "true" ]; then printf "(scan-build enabled) " echo "CONFIG_SCANBUILD_ENABLE=y" >> ${build_dir}/config.build @@ -534,6 +539,7 @@ function myhelp printf " [-l|--loglevel ] set loglevel\n" printf " [-u|--update] update existing image\n" printf " [-P|--prefix ] file name prefix in CBFS\n" + printf " [-B|--blobs] Allow using binary files\n" printf " [lbroot] absolute path to coreboot sources\n" printf " (defaults to $ROOT)\n\n" } @@ -571,7 +577,7 @@ getopt - > /dev/null 2>/dev/null || gcc -o util/abuild/getopt util/abuild/getopt getoptbrand="`getopt -V`" if [ "${getoptbrand:0:6}" == "getopt" ]; then # Detected GNU getopt that supports long options. - args=`getopt -l version,verbose,help,all,target:,payloads:,test,cpus:,silent,junit,xml,config,loglevel:,remove,prefix:,update,nostackprotect,scan-build,ccache -o Vvhat:p:Tc:sJxCl:rP:uy -- "$@"` + args=`getopt -l version,verbose,help,all,target:,payloads:,test,cpus:,silent,junit,xml,config,loglevel:,remove,prefix:,update,nostackprotect,scan-build,ccache,blobs -o Vvhat:p:Tc:sJxCl:rP:uyB -- "$@"` eval set -- $args else # Detected non-GNU getopt @@ -605,6 +611,7 @@ while true ; do -l|--loglevel) shift; loglevel="$1"; shift;; -u|--update) shift; update="true";; -P|--prefix) shift; cbfs_prefix="$1"; shift;; + -B|--blobs) shift; enable_blobs="true";; --) shift; break;; -*) printf "Invalid option\n\n"; myhelp; exit 1;; *) break;; From gerrit at coreboot.org Tue May 1 00:00:22 2012 From: gerrit at coreboot.org (Patrick Georgi (patrick@georgi-clan.de)) Date: Tue, 1 May 2012 00:00:22 +0200 Subject: [coreboot] New patch to review for coreboot: 63385c6 Make geode_lx use the vsa from blobs repository References: Message-ID: Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/959 -gerrit commit 63385c66126389fec8b6abc5923ec477442b360b Author: Patrick Georgi Date: Mon Apr 30 22:56:30 2012 +0200 Make geode_lx use the vsa from blobs repository ... or fail if repository is not enabled. Change-Id: I0a1e6d6fed852ec7edf96ace8346ae6b23838a56 Signed-off-by: Patrick Georgi --- src/cpu/amd/geode_lx/Kconfig | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/src/cpu/amd/geode_lx/Kconfig b/src/cpu/amd/geode_lx/Kconfig index e5462c6..777dc94 100644 --- a/src/cpu/amd/geode_lx/Kconfig +++ b/src/cpu/amd/geode_lx/Kconfig @@ -19,9 +19,11 @@ config GEODE_VSA bool default y select PCI_OPTION_ROM_RUN_REALMODE + select REQUIRES_BLOB config GEODE_VSA_FILE bool "Add a VSA image" + default y help Select this option if you have an AMD Geode LX vsa that you would like to add to your ROM. @@ -32,7 +34,7 @@ config GEODE_VSA_FILE config VSA_FILENAME string "AMD Geode LX VSA path and filename" depends on GEODE_VSA_FILE - default "gpl_vsa_lx_102.bin" + default "3rdparty/cpu/amd/geode_lx/gpl_vsa_lx_102.bin" help The path and filename of the file to use as VSA. From gerrit at coreboot.org Tue May 1 00:00:23 2012 From: gerrit at coreboot.org (Patrick Georgi (patrick@georgi-clan.de)) Date: Tue, 1 May 2012 00:00:23 +0200 Subject: [coreboot] New patch to review for coreboot: e6089c3 Add vsa processor to cbfs-files References: Message-ID: Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/960 -gerrit commit e6089c31deb1712509edd11c15081a4a189b325a Author: Patrick Georgi Date: Mon Apr 30 23:15:17 2012 +0200 Add vsa processor to cbfs-files Change-Id: I548e86084acc51b0471160d37439385f524224cf Signed-off-by: Patrick Georgi --- Makefile.inc | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Makefile.inc b/Makefile.inc index c179784..534b985 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -108,6 +108,14 @@ cbfs-files-processor-nvramtool= \ printf " CREATE $(2) (from $(1))\n"; $(objutil)/nvramtool/nvramtool -y $(src)/mainboard/$(MAINBOARDDIR)/cmos.layout -D $(2).tmp -p $(1) && mv $(2).tmp $(2)) ####################################################################### +# Link VSA binary to ELF-ish stage +# arg1: source file +# arg2: binary file name +cbfs-files-processor-vsa= \ + $(eval $(2): $(1) ; \ + printf " CREATE $(2) (from $(1))\n"; $(OBJCOPY) --set-start 0x20 --adjust-vma 0x60000 -I binary -O elf32-i386 -B i386 $(1) $(2).tmp && $(LD) -m elf_i386 -e 0x60020 --section-start .data=0x60000 $(2).tmp -o $(2)) + +####################################################################### # Add handler for arbitrary files in CBFS $(call add-special-class,cbfs-files) cbfs-files-handler= \ From gerrit at coreboot.org Tue May 1 00:00:23 2012 From: gerrit at coreboot.org (Patrick Georgi (patrick@georgi-clan.de)) Date: Tue, 1 May 2012 00:00:23 +0200 Subject: [coreboot] New patch to review for coreboot: 2558f47 Support adding stages with cbfs-files References: Message-ID: Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/961 -gerrit commit 2558f479d59042d9748ba931fa2436cc07faa933 Author: Patrick Georgi Date: Mon Apr 30 23:53:56 2012 +0200 Support adding stages with cbfs-files stages have special cbfstool syntax, which we need to support. Change-Id: I119255246af818f010acfc7ec2091a6184e74eb3 Signed-off-by: Patrick Georgi --- src/arch/x86/Makefile.inc | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc index 45a90ac..a5116c0 100755 --- a/src/arch/x86/Makefile.inc +++ b/src/arch/x86/Makefile.inc @@ -58,8 +58,8 @@ extract_nth=$(word $(1), $(subst |, ,$(2))) ifneq ($(CONFIG_UPDATE_IMAGE),y) prebuild-files = \ $(foreach file,$(cbfs-files), \ - $(CBFSTOOL) $@.tmp add $(call extract_nth,1,$(file)) \ - $(call extract_nth,2,$(file)) $(call extract_nth,3,$(file)) \ + $(CBFSTOOL) $@.tmp add$(if $(filter stage,$(call extract_nth,3,$(file))),-stage) $(call extract_nth,1,$(file)) \ + $(call extract_nth,2,$(file)) $(if $(filter-out stage,$(call extract_nth,3,$(file))),$(call extract_nth,3,$(file))) \ $(call extract_nth,4,$(file)) &&) prebuilt-files = $(foreach file,$(cbfs-files), $(call extract_nth,1,$(file))) From gerrit at coreboot.org Tue May 1 00:00:24 2012 From: gerrit at coreboot.org (Patrick Georgi (patrick@georgi-clan.de)) Date: Tue, 1 May 2012 00:00:24 +0200 Subject: [coreboot] New patch to review for coreboot: 68ae60f Move VSA support from x86 to Geode References: Message-ID: Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/962 -gerrit commit 68ae60f6d9bcef7e365a3a00fbe78111e7da7ee6 Author: Patrick Georgi Date: Mon Apr 30 23:56:58 2012 +0200 Move VSA support from x86 to Geode Instead of the special case in the generic Makefile.inc, use cbfs-files in the CPU directories. Change-Id: I71d9c8dff906c9a516ac0dd09a315f8956075592 Signed-off-by: Patrick Georgi --- src/arch/x86/Makefile.inc | 9 --------- src/cpu/amd/geode_gx2/Makefile.inc | 4 ++++ src/cpu/amd/geode_lx/Makefile.inc | 4 ++++ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/arch/x86/Makefile.inc b/src/arch/x86/Makefile.inc index a5116c0..5486bb1 100755 --- a/src/arch/x86/Makefile.inc +++ b/src/arch/x86/Makefile.inc @@ -49,9 +49,6 @@ endif ifeq ($(CONFIG_AP_CODE_IN_CAR),y) COREBOOT_ROM_DEPENDENCIES+=$(objcbfs)/coreboot_ap.elf endif -ifeq ($(CONFIG_GEODE_VSA_FILE),y) -COREBOOT_ROM_DEPENDENCIES+=$(CONFIG_VSA_FILENAME) -endif extract_nth=$(word $(1), $(subst |, ,$(2))) @@ -96,12 +93,6 @@ ifeq ($(CONFIG_PAYLOAD_FILO),y) @printf " PAYLOAD FILO (internal, compression: $(CBFS_PAYLOAD_COMPRESS_NAME))\n" $(CBFSTOOL) $@.tmp add-payload $(CONFIG_PAYLOAD_FILE) $(CONFIG_CBFS_PREFIX)/payload $(CBFS_PAYLOAD_COMPRESS_FLAG) endif -ifeq ($(CONFIG_GEODE_VSA_FILE),y) - @printf " VSA $(CONFIG_VSA_FILENAME)\n" - $(OBJCOPY) --set-start 0x20 --adjust-vma 0x60000 -I binary -O elf32-i386 -B i386 $(CONFIG_VSA_FILENAME) $(obj)/vsa.o - $(LD) -m elf_i386 -e 0x60020 --section-start .data=0x60000 $(obj)/vsa.o -o $(obj)/vsa.elf - $(CBFSTOOL) $@.tmp add-stage $(obj)/vsa.elf vsa -endif ifeq ($(CONFIG_INCLUDE_CONFIG_FILE),y) @printf " CONFIG $(DOTCONFIG)\n" if [ -f $(DOTCONFIG) ]; then \ diff --git a/src/cpu/amd/geode_gx2/Makefile.inc b/src/cpu/amd/geode_gx2/Makefile.inc index b70537a..d3777a6 100644 --- a/src/cpu/amd/geode_gx2/Makefile.inc +++ b/src/cpu/amd/geode_gx2/Makefile.inc @@ -7,3 +7,7 @@ driver-y += geode_gx2_init.c ramstage-y += cpubug.c cpu_incs += $(src)/cpu/amd/geode_gx2/cache_as_ram.inc + +cbfs-files-$(CONFIG_GEODE_VSA_FILE) += vsa +vsa-file = $(call strip_quotes,$(CONFIG_VSA_FILENAME)):vsa +vsa-type = stage diff --git a/src/cpu/amd/geode_lx/Makefile.inc b/src/cpu/amd/geode_lx/Makefile.inc index a5e1281..4b2b37c 100644 --- a/src/cpu/amd/geode_lx/Makefile.inc +++ b/src/cpu/amd/geode_lx/Makefile.inc @@ -7,3 +7,7 @@ driver-y += geode_lx_init.c ramstage-y += cpubug.c cpu_incs += $(src)/cpu/amd/geode_lx/cache_as_ram.inc + +cbfs-files-$(CONFIG_GEODE_VSA_FILE) += vsa +vsa-file = $(call strip_quotes,$(CONFIG_VSA_FILENAME)):vsa +vsa-type = stage From gerrit at coreboot.org Tue May 1 00:02:44 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 00:02:44 +0200 Subject: [coreboot] New patch to review for coreboot: faffebf Fix Sandybridge/Ivybridge mainboards according to code review References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/963 -gerrit commit faffebf1bf40107559cf965e5d547c2a82d6db87 Author: Stefan Reinauer Date: Mon Apr 30 14:57:51 2012 -0700 Fix Sandybridge/Ivybridge mainboards according to code review This fixes a few cosmetics with the following three boards: - Intel Emerald Lake 2 - Samsung ChromeBook - Samsung ChromeBox The following issues were fixed: - rely on include path in ASL code instead of specifying relative paths - use updated ALIGN_CURRENT in acpi_tables.c - use preprocessor defines instead of hard coded values where possible Change-Id: Ia5941be3873aa84c30c13ff2f0428d1c52daa563 Signed-off-by: Stefan Reinauer --- src/mainboard/intel/emeraldlake2/acpi/superio.asl | 2 +- src/mainboard/intel/emeraldlake2/acpi_tables.c | 2 +- src/mainboard/intel/emeraldlake2/romstage.c | 18 +++++++++--------- src/mainboard/samsung/lumpy/acpi/superio.asl | 2 +- src/mainboard/samsung/lumpy/acpi_tables.c | 2 +- src/mainboard/samsung/lumpy/romstage.c | 18 +++++++++--------- src/mainboard/samsung/stumpy/acpi/superio.asl | 2 +- src/mainboard/samsung/stumpy/acpi_tables.c | 2 +- src/mainboard/samsung/stumpy/romstage.c | 18 +++++++++--------- src/northbridge/intel/sandybridge/sandybridge.h | 1 + 10 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/mainboard/intel/emeraldlake2/acpi/superio.asl b/src/mainboard/intel/emeraldlake2/acpi/superio.asl index f803aaf..a50c4b3 100644 --- a/src/mainboard/intel/emeraldlake2/acpi/superio.asl +++ b/src/mainboard/intel/emeraldlake2/acpi/superio.asl @@ -32,4 +32,4 @@ #define SIO_GPIO_IO0 0x720 // pnp 2e.7: io 0x60 #define SIO_GPIO_IO1 0x730 // pnp 2e.7: io 0x60 -#include "../../../../superio/smsc/sio1007/acpi/superio.asl" +#include "superio/smsc/sio1007/acpi/superio.asl" diff --git a/src/mainboard/intel/emeraldlake2/acpi_tables.c b/src/mainboard/intel/emeraldlake2/acpi_tables.c index c84ac46..01d4b54 100644 --- a/src/mainboard/intel/emeraldlake2/acpi_tables.c +++ b/src/mainboard/intel/emeraldlake2/acpi_tables.c @@ -180,7 +180,7 @@ unsigned long acpi_fill_srat(unsigned long current) void smm_setup_structures(void *gnvs, void *tcg, void *smi1); -#define ALIGN_CURRENT current = ((current + 0x0f) & -0x10) +#define ALIGN_CURRENT current = (ALIGN(current, 16)) unsigned long write_acpi_tables(unsigned long start) { unsigned long current; diff --git a/src/mainboard/intel/emeraldlake2/romstage.c b/src/mainboard/intel/emeraldlake2/romstage.c index 23d1d6b..0cf113b 100644 --- a/src/mainboard/intel/emeraldlake2/romstage.c +++ b/src/mainboard/intel/emeraldlake2/romstage.c @@ -188,17 +188,17 @@ void main(unsigned long bist) #endif struct pei_data pei_data = { pei_version: PEI_VERSION, - mchbar: 0xfed10000, - dmibar: 0xfed18000, - epbar: 0xfed19000, - pciexbar: 0xf0000000, - smbusbar: 0x400, + mchbar: DEFAULT_MCHBAR, + dmibar: DEFAULT_DMIBAR, + epbar: DEFAULT_EPBAR, + pciexbar: CONFIG_MMCONF_BASE_ADDRESS, + smbusbar: SMBUS_IO_BASE, wdbbar: 0x4000000, wdbsize: 0x1000, - hpet_address: 0xfed00000, - rcba: 0xfed1c000, - pmbase: 0x500, - gpiobase: 0x480, + hpet_address: HPET_ADDR, + rcba: DEFAULT_RCBABASE, + pmbase: DEFAULT_PMBASE, + gpiobase: DEFAULT_GPIOBASE, thermalbase: 0xfed08000, system_type: 0, // 0 Mobile, 1 Desktop/Server tseg_size: CONFIG_SMM_TSEG_SIZE, diff --git a/src/mainboard/samsung/lumpy/acpi/superio.asl b/src/mainboard/samsung/lumpy/acpi/superio.asl index 465fa54..01d9447 100644 --- a/src/mainboard/samsung/lumpy/acpi/superio.asl +++ b/src/mainboard/samsung/lumpy/acpi/superio.asl @@ -35,4 +35,4 @@ #define SIO_ENABLE_SMBX // pnp 2e.9: Enable Mailbox #define SIO_SMBX_IO0 0xa00 // pnp 2e.9: io 0xa00 -#include "../../../../superio/smsc/mec1308/acpi/superio.asl" +#include "superio/smsc/mec1308/acpi/superio.asl" diff --git a/src/mainboard/samsung/lumpy/acpi_tables.c b/src/mainboard/samsung/lumpy/acpi_tables.c index a9eeb74..46fdf31 100644 --- a/src/mainboard/samsung/lumpy/acpi_tables.c +++ b/src/mainboard/samsung/lumpy/acpi_tables.c @@ -177,7 +177,7 @@ unsigned long acpi_fill_srat(unsigned long current) void smm_setup_structures(void *gnvs, void *tcg, void *smi1); -#define ALIGN_CURRENT current = ((current + 0x0f) & -0x10) +#define ALIGN_CURRENT current = (ALIGN(current, 16)) unsigned long write_acpi_tables(unsigned long start) { unsigned long current; diff --git a/src/mainboard/samsung/lumpy/romstage.c b/src/mainboard/samsung/lumpy/romstage.c index 7aa4746..82856f6 100644 --- a/src/mainboard/samsung/lumpy/romstage.c +++ b/src/mainboard/samsung/lumpy/romstage.c @@ -151,17 +151,17 @@ void main(unsigned long bist) #endif struct pei_data pei_data = { - .mchbar = 0xfed10000, - .dmibar = 0xfed18000, - .epbar = 0xfed19000, - .pciexbar = 0xf0000000, - .smbusbar = 0x400, + .mchbar = DEFAULT_MCHBAR, + .dmibar = DEFAULT_DMIBAR, + .epbar = DEFAULT_EPBAR, + .pciexbar = CONFIG_MMCONF_BASE_ADDRESS, + .smbusbar = SMBUS_IO_BASE, .wdbbar = 0x4000000, .wdbsize = 0x1000, - .hpet_address = 0xfed00000, - .rcba = 0xfed1c000, - .pmbase = 0x500, - .gpiobase = 0x480, + .hpet_address = HPET_ADDR, + .rcba = DEFAULT_RCBABASE, + .pmbase = DEFAULT_PMBASE, + .gpiobase = DEFAULT_GPIOBASE, .thermalbase = 0xfed08000, .system_type = 0, // 0 Mobile, 1 Desktop/Server .tseg_size = CONFIG_SMM_TSEG_SIZE, diff --git a/src/mainboard/samsung/stumpy/acpi/superio.asl b/src/mainboard/samsung/stumpy/acpi/superio.asl index 24bc8cf..75869ca 100644 --- a/src/mainboard/samsung/stumpy/acpi/superio.asl +++ b/src/mainboard/samsung/stumpy/acpi/superio.asl @@ -32,4 +32,4 @@ #define SIO_GPIO_IO0 0x720 // pnp 2e.7: io 0x60 #define SIO_GPIO_IO1 0x730 // pnp 2e.7: io 0x60 -#include "../../../../superio/ite/it8772f/acpi/superio.asl" +#include "superio/ite/it8772f/acpi/superio.asl" diff --git a/src/mainboard/samsung/stumpy/acpi_tables.c b/src/mainboard/samsung/stumpy/acpi_tables.c index 686e7dc..68da59d 100644 --- a/src/mainboard/samsung/stumpy/acpi_tables.c +++ b/src/mainboard/samsung/stumpy/acpi_tables.c @@ -181,7 +181,7 @@ unsigned long acpi_fill_srat(unsigned long current) void smm_setup_structures(void *gnvs, void *tcg, void *smi1); -#define ALIGN_CURRENT current = ((current + 0x0f) & -0x10) +#define ALIGN_CURRENT current = (ALIGN(current, 16)) unsigned long write_acpi_tables(unsigned long start) { unsigned long current; diff --git a/src/mainboard/samsung/stumpy/romstage.c b/src/mainboard/samsung/stumpy/romstage.c index c7c392d..10a9d7b 100644 --- a/src/mainboard/samsung/stumpy/romstage.c +++ b/src/mainboard/samsung/stumpy/romstage.c @@ -186,17 +186,17 @@ void main(unsigned long bist) }; #endif struct pei_data pei_data = { - mchbar: 0xfed10000, - dmibar: 0xfed18000, - epbar: 0xfed19000, - pciexbar: 0xf0000000, - smbusbar: 0x400, + mchbar: DEFAULT_MCHBAR, + dmibar: DEFAULT_DMIBAR, + epbar: DEFAULT_EPBAR, + pciexbar: CONFIG_MMCONF_BASE_ADDRESS, + smbusbar: SMBUS_IO_BASE, wdbbar: 0x4000000, wdbsize: 0x1000, - hpet_address: 0xfed00000, - rcba: 0xfed1c000, - pmbase: 0x500, - gpiobase: 0x480, + hpet_address: HPET_ADDR, + rcba: DEFAULT_RCBABASE, + pmbase: DEFAULT_PMBASE, + gpiobase: DEFAULT_GPIOBASE, thermalbase: 0xfed08000, system_type: 0, // 0 Mobile, 1 Desktop/Server tseg_size: CONFIG_SMM_TSEG_SIZE, diff --git a/src/northbridge/intel/sandybridge/sandybridge.h b/src/northbridge/intel/sandybridge/sandybridge.h index 9ff6555..c7bea98 100644 --- a/src/northbridge/intel/sandybridge/sandybridge.h +++ b/src/northbridge/intel/sandybridge/sandybridge.h @@ -51,6 +51,7 @@ #define DEFAULT_MCHBAR 0xfed10000 /* 16 KB */ #define DEFAULT_DMIBAR 0xfed18000 /* 4 KB */ #define DEFAULT_EPBAR 0xfed19000 /* 4 KB */ +#define DEFAULT_RCBABASE 0xfed1c000 #include "../../../southbridge/intel/bd82x6x/pch.h" From gerrit at coreboot.org Tue May 1 00:09:28 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 00:09:28 +0200 Subject: [coreboot] Patch merged into coreboot/master: 248b15c Add 3rdparty as submodule References: Message-ID: the following patch was just integrated into master: commit 248b15cc4a4dff6570acf1b32485f03ec326d19f Author: Patrick Georgi Date: Mon Apr 30 20:11:34 2012 +0200 Add 3rdparty as submodule The build system will make sure only to fetch this if desired by the user. Change-Id: Ie3c1b44f67ba2595cae001234e29e36cf855a3e4 Signed-off-by: Patrick Georgi See http://review.coreboot.org/956 for details. -gerrit From gerrit at coreboot.org Tue May 1 00:11:53 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 00:11:53 +0200 Subject: [coreboot] Patch merged into coreboot/master: 85c53cc Add Kconfig options to handle the blobs repository References: Message-ID: the following patch was just integrated into master: commit 85c53ccd199b2790957234537e4deb0afdff9876 Author: Patrick Georgi Date: Mon Apr 30 21:06:10 2012 +0200 Add Kconfig options to handle the blobs repository One option to allow using the repo (defaults to no), one to let boards state that they require it in the current configuration. The build system checks out the repo if allowed, and fails if the repo is requested by the configuration but not desired by the user. Change-Id: If71d80b329cf528aa467fcb0b4d9d7c7434aab27 Signed-off-by: Patrick Georgi See http://review.coreboot.org/957 for details. -gerrit From gerrit at coreboot.org Tue May 1 00:29:16 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 00:29:16 +0200 Subject: [coreboot] Patch merged into coreboot/master: 88e6526 abuild: Add option to use binary files References: Message-ID: the following patch was just integrated into master: commit 88e65268cac4b433bc7dbd9b428d8b971f62b3df Author: Patrick Georgi Date: Mon Apr 30 22:55:28 2012 +0200 abuild: Add option to use binary files abuild -B enables the use of the blob repository. Change-Id: I2dd823d3b024ad249d72d668657bf6a6e92145cf Signed-off-by: Patrick Georgi See http://review.coreboot.org/958 for details. -gerrit From gerrit at coreboot.org Tue May 1 01:49:49 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:49:49 +0200 Subject: [coreboot] New patch to review for coreboot: 887793d Set up the Emerald Lake 2 SMI and SCI sources based on the schematic. References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/964 -gerrit commit 887793df39d78bcdab65cb965a98fcd31b88fca4 Author: Gabe Black Date: Thu Mar 29 17:58:52 2012 -0700 Set up the Emerald Lake 2 SMI and SCI sources based on the schematic. This sets up the SMI and SCI inputs on the PCH for Emerald Lake 2 based on my best interpretation of the schematic. It may not be correct, but it doesn't seem to cause any problems either. Change-Id: I21238b3853a92893ec7f08baa2a3ebd35c49dd97 Signed-off-by: Gabe Black --- src/mainboard/intel/emeraldlake2/devicetree.cb | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/src/mainboard/intel/emeraldlake2/devicetree.cb b/src/mainboard/intel/emeraldlake2/devicetree.cb index 2631cfc..686fe2e 100644 --- a/src/mainboard/intel/emeraldlake2/devicetree.cb +++ b/src/mainboard/intel/emeraldlake2/devicetree.cb @@ -45,8 +45,10 @@ chip northbridge/intel/sandybridge # 0 No effect (default) # 1 SMI# (if corresponding ALT_GPI_SMI_EN bit is also set) # 2 SCI (if corresponding GPIO_EN bit is also set) - register "gpi1_routing" = "0" + register "gpi1_routing" = "1" register "gpi14_routing" = "2" + register "alt_gp_smi_en" = "0x0002" + register "gpe0_en" = "0x4000" register "ide_legacy_combined" = "0x0" register "sata_ahci" = "0x1" From gerrit at coreboot.org Tue May 1 01:49:51 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:49:51 +0200 Subject: [coreboot] New patch to review for coreboot: db4ce07 Set up ChromeOS dev mode, recovery, and write protect GPIOs on Emerald Lake 2. References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/965 -gerrit commit db4ce0735688cb695465e162974d88f95e8a4833 Author: Gabe Black Date: Thu Mar 29 18:04:56 2012 -0700 Set up ChromeOS dev mode, recovery, and write protect GPIOs on Emerald Lake 2. The Emerald Lake 2 CRB wasn't designed with ChromeOS in mind, so there aren't any actual developer mode, recovery mode, or write protect switches, let alone GPIOs to read them from. Instead, I've commandeered signals connected to GPIOs which are for other things but which aren't used by hardware or, for instance, the EC to do something Coreboot doesn't control. The recovery mode switch is connected to GPIO 22 and is called BIOS_REC on the schematic. The name is at least very reminiscent of the right thing even if it's supposed to be used for something else. There's a jumper on the board labelled J8G1 which can force the line to ground, and if not, there's a switch on the front of the case which toggles its value. "RECOVER" is for recovery mode and "KEEP" is for normal mode. The developer mode switch is connected to GPIO 57 and is called SV_DET on the schematic. It's connected to a jumper labelled J8E2 on the board and, as far as I can tell, can't be controlled in any other way. When the jumper is in place and the pins are shorted, developer mode is selected. When the jumper is removed, normal mode is selected. The write protect is connected to GPIO 48 which is called BIOS_RESP on the schematic. It's connected to a jumper labelled J8E3 which, like j8E2, seems to be the only way to control the line it's on. When the jumper is in place, write protect is "disabled", and when it's in place it's "enabled" even though there's no functional difference. The input for the recovery mode switch was chosen because of the name it already had on the CRB, BIOS recovery, and because there's a switch to control it on the front of the case which makes it easy to get at. The jumpers for developer mode and recovery mode were chosen because there weren't very many options available, and of those these were next to each other which should make them easier to find and work with. It might be a good idea to wire toggle switches up to the pins of those jumpers so they'll be easy to identify, can be labelled, and would be easier to work with than little jumpers in the middle of the motherboard. Change-Id: Ib2c3dc05077dacfbede596dae143ed81a99dbebd Signed-off-by: Gabe Black --- src/mainboard/intel/emeraldlake2/acpi/chromeos.asl | 6 +- src/mainboard/intel/emeraldlake2/chromeos.c | 44 ++++++++------------ src/mainboard/intel/emeraldlake2/gpio.h | 4 ++ 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/mainboard/intel/emeraldlake2/acpi/chromeos.asl b/src/mainboard/intel/emeraldlake2/acpi/chromeos.asl index 65202cb..81ead2e 100644 --- a/src/mainboard/intel/emeraldlake2/acpi/chromeos.asl +++ b/src/mainboard/intel/emeraldlake2/acpi/chromeos.asl @@ -65,9 +65,9 @@ Device (CRHW) Method(GPIO, 0, Serialized) { Name(OIPG, Package() { - Package() { 0x001, 0, 42, "CougarPoint" }, // recovery button - Package() { 0x002, 1, 17, "CougarPoint" }, // developer switch - Package() { 0x003, 1, 68, "CougarPoint" }, // firmware write protect + Package() { 0x001, 0, 22, "CougarPoint" }, // recovery button + Package() { 0x002, 1, 57, "CougarPoint" }, // developer switch + Package() { 0x003, 0, 48, "CougarPoint" }, // firmware write protect Package() { 0x100, 0, 9, "CougarPoint" }, // debug header gpio Package() { 0x101, 0, 10, "CougarPoint" }, // debug header gpio 1 Package() { 0x102, 0, 12, "CougarPoint" }, // debug header gpio 2 diff --git a/src/mainboard/intel/emeraldlake2/chromeos.c b/src/mainboard/intel/emeraldlake2/chromeos.c index 0acd20f..850af7b 100644 --- a/src/mainboard/intel/emeraldlake2/chromeos.c +++ b/src/mainboard/intel/emeraldlake2/chromeos.c @@ -45,36 +45,30 @@ void fill_lb_gpios(struct lb_gpios *gpios) if (!gpio_base) return; -#if 0 // Dev mode is hardcoded on, so we don't need to read these GPIOs. u32 gp_lvl = inl(gpio_base + 0x0c); -#endif u32 gp_lvl2 = inl(gpio_base + 0x38); - u32 gp_lvl3 = inl(gpio_base + 0x48); + /* u32 gp_lvl3 = inl(gpio_base + 0x48); */ gpios->size = sizeof(*gpios) + (GPIO_COUNT * sizeof(struct lb_gpio)); gpios->count = GPIO_COUNT; - /* Write Protect: GPIO68 = CHP3_SPI_WP */ - gpios->gpios[0].port = 68; - gpios->gpios[0].polarity = ACTIVE_HIGH; - gpios->gpios[0].value = (gp_lvl3 >> (68-64)) & 1; + /* Write Protect: GPIO48 */ + gpios->gpios[0].port = 48; + gpios->gpios[0].polarity = ACTIVE_LOW; + gpios->gpios[0].value = (gp_lvl2 >> (48-32)) & 1; strncpy((char *)gpios->gpios[0].name,"write protect", GPIO_MAX_NAME_LENGTH); - /* Recovery: GPIO42 = CHP3_REC_MODE# */ - gpios->gpios[1].port = 42; + /* Recovery: GPIO22 */ + gpios->gpios[1].port = 22; gpios->gpios[1].polarity = ACTIVE_LOW; - gpios->gpios[1].value = (gp_lvl2 >> (42-32)) & 1; + gpios->gpios[1].value = (gp_lvl >> 22) & 1; strncpy((char *)gpios->gpios[1].name,"recovery", GPIO_MAX_NAME_LENGTH); - /* Developer: GPIO17 = KBC3_DVP_MODE */ - gpios->gpios[2].port = 17; + /* Developer: GPIO57 */ + gpios->gpios[2].port = 57; gpios->gpios[2].polarity = ACTIVE_HIGH; -#if 0 // Dev mode is hardcoded on. - gpios->gpios[2].value = (gp_lvl >> 17) & 1; -#else - gpios->gpios[2].value = 1; -#endif + gpios->gpios[2].value = (gp_lvl2 >> (57-32)) & 1; strncpy((char *)gpios->gpios[2].name,"developer", GPIO_MAX_NAME_LENGTH); /* Hard code the lid switch GPIO to open. */ @@ -93,7 +87,6 @@ void fill_lb_gpios(struct lb_gpios *gpios) int get_developer_mode_switch(void) { -#if 0 // Dev mode is hardcoded on. device_t dev; #ifdef __PRE_RAM__ dev = PCI_DEV(0, 0x1f, 0); @@ -101,13 +94,10 @@ int get_developer_mode_switch(void) dev = dev_find_slot(0, PCI_DEVFN(0x1f,0)); #endif u16 gpio_base = pci_read_config32(dev, GPIOBASE) & 0xfffe; - u32 gp_lvl = inl(gpio_base + 0x0c); + u32 gp_lvl2 = inl(gpio_base + 0x38); - /* Developer: GPIO17 = KBC3_DVP_MODE, active high */ - return (gp_lvl >> 17) & 1; -#else - return 1; -#endif + /* Developer: GPIO17, active high */ + return (gp_lvl2 >> (57-32)) & 1; } int get_recovery_mode_switch(void) @@ -119,9 +109,9 @@ int get_recovery_mode_switch(void) dev = dev_find_slot(0, PCI_DEVFN(0x1f,0)); #endif u16 gpio_base = pci_read_config32(dev, GPIOBASE) & 0xfffe; - u32 gp_lvl2 = inl(gpio_base + 0x38); + u32 gp_lvl = inl(gpio_base + 0x0c); - /* Recovery: GPIO42 = CHP3_REC_MODE#, active low */ - return !((gp_lvl2 >> (42-32)) & 1); + /* Recovery: GPIO22, active low */ + return !((gp_lvl >> 22) & 1); } diff --git a/src/mainboard/intel/emeraldlake2/gpio.h b/src/mainboard/intel/emeraldlake2/gpio.h index bec34aa..c458c83 100644 --- a/src/mainboard/intel/emeraldlake2/gpio.h +++ b/src/mainboard/intel/emeraldlake2/gpio.h @@ -34,6 +34,7 @@ const struct pch_gpio_set1 pch_gpio_set1_mode = { .gpio12 = GPIO_MODE_GPIO, .gpio15 = GPIO_MODE_GPIO, .gpio21 = GPIO_MODE_GPIO, + .gpio22 = GPIO_MODE_GPIO, .gpio24 = GPIO_MODE_GPIO, .gpio27 = GPIO_MODE_GPIO, .gpio28 = GPIO_MODE_GPIO, @@ -49,6 +50,7 @@ const struct pch_gpio_set1 pch_gpio_set1_direction = { .gpio12 = GPIO_DIR_INPUT, .gpio15 = GPIO_DIR_INPUT, .gpio21 = GPIO_DIR_INPUT, + .gpio22 = GPIO_DIR_INPUT, .gpio27 = GPIO_DIR_INPUT, }; @@ -60,11 +62,13 @@ const struct pch_gpio_set1 pch_gpio_set1_invert = { const struct pch_gpio_set2 pch_gpio_set2_mode = { .gpio36 = GPIO_MODE_GPIO, + .gpio48 = GPIO_MODE_GPIO, .gpio57 = GPIO_MODE_GPIO, .gpio60 = GPIO_MODE_GPIO, }; const struct pch_gpio_set2 pch_gpio_set2_direction = { + .gpio48 = GPIO_DIR_INPUT, .gpio57 = GPIO_DIR_INPUT, }; From gerrit at coreboot.org Tue May 1 01:49:52 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:49:52 +0200 Subject: [coreboot] New patch to review for coreboot: d7f3d69 Allow more CPU cores on Emerald Lake 2 CRB References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/966 -gerrit commit d7f3d6996e3d67f69533a69d773e4fde897d347a Author: Stefan Reinauer Date: Wed Mar 28 13:19:15 2012 -0700 Allow more CPU cores on Emerald Lake 2 CRB The Emerald Lake 2 CRB can potentially have more than 8 CPU cores, so update the number of max cores accordingly. Change-Id: Ia42ed8a84916f66dfbfdf2a72cbbed5cea61899b Signed-off-by: Stefan Reinauer --- src/mainboard/intel/emeraldlake2/Kconfig | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/mainboard/intel/emeraldlake2/Kconfig b/src/mainboard/intel/emeraldlake2/Kconfig index 9916aaa..002ae2a 100644 --- a/src/mainboard/intel/emeraldlake2/Kconfig +++ b/src/mainboard/intel/emeraldlake2/Kconfig @@ -37,7 +37,7 @@ config IRQ_SLOT_COUNT config MAX_CPUS int - default 8 + default 16 config MAX_PHYSICAL_CPUS int From gerrit at coreboot.org Tue May 1 01:49:58 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:49:58 +0200 Subject: [coreboot] New patch to review for coreboot: ea39273 Clean up Emerald Lake 2 mainboard directory References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/967 -gerrit commit ea39273f80f64da5992b79e86ec950d6e0a3b420 Author: Gabe Black Date: Fri Mar 30 14:33:02 2012 -0700 Clean up Emerald Lake 2 mainboard directory Change-Id: I4a64a56dda22050a31232807096e15565a665377 Signed-off-by: Gabe Black --- src/mainboard/intel/emeraldlake2/gpio.h | 6 +++--- src/mainboard/intel/emeraldlake2/romstage.c | 2 +- src/mainboard/intel/emeraldlake2/thermal.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mainboard/intel/emeraldlake2/gpio.h b/src/mainboard/intel/emeraldlake2/gpio.h index c458c83..05b9164 100644 --- a/src/mainboard/intel/emeraldlake2/gpio.h +++ b/src/mainboard/intel/emeraldlake2/gpio.h @@ -17,8 +17,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef LINK_GPIO_H -#define LINK_GPIO_H +#ifndef EMERALDLAKE2_GPIO_H +#define EMERALDLAKE2_GPIO_H #include "southbridge/intel/bd82x6x/gpio.h" @@ -84,7 +84,7 @@ const struct pch_gpio_set3 pch_gpio_set3_direction = { const struct pch_gpio_set3 pch_gpio_set3_level = { }; -const struct pch_gpio_map link_gpio_map = { +const struct pch_gpio_map emeraldlake2_gpio_map = { .set1 = { .mode = &pch_gpio_set1_mode, .direction = &pch_gpio_set1_direction, diff --git a/src/mainboard/intel/emeraldlake2/romstage.c b/src/mainboard/intel/emeraldlake2/romstage.c index 23d1d6b..753d1d7 100644 --- a/src/mainboard/intel/emeraldlake2/romstage.c +++ b/src/mainboard/intel/emeraldlake2/romstage.c @@ -242,7 +242,7 @@ void main(unsigned long bist) /* Enable GPIOs */ pci_write_config32(PCH_LPC_DEV, GPIO_BASE, DEFAULT_GPIOBASE|1); pci_write_config8(PCH_LPC_DEV, GPIO_CNTL, 0x10); - setup_pch_gpios(&link_gpio_map); + setup_pch_gpios(&emeraldlake2_gpio_map); setup_sio_gpios(); /* Early SuperIO setup */ diff --git a/src/mainboard/intel/emeraldlake2/thermal.h b/src/mainboard/intel/emeraldlake2/thermal.h index deb40c2..883849d 100644 --- a/src/mainboard/intel/emeraldlake2/thermal.h +++ b/src/mainboard/intel/emeraldlake2/thermal.h @@ -17,8 +17,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef LINK_THERMAL_H -#define LINK_THERMAL_H +#ifndef EMERALDLAKE2_THERMAL_H +#define EMERALDLAKE2_THERMAL_H /* Fan is OFF */ #define FAN4_THRESHOLD_OFF 0 From gerrit at coreboot.org Tue May 1 01:50:02 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:02 +0200 Subject: [coreboot] New patch to review for coreboot: e1b81de add new LPC controller device ID value References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/968 -gerrit commit e1b81deaf1c17cb2c6723b8a35a595e0e6edf162 Author: Vadim Bendebury Date: Sat Apr 7 02:11:36 2012 +0000 add new LPC controller device ID value This adds the PCI device id of the LPC controller identifying the QPRJ/QS stepping of the Panther Point southbridge. Change-Id: Idcaa7dbd30224e3690ea469c6cb74f75de287631 Signed-off-by: Vadim Bendebury --- src/southbridge/intel/bd82x6x/lpc.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/src/southbridge/intel/bd82x6x/lpc.c b/src/southbridge/intel/bd82x6x/lpc.c index 1ecaf8f..9a3dc99 100644 --- a/src/southbridge/intel/bd82x6x/lpc.c +++ b/src/southbridge/intel/bd82x6x/lpc.c @@ -676,3 +676,8 @@ static const struct pci_driver c216_lpc __pci_driver = { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x1e55, }; +static const struct pci_driver hm75_lpc __pci_driver = { + .ops = &device_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x1e5d, +}; From gerrit at coreboot.org Tue May 1 01:50:04 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:04 +0200 Subject: [coreboot] New patch to review for coreboot: e3e901d Modify DMI init for IvyBridge References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/969 -gerrit commit e3e901db657591603411402a1ceb581873480442 Author: Vincent Palatin Date: Wed Mar 28 16:10:29 2012 -0700 Modify DMI init for IvyBridge The ASPM setting for the Direct Media Interface should no longer be done on Ivybridge/PantherPoint based systems. Change-Id: Id30de1beb1b162564048e76712736ccf7049dc7c Signed-off-by: Vincent Palatin --- src/northbridge/intel/sandybridge/northbridge.c | 18 +++++++++++------- 1 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/northbridge/intel/sandybridge/northbridge.c b/src/northbridge/intel/sandybridge/northbridge.c index e3334c4..b1f7c72 100644 --- a/src/northbridge/intel/sandybridge/northbridge.c +++ b/src/northbridge/intel/sandybridge/northbridge.c @@ -347,10 +347,12 @@ static void northbridge_dmi_init(struct device *dev) DMIBAR32(0x1d0) = 0xffffffff; /* Steps prior to DMI ASPM */ - reg32 = DMIBAR32(0x250); - reg32 &= ~((1 << 22)|(1 << 20)); - reg32 |= (1 << 21); - DMIBAR32(0x250) = reg32; + if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) { + reg32 = DMIBAR32(0x250); + reg32 &= ~((1 << 22)|(1 << 20)); + reg32 |= (1 << 21); + DMIBAR32(0x250) = reg32; + } reg32 = DMIBAR32(0x238); reg32 |= (1 << 29); @@ -372,9 +374,11 @@ static void northbridge_dmi_init(struct device *dev) } /* Enable ASPM on SNB link, should happen before PCH link */ - reg32 = DMIBAR32(0xd04); - reg32 |= (1 << 4); - DMIBAR32(0xd04) = reg32; + if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) { + reg32 = DMIBAR32(0xd04); + reg32 |= (1 << 4); + DMIBAR32(0xd04) = reg32; + } reg32 = DMIBAR32(0x88); reg32 |= (1 << 1) | (1 << 0); From gerrit at coreboot.org Tue May 1 01:50:08 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:08 +0200 Subject: [coreboot] New patch to review for coreboot: 448a583 Only send ME Dram Init Done message on Sandybridge References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/970 -gerrit commit 448a58332fe61afe811862167486c6ec291963ba Author: Duncan Laurie Date: Mon Apr 9 12:30:43 2012 -0700 Only send ME Dram Init Done message on Sandybridge This is done inside the SystemAgent binary on Ivybridge. Change-Id: I8fb0f593a65a4803e160b284c21b9d5021e2e4a0 Signed-off-by: Duncan Laurie --- src/northbridge/intel/sandybridge/raminit.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index dcf9f63..bbb743f 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "raminit.h" #include "pei_data.h" #include "sandybridge.h" @@ -365,7 +366,13 @@ void sdram_initialize(struct pei_data *pei_data) version >> 24 , (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); - intel_early_me_init_done(ME_INIT_STATUS_SUCCESS); + /* Send ME init done for SandyBridge here. This is done + * inside the SystemAgent binary on IvyBridge. */ + if (BASE_REV_SNB == + (pci_read_config16(PCI_CPU_DEVICE, PCI_DEVICE_ID) & BASE_REV_MASK)) + intel_early_me_init_done(ME_INIT_STATUS_SUCCESS); + else + intel_early_me_status(); report_memory_config(); From gerrit at coreboot.org Tue May 1 01:50:09 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:09 +0200 Subject: [coreboot] New patch to review for coreboot: dc5c7e0 Don't disable ACPI in the S3 resume path References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/971 -gerrit commit dc5c7e0b63d9b8b3429ae6fb929cbb39efec4159 Author: Duncan Laurie Date: Mon Apr 9 12:31:43 2012 -0700 Don't disable ACPI in the S3 resume path The OS does not re-execute the APMC 'enable ACPI' SMI on resume so this has the potential to leave things in an unknown state. Change-Id: Iaf0fcb99f699e9e0ecacaab3f529026782a95151 Signed-off-by: Duncan Laurie --- src/southbridge/intel/bd82x6x/lpc.c | 15 +++++++++------ 1 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/southbridge/intel/bd82x6x/lpc.c b/src/southbridge/intel/bd82x6x/lpc.c index 9a3dc99..dddab6a 100644 --- a/src/southbridge/intel/bd82x6x/lpc.c +++ b/src/southbridge/intel/bd82x6x/lpc.c @@ -396,15 +396,18 @@ static void pch_lock_smm(struct device *dev) u8 reg8; #endif + if (acpi_slp_type != 3) { #if ENABLE_ACPI_MODE_IN_COREBOOT - printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n"); - outb(0xe1, 0xb2); // Enable ACPI mode - printk(BIOS_DEBUG, "done.\n"); + printk(BIOS_DEBUG, "Enabling ACPI via APMC:\n"); + outb(0xe1, 0xb2); // Enable ACPI mode + printk(BIOS_DEBUG, "done.\n"); #else - printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n"); - outb(0x1e, 0xb2); // Disable ACPI mode - printk(BIOS_DEBUG, "done.\n"); + printk(BIOS_DEBUG, "Disabling ACPI via APMC:\n"); + outb(0x1e, 0xb2); // Disable ACPI mode + printk(BIOS_DEBUG, "done.\n"); #endif + } + /* Don't allow evil boot loaders, kernels, or * userspace applications to deceive us: */ From gerrit at coreboot.org Tue May 1 01:50:16 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:16 +0200 Subject: [coreboot] New patch to review for coreboot: d3884c8 Fix TPM driver to work with multiple vendor TPMs References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/972 -gerrit commit d3884c83a8cc31b3b3bae3eee92e4d429d4c8d52 Author: Stefan Reinauer Date: Mon Apr 30 16:33:44 2012 -0700 Fix TPM driver to work with multiple vendor TPMs Port u-boot patch for low-level driver: - Fix bug in traversal of vendor name list. - Sending "command ready" needs additional logic to handle TPMs that need that bit set twice: once to empty the read FIFOs and once to actualy set command ready. Change-Id: I57c280266b2e966c5b90e4f9e968426a33b93cf1 Signed-off-by: Duncan Laurie --- src/drivers/pc80/tpm.c | 85 ++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/drivers/pc80/tpm.c b/src/drivers/pc80/tpm.c index 17e1ed7..c7b5081 100644 --- a/src/drivers/pc80/tpm.c +++ b/src/drivers/pc80/tpm.c @@ -127,13 +127,31 @@ struct vendor_name { const struct device_name* dev_names; }; +static const struct device_name atmel_devices[] = { + {0x3204, "AT97SC3204"}, + {0xffff} +}; + static const struct device_name infineon_devices[] = { - {0xb, "SLB9635 TT 1.2"}, - {0} + {0x000b, "SLB9635 TT 1.2"}, + {0xffff} +}; + +static const struct device_name nuvoton_devices[] = { + {0x00fe, "NPCT420AA V2"}, + {0xffff} +}; + +static const struct device_name stmicro_devices[] = { + {0x0000, "ST33ZP24" }, + {0xffff} }; static const struct vendor_name vendor_names[] = { + {0x1114, "Atmel", atmel_devices}, {0x15d1, "Infineon", infineon_devices}, + {0x1050, "Nuvoton", nuvoton_devices}, + {0x104a, "ST Microelectronics", stmicro_devices}, }; /* @@ -208,6 +226,44 @@ static u32 tis_wait_reg(u8 reg, u8 locality, u8 mask, u8 expected) } /* + * PC Client Specific TPM Interface Specification section 11.2.12: + * + * Software must be prepared to send two writes of a "1" to command ready + * field: the first to indicate successful read of all the data, thus + * clearing the data from the ReadFIFO and freeing the TPM's resources, + * and the second to indicate to the TPM it is about to send a new command. + * + * In practice not all TPMs behave the same so it is necessary to be + * flexible when trying to set command ready. + * + * Returns 0 on success if the TPM is ready for transactions. + * Returns TPM_TIMEOUT_ERR if the command ready bit does not get set. + */ +static int tis_command_ready(u8 locality) +{ + u32 status; + + /* 1st attempt to set command ready */ + tpm_write(TIS_STS_COMMAND_READY, locality, TIS_REG_STS); + + /* Wait for response */ + status = tpm_read(locality, TIS_REG_STS); + + /* Check if command ready is set yet */ + if (status & TIS_STS_COMMAND_READY) + return 0; + + /* 2nd attempt to set command ready */ + tpm_write(TIS_STS_COMMAND_READY, locality, TIS_REG_STS); + + /* Wait for command ready to get set */ + status = tis_wait_reg(TIS_REG_STS, locality, + TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY); + + return (status == TPM_TIMEOUT_ERR) ? TPM_TIMEOUT_ERR : 0; +} + +/* * Probe the TPM device and try determining its manufacturer/device name. * * Returns 0 on success (the device is found or was found during an earlier @@ -215,15 +271,17 @@ static u32 tis_wait_reg(u8 reg, u8 locality, u8 mask, u8 expected) */ static u32 tis_probe(void) { - u32 didvid = tpm_read(0, TIS_REG_DID_VID); - int i; const char *device_name = "unknown"; const char *vendor_name = device_name; + const struct device_name *dev; + u32 didvid; u16 vid, did; + int i; if (vendor_dev_id) return 0; /* Already probed. */ + didvid = tpm_read(0, TIS_REG_DID_VID); if (!didvid || (didvid == 0xffffffff)) { printf("%s: No TPM device found\n", __FUNCTION__); return TPM_DRIVER_ERR; @@ -238,11 +296,13 @@ static u32 tis_probe(void) u16 known_did; if (vid == vendor_names[i].vendor_id) { vendor_name = vendor_names[i].vendor_name; + } else { + continue; } - while ((known_did = vendor_names[i].dev_names[j].dev_id) != 0) { + dev = &vendor_names[i].dev_names[j]; + while ((known_did = dev->dev_id) != 0xffff) { if (known_did == did) { - device_name = - vendor_names[i].dev_names[j].dev_name; + device_name = dev->dev_name; break; } j++; @@ -250,7 +310,7 @@ static u32 tis_probe(void) break; } /* this will have to be converted into debug printout */ - TPM_DEBUG("Found TPM %s by %s\n", device_name, vendor_name); + printf("Found TPM %s by %s\n", device_name, vendor_name); return 0; } @@ -446,7 +506,8 @@ static u32 tis_readresponse(u8 *buffer, size_t *len) } /* Tell the TPM that we are done. */ - tpm_write(TIS_STS_COMMAND_READY, locality, TIS_REG_STS); + if (tis_command_ready(locality) == TPM_TIMEOUT_ERR) + return TPM_DRIVER_ERR; *len = offset; return 0; @@ -492,7 +553,11 @@ int tis_open(void) return TPM_DRIVER_ERR; } - tpm_write(TIS_STS_COMMAND_READY, locality, TIS_REG_STS); + /* Certain TPMs seem to need some delay here or they hang... */ + udelay(10); + + if (tis_command_ready(locality) == TPM_TIMEOUT_ERR) + return TPM_DRIVER_ERR; return 0; } From gerrit at coreboot.org Tue May 1 01:50:18 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:18 +0200 Subject: [coreboot] New patch to review for coreboot: 8f492d6 Update ivybridge graphics initialization References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/973 -gerrit commit 8f492d6c487068317267a59a9a47c9be7b72a543 Author: Duncan Laurie Date: Mon Apr 9 12:05:18 2012 -0700 Update ivybridge graphics initialization - Add config options to set backlight registers - Update powermeter weight tables for IvyBridge GT1 and add a new table for GT2 SKU - Fix a few registers used during GPU PM init sequence Change-Id: I1500bc07e3ba1bc10c77e7856089e716489dc07a Signed-off-by: Duncan Laurie --- src/northbridge/intel/sandybridge/chip.h | 3 + src/northbridge/intel/sandybridge/gma.c | 309 ++++++++++++++++++++---------- 2 files changed, 213 insertions(+), 99 deletions(-) diff --git a/src/northbridge/intel/sandybridge/chip.h b/src/northbridge/intel/sandybridge/chip.h index b891884..bd89787 100644 --- a/src/northbridge/intel/sandybridge/chip.h +++ b/src/northbridge/intel/sandybridge/chip.h @@ -35,6 +35,9 @@ struct northbridge_intel_sandybridge_config { u16 gpu_panel_power_down_delay; /* T3 time sequence */ u16 gpu_panel_power_backlight_on_delay; /* T5 time sequence */ u16 gpu_panel_power_backlight_off_delay; /* Tx time sequence */ + + u32 gpu_cpu_backlight; /* CPU Backlight PWM value */ + u32 gpu_pch_backlight; /* PCH Backlight PWM value */ }; extern struct chip_operations northbridge_intel_sandybridge_ops; diff --git a/src/northbridge/intel/sandybridge/gma.c b/src/northbridge/intel/sandybridge/gma.c index 4aabb75..181d901 100644 --- a/src/northbridge/intel/sandybridge/gma.c +++ b/src/northbridge/intel/sandybridge/gma.c @@ -27,6 +27,169 @@ #include "chip.h" #include "sandybridge.h" +struct gt_powermeter { + u16 reg; + u32 value; +}; + +struct gt_powermeter snb_pm_gt1[] = { + { 0xa200, 0xcc000000 }, + { 0xa204, 0x07000040 }, + { 0xa208, 0x0000fe00 }, + { 0xa20c, 0x00000000 }, + { 0xa210, 0x17000000 }, + { 0xa214, 0x00000021 }, + { 0xa218, 0x0817fe19 }, + { 0xa21c, 0x00000000 }, + { 0xa220, 0x00000000 }, + { 0xa224, 0xcc000000 }, + { 0xa228, 0x07000040 }, + { 0xa22c, 0x0000fe00 }, + { 0xa230, 0x00000000 }, + { 0xa234, 0x17000000 }, + { 0xa238, 0x00000021 }, + { 0xa23c, 0x0817fe19 }, + { 0xa240, 0x00000000 }, + { 0xa244, 0x00000000 }, + { 0xa248, 0x8000421e }, + { 0 } +}; + +struct gt_powermeter snb_pm_gt2[] = { + { 0xa200, 0x330000a6 }, + { 0xa204, 0x402d0031 }, + { 0xa208, 0x00165f83 }, + { 0xa20c, 0xf1000000 }, + { 0xa210, 0x00000000 }, + { 0xa214, 0x00160016 }, + { 0xa218, 0x002a002b }, + { 0xa21c, 0x00000000 }, + { 0xa220, 0x00000000 }, + { 0xa224, 0x330000a6 }, + { 0xa228, 0x402d0031 }, + { 0xa22c, 0x00165f83 }, + { 0xa230, 0xf1000000 }, + { 0xa234, 0x00000000 }, + { 0xa238, 0x00160016 }, + { 0xa23c, 0x002a002b }, + { 0xa240, 0x00000000 }, + { 0xa244, 0x00000000 }, + { 0xa248, 0x8000421e }, + { 0 } +}; + +struct gt_powermeter ivb_pm_gt1[] = { + { 0xa800, 0x10000000 }, + { 0xa804, 0x00033800 }, + { 0xa808, 0x00000902 }, + { 0xa80c, 0x0c002f00 }, + { 0xa810, 0x12000400 }, + { 0xa814, 0x00000000 }, + { 0xa818, 0x00d20800 }, + { 0xa81c, 0x00000002 }, + { 0xa820, 0x03004b02 }, + { 0xa824, 0x00000600 }, + { 0xa828, 0x07000773 }, + { 0xa82c, 0x00000000 }, + { 0xa830, 0x00010032 }, + { 0xa834, 0x1520040d }, + { 0xa838, 0x00020105 }, + { 0xa83c, 0x00083700 }, + { 0xa840, 0x0000151d }, + { 0xa844, 0x00000000 }, + { 0xa848, 0x20001b00 }, + { 0xa84c, 0x0a000010 }, + { 0xa850, 0x00000000 }, + { 0xa854, 0x00000008 }, + { 0xa858, 0x00000008 }, + { 0xa85c, 0x00000000 }, + { 0xa860, 0x00020000 }, + { 0xa248, 0x0000221e }, + { 0xa900, 0x00000000 }, + { 0xa904, 0x00003500 }, + { 0xa908, 0x00000000 }, + { 0xa90c, 0x0c000000 }, + { 0xa910, 0x12000500 }, + { 0xa914, 0x00000000 }, + { 0xa918, 0x00b20000 }, + { 0xa91c, 0x00000000 }, + { 0xa920, 0x08004b02 }, + { 0xa924, 0x00000200 }, + { 0xa928, 0x07000820 }, + { 0xa92c, 0x00000000 }, + { 0xa930, 0x00030000 }, + { 0xa934, 0x050f020d }, + { 0xa938, 0x00020300 }, + { 0xa93c, 0x00903900 }, + { 0xa940, 0x00000000 }, + { 0xa944, 0x00000000 }, + { 0xa948, 0x20001b00 }, + { 0xa94c, 0x0a000010 }, + { 0xa950, 0x00000000 }, + { 0xa954, 0x00000008 }, + { 0xa960, 0x00110000 }, + { 0xaa3c, 0x00003900 }, + { 0xaa54, 0x00000008 }, + { 0xaa60, 0x00110000 }, + { 0 } +}; + +struct gt_powermeter ivb_pm_gt2[] = { + { 0xa800, 0x20000000 }, + { 0xa804, 0x000e3800 }, + { 0xa808, 0x00000806 }, + { 0xa80c, 0x0c002f00 }, + { 0xa810, 0x0c000800 }, + { 0xa814, 0x00000000 }, + { 0xa818, 0x00d20d00 }, + { 0xa81c, 0x000000ff }, + { 0xa820, 0x03004b02 }, + { 0xa824, 0x00000600 }, + { 0xa828, 0x07000773 }, + { 0xa82c, 0x00000000 }, + { 0xa830, 0x00020032 }, + { 0xa834, 0x1520040d }, + { 0xa838, 0x00020105 }, + { 0xa83c, 0x00083700 }, + { 0xa840, 0x000016ff }, + { 0xa844, 0x00000000 }, + { 0xa848, 0xff000000 }, + { 0xa84c, 0x0a000010 }, + { 0xa850, 0x00000004 }, + { 0xa854, 0x00000008 }, + { 0xa858, 0x00000018 }, + { 0xa85c, 0x00000000 }, + { 0xa860, 0x00020000 }, + { 0xa248, 0x0000221e }, + { 0xa900, 0x00000000 }, + { 0xa904, 0x00003800 }, + { 0xa908, 0x00000000 }, + { 0xa90c, 0x0c000000 }, + { 0xa910, 0x12000500 }, + { 0xa914, 0x00000000 }, + { 0xa918, 0x00b20000 }, + { 0xa91c, 0x00000000 }, + { 0xa920, 0x08004b02 }, + { 0xa924, 0x00000200 }, + { 0xa928, 0x07000820 }, + { 0xa92c, 0x00000000 }, + { 0xa930, 0x00030000 }, + { 0xa934, 0x050f020d }, + { 0xa938, 0x00020300 }, + { 0xa93c, 0x00903900 }, + { 0xa940, 0x00000000 }, + { 0xa944, 0x00000000 }, + { 0xa948, 0x20001b00 }, + { 0xa94c, 0x0a000010 }, + { 0xa950, 0x00000000 }, + { 0xa954, 0x00000008 }, + { 0xa960, 0x00110000 }, + { 0xaa3c, 0x00003900 }, + { 0xaa54, 0x00000008 }, + { 0xaa60, 0x00110000 }, + { 0 } +}; + /* some vga option roms are used for several chipsets but they only have one * PCI ID in their header. If we encounter such an option rom, we need to do * the mapping ourselfes @@ -63,6 +226,12 @@ static inline void gtt_write(u32 reg, u32 data) write32(gtt_res->base + reg, data); } +static inline void gtt_write_powermeter(struct gt_powermeter *pm) +{ + for (; pm && pm->reg; pm++) + gtt_write(pm->reg, pm->value); +} + #define GTT_RETRY 1000 static int gtt_poll(u32 reg, u32 mask, u32 value) { @@ -98,7 +267,7 @@ static void gma_pm_init_pre_vbios(struct device *dev) } else { gtt_write(0xa180, 1 << 5); gtt_write(0xa188, 0xffff0001); - if (!gtt_poll(0x130090, (1 << 0), (1 << 0))) + if (!gtt_poll(0x130040, (1 << 0), (1 << 0))) return; } @@ -111,112 +280,35 @@ static void gma_pm_init_pre_vbios(struct device *dev) if (bridge_silicon_revision() >= IVB_STEP_A0) { /* Display Reset Acknowledge Settings */ - gtt_write(0xa18c, 0x00000001); reg32 = gtt_read(0x45010); reg32 |= (1 << 1) | (1 << 0); gtt_write(0x45010, reg32); } /* 2: Get GT SKU from GTT+0x911c[13] */ + reg32 = gtt_read(0x911c); if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) { - reg32 = gtt_read(0x911c); if (reg32 & (1 << 13)) { - printk(BIOS_DEBUG, "GT1 Power Meter Weights\n"); - gtt_write(0xa200, 0xcc000000); - gtt_write(0xa204, 0x07000040); - gtt_write(0xa208, 0x0000fe00); - gtt_write(0xa20c, 0x00000000); - gtt_write(0xa210, 0x17000000); - gtt_write(0xa214, 0x00000021); - gtt_write(0xa218, 0x0817fe19); - gtt_write(0xa21c, 0x00000000); - gtt_write(0xa220, 0x00000000); - gtt_write(0xa224, 0xcc000000); - gtt_write(0xa228, 0x07000040); - gtt_write(0xa22c, 0x0000fe00); - gtt_write(0xa230, 0x00000000); - gtt_write(0xa234, 0x17000000); - gtt_write(0xa238, 0x00000021); - gtt_write(0xa23c, 0x0817fe19); - gtt_write(0xa240, 0x00000000); - gtt_write(0xa244, 0x00000000); - gtt_write(0xa248, 0x8000421e); + printk(BIOS_DEBUG, "SNB GT1 Power Meter Weights\n"); + gtt_write_powermeter(snb_pm_gt1); } else { - printk(BIOS_DEBUG, "GT2 Power Meter Weights\n"); - gtt_write(0xa200, 0x330000a6); - gtt_write(0xa204, 0x402d0031); - gtt_write(0xa208, 0x00165f83); - gtt_write(0xa20c, 0xf1000000); - gtt_write(0xa210, 0x00000000); - gtt_write(0xa214, 0x00160016); - gtt_write(0xa218, 0x002a002b); - gtt_write(0xa21c, 0x00000000); - gtt_write(0xa220, 0x00000000); - gtt_write(0xa224, 0x330000a6); - gtt_write(0xa228, 0x402d0031); - gtt_write(0xa22c, 0x00165f83); - gtt_write(0xa230, 0xf1000000); - gtt_write(0xa234, 0x00000000); - gtt_write(0xa238, 0x00160016); - gtt_write(0xa23c, 0x002a002b); - gtt_write(0xa240, 0x00000000); - gtt_write(0xa244, 0x00000000); - gtt_write(0xa248, 0x8000421e); + printk(BIOS_DEBUG, "SNB GT2 Power Meter Weights\n"); + gtt_write_powermeter(snb_pm_gt2); } } else { - printk(BIOS_DEBUG, "IVB GT Power Meter Weights\n"); - gtt_write(0xa800, 0x00000000); - gtt_write(0xa804, 0x00023800); - gtt_write(0xa808, 0x00000902); - gtt_write(0xa80c, 0x0c002f00); - gtt_write(0xa810, 0x12000500); - gtt_write(0xa814, 0x00000000); - gtt_write(0xa818, 0x00b20000); - gtt_write(0xa81c, 0x00000002); - gtt_write(0xa820, 0x03004b02); - gtt_write(0xa824, 0x00000600); - gtt_write(0xa828, 0x07000773); - gtt_write(0xa82c, 0x00000000); - gtt_write(0xa830, 0x00010000); - gtt_write(0xa834, 0x0510020d); - gtt_write(0xa838, 0x00020100); - gtt_write(0xa83c, 0x00103700); - gtt_write(0xa840, 0x0000001d); - gtt_write(0xa844, 0x00000000); - gtt_write(0xa848, 0x20001b00); - gtt_write(0xa84c, 0x0a000010); - gtt_write(0xa850, 0x00000000); - gtt_write(0xa854, 0x00000008); - gtt_write(0xa858, 0x00000000); - gtt_write(0xa85c, 0x00000000); - gtt_write(0xa860, 0x00040000); - gtt_write(0xa248, 0x0000221e); - gtt_write(0xa900, 0x00000000); - gtt_write(0xa904, 0x00003500); - gtt_write(0xa908, 0x00000000); - gtt_write(0xa90c, 0x0c000000); - gtt_write(0xa910, 0x12000500); - gtt_write(0xa914, 0x00000000); - gtt_write(0xa918, 0x00b20000); - gtt_write(0xa91c, 0x00000000); - gtt_write(0xa920, 0x08004b02); - gtt_write(0xa924, 0x00000400); - gtt_write(0xa928, 0x07000820); - gtt_write(0xa92c, 0x00000000); - gtt_write(0xa930, 0x00030000); - gtt_write(0xa934, 0x050f020d); - gtt_write(0xa938, 0x00020300); - gtt_write(0xa93c, 0x00903900); - gtt_write(0xa940, 0x00000000); - gtt_write(0xa944, 0x00000000); - gtt_write(0xa948, 0x20001b00); - gtt_write(0xa94c, 0x0a000010); - gtt_write(0xa950, 0x00000000); - gtt_write(0xa954, 0x00000008); - gtt_write(0xa960, 0x00110000); - gtt_write(0xaa3c, 0x00003900); - gtt_write(0xaa54, 0x00000008); - gtt_write(0xaa60, 0x00110000); + u32 unit = MCHBAR32(0x5938) & 0xf; + u32 tdp = MCHBAR32(0x5930) & 0x7fff; + tdp /= (1 << unit); + + if ((tdp <= 17) && !(reg32 & (1 << 13))) { + /* <=17W ULV and GT2 SKU */ + printk(BIOS_DEBUG, "IVB GT2 Power Meter Weights\n"); + gtt_write_powermeter(ivb_pm_gt2); + } else { + /* GT1 SKU */ + printk(BIOS_DEBUG, "IVB GT1 Power Meter Weights\n"); + gtt_write_powermeter(ivb_pm_gt1); + } } /* 3: Gear ratio map */ @@ -339,9 +431,18 @@ static void gma_pm_init_post_vbios(struct device *dev) printk(BIOS_DEBUG, "GT Power Management Init (post VBIOS)\n"); /* 15: Deassert Force Wake */ - gtt_write(0xa18c, gtt_read(0xa18c) & ~1); - if (!gtt_poll(0x130090, (1 << 0), (0 << 0))) - return; + if (bridge_silicon_revision() < IVB_STEP_C0) { + gtt_write(0xa18c, gtt_read(0xa18c) & ~1); + if (!gtt_poll(0x130090, (1 << 0), (0 << 0))) { + return; + } + } else { + gtt_write(0xa188, 0x1fffe); + if (!gtt_poll(0x130040, (1 << 0), (0 << 0))) { + return; + } + gtt_write(0xa188, gtt_read(0xa188) | 1); + } /* 16: SW RC Control */ gtt_write(0xa094, 0x00060000); @@ -379,6 +480,16 @@ static void gma_pm_init_post_vbios(struct device *dev) reg32 |= conf->gpu_panel_power_cycle_delay & 0xff; gtt_write(0xc7210, reg32); } + + /* Enable Backlight if needed */ + if (conf->gpu_cpu_backlight) { + gtt_write(0x48250, (1 << 31)); + gtt_write(0x48254, conf->gpu_cpu_backlight); + } + if (conf->gpu_pch_backlight) { + gtt_write(0xc8250, (1 << 31)); + gtt_write(0xc8254, conf->gpu_pch_backlight); + } } static void gma_func0_init(struct device *dev) From gerrit at coreboot.org Tue May 1 01:50:21 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:21 +0200 Subject: [coreboot] New patch to review for coreboot: 20e11fc Update Ivybridge GT power meter tables References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/974 -gerrit commit 20e11fca1ae27e041e0c8a4a1a6f5a6b4f5c2a05 Author: Duncan Laurie Date: Thu Apr 12 16:02:43 2012 -0700 Update Ivybridge GT power meter tables - New table for GT1 - Updates to GT2 17W table - New table for GT2 35W SKU - New table for GT2 Other This also includes a workaround to poll on a different register when deasserting force wake. On some SKUs the kernel is hanging when bringing up graphics unless this register is also polled. Change-Id: I2badf62b464e901cfb0eaf4fc196f59111c71564 Signed-off-by: Duncan Laurie --- src/northbridge/intel/sandybridge/gma.c | 168 ++++++++++++++++++++++++++++--- 1 files changed, 154 insertions(+), 14 deletions(-) diff --git a/src/northbridge/intel/sandybridge/gma.c b/src/northbridge/intel/sandybridge/gma.c index 181d901..499f347 100644 --- a/src/northbridge/intel/sandybridge/gma.c +++ b/src/northbridge/intel/sandybridge/gma.c @@ -79,6 +79,62 @@ struct gt_powermeter snb_pm_gt2[] = { }; struct gt_powermeter ivb_pm_gt1[] = { + { 0xa800, 0x00000000 }, + { 0xa804, 0x00021c00 }, + { 0xa808, 0x00000403 }, + { 0xa80c, 0x02001700 }, + { 0xa810, 0x05000200 }, + { 0xa814, 0x00000000 }, + { 0xa818, 0x00690500 }, + { 0xa81c, 0x0000007f }, + { 0xa820, 0x01002501 }, + { 0xa824, 0x00000300 }, + { 0xa828, 0x01000331 }, + { 0xa82c, 0x0000000c }, + { 0xa830, 0x00010016 }, + { 0xa834, 0x01100101 }, + { 0xa838, 0x00010103 }, + { 0xa83c, 0x00041300 }, + { 0xa840, 0x00000b30 }, + { 0xa844, 0x00000000 }, + { 0xa848, 0x7f000000 }, + { 0xa84c, 0x05000008 }, + { 0xa850, 0x00000001 }, + { 0xa854, 0x00000004 }, + { 0xa858, 0x00000007 }, + { 0xa85c, 0x00000000 }, + { 0xa860, 0x00010000 }, + { 0xa248, 0x0000221e }, + { 0xa900, 0x00000000 }, + { 0xa904, 0x00001c00 }, + { 0xa908, 0x00000000 }, + { 0xa90c, 0x06000000 }, + { 0xa910, 0x09000200 }, + { 0xa914, 0x00000000 }, + { 0xa918, 0x00590000 }, + { 0xa91c, 0x00000000 }, + { 0xa920, 0x04002501 }, + { 0xa924, 0x00000100 }, + { 0xa928, 0x03000410 }, + { 0xa92c, 0x00000000 }, + { 0xa930, 0x00020000 }, + { 0xa934, 0x02070106 }, + { 0xa938, 0x00010100 }, + { 0xa93c, 0x00401c00 }, + { 0xa940, 0x00000000 }, + { 0xa944, 0x00000000 }, + { 0xa948, 0x10000e00 }, + { 0xa94c, 0x02000004 }, + { 0xa950, 0x00000001 }, + { 0xa954, 0x00000004 }, + { 0xa960, 0x00060000 }, + { 0xaa3c, 0x00001c00 }, + { 0xaa54, 0x00000004 }, + { 0xaa60, 0x00060000 }, + { 0 } +}; + +struct gt_powermeter ivb_pm_gt2[] = { { 0xa800, 0x10000000 }, { 0xa804, 0x00033800 }, { 0xa808, 0x00000902 }, @@ -134,7 +190,7 @@ struct gt_powermeter ivb_pm_gt1[] = { { 0 } }; -struct gt_powermeter ivb_pm_gt2[] = { +struct gt_powermeter ivb_pm_gt2_17w[] = { { 0xa800, 0x20000000 }, { 0xa804, 0x000e3800 }, { 0xa808, 0x00000806 }, @@ -155,9 +211,9 @@ struct gt_powermeter ivb_pm_gt2[] = { { 0xa844, 0x00000000 }, { 0xa848, 0xff000000 }, { 0xa84c, 0x0a000010 }, - { 0xa850, 0x00000004 }, + { 0xa850, 0x00000002 }, { 0xa854, 0x00000008 }, - { 0xa858, 0x00000018 }, + { 0xa858, 0x0000000f }, { 0xa85c, 0x00000000 }, { 0xa860, 0x00020000 }, { 0xa248, 0x0000221e }, @@ -165,16 +221,72 @@ struct gt_powermeter ivb_pm_gt2[] = { { 0xa904, 0x00003800 }, { 0xa908, 0x00000000 }, { 0xa90c, 0x0c000000 }, - { 0xa910, 0x12000500 }, + { 0xa910, 0x12000800 }, { 0xa914, 0x00000000 }, { 0xa918, 0x00b20000 }, { 0xa91c, 0x00000000 }, { 0xa920, 0x08004b02 }, - { 0xa924, 0x00000200 }, - { 0xa928, 0x07000820 }, + { 0xa924, 0x00000300 }, + { 0xa928, 0x01000820 }, { 0xa92c, 0x00000000 }, { 0xa930, 0x00030000 }, - { 0xa934, 0x050f020d }, + { 0xa934, 0x15150406 }, + { 0xa938, 0x00020300 }, + { 0xa93c, 0x00903900 }, + { 0xa940, 0x00000000 }, + { 0xa944, 0x00000000 }, + { 0xa948, 0x20001b00 }, + { 0xa94c, 0x0a000010 }, + { 0xa950, 0x00000000 }, + { 0xa954, 0x00000008 }, + { 0xa960, 0x00110000 }, + { 0xaa3c, 0x00003900 }, + { 0xaa54, 0x00000008 }, + { 0xaa60, 0x00110000 }, + { 0 } +}; + +struct gt_powermeter ivb_pm_gt2_35w[] = { + { 0xa800, 0x00000000 }, + { 0xa804, 0x00030400 }, + { 0xa808, 0x00000806 }, + { 0xa80c, 0x0c002f00 }, + { 0xa810, 0x0c000300 }, + { 0xa814, 0x00000000 }, + { 0xa818, 0x00d20d00 }, + { 0xa81c, 0x000000ff }, + { 0xa820, 0x03004b02 }, + { 0xa824, 0x00000600 }, + { 0xa828, 0x07000773 }, + { 0xa82c, 0x00000000 }, + { 0xa830, 0x00020032 }, + { 0xa834, 0x1520040d }, + { 0xa838, 0x00020105 }, + { 0xa83c, 0x00083700 }, + { 0xa840, 0x000016ff }, + { 0xa844, 0x00000000 }, + { 0xa848, 0xff000000 }, + { 0xa84c, 0x0a000010 }, + { 0xa850, 0x00000001 }, + { 0xa854, 0x00000008 }, + { 0xa858, 0x00000008 }, + { 0xa85c, 0x00000000 }, + { 0xa860, 0x00020000 }, + { 0xa248, 0x0000221e }, + { 0xa900, 0x00000000 }, + { 0xa904, 0x00003800 }, + { 0xa908, 0x00000000 }, + { 0xa90c, 0x0c000000 }, + { 0xa910, 0x12000800 }, + { 0xa914, 0x00000000 }, + { 0xa918, 0x00b20000 }, + { 0xa91c, 0x00000000 }, + { 0xa920, 0x08004b02 }, + { 0xa924, 0x00000300 }, + { 0xa928, 0x01000820 }, + { 0xa92c, 0x00000000 }, + { 0xa930, 0x00030000 }, + { 0xa934, 0x15150406 }, { 0xa938, 0x00020300 }, { 0xa93c, 0x00903900 }, { 0xa940, 0x00000000 }, @@ -269,6 +381,12 @@ static void gma_pm_init_pre_vbios(struct device *dev) gtt_write(0xa188, 0xffff0001); if (!gtt_poll(0x130040, (1 << 0), (1 << 0))) return; + /* + * HACK: also poll on 0x130090, for some reason graphics does + * not work on all SKUs unless this register is polled at boot. + */ + if (!gtt_poll(0x130090, (1 << 0), (1 << 0))) + return; } if ((bridge_silicon_revision() & BASE_REV_MASK) == BASE_REV_SNB) { @@ -297,17 +415,32 @@ static void gma_pm_init_pre_vbios(struct device *dev) } } else { u32 unit = MCHBAR32(0x5938) & 0xf; - u32 tdp = MCHBAR32(0x5930) & 0x7fff; - tdp /= (1 << unit); - if ((tdp <= 17) && !(reg32 & (1 << 13))) { - /* <=17W ULV and GT2 SKU */ - printk(BIOS_DEBUG, "IVB GT2 Power Meter Weights\n"); - gtt_write_powermeter(ivb_pm_gt2); - } else { + if (reg32 & (1 << 13)) { /* GT1 SKU */ printk(BIOS_DEBUG, "IVB GT1 Power Meter Weights\n"); gtt_write_powermeter(ivb_pm_gt1); + } else { + /* GT2 SKU */ + u32 tdp = MCHBAR32(0x5930) & 0x7fff; + tdp /= (1 << unit); + + if (tdp <= 17) { + /* <=17W ULV */ + printk(BIOS_DEBUG, "IVB GT2 17W " + "Power Meter Weights\n"); + gtt_write_powermeter(ivb_pm_gt2_17w); + } else if ((tdp >= 25) && (tdp <= 35)) { + /* 25W-35W */ + printk(BIOS_DEBUG, "IVB GT2 35W " + "Power Meter Weights\n"); + gtt_write_powermeter(ivb_pm_gt2_35w); + } else { + /* All others */ + printk(BIOS_DEBUG, "IVB GT2 35W " + "Power Meter Weights\n"); + gtt_write_powermeter(ivb_pm_gt2_35w); + } } } @@ -441,6 +574,13 @@ static void gma_pm_init_post_vbios(struct device *dev) if (!gtt_poll(0x130040, (1 << 0), (0 << 0))) { return; } + /* + * HACK: also poll on 0x130090, for some reason graphics does + * not work on all SKUs unless this register is polled at boot. + */ + if (!gtt_poll(0x130090, (1 << 0), (0 << 0))) { + return; + } gtt_write(0xa188, gtt_read(0xa188) | 1); } From gerrit at coreboot.org Tue May 1 01:50:24 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:24 +0200 Subject: [coreboot] New patch to review for coreboot: 22fe62d Sandybridge: Display platform information early It is important to have the system configuration reported as early as possible to have a better idea what exact chipset the platform is running with. References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/975 -gerrit commit 22fe62dc4d4f662d067719bbac23dfb92891820e Author: Vadim Bendebury Date: Wed Apr 18 15:47:32 2012 -0700 Sandybridge: Display platform information early It is important to have the system configuration reported as early as possible to have a better idea what exact chipset the platform is running with. This change adds code to have an early coreboot module report the CPU and PCH information. CPU info includes the 32 bit feature information word, the symbolic processor brand string, and information about some features support, as obtained through CPUID instructions. The PCH information includes the symbolic device name and PCI device version. Change-Id: If6c21ad5ffb76d7d57d89f4f87d04bdd7192480a Signed-off-by: Vadim Bendebury --- src/northbridge/intel/sandybridge/Makefile.inc | 1 + src/northbridge/intel/sandybridge/raminit.c | 2 + .../intel/sandybridge/report_platform.c | 103 ++++++++++++++++++++ src/northbridge/intel/sandybridge/sandybridge.h | 1 + 4 files changed, 107 insertions(+), 0 deletions(-) diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index b72e9fa..79aa6ea 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -25,6 +25,7 @@ ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c romstage-y += udelay.c romstage-y += raminit.c romstage-y += early_init.c +romstage-y += report_platform.c romstage-y += ../../../arch/x86/lib/walkcbfs.S smm-$(CONFIG_HAVE_SMI_HANDLER) += udelay.c diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index bbb743f..e1d5d26 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -318,6 +318,8 @@ void sdram_initialize(struct pei_data *pei_data) const char *target = "mrc.bin"; unsigned long entry; + report_platform_info(); + /* Wait for ME to be ready */ intel_early_me_init(); intel_early_me_uma_size(); diff --git a/src/northbridge/intel/sandybridge/report_platform.c b/src/northbridge/intel/sandybridge/report_platform.c new file mode 100644 index 0000000..d59cfe9 --- /dev/null +++ b/src/northbridge/intel/sandybridge/report_platform.c @@ -0,0 +1,103 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Google Inc. + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "southbridge/intel/bd82x6x/pch.h" +#include +#include +#include "sandybridge.h" + +static void report_cpu_info(void) +{ + struct cpuid_result cpuidr; + u32 i, index; + char cpu_string[50]; /* 48 bytes are reported */ + int vt, txt, aes; + const char *mode[] = {"NOT ", ""}; + + index = 0x80000000; + cpuidr = cpuid(index); + if (cpuidr.eax < 0x80000004) { + strcpy(cpu_string, "Platform info not available"); + } else { + u32 *p = (u32*) cpu_string; + for (i = 2; i <= 4 ; i++) { + cpuidr = cpuid(index + i); + *p++ = cpuidr.eax; + *p++ = cpuidr.ebx; + *p++ = cpuidr.ecx; + *p++ = cpuidr.edx; + } + } + cpuidr = cpuid(1); + printk(BIOS_DEBUG, "CPU id(%x): %s\n", cpuidr.eax, cpu_string); + aes = (cpuidr.ecx & (1 << 25)) ? 1 : 0; + txt = (cpuidr.ecx & (1 << 6)) ? 1 : 0; + vt = (cpuidr.ecx & (1 << 5)) ? 1 : 0; + printk(BIOS_DEBUG, "AES %ssupported, TXT %ssupported, VT %ssupported\n", + mode[aes], mode[txt], mode[vt]); +} + +/* The PCI id name match comes from Intel document 472178 */ +static struct { + u16 dev_id; + const char *dev_name; +} pch_table [] = { + {0x1E41, "Desktop Sample"}, + {0x1E47, "Q77"}, + {0x1E48, "Q75"}, + {0x1E49, "B75"}, + {0x1E44, "Z77"}, + {0x1E46, "Z75"}, + {0x1E4A, "H77"}, + {0x1E53, "C216"}, + {0x1E42, "Mobile Sample"}, + {0x1E55, "QM77"}, + {0x1E58, "UM77"}, + {0x1E57, "HM77"}, + {0x1E59, "HM76"}, + {0x1E5d, "HM75"}, + {0x1E43, "SFF Sample"}, + {0x1E56, "QS77"}, +}; + +static void report_pch_info(void) +{ + int i; + u16 dev_id = pci_read_config16(PCH_LPC_DEV, 2); + + + const char *pch_type = "Unknown"; + for (i = 0; i < ARRAY_SIZE(pch_table); i++) { + if (pch_table[i].dev_id == dev_id) { + pch_type = pch_table[i].dev_name; + break; + } + } + printk (BIOS_DEBUG, "PCH type: %s rev id %x\n", + pch_type, pci_read_config8(PCH_LPC_DEV, 8)); +} + +void report_platform_info(void) +{ + report_cpu_info(); + report_pch_info(); +} diff --git a/src/northbridge/intel/sandybridge/sandybridge.h b/src/northbridge/intel/sandybridge/sandybridge.h index 9ff6555..1aa3a11 100644 --- a/src/northbridge/intel/sandybridge/sandybridge.h +++ b/src/northbridge/intel/sandybridge/sandybridge.h @@ -218,6 +218,7 @@ void dump_pci_device(unsigned dev); void dump_pci_devices(void); void dump_spd_registers(void); void dump_mem(unsigned start, unsigned end); +void report_platform_info(void); #endif /* !__SMM__ */ #endif #endif From gerrit at coreboot.org Tue May 1 01:50:27 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:27 +0200 Subject: [coreboot] New patch to review for coreboot: eb370e8 PantherPoint: Add additional PCI device IDs for SATA This includes IDs for the controller in normal mode and the desktop SKU IDs. References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/976 -gerrit commit eb370e842d0d89d58875d13a5610d796c5055a73 Author: Duncan Laurie Date: Tue Apr 24 10:00:41 2012 -0700 PantherPoint: Add additional PCI device IDs for SATA This includes IDs for the controller in normal mode and the desktop SKU IDs. Change-Id: I94c9d8d19a7a2ad9a0e560fa554c566b17c5d5ed Signed-off-by: Duncan Laurie --- src/southbridge/intel/bd82x6x/sata.c | 22 +++++++++++++++++++++- 1 files changed, 21 insertions(+), 1 deletions(-) diff --git a/src/southbridge/intel/bd82x6x/sata.c b/src/southbridge/intel/bd82x6x/sata.c index 057b882..ce5aea9 100644 --- a/src/southbridge/intel/bd82x6x/sata.c +++ b/src/southbridge/intel/bd82x6x/sata.c @@ -238,7 +238,27 @@ static const struct pci_driver pch_sata_mobile_ahci_driver __pci_driver = { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x1c03, }; -static const struct pci_driver pch_sata_mobile_ahci_driver_a __pci_driver = { + +/* PantherPoint */ +static const struct pci_driver ppt_sata_desktop_normal_driver __pci_driver = { + .ops = &sata_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x1e00, +}; + +static const struct pci_driver ppt_sata_mobile_normal_driver __pci_driver = { + .ops = &sata_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x1e01, +}; + +static const struct pci_driver ppt_sata_desktop_ahci_driver __pci_driver = { + .ops = &sata_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x1e02, +}; + +static const struct pci_driver ppt_sata_mobile_ahci_driver __pci_driver = { .ops = &sata_ops, .vendor = PCI_VENDOR_ID_INTEL, .device = 0x1e03, From gerrit at coreboot.org Tue May 1 01:50:28 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:28 +0200 Subject: [coreboot] New patch to review for coreboot: 9bf656b Fix SATA port map to only enable port 0 References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/977 -gerrit commit 9bf656b94d245b89d388fc63ff5512f32ad7b4ee Author: Stefan Reinauer Date: Mon Apr 30 16:42:07 2012 -0700 Fix SATA port map to only enable port 0 The sata controller comes up in legacy/normal mode and is currently put into AHCI mode in romstage. If that is removed and the controller is left alone until the ramstage driver (like we do on Stumpy/Lumpy) then the resource allocator will have configured the device for IDE mode with an IO address in BAR5. Then when the ramstage driver puts the controller into AHCI mode it will not have the correct resources to do the rest of the AHCI setup. So the controller mode needs to be changed in the enable stage rather than in the init phase. This same register contains the port map and it is a R/WO (write once) field so the configured port map must be written at the same time. For non-AHCI mode the devicetree map was ignored before but it is used now. Since the port map register is now written at enable step it does not need to be written again during init. With this change the sata port map can be reduced to just port 0 and then U-boot does not have to probe all available ports. Change-Id: I977952cd88797ab4cea79202e832ecbb5c37e0bd Signed-off-by: Duncan Laurie --- src/southbridge/intel/bd82x6x/sata.c | 29 ++++++++++++++++++++++------- 1 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/southbridge/intel/bd82x6x/sata.c b/src/southbridge/intel/bd82x6x/sata.c index ce5aea9..93dff91 100644 --- a/src/southbridge/intel/bd82x6x/sata.c +++ b/src/southbridge/intel/bd82x6x/sata.c @@ -48,8 +48,6 @@ static void sata_init(struct device *dev) if (config->ide_legacy_combined) { printk(BIOS_DEBUG, "SATA controller in combined mode.\n"); - /* Combine IDE - SATA configuration */ - pci_write_config16(dev, 0x90, 0x0000); /* No AHCI: clear AHCI base */ pci_write_config32(dev, 0x24, 0x00000000); @@ -88,9 +86,6 @@ static void sata_init(struct device *dev) u32 abar; printk(BIOS_DEBUG, "SATA controller in AHCI mode.\n"); - /* Set Sata Controller Mode. */ - pci_write_config16(dev, 0x90, 0x0060 | - ((config->sata_port_map ^ 0x3f) << 8)); /* Set Interrupt Line */ /* Interrupt Pin is set by D31IP.PIP */ @@ -143,8 +138,6 @@ static void sata_init(struct device *dev) write32(abar + 0xa0, reg32); } else { printk(BIOS_DEBUG, "SATA controller in plain mode.\n"); - /* Set Sata Controller Mode. No Mapping(?) */ - pci_write_config16(dev, 0x90, 0x0000); /* No AHCI: clear AHCI base */ pci_write_config32(dev, 0x24, 0x00000000); @@ -191,6 +184,27 @@ static void sata_init(struct device *dev) } } +static void sata_enable(device_t dev) +{ + /* Get the chip configuration */ + config_t *config = dev->chip_info; + u16 map = 0; + + if (!config) + return; + + /* + * Set SATA controller mode early so the resource allocator can + * properly assign IO/Memory resources for the controller. + */ + if (config->sata_ahci) + map = 0x0060; + + map |= (config->sata_port_map ^ 0x3f) << 8; + + pci_write_config16(dev, 0x90, map); +} + static void sata_set_subsystem(device_t dev, unsigned vendor, unsigned device) { if (!vendor || !device) { @@ -211,6 +225,7 @@ static struct device_operations sata_ops = { .set_resources = pci_dev_set_resources, .enable_resources = pci_dev_enable_resources, .init = sata_init, + .enable = sata_enable, .scan_bus = 0, .ops_pci = &sata_pci_ops, }; From gerrit at coreboot.org Tue May 1 01:50:31 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:31 +0200 Subject: [coreboot] New patch to review for coreboot: 84981fe Update PCIe Root Port _PRT to handle re-mapped functions References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/978 -gerrit commit 84981fe4c4542eecf8e834e19ba38f505515a3c0 Author: Duncan Laurie Date: Fri Apr 27 09:55:45 2012 -0700 Update PCIe Root Port _PRT to handle re-mapped functions The chipset enforces static-defined interrupt swizzling on PCIe root ports so if a port is remapped to a different function it needs to still report the proper interrupt map to the OS instead of assuming that function number is equivalent to root port number. This change also includes an update to the PCH function disable register which was incorrect for CPT/PPT and would cause unpredictable behavior if used. The kernel command line was changed to add 'nomsi' in order to force PCIe devices to use IO-APIC assigned interrupts and not MSI to ensure that the mapping is correct. LUMPY current: 00:1c.0 PCI bridge: Intel Corporation Device 1c10 (rev b5) 00:1c.3 PCI bridge: Intel Corporation Device 1c16 (rev b5) 16: 41518 0 0 0 IO-APIC-fasteoi i915, ahci, ath9k 19: 720 0 0 0 IO-APIC-fasteoi ehci_hcd:usb2, eth0 LUMPY with PCIe port coalesce enabled: 00:1c.0 PCI bridge: Intel Corporation Device 1c10 (rev b5) 00:1c.1 PCI bridge: Intel Corporation Device 1c16 (rev b5) 16: 38988 0 0 0 IO-APIC-fasteoi i915, ahci, ath9k 19: 347 0 0 0 IO-APIC-fasteoi ehci_hcd:usb2, eth0 Change-Id: Ia5f6bb8888b5c38a5dbc88bb25ecdf1fca41ee3e Signed-off-by: Duncan Laurie --- src/southbridge/intel/bd82x6x/acpi/pch.asl | 32 ++- src/southbridge/intel/bd82x6x/acpi/pcie.asl | 294 ++++++++++------------ src/southbridge/intel/bd82x6x/acpi/pcie_port.asl | 30 +++ 3 files changed, 188 insertions(+), 168 deletions(-) diff --git a/src/southbridge/intel/bd82x6x/acpi/pch.asl b/src/southbridge/intel/bd82x6x/acpi/pch.asl index 3e6651d..8632ad8 100644 --- a/src/southbridge/intel/bd82x6x/acpi/pch.asl +++ b/src/southbridge/intel/bd82x6x/acpi/pch.asl @@ -211,26 +211,32 @@ Scope(\) , 5, HPTE, 1, // Address Enable Offset(0x3418), // FD (Function Disable) - , 2, // Reserved - SATD, 1, // SATA disable + , 1, // Reserved + PCID, 1, // PCI bridge disable + SA1D, 1, // SATA1 disable SMBD, 1, // SMBUS disable HDAD, 1, // Azalia disable - , 2, // Reserved - ILND, 1, // Internal LAN disable - US1D, 1, // UHCI #1 disable - US2D, 1, // UHCI #2 disable - US3D, 1, // UHCI #3 disable - US4D, 1, // UHCI #4 disable - , 2, // Reserved + , 8, // Reserved + EH2D, 1, // EHCI #2 disable LPBD, 1, // LPC bridge disable - EHCD, 1, // EHCI disable - Offset(0x341a), // FD Root Ports + EH1D, 1, // EHCI #1 disable RP1D, 1, // Root Port 1 disable RP2D, 1, // Root Port 2 disable RP3D, 1, // Root Port 3 disable - RP4D, 1 // Root Port 4 disable + RP4D, 1, // Root Port 4 disable + RP5D, 1, // Root Port 5 disable + RP6D, 1, // Root Port 6 disable + RP7D, 1, // Root Port 7 disable + RP8D, 1, // Root Port 8 disable + TTRD, 1, // Thermal sensor registers disable + SA2D, 1, // SATA2 disable + Offset(0x3428), // FD2 (Function Disable 2) + BDFD, 1, // Display BDF + ME1D, 1, // ME Interface 1 disable + ME2D, 1, // ME Interface 2 disable + IDRD, 1, // IDE redirect disable + KTCT, 1, // Keyboard Text redirect disable } - } // High Definition Audio (Azalia) 0:1b.0 diff --git a/src/southbridge/intel/bd82x6x/acpi/pcie.asl b/src/southbridge/intel/bd82x6x/acpi/pcie.asl index f6b93bf..934cf78 100644 --- a/src/southbridge/intel/bd82x6x/acpi/pcie.asl +++ b/src/southbridge/intel/bd82x6x/acpi/pcie.asl @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2007-2009 coresystems GmbH + * Copyright (C) 2012 The Chromium OS Authors. All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,216 +20,199 @@ * MA 02110-1301 USA */ -/* Intel Cougar Point PCH PCIe support */ +/* Intel 6/7 Series PCH PCIe support */ // PCI Express Ports +Method (IRQM, 1, Serialized) { + + /* Interrupt Map INTA->INTA, INTB->INTB, INTC->INTC, INTD->INTD */ + Name (IQAA, Package() { + Package() { 0x0000ffff, 0, 0, 16 }, + Package() { 0x0000ffff, 1, 0, 17 }, + Package() { 0x0000ffff, 2, 0, 18 }, + Package() { 0x0000ffff, 3, 0, 19 } }) + Name (IQAP, Package() { + Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKA, 0 }, + Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKB, 0 }, + Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKC, 0 }, + Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKD, 0 } }) + + /* Interrupt Map INTA->INTB, INTB->INTC, INTC->INTD, INTD->INTA */ + Name (IQBA, Package() { + Package() { 0x0000ffff, 0, 0, 17 }, + Package() { 0x0000ffff, 1, 0, 18 }, + Package() { 0x0000ffff, 2, 0, 19 }, + Package() { 0x0000ffff, 3, 0, 16 } }) + Name (IQBP, Package() { + Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKB, 0 }, + Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKC, 0 }, + Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKD, 0 }, + Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKA, 0 } }) + + /* Interrupt Map INTA->INTC, INTB->INTD, INTC->INTA, INTD->INTB */ + Name (IQCA, Package() { + Package() { 0x0000ffff, 0, 0, 18 }, + Package() { 0x0000ffff, 1, 0, 19 }, + Package() { 0x0000ffff, 2, 0, 16 }, + Package() { 0x0000ffff, 3, 0, 17 } }) + Name (IQCP, Package() { + Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKC, 0 }, + Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKD, 0 }, + Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKA, 0 }, + Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKB, 0 } }) + + /* Interrupt Map INTA->INTD, INTB->INTA, INTC->INTB, INTD->INTC */ + Name (IQDA, Package() { + Package() { 0x0000ffff, 0, 0, 19 }, + Package() { 0x0000ffff, 1, 0, 16 }, + Package() { 0x0000ffff, 2, 0, 17 }, + Package() { 0x0000ffff, 3, 0, 18 } }) + Name (IQDP, Package() { + Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKD, 0 }, + Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKA, 0 }, + Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKB, 0 }, + Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKC, 0 } }) + + Switch (ToInteger (Arg0)) { + /* PCIe Root Port 1 and 5 */ + Case (Package() { 1, 5 }) { + If (PICM) { + Return (IQAA) + } Else { + Return (IQAP) + } + } + + /* PCIe Root Port 2 and 6 */ + Case (Package() { 2, 6 }) { + If (PICM) { + Return (IQBA) + } Else { + Return (IQBP) + } + } + + /* PCIe Root Port 3 and 7 */ + Case (Package() { 3, 7 }) { + If (PICM) { + Return (IQCA) + } Else { + Return (IQCP) + } + } + + /* PCIe Root Port 4 and 8 */ + Case (Package() { 4, 8 }) { + If (PICM) { + Return (IQDA) + } Else { + Return (IQDP) + } + } + + Default { + If (PICM) { + Return (IQDA) + } Else { + Return (IQDP) + } + } + } +} + Device (RP01) { - NAME(_ADR, 0x001c0000) // FIXME: Have a macro for PCI Devices -> ACPI notation? - //#include "pcie_port.asl" - Method(_PRT) - { - If (PICM) { - Return (Package() { - Package() { 0x0000ffff, 0, 0, 16 }, - Package() { 0x0000ffff, 1, 0, 17 }, - Package() { 0x0000ffff, 2, 0, 18 }, - Package() { 0x0000ffff, 3, 0, 19 } - }) - } Else { - Return (Package() { - Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKA, 0 }, - Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKB, 0 }, - Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKC, 0 }, - Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKD, 0 } - }) + Name (_ADR, 0x001c0000) - } + #include "pcie_port.asl" + Method (_PRT) + { + Return (IRQM (RPPN)) } } Device (RP02) { - NAME(_ADR, 0x001c0001) // FIXME: Have a macro for PCI Devices -> ACPI notation? - //#include "pcie_port.asl" - Method(_PRT) - { - If (PICM) { - Return (Package() { - Package() { 0x0000ffff, 0, 0, 17 }, - Package() { 0x0000ffff, 1, 0, 18 }, - Package() { 0x0000ffff, 2, 0, 19 }, - Package() { 0x0000ffff, 3, 0, 16 } - }) - } Else { - Return (Package() { - Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKB, 0 }, - Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKC, 0 }, - Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKD, 0 }, - Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKA, 0 } - }) + Name (_ADR, 0x001c0001) - } + #include "pcie_port.asl" + Method (_PRT) + { + Return (IRQM (RPPN)) } } Device (RP03) { - NAME(_ADR, 0x001c0002) // FIXME: Have a macro for PCI Devices -> ACPI notation? - //#include "pcie_port.asl" - Method(_PRT) - { - If (PICM) { - Return (Package() { - Package() { 0x0000ffff, 0, 0, 18 }, - Package() { 0x0000ffff, 1, 0, 19 }, - Package() { 0x0000ffff, 2, 0, 16 }, - Package() { 0x0000ffff, 3, 0, 17 } - }) - } Else { - Return (Package() { - Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKC, 0 }, - Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKD, 0 }, - Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKA, 0 }, - Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKB, 0 } - }) + Name (_ADR, 0x001c0002) - } + #include "pcie_port.asl" + Method (_PRT) + { + Return (IRQM (RPPN)) } } Device (RP04) { - NAME(_ADR, 0x001c0003) // FIXME: Have a macro for PCI Devices -> ACPI notation? - //#include "pcie_port.asl" - Method(_PRT) - { - If (PICM) { - Return (Package() { - Package() { 0x0000ffff, 0, 0, 17 }, - Package() { 0x0000ffff, 1, 0, 18 }, - Package() { 0x0000ffff, 2, 0, 19 }, - Package() { 0x0000ffff, 3, 0, 16 } - }) - } Else { - Return (Package() { - Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKB, 0 }, - Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKC, 0 }, - Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKD, 0 }, - Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKA, 0 } - }) + Name (_ADR, 0x001c0003) - } + #include "pcie_port.asl" + Method (_PRT) + { + Return (IRQM (RPPN)) } } Device (RP05) { - NAME(_ADR, 0x001c0004) // FIXME: Have a macro for PCI Devices -> ACPI notation? - //#include "pcie_port.asl" - Method(_PRT) - { - If (PICM) { - Return (Package() { - Package() { 0x0000ffff, 0, 0, 16 }, - Package() { 0x0000ffff, 1, 0, 17 }, - Package() { 0x0000ffff, 2, 0, 18 }, - Package() { 0x0000ffff, 3, 0, 19 } - }) - } Else { - Return (Package() { - Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKA, 0 }, - Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKB, 0 }, - Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKC, 0 }, - Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKD, 0 } - }) + Name (_ADR, 0x001c0004) - } + #include "pcie_port.asl" + Method (_PRT) + { + Return (IRQM (RPPN)) } } Device (RP06) { - NAME(_ADR, 0x001c0005) // FIXME: Have a macro for PCI Devices -> ACPI notation? - //#include "pcie_port.asl" - Method(_PRT) - { - If (PICM) { - Return (Package() { - Package() { 0x0000ffff, 0, 0, 17 }, - Package() { 0x0000ffff, 1, 0, 18 }, - Package() { 0x0000ffff, 2, 0, 19 }, - Package() { 0x0000ffff, 3, 0, 16 } - }) - } Else { - Return (Package() { - Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKB, 0 }, - Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKC, 0 }, - Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKD, 0 }, - Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKA, 0 } - }) + Name (_ADR, 0x001c0005) - } + #include "pcie_port.asl" + Method (_PRT) + { + Return (IRQM (RPPN)) } } Device (RP07) { - NAME(_ADR, 0x001c0006) // FIXME: Have a macro for PCI Devices -> ACPI notation? - //#include "pcie_port.asl" - Method(_PRT) - { - If (PICM) { - Return (Package() { - Package() { 0x0000ffff, 0, 0, 18 }, - Package() { 0x0000ffff, 1, 0, 19 }, - Package() { 0x0000ffff, 2, 0, 16 }, - Package() { 0x0000ffff, 3, 0, 17 } - }) - } Else { - Return (Package() { - Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKC, 0 }, - Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKD, 0 }, - Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKA, 0 }, - Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKB, 0 } - }) + Name (_ADR, 0x001c0006) - } + #include "pcie_port.asl" + Method (_PRT) + { + Return (IRQM (RPPN)) } } Device (RP08) { - NAME(_ADR, 0x001c0007) // FIXME: Have a macro for PCI Devices -> ACPI notation? - //#include "pcie_port.asl" - Method(_PRT) - { - If (PICM) { - Return (Package() { - Package() { 0x0000ffff, 0, 0, 19 }, - Package() { 0x0000ffff, 1, 0, 16 }, - Package() { 0x0000ffff, 2, 0, 17 }, - Package() { 0x0000ffff, 3, 0, 18 } - }) - } Else { - Return (Package() { - Package() { 0x0000ffff, 0, \_SB.PCI0.LPCB.LNKD, 0 }, - Package() { 0x0000ffff, 1, \_SB.PCI0.LPCB.LNKA, 0 }, - Package() { 0x0000ffff, 2, \_SB.PCI0.LPCB.LNKB, 0 }, - Package() { 0x0000ffff, 3, \_SB.PCI0.LPCB.LNKC, 0 } - }) + Name (_ADR, 0x001c0007) - } + #include "pcie_port.asl" + Method (_PRT) + { + Return (IRQM (RPPN)) } } - - diff --git a/src/southbridge/intel/bd82x6x/acpi/pcie_port.asl b/src/southbridge/intel/bd82x6x/acpi/pcie_port.asl new file mode 100644 index 0000000..fedd9c9 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/acpi/pcie_port.asl @@ -0,0 +1,30 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 The Chromium OS Authors. All Rights Reserved. + * + * 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; version 2 of + * the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +/* Included in each PCIe Root Port device */ + +OperationRegion (RPCS, PCI_Config, 0x00, 0xFF) +Field (RPCS, AnyAcc, NoLock, Preserve) +{ + Offset (0x4c), // Link Capabilities + , 24, + RPPN, 8, // Root Port Number +} From gerrit at coreboot.org Tue May 1 01:50:35 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:35 +0200 Subject: [coreboot] New patch to review for coreboot: 050c40f Add an option to enable PCIe root port coalescing References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/979 -gerrit commit 050c40f1dcee3945709146abf0c8cfd47b4abca3 Author: Duncan Laurie Date: Fri Apr 27 10:30:51 2012 -0700 Add an option to enable PCIe root port coalescing Background: The PCI spec (3.0-3.2.2.3.4) requires that PCI devices implement function 0. The Linux Kernel therefore will not enumerate a PCI device if it does not present a valid config space at function 0. If a board does not have anything connected to root port 0 and it is desired to disable the unused ports in order to save power then this will cause the other downstream PCIe devices to go missing as they will not be enumerated. Intel chipsets provide a way to map root port numbers to different PCI function numbers, thereby avoiding this issue and allowing root port 0 to be turned off. This change adds a new chip config option 'pcie_port_coalesce' that will collapse the enabled root ports into a linear map starting at zero. This option defaults to disabled as it can have a confusing effect on the system as the declared static devicetree may not match what is seen at runtime. This option is also forced on if the static devicetree disables port 0. When each root port is processed in the early enable stage it looks for a lower numbered root port that has been disabled and then swaps the two assigned function numbers. However the mapping register is write-once so it has to keep track of the proposed mapping changes until all ports have been processed before writing out the final map value. At this point it also updates the function numbers in the static device tree so they are consistent with the new layout. There are a few other closely related fixes in this change: 1) There is a power savings opportunity if an entire bank of ports (0-3 or 4-7) are disabled. This was checking the chipset revision to look for CougarPoint B1+ stepping and that was not passing on PantherPoint where this should always be applied. To fix this I added a function to determine the chipset type based on comparing the upper byte of the device ID. 2) Apply the same chipset type check fix to the IOBP programming. 3) There is another power savings opportunity to enable dynamic clock gating on shared PCIe resources which only applies to ports 0 and 4. However if 0 or 4 is disabled then the later check to enable this would fail as that device is already hidden. LUMPY current: 00:1c.0 PCI bridge: Intel Corporation Device 1c10 (rev b5) 00:1c.3 PCI bridge: Intel Corporation Device 1c16 (rev b5) 01:00.0 Network controller: Atheros Communications Inc. Device 0030 (rev 01) 02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B LUMPY with PCIe port coalesce enabled: 00:1c.0 PCI bridge: Intel Corporation Device 1c10 (rev b5) 00:1c.1 PCI bridge: Intel Corporation Device 1c16 (rev b5) 01:00.0 Network controller: Atheros Communications Inc. Device 0030 (rev 01) 02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B Change-Id: I828aa407fdc9c156c1c42eda8e2d893c0aa66eef Signed-off-by: Duncan Laurie --- src/southbridge/intel/bd82x6x/chip.h | 3 + src/southbridge/intel/bd82x6x/pch.c | 196 ++++++++++++++++++++++++++++++++-- src/southbridge/intel/bd82x6x/pch.h | 21 +++- 3 files changed, 206 insertions(+), 14 deletions(-) diff --git a/src/southbridge/intel/bd82x6x/chip.h b/src/southbridge/intel/bd82x6x/chip.h index 2786d72..880244b 100644 --- a/src/southbridge/intel/bd82x6x/chip.h +++ b/src/southbridge/intel/bd82x6x/chip.h @@ -72,6 +72,9 @@ struct southbridge_intel_bd82x6x_config { uint32_t gen2_dec; uint32_t gen3_dec; uint32_t gen4_dec; + + /* Enable linear PCIe Root Port function numbers starting at zero */ + uint8_t pcie_port_coalesce; }; extern struct chip_operations southbridge_intel_bd82x6x_ops; diff --git a/src/southbridge/intel/bd82x6x/pch.c b/src/southbridge/intel/bd82x6x/pch.c index e83c2e6..5f440e6 100644 --- a/src/southbridge/intel/bd82x6x/pch.c +++ b/src/southbridge/intel/bd82x6x/pch.c @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2008-2009 coresystems GmbH + * Copyright (C) 2012 The Chromium OS Authors. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -25,6 +26,7 @@ #include "pch.h" static int pch_revision_id = -1; +static int pch_type = -1; int pch_silicon_revision(void) { @@ -35,6 +37,40 @@ int pch_silicon_revision(void) return pch_revision_id; } +int pch_silicon_type(void) +{ + if (pch_type < 0) + pch_type = pci_read_config8( + dev_find_slot(0, PCI_DEVFN(0x1f, 0)), + PCI_DEVICE_ID + 1); + return pch_type; +} + +int pch_silicon_supported(int type, int rev) +{ + int cur_type = pch_silicon_type(); + int cur_rev = pch_silicon_revision(); + + switch (type) { + case PCH_TYPE_CPT: + /* CougarPoint minimum revision */ + if (cur_type == PCH_TYPE_CPT && cur_rev >= rev) + return 1; + /* PantherPoint any revision */ + if (cur_type == PCH_TYPE_PPT) + return 1; + break; + + case PCH_TYPE_PPT: + /* PantherPoint minimum revision */ + if (cur_type == PCH_TYPE_PPT && cur_rev >= rev) + return 1; + break; + } + + return 0; +} + /* Set bit in Function Disble register to hide this device */ static void pch_hide_devfn(unsigned devfn) { @@ -119,7 +155,7 @@ void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue) RCBA32(IOBPIRI) = address; /* READ OPCODE */ - if (pch_silicon_revision() >= PCH_STEP_B0) + if (pch_silicon_supported(PCH_TYPE_CPT, PCH_STEP_B0)) RCBA32(IOBPS) = IOBPS_RW_BX; else RCBA32(IOBPS) = IOBPS_READ_AX; @@ -142,7 +178,7 @@ void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue) data |= orvalue; /* WRITE OPCODE */ - if (pch_silicon_revision() >= PCH_STEP_B0) + if (pch_silicon_supported(PCH_TYPE_CPT, PCH_STEP_B0)) RCBA32(IOBPS) = IOBPS_RW_BX; else RCBA32(IOBPS) = IOBPS_WRITE_AX; @@ -184,15 +220,85 @@ static int pch_pcie_check_set_enabled(device_t dev) return 0; } -void pch_enable(device_t dev) +/* RPFN is a write-once register so keep a copy until it is written */ +static u32 new_rpfn; + +/* Swap function numbers assigned to two PCIe Root Ports */ +static void pch_pcie_function_swap(u8 old_fn, u8 new_fn) +{ + u32 old_rpfn = new_rpfn; + + printk(BIOS_DEBUG, "PCH: Remap PCIe function %d to %d\n", + old_fn, new_fn); + + new_rpfn &= ~(RPFN_FNMASK(old_fn) | RPFN_FNMASK(new_fn)); + + /* Old function set to new function and disabled */ + new_rpfn |= RPFN_FNSET(old_fn, RPFN_FNGET(old_rpfn, new_fn)); + new_rpfn |= RPFN_FNSET(new_fn, RPFN_FNGET(old_rpfn, old_fn)); +} + +/* Update devicetree with new Root Port function number assignment */ +static void pch_pcie_devicetree_update(void) +{ + device_t dev; + + /* Update the function numbers in the static devicetree */ + for (dev = all_devices; dev; dev = dev->next) { + u8 new_devfn; + + /* Only care about PCH PCIe root ports */ + if (PCI_SLOT(dev->path.pci.devfn) != + PCH_PCIE_DEV_SLOT) + continue; + + /* Determine the new devfn for this port */ + new_devfn = PCI_DEVFN(PCH_PCIE_DEV_SLOT, + RPFN_FNGET(new_rpfn, + PCI_FUNC(dev->path.pci.devfn))); + + if (dev->path.pci.devfn != new_devfn) { + printk(BIOS_DEBUG, + "PCH: PCIe map %02x.%1x -> %02x.%1x\n", + PCI_SLOT(dev->path.pci.devfn), + PCI_FUNC(dev->path.pci.devfn), + PCI_SLOT(new_devfn), PCI_FUNC(new_devfn)); + + dev->path.pci.devfn = new_devfn; + } + } +} + +/* Special handling for PCIe Root Port devices */ +static void pch_pcie_enable(device_t dev) { + struct southbridge_intel_bd82x6x_config *config = dev->chip_info; u32 reg32; - if (!dev->enabled) { - printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev)); + /* + * Save a copy of the Root Port Function Number map when + * starting to walk the list of PCIe Root Ports so it can + * be updated locally and written out when the last port + * has been processed. + */ + if (PCI_FUNC(dev->path.pci.devfn) == 0) { + new_rpfn = RCBA32(RPFN); /* - * PCIE Power Savings for stepping B1+: + * Enable Root Port coalescing if the first port is disabled + * or the other devices will not be enumerated by the OS. + */ + if (!dev->enabled) + config->pcie_port_coalesce = 1; + + if (config->pcie_port_coalesce) + printk(BIOS_INFO, + "PCH: PCIe Root Port coalescing is enabled\n"); + } + + if (!dev->enabled) { + /* + * PCIE Power Savings for PantherPoint and CougarPoint/B1+ * * If PCIe 0-3 disabled set Function 0 0xE2[0] = 1 * If PCIe 4-7 disabled set Function 4 0xE2[0] = 1 @@ -201,21 +307,89 @@ void pch_enable(device_t dev) * because the pcie driver enable() handler is not * called unless the device is enabled. */ - if (pch_silicon_revision() >= PCH_STEP_B1 && - PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT && - (PCI_FUNC(dev->path.pci.devfn) == 0 || + if ((PCI_FUNC(dev->path.pci.devfn) == 0 || PCI_FUNC(dev->path.pci.devfn) == 4)) { - if (!pch_pcie_check_set_enabled(dev)) { + /* Handle workaround for PPT and CPT/B1+ */ + if (pch_silicon_supported(PCH_TYPE_CPT, PCH_STEP_B1) && + !pch_pcie_check_set_enabled(dev)) { u8 reg8 = pci_read_config8(dev, 0xe2); reg8 |= 1; pci_write_config8(dev, 0xe2, reg8); } + + /* + * Enable Clock Gating for shared PCIe resources + * before disabling this particular port. + */ + pci_write_config8(dev, 0xe1, 0x3c); } /* Ensure memory, io, and bus master are all disabled */ reg32 = pci_read_config32(dev, PCI_COMMAND); reg32 &= ~(PCI_COMMAND_MASTER | - PCI_COMMAND_MEMORY | PCI_COMMAND_IO ); + PCI_COMMAND_MEMORY | PCI_COMMAND_IO); + pci_write_config32(dev, PCI_COMMAND, reg32); + + /* Do not claim downstream transactions for PCIe ports */ + new_rpfn |= RPFN_HIDE(PCI_FUNC(dev->path.pci.devfn)); + + /* Hide this device if possible */ + pch_hide_devfn(dev->path.pci.devfn); + } else { + int fn; + + /* + * Check if there is a lower disabled port to swap with this + * port in order to maintain linear order starting at zero. + */ + if (config->pcie_port_coalesce) { + for (fn=0; fn < PCI_FUNC(dev->path.pci.devfn); fn++) { + if (!(new_rpfn & RPFN_HIDE(fn))) + continue; + + /* Swap places with this function */ + pch_pcie_function_swap( + PCI_FUNC(dev->path.pci.devfn), fn); + break; + } + } + + /* Enable SERR */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 |= PCI_COMMAND_SERR; + pci_write_config32(dev, PCI_COMMAND, reg32); + } + + /* + * When processing the last PCIe root port we can now + * update the Root Port Function Number and Hide register. + */ + if (PCI_FUNC(dev->path.pci.devfn) == 7) { + printk(BIOS_SPEW, "PCH: RPFN 0x%08x -> 0x%08x\n", + RCBA32(RPFN), new_rpfn); + RCBA32(RPFN) = new_rpfn; + + /* Update static devictree with new function numbers */ + if (config->pcie_port_coalesce) + pch_pcie_devicetree_update(); + } +} + +void pch_enable(device_t dev) +{ + u32 reg32; + + /* PCH PCIe Root Ports get special handling */ + if (PCI_SLOT(dev->path.pci.devfn) == PCH_PCIE_DEV_SLOT) + return pch_pcie_enable(dev); + + if (!dev->enabled) { + printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev)); + + /* Ensure memory, io, and bus master are all disabled */ + reg32 = pci_read_config32(dev, PCI_COMMAND); + reg32 &= ~(PCI_COMMAND_MASTER | + PCI_COMMAND_MEMORY | PCI_COMMAND_IO); pci_write_config32(dev, PCI_COMMAND, reg32); /* Hide this device if possible */ diff --git a/src/southbridge/intel/bd82x6x/pch.h b/src/southbridge/intel/bd82x6x/pch.h index 80b09e2..7b646f3 100644 --- a/src/southbridge/intel/bd82x6x/pch.h +++ b/src/southbridge/intel/bd82x6x/pch.h @@ -2,7 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2008-2009 coresystems GmbH - * Copyright (C) 2011 Google Inc. + * Copyright (C) 2012 The Chromium OS Authors. All rights reserved. * * 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 @@ -21,6 +21,10 @@ #ifndef SOUTHBRIDGE_INTEL_BD82X6X_PCH_H #define SOUTHBRIDGE_INTEL_BD82X6X_PCH_H +/* PCH types */ +#define PCH_TYPE_CPT 0x1c /* CougarPoint */ +#define PCH_TYPE_PPT 0x1e /* IvyBridge */ + /* PCH stepping values for LPC device */ #define PCH_STEP_A0 0 #define PCH_STEP_A1 1 @@ -57,6 +61,8 @@ void intel_pch_finalize_smm(void); #if !defined(__PRE_RAM__) && !defined(__SMM__) #include "chip.h" int pch_silicon_revision(void); +int pch_silicon_type(void); +int pch_silicon_supported(int type, int rev); void pch_enable(device_t dev); void pch_iobp_update(u32 address, u32 andvalue, u32 orvalue); #else @@ -270,8 +276,17 @@ int smbus_read_byte(unsigned device, unsigned address); #define RP6D 0x0180 /* 32bit */ #define RP6BA 0x0188 /* 64bit */ -#define RPC 0x0224 /* 32bit */ -#define RPFN 0x0238 /* 32bit */ +#define RPC 0x0400 /* 32bit */ +#define RPFN 0x0404 /* 32bit */ + +/* Root Port configuratinon space hide */ +#define RPFN_HIDE(port) (1 << (((port) * 4) + 3)) +/* Get the function number assigned to a Root Port */ +#define RPFN_FNGET(reg,port) (((reg) >> ((port) * 4)) & 7) +/* Set the function number for a Root Port */ +#define RPFN_FNSET(port,func) (((func) & 7) << ((port) * 4)) +/* Root Port function number mask */ +#define RPFN_FNMASK(port) (7 << ((port) * 4)) #define TRSR 0x1e00 /* 8bit */ #define TRCR 0x1e10 /* 64bit */ From gerrit at coreboot.org Tue May 1 01:50:40 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 01:50:40 +0200 Subject: [coreboot] New patch to review for coreboot: aea1621 Fix issue with PCIe power management setup References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/980 -gerrit commit aea1621bd1489a910483d2858dc5810c8d48207e Author: Duncan Laurie Date: Fri Apr 27 10:58:22 2012 -0700 Fix issue with PCIe power management setup The current early PM setup that attempts to configure dynamic clock gating relies on PCIe functions to be enabled that may not be. Instead of reading port 0 or 4 directly to determine the link width use the register that refelects the soft strapping options as this will always be available. Also add a clear register assignment and break for port 0 in the switch statement instead of falling through to port 4 as that could end up setting the slot power limit based on port 4 values instead of based on port 0. register 0xE1=0x3f and all other root ports should have 0xE1=0x03. When port 0 and 4 are disabled they will have 0xE1=0x3C before being disabled by the pch enable handler. LUMPY default: 00:1c.0 PCI bridge: Intel Corporation Device 1c10 (rev b5) 00:1c.3 PCI bridge: Intel Corporation Device 1c16 (rev b5) pci_read8 0 0x1c 0 0xe1 0x3f pci_read8 0 0x1c 3 0xe1 0x03 LUMPY with PCIe port coalesce enabled: 00:1c.0 PCI bridge: Intel Corporation Device 1c10 (rev b5) 00:1c.1 PCI bridge: Intel Corporation Device 1c16 (rev b5) pci_read8 0 0x1c 0 0xe1 0x3f pci_read8 0 0x1c 1 0xe1 0x03 Change-Id: I33a37b0ec0c8e570cf5d9dda2c06e0225fee135c Signed-off-by: Duncan Laurie --- src/southbridge/intel/bd82x6x/pcie.c | 44 ++++++++++++++++++++++++---------- 1 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/southbridge/intel/bd82x6x/pcie.c b/src/southbridge/intel/bd82x6x/pcie.c index 599692d..5ab18f6 100644 --- a/src/southbridge/intel/bd82x6x/pcie.c +++ b/src/southbridge/intel/bd82x6x/pcie.c @@ -25,17 +25,6 @@ #include #include "pch.h" -static u16 pcie_port_link_width(int port) -{ - u16 link_width; - - link_width = pci_read_config16( - dev_find_slot(0, PCI_DEVFN(0x1c, port)), 0x52); - link_width >>= 4; - link_width &= 0x3f; - return link_width; -} - static void pch_pcie_pm_early(struct device *dev) { u16 link_width_p0, link_width_p4; @@ -43,8 +32,35 @@ static void pch_pcie_pm_early(struct device *dev) u32 reg32; u8 reg8; - link_width_p0 = pcie_port_link_width(0); - link_width_p4 = pcie_port_link_width(4); + reg32 = RCBA32(RPC); + + /* Port 0-3 link aggregation from PCIEPCS1[1:0] soft strap */ + switch (reg32 & 3) { + case 3: + link_width_p0 = 4; + break; + case 1: + case 2: + link_width_p0 = 2; + break; + case 0: + default: + link_width_p0 = 1; + } + + /* Port 4-7 link aggregation from PCIEPCS2[1:0] soft strap */ + switch ((reg32 >> 2) & 3) { + case 3: + link_width_p4 = 4; + break; + case 1: + case 2: + link_width_p4 = 2; + break; + case 0: + default: + link_width_p4 = 1; + } /* Enable dynamic clock gating where needed */ reg8 = pci_read_config8(dev, 0xe1); @@ -54,6 +70,8 @@ static void pch_pcie_pm_early(struct device *dev) slot_power_limit = 40; /* 40W for x4 */ else if (link_width_p0 == 2) slot_power_limit = 20; /* 20W for x2 */ + reg8 |= 0x3f; + break; case 4: /* Port 4 */ if (link_width_p4 == 4) slot_power_limit = 40; /* 40W for x4 */ From gerrit at coreboot.org Tue May 1 02:49:19 2012 From: gerrit at coreboot.org (Martin Roth (martin@se-eng.com)) Date: Tue, 1 May 2012 02:49:19 +0200 Subject: [coreboot] New patch to review for coreboot: f7738ff Add simple PMIO & PMIO2 read/write routines to CIMX wrapper References: Message-ID: Martin Roth (martin at se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/981 -gerrit commit f7738ffdbf221cb4ae80ce3172e8dfa3a54e043d Author: Martin Roth Date: Sat Apr 28 10:25:20 2012 -0600 Add simple PMIO & PMIO2 read/write routines to CIMX wrapper These are the PMIO & PMIO2 read & write routines from src/southbridge/amd/sb800/sb800.c & sb800.h for use in the cimx tree. Currently most platforms using CIMX are calling WritePMIO() directly from the src/vendorcode/amd/cimx/sbX00 directories instead of using a wrapper function. These functions only do byte reads & writes. Change-Id: I881a6e2d4ddbba3dbdf4dd33e06313fe88b3682a Signed-off-by: Martin L Roth --- src/southbridge/amd/cimx/Makefile.inc | 4 ++ src/southbridge/amd/cimx/cimx_util.c | 52 +++++++++++++++++++++++++++++++++ src/southbridge/amd/cimx/cimx_util.h | 36 ++++++++++++++++++++++ 3 files changed, 92 insertions(+), 0 deletions(-) diff --git a/src/southbridge/amd/cimx/Makefile.inc b/src/southbridge/amd/cimx/Makefile.inc index 80c6378..a9ea8b9 100644 --- a/src/southbridge/amd/cimx/Makefile.inc +++ b/src/southbridge/amd/cimx/Makefile.inc @@ -19,3 +19,7 @@ subdirs-$(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB700) += sb700 subdirs-$(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB800) += sb800 subdirs-$(CONFIG_SOUTHBRIDGE_AMD_CIMX_SB900) += sb900 + +romstage-y += cimx_util.c + +ramstage-y += cimx_util.c diff --git a/src/southbridge/amd/cimx/cimx_util.c b/src/southbridge/amd/cimx/cimx_util.c new file mode 100755 index 0000000..ca4c86a --- /dev/null +++ b/src/southbridge/amd/cimx/cimx_util.c @@ -0,0 +1,52 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Advanced Micro Devices, Inc. + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include "cimx_util.h" + +static void pmio_write_index(u16 port_base, u8 reg, u8 value) +{ + outb(reg, port_base); + outb(value, port_base + 1); +} + +static u8 pmio_read_index(u16 port_base, u8 reg) +{ + outb(reg, port_base); + return inb(port_base + 1); +} + +void pm_iowrite(u8 reg, u8 value) +{ + pmio_write_index(PM_INDEX, reg, value); +} + +u8 pm_ioread(u8 reg) +{ + return pmio_read_index(PM_INDEX, reg); +} + +void pm2_iowrite(u8 reg, u8 value) +{ + pmio_write_index(PM2_INDEX, reg, value); +} + +u8 pm2_ioread(u8 reg) +{ + return pmio_read_index(PM2_INDEX, reg); +} diff --git a/src/southbridge/amd/cimx/cimx_util.h b/src/southbridge/amd/cimx/cimx_util.h new file mode 100755 index 0000000..4ef534c --- /dev/null +++ b/src/southbridge/amd/cimx/cimx_util.h @@ -0,0 +1,36 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2010 Advanced Micro Devices, Inc. + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef CIMX_UTIL_H +#define CIMX_UTIL_H + +#include + +/* Power management index/data registers */ +#define PM_INDEX 0xcd6 +#define PM_DATA 0xcd7 +#define PM2_INDEX 0xcd0 +#define PM2_DATA 0xcd1 + +void pm_iowrite(u8 reg, u8 value); +u8 pm_ioread(u8 reg); +void pm2_iowrite(u8 reg, u8 value); +u8 pm2_ioread(u8 reg); + +#endif /* CIMX_UTIL_H */ From gerrit at coreboot.org Tue May 1 06:23:36 2012 From: gerrit at coreboot.org (Vadim Bendebury (vbendeb@chromium.org)) Date: Tue, 1 May 2012 06:23:36 +0200 Subject: [coreboot] New patch to review for coreboot: 9297200 Allow device ID arrays in the PCI driver structure References: Message-ID: Vadim Bendebury (vbendeb at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/982 -gerrit commit 929720020030761885433ef7027005480812424b Author: Vadim Bendebury Date: Tue Apr 24 12:53:19 2012 -0700 Allow device ID arrays in the PCI driver structure Many PCI devices share the very same driver despite having different PCI device IDs, which causes a lot of copy and paste of driver definitions. This change introduces a way to specify the array of acceptable device IDs in a single driver entry. As an example the Intel {Sandy|Ivy} Bridge SATA driver is being modified to use a single driver structure for all different SATA controller flavors, a few more Ivy Bridge IDs are being added as well. BUG=none TEST=manual . modified coreboot brought up an Ivy Bridge platform all the way to Linux login screen. Change-Id: I761c5611b93ef946053783f7a755e6c456dd6991 Signed-off-by: Vadim Bendebury --- src/devices/pci_device.c | 24 +++++++++++++++++++++++- src/include/device/pci.h | 1 + src/southbridge/intel/bd82x6x/sata.c | 27 ++++----------------------- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c index c055995..c9af7c4 100644 --- a/src/devices/pci_device.c +++ b/src/devices/pci_device.c @@ -796,6 +796,28 @@ static struct device_operations *get_pci_bridge_ops(device_t dev) } /** + * Check if a device id matches a PCI driver entry. + * + * The driver entry can either point at a zero terminated array of acceptable + * device IDs, or include a single device ID. + * + * @driver pointer to the PCI driver entry being checked + * @device_id PCI device ID of the device being matched + */ +static int device_id_match(struct pci_driver *driver, unsigned short device_id) +{ + if (driver->devices) { + unsigned short check_id; + const unsigned short *device_list = driver->devices; + while ((check_id = *device_list++) != 0) + if (check_id == device_id) + return 1; + } + + return (driver->device == device_id); +} + +/** * Set up PCI device operation. * * Check if it already has a driver. If not, use find_device_operations(), @@ -817,7 +839,7 @@ static void set_pci_ops(struct device *dev) */ for (driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) { if ((driver->vendor == dev->vendor) && - (driver->device == dev->device)) { + device_id_match(driver, dev->device)) { dev->ops = (struct device_operations *)driver->ops; printk(BIOS_SPEW, "%s [%04x/%04x] %sops\n", dev_path(dev), driver->vendor, driver->device, diff --git a/src/include/device/pci.h b/src/include/device/pci.h index d4cfb85..e864d6d 100644 --- a/src/include/device/pci.h +++ b/src/include/device/pci.h @@ -42,6 +42,7 @@ struct pci_driver { const struct device_operations *ops; unsigned short vendor; unsigned short device; + const unsigned short *devices; }; #define __pci_driver __attribute__ ((used,__section__(".rodata.pci_driver"))) diff --git a/src/southbridge/intel/bd82x6x/sata.c b/src/southbridge/intel/bd82x6x/sata.c index 057b882..fef12cd 100644 --- a/src/southbridge/intel/bd82x6x/sata.c +++ b/src/southbridge/intel/bd82x6x/sata.c @@ -215,32 +215,13 @@ static struct device_operations sata_ops = { .ops_pci = &sata_pci_ops, }; +static const unsigned short all_dev_ids[] = { 0x1c00, 0x1c01, 0x1c02, 0x1c03, + 0x1e00, 0x1e01, 0x1e02, 0x1e03, + 0 }; /* Non-AHCI and Non-RAID Mode */ static const struct pci_driver pch_sata_normal_driver __pci_driver = { .ops = &sata_ops, .vendor = PCI_VENDOR_ID_INTEL, - .device = 0x1c00, -}; -static const struct pci_driver pch_sata_mobile_normal_driver __pci_driver = { - .ops = &sata_ops, - .vendor = PCI_VENDOR_ID_INTEL, - .device = 0x1c01, -}; - -/* AHCI Mode */ -static const struct pci_driver pch_sata_ahci_driver __pci_driver = { - .ops = &sata_ops, - .vendor = PCI_VENDOR_ID_INTEL, - .device = 0x1c02, -}; -static const struct pci_driver pch_sata_mobile_ahci_driver __pci_driver = { - .ops = &sata_ops, - .vendor = PCI_VENDOR_ID_INTEL, - .device = 0x1c03, -}; -static const struct pci_driver pch_sata_mobile_ahci_driver_a __pci_driver = { - .ops = &sata_ops, - .vendor = PCI_VENDOR_ID_INTEL, - .device = 0x1e03, + .devices = all_dev_ids, }; From gerrit at coreboot.org Tue May 1 07:24:18 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 07:24:18 +0200 Subject: [coreboot] Patch merged into coreboot/master: 887793d Set up the Emerald Lake 2 SMI and SCI sources based on the schematic. References: Message-ID: the following patch was just integrated into master: commit 887793df39d78bcdab65cb965a98fcd31b88fca4 Author: Gabe Black Date: Thu Mar 29 17:58:52 2012 -0700 Set up the Emerald Lake 2 SMI and SCI sources based on the schematic. This sets up the SMI and SCI inputs on the PCH for Emerald Lake 2 based on my best interpretation of the schematic. It may not be correct, but it doesn't seem to cause any problems either. Change-Id: I21238b3853a92893ec7f08baa2a3ebd35c49dd97 Signed-off-by: Gabe Black Reviewed-By: Patrick Georgi at Tue May 1 07:24:16 2012, giving +2 See http://review.coreboot.org/964 for details. -gerrit From gerrit at coreboot.org Tue May 1 11:35:24 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 11:35:24 +0200 Subject: [coreboot] Patch merged into coreboot/master: 63385c6 Make geode_lx use the vsa from blobs repository References: Message-ID: the following patch was just integrated into master: commit 63385c66126389fec8b6abc5923ec477442b360b Author: Patrick Georgi Date: Mon Apr 30 22:56:30 2012 +0200 Make geode_lx use the vsa from blobs repository ... or fail if repository is not enabled. Change-Id: I0a1e6d6fed852ec7edf96ace8346ae6b23838a56 Signed-off-by: Patrick Georgi See http://review.coreboot.org/959 for details. -gerrit From gerrit at coreboot.org Tue May 1 11:35:30 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 11:35:30 +0200 Subject: [coreboot] Patch merged into coreboot/master: e6089c3 Add vsa processor to cbfs-files References: Message-ID: the following patch was just integrated into master: commit e6089c31deb1712509edd11c15081a4a189b325a Author: Patrick Georgi Date: Mon Apr 30 23:15:17 2012 +0200 Add vsa processor to cbfs-files Change-Id: I548e86084acc51b0471160d37439385f524224cf Signed-off-by: Patrick Georgi See http://review.coreboot.org/960 for details. -gerrit From gerrit at coreboot.org Tue May 1 11:35:36 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 11:35:36 +0200 Subject: [coreboot] Patch merged into coreboot/master: 2558f47 Support adding stages with cbfs-files References: Message-ID: the following patch was just integrated into master: commit 2558f479d59042d9748ba931fa2436cc07faa933 Author: Patrick Georgi Date: Mon Apr 30 23:53:56 2012 +0200 Support adding stages with cbfs-files stages have special cbfstool syntax, which we need to support. Change-Id: I119255246af818f010acfc7ec2091a6184e74eb3 Signed-off-by: Patrick Georgi See http://review.coreboot.org/961 for details. -gerrit From gerrit at coreboot.org Tue May 1 11:35:42 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 11:35:42 +0200 Subject: [coreboot] Patch merged into coreboot/master: 68ae60f Move VSA support from x86 to Geode References: Message-ID: the following patch was just integrated into master: commit 68ae60f6d9bcef7e365a3a00fbe78111e7da7ee6 Author: Patrick Georgi Date: Mon Apr 30 23:56:58 2012 +0200 Move VSA support from x86 to Geode Instead of the special case in the generic Makefile.inc, use cbfs-files in the CPU directories. Change-Id: I71d9c8dff906c9a516ac0dd09a315f8956075592 Signed-off-by: Patrick Georgi See http://review.coreboot.org/962 for details. -gerrit From gerrit at coreboot.org Tue May 1 12:18:57 2012 From: gerrit at coreboot.org (Patrick Georgi (patrick@georgi-clan.de)) Date: Tue, 1 May 2012 12:18:57 +0200 Subject: [coreboot] New patch to review for coreboot: 1bf5cea Fix build with CMOS support on various platforms References: Message-ID: Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/983 -gerrit commit 1bf5cea9b5902d27029725611a947e09db529201 Author: Patrick Georgi Date: Tue May 1 12:10:45 2012 +0200 Fix build with CMOS support on various platforms When bringing in nvramtool as build_opt_tbl replacement, various platforms where left in the cold that don't provide direct IO support from userland (or at least not in a way we support). Build nvramtool without CMOS support when done as part of a coreboot build. We don't need to touch CMOS in this case. Change-Id: Icc88d1d32f10384867a5d44b065f9aa119bb0d50 Signed-off-by: Patrick Georgi --- util/nvramtool/Makefile | 2 +- util/nvramtool/Makefile.inc | 2 +- util/nvramtool/cmos_lowlevel.c | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/util/nvramtool/Makefile b/util/nvramtool/Makefile index 063bb1a..6723a48 100644 --- a/util/nvramtool/Makefile +++ b/util/nvramtool/Makefile @@ -24,7 +24,7 @@ CC = gcc STRIP = strip INSTALL = /usr/bin/install PREFIX = /usr/local -CFLAGS = -O2 -g -Wall -W -I. +CFLAGS = -O2 -g -Wall -W -I. -DCMOS_HAL=1 #CFLAGS = -Os -Wall CLI_OBJS = cli/nvramtool.o cli/opts.o diff --git a/util/nvramtool/Makefile.inc b/util/nvramtool/Makefile.inc index b356720..0acda04 100644 --- a/util/nvramtool/Makefile.inc +++ b/util/nvramtool/Makefile.inc @@ -37,7 +37,7 @@ nvramtoolobj := nvramtoolobj += cli/nvramtool.o cli/opts.o nvramtoolobj += cmos_lowlevel.o cmos_ops.o common.o compute_ip_checksum.o nvramtoolobj += hexdump.o input_file.o layout.o accessors/layout-common.o accessors/layout-text.o accessors/layout-bin.o lbtable.o -nvramtoolobj += reg_expr.o cbfs.o accessors/cmos-hw-unix.o accessors/cmos-mem.o +nvramtoolobj += reg_expr.o cbfs.o accessors/cmos-mem.o $(objutil)/nvramtool $(objutil)/nvramtool/accessors $(objutil)/nvramtool/cli: mkdir -p $@ diff --git a/util/nvramtool/cmos_lowlevel.c b/util/nvramtool/cmos_lowlevel.c index 58494f9..55b1879 100644 --- a/util/nvramtool/cmos_lowlevel.c +++ b/util/nvramtool/cmos_lowlevel.c @@ -39,14 +39,21 @@ /* Hardware Abstraction Layer: lowlevel byte-wise write access */ extern cmos_access_t cmos_hal, memory_hal; -static cmos_access_t *current_access = &cmos_hal; +static cmos_access_t *current_access = +#ifdef CMOS_HAL + &cmos_hal; +#else + &memory_hal; +#endif void select_hal(hal_t hal, void *data) { switch(hal) { +#ifdef CMOS_HAL case HAL_CMOS: current_access = &cmos_hal; break; +#endif case HAL_MEMORY: current_access = &memory_hal; break; From nachiketh at gmail.com Tue May 1 12:08:18 2012 From: nachiketh at gmail.com (Nachiketh G) Date: Tue, 1 May 2012 15:38:18 +0530 Subject: [coreboot] Grub2 for Coreboot In-Reply-To: References: Message-ID: Hi Gregg, You were spot an about updating my build tools, I did that and also downgraded to a different version of Grub2 from the repository(1.99) and I was able to compile it! I now have an elf file ready to integrate with Coreboot. Thanks! Regards, Nachiketh On Sun, Apr 29, 2012 at 2:26 AM, Gregg Levine wrote: > On Sat, Apr 28, 2012 at 4:53 PM, Nachiketh G wrote: > > Hi Greg, > > Please find the answers below: > > > > > > 1) What release of Grub2 did you select? (There are many numbered ones > > each running towards the 2.00 release one.) > >>> I checked out the latest version on > >>> http://bzr.savannah.gnu.org/r/grub/trunk/grub (Using bzr branch > >>> http://bzr.savannah.gnu.org/r/grub/trunk/grub) > > > > 2) Was this release of Grub2 retrieved from their storage point recently? > >>> Yes > > > > > > 3) Was Coreboot updated recently? > >>>I have checked out the latest copy of Coreboot from their repository as > >>> well, I have not yet compiled it though... thought I would compile the > >>> payload first before compiling Coreboot. > > > > > > 4) What is your build environment? What distribution is this on? > >>> I'm using a Ubuntu(2.6.38 Kernel) with a gcc (Ubuntu/Linaro > >>> 4.5.2-8ubuntu4) 4.5.2 compiler. > > > > Please let me know if there is something wrong in what I'm doing. > > Thanks! > > -Nachiketh > > > > > > On Sun, Apr 29, 2012 at 1:38 AM, Gregg Levine > > wrote: > >> > >> On Sat, Apr 28, 2012 at 3:07 PM, Nachiketh G > wrote: > >> > Hi Folks, > >> > I'm new on Coreboot and I'm trying to compile Grub2 as a payload for > >> > Coreboot. I'm following the steps provided under > >> > http://www.coreboot.org/Talk:GRUB2 and i'm getting the following > >> > compilation > >> > error: > >> > > >> > cc1: warnings being treated as errors > >> > kern/i386/coreboot/init.c:45:9: error: unknown option after '#pragma > GCC > >> > diagnostic' kind > >> > make[3]: *** [kern/i386/coreboot/kernel_exec-init.o] Error 1 > >> > make[3]: Leaving directory `/home/nachiketh/coreboot/grub/grub-core' > >> > make[2]: *** [all] Error 2 > >> > make[2]: Leaving directory `/home/nachiketh/coreboot/grub/grub-core' > >> > make[1]: *** [all-recursive] Error 1 > >> > make[1]: Leaving directory `/home/nachiketh/coreboot/grub' > >> > make: *** [all] Error 2 > >> > > >> > Please let me know what I'm doing wrong or is there any step that has > >> > got > >> > missed out which is causing this problem. > >> > Thanks in advance! > >> > > >> > Regards, > >> > Nachiketh > >> > > >> > -- > >> > coreboot mailing list: coreboot at coreboot.org > >> > http://www.coreboot.org/mailman/listinfo/coreboot > >> > >> Hello! > >> Let's start it out this way: > >> 1) What release of Grub2 did you select? (There are many numbered ones > >> each running towards the 2.00 release one.) > >> > >> 2) Was this release of Grub2 retrieved from their storage point > recently? > >> > >> 3) Was Coreboot updated recently? > >> > >> 4) What is your build environment? What distribution is this on? > >> ------ > >> Gregg C Levine gregg.drwho8 at gmail.com > >> "This signature fought the Time Wars, time and again." > > Hello! > About the only thing I can suggest is that there is yet another drift > to be explained inside the Ubuntu set you have. Please make sure your > build tools are properly updated. > > Also please consider keeping the list (both the help grub list and > this one) informed. > > ----- > Gregg C Levine gregg.drwho8 at gmail.com > "This signature fought the Time Wars, time and again." > > -- > coreboot mailing list: coreboot at coreboot.org > http://www.coreboot.org/mailman/listinfo/coreboot > -------------- next part -------------- An HTML attachment was scrubbed... URL: From desired.mta at gmail.com Tue May 1 16:03:33 2012 From: desired.mta at gmail.com (=?UTF-8?Q?Motiejus_Jak=C5=A1tys?=) Date: Tue, 1 May 2012 15:03:33 +0100 Subject: [coreboot] bluetooth on Thinkpad X60s Message-ID: Hi, bluetooth was not working for me on Thinkpad X60s. Rfkill was not showing the device and the bluetooth led was off. The way I managed to make it work is with this patch: diff --git a/src/ec/lenovo/h8/h8.c b/src/ec/lenovo/h8/h8.c index ecd34b2..b13d687 100644 --- a/src/ec/lenovo/h8/h8.c +++ b/src/ec/lenovo/h8/h8.c @@ -151,8 +151,7 @@ static void h8_enable(device_t dev) ec_write(H8_VOLUME_CONTROL, val); - if (!get_option(&val, "bluetooth")) - h8_bluetooth_enable(val); + h8_bluetooth_enable(1); if (!get_option(&val, "first_battery")) { tmp = ec_read(H8_CONFIG3); What would be a better way to do it? -- Motiejus Jak?tys From patrick at georgi-clan.de Tue May 1 17:18:27 2012 From: patrick at georgi-clan.de (Patrick Georgi) Date: Tue, 01 May 2012 17:18:27 +0200 Subject: [coreboot] bluetooth on Thinkpad X60s In-Reply-To: References: Message-ID: <4F9FFEC3.1020102@georgi-clan.de> Am Dienstag, 1. Mai 2012 16:03:33 schrieb Motiejus Jak?tys: > - if (!get_option(&val, "bluetooth")) > - h8_bluetooth_enable(val); > + h8_bluetooth_enable(1); > What would be a better way to do it? val = 1; get_option(&val, "bluetooth"); h8_bluetooth_enable(val); get_option only updates the value pointed to by the first argument if there's something to update to (CMOS use must be enabled _and_ CMOS must contain valid data). Otherwise it's kept as is. Regards, Patrick From gerrit at coreboot.org Tue May 1 19:27:37 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 19:27:37 +0200 Subject: [coreboot] Patch merged into coreboot/master: faffebf Fix Sandybridge/Ivybridge mainboards according to code review References: Message-ID: the following patch was just integrated into master: commit faffebf1bf40107559cf965e5d547c2a82d6db87 Author: Stefan Reinauer Date: Mon Apr 30 14:57:51 2012 -0700 Fix Sandybridge/Ivybridge mainboards according to code review This fixes a few cosmetics with the following three boards: - Intel Emerald Lake 2 - Samsung ChromeBook - Samsung ChromeBox The following issues were fixed: - rely on include path in ASL code instead of specifying relative paths - use updated ALIGN_CURRENT in acpi_tables.c - use preprocessor defines instead of hard coded values where possible Change-Id: Ia5941be3873aa84c30c13ff2f0428d1c52daa563 Signed-off-by: Stefan Reinauer Build-Tested: build bot (Jenkins) at Tue May 1 02:48:50 2012, giving +1 See http://review.coreboot.org/963 for details. -gerrit From gerrit at coreboot.org Tue May 1 19:54:08 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 19:54:08 +0200 Subject: [coreboot] Patch merged into coreboot/master: d7f3d69 Allow more CPU cores on Emerald Lake 2 CRB References: Message-ID: the following patch was just integrated into master: commit d7f3d6996e3d67f69533a69d773e4fde897d347a Author: Stefan Reinauer Date: Wed Mar 28 13:19:15 2012 -0700 Allow more CPU cores on Emerald Lake 2 CRB The Emerald Lake 2 CRB can potentially have more than 8 CPU cores, so update the number of max cores accordingly. Change-Id: Ia42ed8a84916f66dfbfdf2a72cbbed5cea61899b Signed-off-by: Stefan Reinauer Build-Tested: build bot (Jenkins) at Tue May 1 03:27:01 2012, giving +1 See http://review.coreboot.org/966 for details. -gerrit From gerrit at coreboot.org Tue May 1 19:36:08 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 19:36:08 +0200 Subject: [coreboot] Patch merged into coreboot/master: db4ce07 Set up ChromeOS dev mode, recovery, and write protect GPIOs on Emerald Lake 2. References: Message-ID: the following patch was just integrated into master: commit db4ce0735688cb695465e162974d88f95e8a4833 Author: Gabe Black Date: Thu Mar 29 18:04:56 2012 -0700 Set up ChromeOS dev mode, recovery, and write protect GPIOs on Emerald Lake 2. The Emerald Lake 2 CRB wasn't designed with ChromeOS in mind, so there aren't any actual developer mode, recovery mode, or write protect switches, let alone GPIOs to read them from. Instead, I've commandeered signals connected to GPIOs which are for other things but which aren't used by hardware or, for instance, the EC to do something Coreboot doesn't control. The recovery mode switch is connected to GPIO 22 and is called BIOS_REC on the schematic. The name is at least very reminiscent of the right thing even if it's supposed to be used for something else. There's a jumper on the board labelled J8G1 which can force the line to ground, and if not, there's a switch on the front of the case which toggles its value. "RECOVER" is for recovery mode and "KEEP" is for normal mode. The developer mode switch is connected to GPIO 57 and is called SV_DET on the schematic. It's connected to a jumper labelled J8E2 on the board and, as far as I can tell, can't be controlled in any other way. When the jumper is in place and the pins are shorted, developer mode is selected. When the jumper is removed, normal mode is selected. The write protect is connected to GPIO 48 which is called BIOS_RESP on the schematic. It's connected to a jumper labelled J8E3 which, like j8E2, seems to be the only way to control the line it's on. When the jumper is in place, write protect is "disabled", and when it's in place it's "enabled" even though there's no functional difference. The input for the recovery mode switch was chosen because of the name it already had on the CRB, BIOS recovery, and because there's a switch to control it on the front of the case which makes it easy to get at. The jumpers for developer mode and recovery mode were chosen because there weren't very many options available, and of those these were next to each other which should make them easier to find and work with. It might be a good idea to wire toggle switches up to the pins of those jumpers so they'll be easy to identify, can be labelled, and would be easier to work with than little jumpers in the middle of the motherboard. Change-Id: Ib2c3dc05077dacfbede596dae143ed81a99dbebd Signed-off-by: Gabe Black Build-Tested: build bot (Jenkins) at Tue May 1 03:15:02 2012, giving +1 See http://review.coreboot.org/965 for details. -gerrit From gerrit at coreboot.org Tue May 1 20:03:25 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 20:03:25 +0200 Subject: [coreboot] Patch merged into coreboot/master: ea39273 Clean up Emerald Lake 2 mainboard directory References: Message-ID: the following patch was just integrated into master: commit ea39273f80f64da5992b79e86ec950d6e0a3b420 Author: Gabe Black Date: Fri Mar 30 14:33:02 2012 -0700 Clean up Emerald Lake 2 mainboard directory Change-Id: I4a64a56dda22050a31232807096e15565a665377 Signed-off-by: Gabe Black Build-Tested: build bot (Jenkins) at Tue May 1 03:39:13 2012, giving +1 See http://review.coreboot.org/967 for details. -gerrit From gerrit at coreboot.org Tue May 1 20:04:59 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 20:04:59 +0200 Subject: [coreboot] Patch merged into coreboot/master: 9297200 Allow device ID arrays in the PCI driver structure References: Message-ID: the following patch was just integrated into master: commit 929720020030761885433ef7027005480812424b Author: Vadim Bendebury Date: Tue Apr 24 12:53:19 2012 -0700 Allow device ID arrays in the PCI driver structure Many PCI devices share the very same driver despite having different PCI device IDs, which causes a lot of copy and paste of driver definitions. This change introduces a way to specify the array of acceptable device IDs in a single driver entry. As an example the Intel {Sandy|Ivy} Bridge SATA driver is being modified to use a single driver structure for all different SATA controller flavors, a few more Ivy Bridge IDs are being added as well. BUG=none TEST=manual . modified coreboot brought up an Ivy Bridge platform all the way to Linux login screen. Change-Id: I761c5611b93ef946053783f7a755e6c456dd6991 Signed-off-by: Vadim Bendebury Reviewed-By: Patrick Georgi at Tue May 1 20:01:39 2012, giving +2 See http://review.coreboot.org/982 for details. -gerrit From gerrit at coreboot.org Tue May 1 20:05:13 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 20:05:13 +0200 Subject: [coreboot] Patch merged into coreboot/master: e1b81de add new LPC controller device ID value References: Message-ID: the following patch was just integrated into master: commit e1b81deaf1c17cb2c6723b8a35a595e0e6edf162 Author: Vadim Bendebury Date: Sat Apr 7 02:11:36 2012 +0000 add new LPC controller device ID value This adds the PCI device id of the LPC controller identifying the QPRJ/QS stepping of the Panther Point southbridge. Change-Id: Idcaa7dbd30224e3690ea469c6cb74f75de287631 Signed-off-by: Vadim Bendebury Build-Tested: build bot (Jenkins) at Tue May 1 03:52:28 2012, giving +1 See http://review.coreboot.org/968 for details. -gerrit From gerrit at coreboot.org Tue May 1 20:05:17 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 20:05:17 +0200 Subject: [coreboot] Patch merged into coreboot/master: e3e901d Modify DMI init for IvyBridge References: Message-ID: the following patch was just integrated into master: commit e3e901db657591603411402a1ceb581873480442 Author: Vincent Palatin Date: Wed Mar 28 16:10:29 2012 -0700 Modify DMI init for IvyBridge The ASPM setting for the Direct Media Interface should no longer be done on Ivybridge/PantherPoint based systems. Change-Id: Id30de1beb1b162564048e76712736ccf7049dc7c Signed-off-by: Vincent Palatin Build-Tested: build bot (Jenkins) at Tue May 1 04:08:11 2012, giving +1 See http://review.coreboot.org/969 for details. -gerrit From gerrit at coreboot.org Tue May 1 20:05:47 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 20:05:47 +0200 Subject: [coreboot] Patch merged into coreboot/master: 448a583 Only send ME Dram Init Done message on Sandybridge References: Message-ID: the following patch was just integrated into master: commit 448a58332fe61afe811862167486c6ec291963ba Author: Duncan Laurie Date: Mon Apr 9 12:30:43 2012 -0700 Only send ME Dram Init Done message on Sandybridge This is done inside the SystemAgent binary on Ivybridge. Change-Id: I8fb0f593a65a4803e160b284c21b9d5021e2e4a0 Signed-off-by: Duncan Laurie Build-Tested: build bot (Jenkins) at Tue May 1 04:21:51 2012, giving +1 See http://review.coreboot.org/970 for details. -gerrit From gerrit at coreboot.org Tue May 1 20:06:45 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 20:06:45 +0200 Subject: [coreboot] Patch merged into coreboot/master: dc5c7e0 Don't disable ACPI in the S3 resume path References: Message-ID: the following patch was just integrated into master: commit dc5c7e0b63d9b8b3429ae6fb929cbb39efec4159 Author: Duncan Laurie Date: Mon Apr 9 12:31:43 2012 -0700 Don't disable ACPI in the S3 resume path The OS does not re-execute the APMC 'enable ACPI' SMI on resume so this has the potential to leave things in an unknown state. Change-Id: Iaf0fcb99f699e9e0ecacaab3f529026782a95151 Signed-off-by: Duncan Laurie Build-Tested: build bot (Jenkins) at Tue May 1 04:35:21 2012, giving +1 See http://review.coreboot.org/971 for details. -gerrit From gerrit at coreboot.org Tue May 1 20:06:47 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 20:06:47 +0200 Subject: [coreboot] Patch merged into coreboot/master: d3884c8 Fix TPM driver to work with multiple vendor TPMs References: Message-ID: the following patch was just integrated into master: commit d3884c83a8cc31b3b3bae3eee92e4d429d4c8d52 Author: Stefan Reinauer Date: Mon Apr 30 16:33:44 2012 -0700 Fix TPM driver to work with multiple vendor TPMs Port u-boot patch for low-level driver: - Fix bug in traversal of vendor name list. - Sending "command ready" needs additional logic to handle TPMs that need that bit set twice: once to empty the read FIFOs and once to actualy set command ready. Change-Id: I57c280266b2e966c5b90e4f9e968426a33b93cf1 Signed-off-by: Duncan Laurie Build-Tested: build bot (Jenkins) at Tue May 1 04:49:36 2012, giving +1 See http://review.coreboot.org/972 for details. -gerrit From gerrit at coreboot.org Tue May 1 20:06:49 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 20:06:49 +0200 Subject: [coreboot] Patch merged into coreboot/master: 8f492d6 Update ivybridge graphics initialization References: Message-ID: the following patch was just integrated into master: commit 8f492d6c487068317267a59a9a47c9be7b72a543 Author: Duncan Laurie Date: Mon Apr 9 12:05:18 2012 -0700 Update ivybridge graphics initialization - Add config options to set backlight registers - Update powermeter weight tables for IvyBridge GT1 and add a new table for GT2 SKU - Fix a few registers used during GPU PM init sequence Change-Id: I1500bc07e3ba1bc10c77e7856089e716489dc07a Signed-off-by: Duncan Laurie Build-Tested: build bot (Jenkins) at Tue May 1 05:04:15 2012, giving +1 See http://review.coreboot.org/973 for details. -gerrit From gerrit at coreboot.org Tue May 1 20:07:06 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 20:07:06 +0200 Subject: [coreboot] Patch merged into coreboot/master: 20e11fc Update Ivybridge GT power meter tables References: Message-ID: the following patch was just integrated into master: commit 20e11fca1ae27e041e0c8a4a1a6f5a6b4f5c2a05 Author: Duncan Laurie Date: Thu Apr 12 16:02:43 2012 -0700 Update Ivybridge GT power meter tables - New table for GT1 - Updates to GT2 17W table - New table for GT2 35W SKU - New table for GT2 Other This also includes a workaround to poll on a different register when deasserting force wake. On some SKUs the kernel is hanging when bringing up graphics unless this register is also polled. Change-Id: I2badf62b464e901cfb0eaf4fc196f59111c71564 Signed-off-by: Duncan Laurie Build-Tested: build bot (Jenkins) at Tue May 1 05:17:44 2012, giving +1 See http://review.coreboot.org/974 for details. -gerrit From gerrit at coreboot.org Tue May 1 20:08:02 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 20:08:02 +0200 Subject: [coreboot] Patch merged into coreboot/master: 9bf656b Fix SATA port map to only enable port 0 References: Message-ID: the following patch was just integrated into master: commit 9bf656b94d245b89d388fc63ff5512f32ad7b4ee Author: Stefan Reinauer Date: Mon Apr 30 16:42:07 2012 -0700 Fix SATA port map to only enable port 0 The sata controller comes up in legacy/normal mode and is currently put into AHCI mode in romstage. If that is removed and the controller is left alone until the ramstage driver (like we do on Stumpy/Lumpy) then the resource allocator will have configured the device for IDE mode with an IO address in BAR5. Then when the ramstage driver puts the controller into AHCI mode it will not have the correct resources to do the rest of the AHCI setup. So the controller mode needs to be changed in the enable stage rather than in the init phase. This same register contains the port map and it is a R/WO (write once) field so the configured port map must be written at the same time. For non-AHCI mode the devicetree map was ignored before but it is used now. Since the port map register is now written at enable step it does not need to be written again during init. With this change the sata port map can be reduced to just port 0 and then U-boot does not have to probe all available ports. Change-Id: I977952cd88797ab4cea79202e832ecbb5c37e0bd Signed-off-by: Duncan Laurie Build-Tested: build bot (Jenkins) at Tue May 1 05:58:41 2012, giving +1 See http://review.coreboot.org/977 for details. -gerrit From gerrit at coreboot.org Tue May 1 20:17:57 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Tue, 1 May 2012 20:17:57 +0200 Subject: [coreboot] New patch to review for coreboot: 92e0b14 Drop CONFIG_MAX_PHYSICAL_CPUS on non-AMD boards References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/984 -gerrit commit 92e0b14eaf465478798f19734f31ea8e579a39f8 Author: Stefan Reinauer Date: Tue May 1 11:13:52 2012 -0700 Drop CONFIG_MAX_PHYSICAL_CPUS on non-AMD boards CONFIG_MAX_PHYSICAL_CPUS is defined by quite a number of mainboards whithout any code actually using the variable. Hence, drop MAX_PHYSICAL_CPUS from Kconfig for those boards. In the long run we should drop CONFIG_MAX_PHYSICAL_CPUS use completely and make the code dynamic or depend on CONFIG_MAX_CPUS instead. Change-Id: I37dcc74d245ddba5186b96bd82220dacb6f4d323 Signed-off-by: Stefan Reinauer --- src/cpu/Kconfig | 2 ++ src/mainboard/asus/p2b-d/Kconfig | 4 ---- src/mainboard/asus/p2b-ds/Kconfig | 4 ---- src/mainboard/getac/p470/Kconfig | 4 ---- src/mainboard/ibase/mb899/Kconfig | 4 ---- src/mainboard/intel/d945gclf/Kconfig | 4 ---- src/mainboard/intel/eagleheights/Kconfig | 4 ---- src/mainboard/intel/emeraldlake2/Kconfig | 4 ---- src/mainboard/intel/xe7501devkit/Kconfig | 4 ---- src/mainboard/kontron/986lcd-m/Kconfig | 4 ---- src/mainboard/lenovo/t60/Kconfig | 4 ---- src/mainboard/lenovo/x60/Kconfig | 4 ---- src/mainboard/roda/rk886ex/Kconfig | 4 ---- src/mainboard/tyan/s2735/Kconfig | 4 ---- 14 files changed, 2 insertions(+), 52 deletions(-) diff --git a/src/cpu/Kconfig b/src/cpu/Kconfig index ec10a97..acb9bb5 100644 --- a/src/cpu/Kconfig +++ b/src/cpu/Kconfig @@ -19,6 +19,8 @@ config DCACHE_RAM_GLOBAL_VAR_SIZE hex default 0x0 +# FIXME MAX_PHYSICAL_CPUS should move to AMD specific code, or better +# yet be dropped completely. config MAX_PHYSICAL_CPUS int default 1 diff --git a/src/mainboard/asus/p2b-d/Kconfig b/src/mainboard/asus/p2b-d/Kconfig index cb9a69a..337e3a0 100644 --- a/src/mainboard/asus/p2b-d/Kconfig +++ b/src/mainboard/asus/p2b-d/Kconfig @@ -49,8 +49,4 @@ config MAX_CPUS int default 2 -config MAX_PHYSICAL_CPUS - int - default 2 - endif # BOARD_ASUS_P2B_D diff --git a/src/mainboard/asus/p2b-ds/Kconfig b/src/mainboard/asus/p2b-ds/Kconfig index cd76e92..4585a22 100644 --- a/src/mainboard/asus/p2b-ds/Kconfig +++ b/src/mainboard/asus/p2b-ds/Kconfig @@ -49,8 +49,4 @@ config MAX_CPUS int default 2 -config MAX_PHYSICAL_CPUS - int - default 2 - endif # BOARD_ASUS_P2B_DS diff --git a/src/mainboard/getac/p470/Kconfig b/src/mainboard/getac/p470/Kconfig index 42ce0e0..b9ed04e 100644 --- a/src/mainboard/getac/p470/Kconfig +++ b/src/mainboard/getac/p470/Kconfig @@ -64,10 +64,6 @@ config MAX_CPUS int default 4 -config MAX_PHYSICAL_CPUS - int - default 2 - config VGA_BIOS_FILE string default "getac-pci8086,27a2.rom" diff --git a/src/mainboard/ibase/mb899/Kconfig b/src/mainboard/ibase/mb899/Kconfig index 58d1d99..28abf43 100644 --- a/src/mainboard/ibase/mb899/Kconfig +++ b/src/mainboard/ibase/mb899/Kconfig @@ -49,10 +49,6 @@ config MAX_CPUS int default 4 -config MAX_PHYSICAL_CPUS - int - default 2 - config VGA_BIOS_FILE string default "amipci_01.20" diff --git a/src/mainboard/intel/d945gclf/Kconfig b/src/mainboard/intel/d945gclf/Kconfig index 32ef3e1..32da387 100644 --- a/src/mainboard/intel/d945gclf/Kconfig +++ b/src/mainboard/intel/d945gclf/Kconfig @@ -62,8 +62,4 @@ config MAX_CPUS int default 4 -config MAX_PHYSICAL_CPUS - int - default 2 - endif # BOARD_INTEL_D945GCLF diff --git a/src/mainboard/intel/eagleheights/Kconfig b/src/mainboard/intel/eagleheights/Kconfig index 00aa1ae..7722ad2 100644 --- a/src/mainboard/intel/eagleheights/Kconfig +++ b/src/mainboard/intel/eagleheights/Kconfig @@ -51,8 +51,4 @@ config MAX_CPUS int default 4 -config MAX_PHYSICAL_CPUS - int - default 2 - endif # BOARD_INTEL_EAGLEHEIGHTS diff --git a/src/mainboard/intel/emeraldlake2/Kconfig b/src/mainboard/intel/emeraldlake2/Kconfig index 002ae2a..9e4f347 100644 --- a/src/mainboard/intel/emeraldlake2/Kconfig +++ b/src/mainboard/intel/emeraldlake2/Kconfig @@ -39,10 +39,6 @@ config MAX_CPUS int default 16 -config MAX_PHYSICAL_CPUS - int - default 8 - config VGA_BIOS_FILE string default "pci8086,0166.rom" diff --git a/src/mainboard/intel/xe7501devkit/Kconfig b/src/mainboard/intel/xe7501devkit/Kconfig index a743469..3f314a6 100644 --- a/src/mainboard/intel/xe7501devkit/Kconfig +++ b/src/mainboard/intel/xe7501devkit/Kconfig @@ -32,8 +32,4 @@ config MAX_CPUS int default 2 -config MAX_PHYSICAL_CPUS - int - default 2 - endif # BOARD_INTEL_XE7501DEVKIT diff --git a/src/mainboard/kontron/986lcd-m/Kconfig b/src/mainboard/kontron/986lcd-m/Kconfig index e50bf1f..322850e 100644 --- a/src/mainboard/kontron/986lcd-m/Kconfig +++ b/src/mainboard/kontron/986lcd-m/Kconfig @@ -42,10 +42,6 @@ config MAX_CPUS int default 4 -config MAX_PHYSICAL_CPUS - int - default 2 - config VGA_BIOS_FILE string default "amipci_01.20" diff --git a/src/mainboard/lenovo/t60/Kconfig b/src/mainboard/lenovo/t60/Kconfig index 8bb2d2d..062a459 100644 --- a/src/mainboard/lenovo/t60/Kconfig +++ b/src/mainboard/lenovo/t60/Kconfig @@ -52,8 +52,4 @@ config MAX_CPUS int default 2 -config MAX_PHYSICAL_CPUS - int - default 1 - endif diff --git a/src/mainboard/lenovo/x60/Kconfig b/src/mainboard/lenovo/x60/Kconfig index 3fdfe2f..d35ab03 100644 --- a/src/mainboard/lenovo/x60/Kconfig +++ b/src/mainboard/lenovo/x60/Kconfig @@ -53,8 +53,4 @@ config MAX_CPUS int default 2 -config MAX_PHYSICAL_CPUS - int - default 1 - endif diff --git a/src/mainboard/roda/rk886ex/Kconfig b/src/mainboard/roda/rk886ex/Kconfig index 53b475c..929e5e6 100644 --- a/src/mainboard/roda/rk886ex/Kconfig +++ b/src/mainboard/roda/rk886ex/Kconfig @@ -43,10 +43,6 @@ config MAX_CPUS int default 4 -config MAX_PHYSICAL_CPUS - int - default 2 - config MAXIMUM_SUPPORTED_FREQUENCY int default 400 diff --git a/src/mainboard/tyan/s2735/Kconfig b/src/mainboard/tyan/s2735/Kconfig index 9e1b57f..f908908 100644 --- a/src/mainboard/tyan/s2735/Kconfig +++ b/src/mainboard/tyan/s2735/Kconfig @@ -40,8 +40,4 @@ config MAX_CPUS int default 4 -config MAX_PHYSICAL_CPUS - int - default 2 - endif # BOARD_TYAN_S2735 From desired.mta at gmail.com Tue May 1 20:24:10 2012 From: desired.mta at gmail.com (=?UTF-8?Q?Motiejus_Jak=C5=A1tys?=) Date: Tue, 1 May 2012 19:24:10 +0100 Subject: [coreboot] bluetooth on Thinkpad X60s In-Reply-To: <4F9FFEC3.1020102@georgi-clan.de> References: <4F9FFEC3.1020102@georgi-clan.de> Message-ID: On Tue, May 1, 2012 at 16:18, Patrick Georgi wrote: > Am Dienstag, 1. Mai 2012 16:03:33 schrieb Motiejus Jak?tys: >> >> - ? ? ? if (!get_option(&val, "bluetooth")) >> - ? ? ? ? ? ? ? h8_bluetooth_enable(val); >> + ? ?h8_bluetooth_enable(1); >> What would be a better way to do it? > > val = 1; > get_option(&val, "bluetooth"); > h8_bluetooth_enable(val); > > get_option only updates the value pointed to by the first argument if > there's something to update to (CMOS use must be enabled _and_ CMOS must > contain valid data). Otherwise it's kept as is. Thanks. Do I understand it correctly that you have just sent a valid patch which could be included? -- Motiejus Jak?tys From patrick at georgi-clan.de Tue May 1 21:13:18 2012 From: patrick at georgi-clan.de (Patrick Georgi) Date: Tue, 01 May 2012 21:13:18 +0200 Subject: [coreboot] bluetooth on Thinkpad X60s In-Reply-To: References: <4F9FFEC3.1020102@georgi-clan.de> Message-ID: <4FA035CE.9080202@georgi-clan.de> Am Di 01 Mai 2012 20:24:10 CEST schrieb Motiejus Jak?tys: > On Tue, May 1, 2012 at 16:18, Patrick Georgi wrote: >> val = 1; >> get_option(&val, "bluetooth"); >> h8_bluetooth_enable(val); >> >> get_option only updates the value pointed to by the first argument if >> there's something to update to (CMOS use must be enabled _and_ CMOS must >> contain valid data). Otherwise it's kept as is. > Do I understand it correctly that you have just sent a valid patch > which could be included? Not a patch. But close. I have no way to test it. I also don't know if "bluetooth enabled by default" is the way to go on that system. With all that covered, a patch could be made and uploaded to review.coreboot.org. Patrick -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 262 bytes Desc: OpenPGP digital signature URL: From gerrit at coreboot.org Tue May 1 21:20:23 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 21:20:23 +0200 Subject: [coreboot] Patch merged into coreboot/master: 92e0b14 Drop CONFIG_MAX_PHYSICAL_CPUS on non-AMD boards References: Message-ID: the following patch was just integrated into master: commit 92e0b14eaf465478798f19734f31ea8e579a39f8 Author: Stefan Reinauer Date: Tue May 1 11:13:52 2012 -0700 Drop CONFIG_MAX_PHYSICAL_CPUS on non-AMD boards CONFIG_MAX_PHYSICAL_CPUS is defined by quite a number of mainboards whithout any code actually using the variable. Hence, drop MAX_PHYSICAL_CPUS from Kconfig for those boards. In the long run we should drop CONFIG_MAX_PHYSICAL_CPUS use completely and make the code dynamic or depend on CONFIG_MAX_CPUS instead. Change-Id: I37dcc74d245ddba5186b96bd82220dacb6f4d323 Signed-off-by: Stefan Reinauer Reviewed-By: Patrick Georgi at Tue May 1 21:00:54 2012, giving +2 Build-Tested: build bot (Jenkins) at Tue May 1 20:55:14 2012, giving +1 See http://review.coreboot.org/984 for details. -gerrit From gerrit at coreboot.org Tue May 1 21:21:21 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 21:21:21 +0200 Subject: [coreboot] Patch merged into coreboot/master: 84981fe Update PCIe Root Port _PRT to handle re-mapped functions References: Message-ID: the following patch was just integrated into master: commit 84981fe4c4542eecf8e834e19ba38f505515a3c0 Author: Duncan Laurie Date: Fri Apr 27 09:55:45 2012 -0700 Update PCIe Root Port _PRT to handle re-mapped functions The chipset enforces static-defined interrupt swizzling on PCIe root ports so if a port is remapped to a different function it needs to still report the proper interrupt map to the OS instead of assuming that function number is equivalent to root port number. This change also includes an update to the PCH function disable register which was incorrect for CPT/PPT and would cause unpredictable behavior if used. The kernel command line was changed to add 'nomsi' in order to force PCIe devices to use IO-APIC assigned interrupts and not MSI to ensure that the mapping is correct. LUMPY current: 00:1c.0 PCI bridge: Intel Corporation Device 1c10 (rev b5) 00:1c.3 PCI bridge: Intel Corporation Device 1c16 (rev b5) 16: 41518 0 0 0 IO-APIC-fasteoi i915, ahci, ath9k 19: 720 0 0 0 IO-APIC-fasteoi ehci_hcd:usb2, eth0 LUMPY with PCIe port coalesce enabled: 00:1c.0 PCI bridge: Intel Corporation Device 1c10 (rev b5) 00:1c.1 PCI bridge: Intel Corporation Device 1c16 (rev b5) 16: 38988 0 0 0 IO-APIC-fasteoi i915, ahci, ath9k 19: 347 0 0 0 IO-APIC-fasteoi ehci_hcd:usb2, eth0 Change-Id: Ia5f6bb8888b5c38a5dbc88bb25ecdf1fca41ee3e Signed-off-by: Duncan Laurie Build-Tested: build bot (Jenkins) at Tue May 1 06:13:23 2012, giving +1 See http://review.coreboot.org/978 for details. -gerrit From gerrit at coreboot.org Tue May 1 21:21:56 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 21:21:56 +0200 Subject: [coreboot] Patch merged into coreboot/master: 050c40f Add an option to enable PCIe root port coalescing References: Message-ID: the following patch was just integrated into master: commit 050c40f1dcee3945709146abf0c8cfd47b4abca3 Author: Duncan Laurie Date: Fri Apr 27 10:30:51 2012 -0700 Add an option to enable PCIe root port coalescing Background: The PCI spec (3.0-3.2.2.3.4) requires that PCI devices implement function 0. The Linux Kernel therefore will not enumerate a PCI device if it does not present a valid config space at function 0. If a board does not have anything connected to root port 0 and it is desired to disable the unused ports in order to save power then this will cause the other downstream PCIe devices to go missing as they will not be enumerated. Intel chipsets provide a way to map root port numbers to different PCI function numbers, thereby avoiding this issue and allowing root port 0 to be turned off. This change adds a new chip config option 'pcie_port_coalesce' that will collapse the enabled root ports into a linear map starting at zero. This option defaults to disabled as it can have a confusing effect on the system as the declared static devicetree may not match what is seen at runtime. This option is also forced on if the static devicetree disables port 0. When each root port is processed in the early enable stage it looks for a lower numbered root port that has been disabled and then swaps the two assigned function numbers. However the mapping register is write-once so it has to keep track of the proposed mapping changes until all ports have been processed before writing out the final map value. At this point it also updates the function numbers in the static device tree so they are consistent with the new layout. There are a few other closely related fixes in this change: 1) There is a power savings opportunity if an entire bank of ports (0-3 or 4-7) are disabled. This was checking the chipset revision to look for CougarPoint B1+ stepping and that was not passing on PantherPoint where this should always be applied. To fix this I added a function to determine the chipset type based on comparing the upper byte of the device ID. 2) Apply the same chipset type check fix to the IOBP programming. 3) There is another power savings opportunity to enable dynamic clock gating on shared PCIe resources which only applies to ports 0 and 4. However if 0 or 4 is disabled then the later check to enable this would fail as that device is already hidden. LUMPY current: 00:1c.0 PCI bridge: Intel Corporation Device 1c10 (rev b5) 00:1c.3 PCI bridge: Intel Corporation Device 1c16 (rev b5) 01:00.0 Network controller: Atheros Communications Inc. Device 0030 (rev 01) 02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B LUMPY with PCIe port coalesce enabled: 00:1c.0 PCI bridge: Intel Corporation Device 1c10 (rev b5) 00:1c.1 PCI bridge: Intel Corporation Device 1c16 (rev b5) 01:00.0 Network controller: Atheros Communications Inc. Device 0030 (rev 01) 02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B Change-Id: I828aa407fdc9c156c1c42eda8e2d893c0aa66eef Signed-off-by: Duncan Laurie Build-Tested: build bot (Jenkins) at Tue May 1 06:27:44 2012, giving +1 See http://review.coreboot.org/979 for details. -gerrit From gerrit at coreboot.org Tue May 1 21:26:37 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Tue, 1 May 2012 21:26:37 +0200 Subject: [coreboot] Patch merged into coreboot/master: aea1621 Fix issue with PCIe power management setup References: Message-ID: the following patch was just integrated into master: commit aea1621bd1489a910483d2858dc5810c8d48207e Author: Duncan Laurie Date: Fri Apr 27 10:58:22 2012 -0700 Fix issue with PCIe power management setup The current early PM setup that attempts to configure dynamic clock gating relies on PCIe functions to be enabled that may not be. Instead of reading port 0 or 4 directly to determine the link width use the register that refelects the soft strapping options as this will always be available. Also add a clear register assignment and break for port 0 in the switch statement instead of falling through to port 4 as that could end up setting the slot power limit based on port 4 values instead of based on port 0. register 0xE1=0x3f and all other root ports should have 0xE1=0x03. When port 0 and 4 are disabled they will have 0xE1=0x3C before being disabled by the pch enable handler. LUMPY default: 00:1c.0 PCI bridge: Intel Corporation Device 1c10 (rev b5) 00:1c.3 PCI bridge: Intel Corporation Device 1c16 (rev b5) pci_read8 0 0x1c 0 0xe1 0x3f pci_read8 0 0x1c 3 0xe1 0x03 LUMPY with PCIe port coalesce enabled: 00:1c.0 PCI bridge: Intel Corporation Device 1c10 (rev b5) 00:1c.1 PCI bridge: Intel Corporation Device 1c16 (rev b5) pci_read8 0 0x1c 0 0xe1 0x3f pci_read8 0 0x1c 1 0xe1 0x03 Change-Id: I33a37b0ec0c8e570cf5d9dda2c06e0225fee135c Signed-off-by: Duncan Laurie Build-Tested: build bot (Jenkins) at Tue May 1 06:41:55 2012, giving +1 See http://review.coreboot.org/980 for details. -gerrit From patrick at georgi-clan.de Tue May 1 21:27:13 2012 From: patrick at georgi-clan.de (Patrick Georgi) Date: Tue, 01 May 2012 21:27:13 +0200 Subject: [coreboot] bluetooth on Thinkpad X60s In-Reply-To: References: <4F9FFEC3.1020102@georgi-clan.de> <4FA035CE.9080202@georgi-clan.de> Message-ID: <4FA03911.3070507@georgi-clan.de> Am Di 01 Mai 2012 21:24:00 CEST schrieb Motiejus Jak?tys: > 2) The only way to disable bluetooth device now is modifying coreboot > source code. There should be a better way. Compile-time configuration > (via make menuconfig) would be feasible and doable for me. However, > any better suggestions? It would be *perfect*, if it was possible to > toggle it at runtime. How could I figure out if it is possible? > > Pointers appreciated. The get_option function uses CMOS nvram, but that has to be compiled in (which isn't the default in the tree yet). The nvram can be configured with our nvramtool (see util/nvramtool). When booting a coreboot equipped system, nvramtool automatically determines the available fields and their legal values from a table kept in RAM by coreboot. Patrick -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 262 bytes Desc: OpenPGP digital signature URL: From desired.mta at gmail.com Tue May 1 21:24:00 2012 From: desired.mta at gmail.com (=?UTF-8?Q?Motiejus_Jak=C5=A1tys?=) Date: Tue, 1 May 2012 20:24:00 +0100 Subject: [coreboot] bluetooth on Thinkpad X60s In-Reply-To: <4FA035CE.9080202@georgi-clan.de> References: <4F9FFEC3.1020102@georgi-clan.de> <4FA035CE.9080202@georgi-clan.de> Message-ID: On Tue, May 1, 2012 at 20:13, Patrick Georgi wrote: > Am Di 01 Mai 2012 20:24:10 CEST schrieb Motiejus Jak?tys: >> On Tue, May 1, 2012 at 16:18, Patrick Georgi wrote: >> Do I understand it correctly that you have just sent a valid patch >> which could be included? > Not a patch. But close. > > I have no way to test it. I also don't know if "bluetooth enabled by > default" is the way to go on that system. > With all that covered, a patch could be made and uploaded to > review.coreboot.org. I am very new to coreboot (basically a linux user with some C knowledge). With some help I would gladly code something "proper". 1) In original BIOS it is possible to turn on/off bluetooth (and device is not seen by OS). Factory settings have it on. 2) The only way to disable bluetooth device now is modifying coreboot source code. There should be a better way. Compile-time configuration (via make menuconfig) would be feasible and doable for me. However, any better suggestions? It would be *perfect*, if it was possible to toggle it at runtime. How could I figure out if it is possible? Pointers appreciated. -- Motiejus Jak?tys From gerrit at coreboot.org Tue May 1 23:10:29 2012 From: gerrit at coreboot.org (Motiejus JakÅ¡tys (desired.mta@gmail.com)) Date: Tue, 1 May 2012 23:10:29 +0200 Subject: [coreboot] New patch to review for coreboot: 241e572 Enable USE_OPTION_TABLE for ThinkPad X60 References: Message-ID: Motiejus Jak?tys (desired.mta at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/985 -gerrit commit 241e57244fe64f0a3b15f72972129ebaacd75d2f Author: Motiejus Jak?tys Date: Tue May 1 21:47:16 2012 +0100 Enable USE_OPTION_TABLE for ThinkPad X60 Without this option bluetooth configuration value in nvram is not consulted properly. It also enables built-in volume control (read-only). Tested on: ThinkPad X60s, 1702. Change-Id: I2fc6bb527c6e086a083e63922d1253eda7d4a36d Signed-off-by: Motiejus Jak?tys --- src/mainboard/lenovo/x60/Kconfig | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/src/mainboard/lenovo/x60/Kconfig b/src/mainboard/lenovo/x60/Kconfig index d35ab03..e77fac6 100644 --- a/src/mainboard/lenovo/x60/Kconfig +++ b/src/mainboard/lenovo/x60/Kconfig @@ -24,6 +24,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy select HAVE_SMI_HANDLER select HAVE_ACPI_TABLES select HAVE_ACPI_RESUME + select USE_OPTION_TABLE config MAINBOARD_DIR string From desired.mta at gmail.com Tue May 1 23:14:48 2012 From: desired.mta at gmail.com (=?UTF-8?Q?Motiejus_Jak=C5=A1tys?=) Date: Tue, 1 May 2012 22:14:48 +0100 Subject: [coreboot] bluetooth on Thinkpad X60s In-Reply-To: <4FA03911.3070507@georgi-clan.de> References: <4F9FFEC3.1020102@georgi-clan.de> <4FA035CE.9080202@georgi-clan.de> <4FA03911.3070507@georgi-clan.de> Message-ID: On Tue, May 1, 2012 at 8:27 PM, Patrick Georgi wrote: > Am Di 01 Mai 2012 21:24:00 CEST schrieb Motiejus Jak?tys: >> 2) The only way to disable bluetooth device now is modifying coreboot >> source code. There should be a better way. Compile-time configuration >> (via make menuconfig) would be feasible and doable for me. However, >> any better suggestions? It would be *perfect*, if it was possible to >> toggle it at runtime. How could I figure out if it is possible? >> >> Pointers appreciated. > The get_option function uses CMOS nvram, but that has to be compiled in > (which isn't the default in the tree yet). > The nvram can be configured with our nvramtool (see util/nvramtool). > When booting a coreboot equipped system, nvramtool automatically > determines the available fields and their legal values from a table > kept in RAM by coreboot. Thanks for the help and clarifications. With your patch bluetooth device starts regardless NVRAM value. Without your patch it does not start regardless NVRAM value. However, with this option set: CONFIG_USE_OPTION_TABLE bluetooth respects the value in NVRAM. I pushed a commit which enables this option if the architecture is Lenovo X60. There are more advantages to enable this option for this architecture, though (noted in commit message). Besides, why isn't it default yet? What are the blockers to enable this option by default (in perfect world, it should be enabled?)? Best regards, Motiejus Jak?tys From gerrit at coreboot.org Wed May 2 01:57:50 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Wed, 2 May 2012 01:57:50 +0200 Subject: [coreboot] New patch to review for coreboot: b95dd5f Make Intel i5000 specific options only appear on i5000 systems References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/986 -gerrit commit b95dd5fb7ed289cea3bb2914077874560351c1fa Author: Stefan Reinauer Date: Tue May 1 16:35:03 2012 -0700 Make Intel i5000 specific options only appear on i5000 systems Change-Id: If183611b0b62d9321a5a12311c4cb3b344b04b36 Signed-off-by: Stefan Reinauer --- src/northbridge/intel/i5000/Kconfig | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/src/northbridge/intel/i5000/Kconfig b/src/northbridge/intel/i5000/Kconfig index 0595a57..b5bc3d6 100644 --- a/src/northbridge/intel/i5000/Kconfig +++ b/src/northbridge/intel/i5000/Kconfig @@ -24,3 +24,4 @@ config NORTHBRIDGE_INTEL_I5000 config NORTHBRIDGE_INTEL_I5000_RAM_CHECK bool prompt "Run ramcheck after RAM initialization" + depends on NORTHBRIDGE_INTEL_I5000 From gerrit at coreboot.org Wed May 2 01:57:50 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Wed, 2 May 2012 01:57:50 +0200 Subject: [coreboot] New patch to review for coreboot: 4a2a115 Strip quotes from Sandybridge MRC blob References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/987 -gerrit commit 4a2a1152bdaea766df1de7645f2320d69fe10a57 Author: Stefan Reinauer Date: Tue May 1 16:37:18 2012 -0700 Strip quotes from Sandybridge MRC blob This fixes my build when specifying an absolute path to the binary. Change-Id: I95fb3960be70f78146c6afeb9cc777dccdca6b5b Signed-off-by: Stefan Reinauer --- src/northbridge/intel/sandybridge/Makefile.inc | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index b72e9fa..3dcbe2b 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -32,7 +32,7 @@ smm-$(CONFIG_HAVE_SMI_HANDLER) += finalize.c # We don't ship that, but booting without it is bound to fail cbfs-files-$(CONFIG_HAVE_MRC) += mrc.bin -mrc.bin-file := $(CONFIG_MRC_FILE) +mrc.bin-file := $(call strip_quotes,$(CONFIG_MRC_FILE)) ifeq ($(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE),y) mrc.bin-position := 0xfffa0000 endif From gerrit at coreboot.org Wed May 2 01:57:51 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Wed, 2 May 2012 01:57:51 +0200 Subject: [coreboot] New patch to review for coreboot: d4508c2 Don't include console.h in microcode.c when compiling with ROMCC References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/988 -gerrit commit d4508c295915bfad6b19daf4b39a5fa3de631d22 Author: Stefan Reinauer Date: Tue May 1 16:53:22 2012 -0700 Don't include console.h in microcode.c when compiling with ROMCC If microcode.c is built by romcc, this indicates that we are running microcode updates in the bootblock (e.g. before enabling cache as ram). In this case we did not enable any consoles yet, so we don't output anything. This patch removes inclusion of the unnecessary console/console.h for that case, which was breaking with certain configurations. Change-Id: Iebb57794d7b1e84cac253d249d47b88de4dd28a3 Signed-off-by: Stefan Reinauer --- src/cpu/intel/microcode/microcode.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/src/cpu/intel/microcode/microcode.c b/src/cpu/intel/microcode/microcode.c index 1511798..ae1c26a 100644 --- a/src/cpu/intel/microcode/microcode.c +++ b/src/cpu/intel/microcode/microcode.c @@ -20,7 +20,9 @@ /* Microcode update for Intel PIII and later CPUs */ #include +#if !defined(__ROMCC__) #include +#endif #include #include #include From gerrit at coreboot.org Wed May 2 02:06:59 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Wed, 2 May 2012 02:06:59 +0200 Subject: [coreboot] New patch to review for coreboot: c22e7fe ChromeOS: drop unused debug header description No part of ChromeOS seems to use the debug header description, so drop it to make sure it does not get copied around wrongly. References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/989 -gerrit commit c22e7fe544fe5418e8671afc2c6b6e08a71f0915 Author: Stefan Reinauer Date: Tue May 1 17:04:51 2012 -0700 ChromeOS: drop unused debug header description No part of ChromeOS seems to use the debug header description, so drop it to make sure it does not get copied around wrongly. Change-Id: Icb0baedbf6112f11289b2ddd9618a955a424ddf7 Signed-off-by: Stefan Reinauer --- src/mainboard/intel/emeraldlake2/acpi/chromeos.asl | 8 -------- src/mainboard/samsung/stumpy/acpi/chromeos.asl | 8 -------- 2 files changed, 0 insertions(+), 16 deletions(-) diff --git a/src/mainboard/intel/emeraldlake2/acpi/chromeos.asl b/src/mainboard/intel/emeraldlake2/acpi/chromeos.asl index 81ead2e..6a61b0d 100644 --- a/src/mainboard/intel/emeraldlake2/acpi/chromeos.asl +++ b/src/mainboard/intel/emeraldlake2/acpi/chromeos.asl @@ -68,14 +68,6 @@ Device (CRHW) Package() { 0x001, 0, 22, "CougarPoint" }, // recovery button Package() { 0x002, 1, 57, "CougarPoint" }, // developer switch Package() { 0x003, 0, 48, "CougarPoint" }, // firmware write protect - Package() { 0x100, 0, 9, "CougarPoint" }, // debug header gpio - Package() { 0x101, 0, 10, "CougarPoint" }, // debug header gpio 1 - Package() { 0x102, 0, 12, "CougarPoint" }, // debug header gpio 2 - Package() { 0x103, 0, 13, "CougarPoint" }, // debug header gpio 3 - Package() { 0x104, 0, 14, "CougarPoint" }, // debug header gpio 4 - Package() { 0x105, 0, 15, "CougarPoint" }, // debug header gpio 5 - Package() { 0x106, 0, 24, "CougarPoint" }, // debug header gpio 6 - Package() { 0x107, 0, 26, "CougarPoint" }, // debug header gpio 7 }) Return (OIPG) diff --git a/src/mainboard/samsung/stumpy/acpi/chromeos.asl b/src/mainboard/samsung/stumpy/acpi/chromeos.asl index 65202cb..f517b16 100644 --- a/src/mainboard/samsung/stumpy/acpi/chromeos.asl +++ b/src/mainboard/samsung/stumpy/acpi/chromeos.asl @@ -68,14 +68,6 @@ Device (CRHW) Package() { 0x001, 0, 42, "CougarPoint" }, // recovery button Package() { 0x002, 1, 17, "CougarPoint" }, // developer switch Package() { 0x003, 1, 68, "CougarPoint" }, // firmware write protect - Package() { 0x100, 0, 9, "CougarPoint" }, // debug header gpio - Package() { 0x101, 0, 10, "CougarPoint" }, // debug header gpio 1 - Package() { 0x102, 0, 12, "CougarPoint" }, // debug header gpio 2 - Package() { 0x103, 0, 13, "CougarPoint" }, // debug header gpio 3 - Package() { 0x104, 0, 14, "CougarPoint" }, // debug header gpio 4 - Package() { 0x105, 0, 15, "CougarPoint" }, // debug header gpio 5 - Package() { 0x106, 0, 24, "CougarPoint" }, // debug header gpio 6 - Package() { 0x107, 0, 26, "CougarPoint" }, // debug header gpio 7 }) Return (OIPG) From patrick at georgi-clan.de Wed May 2 08:27:12 2012 From: patrick at georgi-clan.de (Patrick Georgi) Date: Wed, 02 May 2012 08:27:12 +0200 Subject: [coreboot] bluetooth on Thinkpad X60s In-Reply-To: References: <4F9FFEC3.1020102@georgi-clan.de> <4FA035CE.9080202@georgi-clan.de> <4FA03911.3070507@georgi-clan.de> Message-ID: <4FA0D3C0.8050805@georgi-clan.de> Am Di 01 Mai 2012 23:14:48 CEST schrieb Motiejus Jak?tys: > Besides, why isn't it default yet? What are the blockers to enable > this option by default (in perfect world, it should be enabled?)? In a perfect world, yes. Problem is, not all boards define a useful CMOS layout (or use the values defined therein, if they simply copy&pasted the data). If they don't define any layout, the build (probably) breaks. If they define bogus values, that will confuse users. Maybe at some point we should just make it the default. Patrick -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 262 bytes Desc: OpenPGP digital signature URL: From svens at stackframe.org Wed May 2 10:12:22 2012 From: svens at stackframe.org (Sven Schnelle) Date: Wed, 02 May 2012 10:12:22 +0200 Subject: [coreboot] bluetooth on Thinkpad X60s In-Reply-To: ("Motiejus \=\?utf-8\?Q\?Jak\=C5\=A1tys\=22's\?\= message of "Tue, 1 May 2012 22:14:48 +0100") References: <4F9FFEC3.1020102@georgi-clan.de> <4FA035CE.9080202@georgi-clan.de> <4FA03911.3070507@georgi-clan.de> Message-ID: <878vhbknmh.fsf@begreifnix.intranet.astaro.de> Hi, Motiejus Jak?tys writes: > On Tue, May 1, 2012 at 8:27 PM, Patrick Georgi wrote: >> Am Di 01 Mai 2012 21:24:00 CEST schrieb Motiejus Jak?tys: >>> 2) The only way to disable bluetooth device now is modifying coreboot >>> source code. There should be a better way. Compile-time configuration >>> (via make menuconfig) would be feasible and doable for me. However, >>> any better suggestions? It would be *perfect*, if it was possible to >>> toggle it at runtime. How could I figure out if it is possible? >>> >>> Pointers appreciated. >> The get_option function uses CMOS nvram, but that has to be compiled in >> (which isn't the default in the tree yet). >> The nvram can be configured with our nvramtool (see util/nvramtool). >> When booting a coreboot equipped system, nvramtool automatically >> determines the available fields and their legal values from a table >> kept in RAM by coreboot. > > Thanks for the help and clarifications. > > With your patch bluetooth device starts regardless NVRAM value. > Without your patch it does not start regardless NVRAM value. > > However, with this option set: > CONFIG_USE_OPTION_TABLE > bluetooth respects the value in NVRAM. > > I pushed a commit which enables this option if the architecture is > Lenovo X60. There are more advantages to enable this option for this > architecture, though (noted in commit message). > > Besides, why isn't it default yet? What are the blockers to enable > this option by default (in perfect world, it should be enabled?)? what does nvramtool -a say? My X60s has no bluetooth, so i can't test on that particular hardware. However, the T60 i own (which is similar in many areas) works correctly. Sven From svante.signell at telia.com Wed May 2 10:51:50 2012 From: svante.signell at telia.com (Svante Signell) Date: Wed, 02 May 2012 10:51:50 +0200 Subject: [coreboot] Definition of _boot_ Message-ID: <1335948710.3707.217.camel@hp.my.own.domain> Dear coreboot developers, I'm trying to get the boot process definition cleared out in a discussion at debian-devel on replacing the sysvint script system with something event based like systemd or upstart. In the list below, please help me to refine it, and especially make a distinction on what is needed to: 1) get the computer up and running 2) all services needed are completed Of special interest is what parts is taken care of different tasks in the boot procedure, and where serial/parallel processes are possible. As I see it we have several tools in the boot process: 1) coreboot/BIOS 2) A workload, like grub2 3) The init scripts/systemd/upstart 4) On linux: udev communicating with the kernel, something else on other architectures In my opinion the boot process definition can be split in two parts: 1) Initial boot, taken care of by sysvinit: Mainly order based or serial 2) secondary boot, taken care of by udev on Linux, something else on other arches: Mainly event-based or parallel Am I completely out in the blue here? Thank you in advance for your opinion! > Hello, > > In line with the recent discussion, lets aim at defining what _boot_ is: > - initializing the RAM: yes > - initializing the CPU(s): yes > - loading the kernel: yes > - initializing the graphics card: yes for text mode, graphics mode can > come later > - initializing the HDD(s): yes, if boot devices. > - setting up swap: yes > -initializing the keyboard and mouse : yes, see below wrt USB > - initializing the serial device: no, only if used for debugging. > - initializing the the parallel port: no > - initializing the audio card: can be done later > - initializing USB devices: yes if keyboard, mouse or boot device, other > things can be done later. > - starting up the network: yes if network booting, other things can be > done later. > - starting an MTA: no > - staring sshd: no > - starting X: no, that is not a _boot_ task, other things can be done > later. This excludes network-manager and what follows with it. > - of course there are missing pieces here, you can help me filling them > in... or reject/not comment on this as usual as many of you would. > > Thank you for your attention! > > From desired.mta at gmail.com Wed May 2 13:10:23 2012 From: desired.mta at gmail.com (=?UTF-8?Q?Motiejus_Jak=C5=A1tys?=) Date: Wed, 2 May 2012 12:10:23 +0100 Subject: [coreboot] bluetooth on Thinkpad X60s In-Reply-To: <878vhbknmh.fsf@begreifnix.intranet.astaro.de> References: <4F9FFEC3.1020102@georgi-clan.de> <4FA035CE.9080202@georgi-clan.de> <4FA03911.3070507@georgi-clan.de> <878vhbknmh.fsf@begreifnix.intranet.astaro.de> Message-ID: Hi, On Wed, May 2, 2012 at 9:12 AM, Sven Schnelle wrote: > what does nvramtool -a say? My X60s has no bluetooth, so i can't test > on that particular hardware. However, the T60 i own (which is similar in > many areas) works correctly. $ ./nvramtool -a boot_option = Fallback last_boot = Fallback baud_rate = 115200 debug_level = Spew hyper_threading = Enable nmi = Disable # Bad value -> boot_devices boot_default = 0x71 cmos_defaults_loaded = Yes lpt = Disable volume = 0xe tft_brightness = 0xff first_battery = Primary bluetooth = Enable Values I can test and which make sense: * volume (read-only). * tft_brightness (read-only). * bluetooth. Read-write, works correctly. This model certainly does not have lpt and hyper-threading. No external RS232 as well (might be some pins on the motherboard, I don't know). Haven't heard about a bay for the second battery. Can't speak about other values, though. -- Motiejus Jak?tys From desired.mta at gmail.com Wed May 2 13:22:07 2012 From: desired.mta at gmail.com (=?UTF-8?Q?Motiejus_Jak=C5=A1tys?=) Date: Wed, 2 May 2012 12:22:07 +0100 Subject: [coreboot] bluetooth on Thinkpad X60s In-Reply-To: References: <4F9FFEC3.1020102@georgi-clan.de> <4FA035CE.9080202@georgi-clan.de> <4FA03911.3070507@georgi-clan.de> <878vhbknmh.fsf@begreifnix.intranet.astaro.de> Message-ID: Hi again, On Wed, May 2, 2012 at 12:10 PM, Motiejus Jak?tys wrote: > Values I can test and which make sense: > * volume (read-only). > * tft_brightness (read-only). > * bluetooth. Read-write, works correctly. > > This model certainly does not have lpt and hyper-threading. No > external RS232 as well (might be some pins on the motherboard, I don't > know). Haven't heard about a bay for the second battery. Can't speak > about other values, though. There is a docking station[1], which has: * additional battery * RS232 * LPT But I don't own it and unfortunately can't test it. Values for volume and brightness are checked on boot, the same way like Bluetooth is. Hence please discard the "read-only" label. Thanks to Pawel for pointing this out. Motiejus [1]: http://www.parts4nb.com/catalogue/product/ibm-thinkpad-x60s--docking-station From gerrit at coreboot.org Wed May 2 18:44:16 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Wed, 2 May 2012 18:44:16 +0200 Subject: [coreboot] Patch set updated for coreboot: db463a6 Sandybridge: Display platform information early References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/975 -gerrit commit db463a6eedd399efb93deee2536a43ff07bef9f6 Author: Vadim Bendebury Date: Wed Apr 18 15:47:32 2012 -0700 Sandybridge: Display platform information early It is important to have the system configuration reported as early as possible to have a better idea what exact chipset the platform is running with. This change adds code to have an early coreboot module report the CPU and PCH information. CPU info includes the 32 bit feature information word, the symbolic processor brand string, and information about some features support, as obtained through CPUID instructions. The PCH information includes the symbolic device name and PCI device version. Change-Id: If6c21ad5ffb76d7d57d89f4f87d04bdd7192480a Signed-off-by: Vadim Bendebury --- src/northbridge/intel/sandybridge/Makefile.inc | 1 + src/northbridge/intel/sandybridge/raminit.c | 2 + .../intel/sandybridge/report_platform.c | 103 ++++++++++++++++++++ src/northbridge/intel/sandybridge/sandybridge.h | 1 + 4 files changed, 107 insertions(+), 0 deletions(-) diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index b72e9fa..79aa6ea 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -25,6 +25,7 @@ ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c romstage-y += udelay.c romstage-y += raminit.c romstage-y += early_init.c +romstage-y += report_platform.c romstage-y += ../../../arch/x86/lib/walkcbfs.S smm-$(CONFIG_HAVE_SMI_HANDLER) += udelay.c diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index bbb743f..e1d5d26 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -318,6 +318,8 @@ void sdram_initialize(struct pei_data *pei_data) const char *target = "mrc.bin"; unsigned long entry; + report_platform_info(); + /* Wait for ME to be ready */ intel_early_me_init(); intel_early_me_uma_size(); diff --git a/src/northbridge/intel/sandybridge/report_platform.c b/src/northbridge/intel/sandybridge/report_platform.c new file mode 100644 index 0000000..d59cfe9 --- /dev/null +++ b/src/northbridge/intel/sandybridge/report_platform.c @@ -0,0 +1,103 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Google Inc. + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "southbridge/intel/bd82x6x/pch.h" +#include +#include +#include "sandybridge.h" + +static void report_cpu_info(void) +{ + struct cpuid_result cpuidr; + u32 i, index; + char cpu_string[50]; /* 48 bytes are reported */ + int vt, txt, aes; + const char *mode[] = {"NOT ", ""}; + + index = 0x80000000; + cpuidr = cpuid(index); + if (cpuidr.eax < 0x80000004) { + strcpy(cpu_string, "Platform info not available"); + } else { + u32 *p = (u32*) cpu_string; + for (i = 2; i <= 4 ; i++) { + cpuidr = cpuid(index + i); + *p++ = cpuidr.eax; + *p++ = cpuidr.ebx; + *p++ = cpuidr.ecx; + *p++ = cpuidr.edx; + } + } + cpuidr = cpuid(1); + printk(BIOS_DEBUG, "CPU id(%x): %s\n", cpuidr.eax, cpu_string); + aes = (cpuidr.ecx & (1 << 25)) ? 1 : 0; + txt = (cpuidr.ecx & (1 << 6)) ? 1 : 0; + vt = (cpuidr.ecx & (1 << 5)) ? 1 : 0; + printk(BIOS_DEBUG, "AES %ssupported, TXT %ssupported, VT %ssupported\n", + mode[aes], mode[txt], mode[vt]); +} + +/* The PCI id name match comes from Intel document 472178 */ +static struct { + u16 dev_id; + const char *dev_name; +} pch_table [] = { + {0x1E41, "Desktop Sample"}, + {0x1E47, "Q77"}, + {0x1E48, "Q75"}, + {0x1E49, "B75"}, + {0x1E44, "Z77"}, + {0x1E46, "Z75"}, + {0x1E4A, "H77"}, + {0x1E53, "C216"}, + {0x1E42, "Mobile Sample"}, + {0x1E55, "QM77"}, + {0x1E58, "UM77"}, + {0x1E57, "HM77"}, + {0x1E59, "HM76"}, + {0x1E5d, "HM75"}, + {0x1E43, "SFF Sample"}, + {0x1E56, "QS77"}, +}; + +static void report_pch_info(void) +{ + int i; + u16 dev_id = pci_read_config16(PCH_LPC_DEV, 2); + + + const char *pch_type = "Unknown"; + for (i = 0; i < ARRAY_SIZE(pch_table); i++) { + if (pch_table[i].dev_id == dev_id) { + pch_type = pch_table[i].dev_name; + break; + } + } + printk (BIOS_DEBUG, "PCH type: %s rev id %x\n", + pch_type, pci_read_config8(PCH_LPC_DEV, 8)); +} + +void report_platform_info(void) +{ + report_cpu_info(); + report_pch_info(); +} diff --git a/src/northbridge/intel/sandybridge/sandybridge.h b/src/northbridge/intel/sandybridge/sandybridge.h index c7bea98..aa62021 100644 --- a/src/northbridge/intel/sandybridge/sandybridge.h +++ b/src/northbridge/intel/sandybridge/sandybridge.h @@ -219,6 +219,7 @@ void dump_pci_device(unsigned dev); void dump_pci_devices(void); void dump_spd_registers(void); void dump_mem(unsigned start, unsigned end); +void report_platform_info(void); #endif /* !__SMM__ */ #endif #endif From gerrit at coreboot.org Wed May 2 19:52:38 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Wed, 2 May 2012 19:52:38 +0200 Subject: [coreboot] Patch merged into coreboot/master: db463a6 Sandybridge: Display platform information early References: Message-ID: the following patch was just integrated into master: commit db463a6eedd399efb93deee2536a43ff07bef9f6 Author: Vadim Bendebury Date: Wed Apr 18 15:47:32 2012 -0700 Sandybridge: Display platform information early It is important to have the system configuration reported as early as possible to have a better idea what exact chipset the platform is running with. This change adds code to have an early coreboot module report the CPU and PCH information. CPU info includes the 32 bit feature information word, the symbolic processor brand string, and information about some features support, as obtained through CPUID instructions. The PCH information includes the symbolic device name and PCI device version. Change-Id: If6c21ad5ffb76d7d57d89f4f87d04bdd7192480a Signed-off-by: Vadim Bendebury Reviewed-By: Patrick Georgi at Wed May 2 19:52:36 2012, giving +2 See http://review.coreboot.org/975 for details. -gerrit From gerrit at coreboot.org Wed May 2 20:00:30 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Wed, 2 May 2012 20:00:30 +0200 Subject: [coreboot] Patch merged into coreboot/master: 4a2a115 Strip quotes from Sandybridge MRC blob References: Message-ID: the following patch was just integrated into master: commit 4a2a1152bdaea766df1de7645f2320d69fe10a57 Author: Stefan Reinauer Date: Tue May 1 16:37:18 2012 -0700 Strip quotes from Sandybridge MRC blob This fixes my build when specifying an absolute path to the binary. Change-Id: I95fb3960be70f78146c6afeb9cc777dccdca6b5b Signed-off-by: Stefan Reinauer Reviewed-By: Patrick Georgi at Wed May 2 19:59:04 2012, giving +2 See http://review.coreboot.org/987 for details. -gerrit From gerrit at coreboot.org Wed May 2 21:06:33 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Wed, 2 May 2012 21:06:33 +0200 Subject: [coreboot] Patch merged into coreboot/master: d4508c2 Don't include console.h in microcode.c when compiling with ROMCC References: Message-ID: the following patch was just integrated into master: commit d4508c295915bfad6b19daf4b39a5fa3de631d22 Author: Stefan Reinauer Date: Tue May 1 16:53:22 2012 -0700 Don't include console.h in microcode.c when compiling with ROMCC If microcode.c is built by romcc, this indicates that we are running microcode updates in the bootblock (e.g. before enabling cache as ram). In this case we did not enable any consoles yet, so we don't output anything. This patch removes inclusion of the unnecessary console/console.h for that case, which was breaking with certain configurations. Change-Id: Iebb57794d7b1e84cac253d249d47b88de4dd28a3 Signed-off-by: Stefan Reinauer See http://review.coreboot.org/988 for details. -gerrit From gerrit at coreboot.org Wed May 2 21:06:58 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Wed, 2 May 2012 21:06:58 +0200 Subject: [coreboot] Patch merged into coreboot/master: b95dd5f Make Intel i5000 specific options only appear on i5000 systems References: Message-ID: the following patch was just integrated into master: commit b95dd5fb7ed289cea3bb2914077874560351c1fa Author: Stefan Reinauer Date: Tue May 1 16:35:03 2012 -0700 Make Intel i5000 specific options only appear on i5000 systems Change-Id: If183611b0b62d9321a5a12311c4cb3b344b04b36 Signed-off-by: Stefan Reinauer See http://review.coreboot.org/986 for details. -gerrit From gerrit at coreboot.org Wed May 2 21:21:07 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Wed, 2 May 2012 21:21:07 +0200 Subject: [coreboot] Patch set updated for coreboot: 8354d7c ChromeOS: drop unused debug header description References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/989 -gerrit commit 8354d7c74f8e5eba784a79bd86941e38c12d092d Author: Stefan Reinauer Date: Tue May 1 17:04:51 2012 -0700 ChromeOS: drop unused debug header description No part of ChromeOS seems to use the debug header description, so drop it to make sure it does not get copied around wrongly. Change-Id: Icb0baedbf6112f11289b2ddd9618a955a424ddf7 Signed-off-by: Stefan Reinauer --- src/mainboard/intel/emeraldlake2/acpi/chromeos.asl | 8 -------- src/mainboard/samsung/stumpy/acpi/chromeos.asl | 8 -------- 2 files changed, 0 insertions(+), 16 deletions(-) diff --git a/src/mainboard/intel/emeraldlake2/acpi/chromeos.asl b/src/mainboard/intel/emeraldlake2/acpi/chromeos.asl index 81ead2e..6a61b0d 100644 --- a/src/mainboard/intel/emeraldlake2/acpi/chromeos.asl +++ b/src/mainboard/intel/emeraldlake2/acpi/chromeos.asl @@ -68,14 +68,6 @@ Device (CRHW) Package() { 0x001, 0, 22, "CougarPoint" }, // recovery button Package() { 0x002, 1, 57, "CougarPoint" }, // developer switch Package() { 0x003, 0, 48, "CougarPoint" }, // firmware write protect - Package() { 0x100, 0, 9, "CougarPoint" }, // debug header gpio - Package() { 0x101, 0, 10, "CougarPoint" }, // debug header gpio 1 - Package() { 0x102, 0, 12, "CougarPoint" }, // debug header gpio 2 - Package() { 0x103, 0, 13, "CougarPoint" }, // debug header gpio 3 - Package() { 0x104, 0, 14, "CougarPoint" }, // debug header gpio 4 - Package() { 0x105, 0, 15, "CougarPoint" }, // debug header gpio 5 - Package() { 0x106, 0, 24, "CougarPoint" }, // debug header gpio 6 - Package() { 0x107, 0, 26, "CougarPoint" }, // debug header gpio 7 }) Return (OIPG) diff --git a/src/mainboard/samsung/stumpy/acpi/chromeos.asl b/src/mainboard/samsung/stumpy/acpi/chromeos.asl index 65202cb..f517b16 100644 --- a/src/mainboard/samsung/stumpy/acpi/chromeos.asl +++ b/src/mainboard/samsung/stumpy/acpi/chromeos.asl @@ -68,14 +68,6 @@ Device (CRHW) Package() { 0x001, 0, 42, "CougarPoint" }, // recovery button Package() { 0x002, 1, 17, "CougarPoint" }, // developer switch Package() { 0x003, 1, 68, "CougarPoint" }, // firmware write protect - Package() { 0x100, 0, 9, "CougarPoint" }, // debug header gpio - Package() { 0x101, 0, 10, "CougarPoint" }, // debug header gpio 1 - Package() { 0x102, 0, 12, "CougarPoint" }, // debug header gpio 2 - Package() { 0x103, 0, 13, "CougarPoint" }, // debug header gpio 3 - Package() { 0x104, 0, 14, "CougarPoint" }, // debug header gpio 4 - Package() { 0x105, 0, 15, "CougarPoint" }, // debug header gpio 5 - Package() { 0x106, 0, 24, "CougarPoint" }, // debug header gpio 6 - Package() { 0x107, 0, 26, "CougarPoint" }, // debug header gpio 7 }) Return (OIPG) From gerrit at coreboot.org Wed May 2 22:28:58 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Wed, 2 May 2012 22:28:58 +0200 Subject: [coreboot] Patch merged into coreboot/master: 8354d7c ChromeOS: drop unused debug header description References: Message-ID: the following patch was just integrated into master: commit 8354d7c74f8e5eba784a79bd86941e38c12d092d Author: Stefan Reinauer Date: Tue May 1 17:04:51 2012 -0700 ChromeOS: drop unused debug header description No part of ChromeOS seems to use the debug header description, so drop it to make sure it does not get copied around wrongly. Change-Id: Icb0baedbf6112f11289b2ddd9618a955a424ddf7 Signed-off-by: Stefan Reinauer Build-Tested: build bot (Jenkins) at Wed May 2 21:42:41 2012, giving +1 Reviewed-By: Stefan Reinauer at Wed May 2 22:28:55 2012, giving +2 See http://review.coreboot.org/989 for details. -gerrit From gerrit at coreboot.org Thu May 3 01:47:54 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Thu, 3 May 2012 01:47:54 +0200 Subject: [coreboot] New patch to review for coreboot: bc9827a Tell CBMEM pretty printer about MRC cache References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/990 -gerrit commit bc9827a733944045eb7c5c58770a72478a69f05d Author: Stefan Reinauer Date: Wed May 2 16:27:26 2012 -0700 Tell CBMEM pretty printer about MRC cache Sandybridge memory initialization produces some amount of training data that has to be kept around in CBMEM. Add a descriptive name to the CBMEM pretty printer to prevent it from just printing the hex value. Change-Id: I587c0bc3dfcf389ba298d445d2594eef73bc69a8 Signed-off-by: Stefan Reinauer --- src/lib/cbmem.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/src/lib/cbmem.c b/src/lib/cbmem.c index e54e1c0..0f2a15d 100644 --- a/src/lib/cbmem.c +++ b/src/lib/cbmem.c @@ -257,6 +257,7 @@ void cbmem_list(void) case CBMEM_ID_RESUME_SCRATCH: printk(BIOS_DEBUG, "ACPISCRATCH"); break; case CBMEM_ID_SMBIOS: printk(BIOS_DEBUG, "SMBIOS "); break; case CBMEM_ID_TIMESTAMP: printk(BIOS_DEBUG, "TIME STAMP "); break; + case CBMEM_ID_MRCDATA: printk(BIOS_DEBUG, "MRC DATA "); break; case CBMEM_ID_CONSOLE: printk(BIOS_DEBUG, "CONSOLE "); break; default: printk(BIOS_DEBUG, "%08x ", cbmem_toc[i].id); } From gerrit at coreboot.org Thu May 3 01:47:55 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Thu, 3 May 2012 01:47:55 +0200 Subject: [coreboot] New patch to review for coreboot: 8ea810a Add missing newline to printk in Sandybridge init code References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/991 -gerrit commit 8ea810ae2fca0f3aa002c9bcbfe1f390fa3e6a76 Author: Stefan Reinauer Date: Wed May 2 16:29:51 2012 -0700 Add missing newline to printk in Sandybridge init code Change-Id: I9217a75ec1a0abb898c45752d990231ce98e5fb2 Signed-off-by: Stefan Reinauer --- src/northbridge/intel/sandybridge/raminit.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index e1d5d26..8209980 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -252,7 +252,7 @@ static void prepare_mrc_cache(struct pei_data *pei_data) __func__, pei_data->mrc_input, entry_id, pei_data->mrc_input_len, mrc_cache->mrc_checksum); #else - printk(BIOS_ERR, "MRC cache handling code has to be redone."); + printk(BIOS_ERR, "MRC cache handling code has to be redone.\n"); #endif } #endif From gerrit at coreboot.org Thu May 3 01:47:55 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Thu, 3 May 2012 01:47:55 +0200 Subject: [coreboot] New patch to review for coreboot: ba795bd Make creation of CBMEM_ID_RESUME_SCRATCH depending on Agesa References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/992 -gerrit commit ba795bd63862f8124ac6f27200a94e303ac04a46 Author: Stefan Reinauer Date: Wed May 2 16:30:53 2012 -0700 Make creation of CBMEM_ID_RESUME_SCRATCH depending on Agesa The CBMEM_ID_RESUME_SCRATCH area is only used by Agesa code, on one particular board (AMD Persimmon). Make the creation of that section depending on Agesa so it does consume space on non-Agesa systems. Change-Id: I2a1a4f76991ef936ea68cf75928b20b7ed132b84 Signed-off-by: Stefan Reinauer --- src/arch/x86/boot/tables.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/src/arch/x86/boot/tables.c b/src/arch/x86/boot/tables.c index 70f3117..4fefc7d 100644 --- a/src/arch/x86/boot/tables.c +++ b/src/arch/x86/boot/tables.c @@ -237,8 +237,10 @@ struct lb_memory *write_tables(void) * the result right now. If it fails, ACPI resume will be disabled. */ cbmem_add(CBMEM_ID_RESUME, HIGH_MEMORY_SAVE); +#if CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY14 cbmem_add(CBMEM_ID_RESUME_SCRATCH, CONFIG_HIGH_SCRATCH_MEMORY_SIZE); #endif +#endif #if CONFIG_MULTIBOOT post_code(0x9d); From gerrit at coreboot.org Thu May 3 01:47:56 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Thu, 3 May 2012 01:47:56 +0200 Subject: [coreboot] New patch to review for coreboot: a2d207d Make CBFS output more consistent References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/993 -gerrit commit a2d207db706d961acb7efdea5a20bd99c4a645e1 Author: Stefan Reinauer Date: Wed May 2 16:33:18 2012 -0700 Make CBFS output more consistent - Prefix all CBFS output messages with CBFS: - Add an option DEBUG_CBFS that is off by default. Without DEBUG_CBFS enabled, the code will no longer print all the files it walks for every file lookup. - Add DEBUG() macro next to LOG() and ERROR() to specify which messages should only be visible with DEBUG_CBFS printed. - Actually print a message when the file we're looking for was found. :) old: Searching for fallback/coreboot_ram Check cmos_layout.bin Check pci8086,0106.rom Check fallback/romstage Check fallback/coreboot_ram Change-Id: I2d731fae17a5f6ca51d435cfb7a58d6e017efa24 Stage: loading fallback/coreboot_ram @ 0x100000 (540672 bytes), entry @ 0x100000 Stage: done loading. new: CBFS: Looking for 'fallback/coreboot_ram' CBFS: found. CBFS: loading stage fallback/coreboot_ram @ 0x100000 (507904 bytes), entry @ 0x100000 CBFS: stage loaded. Signed-off-by: Stefan Reinauer --- src/Kconfig | 7 +++++++ src/lib/cbfs.c | 17 +++++++++++------ src/lib/cbfs_core.c | 8 ++++++-- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/Kconfig b/src/Kconfig index d449b30..a6b09dc 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -664,6 +664,13 @@ config GDB_STUB If enabled, you will be able to set breakpoints for gdb debugging. See src/arch/x86/lib/c_start.S for details. +config DEBUG_CBFS + bool "Output verbose CBFS debug messages" + default n + depends on TPM + help + This option enables additional CBFS related debug messages. + config HAVE_DEBUG_RAM_SETUP def_bool n diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index 33fa799..98672d4 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -30,8 +30,13 @@ #endif #define phys_to_virt(x) (void*)(x) #define virt_to_phys(x) (uint32_t)(x) -#define ERROR(x...) printk(BIOS_ERR, x) -#define LOG(x...) printk(BIOS_INFO, x) +#define ERROR(x...) printk(BIOS_ERR, "CBFS: " x) +#define LOG(x...) printk(BIOS_INFO, "CBFS: " x) +#if CONFIG_DEBUG_CBFS +#define DEBUG(x...) printk(BIOS_SPEW, "CBFS: " x) +#else +#define DEBUG(x...) +#endif // FIXME: romstart/romend are fine on x86, but not on ARM #define romstart() 0xffffffff #define romend() 0 @@ -100,7 +105,7 @@ void * cbfs_load_stage(const char *name) if (stage == NULL) return (void *) -1; - printk(BIOS_INFO, "Stage: loading %s @ 0x%x (%d bytes), entry @ 0x%llx\n", + LOG("loading stage %s @ 0x%x (%d bytes), entry @ 0x%llx\n", name, (u32) stage->load, stage->memlen, stage->entry); @@ -113,7 +118,7 @@ void * cbfs_load_stage(const char *name) stage->len)) return (void *) -1; - printk(BIOS_DEBUG, "Stage: done loading.\n"); + DEBUG("stage loaded.\n"); entry = stage->entry; // entry = ntohll(stage->entry); @@ -130,13 +135,13 @@ int cbfs_execute_stage(const char *name) return 1; if (ntohl(stage->compression) != CBFS_COMPRESS_NONE) { - printk(BIOS_INFO, "CBFS: Unable to run %s: Compressed file" + LOG("Unable to run %s: Compressed file" "Not supported for in-place execution\n", name); return 1; } /* FIXME: This isn't right */ - printk(BIOS_INFO, "CBFS: run @ %p\n", (void *) ntohl((u32) stage->entry)); + LOG("run @ %p\n", (void *) ntohl((u32) stage->entry)); return run_address((void *) (intptr_t)ntohll(stage->entry)); } diff --git a/src/lib/cbfs_core.c b/src/lib/cbfs_core.c index 4bf755b..15cb68e 100644 --- a/src/lib/cbfs_core.c +++ b/src/lib/cbfs_core.c @@ -40,6 +40,9 @@ * print an error message x (in printf format) * * LOG(x...) + * print a message x (in printf format) + * + * DEBUG(x...) * print a debug message x (in printf format) * * romstart() @@ -86,7 +89,7 @@ struct cbfs_file *cbfs_find(const char *name) struct cbfs_header *header = get_cbfs_header(); if (header == (void*)0xffffffff) return NULL; - LOG("Searching for %s\n", name); + LOG("Looking for '%s'\n", name); void *data, *dataend, *origdata; /* find first entry */ @@ -111,8 +114,9 @@ struct cbfs_file *cbfs_find(const char *name) data = phys_to_virt(CBFS_ALIGN_UP(virt_to_phys(data), align)); continue; } - LOG("Check %s\n", CBFS_NAME(file)); + DEBUG("Check '%s'\n", CBFS_NAME(file)); if (strcmp(CBFS_NAME(file), name) == 0) { + LOG("found.\n"); return file; } void *olddata = data; From gerrit at coreboot.org Thu May 3 01:47:56 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Thu, 3 May 2012 01:47:56 +0200 Subject: [coreboot] New patch to review for coreboot: 2badb25 Print some useful debugging information in PSS table creation References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/994 -gerrit commit 2badb25677a0425f43f53ece4db187ec829fa659 Author: Stefan Reinauer Date: Wed May 2 16:38:47 2012 -0700 Print some useful debugging information in PSS table creation Change-Id: I1ec7a7e54513671331ac12f08d5f59161b72b0fd Example: PSS: 1900MHz power 35000 control 0x1300 status 0x1300 PSS: 1600MHz power 28468 control 0x1000 status 0x1000 PSS: 1400MHz power 24291 control 0xe00 status 0xe00 PSS: 1200MHz power 20340 control 0xc00 status 0xc00 PSS: 1000MHz power 16569 control 0xa00 status 0xa00 PSS: 800MHz power 12937 control 0x800 status 0x800 PSS: 1900MHz power 35000 control 0x1300 status 0x1300 PSS: 1600MHz power 28468 control 0x1000 status 0x1000 PSS: 1400MHz power 24291 control 0xe00 status 0xe00 PSS: 1200MHz power 20340 control 0xc00 status 0xc00 PSS: 1000MHz power 16569 control 0xa00 status 0xa00 PSS: 800MHz power 12937 control 0x800 status 0x800 Signed-off-by: Stefan Reinauer --- src/arch/x86/boot/acpigen.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/src/arch/x86/boot/acpigen.c b/src/arch/x86/boot/acpigen.c index 04aeddf..e7a297d 100644 --- a/src/arch/x86/boot/acpigen.c +++ b/src/arch/x86/boot/acpigen.c @@ -426,8 +426,12 @@ int acpigen_write_PSS_package(u32 coreFreq, u32 power, u32 transLat, len += acpigen_write_dword(busmLat); len += acpigen_write_dword(control); len += acpigen_write_dword(status); - //pkglen without the len opcode + // pkglen without the len opcode acpigen_patch_len(len - 1); + + printk(BIOS_DEBUG, "PSS: %uMHz power %u control 0x%x status 0x%x\n", + coreFreq, power, control, status); + return len; } From gerrit at coreboot.org Thu May 3 01:47:57 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Thu, 3 May 2012 01:47:57 +0200 Subject: [coreboot] New patch to review for coreboot: cb60b66 Don't pre-enable SATA AHCI in romstage.c References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/995 -gerrit commit cb60b660540716f4b6671e2b5d21bf75ec9c55e3 Author: Stefan Reinauer Date: Wed May 2 16:39:56 2012 -0700 Don't pre-enable SATA AHCI in romstage.c In a recent commit the SATA code of Panther Point / Cougar Point was changed to enable AHCI mode depending on the device tree settings rather than a hard code hidden in romstage.c. However, Emerald Lake 2 was not fixed up accordingly. Change-Id: I6c93f386509361e1ab5565b0e4d0e84f0ba282a2 Signed-off-by: Stefan Reinauer --- src/mainboard/intel/emeraldlake2/romstage.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/src/mainboard/intel/emeraldlake2/romstage.c b/src/mainboard/intel/emeraldlake2/romstage.c index 879756b..aba89d4 100644 --- a/src/mainboard/intel/emeraldlake2/romstage.c +++ b/src/mainboard/intel/emeraldlake2/romstage.c @@ -132,9 +132,6 @@ static void early_pch_init(void) reg8 = pci_read_config8(PCH_LPC_DEV, 0xa4); reg8 &= ~(1 << 2); pci_write_config8(PCH_LPC_DEV, 0xa4, reg8); - - // SATA - enable AHCI - pci_write_config16(PCH_SATA_DEV, 0x90, 0x0060); } static void setup_sio_gpios(void) From gerrit at coreboot.org Thu May 3 01:47:57 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Thu, 3 May 2012 01:47:57 +0200 Subject: [coreboot] New patch to review for coreboot: ef6dfc1 Fix register corruption during Intel Microcode update References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/996 -gerrit commit ef6dfc1d0656f34331519fb97e5ec87784c4686d Author: Stefan Reinauer Date: Wed May 2 16:41:55 2012 -0700 Fix register corruption during Intel Microcode update Another bug in the Intel microcode update code that existed since we switched to LinuxBIOSv2 in 2004: The inline assembly code that reads the CPU revision from an MSR after running cpuid(1) trashes registers EBX and ECX. Only ECX was mentioned in the clobber list. C code running after this function could silently access completely wrong data, which resulted in the wrong date being printed on microcode updates (and potentially other issues happening until the C code writes to EBX again) Change-Id: Ida733fa1747565ec9824d3a37d08b1a73cd8355f Signed-off-by: Stefan Reinauer --- src/cpu/intel/microcode/microcode.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/cpu/intel/microcode/microcode.c b/src/cpu/intel/microcode/microcode.c index ae1c26a..ec42fb9 100644 --- a/src/cpu/intel/microcode/microcode.c +++ b/src/cpu/intel/microcode/microcode.c @@ -63,7 +63,7 @@ static inline u32 read_microcode_rev(void) "=a" (msr.lo), "=d" (msr.hi) : /* inputs */ : /* trashed */ - "ecx" + "ebx", "ecx" ); return msr.hi; } From gerrit at coreboot.org Thu May 3 02:29:13 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Thu, 3 May 2012 02:29:13 +0200 Subject: [coreboot] New patch to review for coreboot: d13510c Add SPI driver References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/997 -gerrit commit d13510c5a18302473903536c8a263c54105b2d80 Author: Stefan Reinauer Date: Wed May 2 17:07:05 2012 -0700 Add SPI driver This driver is taken from u-boot and adapted to match coreboot. It still contains some hacks and is ICH specific at places. Change-Id: I97dd8096f7db3b62f8f4f4e4d08bdee10d88f689 Signed-off-by: Patrick Georgi --- src/drivers/Makefile.inc | 1 + src/drivers/spi/Makefile.inc | 12 + src/drivers/spi/eon.c | 161 ++++++ src/drivers/spi/macronix.c | 220 +++++++++ src/drivers/spi/ramtron.c | 315 ++++++++++++ src/drivers/spi/spansion.c | 241 +++++++++ src/drivers/spi/spi_flash.c | 327 ++++++++++++ src/drivers/spi/spi_flash_internal.h | 81 +++ src/drivers/spi/sst.c | 268 ++++++++++ src/drivers/spi/stmicro.c | 250 ++++++++++ src/drivers/spi/winbond.c | 218 ++++++++ src/include/device/pci_ids.h | 4 + src/include/spi.h | 203 ++++++++ src/include/spi_flash.h | 91 ++++ src/northbridge/intel/sandybridge/raminit.c | 1 + src/southbridge/intel/bd82x6x/Makefile.inc | 2 + src/southbridge/intel/bd82x6x/spi.c | 712 +++++++++++++++++++++++++++ 17 files changed, 3107 insertions(+), 0 deletions(-) diff --git a/src/drivers/Makefile.inc b/src/drivers/Makefile.inc index 5f6dadf..851a4df 100644 --- a/src/drivers/Makefile.inc +++ b/src/drivers/Makefile.inc @@ -26,4 +26,5 @@ subdirs-y += oxford subdirs-y += sil subdirs-y += trident subdirs-y += ics +subdirs-y += spi subdirs-$(CONFIG_ARCH_X86) += pc80 diff --git a/src/drivers/spi/Makefile.inc b/src/drivers/spi/Makefile.inc new file mode 100644 index 0000000..9eca90b --- /dev/null +++ b/src/drivers/spi/Makefile.inc @@ -0,0 +1,12 @@ +# SPI driver interface +ramstage-y += spi_flash.c + +# drivers +ramstage-y += eon.c +ramstage-y += macronix.c +ramstage-y += ramtron.c +ramstage-y += spansion.c +ramstage-y += sst.c +ramstage-y += stmicro.c +ramstage-y += winbond.c + diff --git a/src/drivers/spi/eon.c b/src/drivers/spi/eon.c new file mode 100644 index 0000000..a94dec1 --- /dev/null +++ b/src/drivers/spi/eon.c @@ -0,0 +1,161 @@ +/* + * (C) Copyright 2010, ucRobotics Inc. + * Author: Chong Huang + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* EN25Q128-specific commands */ +#define CMD_EN25Q128_WREN 0x06 /* Write Enable */ +#define CMD_EN25Q128_WRDI 0x04 /* Write Disable */ +#define CMD_EN25Q128_RDSR 0x05 /* Read Status Register */ +#define CMD_EN25Q128_WRSR 0x01 /* Write Status Register */ +#define CMD_EN25Q128_READ 0x03 /* Read Data Bytes */ +#define CMD_EN25Q128_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_EN25Q128_PP 0x02 /* Page Program */ +#define CMD_EN25Q128_SE 0x20 /* Sector Erase */ +#define CMD_EN25Q128_BE 0xd8 /* Block Erase */ +#define CMD_EN25Q128_DP 0xb9 /* Deep Power-down */ +#define CMD_EN25Q128_RES 0xab /* Release from DP, and Read Signature */ + +#define EON_ID_EN25Q128 0x18 + +struct eon_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 sectors_per_block; + u16 nr_sectors; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct eon_spi_flash { + struct spi_flash flash; + const struct eon_spi_flash_params *params; +}; + +static inline struct eon_spi_flash *to_eon_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct eon_spi_flash, flash); +} + +static const struct eon_spi_flash_params eon_spi_flash_table[] = { + { + .idcode1 = EON_ID_EN25Q128, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_sectors = 4096, + .name = "EN25Q128", + }, +}; + +static int eon_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct eon_spi_flash *eon = to_eon_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = eon->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_EN25Q128_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, + "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_EN25Q128_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: EON Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: EON: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int eon_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_EN25Q128_BE, offset, len); +} + +struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode) +{ + const struct eon_spi_flash_params *params; + struct eon_spi_flash *eon; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(eon_spi_flash_table); ++i) { + params = &eon_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(eon_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported EON ID %02x\n", idcode[1]); + return NULL; + } + + eon = malloc(sizeof(*eon)); + if (!eon) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + eon->params = params; + eon->flash.spi = spi; + eon->flash.name = params->name; + + eon->flash.write = eon_write; + eon->flash.erase = eon_erase; + eon->flash.read = spi_flash_cmd_read_fast; + eon->flash.sector_size = params->page_size * params->pages_per_sector + * params->sectors_per_block; + eon->flash.size = params->page_size * params->pages_per_sector + * params->nr_sectors; + + return &eon->flash; +} diff --git a/src/drivers/spi/macronix.c b/src/drivers/spi/macronix.c new file mode 100644 index 0000000..700a0a2 --- /dev/null +++ b/src/drivers/spi/macronix.c @@ -0,0 +1,220 @@ +/* + * Copyright 2009(C) Marvell International Ltd. and its affiliates + * Prafulla Wadaskar + * + * Based on drivers/mtd/spi/stmicro.c + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* MX25xx-specific commands */ +#define CMD_MX25XX_WREN 0x06 /* Write Enable */ +#define CMD_MX25XX_WRDI 0x04 /* Write Disable */ +#define CMD_MX25XX_RDSR 0x05 /* Read Status Register */ +#define CMD_MX25XX_WRSR 0x01 /* Write Status Register */ +#define CMD_MX25XX_READ 0x03 /* Read Data Bytes */ +#define CMD_MX25XX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_MX25XX_PP 0x02 /* Page Program */ +#define CMD_MX25XX_SE 0x20 /* Sector Erase */ +#define CMD_MX25XX_BE 0xD8 /* Block Erase */ +#define CMD_MX25XX_CE 0xc7 /* Chip Erase */ +#define CMD_MX25XX_DP 0xb9 /* Deep Power-down */ +#define CMD_MX25XX_RES 0xab /* Release from DP, and Read Signature */ + +#define MACRONIX_SR_WIP (1 << 0) /* Write-in-Progress */ + +struct macronix_spi_flash_params { + u16 idcode; + u16 page_size; + u16 pages_per_sector; + u16 sectors_per_block; + u16 nr_blocks; + const char *name; +}; + +struct macronix_spi_flash { + struct spi_flash flash; + const struct macronix_spi_flash_params *params; +}; + +static inline struct macronix_spi_flash *to_macronix_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct macronix_spi_flash, flash); +} + +static const struct macronix_spi_flash_params macronix_spi_flash_table[] = { + { + .idcode = 0x2015, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "MX25L1605D", + }, + { + .idcode = 0x2016, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "MX25L3205D", + }, + { + .idcode = 0x2017, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "MX25L6405D", + }, + { + .idcode = 0x2018, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "MX25L12805D", + }, + { + .idcode = 0x2618, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "MX25L12855E", + }, +}; + +static int macronix_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct macronix_spi_flash *mcx = to_macronix_spi_flash(flash); + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = min(mcx->params->page_size, CONTROLLER_PAGE_LIMIT); + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_MX25XX_PP; + cmd[1] = (offset >> 16) & 0xff; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_MX25XX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Macronix Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + offset += chunk_len; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: Macronix: Successfully programmed %zu bytes @ 0x%lx\n", + len, offset - len); + + spi_release_bus(flash->spi); + return ret; +} + +static int macronix_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_MX25XX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode) +{ + const struct macronix_spi_flash_params *params; + struct macronix_spi_flash *mcx; + unsigned int i; + u16 id = idcode[2] | idcode[1] << 8; + + for (i = 0; i < ARRAY_SIZE(macronix_spi_flash_table); i++) { + params = ¯onix_spi_flash_table[i]; + if (params->idcode == id) + break; + } + + if (i == ARRAY_SIZE(macronix_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported Macronix ID %04x\n", id); + return NULL; + } + + mcx = malloc(sizeof(*mcx)); + if (!mcx) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + mcx->params = params; + mcx->flash.spi = spi; + mcx->flash.name = params->name; + + mcx->flash.write = macronix_write; + mcx->flash.erase = macronix_erase; +#ifdef CONFIG_SPI_FLASH_NO_FAST_READ + mcx->flash.read = spi_flash_cmd_read_slow; +#else + mcx->flash.read = spi_flash_cmd_read_fast; +#endif + mcx->flash.sector_size = params->page_size * params->pages_per_sector; + mcx->flash.size = mcx->flash.sector_size * params->sectors_per_block * + params->nr_blocks; + + return &mcx->flash; +} diff --git a/src/drivers/spi/ramtron.c b/src/drivers/spi/ramtron.c new file mode 100644 index 0000000..d599cd9 --- /dev/null +++ b/src/drivers/spi/ramtron.c @@ -0,0 +1,315 @@ +/* + * (C) Copyright 2010 + * Reinhard Meyer, EMK Elektronik, reinhard.meyer at emk-elektronik.de + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Note: RAMTRON SPI FRAMs are ferroelectric, nonvolatile RAMs + * with an interface identical to SPI flash devices. + * However since they behave like RAM there are no delays or + * busy polls required. They can sustain read or write at the + * allowed SPI bus speed, which can be 40 MHz for some devices. + * + * Unfortunately some RAMTRON devices do not have a means of + * identifying them. They will leave the SO line undriven when + * the READ-ID command is issued. It is therefore mandatory + * that the MISO line has a proper pull-up, so that READ-ID + * will return a row of 0xff. This 0xff pseudo-id will cause + * probes by all vendor specific functions that are designed + * to handle it. If the MISO line is not pulled up, READ-ID + * could return any random noise, even mimicking another + * device. + * + * We use CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + * to define which device will be assumed after a simple status + * register verify. This method is prone to false positive + * detection and should therefore be the last to be tried. + * Enter it in the last position in the table in spi_flash.c! + * + * The define CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC both activates + * compilation of the special handler and defines the device + * to assume. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* RAMTRON commands common to all devices */ +#define CMD_RAMTRON_WREN 0x06 /* Write Enable */ +#define CMD_RAMTRON_WRDI 0x04 /* Write Disable */ +#define CMD_RAMTRON_RDSR 0x05 /* Read Status Register */ +#define CMD_RAMTRON_WRSR 0x01 /* Write Status Register */ +#define CMD_RAMTRON_READ 0x03 /* Read Data Bytes */ +#define CMD_RAMTRON_WRITE 0x02 /* Write Data Bytes */ +/* not all have those: */ +#define CMD_RAMTRON_FSTRD 0x0b /* Fast Read (for compatibility - not used here) */ +#define CMD_RAMTRON_SLEEP 0xb9 /* Enter Sleep Mode */ +#define CMD_RAMTRON_RDID 0x9f /* Read ID */ +#define CMD_RAMTRON_SNR 0xc3 /* Read Serial Number */ + +/* + * Properties of supported FRAMs + * Note: speed is currently not used because we have no method to deliver that + * value to the upper layers + */ +struct ramtron_spi_fram_params { + u32 size; /* size in bytes */ + u8 addr_len; /* number of address bytes */ + u8 merge_cmd; /* some address bits are in the command byte */ + u8 id1; /* device ID 1 (family, density) */ + u8 id2; /* device ID 2 (sub, rev, rsvd) */ + u32 speed; /* max. SPI clock in Hz */ + const char *name; /* name for display and/or matching */ +}; + +struct ramtron_spi_fram { + struct spi_flash flash; + const struct ramtron_spi_fram_params *params; +}; + +static inline struct ramtron_spi_fram *to_ramtron_spi_fram(struct spi_flash + *flash) +{ + return container_of(flash, struct ramtron_spi_fram, flash); +} + +/* + * table describing supported FRAM chips: + * chips without RDID command must have the values 0xff for id1 and id2 + */ +static const struct ramtron_spi_fram_params ramtron_spi_fram_table[] = { + { + .size = 32*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x22, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V02", + }, + { + .size = 32*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x22, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN02", + }, + { + .size = 64*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x23, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V05", + }, + { + .size = 64*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x23, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN05", + }, + { + .size = 128*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0x24, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V10", + }, + { + .size = 128*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0x24, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN10", + }, +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + { + .size = 256*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0xff, + .id2 = 0xff, + .speed = 40000000, + .name = "FM25H20", + }, +#endif +}; + +static int ramtron_common(struct spi_flash *flash, + u32 offset, size_t len, void *buf, u8 command) +{ + struct ramtron_spi_fram *sn = to_ramtron_spi_fram(flash); + u8 cmd[4]; + int cmd_len; + int ret; + + if (sn->params->addr_len == 3 && sn->params->merge_cmd == 0) { + cmd[0] = command; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + cmd_len = 4; + } else if (sn->params->addr_len == 2 && sn->params->merge_cmd == 0) { + cmd[0] = command; + cmd[1] = offset >> 8; + cmd[2] = offset; + cmd_len = 3; + } else { + printk(BIOS_SPEW, "SF: unsupported addr_len or merge_cmd\n"); + return -1; + } + + /* claim the bus */ + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + if (command == CMD_RAMTRON_WRITE) { + /* send WREN */ + ret = spi_flash_cmd(flash->spi, CMD_RAMTRON_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + goto releasebus; + } + } + + /* do the transaction */ + if (command == CMD_RAMTRON_WRITE) + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, buf, len); + else + ret = spi_flash_cmd_read(flash->spi, cmd, cmd_len, buf, len); + if (ret < 0) + printk(BIOS_SPEW, "SF: Transaction failed\n"); + +releasebus: + /* release the bus */ + spi_release_bus(flash->spi); + return ret; +} + +static int ramtron_read(struct spi_flash *flash, + u32 offset, size_t len, void *buf) +{ + return ramtron_common(flash, offset, len, buf, + CMD_RAMTRON_READ); +} + +static int ramtron_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + return ramtron_common(flash, offset, len, (void *)buf, + CMD_RAMTRON_WRITE); +} + +static int ramtron_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + printk(BIOS_SPEW, "SF: Erase of RAMTRON FRAMs is pointless\n"); + return -1; +} + +/* + * nore: we are called here with idcode pointing to the first non-0x7f byte + * already! + */ +struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode) +{ + const struct ramtron_spi_fram_params *params; + struct ramtron_spi_fram *sn; + unsigned int i; +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + int ret; + u8 sr; +#endif + + /* NOTE: the bus has been claimed before this function is called! */ + switch (idcode[0]) { + case 0xc2: + /* JEDEC conformant RAMTRON id */ + for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) { + params = &ramtron_spi_fram_table[i]; + if (idcode[1] == params->id1 && idcode[2] == params->id2) + goto found; + } + break; +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + case 0xff: + /* + * probably open MISO line, pulled up. + * We COULD have a non JEDEC conformant FRAM here, + * read the status register to verify + */ + ret = spi_flash_cmd(spi, CMD_RAMTRON_RDSR, &sr, 1); + if (ret) + return NULL; + + /* Bits 5,4,0 are fixed 0 for all devices */ + if ((sr & 0x31) != 0x00) + return NULL; + /* now find the device */ + for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) { + params = &ramtron_spi_fram_table[i]; + if (!strcmp(params->name, CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC)) + goto found; + } + printk(BIOS_SPEW, "SF: Unsupported non-JEDEC RAMTRON device " + CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC "\n"); + break; +#endif + default: + break; + } + + /* arriving here means no method has found a device we can handle */ + printk(BIOS_SPEW, "SF/ramtron: unsupported device id0=%02x id1=%02x id2=%02x\n", + idcode[0], idcode[1], idcode[2]); + return NULL; + +found: + sn = malloc(sizeof(*sn)); + if (!sn) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + sn->params = params; + sn->flash.spi = spi; + sn->flash.name = params->name; + + sn->flash.write = ramtron_write; + sn->flash.read = ramtron_read; + sn->flash.erase = ramtron_erase; + sn->flash.size = params->size; + + return &sn->flash; +} diff --git a/src/drivers/spi/spansion.c b/src/drivers/spi/spansion.c new file mode 100644 index 0000000..719a8a8 --- /dev/null +++ b/src/drivers/spi/spansion.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2009 Freescale Semiconductor, Inc. + * + * Author: Mingkai Hu (Mingkai.hu at freescale.com) + * Based on stmicro.c by Wolfgang Denk (wd at denx.de), + * TsiChung Liew (Tsi-Chung.Liew at freescale.com), + * and Jason McMullan (mcmullan at netapp.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* S25FLxx-specific commands */ +#define CMD_S25FLXX_READ 0x03 /* Read Data Bytes */ +#define CMD_S25FLXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_S25FLXX_READID 0x90 /* Read Manufacture ID and Device ID */ +#define CMD_S25FLXX_WREN 0x06 /* Write Enable */ +#define CMD_S25FLXX_WRDI 0x04 /* Write Disable */ +#define CMD_S25FLXX_RDSR 0x05 /* Read Status Register */ +#define CMD_S25FLXX_WRSR 0x01 /* Write Status Register */ +#define CMD_S25FLXX_PP 0x02 /* Page Program */ +#define CMD_S25FLXX_SE 0xd8 /* Sector Erase */ +#define CMD_S25FLXX_BE 0xc7 /* Bulk Erase */ +#define CMD_S25FLXX_DP 0xb9 /* Deep Power-down */ +#define CMD_S25FLXX_RES 0xab /* Release from DP, and Read Signature */ + +#define SPSN_ID_S25FL008A 0x0213 +#define SPSN_ID_S25FL016A 0x0214 +#define SPSN_ID_S25FL032A 0x0215 +#define SPSN_ID_S25FL064A 0x0216 +#define SPSN_ID_S25FL128P 0x2018 +#define SPSN_EXT_ID_S25FL128P_256KB 0x0300 +#define SPSN_EXT_ID_S25FL128P_64KB 0x0301 +#define SPSN_EXT_ID_S25FL032P 0x4d00 + +struct spansion_spi_flash_params { + u16 idcode1; + u16 idcode2; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +struct spansion_spi_flash { + struct spi_flash flash; + const struct spansion_spi_flash_params *params; +}; + +static inline struct spansion_spi_flash *to_spansion_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct spansion_spi_flash, flash); +} + +static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { + { + .idcode1 = SPSN_ID_S25FL008A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "S25FL008A", + }, + { + .idcode1 = SPSN_ID_S25FL016A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "S25FL016A", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032A", + }, + { + .idcode1 = SPSN_ID_S25FL064A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "S25FL064A", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_64KB, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 256, + .name = "S25FL128P_64K", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_256KB, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "S25FL128P_256K", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = SPSN_EXT_ID_S25FL032P, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032P", + }, +}; + +static int spansion_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct spansion_spi_flash *spsn = to_spansion_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = spsn->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_S25FLXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_S25FLXX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: SPANSION Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: SPANSION: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int spansion_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_S25FLXX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) +{ + const struct spansion_spi_flash_params *params; + struct spansion_spi_flash *spsn; + unsigned int i; + unsigned short jedec, ext_jedec; + + jedec = idcode[1] << 8 | idcode[2]; + ext_jedec = idcode[3] << 8 | idcode[4]; + + for (i = 0; i < ARRAY_SIZE(spansion_spi_flash_table); i++) { + params = &spansion_spi_flash_table[i]; + if (params->idcode1 == jedec) { + if (params->idcode2 == ext_jedec) + break; + } + } + + if (i == ARRAY_SIZE(spansion_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported SPANSION ID %04x %04x\n", jedec, ext_jedec); + return NULL; + } + + spsn = malloc(sizeof(struct spansion_spi_flash)); + if (!spsn) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + spsn->params = params; + spsn->flash.spi = spi; + spsn->flash.name = params->name; + + spsn->flash.write = spansion_write; + spsn->flash.erase = spansion_erase; + spsn->flash.read = spi_flash_cmd_read_fast; + spsn->flash.sector_size = params->page_size * params->pages_per_sector; + spsn->flash.size = spsn->flash.sector_size * params->nr_sectors; + + return &spsn->flash; +} diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c new file mode 100644 index 0000000..378f142 --- /dev/null +++ b/src/drivers/spi/spi_flash.c @@ -0,0 +1,327 @@ +/* + * SPI flash interface + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include "spi_flash_internal.h" + +#define CONFIG_SPI_FLASH_EON +#define CONFIG_SPI_FLASH_MACRONIX +#define CONFIG_SPI_FLASH_SPANSION +#define CONFIG_SPI_FLASH_SST +#define CONFIG_SPI_FLASH_STMICRO +#define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_SPI_FLASH_RAMTRON + +static void spi_flash_addr(u32 addr, u8 *cmd) +{ + /* cmd[0] is actual command */ + cmd[1] = addr >> 16; + cmd[2] = addr >> 8; + cmd[3] = addr >> 0; +} + +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) +{ + int ret = spi_xfer(spi, &cmd, 8, response, len * 8); + if (ret) + printk(BIOS_SPEW, "SF: Failed to send command %02x: %d\n", cmd, ret); + + return ret; +} + +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + int ret = spi_xfer(spi, cmd, cmd_len * 8, data, data_len * 8); + if (ret) { + printk(BIOS_SPEW, "SF: Failed to send read command (%zu bytes): %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len) +{ + int ret; + u8 buff[cmd_len + data_len]; + memcpy(buff, cmd, cmd_len); + memcpy(buff + cmd_len, data, data_len); + + ret = spi_xfer(spi, buff, (cmd_len + data_len) * 8, NULL, 0); + if (ret) { + printk(BIOS_SPEW, "SF: Failed to send write command (%zu bytes): %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + struct spi_slave *spi = flash->spi; + int ret; + + spi_claim_bus(spi); + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + spi_release_bus(spi); + + return ret; +} + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[5]; + + cmd[0] = CMD_READ_ARRAY_FAST; + spi_flash_addr(offset, cmd); + cmd[4] = 0x00; + + return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); +} + +int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[4]; + + cmd[0] = CMD_READ_ARRAY_SLOW; + spi_flash_addr(offset, cmd); + + return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); +} + +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 status; + + timebase = timeout; + do { + ret = spi_flash_cmd_read(spi, &cmd, 1, &status, 1); + if (ret) + return -1; + + if ((status & poll_bit) == 0) + break; + + mdelay(1); + } while (timebase--); + + if ((status & poll_bit) == 0) + return 0; + + /* Timed out */ + printk(BIOS_SPEW, "SF: time out!\n"); + return -1; +} + +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + return spi_flash_cmd_poll_bit(flash, timeout, + CMD_READ_STATUS, STATUS_WIP); +} + +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 offset, size_t len) +{ + u32 start, end, erase_size; + int ret; + u8 cmd[4]; + + erase_size = flash->sector_size; + if (offset % erase_size || len % erase_size) { + printk(BIOS_SPEW, "SF: Erase offset/length not multiple of erase size\n"); + return -1; + } + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + cmd[0] = erase_cmd; + start = offset; + end = start + len; + + while (offset < end) { + spi_flash_addr(offset, cmd); + offset += erase_size; + + printk(BIOS_SPEW, "SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) + goto out; + } + + printk(BIOS_SPEW, "SF: Successfully erased %zu bytes @ %#x\n", len, start); + + out: + spi_release_bus(flash->spi); + return ret; +} + +/* + * The following table holds all device probe functions + * + * shift: number of continuation bytes before the ID + * idcode: the expected IDCODE or 0xff for non JEDEC devices + * probe: the function to call + * + * Non JEDEC devices should be ordered in the table such that + * the probe functions with best detection algorithms come first. + * + * Several matching entries are permitted, they will be tried + * in sequence until a probe function returns non NULL. + * + * IDCODE_CONT_LEN may be redefined if a device needs to declare a + * larger "shift" value. IDCODE_PART_LEN generally shouldn't be + * changed. This is the max number of bytes probe functions may + * examine when looking up part-specific identification info. + * + * Probe functions will be given the idcode buffer starting at their + * manu id byte (the "idcode" in the table below). In other words, + * all of the continuation bytes will be skipped (the "shift" below). + */ +#define IDCODE_CONT_LEN 0 +#define IDCODE_PART_LEN 5 +static const struct { + const u8 shift; + const u8 idcode; + struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); +} flashes[] = { + /* Keep it sorted by define name */ +#ifdef CONFIG_SPI_FLASH_ATMEL + { 0, 0x1f, spi_flash_probe_atmel, }, +#endif +#ifdef CONFIG_SPI_FLASH_EON + { 0, 0x1c, spi_flash_probe_eon, }, +#endif +#ifdef CONFIG_SPI_FLASH_MACRONIX + { 0, 0xc2, spi_flash_probe_macronix, }, +#endif +#ifdef CONFIG_SPI_FLASH_SPANSION + { 0, 0x01, spi_flash_probe_spansion, }, +#endif +#ifdef CONFIG_SPI_FLASH_SST + { 0, 0xbf, spi_flash_probe_sst, }, +#endif +#ifdef CONFIG_SPI_FLASH_STMICRO + { 0, 0x20, spi_flash_probe_stmicro, }, +#endif +#ifdef CONFIG_SPI_FLASH_WINBOND + { 0, 0xef, spi_flash_probe_winbond, }, +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON + { 6, 0xc2, spi_fram_probe_ramtron, }, +# undef IDCODE_CONT_LEN +# define IDCODE_CONT_LEN 6 +#endif + /* Keep it sorted by best detection */ +#ifdef CONFIG_SPI_FLASH_STMICRO + { 0, 0xff, spi_flash_probe_stmicro, }, +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + { 0, 0xff, spi_fram_probe_ramtron, }, +#endif +}; +#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_slave *spi; + struct spi_flash *flash = NULL; + int ret, i, shift; + u8 idcode[IDCODE_LEN], *idp; + + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); + if (!spi) { + printk(BIOS_SPEW, "SF: Failed to set up slave\n"); + return NULL; + } + + ret = spi_claim_bus(spi); + if (ret) { + printk(BIOS_SPEW, "SF: Failed to claim SPI bus: %d\n", ret); + goto err_claim_bus; + } + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); + if (ret) + goto err_read_id; + +#ifdef DEBUG + printk(BIOS_SPEW, "SF: Got idcodes\n"); + print_buffer(0, idcode, 1, sizeof(idcode), 0); +#endif + + /* count the number of continuation bytes */ + for (shift = 0, idp = idcode; + shift < IDCODE_CONT_LEN && *idp == 0x7f; + ++shift, ++idp) + continue; + + /* search the table for matches in shift and id */ + for (i = 0; i < ARRAY_SIZE(flashes); ++i) + if (flashes[i].shift == shift && flashes[i].idcode == *idp) { + /* we have a match, call probe */ + flash = flashes[i].probe(spi, idp); + if (flash) + break; + } + + if (!flash) { + printk(BIOS_SPEW, "SF: Unsupported manufacturer %02x\n", *idp); + goto err_manufacturer_probe; + } + + printk(BIOS_SPEW, "SF: Detected %s with page size %x, total %x\n", flash->name, flash->sector_size, flash->size); + + spi_release_bus(spi); + + return flash; + +err_manufacturer_probe: +err_read_id: + spi_release_bus(spi); +err_claim_bus: + spi_free_slave(spi); + return NULL; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_free_slave(flash->spi); + free(flash); +} diff --git a/src/drivers/spi/spi_flash_internal.h b/src/drivers/spi/spi_flash_internal.h new file mode 100644 index 0000000..b895e2b --- /dev/null +++ b/src/drivers/spi/spi_flash_internal.h @@ -0,0 +1,81 @@ +/* + * SPI flash internal definitions + * + * Copyright (C) 2008 Atmel Corporation + */ + +/* Common parameters -- kind of high, but they should only occur when there + * is a problem (and well your system already is broken), so err on the side + * of caution in case we're dealing with slower SPI buses and/or processors. + */ +#define CONFIG_SYS_HZ 100 +#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) +#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) +#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) + +/* Common commands */ +#define CMD_READ_ID 0x9f + +#define CMD_READ_ARRAY_SLOW 0x03 +#define CMD_READ_ARRAY_FAST 0x0b +#define CMD_READ_ARRAY_LEGACY 0xe8 + +#define CMD_READ_STATUS 0x05 +#define CMD_WRITE_ENABLE 0x06 + +/* Common status */ +#define STATUS_WIP 0x01 + +/* Send a single-byte command to the device and read the response */ +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); + +/* + * Send a multi-byte command to the device and read the response. Used + * for flash array reads, etc. + */ +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +/* + * Send a multi-byte command to the device followed by (optional) + * data. Used for programming the flash array, etc. + */ +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len); + +/* + * Same as spi_flash_cmd_read() except it also claims/releases the SPI + * bus. Used as common part of the ->read() operation. + */ +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* Send a command to the device and wait for some bit to clear itself. */ +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit); + +/* + * Send the read status command to the device and wait for the wip + * (write-in-progress) bit to clear itself. + */ +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); + +/* Erase sectors. */ +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 offset, size_t len); + +/* Manufacturer-specific probe functions */ +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode); diff --git a/src/drivers/spi/sst.c b/src/drivers/spi/sst.c new file mode 100644 index 0000000..9c87dae --- /dev/null +++ b/src/drivers/spi/sst.c @@ -0,0 +1,268 @@ +/* + * Driver for SST serial flashes + * + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd at denx.de. + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +#define CMD_SST_WREN 0x06 /* Write Enable */ +#define CMD_SST_WRDI 0x04 /* Write Disable */ +#define CMD_SST_RDSR 0x05 /* Read Status Register */ +#define CMD_SST_WRSR 0x01 /* Write Status Register */ +#define CMD_SST_READ 0x03 /* Read Data Bytes */ +#define CMD_SST_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_SST_BP 0x02 /* Byte Program */ +#define CMD_SST_AAI_WP 0xAD /* Auto Address Increment Word Program */ +#define CMD_SST_SE 0x20 /* Sector Erase */ + +#define SST_SR_WIP (1 << 0) /* Write-in-Progress */ +#define SST_SR_WEL (1 << 1) /* Write enable */ +#define SST_SR_BP0 (1 << 2) /* Block Protection 0 */ +#define SST_SR_BP1 (1 << 3) /* Block Protection 1 */ +#define SST_SR_BP2 (1 << 4) /* Block Protection 2 */ +#define SST_SR_AAI (1 << 6) /* Addressing mode */ +#define SST_SR_BPL (1 << 7) /* BP bits lock */ + +struct sst_spi_flash_params { + u8 idcode1; + u16 nr_sectors; + const char *name; +}; + +struct sst_spi_flash { + struct spi_flash flash; + const struct sst_spi_flash_params *params; +}; + +static inline struct sst_spi_flash *to_sst_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct sst_spi_flash, flash); +} + +#define SST_SECTOR_SIZE (4 * 1024) +static const struct sst_spi_flash_params sst_spi_flash_table[] = { + { + .idcode1 = 0x8d, + .nr_sectors = 128, + .name = "SST25VF040B", + },{ + .idcode1 = 0x8e, + .nr_sectors = 256, + .name = "SST25VF080B", + },{ + .idcode1 = 0x41, + .nr_sectors = 512, + .name = "SST25VF016B", + },{ + .idcode1 = 0x4a, + .nr_sectors = 1024, + .name = "SST25VF032B", + },{ + .idcode1 = 0x4b, + .nr_sectors = 2048, + .name = "SST25VF064C", + },{ + .idcode1 = 0x01, + .nr_sectors = 16, + .name = "SST25WF512", + },{ + .idcode1 = 0x02, + .nr_sectors = 32, + .name = "SST25WF010", + },{ + .idcode1 = 0x03, + .nr_sectors = 64, + .name = "SST25WF020", + },{ + .idcode1 = 0x04, + .nr_sectors = 128, + .name = "SST25WF040", + }, +}; + +static int +sst_enable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WREN, NULL, 0); + if (ret) + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + return ret; +} + +static int +sst_disable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WRDI, NULL, 0); + if (ret) + printk(BIOS_SPEW, "SF: Disabling Write failed\n"); + return ret; +} + +static int +sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) +{ + int ret; + u8 cmd[4] = { + CMD_SST_BP, + offset >> 16, + offset >> 8, + offset, + }; + + printk(BIOS_SPEW, "BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf, cmd[0], offset); + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); + if (ret) + return ret; + + return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); +} + +static int +sst_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) +{ + size_t actual, cmd_len; + int ret; + u8 cmd[4]; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + /* If the data is not word aligned, write out leading single byte */ + actual = offset % 2; + if (actual) { + ret = sst_byte_write(flash, offset, buf); + if (ret) + goto done; + } + offset += actual; + + ret = sst_enable_writing(flash); + if (ret) + goto done; + + cmd_len = 4; + cmd[0] = CMD_SST_AAI_WP; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + + for (; actual < len - 1; actual += 2) { + printk(BIOS_SPEW, "WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf + actual, cmd[0], + offset); + + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, + buf + actual, 2); + if (ret) { + printk(BIOS_SPEW, "SF: sst word program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + cmd_len = 1; + offset += 2; + } + + if (!ret) + ret = sst_disable_writing(flash); + + /* If there is a single trailing byte, write it out */ + if (!ret && actual != len) + ret = sst_byte_write(flash, offset, buf + actual); + + done: + printk(BIOS_SPEW, "SF: sst: program %s %zu bytes @ 0x%lx\n", + ret ? "failure" : "success", len, offset - actual); + + spi_release_bus(flash->spi); + return ret; +} + +static int sst_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_SST_SE, offset, len); +} + +static int +sst_unlock(struct spi_flash *flash) +{ + int ret; + u8 cmd, status; + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + cmd = CMD_SST_WRSR; + status = 0; + ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &status, 1); + if (ret) + printk(BIOS_SPEW, "SF: Unable to set status byte\n"); + + printk(BIOS_SPEW, "SF: sst: status = %x\n", spi_w8r8(flash->spi, CMD_SST_RDSR)); + + return ret; +} + +struct spi_flash * +spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode) +{ + const struct sst_spi_flash_params *params; + struct sst_spi_flash *stm; + size_t i; + + for (i = 0; i < ARRAY_SIZE(sst_spi_flash_table); ++i) { + params = &sst_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(sst_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported SST ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(*stm)); + if (!stm) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = sst_write; + stm->flash.erase = sst_erase; + stm->flash.read = spi_flash_cmd_read_fast; + stm->flash.sector_size = SST_SECTOR_SIZE; + stm->flash.size = stm->flash.sector_size * params->nr_sectors; + + /* Flash powers up read-only, so clear BP# bits */ + sst_unlock(&stm->flash); + + return &stm->flash; +} diff --git a/src/drivers/spi/stmicro.c b/src/drivers/spi/stmicro.c new file mode 100644 index 0000000..370d15a --- /dev/null +++ b/src/drivers/spi/stmicro.c @@ -0,0 +1,250 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd at denx.de. + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_M25PXX_WREN 0x06 /* Write Enable */ +#define CMD_M25PXX_WRDI 0x04 /* Write Disable */ +#define CMD_M25PXX_RDSR 0x05 /* Read Status Register */ +#define CMD_M25PXX_WRSR 0x01 /* Write Status Register */ +#define CMD_M25PXX_READ 0x03 /* Read Data Bytes */ +#define CMD_M25PXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_M25PXX_PP 0x02 /* Page Program */ +#define CMD_M25PXX_SE 0xd8 /* Sector Erase */ +#define CMD_M25PXX_BE 0xc7 /* Bulk Erase */ +#define CMD_M25PXX_DP 0xb9 /* Deep Power-down */ +#define CMD_M25PXX_RES 0xab /* Release from DP, and Read Signature */ + +#define STM_ID_M25P10 0x11 +#define STM_ID_M25P16 0x15 +#define STM_ID_M25P20 0x12 +#define STM_ID_M25P32 0x16 +#define STM_ID_M25P40 0x13 +#define STM_ID_M25P64 0x17 +#define STM_ID_M25P80 0x14 +#define STM_ID_M25P128 0x18 + +struct stmicro_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct stmicro_spi_flash { + struct spi_flash flash; + const struct stmicro_spi_flash_params *params; +}; + +static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct stmicro_spi_flash, flash); +} + +static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { + { + .idcode1 = STM_ID_M25P10, + .page_size = 256, + .pages_per_sector = 128, + .nr_sectors = 4, + .name = "M25P10", + }, + { + .idcode1 = STM_ID_M25P16, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "M25P16", + }, + { + .idcode1 = STM_ID_M25P20, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 4, + .name = "M25P20", + }, + { + .idcode1 = STM_ID_M25P32, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "M25P32", + }, + { + .idcode1 = STM_ID_M25P40, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 8, + .name = "M25P40", + }, + { + .idcode1 = STM_ID_M25P64, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "M25P64", + }, + { + .idcode1 = STM_ID_M25P80, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "M25P80", + }, + { + .idcode1 = STM_ID_M25P128, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "M25P128", + }, +}; + +static int stmicro_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = stm->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_M25PXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: STMicro Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: STMicro: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_M25PXX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) +{ + const struct stmicro_spi_flash_params *params; + struct stmicro_spi_flash *stm; + unsigned int i; + + if (idcode[0] == 0xff) { + i = spi_flash_cmd(spi, CMD_M25PXX_RES, + idcode, 4); + if (i) + return NULL; + if ((idcode[3] & 0xf0) == 0x10) { + idcode[0] = 0x20; + idcode[1] = 0x20; + idcode[2] = idcode[3] + 1; + } else + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) { + params = &stmicro_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) { + break; + } + } + + if (i == ARRAY_SIZE(stmicro_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported STMicro ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(struct stmicro_spi_flash)); + if (!stm) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = stmicro_write; + stm->flash.erase = stmicro_erase; + stm->flash.read = spi_flash_cmd_read_fast; + stm->flash.sector_size = params->page_size * params->pages_per_sector; + stm->flash.size = stm->flash.sector_size * params->nr_sectors; + + return &stm->flash; +} diff --git a/src/drivers/spi/winbond.c b/src/drivers/spi/winbond.c new file mode 100644 index 0000000..4329c55 --- /dev/null +++ b/src/drivers/spi/winbond.c @@ -0,0 +1,218 @@ +/* + * Copyright 2008, Network Appliance Inc. + * Author: Jason McMullan netapp.com> + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_W25_WREN 0x06 /* Write Enable */ +#define CMD_W25_WRDI 0x04 /* Write Disable */ +#define CMD_W25_RDSR 0x05 /* Read Status Register */ +#define CMD_W25_WRSR 0x01 /* Write Status Register */ +#define CMD_W25_READ 0x03 /* Read Data Bytes */ +#define CMD_W25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_W25_PP 0x02 /* Page Program */ +#define CMD_W25_SE 0x20 /* Sector (4K) Erase */ +#define CMD_W25_BE 0xd8 /* Block (64K) Erase */ +#define CMD_W25_CE 0xc7 /* Chip Erase */ +#define CMD_W25_DP 0xb9 /* Deep Power-down */ +#define CMD_W25_RES 0xab /* Release from DP, and Read Signature */ + +struct winbond_spi_flash_params { + uint16_t id; + /* Log2 of page size in power-of-two mode */ + uint8_t l2_page_size; + uint16_t pages_per_sector; + uint16_t sectors_per_block; + uint16_t nr_blocks; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct winbond_spi_flash { + struct spi_flash flash; + const struct winbond_spi_flash_params *params; +}; + +static inline struct winbond_spi_flash * +to_winbond_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct winbond_spi_flash, flash); +} + +static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { + { + .id = 0x3015, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "W25X16", + }, + { + .id = 0x3016, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "W25X32", + }, + { + .id = 0x3017, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "W25X64", + }, + { + .id = 0x4015, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "W25Q16", + }, + { + .id = 0x4016, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "W25Q32", + }, + { + .id = 0x4017, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "W25Q64", + }, + { + .id = 0x4018, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "W25Q128", + }, +}; + +static int winbond_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct winbond_spi_flash *stm = to_winbond_spi_flash(flash); + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT); + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_W25_PP; + cmd[1] = (offset >> 16) & 0xff; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %ld\n", + buf + actual, + cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_W25_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + goto out; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Winbond Page Program failed\n"); + goto out; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + goto out; + + offset += chunk_len; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: Winbond: Successfully programmed %zu bytes @ 0x%lx\n", + len, offset - len); + ret = 0; + +out: + spi_release_bus(flash->spi); + return ret; +} + +static int winbond_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_W25_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) +{ + const struct winbond_spi_flash_params *params; + unsigned page_size; + struct winbond_spi_flash *stm; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(winbond_spi_flash_table); i++) { + params = &winbond_spi_flash_table[i]; + if (params->id == ((idcode[1] << 8) | idcode[2])) + break; + } + + if (i == ARRAY_SIZE(winbond_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported Winbond ID %02x%02x\n", + idcode[1], idcode[2]); + return NULL; + } + + stm = malloc(sizeof(struct winbond_spi_flash)); + if (!stm) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + /* Assuming power-of-two page size initially. */ + page_size = 1 << params->l2_page_size; + + stm->flash.write = winbond_write; + stm->flash.erase = winbond_erase; +#ifdef CONFIG_SPI_FLASH_NO_FAST_READ + stm->flash.read = spi_flash_cmd_read_slow; +#else + stm->flash.read = spi_flash_cmd_read_fast; +#endif + stm->flash.sector_size = (1 << stm->params->l2_page_size) * + stm->params->pages_per_sector; + stm->flash.size = page_size * params->pages_per_sector + * params->sectors_per_block + * params->nr_blocks; + + return &stm->flash; +} diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h index a2d6884..1765293 100644 --- a/src/include/device/pci_ids.h +++ b/src/include/device/pci_ids.h @@ -2502,6 +2502,10 @@ #define PCI_DEVICE_ID_INTEL_82801IO_LPC 0x2914 #define PCI_DEVICE_ID_INTEL_82801IH_LPC 0x2912 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f +#define PCI_DEVICE_ID_INTEL_TGP_LPC 0x27bc + /* Intel 82801E (C-ICH) */ #define PCI_DEVICE_ID_INTEL_82801E_LPC 0x2450 #define PCI_DEVICE_ID_INTEL_82801E_USB 0x2452 diff --git a/src/include/spi.h b/src/include/spi.h new file mode 100644 index 0000000..bb84258 --- /dev/null +++ b/src/include/spi.h @@ -0,0 +1,203 @@ +/* + * (C) Copyright 2001 + * Gerald Van Baren, Custom IDEAS, vanbaren at cideas.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _SPI_H_ +#define _SPI_H_ + +#include + +/* Controller-specific definitions: */ + +/* SPI mode flags */ +#define SPI_CPHA 0x01 /* clock phase */ +#define SPI_CPOL 0x02 /* clock polarity */ +#define SPI_MODE_0 (0|0) /* (original MicroWire) */ +#define SPI_MODE_1 (0|SPI_CPHA) +#define SPI_MODE_2 (SPI_CPOL|0) +#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) +#define SPI_CS_HIGH 0x04 /* CS active high */ +#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ +#define SPI_3WIRE 0x10 /* SI/SO signals shared */ +#define SPI_LOOP 0x20 /* loopback mode */ + +/* SPI transfer flags */ +#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ +#define SPI_XFER_END 0x02 /* Deassert CS after transfer */ + +/*----------------------------------------------------------------------- + * Representation of a SPI slave, i.e. what we're communicating with. + * + * Drivers are expected to extend this with controller-specific data. + * + * bus: ID of the bus that the slave is attached to. + * cs: ID of the chip select connected to the slave. + */ +struct spi_slave { + unsigned int bus; + unsigned int cs; +}; + +/*----------------------------------------------------------------------- + * Initialization, must be called once on start up. + * + * TODO: I don't think we really need this. + */ +void spi_init(void); + +/*----------------------------------------------------------------------- + * Set up communications parameters for a SPI slave. + * + * This must be called once for each slave. Note that this function + * usually doesn't touch any actual hardware, it only initializes the + * contents of spi_slave so that the hardware can be easily + * initialized later. + * + * bus: Bus ID of the slave chip. + * cs: Chip select ID of the slave chip on the specified bus. + * max_hz: Maximum SCK rate in Hz. + * mode: Clock polarity, clock phase and other parameters. + * + * Returns: A spi_slave reference that can be used in subsequent SPI + * calls, or NULL if one or more of the parameters are not supported. + */ +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode); + +/*----------------------------------------------------------------------- + * Free any memory associated with a SPI slave. + * + * slave: The SPI slave + */ +void spi_free_slave(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Claim the bus and prepare it for communication with a given slave. + * + * This must be called before doing any transfers with a SPI slave. It + * will enable and initialize any SPI hardware as necessary, and make + * sure that the SCK line is in the correct idle state. It is not + * allowed to claim the same bus for several slaves without releasing + * the bus in between. + * + * slave: The SPI slave + * + * Returns: 0 if the bus was claimed successfully, or a negative value + * if it wasn't. + */ +int spi_claim_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Release the SPI bus + * + * This must be called once for every call to spi_claim_bus() after + * all transfers have finished. It may disable any SPI hardware as + * appropriate. + * + * slave: The SPI slave + */ +void spi_release_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * SPI transfer + * + * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks + * "bitlen" bits in the SPI MISO port. That's just the way SPI works. + * + * The source of the outgoing bits is the "dout" parameter and the + * destination of the input bits is the "din" parameter. Note that "dout" + * and "din" can point to the same memory location, in which case the + * input data overwrites the output data (since both are buffered by + * temporary variables, this is OK). + * + * spi_xfer() interface: + * slave: The SPI slave which will be sending/receiving the data. + * dout: Pointer to a string of bits to send out. The bits are + * held in a byte array and are sent MSB first. + * bitsout: How many bits to write. + * din: Pointer to a string of bits that will be filled in. + * bitsin: How many bits to read. + * + * Returns: 0 on success, not 0 on failure + */ +int spi_xfer(struct spi_slave *slave, const void *dout, unsigned int bitsout, + void *din, unsigned int bitsin); + +/*----------------------------------------------------------------------- + * Determine if a SPI chipselect is valid. + * This function is provided by the board if the low-level SPI driver + * needs it to determine if a given chipselect is actually valid. + * + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 + * otherwise. + */ +int spi_cs_is_valid(unsigned int bus, unsigned int cs); + +/*----------------------------------------------------------------------- + * Activate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should activate the chip select + * to the device identified by "slave". + */ +void spi_cs_activate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Deactivate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should deactivate the chip + * select to the device identified by "slave". + */ +void spi_cs_deactivate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Set transfer speed. + * This sets a new speed to be applied for next spi_xfer(). + * slave: The SPI slave + * hz: The transfer speed + */ +void spi_set_speed(struct spi_slave *slave, uint32_t hz); + +/*----------------------------------------------------------------------- + * Write 8 bits, then read 8 bits. + * slave: The SPI slave we're communicating with + * byte: Byte to be written + * + * Returns: The value that was read, or a negative value on error. + * + * TODO: This function probably shouldn't be inlined. + */ +static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) +{ + unsigned char dout[2]; + unsigned char din[2]; + int ret; + + dout[0] = byte; + dout[1] = 0; + + ret = spi_xfer(slave, dout, 16, din, 16); + return ret < 0 ? ret : din[1]; +} + +#endif /* _SPI_H_ */ diff --git a/src/include/spi_flash.h b/src/include/spi_flash.h new file mode 100644 index 0000000..2a1dcd4 --- /dev/null +++ b/src/include/spi_flash.h @@ -0,0 +1,91 @@ +/* + * Interface to SPI flash + * + * Copyright (C) 2008 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _SPI_FLASH_H_ +#define _SPI_FLASH_H_ + +#include +#include +#include +#include + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define min(a, b) ((a)<(b)?(a):(b)) + +#define CONFIG_ICH_SPI +#ifdef CONFIG_ICH_SPI +#define CONTROLLER_PAGE_LIMIT 64 +#else +/* any number larger than 4K would do, actually */ +#define CONTROLLER_PAGE_LIMIT ((int)(~0U>>1)) +#endif + +struct spi_flash { + struct spi_slave *spi; + + const char *name; + + u32 size; + + u32 sector_size; + + int (*read)(struct spi_flash *flash, u32 offset, + size_t len, void *buf); + int (*write)(struct spi_flash *flash, u32 offset, + size_t len, const void *buf); + int (*erase)(struct spi_flash *flash, u32 offset, + size_t len); +}; + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode); +void spi_flash_free(struct spi_flash *flash); + +static inline int spi_flash_read(struct spi_flash *flash, u32 offset, + size_t len, void *buf) +{ + return flash->read(flash, offset, len, buf); +} + +static inline int spi_flash_write(struct spi_flash *flash, u32 offset, + size_t len, const void *buf) +{ + return flash->write(flash, offset, len, buf); +} + +static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, + size_t len) +{ + return flash->erase(flash, offset, len); +} + +#endif /* _SPI_FLASH_H_ */ diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 8209980..6548b32 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -340,6 +340,7 @@ void sdram_initialize(struct pei_data *pei_data) /* If MRC data is not found we cannot continue S3 resume. */ if (pei_data->boot_mode == 2 && !pei_data->mrc_input) { + printk(BIOS_DEBUG, "Giving up in sdram_initialize: No MRC data\n"); outb(0x6, 0xcf9); hlt(); } diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc index 5732254..f086426 100644 --- a/src/southbridge/intel/bd82x6x/Makefile.inc +++ b/src/southbridge/intel/bd82x6x/Makefile.inc @@ -34,6 +34,8 @@ ramstage-y += me_status.c ramstage-y += reset.c ramstage-y += watchdog.c +ramstage-y += spi.c + ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c $(me-src-y) finalize.c diff --git a/src/southbridge/intel/bd82x6x/spi.c b/src/southbridge/intel/bd82x6x/spi.c new file mode 100644 index 0000000..c54a325 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/spi.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* This file is derived from the flashrom project. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define min(a, b) ((a)<(b)?(a):(b)) + +typedef device_t pci_dev_t; +#define pci_read_config_byte(dev, reg, targ) *(targ) = pci_read_config8(dev, reg) +#define pci_read_config_word(dev, reg, targ) *(targ) = pci_read_config16(dev, reg) +#define pci_read_config_dword(dev, reg, targ) *(targ) = pci_read_config32(dev, reg) +#define pci_write_config_byte(dev, reg, val) pci_write_config8(dev, reg, val) +#define pci_write_config_word(dev, reg, val) pci_write_config16(dev, reg, val) +#define pci_write_config_dword(dev, reg, val) pci_write_config32(dev, reg, val) + +typedef struct spi_slave ich_spi_slave; + +static int ichspi_lock = 0; + +typedef struct ich7_spi_regs { + uint16_t spis; + uint16_t spic; + uint32_t spia; + uint64_t spid[8]; + uint64_t _pad; + uint32_t bbar; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; +} __attribute__((packed)) ich7_spi_regs; + +typedef struct ich9_spi_regs { + uint32_t bfpr; + uint16_t hsfs; + uint16_t hsfc; + uint32_t faddr; + uint32_t _reserved0; + uint32_t fdata[16]; + uint32_t frap; + uint32_t freg[5]; + uint32_t _reserved1[3]; + uint32_t pr[5]; + uint32_t _reserved2[2]; + uint8_t ssfs; + uint8_t ssfc[3]; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; + uint32_t bbar; + uint8_t _reserved3[12]; + uint32_t fdoc; + uint32_t fdod; + uint8_t _reserved4[8]; + uint32_t afc; + uint32_t lvscc; + uint32_t uvscc; + uint8_t _reserved5[4]; + uint32_t fpb; + uint8_t _reserved6[28]; + uint32_t srdl; + uint32_t srdc; + uint32_t srd; +} __attribute__((packed)) ich9_spi_regs; + +typedef struct ich_spi_controller { + int locked; + + uint8_t *opmenu; + int menubytes; + uint16_t *preop; + uint16_t *optype; + uint32_t *addr; + uint8_t *data; + unsigned databytes; + uint8_t *status; + uint16_t *control; + uint32_t *bbar; +} ich_spi_controller; + +static ich_spi_controller cntlr; + +enum { + SPIS_SCIP = 0x0001, + SPIS_GRANT = 0x0002, + SPIS_CDS = 0x0004, + SPIS_FCERR = 0x0008, + SSFS_AEL = 0x0010, + SPIS_LOCK = 0x8000, + SPIS_RESERVED_MASK = 0x7ff0, + SSFS_RESERVED_MASK = 0x7fe2 +}; + +enum { + SPIC_SCGO = 0x000002, + SPIC_ACS = 0x000004, + SPIC_SPOP = 0x000008, + SPIC_DBC = 0x003f00, + SPIC_DS = 0x004000, + SPIC_SME = 0x008000, + SSFC_SCF_MASK = 0x070000, + SSFC_RESERVED = 0xf80000 +}; + +enum { + HSFS_FDONE = 0x0001, + HSFS_FCERR = 0x0002, + HSFS_AEL = 0x0004, + HSFS_BERASE_MASK = 0x0018, + HSFS_BERASE_SHIFT = 3, + HSFS_SCIP = 0x0020, + HSFS_FDOPSS = 0x2000, + HSFS_FDV = 0x4000, + HSFS_FLOCKDN = 0x8000 +}; + +enum { + HSFC_FGO = 0x0001, + HSFC_FCYCLE_MASK = 0x0006, + HSFC_FCYCLE_SHIFT = 1, + HSFC_FDBC_MASK = 0x3f00, + HSFC_FDBC_SHIFT = 8, + HSFC_FSMIE = 0x8000 +}; + +enum { + SPI_OPCODE_TYPE_READ_NO_ADDRESS = 0, + SPI_OPCODE_TYPE_WRITE_NO_ADDRESS = 1, + SPI_OPCODE_TYPE_READ_WITH_ADDRESS = 2, + SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS = 3 +}; + +#ifdef DEBUG + +static u8 readb_(const void *addr) +{ + u8 v = readb(addr); + printk(BIOS_DEBUG, "read %2.2x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u16 readw_(const void *addr) +{ + u16 v = readw(addr); + printk(BIOS_DEBUG, "read %4.4x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u32 readl_(const void *addr) +{ + u32 v = readl(addr); + printk(BIOS_DEBUG, "read %8.8x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static void writeb_(u8 b, const void *addr) +{ + writeb(b, addr); + printk(BIOS_DEBUG, "wrote %2.2x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writew_(u16 b, const void *addr) +{ + writew(b, addr); + printk(BIOS_DEBUG, "wrote %4.4x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writel_(u32 b, const void *addr) +{ + writel(b, addr); + printk(BIOS_DEBUG, "wrote %8.8x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +#else /* DEBUG ^^^ defined vvv NOT defined */ + +#define readb_(a) read8((uint32_t)a) +#define readw_(a) read16((uint32_t)a) +#define readl_(a) read32((uint32_t)a) +#define writeb_(val, addr) write8((uint32_t)addr, val) +#define writew_(val, addr) write16((uint32_t)addr, val) +#define writel_(val, addr) write32((uint32_t)addr, val) + +#endif /* DEBUG ^^^ NOT defined */ + +static void write_reg(const void *value, void *dest, uint32_t size) +{ + const uint8_t *bvalue = value; + uint8_t *bdest = dest; + + while (size >= 4) { + writel_(*(const uint32_t *)bvalue, bdest); + bdest += 4; bvalue += 4; size -= 4; + } + while (size) { + writeb_(*bvalue, bdest); + bdest++; bvalue++; size--; + } +} + +static void read_reg(const void *src, void *value, uint32_t size) +{ + const uint8_t *bsrc = src; + uint8_t *bvalue = value; + + while (size >= 4) { + *(uint32_t *)bvalue = readl_(bsrc); + bsrc += 4; bvalue += 4; size -= 4; + } + while (size) { + *bvalue = readb_(bsrc); + bsrc++; bvalue++; size--; + } +} + +static void ich_set_bbar(uint32_t minaddr) +{ + const uint32_t bbar_mask = 0x00ffff00; + uint32_t ichspi_bbar; + + minaddr &= bbar_mask; + ichspi_bbar = readl_(cntlr.bbar) & ~bbar_mask; + ichspi_bbar |= minaddr; + writel_(ichspi_bbar, cntlr.bbar); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + printk(BIOS_DEBUG, "spi_cs_is_valid used but not implemented\n"); + return 0; +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + ich_spi_slave *slave = malloc(sizeof(*slave)); + + if (!slave) { + printk(BIOS_DEBUG, "ICH SPI: Bad allocation\n"); + return NULL; + } + + memset(slave, 0, sizeof(*slave)); + + slave->bus = bus; + slave->cs = cs; + return slave; +} + +void spi_free_slave(struct spi_slave *_slave) +{ + ich_spi_slave *slave = (ich_spi_slave *)_slave; + free(slave); +} + +static inline int spi_is_cougarpoint_lpc(uint16_t device_id) +{ + return device_id >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN && + device_id <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX; +}; + +void spi_init(void) +{ + int ich_version = 0; + + uint8_t *rcrb; /* Root Complex Register Block */ + uint32_t rcba; /* Root Complex Base Address */ + uint8_t bios_cntl; + pci_dev_t dev; + + int bus; + int last_bus = 1; //FIXME: pci_last_busno(); + + if (last_bus == -1) { + printk(BIOS_DEBUG, "No PCI busses?\n"); + return; + } + + for (bus = 0; bus <= last_bus; bus++) { + uint32_t ids; + uint16_t vendor_id, device_id; + + dev = dev_find_slot(bus, PCI_DEVFN(31, 0)); + pci_read_config_dword(dev, 0, &ids); + vendor_id = ids; + device_id = (ids >> 16); + + if (vendor_id != PCI_VENDOR_ID_INTEL) + continue; + + if (device_id == PCI_DEVICE_ID_INTEL_TGP_LPC) { + ich_version = 7; + break; + } else if (spi_is_cougarpoint_lpc(device_id)) { + ich_version = 9; + break; + } + } + + if (!ich_version) { + printk(BIOS_DEBUG, "ICH SPI: No ICH found.\n"); + return; + } + + pci_read_config_dword(dev, 0xf0, &rcba); + /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable. */ + rcrb = (uint8_t *)(rcba & 0xffffc000); + switch (ich_version) { + case 7: + { + const uint16_t ich7_spibar_offset = 0x3020; + ich7_spi_regs *ich7_spi = + (ich7_spi_regs *)(rcrb + ich7_spibar_offset); + + ichspi_lock = readw_(&ich7_spi->spis) & SPIS_LOCK; + cntlr.opmenu = ich7_spi->opmenu; + cntlr.menubytes = sizeof(ich7_spi->opmenu); + cntlr.optype = &ich7_spi->optype; + cntlr.addr = &ich7_spi->spia; + cntlr.data = (uint8_t *)ich7_spi->spid; + cntlr.databytes = sizeof(ich7_spi->spid); + cntlr.status = (uint8_t *)&ich7_spi->spis; + cntlr.control = &ich7_spi->spic; + cntlr.bbar = &ich7_spi->bbar; + cntlr.preop = &ich7_spi->preop; + break; + } + case 9: + { + const uint16_t ich9_spibar_offset = 0x3800; + ich9_spi_regs *ich9_spi = + (ich9_spi_regs *)(rcrb + ich9_spibar_offset); + ichspi_lock = readw_(&ich9_spi->hsfs) & HSFS_FLOCKDN; + cntlr.opmenu = ich9_spi->opmenu; + cntlr.menubytes = sizeof(ich9_spi->opmenu); + cntlr.optype = &ich9_spi->optype; + cntlr.addr = &ich9_spi->faddr; + cntlr.data = (uint8_t *)ich9_spi->fdata; + cntlr.databytes = sizeof(ich9_spi->fdata); + cntlr.status = &ich9_spi->ssfs; + cntlr.control = (uint16_t *)ich9_spi->ssfc; + cntlr.bbar = &ich9_spi->bbar; + cntlr.preop = &ich9_spi->preop; + break; + } + default: + printk(BIOS_DEBUG, "ICH SPI: Unrecognized ICH version %d.\n", ich_version); + } + + ich_set_bbar(0); + + /* Disable the BIOS write protect so write commands are allowed. */ + pci_read_config_byte(dev, 0xdc, &bios_cntl); + switch (ich_version) { + case 9: + /* Deassert SMM BIOS Write Protect Disable. */ + bios_cntl &= ~(1 << 5); + break; + + default: + break; + } + pci_write_config_byte(dev, 0xdc, bios_cntl | 0x1); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_activate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +typedef struct spi_transaction { + const uint8_t *out; + uint32_t bytesout; + uint8_t *in; + uint32_t bytesin; + uint8_t type; + uint8_t opcode; + uint32_t offset; +} spi_transaction; + +static inline void spi_use_out(spi_transaction *trans, unsigned bytes) +{ + trans->out += bytes; + trans->bytesout -= bytes; +} + +static inline void spi_use_in(spi_transaction *trans, unsigned bytes) +{ + trans->in += bytes; + trans->bytesin -= bytes; +} + +static void spi_setup_type(spi_transaction *trans) +{ + trans->type = 0xFF; + + /* Try to guess spi type from read/write sizes. */ + if (trans->bytesin == 0) { + if (trans->bytesout > 4) + /* + * If bytesin = 0 and bytesout > 4, we presume this is + * a write data operation, which is accompanied by an + * address. + */ + trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS; + else + trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS; + return; + } + + if (trans->bytesout == 1) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS; + return; + } + + if (trans->bytesout == 4) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS; + } +} + +static int spi_setup_opcode(spi_transaction *trans) +{ + uint16_t optypes; + uint8_t opmenu[cntlr.menubytes]; + + trans->opcode = trans->out[0]; + spi_use_out(trans, 1); + if (!ichspi_lock) { + /* The lock is off, so just use index 0. */ + writeb_(trans->opcode, cntlr.opmenu); + optypes = readw_(cntlr.optype); + optypes = (optypes & 0xfffc) | (trans->type & 0x3); + writew_(optypes, cntlr.optype); + return 0; + } else { + /* The lock is on. See if what we need is on the menu. */ + uint8_t optype; + uint16_t opcode_index; + + read_reg(cntlr.opmenu, opmenu, sizeof(opmenu)); + for (opcode_index = 0; opcode_index < cntlr.menubytes; + opcode_index++) { + if (opmenu[opcode_index] == trans->opcode) + break; + } + + if (opcode_index == cntlr.menubytes) { + printk(BIOS_DEBUG, "ICH SPI: Opcode %x not found\n", + trans->opcode); + return -1; + } + + optypes = readw_(cntlr.optype); + optype = (optypes >> (opcode_index * 2)) & 0x3; + if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS && + optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS && + trans->bytesout >= 3) { + /* We guessed wrong earlier. Fix it up. */ + trans->type = optype; + } + if (optype != trans->type) { + printk(BIOS_DEBUG, "ICH SPI: Transaction doesn't fit type %d\n", + optype); + return -1; + } + return opcode_index; + } +} + +static int spi_setup_offset(spi_transaction *trans) +{ + /* Separate the SPI address and data. */ + switch (trans->type) { + case SPI_OPCODE_TYPE_READ_NO_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_NO_ADDRESS: + return 0; + case SPI_OPCODE_TYPE_READ_WITH_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS: + trans->offset = ((uint32_t)trans->out[0] << 16) | + ((uint32_t)trans->out[1] << 8) | + ((uint32_t)trans->out[2] << 0); + spi_use_out(trans, 3); + return 1; + default: + printk(BIOS_DEBUG, "Unrecognized SPI transaction type %#x\n", trans->type); + return -1; + } +} + +/* + * Wait for up to 60ms til status register bit(s) turn 1 (in case wait_til_set + * below is True) or 0. In case the wait was for the bit(s) to set - write + * those bits back, which would cause resetting them. + * + * Return the last read status value on success or -1 on failure. + */ +static int ich_status_poll(u16 bitmask, int wait_til_set) +{ + int timeout = 6000; /* This will result in 60 ms */ + u16 status = 0; + + while (timeout--) { + status = readw_(cntlr.status); + if (wait_til_set ^ ((status & bitmask) == 0)) { + if (wait_til_set) + writew_((status & bitmask), cntlr.status); + return status; + } + udelay(10); + } + + printk(BIOS_DEBUG, "ICH SPI: SCIP timeout, read %x, expected %x\n", + status, bitmask); + return -1; +} + +int spi_xfer(struct spi_slave *slave, const void *dout, + unsigned int bitsout, void *din, unsigned int bitsin) +{ + uint16_t control; + int16_t opcode_index; + int with_address; + int status; + + spi_transaction trans = { + dout, bitsout / 8, + din, bitsin / 8, + 0xff, 0xff, 0 + }; + + /* There has to always at least be an opcode. */ + if (!bitsout || !dout) { + printk(BIOS_DEBUG, "ICH SPI: No opcode for transfer\n"); + return -1; + } + /* Make sure if we read something we have a place to put it. */ + if (bitsin != 0 && !din) { + printk(BIOS_DEBUG, "ICH SPI: Read but no target buffer\n"); + return -1; + } + /* Right now we don't support writing partial bytes. */ + if (bitsout % 8 || bitsin % 8) { + printk(BIOS_DEBUG, "ICH SPI: Accessing partial bytes not supported\n"); + return -1; + } + + if (ich_status_poll(SPIS_SCIP, 0) == -1) + return -1; + + writew_(SPIS_CDS | SPIS_FCERR, cntlr.status); + + spi_setup_type(&trans); + if ((opcode_index = spi_setup_opcode(&trans)) < 0) + return -1; + if ((with_address = spi_setup_offset(&trans)) < 0) + return -1; + + if (!ichspi_lock && trans.opcode == 0x06) { + /* + * Treat Write Enable as Atomic Pre-Op if possible + * in order to prevent the Management Engine from + * issuing a transaction between WREN and DATA. + */ + writew_(trans.opcode, cntlr.preop); + return 0; + } + + /* Preset control fields */ + control = SPIC_SCGO | ((opcode_index & 0x07) << 4); + + /* Issue atomic preop cycle if needed */ + if (readw_(cntlr.preop)) + control |= SPIC_ACS; + + if (!trans.bytesout && !trans.bytesin) { + /* + * This is a 'no data' command (like Write Enable), its + * bitesout size was 1, decremented to zero while executing + * spi_setup_opcode() above. Tell the chip to send the + * command. + */ + writew_(control, cntlr.control); + + /* wait for the result */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Command transaction error\n"); + return -1; + } + + return 0; + } + + /* + * Check if this is a write command atempting to transfer more bytes + * than the controller can handle. Iterations for writes are not + * supported here because each SPI write command needs to be preceded + * and followed by other SPI commands, and this sequence is controlled + * by the SPI chip driver. + */ + if (trans.bytesout > cntlr.databytes) { + printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use" + " CONTROLLER_PAGE_LIMIT?\n"); + return -1; + } + + /* + * Read or write up to databytes bytes at a time until everything has + * been sent. + */ + while (trans.bytesout || trans.bytesin) { + uint32_t data_length; + + /* SPI addresses are 24 bit only */ + writel_(trans.offset & 0x00FFFFFF, cntlr.addr); + + if (trans.bytesout) + data_length = min(trans.bytesout, cntlr.databytes); + else + data_length = min(trans.bytesin, cntlr.databytes); + + /* Program data into FDATA0 to N */ + if (trans.bytesout) { + write_reg(trans.out, cntlr.data, data_length); + spi_use_out(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + + /* Add proper control fields' values */ + control &= ~((cntlr.databytes - 1) << 8); + control |= SPIC_DS; + control |= (data_length - 1) << 8; + + /* write it */ + writew_(control, cntlr.control); + + /* Wait for Cycle Done Status or Flash Cycle Error. */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Data transaction error\n"); + return -1; + } + + if (trans.bytesin) { + read_reg(cntlr.data, trans.in, data_length); + spi_use_in(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + } + + /* Clear atomic preop now that xfer is done */ + writew_(0, cntlr.preop); + + return 0; +} From c-d.hailfinger.devel.2006 at gmx.net Thu May 3 03:20:13 2012 From: c-d.hailfinger.devel.2006 at gmx.net (Carl-Daniel Hailfinger) Date: Thu, 03 May 2012 03:20:13 +0200 Subject: [coreboot] New patch to review for coreboot: d13510c Add SPI driver In-Reply-To: References: Message-ID: <4FA1DD4D.5020102@gmx.net> Am 03.05.2012 02:29 schrieb Stefan Reinauer (stefan.reinauer at coreboot.org): > Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/997 > > commit d13510c5a18302473903536c8a263c54105b2d80 > Author: Stefan Reinauer > Date: Wed May 2 17:07:05 2012 -0700 > > Add SPI driver > > This driver is taken from u-boot and adapted to match > coreboot. It still contains some hacks and is ICH specific > at places. > > Change-Id: I97dd8096f7db3b62f8f4f4e4d08bdee10d88f689 > Signed-off-by: Patrick Georgi Hm. Any reasons why you're not using flashrom instead? Regards, Carl-Daniel From paulepanter at users.sourceforge.net Thu May 3 08:21:54 2012 From: paulepanter at users.sourceforge.net (Paul Menzel) Date: Thu, 03 May 2012 08:21:54 +0200 Subject: [coreboot] New patch to review for coreboot: cb60b66 Don't pre-enable SATA AHCI in romstage.c In-Reply-To: References: Message-ID: <1336026114.3985.3.camel@mattotaupa> Dear Stefan, Am Donnerstag, den 03.05.2012, 01:47 +0200 schrieb Stefan Reinauer: > Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/995 > > -gerrit > > commit cb60b660540716f4b6671e2b5d21bf75ec9c55e3 > Author: Stefan Reinauer > Date: Wed May 2 16:39:56 2012 -0700 > > Don't pre-enable SATA AHCI in romstage.c > > In a recent commit the SATA code of Panther Point / Cougar Point was please add the exact commit ID and summary of that commit to this commit message. I could not find it in the master branch. If it is not committed yet, please merge this patch with the non-committed one yet. > changed to enable AHCI mode depending on the device tree settings rather > than a hard code hidden in romstage.c. However, Emerald Lake 2 was not > fixed up accordingly. > > Change-Id: I6c93f386509361e1ab5565b0e4d0e84f0ba282a2 > Signed-off-by: Stefan Reinauer > --- > src/mainboard/intel/emeraldlake2/romstage.c | 3 --- > 1 files changed, 0 insertions(+), 3 deletions(-) Thanks, Paul -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 198 bytes Desc: This is a digitally signed message part URL: From gerrit at coreboot.org Thu May 3 11:35:41 2012 From: gerrit at coreboot.org (Patrick Georgi (patrick@georgi-clan.de)) Date: Thu, 3 May 2012 11:35:41 +0200 Subject: [coreboot] New patch to review for coreboot: 5273ea5 roda/rk886ex: Expose VGA devices in devicetree References: Message-ID: Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/998 -gerrit commit 5273ea56be0c1aa191fde01c5d5d160952fa22d6 Author: Patrick Georgi Date: Thu May 3 11:34:20 2012 +0200 roda/rk886ex: Expose VGA devices in devicetree Otherwise set_subsystem isn't called for these (as they're not marked on_mainboard) Change-Id: I08e781735c59e4aa61009d2afa165d782f5a849e Signed-off-by: Patrick Georgi --- src/mainboard/roda/rk886ex/devicetree.cb | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mainboard/roda/rk886ex/devicetree.cb b/src/mainboard/roda/rk886ex/devicetree.cb index 1bd0d14..aadba9d 100644 --- a/src/mainboard/roda/rk886ex/devicetree.cb +++ b/src/mainboard/roda/rk886ex/devicetree.cb @@ -32,8 +32,8 @@ chip northbridge/intel/i945 device pci 00.0 on end # host bridge # auto detection: #device pci 01.0 off end # i945 PCIe root port - #device pci 02.0 on end # vga controller - #device pci 02.1 on end # display controller + device pci 02.0 on end # vga controller + device pci 02.1 on end # display controller chip southbridge/intel/i82801gx register "pirqa_routing" = "0x0b" From manasa671989 at gmail.com Thu May 3 11:38:30 2012 From: manasa671989 at gmail.com (manasa gv) Date: Thu, 3 May 2012 15:08:30 +0530 Subject: [coreboot] Regarding patch review 707 Message-ID: Hi, I am posting this question again because did not got any solution.. How to compile and test the assemebly program of patch 707 that is '.inc file' ?? Specially entry16.inc file in coreboot,because privileged instruction that is LIDT is used..please provide me any document or suggest me where do i get more information related to this.. Below given is the File path. src/cpu/x86/16bit/entry16.inc I am new to this coreboot..please guide me ... Thanks, Manasa From gerrit at coreboot.org Thu May 3 11:57:29 2012 From: gerrit at coreboot.org (Patrick Georgi (patrick@georgi-clan.de)) Date: Thu, 3 May 2012 11:57:29 +0200 Subject: [coreboot] New patch to review for coreboot: 13a40c2 lint: Avoid downloading blobs repository References: Message-ID: Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/999 -gerrit commit 13a40c24f0d5c60df2045ad5c7b3709d2d82ccc4 Author: Patrick Georgi Date: Thu May 3 11:55:17 2012 +0200 lint: Avoid downloading blobs repository The stable lint test "build-dir-handling" ran the build system in a way that made it download the blobs repository. Since this is part of the pre-commit hook, this might have kicked in with users desiring not to have them. Change-Id: I44a00137352c5966ff7fe2a030673276f6803908 Signed-off-by: Patrick Georgi --- util/lint/lint-stable-002-build-dir-handling | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/util/lint/lint-stable-002-build-dir-handling b/util/lint/lint-stable-002-build-dir-handling index 6b902d8..c4247b5 100755 --- a/util/lint/lint-stable-002-build-dir-handling +++ b/util/lint/lint-stable-002-build-dir-handling @@ -33,7 +33,7 @@ fi # $1: object directory run_printall() { -$MAKE CONFIG_CCACHE=n CONFIG_SCANBUILD_ENABLE=n NOMKDIR=1 DOTCONFIG=$TMPCONFIG obj=$1 printall |sed -e "s,^ *,," -e "s,^ramstage-objs:=,," -e "s,mainboard/[^/]*/[^/]*/,.../," |tr " " "\n"|grep "/static.*\.[co]" |sort |tr '\012\015' ' ' |sed -e "s, *, ,g" -e "s, *$,," +$MAKE CONFIG_USE_BLOBS=n CONFIG_CCACHE=n CONFIG_SCANBUILD_ENABLE=n NOMKDIR=1 DOTCONFIG=$TMPCONFIG obj=$1 printall |sed -e "s,^ *,," -e "s,^ramstage-objs:=,," -e "s,mainboard/[^/]*/[^/]*/,.../," |tr " " "\n"|grep "/static.*\.[co]" |sort |tr '\012\015' ' ' |sed -e "s, *, ,g" -e "s, *$,," } # find GNU make From gerrit at coreboot.org Thu May 3 11:58:17 2012 From: gerrit at coreboot.org (Patrick Georgi (patrick@georgi-clan.de)) Date: Thu, 3 May 2012 11:58:17 +0200 Subject: [coreboot] New patch to review for coreboot: 620d539 siemens/sitemp_g1p1: Drop debug code References: Message-ID: Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1000 -gerrit commit 620d539482e5a21b931f37fb248b54915b7f8a88 Author: Patrick Georgi Date: Fri Oct 7 14:25:01 2011 +0200 siemens/sitemp_g1p1: Drop debug code Change-Id: I40a4201b468131ba67e48ab68d62ca5413f2e2e8 Signed-off-by: Patrick Georgi --- src/mainboard/siemens/sitemp_g1p1/mainboard.c | 29 ------------------------- 1 files changed, 0 insertions(+), 29 deletions(-) diff --git a/src/mainboard/siemens/sitemp_g1p1/mainboard.c b/src/mainboard/siemens/sitemp_g1p1/mainboard.c index 60a2ee2..76397ab 100644 --- a/src/mainboard/siemens/sitemp_g1p1/mainboard.c +++ b/src/mainboard/siemens/sitemp_g1p1/mainboard.c @@ -661,34 +661,6 @@ static void patch_mmio_nonposted( void ) * @param */ -static void wait_pepp( void ) { - - int boot_delay = 0; - - if( get_option(&boot_delay, "boot_delay") < 0) - boot_delay = 5; - - printk(BIOS_DEBUG, "boot_delay = %d sec\n", boot_delay); - if ( boot_delay > 0 ) { - init_timer(); - // wait for PEPP-Board - printk(BIOS_INFO, "Give PEPP-Board %d sec(s) time to coming up ", boot_delay); - while ( boot_delay ) { - lapic_write(LAPIC_TMICT, 0xffffffff); - udelay(1000000); // delay time approx. 1 sec - printk(BIOS_INFO, "."); - boot_delay--; - } - printk(BIOS_INFO, "\n"); - } -} - - /** - * @brief - * - * @param - */ - struct { unsigned int bus; unsigned int devfn; @@ -926,7 +898,6 @@ static void enable_dev(device_t dev) uma_memory_base = 0; #endif - wait_pepp(); dev->ops->init = init; // rest of mainboard init later } From svante.signell at telia.com Thu May 3 15:04:49 2012 From: svante.signell at telia.com (Svante Signell) Date: Thu, 03 May 2012 15:04:49 +0200 Subject: [coreboot] Definition of _boot_ In-Reply-To: <1335948710.3707.217.camel@hp.my.own.domain> References: <1335948710.3707.217.camel@hp.my.own.domain> Message-ID: <1336050289.1152.309.camel@s1499.it.kth.se> Please, I been subscribing to this list for many years now. I assume you have an opinion, can you give me some feedback please. Maybe more appropriate names are: 1) Boot manger 2) Services manager On Wed, 2012-05-02 at 10:51 +0200, Svante Signell wrote: > Dear coreboot developers, > > I'm trying to get the boot process definition cleared out in a > discussion at debian-devel on replacing the sysvint script system with > something event based like systemd or upstart. In the list below, > please help me to refine it, and especially make a distinction on what > is needed to: > 1) get the computer up and running > 2) all services needed are completed > > Of special interest is what parts is taken care of different tasks in > the boot procedure, and where serial/parallel processes are possible. > > As I see it we have several tools in the boot process: > 1) coreboot/BIOS > 2) A workload, like grub2 > 3) The init scripts/systemd/upstart > 4) On linux: udev communicating with the kernel, something else on other architectures > > In my opinion the boot process definition can be split in two parts: > 1) Initial boot, taken care of by sysvinit: Mainly order based or serial > 2) secondary boot, taken care of by udev on Linux, something else on > other arches: Mainly event-based or parallel > > Am I completely out in the blue here? > Thank you in advance for your opinion! > > > Hello, > > > > In line with the recent discussion, lets aim at defining what _boot_ is: > > - initializing the RAM: yes > > - initializing the CPU(s): yes > > - loading the kernel: yes > > - initializing the graphics card: yes for text mode, graphics mode can > > come later > > - initializing the HDD(s): yes, if boot devices. > > - setting up swap: yes > > -initializing the keyboard and mouse : yes, see below wrt USB > > - initializing the serial device: no, only if used for debugging. > > - initializing the the parallel port: no > > - initializing the audio card: can be done later > > - initializing USB devices: yes if keyboard, mouse or boot device, other > > things can be done later. > > - starting up the network: yes if network booting, other things can be > > done later. > > - starting an MTA: no > > - staring sshd: no > > - starting X: no, that is not a _boot_ task, other things can be done > > later. This excludes network-manager and what follows with it. > > - of course there are missing pieces here, you can help me filling them > > in... or reject/not comment on this as usual as many of you would. > > > > Thank you for your attention! > > > > > > From GNUtoo at no-log.org Thu May 3 16:18:54 2012 From: GNUtoo at no-log.org (Denis 'GNUtoo' Carikli) Date: Thu, 03 May 2012 16:18:54 +0200 Subject: [coreboot] Definition of _boot_ In-Reply-To: <1335948710.3707.217.camel@hp.my.own.domain> References: <1335948710.3707.217.camel@hp.my.own.domain> Message-ID: <2376158.BXhaVDIWGJ@gnutoo-desktop> The boot order is the following(semplified for clarity): 1)First the BIOS (or coreboot combined with seabios) get executed. The BIOS or coreboot+sea bios reside in a flash memory that is on the mainboard. 2)Then the BIOS(or coreboot) loads grub grub usually resides on a hard disk. 3)grub which loads a kernel The kernel usually resides in a filesystem on a partition under /boot/ 4) the kernel once it finished booting usually loads /sbin/init and then the boot process continue in userspace(the init daemon loads udev, and various services, and at the end your display manager which at the end will start your desktop environment). /sbin/init usually resides in a filesystem on a partition under /sbin/init I think wikipedia should have many pointers on the boot process. Denis. From gerrit at coreboot.org Thu May 3 19:49:23 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Thu, 3 May 2012 19:49:23 +0200 Subject: [coreboot] Patch merged into coreboot/master: ef6dfc1 Fix register corruption during Intel Microcode update References: Message-ID: the following patch was just integrated into master: commit ef6dfc1d0656f34331519fb97e5ec87784c4686d Author: Stefan Reinauer Date: Wed May 2 16:41:55 2012 -0700 Fix register corruption during Intel Microcode update Another bug in the Intel microcode update code that existed since we switched to LinuxBIOSv2 in 2004: The inline assembly code that reads the CPU revision from an MSR after running cpuid(1) trashes registers EBX and ECX. Only ECX was mentioned in the clobber list. C code running after this function could silently access completely wrong data, which resulted in the wrong date being printed on microcode updates (and potentially other issues happening until the C code writes to EBX again) Change-Id: Ida733fa1747565ec9824d3a37d08b1a73cd8355f Signed-off-by: Stefan Reinauer Reviewed-By: Patrick Georgi at Thu May 3 10:47:36 2012, giving +2 Build-Tested: build bot (Jenkins) at Thu May 3 03:37:28 2012, giving +1 See http://review.coreboot.org/996 for details. -gerrit From gerrit at coreboot.org Thu May 3 20:33:16 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Thu, 3 May 2012 20:33:16 +0200 Subject: [coreboot] Patch merged into coreboot/master: bc9827a Tell CBMEM pretty printer about MRC cache References: Message-ID: the following patch was just integrated into master: commit bc9827a733944045eb7c5c58770a72478a69f05d Author: Stefan Reinauer Date: Wed May 2 16:27:26 2012 -0700 Tell CBMEM pretty printer about MRC cache Sandybridge memory initialization produces some amount of training data that has to be kept around in CBMEM. Add a descriptive name to the CBMEM pretty printer to prevent it from just printing the hex value. Change-Id: I587c0bc3dfcf389ba298d445d2594eef73bc69a8 Signed-off-by: Stefan Reinauer Build-Tested: build bot (Jenkins) at Thu May 3 02:07:53 2012, giving +1 See http://review.coreboot.org/990 for details. -gerrit From gerrit at coreboot.org Thu May 3 20:33:24 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Thu, 3 May 2012 20:33:24 +0200 Subject: [coreboot] Patch merged into coreboot/master: 8ea810a Add missing newline to printk in Sandybridge init code References: Message-ID: the following patch was just integrated into master: commit 8ea810ae2fca0f3aa002c9bcbfe1f390fa3e6a76 Author: Stefan Reinauer Date: Wed May 2 16:29:51 2012 -0700 Add missing newline to printk in Sandybridge init code Change-Id: I9217a75ec1a0abb898c45752d990231ce98e5fb2 Signed-off-by: Stefan Reinauer Build-Tested: build bot (Jenkins) at Thu May 3 02:23:18 2012, giving +1 See http://review.coreboot.org/991 for details. -gerrit From gerrit at coreboot.org Thu May 3 20:33:44 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Thu, 3 May 2012 20:33:44 +0200 Subject: [coreboot] Patch merged into coreboot/master: ba795bd Make creation of CBMEM_ID_RESUME_SCRATCH depending on Agesa References: Message-ID: the following patch was just integrated into master: commit ba795bd63862f8124ac6f27200a94e303ac04a46 Author: Stefan Reinauer Date: Wed May 2 16:30:53 2012 -0700 Make creation of CBMEM_ID_RESUME_SCRATCH depending on Agesa The CBMEM_ID_RESUME_SCRATCH area is only used by Agesa code, on one particular board (AMD Persimmon). Make the creation of that section depending on Agesa so it does consume space on non-Agesa systems. Change-Id: I2a1a4f76991ef936ea68cf75928b20b7ed132b84 Signed-off-by: Stefan Reinauer Build-Tested: build bot (Jenkins) at Thu May 3 02:39:45 2012, giving +1 See http://review.coreboot.org/992 for details. -gerrit From gerrit at coreboot.org Thu May 3 20:34:07 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Thu, 3 May 2012 20:34:07 +0200 Subject: [coreboot] Patch merged into coreboot/master: 2badb25 Print some useful debugging information in PSS table creation References: Message-ID: the following patch was just integrated into master: commit 2badb25677a0425f43f53ece4db187ec829fa659 Author: Stefan Reinauer Date: Wed May 2 16:38:47 2012 -0700 Print some useful debugging information in PSS table creation Change-Id: I1ec7a7e54513671331ac12f08d5f59161b72b0fd Example: PSS: 1900MHz power 35000 control 0x1300 status 0x1300 PSS: 1600MHz power 28468 control 0x1000 status 0x1000 PSS: 1400MHz power 24291 control 0xe00 status 0xe00 PSS: 1200MHz power 20340 control 0xc00 status 0xc00 PSS: 1000MHz power 16569 control 0xa00 status 0xa00 PSS: 800MHz power 12937 control 0x800 status 0x800 PSS: 1900MHz power 35000 control 0x1300 status 0x1300 PSS: 1600MHz power 28468 control 0x1000 status 0x1000 PSS: 1400MHz power 24291 control 0xe00 status 0xe00 PSS: 1200MHz power 20340 control 0xc00 status 0xc00 PSS: 1000MHz power 16569 control 0xa00 status 0xa00 PSS: 800MHz power 12937 control 0x800 status 0x800 Signed-off-by: Stefan Reinauer Build-Tested: build bot (Jenkins) at Thu May 3 03:12:13 2012, giving +1 See http://review.coreboot.org/994 for details. -gerrit From gerrit at coreboot.org Thu May 3 20:35:02 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Thu, 3 May 2012 20:35:02 +0200 Subject: [coreboot] Patch merged into coreboot/master: cb60b66 Don't pre-enable SATA AHCI in romstage.c References: Message-ID: the following patch was just integrated into master: commit cb60b660540716f4b6671e2b5d21bf75ec9c55e3 Author: Stefan Reinauer Date: Wed May 2 16:39:56 2012 -0700 Don't pre-enable SATA AHCI in romstage.c In a recent commit the SATA code of Panther Point / Cougar Point was changed to enable AHCI mode depending on the device tree settings rather than a hard code hidden in romstage.c. However, Emerald Lake 2 was not fixed up accordingly. Change-Id: I6c93f386509361e1ab5565b0e4d0e84f0ba282a2 Signed-off-by: Stefan Reinauer Build-Tested: build bot (Jenkins) at Thu May 3 03:25:13 2012, giving +1 See http://review.coreboot.org/995 for details. -gerrit From gerrit at coreboot.org Thu May 3 20:52:11 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Thu, 3 May 2012 20:52:11 +0200 Subject: [coreboot] Patch set updated for coreboot: 9beffaa Add SPI driver References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/997 -gerrit commit 9beffaaede80ca9a783fd92c616e110fe5e08eae Author: Stefan Reinauer Date: Wed May 2 17:07:05 2012 -0700 Add SPI driver This driver is taken from u-boot and adapted to match coreboot. It still contains some hacks and is ICH specific at places. Change-Id: I97dd8096f7db3b62f8f4f4e4d08bdee10d88f689 Signed-off-by: Patrick Georgi --- src/drivers/Kconfig | 1 + src/drivers/Makefile.inc | 1 + src/drivers/spi/Kconfig | 24 + src/drivers/spi/Makefile.inc | 12 + src/drivers/spi/eon.c | 161 ++++++ src/drivers/spi/macronix.c | 220 +++++++++ src/drivers/spi/ramtron.c | 315 ++++++++++++ src/drivers/spi/spansion.c | 241 +++++++++ src/drivers/spi/spi_flash.c | 327 ++++++++++++ src/drivers/spi/spi_flash_internal.h | 81 +++ src/drivers/spi/sst.c | 268 ++++++++++ src/drivers/spi/stmicro.c | 250 ++++++++++ src/drivers/spi/winbond.c | 218 ++++++++ src/include/device/pci_ids.h | 4 + src/include/spi.h | 203 ++++++++ src/include/spi_flash.h | 91 ++++ src/northbridge/intel/sandybridge/raminit.c | 1 + src/southbridge/intel/bd82x6x/Kconfig | 1 + src/southbridge/intel/bd82x6x/Makefile.inc | 2 + src/southbridge/intel/bd82x6x/spi.c | 712 +++++++++++++++++++++++++++ 20 files changed, 3133 insertions(+), 0 deletions(-) diff --git a/src/drivers/Kconfig b/src/drivers/Kconfig index 259bc29..60e5b65 100644 --- a/src/drivers/Kconfig +++ b/src/drivers/Kconfig @@ -26,3 +26,4 @@ source src/drivers/oxford/Kconfig source src/drivers/sil/Kconfig source src/drivers/trident/Kconfig source src/drivers/ics/Kconfig +source src/drivers/spi/Kconfig diff --git a/src/drivers/Makefile.inc b/src/drivers/Makefile.inc index 5f6dadf..851a4df 100644 --- a/src/drivers/Makefile.inc +++ b/src/drivers/Makefile.inc @@ -26,4 +26,5 @@ subdirs-y += oxford subdirs-y += sil subdirs-y += trident subdirs-y += ics +subdirs-y += spi subdirs-$(CONFIG_ARCH_X86) += pc80 diff --git a/src/drivers/spi/Kconfig b/src/drivers/spi/Kconfig new file mode 100644 index 0000000..482881c --- /dev/null +++ b/src/drivers/spi/Kconfig @@ -0,0 +1,24 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2012 The Chromium OS Authors. +## +## 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; version 2 of the License. +## +## 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +config SPI + bool + help + Select this option if your chipset driver needs to store certain + data in the SPI flash. diff --git a/src/drivers/spi/Makefile.inc b/src/drivers/spi/Makefile.inc new file mode 100644 index 0000000..54239b9 --- /dev/null +++ b/src/drivers/spi/Makefile.inc @@ -0,0 +1,12 @@ +# SPI driver interface +ramstage-$(CONFIG_SPI) += spi_flash.c + +# drivers +ramstage-$(CONFIG_SPI) += eon.c +ramstage-$(CONFIG_SPI) += macronix.c +ramstage-$(CONFIG_SPI) += ramtron.c +ramstage-$(CONFIG_SPI) += spansion.c +ramstage-$(CONFIG_SPI) += sst.c +ramstage-$(CONFIG_SPI) += stmicro.c +ramstage-$(CONFIG_SPI) += winbond.c + diff --git a/src/drivers/spi/eon.c b/src/drivers/spi/eon.c new file mode 100644 index 0000000..a94dec1 --- /dev/null +++ b/src/drivers/spi/eon.c @@ -0,0 +1,161 @@ +/* + * (C) Copyright 2010, ucRobotics Inc. + * Author: Chong Huang + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* EN25Q128-specific commands */ +#define CMD_EN25Q128_WREN 0x06 /* Write Enable */ +#define CMD_EN25Q128_WRDI 0x04 /* Write Disable */ +#define CMD_EN25Q128_RDSR 0x05 /* Read Status Register */ +#define CMD_EN25Q128_WRSR 0x01 /* Write Status Register */ +#define CMD_EN25Q128_READ 0x03 /* Read Data Bytes */ +#define CMD_EN25Q128_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_EN25Q128_PP 0x02 /* Page Program */ +#define CMD_EN25Q128_SE 0x20 /* Sector Erase */ +#define CMD_EN25Q128_BE 0xd8 /* Block Erase */ +#define CMD_EN25Q128_DP 0xb9 /* Deep Power-down */ +#define CMD_EN25Q128_RES 0xab /* Release from DP, and Read Signature */ + +#define EON_ID_EN25Q128 0x18 + +struct eon_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 sectors_per_block; + u16 nr_sectors; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct eon_spi_flash { + struct spi_flash flash; + const struct eon_spi_flash_params *params; +}; + +static inline struct eon_spi_flash *to_eon_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct eon_spi_flash, flash); +} + +static const struct eon_spi_flash_params eon_spi_flash_table[] = { + { + .idcode1 = EON_ID_EN25Q128, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_sectors = 4096, + .name = "EN25Q128", + }, +}; + +static int eon_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct eon_spi_flash *eon = to_eon_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = eon->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_EN25Q128_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, + "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_EN25Q128_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: EON Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: EON: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int eon_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_EN25Q128_BE, offset, len); +} + +struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode) +{ + const struct eon_spi_flash_params *params; + struct eon_spi_flash *eon; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(eon_spi_flash_table); ++i) { + params = &eon_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(eon_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported EON ID %02x\n", idcode[1]); + return NULL; + } + + eon = malloc(sizeof(*eon)); + if (!eon) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + eon->params = params; + eon->flash.spi = spi; + eon->flash.name = params->name; + + eon->flash.write = eon_write; + eon->flash.erase = eon_erase; + eon->flash.read = spi_flash_cmd_read_fast; + eon->flash.sector_size = params->page_size * params->pages_per_sector + * params->sectors_per_block; + eon->flash.size = params->page_size * params->pages_per_sector + * params->nr_sectors; + + return &eon->flash; +} diff --git a/src/drivers/spi/macronix.c b/src/drivers/spi/macronix.c new file mode 100644 index 0000000..700a0a2 --- /dev/null +++ b/src/drivers/spi/macronix.c @@ -0,0 +1,220 @@ +/* + * Copyright 2009(C) Marvell International Ltd. and its affiliates + * Prafulla Wadaskar + * + * Based on drivers/mtd/spi/stmicro.c + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* MX25xx-specific commands */ +#define CMD_MX25XX_WREN 0x06 /* Write Enable */ +#define CMD_MX25XX_WRDI 0x04 /* Write Disable */ +#define CMD_MX25XX_RDSR 0x05 /* Read Status Register */ +#define CMD_MX25XX_WRSR 0x01 /* Write Status Register */ +#define CMD_MX25XX_READ 0x03 /* Read Data Bytes */ +#define CMD_MX25XX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_MX25XX_PP 0x02 /* Page Program */ +#define CMD_MX25XX_SE 0x20 /* Sector Erase */ +#define CMD_MX25XX_BE 0xD8 /* Block Erase */ +#define CMD_MX25XX_CE 0xc7 /* Chip Erase */ +#define CMD_MX25XX_DP 0xb9 /* Deep Power-down */ +#define CMD_MX25XX_RES 0xab /* Release from DP, and Read Signature */ + +#define MACRONIX_SR_WIP (1 << 0) /* Write-in-Progress */ + +struct macronix_spi_flash_params { + u16 idcode; + u16 page_size; + u16 pages_per_sector; + u16 sectors_per_block; + u16 nr_blocks; + const char *name; +}; + +struct macronix_spi_flash { + struct spi_flash flash; + const struct macronix_spi_flash_params *params; +}; + +static inline struct macronix_spi_flash *to_macronix_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct macronix_spi_flash, flash); +} + +static const struct macronix_spi_flash_params macronix_spi_flash_table[] = { + { + .idcode = 0x2015, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "MX25L1605D", + }, + { + .idcode = 0x2016, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "MX25L3205D", + }, + { + .idcode = 0x2017, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "MX25L6405D", + }, + { + .idcode = 0x2018, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "MX25L12805D", + }, + { + .idcode = 0x2618, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "MX25L12855E", + }, +}; + +static int macronix_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct macronix_spi_flash *mcx = to_macronix_spi_flash(flash); + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = min(mcx->params->page_size, CONTROLLER_PAGE_LIMIT); + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_MX25XX_PP; + cmd[1] = (offset >> 16) & 0xff; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_MX25XX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Macronix Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + offset += chunk_len; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: Macronix: Successfully programmed %zu bytes @ 0x%lx\n", + len, offset - len); + + spi_release_bus(flash->spi); + return ret; +} + +static int macronix_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_MX25XX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode) +{ + const struct macronix_spi_flash_params *params; + struct macronix_spi_flash *mcx; + unsigned int i; + u16 id = idcode[2] | idcode[1] << 8; + + for (i = 0; i < ARRAY_SIZE(macronix_spi_flash_table); i++) { + params = ¯onix_spi_flash_table[i]; + if (params->idcode == id) + break; + } + + if (i == ARRAY_SIZE(macronix_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported Macronix ID %04x\n", id); + return NULL; + } + + mcx = malloc(sizeof(*mcx)); + if (!mcx) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + mcx->params = params; + mcx->flash.spi = spi; + mcx->flash.name = params->name; + + mcx->flash.write = macronix_write; + mcx->flash.erase = macronix_erase; +#ifdef CONFIG_SPI_FLASH_NO_FAST_READ + mcx->flash.read = spi_flash_cmd_read_slow; +#else + mcx->flash.read = spi_flash_cmd_read_fast; +#endif + mcx->flash.sector_size = params->page_size * params->pages_per_sector; + mcx->flash.size = mcx->flash.sector_size * params->sectors_per_block * + params->nr_blocks; + + return &mcx->flash; +} diff --git a/src/drivers/spi/ramtron.c b/src/drivers/spi/ramtron.c new file mode 100644 index 0000000..d599cd9 --- /dev/null +++ b/src/drivers/spi/ramtron.c @@ -0,0 +1,315 @@ +/* + * (C) Copyright 2010 + * Reinhard Meyer, EMK Elektronik, reinhard.meyer at emk-elektronik.de + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Note: RAMTRON SPI FRAMs are ferroelectric, nonvolatile RAMs + * with an interface identical to SPI flash devices. + * However since they behave like RAM there are no delays or + * busy polls required. They can sustain read or write at the + * allowed SPI bus speed, which can be 40 MHz for some devices. + * + * Unfortunately some RAMTRON devices do not have a means of + * identifying them. They will leave the SO line undriven when + * the READ-ID command is issued. It is therefore mandatory + * that the MISO line has a proper pull-up, so that READ-ID + * will return a row of 0xff. This 0xff pseudo-id will cause + * probes by all vendor specific functions that are designed + * to handle it. If the MISO line is not pulled up, READ-ID + * could return any random noise, even mimicking another + * device. + * + * We use CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + * to define which device will be assumed after a simple status + * register verify. This method is prone to false positive + * detection and should therefore be the last to be tried. + * Enter it in the last position in the table in spi_flash.c! + * + * The define CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC both activates + * compilation of the special handler and defines the device + * to assume. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* RAMTRON commands common to all devices */ +#define CMD_RAMTRON_WREN 0x06 /* Write Enable */ +#define CMD_RAMTRON_WRDI 0x04 /* Write Disable */ +#define CMD_RAMTRON_RDSR 0x05 /* Read Status Register */ +#define CMD_RAMTRON_WRSR 0x01 /* Write Status Register */ +#define CMD_RAMTRON_READ 0x03 /* Read Data Bytes */ +#define CMD_RAMTRON_WRITE 0x02 /* Write Data Bytes */ +/* not all have those: */ +#define CMD_RAMTRON_FSTRD 0x0b /* Fast Read (for compatibility - not used here) */ +#define CMD_RAMTRON_SLEEP 0xb9 /* Enter Sleep Mode */ +#define CMD_RAMTRON_RDID 0x9f /* Read ID */ +#define CMD_RAMTRON_SNR 0xc3 /* Read Serial Number */ + +/* + * Properties of supported FRAMs + * Note: speed is currently not used because we have no method to deliver that + * value to the upper layers + */ +struct ramtron_spi_fram_params { + u32 size; /* size in bytes */ + u8 addr_len; /* number of address bytes */ + u8 merge_cmd; /* some address bits are in the command byte */ + u8 id1; /* device ID 1 (family, density) */ + u8 id2; /* device ID 2 (sub, rev, rsvd) */ + u32 speed; /* max. SPI clock in Hz */ + const char *name; /* name for display and/or matching */ +}; + +struct ramtron_spi_fram { + struct spi_flash flash; + const struct ramtron_spi_fram_params *params; +}; + +static inline struct ramtron_spi_fram *to_ramtron_spi_fram(struct spi_flash + *flash) +{ + return container_of(flash, struct ramtron_spi_fram, flash); +} + +/* + * table describing supported FRAM chips: + * chips without RDID command must have the values 0xff for id1 and id2 + */ +static const struct ramtron_spi_fram_params ramtron_spi_fram_table[] = { + { + .size = 32*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x22, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V02", + }, + { + .size = 32*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x22, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN02", + }, + { + .size = 64*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x23, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V05", + }, + { + .size = 64*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x23, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN05", + }, + { + .size = 128*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0x24, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V10", + }, + { + .size = 128*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0x24, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN10", + }, +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + { + .size = 256*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0xff, + .id2 = 0xff, + .speed = 40000000, + .name = "FM25H20", + }, +#endif +}; + +static int ramtron_common(struct spi_flash *flash, + u32 offset, size_t len, void *buf, u8 command) +{ + struct ramtron_spi_fram *sn = to_ramtron_spi_fram(flash); + u8 cmd[4]; + int cmd_len; + int ret; + + if (sn->params->addr_len == 3 && sn->params->merge_cmd == 0) { + cmd[0] = command; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + cmd_len = 4; + } else if (sn->params->addr_len == 2 && sn->params->merge_cmd == 0) { + cmd[0] = command; + cmd[1] = offset >> 8; + cmd[2] = offset; + cmd_len = 3; + } else { + printk(BIOS_SPEW, "SF: unsupported addr_len or merge_cmd\n"); + return -1; + } + + /* claim the bus */ + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + if (command == CMD_RAMTRON_WRITE) { + /* send WREN */ + ret = spi_flash_cmd(flash->spi, CMD_RAMTRON_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + goto releasebus; + } + } + + /* do the transaction */ + if (command == CMD_RAMTRON_WRITE) + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, buf, len); + else + ret = spi_flash_cmd_read(flash->spi, cmd, cmd_len, buf, len); + if (ret < 0) + printk(BIOS_SPEW, "SF: Transaction failed\n"); + +releasebus: + /* release the bus */ + spi_release_bus(flash->spi); + return ret; +} + +static int ramtron_read(struct spi_flash *flash, + u32 offset, size_t len, void *buf) +{ + return ramtron_common(flash, offset, len, buf, + CMD_RAMTRON_READ); +} + +static int ramtron_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + return ramtron_common(flash, offset, len, (void *)buf, + CMD_RAMTRON_WRITE); +} + +static int ramtron_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + printk(BIOS_SPEW, "SF: Erase of RAMTRON FRAMs is pointless\n"); + return -1; +} + +/* + * nore: we are called here with idcode pointing to the first non-0x7f byte + * already! + */ +struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode) +{ + const struct ramtron_spi_fram_params *params; + struct ramtron_spi_fram *sn; + unsigned int i; +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + int ret; + u8 sr; +#endif + + /* NOTE: the bus has been claimed before this function is called! */ + switch (idcode[0]) { + case 0xc2: + /* JEDEC conformant RAMTRON id */ + for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) { + params = &ramtron_spi_fram_table[i]; + if (idcode[1] == params->id1 && idcode[2] == params->id2) + goto found; + } + break; +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + case 0xff: + /* + * probably open MISO line, pulled up. + * We COULD have a non JEDEC conformant FRAM here, + * read the status register to verify + */ + ret = spi_flash_cmd(spi, CMD_RAMTRON_RDSR, &sr, 1); + if (ret) + return NULL; + + /* Bits 5,4,0 are fixed 0 for all devices */ + if ((sr & 0x31) != 0x00) + return NULL; + /* now find the device */ + for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) { + params = &ramtron_spi_fram_table[i]; + if (!strcmp(params->name, CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC)) + goto found; + } + printk(BIOS_SPEW, "SF: Unsupported non-JEDEC RAMTRON device " + CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC "\n"); + break; +#endif + default: + break; + } + + /* arriving here means no method has found a device we can handle */ + printk(BIOS_SPEW, "SF/ramtron: unsupported device id0=%02x id1=%02x id2=%02x\n", + idcode[0], idcode[1], idcode[2]); + return NULL; + +found: + sn = malloc(sizeof(*sn)); + if (!sn) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + sn->params = params; + sn->flash.spi = spi; + sn->flash.name = params->name; + + sn->flash.write = ramtron_write; + sn->flash.read = ramtron_read; + sn->flash.erase = ramtron_erase; + sn->flash.size = params->size; + + return &sn->flash; +} diff --git a/src/drivers/spi/spansion.c b/src/drivers/spi/spansion.c new file mode 100644 index 0000000..719a8a8 --- /dev/null +++ b/src/drivers/spi/spansion.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2009 Freescale Semiconductor, Inc. + * + * Author: Mingkai Hu (Mingkai.hu at freescale.com) + * Based on stmicro.c by Wolfgang Denk (wd at denx.de), + * TsiChung Liew (Tsi-Chung.Liew at freescale.com), + * and Jason McMullan (mcmullan at netapp.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* S25FLxx-specific commands */ +#define CMD_S25FLXX_READ 0x03 /* Read Data Bytes */ +#define CMD_S25FLXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_S25FLXX_READID 0x90 /* Read Manufacture ID and Device ID */ +#define CMD_S25FLXX_WREN 0x06 /* Write Enable */ +#define CMD_S25FLXX_WRDI 0x04 /* Write Disable */ +#define CMD_S25FLXX_RDSR 0x05 /* Read Status Register */ +#define CMD_S25FLXX_WRSR 0x01 /* Write Status Register */ +#define CMD_S25FLXX_PP 0x02 /* Page Program */ +#define CMD_S25FLXX_SE 0xd8 /* Sector Erase */ +#define CMD_S25FLXX_BE 0xc7 /* Bulk Erase */ +#define CMD_S25FLXX_DP 0xb9 /* Deep Power-down */ +#define CMD_S25FLXX_RES 0xab /* Release from DP, and Read Signature */ + +#define SPSN_ID_S25FL008A 0x0213 +#define SPSN_ID_S25FL016A 0x0214 +#define SPSN_ID_S25FL032A 0x0215 +#define SPSN_ID_S25FL064A 0x0216 +#define SPSN_ID_S25FL128P 0x2018 +#define SPSN_EXT_ID_S25FL128P_256KB 0x0300 +#define SPSN_EXT_ID_S25FL128P_64KB 0x0301 +#define SPSN_EXT_ID_S25FL032P 0x4d00 + +struct spansion_spi_flash_params { + u16 idcode1; + u16 idcode2; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +struct spansion_spi_flash { + struct spi_flash flash; + const struct spansion_spi_flash_params *params; +}; + +static inline struct spansion_spi_flash *to_spansion_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct spansion_spi_flash, flash); +} + +static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { + { + .idcode1 = SPSN_ID_S25FL008A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "S25FL008A", + }, + { + .idcode1 = SPSN_ID_S25FL016A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "S25FL016A", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032A", + }, + { + .idcode1 = SPSN_ID_S25FL064A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "S25FL064A", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_64KB, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 256, + .name = "S25FL128P_64K", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_256KB, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "S25FL128P_256K", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = SPSN_EXT_ID_S25FL032P, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032P", + }, +}; + +static int spansion_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct spansion_spi_flash *spsn = to_spansion_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = spsn->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_S25FLXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_S25FLXX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: SPANSION Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: SPANSION: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int spansion_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_S25FLXX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) +{ + const struct spansion_spi_flash_params *params; + struct spansion_spi_flash *spsn; + unsigned int i; + unsigned short jedec, ext_jedec; + + jedec = idcode[1] << 8 | idcode[2]; + ext_jedec = idcode[3] << 8 | idcode[4]; + + for (i = 0; i < ARRAY_SIZE(spansion_spi_flash_table); i++) { + params = &spansion_spi_flash_table[i]; + if (params->idcode1 == jedec) { + if (params->idcode2 == ext_jedec) + break; + } + } + + if (i == ARRAY_SIZE(spansion_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported SPANSION ID %04x %04x\n", jedec, ext_jedec); + return NULL; + } + + spsn = malloc(sizeof(struct spansion_spi_flash)); + if (!spsn) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + spsn->params = params; + spsn->flash.spi = spi; + spsn->flash.name = params->name; + + spsn->flash.write = spansion_write; + spsn->flash.erase = spansion_erase; + spsn->flash.read = spi_flash_cmd_read_fast; + spsn->flash.sector_size = params->page_size * params->pages_per_sector; + spsn->flash.size = spsn->flash.sector_size * params->nr_sectors; + + return &spsn->flash; +} diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c new file mode 100644 index 0000000..378f142 --- /dev/null +++ b/src/drivers/spi/spi_flash.c @@ -0,0 +1,327 @@ +/* + * SPI flash interface + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include "spi_flash_internal.h" + +#define CONFIG_SPI_FLASH_EON +#define CONFIG_SPI_FLASH_MACRONIX +#define CONFIG_SPI_FLASH_SPANSION +#define CONFIG_SPI_FLASH_SST +#define CONFIG_SPI_FLASH_STMICRO +#define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_SPI_FLASH_RAMTRON + +static void spi_flash_addr(u32 addr, u8 *cmd) +{ + /* cmd[0] is actual command */ + cmd[1] = addr >> 16; + cmd[2] = addr >> 8; + cmd[3] = addr >> 0; +} + +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) +{ + int ret = spi_xfer(spi, &cmd, 8, response, len * 8); + if (ret) + printk(BIOS_SPEW, "SF: Failed to send command %02x: %d\n", cmd, ret); + + return ret; +} + +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + int ret = spi_xfer(spi, cmd, cmd_len * 8, data, data_len * 8); + if (ret) { + printk(BIOS_SPEW, "SF: Failed to send read command (%zu bytes): %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len) +{ + int ret; + u8 buff[cmd_len + data_len]; + memcpy(buff, cmd, cmd_len); + memcpy(buff + cmd_len, data, data_len); + + ret = spi_xfer(spi, buff, (cmd_len + data_len) * 8, NULL, 0); + if (ret) { + printk(BIOS_SPEW, "SF: Failed to send write command (%zu bytes): %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + struct spi_slave *spi = flash->spi; + int ret; + + spi_claim_bus(spi); + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + spi_release_bus(spi); + + return ret; +} + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[5]; + + cmd[0] = CMD_READ_ARRAY_FAST; + spi_flash_addr(offset, cmd); + cmd[4] = 0x00; + + return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); +} + +int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[4]; + + cmd[0] = CMD_READ_ARRAY_SLOW; + spi_flash_addr(offset, cmd); + + return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); +} + +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 status; + + timebase = timeout; + do { + ret = spi_flash_cmd_read(spi, &cmd, 1, &status, 1); + if (ret) + return -1; + + if ((status & poll_bit) == 0) + break; + + mdelay(1); + } while (timebase--); + + if ((status & poll_bit) == 0) + return 0; + + /* Timed out */ + printk(BIOS_SPEW, "SF: time out!\n"); + return -1; +} + +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + return spi_flash_cmd_poll_bit(flash, timeout, + CMD_READ_STATUS, STATUS_WIP); +} + +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 offset, size_t len) +{ + u32 start, end, erase_size; + int ret; + u8 cmd[4]; + + erase_size = flash->sector_size; + if (offset % erase_size || len % erase_size) { + printk(BIOS_SPEW, "SF: Erase offset/length not multiple of erase size\n"); + return -1; + } + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + cmd[0] = erase_cmd; + start = offset; + end = start + len; + + while (offset < end) { + spi_flash_addr(offset, cmd); + offset += erase_size; + + printk(BIOS_SPEW, "SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) + goto out; + } + + printk(BIOS_SPEW, "SF: Successfully erased %zu bytes @ %#x\n", len, start); + + out: + spi_release_bus(flash->spi); + return ret; +} + +/* + * The following table holds all device probe functions + * + * shift: number of continuation bytes before the ID + * idcode: the expected IDCODE or 0xff for non JEDEC devices + * probe: the function to call + * + * Non JEDEC devices should be ordered in the table such that + * the probe functions with best detection algorithms come first. + * + * Several matching entries are permitted, they will be tried + * in sequence until a probe function returns non NULL. + * + * IDCODE_CONT_LEN may be redefined if a device needs to declare a + * larger "shift" value. IDCODE_PART_LEN generally shouldn't be + * changed. This is the max number of bytes probe functions may + * examine when looking up part-specific identification info. + * + * Probe functions will be given the idcode buffer starting at their + * manu id byte (the "idcode" in the table below). In other words, + * all of the continuation bytes will be skipped (the "shift" below). + */ +#define IDCODE_CONT_LEN 0 +#define IDCODE_PART_LEN 5 +static const struct { + const u8 shift; + const u8 idcode; + struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); +} flashes[] = { + /* Keep it sorted by define name */ +#ifdef CONFIG_SPI_FLASH_ATMEL + { 0, 0x1f, spi_flash_probe_atmel, }, +#endif +#ifdef CONFIG_SPI_FLASH_EON + { 0, 0x1c, spi_flash_probe_eon, }, +#endif +#ifdef CONFIG_SPI_FLASH_MACRONIX + { 0, 0xc2, spi_flash_probe_macronix, }, +#endif +#ifdef CONFIG_SPI_FLASH_SPANSION + { 0, 0x01, spi_flash_probe_spansion, }, +#endif +#ifdef CONFIG_SPI_FLASH_SST + { 0, 0xbf, spi_flash_probe_sst, }, +#endif +#ifdef CONFIG_SPI_FLASH_STMICRO + { 0, 0x20, spi_flash_probe_stmicro, }, +#endif +#ifdef CONFIG_SPI_FLASH_WINBOND + { 0, 0xef, spi_flash_probe_winbond, }, +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON + { 6, 0xc2, spi_fram_probe_ramtron, }, +# undef IDCODE_CONT_LEN +# define IDCODE_CONT_LEN 6 +#endif + /* Keep it sorted by best detection */ +#ifdef CONFIG_SPI_FLASH_STMICRO + { 0, 0xff, spi_flash_probe_stmicro, }, +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + { 0, 0xff, spi_fram_probe_ramtron, }, +#endif +}; +#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_slave *spi; + struct spi_flash *flash = NULL; + int ret, i, shift; + u8 idcode[IDCODE_LEN], *idp; + + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); + if (!spi) { + printk(BIOS_SPEW, "SF: Failed to set up slave\n"); + return NULL; + } + + ret = spi_claim_bus(spi); + if (ret) { + printk(BIOS_SPEW, "SF: Failed to claim SPI bus: %d\n", ret); + goto err_claim_bus; + } + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); + if (ret) + goto err_read_id; + +#ifdef DEBUG + printk(BIOS_SPEW, "SF: Got idcodes\n"); + print_buffer(0, idcode, 1, sizeof(idcode), 0); +#endif + + /* count the number of continuation bytes */ + for (shift = 0, idp = idcode; + shift < IDCODE_CONT_LEN && *idp == 0x7f; + ++shift, ++idp) + continue; + + /* search the table for matches in shift and id */ + for (i = 0; i < ARRAY_SIZE(flashes); ++i) + if (flashes[i].shift == shift && flashes[i].idcode == *idp) { + /* we have a match, call probe */ + flash = flashes[i].probe(spi, idp); + if (flash) + break; + } + + if (!flash) { + printk(BIOS_SPEW, "SF: Unsupported manufacturer %02x\n", *idp); + goto err_manufacturer_probe; + } + + printk(BIOS_SPEW, "SF: Detected %s with page size %x, total %x\n", flash->name, flash->sector_size, flash->size); + + spi_release_bus(spi); + + return flash; + +err_manufacturer_probe: +err_read_id: + spi_release_bus(spi); +err_claim_bus: + spi_free_slave(spi); + return NULL; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_free_slave(flash->spi); + free(flash); +} diff --git a/src/drivers/spi/spi_flash_internal.h b/src/drivers/spi/spi_flash_internal.h new file mode 100644 index 0000000..b895e2b --- /dev/null +++ b/src/drivers/spi/spi_flash_internal.h @@ -0,0 +1,81 @@ +/* + * SPI flash internal definitions + * + * Copyright (C) 2008 Atmel Corporation + */ + +/* Common parameters -- kind of high, but they should only occur when there + * is a problem (and well your system already is broken), so err on the side + * of caution in case we're dealing with slower SPI buses and/or processors. + */ +#define CONFIG_SYS_HZ 100 +#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) +#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) +#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) + +/* Common commands */ +#define CMD_READ_ID 0x9f + +#define CMD_READ_ARRAY_SLOW 0x03 +#define CMD_READ_ARRAY_FAST 0x0b +#define CMD_READ_ARRAY_LEGACY 0xe8 + +#define CMD_READ_STATUS 0x05 +#define CMD_WRITE_ENABLE 0x06 + +/* Common status */ +#define STATUS_WIP 0x01 + +/* Send a single-byte command to the device and read the response */ +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); + +/* + * Send a multi-byte command to the device and read the response. Used + * for flash array reads, etc. + */ +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +/* + * Send a multi-byte command to the device followed by (optional) + * data. Used for programming the flash array, etc. + */ +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len); + +/* + * Same as spi_flash_cmd_read() except it also claims/releases the SPI + * bus. Used as common part of the ->read() operation. + */ +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* Send a command to the device and wait for some bit to clear itself. */ +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit); + +/* + * Send the read status command to the device and wait for the wip + * (write-in-progress) bit to clear itself. + */ +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); + +/* Erase sectors. */ +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 offset, size_t len); + +/* Manufacturer-specific probe functions */ +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode); diff --git a/src/drivers/spi/sst.c b/src/drivers/spi/sst.c new file mode 100644 index 0000000..9c87dae --- /dev/null +++ b/src/drivers/spi/sst.c @@ -0,0 +1,268 @@ +/* + * Driver for SST serial flashes + * + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd at denx.de. + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +#define CMD_SST_WREN 0x06 /* Write Enable */ +#define CMD_SST_WRDI 0x04 /* Write Disable */ +#define CMD_SST_RDSR 0x05 /* Read Status Register */ +#define CMD_SST_WRSR 0x01 /* Write Status Register */ +#define CMD_SST_READ 0x03 /* Read Data Bytes */ +#define CMD_SST_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_SST_BP 0x02 /* Byte Program */ +#define CMD_SST_AAI_WP 0xAD /* Auto Address Increment Word Program */ +#define CMD_SST_SE 0x20 /* Sector Erase */ + +#define SST_SR_WIP (1 << 0) /* Write-in-Progress */ +#define SST_SR_WEL (1 << 1) /* Write enable */ +#define SST_SR_BP0 (1 << 2) /* Block Protection 0 */ +#define SST_SR_BP1 (1 << 3) /* Block Protection 1 */ +#define SST_SR_BP2 (1 << 4) /* Block Protection 2 */ +#define SST_SR_AAI (1 << 6) /* Addressing mode */ +#define SST_SR_BPL (1 << 7) /* BP bits lock */ + +struct sst_spi_flash_params { + u8 idcode1; + u16 nr_sectors; + const char *name; +}; + +struct sst_spi_flash { + struct spi_flash flash; + const struct sst_spi_flash_params *params; +}; + +static inline struct sst_spi_flash *to_sst_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct sst_spi_flash, flash); +} + +#define SST_SECTOR_SIZE (4 * 1024) +static const struct sst_spi_flash_params sst_spi_flash_table[] = { + { + .idcode1 = 0x8d, + .nr_sectors = 128, + .name = "SST25VF040B", + },{ + .idcode1 = 0x8e, + .nr_sectors = 256, + .name = "SST25VF080B", + },{ + .idcode1 = 0x41, + .nr_sectors = 512, + .name = "SST25VF016B", + },{ + .idcode1 = 0x4a, + .nr_sectors = 1024, + .name = "SST25VF032B", + },{ + .idcode1 = 0x4b, + .nr_sectors = 2048, + .name = "SST25VF064C", + },{ + .idcode1 = 0x01, + .nr_sectors = 16, + .name = "SST25WF512", + },{ + .idcode1 = 0x02, + .nr_sectors = 32, + .name = "SST25WF010", + },{ + .idcode1 = 0x03, + .nr_sectors = 64, + .name = "SST25WF020", + },{ + .idcode1 = 0x04, + .nr_sectors = 128, + .name = "SST25WF040", + }, +}; + +static int +sst_enable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WREN, NULL, 0); + if (ret) + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + return ret; +} + +static int +sst_disable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WRDI, NULL, 0); + if (ret) + printk(BIOS_SPEW, "SF: Disabling Write failed\n"); + return ret; +} + +static int +sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) +{ + int ret; + u8 cmd[4] = { + CMD_SST_BP, + offset >> 16, + offset >> 8, + offset, + }; + + printk(BIOS_SPEW, "BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf, cmd[0], offset); + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); + if (ret) + return ret; + + return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); +} + +static int +sst_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) +{ + size_t actual, cmd_len; + int ret; + u8 cmd[4]; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + /* If the data is not word aligned, write out leading single byte */ + actual = offset % 2; + if (actual) { + ret = sst_byte_write(flash, offset, buf); + if (ret) + goto done; + } + offset += actual; + + ret = sst_enable_writing(flash); + if (ret) + goto done; + + cmd_len = 4; + cmd[0] = CMD_SST_AAI_WP; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + + for (; actual < len - 1; actual += 2) { + printk(BIOS_SPEW, "WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf + actual, cmd[0], + offset); + + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, + buf + actual, 2); + if (ret) { + printk(BIOS_SPEW, "SF: sst word program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + cmd_len = 1; + offset += 2; + } + + if (!ret) + ret = sst_disable_writing(flash); + + /* If there is a single trailing byte, write it out */ + if (!ret && actual != len) + ret = sst_byte_write(flash, offset, buf + actual); + + done: + printk(BIOS_SPEW, "SF: sst: program %s %zu bytes @ 0x%lx\n", + ret ? "failure" : "success", len, offset - actual); + + spi_release_bus(flash->spi); + return ret; +} + +static int sst_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_SST_SE, offset, len); +} + +static int +sst_unlock(struct spi_flash *flash) +{ + int ret; + u8 cmd, status; + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + cmd = CMD_SST_WRSR; + status = 0; + ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &status, 1); + if (ret) + printk(BIOS_SPEW, "SF: Unable to set status byte\n"); + + printk(BIOS_SPEW, "SF: sst: status = %x\n", spi_w8r8(flash->spi, CMD_SST_RDSR)); + + return ret; +} + +struct spi_flash * +spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode) +{ + const struct sst_spi_flash_params *params; + struct sst_spi_flash *stm; + size_t i; + + for (i = 0; i < ARRAY_SIZE(sst_spi_flash_table); ++i) { + params = &sst_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(sst_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported SST ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(*stm)); + if (!stm) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = sst_write; + stm->flash.erase = sst_erase; + stm->flash.read = spi_flash_cmd_read_fast; + stm->flash.sector_size = SST_SECTOR_SIZE; + stm->flash.size = stm->flash.sector_size * params->nr_sectors; + + /* Flash powers up read-only, so clear BP# bits */ + sst_unlock(&stm->flash); + + return &stm->flash; +} diff --git a/src/drivers/spi/stmicro.c b/src/drivers/spi/stmicro.c new file mode 100644 index 0000000..370d15a --- /dev/null +++ b/src/drivers/spi/stmicro.c @@ -0,0 +1,250 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd at denx.de. + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_M25PXX_WREN 0x06 /* Write Enable */ +#define CMD_M25PXX_WRDI 0x04 /* Write Disable */ +#define CMD_M25PXX_RDSR 0x05 /* Read Status Register */ +#define CMD_M25PXX_WRSR 0x01 /* Write Status Register */ +#define CMD_M25PXX_READ 0x03 /* Read Data Bytes */ +#define CMD_M25PXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_M25PXX_PP 0x02 /* Page Program */ +#define CMD_M25PXX_SE 0xd8 /* Sector Erase */ +#define CMD_M25PXX_BE 0xc7 /* Bulk Erase */ +#define CMD_M25PXX_DP 0xb9 /* Deep Power-down */ +#define CMD_M25PXX_RES 0xab /* Release from DP, and Read Signature */ + +#define STM_ID_M25P10 0x11 +#define STM_ID_M25P16 0x15 +#define STM_ID_M25P20 0x12 +#define STM_ID_M25P32 0x16 +#define STM_ID_M25P40 0x13 +#define STM_ID_M25P64 0x17 +#define STM_ID_M25P80 0x14 +#define STM_ID_M25P128 0x18 + +struct stmicro_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct stmicro_spi_flash { + struct spi_flash flash; + const struct stmicro_spi_flash_params *params; +}; + +static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct stmicro_spi_flash, flash); +} + +static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { + { + .idcode1 = STM_ID_M25P10, + .page_size = 256, + .pages_per_sector = 128, + .nr_sectors = 4, + .name = "M25P10", + }, + { + .idcode1 = STM_ID_M25P16, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "M25P16", + }, + { + .idcode1 = STM_ID_M25P20, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 4, + .name = "M25P20", + }, + { + .idcode1 = STM_ID_M25P32, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "M25P32", + }, + { + .idcode1 = STM_ID_M25P40, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 8, + .name = "M25P40", + }, + { + .idcode1 = STM_ID_M25P64, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "M25P64", + }, + { + .idcode1 = STM_ID_M25P80, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "M25P80", + }, + { + .idcode1 = STM_ID_M25P128, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "M25P128", + }, +}; + +static int stmicro_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = stm->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_M25PXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: STMicro Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: STMicro: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_M25PXX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) +{ + const struct stmicro_spi_flash_params *params; + struct stmicro_spi_flash *stm; + unsigned int i; + + if (idcode[0] == 0xff) { + i = spi_flash_cmd(spi, CMD_M25PXX_RES, + idcode, 4); + if (i) + return NULL; + if ((idcode[3] & 0xf0) == 0x10) { + idcode[0] = 0x20; + idcode[1] = 0x20; + idcode[2] = idcode[3] + 1; + } else + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) { + params = &stmicro_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) { + break; + } + } + + if (i == ARRAY_SIZE(stmicro_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported STMicro ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(struct stmicro_spi_flash)); + if (!stm) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = stmicro_write; + stm->flash.erase = stmicro_erase; + stm->flash.read = spi_flash_cmd_read_fast; + stm->flash.sector_size = params->page_size * params->pages_per_sector; + stm->flash.size = stm->flash.sector_size * params->nr_sectors; + + return &stm->flash; +} diff --git a/src/drivers/spi/winbond.c b/src/drivers/spi/winbond.c new file mode 100644 index 0000000..4329c55 --- /dev/null +++ b/src/drivers/spi/winbond.c @@ -0,0 +1,218 @@ +/* + * Copyright 2008, Network Appliance Inc. + * Author: Jason McMullan netapp.com> + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_W25_WREN 0x06 /* Write Enable */ +#define CMD_W25_WRDI 0x04 /* Write Disable */ +#define CMD_W25_RDSR 0x05 /* Read Status Register */ +#define CMD_W25_WRSR 0x01 /* Write Status Register */ +#define CMD_W25_READ 0x03 /* Read Data Bytes */ +#define CMD_W25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_W25_PP 0x02 /* Page Program */ +#define CMD_W25_SE 0x20 /* Sector (4K) Erase */ +#define CMD_W25_BE 0xd8 /* Block (64K) Erase */ +#define CMD_W25_CE 0xc7 /* Chip Erase */ +#define CMD_W25_DP 0xb9 /* Deep Power-down */ +#define CMD_W25_RES 0xab /* Release from DP, and Read Signature */ + +struct winbond_spi_flash_params { + uint16_t id; + /* Log2 of page size in power-of-two mode */ + uint8_t l2_page_size; + uint16_t pages_per_sector; + uint16_t sectors_per_block; + uint16_t nr_blocks; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct winbond_spi_flash { + struct spi_flash flash; + const struct winbond_spi_flash_params *params; +}; + +static inline struct winbond_spi_flash * +to_winbond_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct winbond_spi_flash, flash); +} + +static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { + { + .id = 0x3015, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "W25X16", + }, + { + .id = 0x3016, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "W25X32", + }, + { + .id = 0x3017, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "W25X64", + }, + { + .id = 0x4015, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "W25Q16", + }, + { + .id = 0x4016, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "W25Q32", + }, + { + .id = 0x4017, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "W25Q64", + }, + { + .id = 0x4018, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "W25Q128", + }, +}; + +static int winbond_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct winbond_spi_flash *stm = to_winbond_spi_flash(flash); + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT); + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_W25_PP; + cmd[1] = (offset >> 16) & 0xff; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %ld\n", + buf + actual, + cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_W25_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + goto out; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Winbond Page Program failed\n"); + goto out; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + goto out; + + offset += chunk_len; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: Winbond: Successfully programmed %zu bytes @ 0x%lx\n", + len, offset - len); + ret = 0; + +out: + spi_release_bus(flash->spi); + return ret; +} + +static int winbond_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_W25_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) +{ + const struct winbond_spi_flash_params *params; + unsigned page_size; + struct winbond_spi_flash *stm; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(winbond_spi_flash_table); i++) { + params = &winbond_spi_flash_table[i]; + if (params->id == ((idcode[1] << 8) | idcode[2])) + break; + } + + if (i == ARRAY_SIZE(winbond_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported Winbond ID %02x%02x\n", + idcode[1], idcode[2]); + return NULL; + } + + stm = malloc(sizeof(struct winbond_spi_flash)); + if (!stm) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + /* Assuming power-of-two page size initially. */ + page_size = 1 << params->l2_page_size; + + stm->flash.write = winbond_write; + stm->flash.erase = winbond_erase; +#ifdef CONFIG_SPI_FLASH_NO_FAST_READ + stm->flash.read = spi_flash_cmd_read_slow; +#else + stm->flash.read = spi_flash_cmd_read_fast; +#endif + stm->flash.sector_size = (1 << stm->params->l2_page_size) * + stm->params->pages_per_sector; + stm->flash.size = page_size * params->pages_per_sector + * params->sectors_per_block + * params->nr_blocks; + + return &stm->flash; +} diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h index a2d6884..1765293 100644 --- a/src/include/device/pci_ids.h +++ b/src/include/device/pci_ids.h @@ -2502,6 +2502,10 @@ #define PCI_DEVICE_ID_INTEL_82801IO_LPC 0x2914 #define PCI_DEVICE_ID_INTEL_82801IH_LPC 0x2912 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f +#define PCI_DEVICE_ID_INTEL_TGP_LPC 0x27bc + /* Intel 82801E (C-ICH) */ #define PCI_DEVICE_ID_INTEL_82801E_LPC 0x2450 #define PCI_DEVICE_ID_INTEL_82801E_USB 0x2452 diff --git a/src/include/spi.h b/src/include/spi.h new file mode 100644 index 0000000..bb84258 --- /dev/null +++ b/src/include/spi.h @@ -0,0 +1,203 @@ +/* + * (C) Copyright 2001 + * Gerald Van Baren, Custom IDEAS, vanbaren at cideas.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _SPI_H_ +#define _SPI_H_ + +#include + +/* Controller-specific definitions: */ + +/* SPI mode flags */ +#define SPI_CPHA 0x01 /* clock phase */ +#define SPI_CPOL 0x02 /* clock polarity */ +#define SPI_MODE_0 (0|0) /* (original MicroWire) */ +#define SPI_MODE_1 (0|SPI_CPHA) +#define SPI_MODE_2 (SPI_CPOL|0) +#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) +#define SPI_CS_HIGH 0x04 /* CS active high */ +#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ +#define SPI_3WIRE 0x10 /* SI/SO signals shared */ +#define SPI_LOOP 0x20 /* loopback mode */ + +/* SPI transfer flags */ +#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ +#define SPI_XFER_END 0x02 /* Deassert CS after transfer */ + +/*----------------------------------------------------------------------- + * Representation of a SPI slave, i.e. what we're communicating with. + * + * Drivers are expected to extend this with controller-specific data. + * + * bus: ID of the bus that the slave is attached to. + * cs: ID of the chip select connected to the slave. + */ +struct spi_slave { + unsigned int bus; + unsigned int cs; +}; + +/*----------------------------------------------------------------------- + * Initialization, must be called once on start up. + * + * TODO: I don't think we really need this. + */ +void spi_init(void); + +/*----------------------------------------------------------------------- + * Set up communications parameters for a SPI slave. + * + * This must be called once for each slave. Note that this function + * usually doesn't touch any actual hardware, it only initializes the + * contents of spi_slave so that the hardware can be easily + * initialized later. + * + * bus: Bus ID of the slave chip. + * cs: Chip select ID of the slave chip on the specified bus. + * max_hz: Maximum SCK rate in Hz. + * mode: Clock polarity, clock phase and other parameters. + * + * Returns: A spi_slave reference that can be used in subsequent SPI + * calls, or NULL if one or more of the parameters are not supported. + */ +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode); + +/*----------------------------------------------------------------------- + * Free any memory associated with a SPI slave. + * + * slave: The SPI slave + */ +void spi_free_slave(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Claim the bus and prepare it for communication with a given slave. + * + * This must be called before doing any transfers with a SPI slave. It + * will enable and initialize any SPI hardware as necessary, and make + * sure that the SCK line is in the correct idle state. It is not + * allowed to claim the same bus for several slaves without releasing + * the bus in between. + * + * slave: The SPI slave + * + * Returns: 0 if the bus was claimed successfully, or a negative value + * if it wasn't. + */ +int spi_claim_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Release the SPI bus + * + * This must be called once for every call to spi_claim_bus() after + * all transfers have finished. It may disable any SPI hardware as + * appropriate. + * + * slave: The SPI slave + */ +void spi_release_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * SPI transfer + * + * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks + * "bitlen" bits in the SPI MISO port. That's just the way SPI works. + * + * The source of the outgoing bits is the "dout" parameter and the + * destination of the input bits is the "din" parameter. Note that "dout" + * and "din" can point to the same memory location, in which case the + * input data overwrites the output data (since both are buffered by + * temporary variables, this is OK). + * + * spi_xfer() interface: + * slave: The SPI slave which will be sending/receiving the data. + * dout: Pointer to a string of bits to send out. The bits are + * held in a byte array and are sent MSB first. + * bitsout: How many bits to write. + * din: Pointer to a string of bits that will be filled in. + * bitsin: How many bits to read. + * + * Returns: 0 on success, not 0 on failure + */ +int spi_xfer(struct spi_slave *slave, const void *dout, unsigned int bitsout, + void *din, unsigned int bitsin); + +/*----------------------------------------------------------------------- + * Determine if a SPI chipselect is valid. + * This function is provided by the board if the low-level SPI driver + * needs it to determine if a given chipselect is actually valid. + * + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 + * otherwise. + */ +int spi_cs_is_valid(unsigned int bus, unsigned int cs); + +/*----------------------------------------------------------------------- + * Activate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should activate the chip select + * to the device identified by "slave". + */ +void spi_cs_activate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Deactivate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should deactivate the chip + * select to the device identified by "slave". + */ +void spi_cs_deactivate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Set transfer speed. + * This sets a new speed to be applied for next spi_xfer(). + * slave: The SPI slave + * hz: The transfer speed + */ +void spi_set_speed(struct spi_slave *slave, uint32_t hz); + +/*----------------------------------------------------------------------- + * Write 8 bits, then read 8 bits. + * slave: The SPI slave we're communicating with + * byte: Byte to be written + * + * Returns: The value that was read, or a negative value on error. + * + * TODO: This function probably shouldn't be inlined. + */ +static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) +{ + unsigned char dout[2]; + unsigned char din[2]; + int ret; + + dout[0] = byte; + dout[1] = 0; + + ret = spi_xfer(slave, dout, 16, din, 16); + return ret < 0 ? ret : din[1]; +} + +#endif /* _SPI_H_ */ diff --git a/src/include/spi_flash.h b/src/include/spi_flash.h new file mode 100644 index 0000000..2a1dcd4 --- /dev/null +++ b/src/include/spi_flash.h @@ -0,0 +1,91 @@ +/* + * Interface to SPI flash + * + * Copyright (C) 2008 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _SPI_FLASH_H_ +#define _SPI_FLASH_H_ + +#include +#include +#include +#include + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define min(a, b) ((a)<(b)?(a):(b)) + +#define CONFIG_ICH_SPI +#ifdef CONFIG_ICH_SPI +#define CONTROLLER_PAGE_LIMIT 64 +#else +/* any number larger than 4K would do, actually */ +#define CONTROLLER_PAGE_LIMIT ((int)(~0U>>1)) +#endif + +struct spi_flash { + struct spi_slave *spi; + + const char *name; + + u32 size; + + u32 sector_size; + + int (*read)(struct spi_flash *flash, u32 offset, + size_t len, void *buf); + int (*write)(struct spi_flash *flash, u32 offset, + size_t len, const void *buf); + int (*erase)(struct spi_flash *flash, u32 offset, + size_t len); +}; + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode); +void spi_flash_free(struct spi_flash *flash); + +static inline int spi_flash_read(struct spi_flash *flash, u32 offset, + size_t len, void *buf) +{ + return flash->read(flash, offset, len, buf); +} + +static inline int spi_flash_write(struct spi_flash *flash, u32 offset, + size_t len, const void *buf) +{ + return flash->write(flash, offset, len, buf); +} + +static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, + size_t len) +{ + return flash->erase(flash, offset, len); +} + +#endif /* _SPI_FLASH_H_ */ diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 8209980..6548b32 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -340,6 +340,7 @@ void sdram_initialize(struct pei_data *pei_data) /* If MRC data is not found we cannot continue S3 resume. */ if (pei_data->boot_mode == 2 && !pei_data->mrc_input) { + printk(BIOS_DEBUG, "Giving up in sdram_initialize: No MRC data\n"); outb(0x6, 0xcf9); hlt(); } diff --git a/src/southbridge/intel/bd82x6x/Kconfig b/src/southbridge/intel/bd82x6x/Kconfig index 3891be1..f105ee3 100644 --- a/src/southbridge/intel/bd82x6x/Kconfig +++ b/src/southbridge/intel/bd82x6x/Kconfig @@ -33,6 +33,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy select USE_WATCHDOG_ON_BOOT select PCIEXP_ASPM select PCIEXP_COMMON_CLOCK + select SPI config EHCI_BAR hex diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc index 5732254..f086426 100644 --- a/src/southbridge/intel/bd82x6x/Makefile.inc +++ b/src/southbridge/intel/bd82x6x/Makefile.inc @@ -34,6 +34,8 @@ ramstage-y += me_status.c ramstage-y += reset.c ramstage-y += watchdog.c +ramstage-y += spi.c + ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c $(me-src-y) finalize.c diff --git a/src/southbridge/intel/bd82x6x/spi.c b/src/southbridge/intel/bd82x6x/spi.c new file mode 100644 index 0000000..c54a325 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/spi.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* This file is derived from the flashrom project. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define min(a, b) ((a)<(b)?(a):(b)) + +typedef device_t pci_dev_t; +#define pci_read_config_byte(dev, reg, targ) *(targ) = pci_read_config8(dev, reg) +#define pci_read_config_word(dev, reg, targ) *(targ) = pci_read_config16(dev, reg) +#define pci_read_config_dword(dev, reg, targ) *(targ) = pci_read_config32(dev, reg) +#define pci_write_config_byte(dev, reg, val) pci_write_config8(dev, reg, val) +#define pci_write_config_word(dev, reg, val) pci_write_config16(dev, reg, val) +#define pci_write_config_dword(dev, reg, val) pci_write_config32(dev, reg, val) + +typedef struct spi_slave ich_spi_slave; + +static int ichspi_lock = 0; + +typedef struct ich7_spi_regs { + uint16_t spis; + uint16_t spic; + uint32_t spia; + uint64_t spid[8]; + uint64_t _pad; + uint32_t bbar; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; +} __attribute__((packed)) ich7_spi_regs; + +typedef struct ich9_spi_regs { + uint32_t bfpr; + uint16_t hsfs; + uint16_t hsfc; + uint32_t faddr; + uint32_t _reserved0; + uint32_t fdata[16]; + uint32_t frap; + uint32_t freg[5]; + uint32_t _reserved1[3]; + uint32_t pr[5]; + uint32_t _reserved2[2]; + uint8_t ssfs; + uint8_t ssfc[3]; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; + uint32_t bbar; + uint8_t _reserved3[12]; + uint32_t fdoc; + uint32_t fdod; + uint8_t _reserved4[8]; + uint32_t afc; + uint32_t lvscc; + uint32_t uvscc; + uint8_t _reserved5[4]; + uint32_t fpb; + uint8_t _reserved6[28]; + uint32_t srdl; + uint32_t srdc; + uint32_t srd; +} __attribute__((packed)) ich9_spi_regs; + +typedef struct ich_spi_controller { + int locked; + + uint8_t *opmenu; + int menubytes; + uint16_t *preop; + uint16_t *optype; + uint32_t *addr; + uint8_t *data; + unsigned databytes; + uint8_t *status; + uint16_t *control; + uint32_t *bbar; +} ich_spi_controller; + +static ich_spi_controller cntlr; + +enum { + SPIS_SCIP = 0x0001, + SPIS_GRANT = 0x0002, + SPIS_CDS = 0x0004, + SPIS_FCERR = 0x0008, + SSFS_AEL = 0x0010, + SPIS_LOCK = 0x8000, + SPIS_RESERVED_MASK = 0x7ff0, + SSFS_RESERVED_MASK = 0x7fe2 +}; + +enum { + SPIC_SCGO = 0x000002, + SPIC_ACS = 0x000004, + SPIC_SPOP = 0x000008, + SPIC_DBC = 0x003f00, + SPIC_DS = 0x004000, + SPIC_SME = 0x008000, + SSFC_SCF_MASK = 0x070000, + SSFC_RESERVED = 0xf80000 +}; + +enum { + HSFS_FDONE = 0x0001, + HSFS_FCERR = 0x0002, + HSFS_AEL = 0x0004, + HSFS_BERASE_MASK = 0x0018, + HSFS_BERASE_SHIFT = 3, + HSFS_SCIP = 0x0020, + HSFS_FDOPSS = 0x2000, + HSFS_FDV = 0x4000, + HSFS_FLOCKDN = 0x8000 +}; + +enum { + HSFC_FGO = 0x0001, + HSFC_FCYCLE_MASK = 0x0006, + HSFC_FCYCLE_SHIFT = 1, + HSFC_FDBC_MASK = 0x3f00, + HSFC_FDBC_SHIFT = 8, + HSFC_FSMIE = 0x8000 +}; + +enum { + SPI_OPCODE_TYPE_READ_NO_ADDRESS = 0, + SPI_OPCODE_TYPE_WRITE_NO_ADDRESS = 1, + SPI_OPCODE_TYPE_READ_WITH_ADDRESS = 2, + SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS = 3 +}; + +#ifdef DEBUG + +static u8 readb_(const void *addr) +{ + u8 v = readb(addr); + printk(BIOS_DEBUG, "read %2.2x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u16 readw_(const void *addr) +{ + u16 v = readw(addr); + printk(BIOS_DEBUG, "read %4.4x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u32 readl_(const void *addr) +{ + u32 v = readl(addr); + printk(BIOS_DEBUG, "read %8.8x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static void writeb_(u8 b, const void *addr) +{ + writeb(b, addr); + printk(BIOS_DEBUG, "wrote %2.2x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writew_(u16 b, const void *addr) +{ + writew(b, addr); + printk(BIOS_DEBUG, "wrote %4.4x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writel_(u32 b, const void *addr) +{ + writel(b, addr); + printk(BIOS_DEBUG, "wrote %8.8x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +#else /* DEBUG ^^^ defined vvv NOT defined */ + +#define readb_(a) read8((uint32_t)a) +#define readw_(a) read16((uint32_t)a) +#define readl_(a) read32((uint32_t)a) +#define writeb_(val, addr) write8((uint32_t)addr, val) +#define writew_(val, addr) write16((uint32_t)addr, val) +#define writel_(val, addr) write32((uint32_t)addr, val) + +#endif /* DEBUG ^^^ NOT defined */ + +static void write_reg(const void *value, void *dest, uint32_t size) +{ + const uint8_t *bvalue = value; + uint8_t *bdest = dest; + + while (size >= 4) { + writel_(*(const uint32_t *)bvalue, bdest); + bdest += 4; bvalue += 4; size -= 4; + } + while (size) { + writeb_(*bvalue, bdest); + bdest++; bvalue++; size--; + } +} + +static void read_reg(const void *src, void *value, uint32_t size) +{ + const uint8_t *bsrc = src; + uint8_t *bvalue = value; + + while (size >= 4) { + *(uint32_t *)bvalue = readl_(bsrc); + bsrc += 4; bvalue += 4; size -= 4; + } + while (size) { + *bvalue = readb_(bsrc); + bsrc++; bvalue++; size--; + } +} + +static void ich_set_bbar(uint32_t minaddr) +{ + const uint32_t bbar_mask = 0x00ffff00; + uint32_t ichspi_bbar; + + minaddr &= bbar_mask; + ichspi_bbar = readl_(cntlr.bbar) & ~bbar_mask; + ichspi_bbar |= minaddr; + writel_(ichspi_bbar, cntlr.bbar); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + printk(BIOS_DEBUG, "spi_cs_is_valid used but not implemented\n"); + return 0; +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + ich_spi_slave *slave = malloc(sizeof(*slave)); + + if (!slave) { + printk(BIOS_DEBUG, "ICH SPI: Bad allocation\n"); + return NULL; + } + + memset(slave, 0, sizeof(*slave)); + + slave->bus = bus; + slave->cs = cs; + return slave; +} + +void spi_free_slave(struct spi_slave *_slave) +{ + ich_spi_slave *slave = (ich_spi_slave *)_slave; + free(slave); +} + +static inline int spi_is_cougarpoint_lpc(uint16_t device_id) +{ + return device_id >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN && + device_id <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX; +}; + +void spi_init(void) +{ + int ich_version = 0; + + uint8_t *rcrb; /* Root Complex Register Block */ + uint32_t rcba; /* Root Complex Base Address */ + uint8_t bios_cntl; + pci_dev_t dev; + + int bus; + int last_bus = 1; //FIXME: pci_last_busno(); + + if (last_bus == -1) { + printk(BIOS_DEBUG, "No PCI busses?\n"); + return; + } + + for (bus = 0; bus <= last_bus; bus++) { + uint32_t ids; + uint16_t vendor_id, device_id; + + dev = dev_find_slot(bus, PCI_DEVFN(31, 0)); + pci_read_config_dword(dev, 0, &ids); + vendor_id = ids; + device_id = (ids >> 16); + + if (vendor_id != PCI_VENDOR_ID_INTEL) + continue; + + if (device_id == PCI_DEVICE_ID_INTEL_TGP_LPC) { + ich_version = 7; + break; + } else if (spi_is_cougarpoint_lpc(device_id)) { + ich_version = 9; + break; + } + } + + if (!ich_version) { + printk(BIOS_DEBUG, "ICH SPI: No ICH found.\n"); + return; + } + + pci_read_config_dword(dev, 0xf0, &rcba); + /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable. */ + rcrb = (uint8_t *)(rcba & 0xffffc000); + switch (ich_version) { + case 7: + { + const uint16_t ich7_spibar_offset = 0x3020; + ich7_spi_regs *ich7_spi = + (ich7_spi_regs *)(rcrb + ich7_spibar_offset); + + ichspi_lock = readw_(&ich7_spi->spis) & SPIS_LOCK; + cntlr.opmenu = ich7_spi->opmenu; + cntlr.menubytes = sizeof(ich7_spi->opmenu); + cntlr.optype = &ich7_spi->optype; + cntlr.addr = &ich7_spi->spia; + cntlr.data = (uint8_t *)ich7_spi->spid; + cntlr.databytes = sizeof(ich7_spi->spid); + cntlr.status = (uint8_t *)&ich7_spi->spis; + cntlr.control = &ich7_spi->spic; + cntlr.bbar = &ich7_spi->bbar; + cntlr.preop = &ich7_spi->preop; + break; + } + case 9: + { + const uint16_t ich9_spibar_offset = 0x3800; + ich9_spi_regs *ich9_spi = + (ich9_spi_regs *)(rcrb + ich9_spibar_offset); + ichspi_lock = readw_(&ich9_spi->hsfs) & HSFS_FLOCKDN; + cntlr.opmenu = ich9_spi->opmenu; + cntlr.menubytes = sizeof(ich9_spi->opmenu); + cntlr.optype = &ich9_spi->optype; + cntlr.addr = &ich9_spi->faddr; + cntlr.data = (uint8_t *)ich9_spi->fdata; + cntlr.databytes = sizeof(ich9_spi->fdata); + cntlr.status = &ich9_spi->ssfs; + cntlr.control = (uint16_t *)ich9_spi->ssfc; + cntlr.bbar = &ich9_spi->bbar; + cntlr.preop = &ich9_spi->preop; + break; + } + default: + printk(BIOS_DEBUG, "ICH SPI: Unrecognized ICH version %d.\n", ich_version); + } + + ich_set_bbar(0); + + /* Disable the BIOS write protect so write commands are allowed. */ + pci_read_config_byte(dev, 0xdc, &bios_cntl); + switch (ich_version) { + case 9: + /* Deassert SMM BIOS Write Protect Disable. */ + bios_cntl &= ~(1 << 5); + break; + + default: + break; + } + pci_write_config_byte(dev, 0xdc, bios_cntl | 0x1); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_activate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +typedef struct spi_transaction { + const uint8_t *out; + uint32_t bytesout; + uint8_t *in; + uint32_t bytesin; + uint8_t type; + uint8_t opcode; + uint32_t offset; +} spi_transaction; + +static inline void spi_use_out(spi_transaction *trans, unsigned bytes) +{ + trans->out += bytes; + trans->bytesout -= bytes; +} + +static inline void spi_use_in(spi_transaction *trans, unsigned bytes) +{ + trans->in += bytes; + trans->bytesin -= bytes; +} + +static void spi_setup_type(spi_transaction *trans) +{ + trans->type = 0xFF; + + /* Try to guess spi type from read/write sizes. */ + if (trans->bytesin == 0) { + if (trans->bytesout > 4) + /* + * If bytesin = 0 and bytesout > 4, we presume this is + * a write data operation, which is accompanied by an + * address. + */ + trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS; + else + trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS; + return; + } + + if (trans->bytesout == 1) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS; + return; + } + + if (trans->bytesout == 4) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS; + } +} + +static int spi_setup_opcode(spi_transaction *trans) +{ + uint16_t optypes; + uint8_t opmenu[cntlr.menubytes]; + + trans->opcode = trans->out[0]; + spi_use_out(trans, 1); + if (!ichspi_lock) { + /* The lock is off, so just use index 0. */ + writeb_(trans->opcode, cntlr.opmenu); + optypes = readw_(cntlr.optype); + optypes = (optypes & 0xfffc) | (trans->type & 0x3); + writew_(optypes, cntlr.optype); + return 0; + } else { + /* The lock is on. See if what we need is on the menu. */ + uint8_t optype; + uint16_t opcode_index; + + read_reg(cntlr.opmenu, opmenu, sizeof(opmenu)); + for (opcode_index = 0; opcode_index < cntlr.menubytes; + opcode_index++) { + if (opmenu[opcode_index] == trans->opcode) + break; + } + + if (opcode_index == cntlr.menubytes) { + printk(BIOS_DEBUG, "ICH SPI: Opcode %x not found\n", + trans->opcode); + return -1; + } + + optypes = readw_(cntlr.optype); + optype = (optypes >> (opcode_index * 2)) & 0x3; + if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS && + optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS && + trans->bytesout >= 3) { + /* We guessed wrong earlier. Fix it up. */ + trans->type = optype; + } + if (optype != trans->type) { + printk(BIOS_DEBUG, "ICH SPI: Transaction doesn't fit type %d\n", + optype); + return -1; + } + return opcode_index; + } +} + +static int spi_setup_offset(spi_transaction *trans) +{ + /* Separate the SPI address and data. */ + switch (trans->type) { + case SPI_OPCODE_TYPE_READ_NO_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_NO_ADDRESS: + return 0; + case SPI_OPCODE_TYPE_READ_WITH_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS: + trans->offset = ((uint32_t)trans->out[0] << 16) | + ((uint32_t)trans->out[1] << 8) | + ((uint32_t)trans->out[2] << 0); + spi_use_out(trans, 3); + return 1; + default: + printk(BIOS_DEBUG, "Unrecognized SPI transaction type %#x\n", trans->type); + return -1; + } +} + +/* + * Wait for up to 60ms til status register bit(s) turn 1 (in case wait_til_set + * below is True) or 0. In case the wait was for the bit(s) to set - write + * those bits back, which would cause resetting them. + * + * Return the last read status value on success or -1 on failure. + */ +static int ich_status_poll(u16 bitmask, int wait_til_set) +{ + int timeout = 6000; /* This will result in 60 ms */ + u16 status = 0; + + while (timeout--) { + status = readw_(cntlr.status); + if (wait_til_set ^ ((status & bitmask) == 0)) { + if (wait_til_set) + writew_((status & bitmask), cntlr.status); + return status; + } + udelay(10); + } + + printk(BIOS_DEBUG, "ICH SPI: SCIP timeout, read %x, expected %x\n", + status, bitmask); + return -1; +} + +int spi_xfer(struct spi_slave *slave, const void *dout, + unsigned int bitsout, void *din, unsigned int bitsin) +{ + uint16_t control; + int16_t opcode_index; + int with_address; + int status; + + spi_transaction trans = { + dout, bitsout / 8, + din, bitsin / 8, + 0xff, 0xff, 0 + }; + + /* There has to always at least be an opcode. */ + if (!bitsout || !dout) { + printk(BIOS_DEBUG, "ICH SPI: No opcode for transfer\n"); + return -1; + } + /* Make sure if we read something we have a place to put it. */ + if (bitsin != 0 && !din) { + printk(BIOS_DEBUG, "ICH SPI: Read but no target buffer\n"); + return -1; + } + /* Right now we don't support writing partial bytes. */ + if (bitsout % 8 || bitsin % 8) { + printk(BIOS_DEBUG, "ICH SPI: Accessing partial bytes not supported\n"); + return -1; + } + + if (ich_status_poll(SPIS_SCIP, 0) == -1) + return -1; + + writew_(SPIS_CDS | SPIS_FCERR, cntlr.status); + + spi_setup_type(&trans); + if ((opcode_index = spi_setup_opcode(&trans)) < 0) + return -1; + if ((with_address = spi_setup_offset(&trans)) < 0) + return -1; + + if (!ichspi_lock && trans.opcode == 0x06) { + /* + * Treat Write Enable as Atomic Pre-Op if possible + * in order to prevent the Management Engine from + * issuing a transaction between WREN and DATA. + */ + writew_(trans.opcode, cntlr.preop); + return 0; + } + + /* Preset control fields */ + control = SPIC_SCGO | ((opcode_index & 0x07) << 4); + + /* Issue atomic preop cycle if needed */ + if (readw_(cntlr.preop)) + control |= SPIC_ACS; + + if (!trans.bytesout && !trans.bytesin) { + /* + * This is a 'no data' command (like Write Enable), its + * bitesout size was 1, decremented to zero while executing + * spi_setup_opcode() above. Tell the chip to send the + * command. + */ + writew_(control, cntlr.control); + + /* wait for the result */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Command transaction error\n"); + return -1; + } + + return 0; + } + + /* + * Check if this is a write command atempting to transfer more bytes + * than the controller can handle. Iterations for writes are not + * supported here because each SPI write command needs to be preceded + * and followed by other SPI commands, and this sequence is controlled + * by the SPI chip driver. + */ + if (trans.bytesout > cntlr.databytes) { + printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use" + " CONTROLLER_PAGE_LIMIT?\n"); + return -1; + } + + /* + * Read or write up to databytes bytes at a time until everything has + * been sent. + */ + while (trans.bytesout || trans.bytesin) { + uint32_t data_length; + + /* SPI addresses are 24 bit only */ + writel_(trans.offset & 0x00FFFFFF, cntlr.addr); + + if (trans.bytesout) + data_length = min(trans.bytesout, cntlr.databytes); + else + data_length = min(trans.bytesin, cntlr.databytes); + + /* Program data into FDATA0 to N */ + if (trans.bytesout) { + write_reg(trans.out, cntlr.data, data_length); + spi_use_out(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + + /* Add proper control fields' values */ + control &= ~((cntlr.databytes - 1) << 8); + control |= SPIC_DS; + control |= (data_length - 1) << 8; + + /* write it */ + writew_(control, cntlr.control); + + /* Wait for Cycle Done Status or Flash Cycle Error. */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Data transaction error\n"); + return -1; + } + + if (trans.bytesin) { + read_reg(cntlr.data, trans.in, data_length); + spi_use_in(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + } + + /* Clear atomic preop now that xfer is done */ + writew_(0, cntlr.preop); + + return 0; +} From c-d.hailfinger.devel.2006 at gmx.net Fri May 4 00:16:26 2012 From: c-d.hailfinger.devel.2006 at gmx.net (Carl-Daniel Hailfinger) Date: Fri, 04 May 2012 00:16:26 +0200 Subject: [coreboot] [flashrom] Flashing capability in coreboot Message-ID: <4FA303BA.3040206@gmx.net> Hi, coreboot has a requirement to store some data in flash to get some chipsets to work well. There are multiple ways to achieve this: 1. Write flashing code from scratch. Pointless. 2. Use parts of the flashrom codebase or libflashrom. Advantages: coreboot and flashrom developers often work on both projects, enabling better cooperation. flashrom has the best chipset/flash support out there. 3. Use parts of the U-Boot codebase (which has drivers derived from flashrom). Advantages: The codebase is designed with firmware constraints in mind. http://review.coreboot.org/997 seems to implement this. As a flashrom developer, I would like to see flashrom code used in coreboot, and I'm very interested in finding and fixing any obstacles to that goal. Patrick, I think you worked on the coreboot patch mentioned above. Could you tell us about your reasons for choosing option 3, and how we can make option 2 viable? Regards, Carl-Daniel -- http://www.hailfinger.org/ From stefan.reinauer at coreboot.org Fri May 4 00:46:20 2012 From: stefan.reinauer at coreboot.org (Stefan Reinauer) Date: Fri, 4 May 2012 00:46:20 +0200 Subject: [coreboot] [flashrom] Flashing capability in coreboot In-Reply-To: <4FA303BA.3040206@gmx.net> References: <4FA303BA.3040206@gmx.net> Message-ID: <20120503224619.GA8641@coreboot.org> Hi Carl-Daniel, thanks a lot for bringing this up.. * Carl-Daniel Hailfinger [120504 00:16]: > coreboot has a requirement to store some data in flash to get some > chipsets to work well. There are multiple ways to achieve this: > > 1. Write flashing code from scratch. Pointless. That's what has been done for the AMD SB800... See src/southbridge/amd/cimx/sb800/spi.c for more information. That driver is very small, but will also only work for one known good combination of chipset + flashchip. http://review.coreboot.org/997 was done with more flexibility in mind; also regarding certain flash usage constraints. For example on the Samsung ChromeBook coreboot's CBFS lives completely in the read-only section of the flash chip for security reasons. > 2. Use parts of the flashrom codebase or libflashrom. Advantages: > coreboot and flashrom developers often work on both projects, enabling > better cooperation. flashrom has the best chipset/flash support out there. There is no doubt that flashrom is the most flexible and universal implementation out there. It's also almost 40k lines of code, whereas the current implementation covering many flash chips and ICH support fits in only 3000 lines. It may be hard (or not?) to keep the goals of flashrom (flexibility) and coreboot (small, simple) under one hood. > 3. Use parts of the U-Boot codebase (which has drivers derived from > flashrom). Advantages: The codebase is designed with firmware > constraints in mind. http://review.coreboot.org/997 seems to implement this. > > As a flashrom developer, I would like to see flashrom code used in > coreboot, and I'm very interested in finding and fixing any obstacles to > that goal. You might be happy to know that portions of the u-boot driver actually came from flashrom. > Patrick, I think you worked on the coreboot patch mentioned above. Could > you tell us about your reasons for choosing option 3, and how we can > make option 2 viable? Here's my take on this (which should not discourage Patrick from telling the full story and additional details that I might have missed) The background of this is that with coreboot in it's current state you will only be able to resume from suspend when using the ChromiumOS version of u-boot as a payload on Sandybridge systems. When we started looking into these issues initially there was no SPI driver in coreboot while u-boot came readily equipped. So we passed the memory training data from coreboot to u-boot in CBMEM and let u-boot write it. Reworking this to be independent from a certain payload (and getting features like resume from suspend to work with e.g. SeaBIOS) it was the simplest approach to move that portion of the code that already existed from u-boot to coreboot, which is what is working today. This is, as every software project, work in progress and open to iterations. Each of those two before mentioned steps were what could be done with reasonable effort at the time, leading to the current situation of a working implementation. Personally, I would appreciate if we can get this code in as it is for now, and replace it with a better solution as soon as somebody is able to come up with one. Thanks, Stefan From gerrit at coreboot.org Fri May 4 01:46:58 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Fri, 4 May 2012 01:46:58 +0200 Subject: [coreboot] New patch to review for coreboot: 2c45d08 Rework Sandybridge MRC cache handling References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1001 -gerrit commit 2c45d086eb817151fb778f18897f0f64500ba9a3 Author: Stefan Reinauer Date: Thu May 3 16:38:09 2012 -0700 Rework Sandybridge MRC cache handling - Separate Sandybridge from ChromeOS a bit The Sandybridge code depends on chromeos features a whole lot. As a first step, provide a code path to look up the MRC cache without depending on u-boot. - Move mrc cache handling to separate file This enables us to handle the MRC cache from ramstage, where we can write the flash safely (eg. to update the cache). Also teach it to lookup the current MRC cache from CBMEM, as the original data block isn't available anymore. After all the preparations, finally write to the SPI as necessary. It's a simple round robin wear levelling that erases the entire MRC cache region when it's full and starts from the beginning. Change-Id: I4751385574cf709b03d5c9d153b7481ffc90ce12 Signed-off-by: Patrick Georgi --- src/northbridge/intel/sandybridge/Kconfig | 17 ++ src/northbridge/intel/sandybridge/Makefile.inc | 2 + src/northbridge/intel/sandybridge/mrccache.c | 265 +++++++++++++++++++++++ src/northbridge/intel/sandybridge/raminit.c | 123 +---------- src/northbridge/intel/sandybridge/sandybridge.h | 22 ++ 5 files changed, 315 insertions(+), 114 deletions(-) diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig index 8cf0a49..67b3def 100644 --- a/src/northbridge/intel/sandybridge/Kconfig +++ b/src/northbridge/intel/sandybridge/Kconfig @@ -37,6 +37,23 @@ config CACHE_MRC_SIZE_KB int default 256 +# FIXME: build from rom size +config MRC_CACHE_BASE + hex + default 0xff800000 + +config MRC_CACHE_LOCATION + hex + default 0x1ec000 + +config MRC_CACHE_SIZE + hex + default 0x10000 + +config MRC_CACHE_ALIGNMENT + hex + default 0x1000 + config DCACHE_RAM_BASE hex default 0xff7f0000 diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index 87a0b2e..824700e 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -21,9 +21,11 @@ driver-y += northbridge.c driver-y += gma.c ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c +ramstage-y += mrccache.c romstage-y += udelay.c romstage-y += raminit.c +romstage-y += mrccache.c romstage-y += early_init.c romstage-y += report_platform.c romstage-y += ../../../arch/x86/lib/walkcbfs.S diff --git a/src/northbridge/intel/sandybridge/mrccache.c b/src/northbridge/intel/sandybridge/mrccache.c new file mode 100644 index 0000000..5c4c382 --- /dev/null +++ b/src/northbridge/intel/sandybridge/mrccache.c @@ -0,0 +1,265 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Google Inc. + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include "pei_data.h" +#include "sandybridge.h" +#include +#include +/* Using the FDT FMAP for finding the MRC cache area requires including FDT + * support in coreboot, which we would like to avoid. There are a number of + * options: + * - Have each mainboard Kconfig supply a hard-coded offset + * - For ChromeOS devices: implement native FMAP + * - For non-ChromeOS devices: use CBFS + * For now let's leave this code in here until the issue is sorted out in + * a way that works for everyone. + */ +#undef USE_FDT_FMAP_FOR_MRC_CACHE +#ifdef USE_FDT_FMAP_FOR_MRC_CACHE +#include +#endif + +struct mrc_data_container *next_mrc_block(struct mrc_data_container *mrc_cache) +{ + /* MRC data blocks are aligned within the region */ + u32 mrc_size = sizeof(*mrc_cache) + mrc_cache->mrc_data_size; + if (mrc_size & (MRC_DATA_ALIGN - 1UL)) { + mrc_size &= ~(MRC_DATA_ALIGN - 1UL); + mrc_size += MRC_DATA_ALIGN; + } + + u8 *region_ptr = (u8*)mrc_cache; + region_ptr += mrc_size; + return (struct mrc_data_container *)region_ptr; +} + +int is_mrc_cache(struct mrc_data_container *mrc_cache) +{ + return (!!mrc_cache) && (mrc_cache->mrc_signature == MRC_DATA_SIGNATURE); +} + +u32 get_mrc_cache_region(struct mrc_data_container **mrc_region_ptr) +{ + u8 *mrc_region; + u32 region_size; + u32 *data; +#ifdef USE_FDT_FMAP_FOR_MRC_CACHE + const struct fdt_header *fdt_header; + const struct fdt_property *fdtp; + int offset, len; + const char *compatible = "chromeos,flashmap"; + const char *subnode = "rw-mrc-cache"; + const char *property = "reg"; + u64 flashrom_base = 0; + + fdt_header = cbfs_find_file(CONFIG_FDT_FILE_NAME, CBFS_TYPE_FDT); + + if (!fdt_header) { + printk(BIOS_ERR, "%s: no FDT found!\n", __func__); + return 0; + } + + offset = fdt_node_offset_by_compatible(fdt_header, 0, compatible); + if (offset < 0) { + printk(BIOS_ERR, "%s: no %s node found!\n", + __func__, compatible); + return 0; + } + + if (fdt_get_base_addr(fdt_header, offset, &flashrom_base) < 0) { + printk(BIOS_ERR, "%s: no base address in node name!\n", + __func__); + return 0; + } + + offset = fdt_subnode_offset(fdt_header, offset, subnode); + if (offset < 0) { + printk(BIOS_ERR, "%s: no %s found!\n", __func__, subnode); + return 0; + } + + fdtp = fdt_get_property(fdt_header, offset, property, &len); + if (!fdtp || (len != 8)) { + printk(BIOS_ERR, "%s: property %s at %p, len %d!\n", + __func__, property, fdtp, len); + return 0; + } + + data = (u32 *)fdtp->data; + + // Calculate actual address of the MRC cache in memory + region_size = fdt32_to_cpu(data[1]); + mrc_region = (u8*)((unsigned long)flashrom_base + fdt32_to_cpu(data[0])); +#else + data = (u32 *)((void *)(CONFIG_MRC_CACHE_BASE + CONFIG_MRC_CACHE_LOCATION + 12)); + + region_size = CONFIG_MRC_CACHE_SIZE; + mrc_region = (u8*)(CONFIG_MRC_CACHE_BASE + be32_to_cpu(data[0])); +#endif + + *mrc_region_ptr = (struct mrc_data_container *)mrc_region; + + return region_size; +} + +/* find the first empty field in the MRC cache area. If there's none, return + * the first region. By testing for emptiness caller can detect if flash + * needs to be erased. + * + * FIXME: that interface is crap + */ +struct mrc_data_container *find_next_mrc_cache(void) +{ + u32 entry_id = 0; + struct mrc_data_container *mrc_cache = NULL; + u32 region_size = get_mrc_cache_region(&mrc_cache); + void *mrc_region = (void*)mrc_cache; + + if (mrc_cache == NULL) { + printk(BIOS_ERR, "%s: could not find mrc cache area\n", __func__); + return NULL; + } + + /* Search for the first empty entry in the region */ + while (is_mrc_cache(mrc_cache)) { + entry_id++; + mrc_cache = next_mrc_block(mrc_cache); + /* If we exceed the defined area, move to front */ + if ((void*)mrc_cache >= (void*)(mrc_region + region_size)) { + mrc_cache = (struct mrc_data_container *)mrc_region; + break; + } + } + + printk(BIOS_DEBUG, "picked entry %u from cache block when looking for empty block\n", entry_id); + + return mrc_cache; +} + +struct mrc_data_container *find_current_mrc_cache(void) +{ + u32 entry_id = 0; + struct mrc_data_container *mrc_next, *mrc_cache = NULL; + u32 region_size = get_mrc_cache_region(&mrc_cache); + void *mrc_region = (void*)mrc_cache; + mrc_next = mrc_cache; + + if (mrc_cache == NULL) { + printk(BIOS_ERR, "%s: could not find mrc cache area\n", __func__); + return NULL; + } + + if (mrc_cache->mrc_data_size == -1UL) { + printk(BIOS_ERR, "%s: MRC cache not initialized?\n", __func__); + /* return non-initialized cache, so we can discern this + * from having no cache area at all + */ + return mrc_cache; + } else { + /* Search for the last filled entry in the region */ + while (is_mrc_cache(mrc_next)) { + entry_id++; + mrc_cache = mrc_next; + mrc_next = next_mrc_block(mrc_cache); + /* Stay in the mrcdata region defined in fdt */ + if ((void*)mrc_next >= (void*)(mrc_region + region_size)) + break; + } + entry_id--; + } + + /* Verify checksum */ + if (mrc_cache->mrc_checksum != + compute_ip_checksum(mrc_cache->mrc_data, + mrc_cache->mrc_data_size)) { + printk(BIOS_ERR, "%s: MRC cache checksum mismatch\n", __func__); + return NULL; + } + + printk(BIOS_DEBUG, "picked entry %u from cache block\n", entry_id); + + return mrc_cache; +} + +/* SPI code needs malloc/free. + * Also unknown if writing flash from XIP-flash code is a good idea + */ +#if !defined(__PRE_RAM__) +void update_mrc_cache(void) +{ + struct mrc_data_container *current = cbmem_find(CBMEM_ID_MRCDATA); + if (!current) { + printk(BIOS_ERR, "No MRC cache in cbmem. Can't update flash.\n"); + return; + } + if (current->mrc_data_size == -1) { + printk(BIOS_ERR, "MRC cache data in cbmem invalid.\n"); + return; + } + + /* + * we need to: + */ + // 0. compare MRC data to last mrc-cache block (exit if same) + struct mrc_data_container *cache; + if ((cache = find_current_mrc_cache()) == NULL) { + printk(BIOS_DEBUG, "Failure looking for current last block\n"); + return; + } + + if ((cache->mrc_data_size == current->mrc_data_size) && (memcmp(cache, current, cache->mrc_data_size) == 0)) { + printk(BIOS_DEBUG, "MRC data in flash is up to date. No update.\n"); + return; + } + + // 1. use spi_flash_probe() to find the flash, then + spi_init(); + struct spi_flash *flash = spi_flash_probe(0, 0, 1000000, SPI_MODE_3); + if (!flash) { + printk(BIOS_DEBUG, "Could not find SPI device\n"); + return; + } + + // 2. look up the first unused block + cache = find_next_mrc_cache(); + if (!cache) { + printk(BIOS_DEBUG, "Could not find MRC cache area\n"); + return; + } + + // 3. if no such place exists, erase entire mrc-cache range & use block 0 + if (cache->mrc_data_size != -1) { + printk(BIOS_DEBUG, "We need to erase the MRC cache region\n"); + flash->erase(flash, CONFIG_MRC_CACHE_LOCATION, CONFIG_MRC_CACHE_SIZE); + /* we know we can start at the beginning again */ + get_mrc_cache_region(&cache); + } + // 4. write mrc data with flash->write() + printk(BIOS_DEBUG, "Finally: write MRC cache update to flash\n"); + flash->write(flash, (u32)(((void*)cache)-CONFIG_MRC_CACHE_BASE), current->mrc_data_size + sizeof(*current), current); +} +#endif + diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 6548b32..0df86d6 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -36,9 +36,8 @@ #include "southbridge/intel/bd82x6x/me.h" #if CONFIG_CHROMEOS #include -#endif -#if 0 -#include +#else +#define recovery_mode_enabled(x) 0 #endif /* @@ -56,17 +55,6 @@ #define CMOS_OFFSET_MRC_SEED_CHK 120 #endif -#define MRC_DATA_ALIGN 0x1000 -#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24)) - -struct mrc_data_container { - u32 mrc_signature; // "MRCD" - u32 mrc_data_size; // Actual total size of this structure - u32 mrc_checksum; // IP style checksum - u32 reserved; // For header alignment - u8 mrc_data[0]; // Variable size, platform/run time dependent. -} __attribute__ ((packed)); - static void save_mrc_data(struct pei_data *pei_data) { u16 c1, c2, checksum; @@ -119,22 +107,10 @@ static void save_mrc_data(struct pei_data *pei_data) cmos_write((checksum >> 8) & 0xff, CMOS_OFFSET_MRC_SEED_CHK+1); } -#if CONFIG_CHROMEOS static void prepare_mrc_cache(struct pei_data *pei_data) { -#if 0 - const struct fdt_header *fdt_header; - const struct fdt_property *fdtp; - int offset, len; - const char *compatible = "chromeos,flashmap"; - const char *subnode = "rw-mrc-cache"; - const char *property = "reg"; - u32 *data; - struct mrc_data_container *mrc_cache, *mrc_next; - u8 *mrc_region, *region_ptr; + struct mrc_data_container *mrc_cache; u16 c1, c2, checksum, seed_checksum; - u32 region_size, entry_id = 0; - u64 flashrom_base = 0; // preset just in case there is an error pei_data->mrc_input = NULL; @@ -166,96 +142,18 @@ static void prepare_mrc_cache(struct pei_data *pei_data) return; } - fdt_header = cbfs_find_file(CONFIG_FDT_FILE_NAME, CBFS_TYPE_FDT); - - if (!fdt_header) { - printk(BIOS_ERR, "%s: no FDT found!\n", __func__); - return; - } - - offset = fdt_node_offset_by_compatible(fdt_header, 0, compatible); - if (offset < 0) { - printk(BIOS_ERR, "%s: no %s node found!\n", - __func__, compatible); - return; - } - - if (fdt_get_base_addr(fdt_header, offset, &flashrom_base) < 0) { - printk(BIOS_ERR, "%s: no base address in node name!\n", - __func__); - return; - } - - offset = fdt_subnode_offset(fdt_header, offset, subnode); - if (offset < 0) { - printk(BIOS_ERR, "%s: no %s found!\n", __func__, subnode); - return; - } - - fdtp = fdt_get_property(fdt_header, offset, property, &len); - if (!fdtp || (len != 8)) { - printk(BIOS_ERR, "%s: property %s at %p, len %d!\n", - __func__, property, fdtp, len); - return; - } - - data = (u32 *)fdtp->data; - - // Calculate actual address of the MRC cache in memory - region_size = fdt32_to_cpu(data[1]); - mrc_region = region_ptr = (u8*) - ((unsigned long)flashrom_base + fdt32_to_cpu(data[0])); - mrc_cache = mrc_next = (struct mrc_data_container *)mrc_region; - - if (!mrc_cache || mrc_cache->mrc_signature != MRC_DATA_SIGNATURE) { - printk(BIOS_ERR, "%s: invalid MRC data\n", __func__); - return; - } - - if (mrc_cache->mrc_data_size == -1UL) { - printk(BIOS_ERR, "%s: MRC cache not initialized?\n", __func__); - return; - } else { - /* MRC data blocks are aligned within the region */ - u32 mrc_size = sizeof(*mrc_cache) + mrc_cache->mrc_data_size; - if (mrc_size & (MRC_DATA_ALIGN - 1UL)) { - mrc_size &= ~(MRC_DATA_ALIGN - 1UL); - mrc_size += MRC_DATA_ALIGN; - } - - /* Search for the last filled entry in the region */ - while (mrc_next && - mrc_next->mrc_signature == MRC_DATA_SIGNATURE) { - entry_id++; - mrc_cache = mrc_next; - /* Stay in the mrcdata region defined in fdt */ - if ((entry_id * mrc_size) > region_size) - break; - region_ptr += mrc_size; - mrc_next = (struct mrc_data_container *)region_ptr; - } - entry_id--; - } - - /* Verify checksum */ - if (mrc_cache->mrc_checksum != - compute_ip_checksum(mrc_cache->mrc_data, - mrc_cache->mrc_data_size)) { - printk(BIOS_ERR, "%s: MRC cache checksum mismatch\n", __func__); + if ((mrc_cache = find_current_mrc_cache()) == NULL) { + /* error message printed in find_current_mrc_cache */ return; } pei_data->mrc_input = mrc_cache->mrc_data; pei_data->mrc_input_len = mrc_cache->mrc_data_size; - printk(BIOS_DEBUG, "%s: at %p, entry %u size %x checksum %04x\n", - __func__, pei_data->mrc_input, entry_id, + printk(BIOS_DEBUG, "%s: at %p, size %x checksum %04x\n", + __func__, pei_data->mrc_input, pei_data->mrc_input_len, mrc_cache->mrc_checksum); -#else - printk(BIOS_ERR, "MRC cache handling code has to be redone.\n"); -#endif } -#endif static const char* ecc_decoder[] = { "inactive", @@ -315,7 +213,6 @@ static void report_memory_config(void) void sdram_initialize(struct pei_data *pei_data) { struct sys_info sysinfo; - const char *target = "mrc.bin"; unsigned long entry; report_platform_info(); @@ -330,7 +227,6 @@ void sdram_initialize(struct pei_data *pei_data) sysinfo.boot_path = pei_data->boot_mode; -#if CONFIG_CHROMEOS /* * Do not pass MRC data in for recovery mode boot, * Always pass it in for S3 resume. @@ -344,17 +240,16 @@ void sdram_initialize(struct pei_data *pei_data) outb(0x6, 0xcf9); hlt(); } -#endif /* Locate and call UEFI System Agent binary. */ - entry = (unsigned long)cbfs_find_file(target, 0xab); + entry = (unsigned long)cbfs_find_file("mrc.bin", 0xab); if (entry) { int rv; asm volatile ( "call *%%ecx\n\t" :"=a" (rv) : "c" (entry), "a" (pei_data)); if (rv) { - printk(BIOS_ERR, "MRC returned %d\n", rv); + printk(BIOS_ERR, "MRC returned %x\n", rv); die("Nonzero MRC return value\n"); } } else { diff --git a/src/northbridge/intel/sandybridge/sandybridge.h b/src/northbridge/intel/sandybridge/sandybridge.h index aa62021..7e12416 100644 --- a/src/northbridge/intel/sandybridge/sandybridge.h +++ b/src/northbridge/intel/sandybridge/sandybridge.h @@ -221,6 +221,28 @@ void dump_spd_registers(void); void dump_mem(unsigned start, unsigned end); void report_platform_info(void); #endif /* !__SMM__ */ + + +#define MRC_DATA_ALIGN 0x1000 +#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24)) + +struct mrc_data_container { + u32 mrc_signature; // "MRCD" + u32 mrc_data_size; // Actual total size of this structure + u32 mrc_checksum; // IP style checksum + u32 reserved; // For header alignment + u8 mrc_data[0]; // Variable size, platform/run time dependent. +} __attribute__ ((packed)); + +struct mrc_data_container *next_mrc_block(struct mrc_data_container *mrc_cache); +int is_mrc_cache(struct mrc_data_container *mrc_cache); +u32 get_mrc_cache_region(struct mrc_data_container **mrc_region_ptr); +struct mrc_data_container *find_next_mrc_cache(void); +struct mrc_data_container *find_current_mrc_cache(void); +#if !defined(__PRE_RAM__) +void update_mrc_cache(void); +#endif + #endif #endif #endif From gerrit at coreboot.org Fri May 4 01:46:59 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Fri, 4 May 2012 01:46:59 +0200 Subject: [coreboot] New patch to review for coreboot: 3e4612f Hook up MRC cache update References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1002 -gerrit commit 3e4612f12abc040419971ac86f32ee7a5a39f75f Author: Stefan Reinauer Date: Thu May 3 16:40:41 2012 -0700 Hook up MRC cache update This one is a WIP: - should not depend on CONFIG_CHROMEOS - There might be a better place for it. Requirements: - must be in ramstage (locking flash while executing code from there might not work) - must be after cbmem is reinitialized (so the mrc cache copy of the current run can be found) Change-Id: I8028fb073349ce2b027ef5f8397dc1a1b8b31c02 Signed-off-by: Patrick Georgi --- src/arch/x86/boot/tables.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/src/arch/x86/boot/tables.c b/src/arch/x86/boot/tables.c index 4fefc7d..ff57422 100644 --- a/src/arch/x86/boot/tables.c +++ b/src/arch/x86/boot/tables.c @@ -53,6 +53,11 @@ struct lb_memory *write_tables(void) */ unsigned long high_table_pointer; +#if CONFIG_CHROMEOS + void update_mrc_cache(void); + update_mrc_cache(); +#endif + if (!high_tables_base) { printk(BIOS_ERR, "ERROR: High Tables Base is not set.\n"); // Are there any boards without? From gerrit at coreboot.org Fri May 4 01:46:59 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Fri, 4 May 2012 01:46:59 +0200 Subject: [coreboot] Patch set updated for coreboot: a0de089 Add SPI driver References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/997 -gerrit commit a0de089b0863f6b867e9d1fecc1298387c3d3d12 Author: Stefan Reinauer Date: Wed May 2 17:07:05 2012 -0700 Add SPI driver This driver is taken from u-boot and adapted to match coreboot. It still contains some hacks and is ICH specific at places. Change-Id: I97dd8096f7db3b62f8f4f4e4d08bdee10d88f689 Signed-off-by: Patrick Georgi --- src/drivers/Kconfig | 1 + src/drivers/Makefile.inc | 1 + src/drivers/spi/Kconfig | 24 + src/drivers/spi/Makefile.inc | 12 + src/drivers/spi/eon.c | 161 ++++++ src/drivers/spi/macronix.c | 220 +++++++++ src/drivers/spi/ramtron.c | 315 ++++++++++++ src/drivers/spi/spansion.c | 241 +++++++++ src/drivers/spi/spi_flash.c | 327 ++++++++++++ src/drivers/spi/spi_flash_internal.h | 81 +++ src/drivers/spi/sst.c | 268 ++++++++++ src/drivers/spi/stmicro.c | 250 ++++++++++ src/drivers/spi/winbond.c | 218 ++++++++ src/include/device/pci_ids.h | 4 + src/include/spi.h | 203 ++++++++ src/include/spi_flash.h | 91 ++++ src/northbridge/intel/sandybridge/raminit.c | 1 + src/southbridge/intel/bd82x6x/Kconfig | 1 + src/southbridge/intel/bd82x6x/Makefile.inc | 2 + src/southbridge/intel/bd82x6x/spi.c | 712 +++++++++++++++++++++++++++ 20 files changed, 3133 insertions(+), 0 deletions(-) diff --git a/src/drivers/Kconfig b/src/drivers/Kconfig index 259bc29..60e5b65 100644 --- a/src/drivers/Kconfig +++ b/src/drivers/Kconfig @@ -26,3 +26,4 @@ source src/drivers/oxford/Kconfig source src/drivers/sil/Kconfig source src/drivers/trident/Kconfig source src/drivers/ics/Kconfig +source src/drivers/spi/Kconfig diff --git a/src/drivers/Makefile.inc b/src/drivers/Makefile.inc index 5f6dadf..851a4df 100644 --- a/src/drivers/Makefile.inc +++ b/src/drivers/Makefile.inc @@ -26,4 +26,5 @@ subdirs-y += oxford subdirs-y += sil subdirs-y += trident subdirs-y += ics +subdirs-y += spi subdirs-$(CONFIG_ARCH_X86) += pc80 diff --git a/src/drivers/spi/Kconfig b/src/drivers/spi/Kconfig new file mode 100644 index 0000000..482881c --- /dev/null +++ b/src/drivers/spi/Kconfig @@ -0,0 +1,24 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2012 The Chromium OS Authors. +## +## 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; version 2 of the License. +## +## 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +config SPI + bool + help + Select this option if your chipset driver needs to store certain + data in the SPI flash. diff --git a/src/drivers/spi/Makefile.inc b/src/drivers/spi/Makefile.inc new file mode 100644 index 0000000..54239b9 --- /dev/null +++ b/src/drivers/spi/Makefile.inc @@ -0,0 +1,12 @@ +# SPI driver interface +ramstage-$(CONFIG_SPI) += spi_flash.c + +# drivers +ramstage-$(CONFIG_SPI) += eon.c +ramstage-$(CONFIG_SPI) += macronix.c +ramstage-$(CONFIG_SPI) += ramtron.c +ramstage-$(CONFIG_SPI) += spansion.c +ramstage-$(CONFIG_SPI) += sst.c +ramstage-$(CONFIG_SPI) += stmicro.c +ramstage-$(CONFIG_SPI) += winbond.c + diff --git a/src/drivers/spi/eon.c b/src/drivers/spi/eon.c new file mode 100644 index 0000000..a94dec1 --- /dev/null +++ b/src/drivers/spi/eon.c @@ -0,0 +1,161 @@ +/* + * (C) Copyright 2010, ucRobotics Inc. + * Author: Chong Huang + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* EN25Q128-specific commands */ +#define CMD_EN25Q128_WREN 0x06 /* Write Enable */ +#define CMD_EN25Q128_WRDI 0x04 /* Write Disable */ +#define CMD_EN25Q128_RDSR 0x05 /* Read Status Register */ +#define CMD_EN25Q128_WRSR 0x01 /* Write Status Register */ +#define CMD_EN25Q128_READ 0x03 /* Read Data Bytes */ +#define CMD_EN25Q128_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_EN25Q128_PP 0x02 /* Page Program */ +#define CMD_EN25Q128_SE 0x20 /* Sector Erase */ +#define CMD_EN25Q128_BE 0xd8 /* Block Erase */ +#define CMD_EN25Q128_DP 0xb9 /* Deep Power-down */ +#define CMD_EN25Q128_RES 0xab /* Release from DP, and Read Signature */ + +#define EON_ID_EN25Q128 0x18 + +struct eon_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 sectors_per_block; + u16 nr_sectors; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct eon_spi_flash { + struct spi_flash flash; + const struct eon_spi_flash_params *params; +}; + +static inline struct eon_spi_flash *to_eon_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct eon_spi_flash, flash); +} + +static const struct eon_spi_flash_params eon_spi_flash_table[] = { + { + .idcode1 = EON_ID_EN25Q128, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_sectors = 4096, + .name = "EN25Q128", + }, +}; + +static int eon_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct eon_spi_flash *eon = to_eon_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = eon->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_EN25Q128_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, + "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_EN25Q128_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: EON Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: EON: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int eon_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_EN25Q128_BE, offset, len); +} + +struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode) +{ + const struct eon_spi_flash_params *params; + struct eon_spi_flash *eon; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(eon_spi_flash_table); ++i) { + params = &eon_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(eon_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported EON ID %02x\n", idcode[1]); + return NULL; + } + + eon = malloc(sizeof(*eon)); + if (!eon) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + eon->params = params; + eon->flash.spi = spi; + eon->flash.name = params->name; + + eon->flash.write = eon_write; + eon->flash.erase = eon_erase; + eon->flash.read = spi_flash_cmd_read_fast; + eon->flash.sector_size = params->page_size * params->pages_per_sector + * params->sectors_per_block; + eon->flash.size = params->page_size * params->pages_per_sector + * params->nr_sectors; + + return &eon->flash; +} diff --git a/src/drivers/spi/macronix.c b/src/drivers/spi/macronix.c new file mode 100644 index 0000000..700a0a2 --- /dev/null +++ b/src/drivers/spi/macronix.c @@ -0,0 +1,220 @@ +/* + * Copyright 2009(C) Marvell International Ltd. and its affiliates + * Prafulla Wadaskar + * + * Based on drivers/mtd/spi/stmicro.c + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* MX25xx-specific commands */ +#define CMD_MX25XX_WREN 0x06 /* Write Enable */ +#define CMD_MX25XX_WRDI 0x04 /* Write Disable */ +#define CMD_MX25XX_RDSR 0x05 /* Read Status Register */ +#define CMD_MX25XX_WRSR 0x01 /* Write Status Register */ +#define CMD_MX25XX_READ 0x03 /* Read Data Bytes */ +#define CMD_MX25XX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_MX25XX_PP 0x02 /* Page Program */ +#define CMD_MX25XX_SE 0x20 /* Sector Erase */ +#define CMD_MX25XX_BE 0xD8 /* Block Erase */ +#define CMD_MX25XX_CE 0xc7 /* Chip Erase */ +#define CMD_MX25XX_DP 0xb9 /* Deep Power-down */ +#define CMD_MX25XX_RES 0xab /* Release from DP, and Read Signature */ + +#define MACRONIX_SR_WIP (1 << 0) /* Write-in-Progress */ + +struct macronix_spi_flash_params { + u16 idcode; + u16 page_size; + u16 pages_per_sector; + u16 sectors_per_block; + u16 nr_blocks; + const char *name; +}; + +struct macronix_spi_flash { + struct spi_flash flash; + const struct macronix_spi_flash_params *params; +}; + +static inline struct macronix_spi_flash *to_macronix_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct macronix_spi_flash, flash); +} + +static const struct macronix_spi_flash_params macronix_spi_flash_table[] = { + { + .idcode = 0x2015, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "MX25L1605D", + }, + { + .idcode = 0x2016, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "MX25L3205D", + }, + { + .idcode = 0x2017, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "MX25L6405D", + }, + { + .idcode = 0x2018, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "MX25L12805D", + }, + { + .idcode = 0x2618, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "MX25L12855E", + }, +}; + +static int macronix_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct macronix_spi_flash *mcx = to_macronix_spi_flash(flash); + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = min(mcx->params->page_size, CONTROLLER_PAGE_LIMIT); + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_MX25XX_PP; + cmd[1] = (offset >> 16) & 0xff; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_MX25XX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Macronix Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + offset += chunk_len; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: Macronix: Successfully programmed %zu bytes @ 0x%lx\n", + len, offset - len); + + spi_release_bus(flash->spi); + return ret; +} + +static int macronix_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_MX25XX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode) +{ + const struct macronix_spi_flash_params *params; + struct macronix_spi_flash *mcx; + unsigned int i; + u16 id = idcode[2] | idcode[1] << 8; + + for (i = 0; i < ARRAY_SIZE(macronix_spi_flash_table); i++) { + params = ¯onix_spi_flash_table[i]; + if (params->idcode == id) + break; + } + + if (i == ARRAY_SIZE(macronix_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported Macronix ID %04x\n", id); + return NULL; + } + + mcx = malloc(sizeof(*mcx)); + if (!mcx) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + mcx->params = params; + mcx->flash.spi = spi; + mcx->flash.name = params->name; + + mcx->flash.write = macronix_write; + mcx->flash.erase = macronix_erase; +#ifdef CONFIG_SPI_FLASH_NO_FAST_READ + mcx->flash.read = spi_flash_cmd_read_slow; +#else + mcx->flash.read = spi_flash_cmd_read_fast; +#endif + mcx->flash.sector_size = params->page_size * params->pages_per_sector; + mcx->flash.size = mcx->flash.sector_size * params->sectors_per_block * + params->nr_blocks; + + return &mcx->flash; +} diff --git a/src/drivers/spi/ramtron.c b/src/drivers/spi/ramtron.c new file mode 100644 index 0000000..d599cd9 --- /dev/null +++ b/src/drivers/spi/ramtron.c @@ -0,0 +1,315 @@ +/* + * (C) Copyright 2010 + * Reinhard Meyer, EMK Elektronik, reinhard.meyer at emk-elektronik.de + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Note: RAMTRON SPI FRAMs are ferroelectric, nonvolatile RAMs + * with an interface identical to SPI flash devices. + * However since they behave like RAM there are no delays or + * busy polls required. They can sustain read or write at the + * allowed SPI bus speed, which can be 40 MHz for some devices. + * + * Unfortunately some RAMTRON devices do not have a means of + * identifying them. They will leave the SO line undriven when + * the READ-ID command is issued. It is therefore mandatory + * that the MISO line has a proper pull-up, so that READ-ID + * will return a row of 0xff. This 0xff pseudo-id will cause + * probes by all vendor specific functions that are designed + * to handle it. If the MISO line is not pulled up, READ-ID + * could return any random noise, even mimicking another + * device. + * + * We use CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + * to define which device will be assumed after a simple status + * register verify. This method is prone to false positive + * detection and should therefore be the last to be tried. + * Enter it in the last position in the table in spi_flash.c! + * + * The define CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC both activates + * compilation of the special handler and defines the device + * to assume. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* RAMTRON commands common to all devices */ +#define CMD_RAMTRON_WREN 0x06 /* Write Enable */ +#define CMD_RAMTRON_WRDI 0x04 /* Write Disable */ +#define CMD_RAMTRON_RDSR 0x05 /* Read Status Register */ +#define CMD_RAMTRON_WRSR 0x01 /* Write Status Register */ +#define CMD_RAMTRON_READ 0x03 /* Read Data Bytes */ +#define CMD_RAMTRON_WRITE 0x02 /* Write Data Bytes */ +/* not all have those: */ +#define CMD_RAMTRON_FSTRD 0x0b /* Fast Read (for compatibility - not used here) */ +#define CMD_RAMTRON_SLEEP 0xb9 /* Enter Sleep Mode */ +#define CMD_RAMTRON_RDID 0x9f /* Read ID */ +#define CMD_RAMTRON_SNR 0xc3 /* Read Serial Number */ + +/* + * Properties of supported FRAMs + * Note: speed is currently not used because we have no method to deliver that + * value to the upper layers + */ +struct ramtron_spi_fram_params { + u32 size; /* size in bytes */ + u8 addr_len; /* number of address bytes */ + u8 merge_cmd; /* some address bits are in the command byte */ + u8 id1; /* device ID 1 (family, density) */ + u8 id2; /* device ID 2 (sub, rev, rsvd) */ + u32 speed; /* max. SPI clock in Hz */ + const char *name; /* name for display and/or matching */ +}; + +struct ramtron_spi_fram { + struct spi_flash flash; + const struct ramtron_spi_fram_params *params; +}; + +static inline struct ramtron_spi_fram *to_ramtron_spi_fram(struct spi_flash + *flash) +{ + return container_of(flash, struct ramtron_spi_fram, flash); +} + +/* + * table describing supported FRAM chips: + * chips without RDID command must have the values 0xff for id1 and id2 + */ +static const struct ramtron_spi_fram_params ramtron_spi_fram_table[] = { + { + .size = 32*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x22, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V02", + }, + { + .size = 32*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x22, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN02", + }, + { + .size = 64*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x23, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V05", + }, + { + .size = 64*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x23, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN05", + }, + { + .size = 128*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0x24, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V10", + }, + { + .size = 128*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0x24, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN10", + }, +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + { + .size = 256*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0xff, + .id2 = 0xff, + .speed = 40000000, + .name = "FM25H20", + }, +#endif +}; + +static int ramtron_common(struct spi_flash *flash, + u32 offset, size_t len, void *buf, u8 command) +{ + struct ramtron_spi_fram *sn = to_ramtron_spi_fram(flash); + u8 cmd[4]; + int cmd_len; + int ret; + + if (sn->params->addr_len == 3 && sn->params->merge_cmd == 0) { + cmd[0] = command; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + cmd_len = 4; + } else if (sn->params->addr_len == 2 && sn->params->merge_cmd == 0) { + cmd[0] = command; + cmd[1] = offset >> 8; + cmd[2] = offset; + cmd_len = 3; + } else { + printk(BIOS_SPEW, "SF: unsupported addr_len or merge_cmd\n"); + return -1; + } + + /* claim the bus */ + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + if (command == CMD_RAMTRON_WRITE) { + /* send WREN */ + ret = spi_flash_cmd(flash->spi, CMD_RAMTRON_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + goto releasebus; + } + } + + /* do the transaction */ + if (command == CMD_RAMTRON_WRITE) + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, buf, len); + else + ret = spi_flash_cmd_read(flash->spi, cmd, cmd_len, buf, len); + if (ret < 0) + printk(BIOS_SPEW, "SF: Transaction failed\n"); + +releasebus: + /* release the bus */ + spi_release_bus(flash->spi); + return ret; +} + +static int ramtron_read(struct spi_flash *flash, + u32 offset, size_t len, void *buf) +{ + return ramtron_common(flash, offset, len, buf, + CMD_RAMTRON_READ); +} + +static int ramtron_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + return ramtron_common(flash, offset, len, (void *)buf, + CMD_RAMTRON_WRITE); +} + +static int ramtron_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + printk(BIOS_SPEW, "SF: Erase of RAMTRON FRAMs is pointless\n"); + return -1; +} + +/* + * nore: we are called here with idcode pointing to the first non-0x7f byte + * already! + */ +struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode) +{ + const struct ramtron_spi_fram_params *params; + struct ramtron_spi_fram *sn; + unsigned int i; +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + int ret; + u8 sr; +#endif + + /* NOTE: the bus has been claimed before this function is called! */ + switch (idcode[0]) { + case 0xc2: + /* JEDEC conformant RAMTRON id */ + for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) { + params = &ramtron_spi_fram_table[i]; + if (idcode[1] == params->id1 && idcode[2] == params->id2) + goto found; + } + break; +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + case 0xff: + /* + * probably open MISO line, pulled up. + * We COULD have a non JEDEC conformant FRAM here, + * read the status register to verify + */ + ret = spi_flash_cmd(spi, CMD_RAMTRON_RDSR, &sr, 1); + if (ret) + return NULL; + + /* Bits 5,4,0 are fixed 0 for all devices */ + if ((sr & 0x31) != 0x00) + return NULL; + /* now find the device */ + for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) { + params = &ramtron_spi_fram_table[i]; + if (!strcmp(params->name, CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC)) + goto found; + } + printk(BIOS_SPEW, "SF: Unsupported non-JEDEC RAMTRON device " + CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC "\n"); + break; +#endif + default: + break; + } + + /* arriving here means no method has found a device we can handle */ + printk(BIOS_SPEW, "SF/ramtron: unsupported device id0=%02x id1=%02x id2=%02x\n", + idcode[0], idcode[1], idcode[2]); + return NULL; + +found: + sn = malloc(sizeof(*sn)); + if (!sn) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + sn->params = params; + sn->flash.spi = spi; + sn->flash.name = params->name; + + sn->flash.write = ramtron_write; + sn->flash.read = ramtron_read; + sn->flash.erase = ramtron_erase; + sn->flash.size = params->size; + + return &sn->flash; +} diff --git a/src/drivers/spi/spansion.c b/src/drivers/spi/spansion.c new file mode 100644 index 0000000..719a8a8 --- /dev/null +++ b/src/drivers/spi/spansion.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2009 Freescale Semiconductor, Inc. + * + * Author: Mingkai Hu (Mingkai.hu at freescale.com) + * Based on stmicro.c by Wolfgang Denk (wd at denx.de), + * TsiChung Liew (Tsi-Chung.Liew at freescale.com), + * and Jason McMullan (mcmullan at netapp.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* S25FLxx-specific commands */ +#define CMD_S25FLXX_READ 0x03 /* Read Data Bytes */ +#define CMD_S25FLXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_S25FLXX_READID 0x90 /* Read Manufacture ID and Device ID */ +#define CMD_S25FLXX_WREN 0x06 /* Write Enable */ +#define CMD_S25FLXX_WRDI 0x04 /* Write Disable */ +#define CMD_S25FLXX_RDSR 0x05 /* Read Status Register */ +#define CMD_S25FLXX_WRSR 0x01 /* Write Status Register */ +#define CMD_S25FLXX_PP 0x02 /* Page Program */ +#define CMD_S25FLXX_SE 0xd8 /* Sector Erase */ +#define CMD_S25FLXX_BE 0xc7 /* Bulk Erase */ +#define CMD_S25FLXX_DP 0xb9 /* Deep Power-down */ +#define CMD_S25FLXX_RES 0xab /* Release from DP, and Read Signature */ + +#define SPSN_ID_S25FL008A 0x0213 +#define SPSN_ID_S25FL016A 0x0214 +#define SPSN_ID_S25FL032A 0x0215 +#define SPSN_ID_S25FL064A 0x0216 +#define SPSN_ID_S25FL128P 0x2018 +#define SPSN_EXT_ID_S25FL128P_256KB 0x0300 +#define SPSN_EXT_ID_S25FL128P_64KB 0x0301 +#define SPSN_EXT_ID_S25FL032P 0x4d00 + +struct spansion_spi_flash_params { + u16 idcode1; + u16 idcode2; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +struct spansion_spi_flash { + struct spi_flash flash; + const struct spansion_spi_flash_params *params; +}; + +static inline struct spansion_spi_flash *to_spansion_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct spansion_spi_flash, flash); +} + +static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { + { + .idcode1 = SPSN_ID_S25FL008A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "S25FL008A", + }, + { + .idcode1 = SPSN_ID_S25FL016A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "S25FL016A", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032A", + }, + { + .idcode1 = SPSN_ID_S25FL064A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "S25FL064A", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_64KB, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 256, + .name = "S25FL128P_64K", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_256KB, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "S25FL128P_256K", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = SPSN_EXT_ID_S25FL032P, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032P", + }, +}; + +static int spansion_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct spansion_spi_flash *spsn = to_spansion_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = spsn->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_S25FLXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_S25FLXX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: SPANSION Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: SPANSION: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int spansion_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_S25FLXX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) +{ + const struct spansion_spi_flash_params *params; + struct spansion_spi_flash *spsn; + unsigned int i; + unsigned short jedec, ext_jedec; + + jedec = idcode[1] << 8 | idcode[2]; + ext_jedec = idcode[3] << 8 | idcode[4]; + + for (i = 0; i < ARRAY_SIZE(spansion_spi_flash_table); i++) { + params = &spansion_spi_flash_table[i]; + if (params->idcode1 == jedec) { + if (params->idcode2 == ext_jedec) + break; + } + } + + if (i == ARRAY_SIZE(spansion_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported SPANSION ID %04x %04x\n", jedec, ext_jedec); + return NULL; + } + + spsn = malloc(sizeof(struct spansion_spi_flash)); + if (!spsn) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + spsn->params = params; + spsn->flash.spi = spi; + spsn->flash.name = params->name; + + spsn->flash.write = spansion_write; + spsn->flash.erase = spansion_erase; + spsn->flash.read = spi_flash_cmd_read_fast; + spsn->flash.sector_size = params->page_size * params->pages_per_sector; + spsn->flash.size = spsn->flash.sector_size * params->nr_sectors; + + return &spsn->flash; +} diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c new file mode 100644 index 0000000..378f142 --- /dev/null +++ b/src/drivers/spi/spi_flash.c @@ -0,0 +1,327 @@ +/* + * SPI flash interface + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include "spi_flash_internal.h" + +#define CONFIG_SPI_FLASH_EON +#define CONFIG_SPI_FLASH_MACRONIX +#define CONFIG_SPI_FLASH_SPANSION +#define CONFIG_SPI_FLASH_SST +#define CONFIG_SPI_FLASH_STMICRO +#define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_SPI_FLASH_RAMTRON + +static void spi_flash_addr(u32 addr, u8 *cmd) +{ + /* cmd[0] is actual command */ + cmd[1] = addr >> 16; + cmd[2] = addr >> 8; + cmd[3] = addr >> 0; +} + +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) +{ + int ret = spi_xfer(spi, &cmd, 8, response, len * 8); + if (ret) + printk(BIOS_SPEW, "SF: Failed to send command %02x: %d\n", cmd, ret); + + return ret; +} + +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + int ret = spi_xfer(spi, cmd, cmd_len * 8, data, data_len * 8); + if (ret) { + printk(BIOS_SPEW, "SF: Failed to send read command (%zu bytes): %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len) +{ + int ret; + u8 buff[cmd_len + data_len]; + memcpy(buff, cmd, cmd_len); + memcpy(buff + cmd_len, data, data_len); + + ret = spi_xfer(spi, buff, (cmd_len + data_len) * 8, NULL, 0); + if (ret) { + printk(BIOS_SPEW, "SF: Failed to send write command (%zu bytes): %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + struct spi_slave *spi = flash->spi; + int ret; + + spi_claim_bus(spi); + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + spi_release_bus(spi); + + return ret; +} + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[5]; + + cmd[0] = CMD_READ_ARRAY_FAST; + spi_flash_addr(offset, cmd); + cmd[4] = 0x00; + + return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); +} + +int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[4]; + + cmd[0] = CMD_READ_ARRAY_SLOW; + spi_flash_addr(offset, cmd); + + return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); +} + +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 status; + + timebase = timeout; + do { + ret = spi_flash_cmd_read(spi, &cmd, 1, &status, 1); + if (ret) + return -1; + + if ((status & poll_bit) == 0) + break; + + mdelay(1); + } while (timebase--); + + if ((status & poll_bit) == 0) + return 0; + + /* Timed out */ + printk(BIOS_SPEW, "SF: time out!\n"); + return -1; +} + +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + return spi_flash_cmd_poll_bit(flash, timeout, + CMD_READ_STATUS, STATUS_WIP); +} + +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 offset, size_t len) +{ + u32 start, end, erase_size; + int ret; + u8 cmd[4]; + + erase_size = flash->sector_size; + if (offset % erase_size || len % erase_size) { + printk(BIOS_SPEW, "SF: Erase offset/length not multiple of erase size\n"); + return -1; + } + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + cmd[0] = erase_cmd; + start = offset; + end = start + len; + + while (offset < end) { + spi_flash_addr(offset, cmd); + offset += erase_size; + + printk(BIOS_SPEW, "SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) + goto out; + } + + printk(BIOS_SPEW, "SF: Successfully erased %zu bytes @ %#x\n", len, start); + + out: + spi_release_bus(flash->spi); + return ret; +} + +/* + * The following table holds all device probe functions + * + * shift: number of continuation bytes before the ID + * idcode: the expected IDCODE or 0xff for non JEDEC devices + * probe: the function to call + * + * Non JEDEC devices should be ordered in the table such that + * the probe functions with best detection algorithms come first. + * + * Several matching entries are permitted, they will be tried + * in sequence until a probe function returns non NULL. + * + * IDCODE_CONT_LEN may be redefined if a device needs to declare a + * larger "shift" value. IDCODE_PART_LEN generally shouldn't be + * changed. This is the max number of bytes probe functions may + * examine when looking up part-specific identification info. + * + * Probe functions will be given the idcode buffer starting at their + * manu id byte (the "idcode" in the table below). In other words, + * all of the continuation bytes will be skipped (the "shift" below). + */ +#define IDCODE_CONT_LEN 0 +#define IDCODE_PART_LEN 5 +static const struct { + const u8 shift; + const u8 idcode; + struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); +} flashes[] = { + /* Keep it sorted by define name */ +#ifdef CONFIG_SPI_FLASH_ATMEL + { 0, 0x1f, spi_flash_probe_atmel, }, +#endif +#ifdef CONFIG_SPI_FLASH_EON + { 0, 0x1c, spi_flash_probe_eon, }, +#endif +#ifdef CONFIG_SPI_FLASH_MACRONIX + { 0, 0xc2, spi_flash_probe_macronix, }, +#endif +#ifdef CONFIG_SPI_FLASH_SPANSION + { 0, 0x01, spi_flash_probe_spansion, }, +#endif +#ifdef CONFIG_SPI_FLASH_SST + { 0, 0xbf, spi_flash_probe_sst, }, +#endif +#ifdef CONFIG_SPI_FLASH_STMICRO + { 0, 0x20, spi_flash_probe_stmicro, }, +#endif +#ifdef CONFIG_SPI_FLASH_WINBOND + { 0, 0xef, spi_flash_probe_winbond, }, +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON + { 6, 0xc2, spi_fram_probe_ramtron, }, +# undef IDCODE_CONT_LEN +# define IDCODE_CONT_LEN 6 +#endif + /* Keep it sorted by best detection */ +#ifdef CONFIG_SPI_FLASH_STMICRO + { 0, 0xff, spi_flash_probe_stmicro, }, +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + { 0, 0xff, spi_fram_probe_ramtron, }, +#endif +}; +#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_slave *spi; + struct spi_flash *flash = NULL; + int ret, i, shift; + u8 idcode[IDCODE_LEN], *idp; + + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); + if (!spi) { + printk(BIOS_SPEW, "SF: Failed to set up slave\n"); + return NULL; + } + + ret = spi_claim_bus(spi); + if (ret) { + printk(BIOS_SPEW, "SF: Failed to claim SPI bus: %d\n", ret); + goto err_claim_bus; + } + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); + if (ret) + goto err_read_id; + +#ifdef DEBUG + printk(BIOS_SPEW, "SF: Got idcodes\n"); + print_buffer(0, idcode, 1, sizeof(idcode), 0); +#endif + + /* count the number of continuation bytes */ + for (shift = 0, idp = idcode; + shift < IDCODE_CONT_LEN && *idp == 0x7f; + ++shift, ++idp) + continue; + + /* search the table for matches in shift and id */ + for (i = 0; i < ARRAY_SIZE(flashes); ++i) + if (flashes[i].shift == shift && flashes[i].idcode == *idp) { + /* we have a match, call probe */ + flash = flashes[i].probe(spi, idp); + if (flash) + break; + } + + if (!flash) { + printk(BIOS_SPEW, "SF: Unsupported manufacturer %02x\n", *idp); + goto err_manufacturer_probe; + } + + printk(BIOS_SPEW, "SF: Detected %s with page size %x, total %x\n", flash->name, flash->sector_size, flash->size); + + spi_release_bus(spi); + + return flash; + +err_manufacturer_probe: +err_read_id: + spi_release_bus(spi); +err_claim_bus: + spi_free_slave(spi); + return NULL; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_free_slave(flash->spi); + free(flash); +} diff --git a/src/drivers/spi/spi_flash_internal.h b/src/drivers/spi/spi_flash_internal.h new file mode 100644 index 0000000..b895e2b --- /dev/null +++ b/src/drivers/spi/spi_flash_internal.h @@ -0,0 +1,81 @@ +/* + * SPI flash internal definitions + * + * Copyright (C) 2008 Atmel Corporation + */ + +/* Common parameters -- kind of high, but they should only occur when there + * is a problem (and well your system already is broken), so err on the side + * of caution in case we're dealing with slower SPI buses and/or processors. + */ +#define CONFIG_SYS_HZ 100 +#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) +#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) +#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) + +/* Common commands */ +#define CMD_READ_ID 0x9f + +#define CMD_READ_ARRAY_SLOW 0x03 +#define CMD_READ_ARRAY_FAST 0x0b +#define CMD_READ_ARRAY_LEGACY 0xe8 + +#define CMD_READ_STATUS 0x05 +#define CMD_WRITE_ENABLE 0x06 + +/* Common status */ +#define STATUS_WIP 0x01 + +/* Send a single-byte command to the device and read the response */ +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); + +/* + * Send a multi-byte command to the device and read the response. Used + * for flash array reads, etc. + */ +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +/* + * Send a multi-byte command to the device followed by (optional) + * data. Used for programming the flash array, etc. + */ +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len); + +/* + * Same as spi_flash_cmd_read() except it also claims/releases the SPI + * bus. Used as common part of the ->read() operation. + */ +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* Send a command to the device and wait for some bit to clear itself. */ +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit); + +/* + * Send the read status command to the device and wait for the wip + * (write-in-progress) bit to clear itself. + */ +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); + +/* Erase sectors. */ +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 offset, size_t len); + +/* Manufacturer-specific probe functions */ +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode); diff --git a/src/drivers/spi/sst.c b/src/drivers/spi/sst.c new file mode 100644 index 0000000..9c87dae --- /dev/null +++ b/src/drivers/spi/sst.c @@ -0,0 +1,268 @@ +/* + * Driver for SST serial flashes + * + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd at denx.de. + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +#define CMD_SST_WREN 0x06 /* Write Enable */ +#define CMD_SST_WRDI 0x04 /* Write Disable */ +#define CMD_SST_RDSR 0x05 /* Read Status Register */ +#define CMD_SST_WRSR 0x01 /* Write Status Register */ +#define CMD_SST_READ 0x03 /* Read Data Bytes */ +#define CMD_SST_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_SST_BP 0x02 /* Byte Program */ +#define CMD_SST_AAI_WP 0xAD /* Auto Address Increment Word Program */ +#define CMD_SST_SE 0x20 /* Sector Erase */ + +#define SST_SR_WIP (1 << 0) /* Write-in-Progress */ +#define SST_SR_WEL (1 << 1) /* Write enable */ +#define SST_SR_BP0 (1 << 2) /* Block Protection 0 */ +#define SST_SR_BP1 (1 << 3) /* Block Protection 1 */ +#define SST_SR_BP2 (1 << 4) /* Block Protection 2 */ +#define SST_SR_AAI (1 << 6) /* Addressing mode */ +#define SST_SR_BPL (1 << 7) /* BP bits lock */ + +struct sst_spi_flash_params { + u8 idcode1; + u16 nr_sectors; + const char *name; +}; + +struct sst_spi_flash { + struct spi_flash flash; + const struct sst_spi_flash_params *params; +}; + +static inline struct sst_spi_flash *to_sst_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct sst_spi_flash, flash); +} + +#define SST_SECTOR_SIZE (4 * 1024) +static const struct sst_spi_flash_params sst_spi_flash_table[] = { + { + .idcode1 = 0x8d, + .nr_sectors = 128, + .name = "SST25VF040B", + },{ + .idcode1 = 0x8e, + .nr_sectors = 256, + .name = "SST25VF080B", + },{ + .idcode1 = 0x41, + .nr_sectors = 512, + .name = "SST25VF016B", + },{ + .idcode1 = 0x4a, + .nr_sectors = 1024, + .name = "SST25VF032B", + },{ + .idcode1 = 0x4b, + .nr_sectors = 2048, + .name = "SST25VF064C", + },{ + .idcode1 = 0x01, + .nr_sectors = 16, + .name = "SST25WF512", + },{ + .idcode1 = 0x02, + .nr_sectors = 32, + .name = "SST25WF010", + },{ + .idcode1 = 0x03, + .nr_sectors = 64, + .name = "SST25WF020", + },{ + .idcode1 = 0x04, + .nr_sectors = 128, + .name = "SST25WF040", + }, +}; + +static int +sst_enable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WREN, NULL, 0); + if (ret) + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + return ret; +} + +static int +sst_disable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WRDI, NULL, 0); + if (ret) + printk(BIOS_SPEW, "SF: Disabling Write failed\n"); + return ret; +} + +static int +sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) +{ + int ret; + u8 cmd[4] = { + CMD_SST_BP, + offset >> 16, + offset >> 8, + offset, + }; + + printk(BIOS_SPEW, "BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf, cmd[0], offset); + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); + if (ret) + return ret; + + return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); +} + +static int +sst_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) +{ + size_t actual, cmd_len; + int ret; + u8 cmd[4]; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + /* If the data is not word aligned, write out leading single byte */ + actual = offset % 2; + if (actual) { + ret = sst_byte_write(flash, offset, buf); + if (ret) + goto done; + } + offset += actual; + + ret = sst_enable_writing(flash); + if (ret) + goto done; + + cmd_len = 4; + cmd[0] = CMD_SST_AAI_WP; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + + for (; actual < len - 1; actual += 2) { + printk(BIOS_SPEW, "WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf + actual, cmd[0], + offset); + + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, + buf + actual, 2); + if (ret) { + printk(BIOS_SPEW, "SF: sst word program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + cmd_len = 1; + offset += 2; + } + + if (!ret) + ret = sst_disable_writing(flash); + + /* If there is a single trailing byte, write it out */ + if (!ret && actual != len) + ret = sst_byte_write(flash, offset, buf + actual); + + done: + printk(BIOS_SPEW, "SF: sst: program %s %zu bytes @ 0x%lx\n", + ret ? "failure" : "success", len, offset - actual); + + spi_release_bus(flash->spi); + return ret; +} + +static int sst_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_SST_SE, offset, len); +} + +static int +sst_unlock(struct spi_flash *flash) +{ + int ret; + u8 cmd, status; + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + cmd = CMD_SST_WRSR; + status = 0; + ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &status, 1); + if (ret) + printk(BIOS_SPEW, "SF: Unable to set status byte\n"); + + printk(BIOS_SPEW, "SF: sst: status = %x\n", spi_w8r8(flash->spi, CMD_SST_RDSR)); + + return ret; +} + +struct spi_flash * +spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode) +{ + const struct sst_spi_flash_params *params; + struct sst_spi_flash *stm; + size_t i; + + for (i = 0; i < ARRAY_SIZE(sst_spi_flash_table); ++i) { + params = &sst_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(sst_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported SST ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(*stm)); + if (!stm) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = sst_write; + stm->flash.erase = sst_erase; + stm->flash.read = spi_flash_cmd_read_fast; + stm->flash.sector_size = SST_SECTOR_SIZE; + stm->flash.size = stm->flash.sector_size * params->nr_sectors; + + /* Flash powers up read-only, so clear BP# bits */ + sst_unlock(&stm->flash); + + return &stm->flash; +} diff --git a/src/drivers/spi/stmicro.c b/src/drivers/spi/stmicro.c new file mode 100644 index 0000000..370d15a --- /dev/null +++ b/src/drivers/spi/stmicro.c @@ -0,0 +1,250 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd at denx.de. + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_M25PXX_WREN 0x06 /* Write Enable */ +#define CMD_M25PXX_WRDI 0x04 /* Write Disable */ +#define CMD_M25PXX_RDSR 0x05 /* Read Status Register */ +#define CMD_M25PXX_WRSR 0x01 /* Write Status Register */ +#define CMD_M25PXX_READ 0x03 /* Read Data Bytes */ +#define CMD_M25PXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_M25PXX_PP 0x02 /* Page Program */ +#define CMD_M25PXX_SE 0xd8 /* Sector Erase */ +#define CMD_M25PXX_BE 0xc7 /* Bulk Erase */ +#define CMD_M25PXX_DP 0xb9 /* Deep Power-down */ +#define CMD_M25PXX_RES 0xab /* Release from DP, and Read Signature */ + +#define STM_ID_M25P10 0x11 +#define STM_ID_M25P16 0x15 +#define STM_ID_M25P20 0x12 +#define STM_ID_M25P32 0x16 +#define STM_ID_M25P40 0x13 +#define STM_ID_M25P64 0x17 +#define STM_ID_M25P80 0x14 +#define STM_ID_M25P128 0x18 + +struct stmicro_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct stmicro_spi_flash { + struct spi_flash flash; + const struct stmicro_spi_flash_params *params; +}; + +static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct stmicro_spi_flash, flash); +} + +static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { + { + .idcode1 = STM_ID_M25P10, + .page_size = 256, + .pages_per_sector = 128, + .nr_sectors = 4, + .name = "M25P10", + }, + { + .idcode1 = STM_ID_M25P16, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "M25P16", + }, + { + .idcode1 = STM_ID_M25P20, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 4, + .name = "M25P20", + }, + { + .idcode1 = STM_ID_M25P32, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "M25P32", + }, + { + .idcode1 = STM_ID_M25P40, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 8, + .name = "M25P40", + }, + { + .idcode1 = STM_ID_M25P64, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "M25P64", + }, + { + .idcode1 = STM_ID_M25P80, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "M25P80", + }, + { + .idcode1 = STM_ID_M25P128, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "M25P128", + }, +}; + +static int stmicro_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = stm->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_M25PXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: STMicro Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: STMicro: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_M25PXX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) +{ + const struct stmicro_spi_flash_params *params; + struct stmicro_spi_flash *stm; + unsigned int i; + + if (idcode[0] == 0xff) { + i = spi_flash_cmd(spi, CMD_M25PXX_RES, + idcode, 4); + if (i) + return NULL; + if ((idcode[3] & 0xf0) == 0x10) { + idcode[0] = 0x20; + idcode[1] = 0x20; + idcode[2] = idcode[3] + 1; + } else + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) { + params = &stmicro_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) { + break; + } + } + + if (i == ARRAY_SIZE(stmicro_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported STMicro ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(struct stmicro_spi_flash)); + if (!stm) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = stmicro_write; + stm->flash.erase = stmicro_erase; + stm->flash.read = spi_flash_cmd_read_fast; + stm->flash.sector_size = params->page_size * params->pages_per_sector; + stm->flash.size = stm->flash.sector_size * params->nr_sectors; + + return &stm->flash; +} diff --git a/src/drivers/spi/winbond.c b/src/drivers/spi/winbond.c new file mode 100644 index 0000000..4329c55 --- /dev/null +++ b/src/drivers/spi/winbond.c @@ -0,0 +1,218 @@ +/* + * Copyright 2008, Network Appliance Inc. + * Author: Jason McMullan netapp.com> + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_W25_WREN 0x06 /* Write Enable */ +#define CMD_W25_WRDI 0x04 /* Write Disable */ +#define CMD_W25_RDSR 0x05 /* Read Status Register */ +#define CMD_W25_WRSR 0x01 /* Write Status Register */ +#define CMD_W25_READ 0x03 /* Read Data Bytes */ +#define CMD_W25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_W25_PP 0x02 /* Page Program */ +#define CMD_W25_SE 0x20 /* Sector (4K) Erase */ +#define CMD_W25_BE 0xd8 /* Block (64K) Erase */ +#define CMD_W25_CE 0xc7 /* Chip Erase */ +#define CMD_W25_DP 0xb9 /* Deep Power-down */ +#define CMD_W25_RES 0xab /* Release from DP, and Read Signature */ + +struct winbond_spi_flash_params { + uint16_t id; + /* Log2 of page size in power-of-two mode */ + uint8_t l2_page_size; + uint16_t pages_per_sector; + uint16_t sectors_per_block; + uint16_t nr_blocks; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct winbond_spi_flash { + struct spi_flash flash; + const struct winbond_spi_flash_params *params; +}; + +static inline struct winbond_spi_flash * +to_winbond_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct winbond_spi_flash, flash); +} + +static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { + { + .id = 0x3015, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "W25X16", + }, + { + .id = 0x3016, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "W25X32", + }, + { + .id = 0x3017, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "W25X64", + }, + { + .id = 0x4015, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "W25Q16", + }, + { + .id = 0x4016, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "W25Q32", + }, + { + .id = 0x4017, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "W25Q64", + }, + { + .id = 0x4018, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "W25Q128", + }, +}; + +static int winbond_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct winbond_spi_flash *stm = to_winbond_spi_flash(flash); + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT); + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_SPEW, "SF: Unable to claim SPI bus\n"); + return ret; + } + + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_W25_PP; + cmd[1] = (offset >> 16) & 0xff; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %ld\n", + buf + actual, + cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_W25_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Enabling Write failed\n"); + goto out; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_SPEW, "SF: Winbond Page Program failed\n"); + goto out; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + goto out; + + offset += chunk_len; + byte_addr = 0; + } + + printk(BIOS_SPEW, "SF: Winbond: Successfully programmed %zu bytes @ 0x%lx\n", + len, offset - len); + ret = 0; + +out: + spi_release_bus(flash->spi); + return ret; +} + +static int winbond_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_W25_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) +{ + const struct winbond_spi_flash_params *params; + unsigned page_size; + struct winbond_spi_flash *stm; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(winbond_spi_flash_table); i++) { + params = &winbond_spi_flash_table[i]; + if (params->id == ((idcode[1] << 8) | idcode[2])) + break; + } + + if (i == ARRAY_SIZE(winbond_spi_flash_table)) { + printk(BIOS_SPEW, "SF: Unsupported Winbond ID %02x%02x\n", + idcode[1], idcode[2]); + return NULL; + } + + stm = malloc(sizeof(struct winbond_spi_flash)); + if (!stm) { + printk(BIOS_SPEW, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + /* Assuming power-of-two page size initially. */ + page_size = 1 << params->l2_page_size; + + stm->flash.write = winbond_write; + stm->flash.erase = winbond_erase; +#ifdef CONFIG_SPI_FLASH_NO_FAST_READ + stm->flash.read = spi_flash_cmd_read_slow; +#else + stm->flash.read = spi_flash_cmd_read_fast; +#endif + stm->flash.sector_size = (1 << stm->params->l2_page_size) * + stm->params->pages_per_sector; + stm->flash.size = page_size * params->pages_per_sector + * params->sectors_per_block + * params->nr_blocks; + + return &stm->flash; +} diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h index a2d6884..1765293 100644 --- a/src/include/device/pci_ids.h +++ b/src/include/device/pci_ids.h @@ -2502,6 +2502,10 @@ #define PCI_DEVICE_ID_INTEL_82801IO_LPC 0x2914 #define PCI_DEVICE_ID_INTEL_82801IH_LPC 0x2912 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f +#define PCI_DEVICE_ID_INTEL_TGP_LPC 0x27bc + /* Intel 82801E (C-ICH) */ #define PCI_DEVICE_ID_INTEL_82801E_LPC 0x2450 #define PCI_DEVICE_ID_INTEL_82801E_USB 0x2452 diff --git a/src/include/spi.h b/src/include/spi.h new file mode 100644 index 0000000..bb84258 --- /dev/null +++ b/src/include/spi.h @@ -0,0 +1,203 @@ +/* + * (C) Copyright 2001 + * Gerald Van Baren, Custom IDEAS, vanbaren at cideas.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _SPI_H_ +#define _SPI_H_ + +#include + +/* Controller-specific definitions: */ + +/* SPI mode flags */ +#define SPI_CPHA 0x01 /* clock phase */ +#define SPI_CPOL 0x02 /* clock polarity */ +#define SPI_MODE_0 (0|0) /* (original MicroWire) */ +#define SPI_MODE_1 (0|SPI_CPHA) +#define SPI_MODE_2 (SPI_CPOL|0) +#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) +#define SPI_CS_HIGH 0x04 /* CS active high */ +#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ +#define SPI_3WIRE 0x10 /* SI/SO signals shared */ +#define SPI_LOOP 0x20 /* loopback mode */ + +/* SPI transfer flags */ +#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ +#define SPI_XFER_END 0x02 /* Deassert CS after transfer */ + +/*----------------------------------------------------------------------- + * Representation of a SPI slave, i.e. what we're communicating with. + * + * Drivers are expected to extend this with controller-specific data. + * + * bus: ID of the bus that the slave is attached to. + * cs: ID of the chip select connected to the slave. + */ +struct spi_slave { + unsigned int bus; + unsigned int cs; +}; + +/*----------------------------------------------------------------------- + * Initialization, must be called once on start up. + * + * TODO: I don't think we really need this. + */ +void spi_init(void); + +/*----------------------------------------------------------------------- + * Set up communications parameters for a SPI slave. + * + * This must be called once for each slave. Note that this function + * usually doesn't touch any actual hardware, it only initializes the + * contents of spi_slave so that the hardware can be easily + * initialized later. + * + * bus: Bus ID of the slave chip. + * cs: Chip select ID of the slave chip on the specified bus. + * max_hz: Maximum SCK rate in Hz. + * mode: Clock polarity, clock phase and other parameters. + * + * Returns: A spi_slave reference that can be used in subsequent SPI + * calls, or NULL if one or more of the parameters are not supported. + */ +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode); + +/*----------------------------------------------------------------------- + * Free any memory associated with a SPI slave. + * + * slave: The SPI slave + */ +void spi_free_slave(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Claim the bus and prepare it for communication with a given slave. + * + * This must be called before doing any transfers with a SPI slave. It + * will enable and initialize any SPI hardware as necessary, and make + * sure that the SCK line is in the correct idle state. It is not + * allowed to claim the same bus for several slaves without releasing + * the bus in between. + * + * slave: The SPI slave + * + * Returns: 0 if the bus was claimed successfully, or a negative value + * if it wasn't. + */ +int spi_claim_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Release the SPI bus + * + * This must be called once for every call to spi_claim_bus() after + * all transfers have finished. It may disable any SPI hardware as + * appropriate. + * + * slave: The SPI slave + */ +void spi_release_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * SPI transfer + * + * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks + * "bitlen" bits in the SPI MISO port. That's just the way SPI works. + * + * The source of the outgoing bits is the "dout" parameter and the + * destination of the input bits is the "din" parameter. Note that "dout" + * and "din" can point to the same memory location, in which case the + * input data overwrites the output data (since both are buffered by + * temporary variables, this is OK). + * + * spi_xfer() interface: + * slave: The SPI slave which will be sending/receiving the data. + * dout: Pointer to a string of bits to send out. The bits are + * held in a byte array and are sent MSB first. + * bitsout: How many bits to write. + * din: Pointer to a string of bits that will be filled in. + * bitsin: How many bits to read. + * + * Returns: 0 on success, not 0 on failure + */ +int spi_xfer(struct spi_slave *slave, const void *dout, unsigned int bitsout, + void *din, unsigned int bitsin); + +/*----------------------------------------------------------------------- + * Determine if a SPI chipselect is valid. + * This function is provided by the board if the low-level SPI driver + * needs it to determine if a given chipselect is actually valid. + * + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 + * otherwise. + */ +int spi_cs_is_valid(unsigned int bus, unsigned int cs); + +/*----------------------------------------------------------------------- + * Activate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should activate the chip select + * to the device identified by "slave". + */ +void spi_cs_activate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Deactivate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should deactivate the chip + * select to the device identified by "slave". + */ +void spi_cs_deactivate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Set transfer speed. + * This sets a new speed to be applied for next spi_xfer(). + * slave: The SPI slave + * hz: The transfer speed + */ +void spi_set_speed(struct spi_slave *slave, uint32_t hz); + +/*----------------------------------------------------------------------- + * Write 8 bits, then read 8 bits. + * slave: The SPI slave we're communicating with + * byte: Byte to be written + * + * Returns: The value that was read, or a negative value on error. + * + * TODO: This function probably shouldn't be inlined. + */ +static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) +{ + unsigned char dout[2]; + unsigned char din[2]; + int ret; + + dout[0] = byte; + dout[1] = 0; + + ret = spi_xfer(slave, dout, 16, din, 16); + return ret < 0 ? ret : din[1]; +} + +#endif /* _SPI_H_ */ diff --git a/src/include/spi_flash.h b/src/include/spi_flash.h new file mode 100644 index 0000000..2a1dcd4 --- /dev/null +++ b/src/include/spi_flash.h @@ -0,0 +1,91 @@ +/* + * Interface to SPI flash + * + * Copyright (C) 2008 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _SPI_FLASH_H_ +#define _SPI_FLASH_H_ + +#include +#include +#include +#include + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define min(a, b) ((a)<(b)?(a):(b)) + +#define CONFIG_ICH_SPI +#ifdef CONFIG_ICH_SPI +#define CONTROLLER_PAGE_LIMIT 64 +#else +/* any number larger than 4K would do, actually */ +#define CONTROLLER_PAGE_LIMIT ((int)(~0U>>1)) +#endif + +struct spi_flash { + struct spi_slave *spi; + + const char *name; + + u32 size; + + u32 sector_size; + + int (*read)(struct spi_flash *flash, u32 offset, + size_t len, void *buf); + int (*write)(struct spi_flash *flash, u32 offset, + size_t len, const void *buf); + int (*erase)(struct spi_flash *flash, u32 offset, + size_t len); +}; + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode); +void spi_flash_free(struct spi_flash *flash); + +static inline int spi_flash_read(struct spi_flash *flash, u32 offset, + size_t len, void *buf) +{ + return flash->read(flash, offset, len, buf); +} + +static inline int spi_flash_write(struct spi_flash *flash, u32 offset, + size_t len, const void *buf) +{ + return flash->write(flash, offset, len, buf); +} + +static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, + size_t len) +{ + return flash->erase(flash, offset, len); +} + +#endif /* _SPI_FLASH_H_ */ diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 8209980..6548b32 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -340,6 +340,7 @@ void sdram_initialize(struct pei_data *pei_data) /* If MRC data is not found we cannot continue S3 resume. */ if (pei_data->boot_mode == 2 && !pei_data->mrc_input) { + printk(BIOS_DEBUG, "Giving up in sdram_initialize: No MRC data\n"); outb(0x6, 0xcf9); hlt(); } diff --git a/src/southbridge/intel/bd82x6x/Kconfig b/src/southbridge/intel/bd82x6x/Kconfig index 3891be1..f105ee3 100644 --- a/src/southbridge/intel/bd82x6x/Kconfig +++ b/src/southbridge/intel/bd82x6x/Kconfig @@ -33,6 +33,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy select USE_WATCHDOG_ON_BOOT select PCIEXP_ASPM select PCIEXP_COMMON_CLOCK + select SPI config EHCI_BAR hex diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc index 5732254..f086426 100644 --- a/src/southbridge/intel/bd82x6x/Makefile.inc +++ b/src/southbridge/intel/bd82x6x/Makefile.inc @@ -34,6 +34,8 @@ ramstage-y += me_status.c ramstage-y += reset.c ramstage-y += watchdog.c +ramstage-y += spi.c + ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c $(me-src-y) finalize.c diff --git a/src/southbridge/intel/bd82x6x/spi.c b/src/southbridge/intel/bd82x6x/spi.c new file mode 100644 index 0000000..c54a325 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/spi.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* This file is derived from the flashrom project. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define min(a, b) ((a)<(b)?(a):(b)) + +typedef device_t pci_dev_t; +#define pci_read_config_byte(dev, reg, targ) *(targ) = pci_read_config8(dev, reg) +#define pci_read_config_word(dev, reg, targ) *(targ) = pci_read_config16(dev, reg) +#define pci_read_config_dword(dev, reg, targ) *(targ) = pci_read_config32(dev, reg) +#define pci_write_config_byte(dev, reg, val) pci_write_config8(dev, reg, val) +#define pci_write_config_word(dev, reg, val) pci_write_config16(dev, reg, val) +#define pci_write_config_dword(dev, reg, val) pci_write_config32(dev, reg, val) + +typedef struct spi_slave ich_spi_slave; + +static int ichspi_lock = 0; + +typedef struct ich7_spi_regs { + uint16_t spis; + uint16_t spic; + uint32_t spia; + uint64_t spid[8]; + uint64_t _pad; + uint32_t bbar; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; +} __attribute__((packed)) ich7_spi_regs; + +typedef struct ich9_spi_regs { + uint32_t bfpr; + uint16_t hsfs; + uint16_t hsfc; + uint32_t faddr; + uint32_t _reserved0; + uint32_t fdata[16]; + uint32_t frap; + uint32_t freg[5]; + uint32_t _reserved1[3]; + uint32_t pr[5]; + uint32_t _reserved2[2]; + uint8_t ssfs; + uint8_t ssfc[3]; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; + uint32_t bbar; + uint8_t _reserved3[12]; + uint32_t fdoc; + uint32_t fdod; + uint8_t _reserved4[8]; + uint32_t afc; + uint32_t lvscc; + uint32_t uvscc; + uint8_t _reserved5[4]; + uint32_t fpb; + uint8_t _reserved6[28]; + uint32_t srdl; + uint32_t srdc; + uint32_t srd; +} __attribute__((packed)) ich9_spi_regs; + +typedef struct ich_spi_controller { + int locked; + + uint8_t *opmenu; + int menubytes; + uint16_t *preop; + uint16_t *optype; + uint32_t *addr; + uint8_t *data; + unsigned databytes; + uint8_t *status; + uint16_t *control; + uint32_t *bbar; +} ich_spi_controller; + +static ich_spi_controller cntlr; + +enum { + SPIS_SCIP = 0x0001, + SPIS_GRANT = 0x0002, + SPIS_CDS = 0x0004, + SPIS_FCERR = 0x0008, + SSFS_AEL = 0x0010, + SPIS_LOCK = 0x8000, + SPIS_RESERVED_MASK = 0x7ff0, + SSFS_RESERVED_MASK = 0x7fe2 +}; + +enum { + SPIC_SCGO = 0x000002, + SPIC_ACS = 0x000004, + SPIC_SPOP = 0x000008, + SPIC_DBC = 0x003f00, + SPIC_DS = 0x004000, + SPIC_SME = 0x008000, + SSFC_SCF_MASK = 0x070000, + SSFC_RESERVED = 0xf80000 +}; + +enum { + HSFS_FDONE = 0x0001, + HSFS_FCERR = 0x0002, + HSFS_AEL = 0x0004, + HSFS_BERASE_MASK = 0x0018, + HSFS_BERASE_SHIFT = 3, + HSFS_SCIP = 0x0020, + HSFS_FDOPSS = 0x2000, + HSFS_FDV = 0x4000, + HSFS_FLOCKDN = 0x8000 +}; + +enum { + HSFC_FGO = 0x0001, + HSFC_FCYCLE_MASK = 0x0006, + HSFC_FCYCLE_SHIFT = 1, + HSFC_FDBC_MASK = 0x3f00, + HSFC_FDBC_SHIFT = 8, + HSFC_FSMIE = 0x8000 +}; + +enum { + SPI_OPCODE_TYPE_READ_NO_ADDRESS = 0, + SPI_OPCODE_TYPE_WRITE_NO_ADDRESS = 1, + SPI_OPCODE_TYPE_READ_WITH_ADDRESS = 2, + SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS = 3 +}; + +#ifdef DEBUG + +static u8 readb_(const void *addr) +{ + u8 v = readb(addr); + printk(BIOS_DEBUG, "read %2.2x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u16 readw_(const void *addr) +{ + u16 v = readw(addr); + printk(BIOS_DEBUG, "read %4.4x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u32 readl_(const void *addr) +{ + u32 v = readl(addr); + printk(BIOS_DEBUG, "read %8.8x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static void writeb_(u8 b, const void *addr) +{ + writeb(b, addr); + printk(BIOS_DEBUG, "wrote %2.2x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writew_(u16 b, const void *addr) +{ + writew(b, addr); + printk(BIOS_DEBUG, "wrote %4.4x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writel_(u32 b, const void *addr) +{ + writel(b, addr); + printk(BIOS_DEBUG, "wrote %8.8x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +#else /* DEBUG ^^^ defined vvv NOT defined */ + +#define readb_(a) read8((uint32_t)a) +#define readw_(a) read16((uint32_t)a) +#define readl_(a) read32((uint32_t)a) +#define writeb_(val, addr) write8((uint32_t)addr, val) +#define writew_(val, addr) write16((uint32_t)addr, val) +#define writel_(val, addr) write32((uint32_t)addr, val) + +#endif /* DEBUG ^^^ NOT defined */ + +static void write_reg(const void *value, void *dest, uint32_t size) +{ + const uint8_t *bvalue = value; + uint8_t *bdest = dest; + + while (size >= 4) { + writel_(*(const uint32_t *)bvalue, bdest); + bdest += 4; bvalue += 4; size -= 4; + } + while (size) { + writeb_(*bvalue, bdest); + bdest++; bvalue++; size--; + } +} + +static void read_reg(const void *src, void *value, uint32_t size) +{ + const uint8_t *bsrc = src; + uint8_t *bvalue = value; + + while (size >= 4) { + *(uint32_t *)bvalue = readl_(bsrc); + bsrc += 4; bvalue += 4; size -= 4; + } + while (size) { + *bvalue = readb_(bsrc); + bsrc++; bvalue++; size--; + } +} + +static void ich_set_bbar(uint32_t minaddr) +{ + const uint32_t bbar_mask = 0x00ffff00; + uint32_t ichspi_bbar; + + minaddr &= bbar_mask; + ichspi_bbar = readl_(cntlr.bbar) & ~bbar_mask; + ichspi_bbar |= minaddr; + writel_(ichspi_bbar, cntlr.bbar); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + printk(BIOS_DEBUG, "spi_cs_is_valid used but not implemented\n"); + return 0; +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + ich_spi_slave *slave = malloc(sizeof(*slave)); + + if (!slave) { + printk(BIOS_DEBUG, "ICH SPI: Bad allocation\n"); + return NULL; + } + + memset(slave, 0, sizeof(*slave)); + + slave->bus = bus; + slave->cs = cs; + return slave; +} + +void spi_free_slave(struct spi_slave *_slave) +{ + ich_spi_slave *slave = (ich_spi_slave *)_slave; + free(slave); +} + +static inline int spi_is_cougarpoint_lpc(uint16_t device_id) +{ + return device_id >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN && + device_id <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX; +}; + +void spi_init(void) +{ + int ich_version = 0; + + uint8_t *rcrb; /* Root Complex Register Block */ + uint32_t rcba; /* Root Complex Base Address */ + uint8_t bios_cntl; + pci_dev_t dev; + + int bus; + int last_bus = 1; //FIXME: pci_last_busno(); + + if (last_bus == -1) { + printk(BIOS_DEBUG, "No PCI busses?\n"); + return; + } + + for (bus = 0; bus <= last_bus; bus++) { + uint32_t ids; + uint16_t vendor_id, device_id; + + dev = dev_find_slot(bus, PCI_DEVFN(31, 0)); + pci_read_config_dword(dev, 0, &ids); + vendor_id = ids; + device_id = (ids >> 16); + + if (vendor_id != PCI_VENDOR_ID_INTEL) + continue; + + if (device_id == PCI_DEVICE_ID_INTEL_TGP_LPC) { + ich_version = 7; + break; + } else if (spi_is_cougarpoint_lpc(device_id)) { + ich_version = 9; + break; + } + } + + if (!ich_version) { + printk(BIOS_DEBUG, "ICH SPI: No ICH found.\n"); + return; + } + + pci_read_config_dword(dev, 0xf0, &rcba); + /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable. */ + rcrb = (uint8_t *)(rcba & 0xffffc000); + switch (ich_version) { + case 7: + { + const uint16_t ich7_spibar_offset = 0x3020; + ich7_spi_regs *ich7_spi = + (ich7_spi_regs *)(rcrb + ich7_spibar_offset); + + ichspi_lock = readw_(&ich7_spi->spis) & SPIS_LOCK; + cntlr.opmenu = ich7_spi->opmenu; + cntlr.menubytes = sizeof(ich7_spi->opmenu); + cntlr.optype = &ich7_spi->optype; + cntlr.addr = &ich7_spi->spia; + cntlr.data = (uint8_t *)ich7_spi->spid; + cntlr.databytes = sizeof(ich7_spi->spid); + cntlr.status = (uint8_t *)&ich7_spi->spis; + cntlr.control = &ich7_spi->spic; + cntlr.bbar = &ich7_spi->bbar; + cntlr.preop = &ich7_spi->preop; + break; + } + case 9: + { + const uint16_t ich9_spibar_offset = 0x3800; + ich9_spi_regs *ich9_spi = + (ich9_spi_regs *)(rcrb + ich9_spibar_offset); + ichspi_lock = readw_(&ich9_spi->hsfs) & HSFS_FLOCKDN; + cntlr.opmenu = ich9_spi->opmenu; + cntlr.menubytes = sizeof(ich9_spi->opmenu); + cntlr.optype = &ich9_spi->optype; + cntlr.addr = &ich9_spi->faddr; + cntlr.data = (uint8_t *)ich9_spi->fdata; + cntlr.databytes = sizeof(ich9_spi->fdata); + cntlr.status = &ich9_spi->ssfs; + cntlr.control = (uint16_t *)ich9_spi->ssfc; + cntlr.bbar = &ich9_spi->bbar; + cntlr.preop = &ich9_spi->preop; + break; + } + default: + printk(BIOS_DEBUG, "ICH SPI: Unrecognized ICH version %d.\n", ich_version); + } + + ich_set_bbar(0); + + /* Disable the BIOS write protect so write commands are allowed. */ + pci_read_config_byte(dev, 0xdc, &bios_cntl); + switch (ich_version) { + case 9: + /* Deassert SMM BIOS Write Protect Disable. */ + bios_cntl &= ~(1 << 5); + break; + + default: + break; + } + pci_write_config_byte(dev, 0xdc, bios_cntl | 0x1); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_activate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +typedef struct spi_transaction { + const uint8_t *out; + uint32_t bytesout; + uint8_t *in; + uint32_t bytesin; + uint8_t type; + uint8_t opcode; + uint32_t offset; +} spi_transaction; + +static inline void spi_use_out(spi_transaction *trans, unsigned bytes) +{ + trans->out += bytes; + trans->bytesout -= bytes; +} + +static inline void spi_use_in(spi_transaction *trans, unsigned bytes) +{ + trans->in += bytes; + trans->bytesin -= bytes; +} + +static void spi_setup_type(spi_transaction *trans) +{ + trans->type = 0xFF; + + /* Try to guess spi type from read/write sizes. */ + if (trans->bytesin == 0) { + if (trans->bytesout > 4) + /* + * If bytesin = 0 and bytesout > 4, we presume this is + * a write data operation, which is accompanied by an + * address. + */ + trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS; + else + trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS; + return; + } + + if (trans->bytesout == 1) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS; + return; + } + + if (trans->bytesout == 4) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS; + } +} + +static int spi_setup_opcode(spi_transaction *trans) +{ + uint16_t optypes; + uint8_t opmenu[cntlr.menubytes]; + + trans->opcode = trans->out[0]; + spi_use_out(trans, 1); + if (!ichspi_lock) { + /* The lock is off, so just use index 0. */ + writeb_(trans->opcode, cntlr.opmenu); + optypes = readw_(cntlr.optype); + optypes = (optypes & 0xfffc) | (trans->type & 0x3); + writew_(optypes, cntlr.optype); + return 0; + } else { + /* The lock is on. See if what we need is on the menu. */ + uint8_t optype; + uint16_t opcode_index; + + read_reg(cntlr.opmenu, opmenu, sizeof(opmenu)); + for (opcode_index = 0; opcode_index < cntlr.menubytes; + opcode_index++) { + if (opmenu[opcode_index] == trans->opcode) + break; + } + + if (opcode_index == cntlr.menubytes) { + printk(BIOS_DEBUG, "ICH SPI: Opcode %x not found\n", + trans->opcode); + return -1; + } + + optypes = readw_(cntlr.optype); + optype = (optypes >> (opcode_index * 2)) & 0x3; + if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS && + optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS && + trans->bytesout >= 3) { + /* We guessed wrong earlier. Fix it up. */ + trans->type = optype; + } + if (optype != trans->type) { + printk(BIOS_DEBUG, "ICH SPI: Transaction doesn't fit type %d\n", + optype); + return -1; + } + return opcode_index; + } +} + +static int spi_setup_offset(spi_transaction *trans) +{ + /* Separate the SPI address and data. */ + switch (trans->type) { + case SPI_OPCODE_TYPE_READ_NO_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_NO_ADDRESS: + return 0; + case SPI_OPCODE_TYPE_READ_WITH_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS: + trans->offset = ((uint32_t)trans->out[0] << 16) | + ((uint32_t)trans->out[1] << 8) | + ((uint32_t)trans->out[2] << 0); + spi_use_out(trans, 3); + return 1; + default: + printk(BIOS_DEBUG, "Unrecognized SPI transaction type %#x\n", trans->type); + return -1; + } +} + +/* + * Wait for up to 60ms til status register bit(s) turn 1 (in case wait_til_set + * below is True) or 0. In case the wait was for the bit(s) to set - write + * those bits back, which would cause resetting them. + * + * Return the last read status value on success or -1 on failure. + */ +static int ich_status_poll(u16 bitmask, int wait_til_set) +{ + int timeout = 6000; /* This will result in 60 ms */ + u16 status = 0; + + while (timeout--) { + status = readw_(cntlr.status); + if (wait_til_set ^ ((status & bitmask) == 0)) { + if (wait_til_set) + writew_((status & bitmask), cntlr.status); + return status; + } + udelay(10); + } + + printk(BIOS_DEBUG, "ICH SPI: SCIP timeout, read %x, expected %x\n", + status, bitmask); + return -1; +} + +int spi_xfer(struct spi_slave *slave, const void *dout, + unsigned int bitsout, void *din, unsigned int bitsin) +{ + uint16_t control; + int16_t opcode_index; + int with_address; + int status; + + spi_transaction trans = { + dout, bitsout / 8, + din, bitsin / 8, + 0xff, 0xff, 0 + }; + + /* There has to always at least be an opcode. */ + if (!bitsout || !dout) { + printk(BIOS_DEBUG, "ICH SPI: No opcode for transfer\n"); + return -1; + } + /* Make sure if we read something we have a place to put it. */ + if (bitsin != 0 && !din) { + printk(BIOS_DEBUG, "ICH SPI: Read but no target buffer\n"); + return -1; + } + /* Right now we don't support writing partial bytes. */ + if (bitsout % 8 || bitsin % 8) { + printk(BIOS_DEBUG, "ICH SPI: Accessing partial bytes not supported\n"); + return -1; + } + + if (ich_status_poll(SPIS_SCIP, 0) == -1) + return -1; + + writew_(SPIS_CDS | SPIS_FCERR, cntlr.status); + + spi_setup_type(&trans); + if ((opcode_index = spi_setup_opcode(&trans)) < 0) + return -1; + if ((with_address = spi_setup_offset(&trans)) < 0) + return -1; + + if (!ichspi_lock && trans.opcode == 0x06) { + /* + * Treat Write Enable as Atomic Pre-Op if possible + * in order to prevent the Management Engine from + * issuing a transaction between WREN and DATA. + */ + writew_(trans.opcode, cntlr.preop); + return 0; + } + + /* Preset control fields */ + control = SPIC_SCGO | ((opcode_index & 0x07) << 4); + + /* Issue atomic preop cycle if needed */ + if (readw_(cntlr.preop)) + control |= SPIC_ACS; + + if (!trans.bytesout && !trans.bytesin) { + /* + * This is a 'no data' command (like Write Enable), its + * bitesout size was 1, decremented to zero while executing + * spi_setup_opcode() above. Tell the chip to send the + * command. + */ + writew_(control, cntlr.control); + + /* wait for the result */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Command transaction error\n"); + return -1; + } + + return 0; + } + + /* + * Check if this is a write command atempting to transfer more bytes + * than the controller can handle. Iterations for writes are not + * supported here because each SPI write command needs to be preceded + * and followed by other SPI commands, and this sequence is controlled + * by the SPI chip driver. + */ + if (trans.bytesout > cntlr.databytes) { + printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use" + " CONTROLLER_PAGE_LIMIT?\n"); + return -1; + } + + /* + * Read or write up to databytes bytes at a time until everything has + * been sent. + */ + while (trans.bytesout || trans.bytesin) { + uint32_t data_length; + + /* SPI addresses are 24 bit only */ + writel_(trans.offset & 0x00FFFFFF, cntlr.addr); + + if (trans.bytesout) + data_length = min(trans.bytesout, cntlr.databytes); + else + data_length = min(trans.bytesin, cntlr.databytes); + + /* Program data into FDATA0 to N */ + if (trans.bytesout) { + write_reg(trans.out, cntlr.data, data_length); + spi_use_out(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + + /* Add proper control fields' values */ + control &= ~((cntlr.databytes - 1) << 8); + control |= SPIC_DS; + control |= (data_length - 1) << 8; + + /* write it */ + writew_(control, cntlr.control); + + /* Wait for Cycle Done Status or Flash Cycle Error. */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Data transaction error\n"); + return -1; + } + + if (trans.bytesin) { + read_reg(cntlr.data, trans.in, data_length); + spi_use_in(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + } + + /* Clear atomic preop now that xfer is done */ + writew_(0, cntlr.preop); + + return 0; +} From gerrit at coreboot.org Fri May 4 01:55:02 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Fri, 4 May 2012 01:55:02 +0200 Subject: [coreboot] Patch merged into coreboot/master: 13a40c2 lint: Avoid downloading blobs repository References: Message-ID: the following patch was just integrated into master: commit 13a40c24f0d5c60df2045ad5c7b3709d2d82ccc4 Author: Patrick Georgi Date: Thu May 3 11:55:17 2012 +0200 lint: Avoid downloading blobs repository The stable lint test "build-dir-handling" ran the build system in a way that made it download the blobs repository. Since this is part of the pre-commit hook, this might have kicked in with users desiring not to have them. Change-Id: I44a00137352c5966ff7fe2a030673276f6803908 Signed-off-by: Patrick Georgi Build-Tested: build bot (Jenkins) at Thu May 3 12:13:41 2012, giving +1 Reviewed-By: Stefan Reinauer at Thu May 3 19:32:25 2012, giving +2 See http://review.coreboot.org/999 for details. -gerrit From gerrit at coreboot.org Fri May 4 01:57:08 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Fri, 4 May 2012 01:57:08 +0200 Subject: [coreboot] Patch merged into coreboot/master: 5273ea5 roda/rk886ex: Expose VGA devices in devicetree References: Message-ID: the following patch was just integrated into master: commit 5273ea56be0c1aa191fde01c5d5d160952fa22d6 Author: Patrick Georgi Date: Thu May 3 11:34:20 2012 +0200 roda/rk886ex: Expose VGA devices in devicetree Otherwise set_subsystem isn't called for these (as they're not marked on_mainboard) Change-Id: I08e781735c59e4aa61009d2afa165d782f5a849e Signed-off-by: Patrick Georgi Build-Tested: build bot (Jenkins) at Thu May 3 11:55:24 2012, giving +1 Reviewed-By: Stefan Reinauer at Thu May 3 19:32:16 2012, giving +2 See http://review.coreboot.org/998 for details. -gerrit From gerrit at coreboot.org Fri May 4 01:57:15 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Fri, 4 May 2012 01:57:15 +0200 Subject: [coreboot] Patch merged into coreboot/master: 620d539 siemens/sitemp_g1p1: Drop debug code References: Message-ID: the following patch was just integrated into master: commit 620d539482e5a21b931f37fb248b54915b7f8a88 Author: Patrick Georgi Date: Fri Oct 7 14:25:01 2011 +0200 siemens/sitemp_g1p1: Drop debug code Change-Id: I40a4201b468131ba67e48ab68d62ca5413f2e2e8 Signed-off-by: Patrick Georgi Build-Tested: build bot (Jenkins) at Thu May 3 12:27:48 2012, giving +1 Reviewed-By: Stefan Reinauer at Thu May 3 19:33:50 2012, giving +2 See http://review.coreboot.org/1000 for details. -gerrit From gerrit at coreboot.org Fri May 4 08:11:30 2012 From: gerrit at coreboot.org (gerrit at coreboot.org) Date: Fri, 4 May 2012 08:11:30 +0200 Subject: [coreboot] Patch merged into coreboot/master: a2d207d Make CBFS output more consistent References: Message-ID: the following patch was just integrated into master: commit a2d207db706d961acb7efdea5a20bd99c4a645e1 Author: Stefan Reinauer Date: Wed May 2 16:33:18 2012 -0700 Make CBFS output more consistent - Prefix all CBFS output messages with CBFS: - Add an option DEBUG_CBFS that is off by default. Without DEBUG_CBFS enabled, the code will no longer print all the files it walks for every file lookup. - Add DEBUG() macro next to LOG() and ERROR() to specify which messages should only be visible with DEBUG_CBFS printed. - Actually print a message when the file we're looking for was found. :) old: Searching for fallback/coreboot_ram Check cmos_layout.bin Check pci8086,0106.rom Check fallback/romstage Check fallback/coreboot_ram Change-Id: I2d731fae17a5f6ca51d435cfb7a58d6e017efa24 Stage: loading fallback/coreboot_ram @ 0x100000 (540672 bytes), entry @ 0x100000 Stage: done loading. new: CBFS: Looking for 'fallback/coreboot_ram' CBFS: found. CBFS: loading stage fallback/coreboot_ram @ 0x100000 (507904 bytes), entry @ 0x100000 CBFS: stage loaded. Signed-off-by: Stefan Reinauer See http://review.coreboot.org/993 for details. -gerrit From gerrit at coreboot.org Fri May 4 21:26:58 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Fri, 4 May 2012 21:26:58 +0200 Subject: [coreboot] Patch set updated for coreboot: 4f0970f Rework Sandybridge MRC cache handling References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1001 -gerrit commit 4f0970f80a9322f969b07b551a2d6c9930ec41a2 Author: Stefan Reinauer Date: Thu May 3 16:38:09 2012 -0700 Rework Sandybridge MRC cache handling - Separate Sandybridge from ChromeOS a bit The Sandybridge code depends on chromeos features a whole lot. As a first step, provide a code path to look up the MRC cache without depending on u-boot. - Move mrc cache handling to separate file This enables us to handle the MRC cache from ramstage, where we can write the flash safely (eg. to update the cache). Also teach it to lookup the current MRC cache from CBMEM, as the original data block isn't available anymore. After all the preparations, finally write to the SPI as necessary. It's a simple round robin wear levelling that erases the entire MRC cache region when it's full and starts from the beginning. Change-Id: I4751385574cf709b03d5c9d153b7481ffc90ce12 Signed-off-by: Patrick Georgi --- src/northbridge/intel/sandybridge/Kconfig | 17 ++ src/northbridge/intel/sandybridge/Makefile.inc | 2 + src/northbridge/intel/sandybridge/mrccache.c | 265 +++++++++++++++++++++++ src/northbridge/intel/sandybridge/raminit.c | 123 +---------- src/northbridge/intel/sandybridge/sandybridge.h | 22 ++ 5 files changed, 315 insertions(+), 114 deletions(-) diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig index 8cf0a49..67b3def 100644 --- a/src/northbridge/intel/sandybridge/Kconfig +++ b/src/northbridge/intel/sandybridge/Kconfig @@ -37,6 +37,23 @@ config CACHE_MRC_SIZE_KB int default 256 +# FIXME: build from rom size +config MRC_CACHE_BASE + hex + default 0xff800000 + +config MRC_CACHE_LOCATION + hex + default 0x1ec000 + +config MRC_CACHE_SIZE + hex + default 0x10000 + +config MRC_CACHE_ALIGNMENT + hex + default 0x1000 + config DCACHE_RAM_BASE hex default 0xff7f0000 diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index 87a0b2e..824700e 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -21,9 +21,11 @@ driver-y += northbridge.c driver-y += gma.c ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c +ramstage-y += mrccache.c romstage-y += udelay.c romstage-y += raminit.c +romstage-y += mrccache.c romstage-y += early_init.c romstage-y += report_platform.c romstage-y += ../../../arch/x86/lib/walkcbfs.S diff --git a/src/northbridge/intel/sandybridge/mrccache.c b/src/northbridge/intel/sandybridge/mrccache.c new file mode 100644 index 0000000..5c4c382 --- /dev/null +++ b/src/northbridge/intel/sandybridge/mrccache.c @@ -0,0 +1,265 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Google Inc. + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include "pei_data.h" +#include "sandybridge.h" +#include +#include +/* Using the FDT FMAP for finding the MRC cache area requires including FDT + * support in coreboot, which we would like to avoid. There are a number of + * options: + * - Have each mainboard Kconfig supply a hard-coded offset + * - For ChromeOS devices: implement native FMAP + * - For non-ChromeOS devices: use CBFS + * For now let's leave this code in here until the issue is sorted out in + * a way that works for everyone. + */ +#undef USE_FDT_FMAP_FOR_MRC_CACHE +#ifdef USE_FDT_FMAP_FOR_MRC_CACHE +#include +#endif + +struct mrc_data_container *next_mrc_block(struct mrc_data_container *mrc_cache) +{ + /* MRC data blocks are aligned within the region */ + u32 mrc_size = sizeof(*mrc_cache) + mrc_cache->mrc_data_size; + if (mrc_size & (MRC_DATA_ALIGN - 1UL)) { + mrc_size &= ~(MRC_DATA_ALIGN - 1UL); + mrc_size += MRC_DATA_ALIGN; + } + + u8 *region_ptr = (u8*)mrc_cache; + region_ptr += mrc_size; + return (struct mrc_data_container *)region_ptr; +} + +int is_mrc_cache(struct mrc_data_container *mrc_cache) +{ + return (!!mrc_cache) && (mrc_cache->mrc_signature == MRC_DATA_SIGNATURE); +} + +u32 get_mrc_cache_region(struct mrc_data_container **mrc_region_ptr) +{ + u8 *mrc_region; + u32 region_size; + u32 *data; +#ifdef USE_FDT_FMAP_FOR_MRC_CACHE + const struct fdt_header *fdt_header; + const struct fdt_property *fdtp; + int offset, len; + const char *compatible = "chromeos,flashmap"; + const char *subnode = "rw-mrc-cache"; + const char *property = "reg"; + u64 flashrom_base = 0; + + fdt_header = cbfs_find_file(CONFIG_FDT_FILE_NAME, CBFS_TYPE_FDT); + + if (!fdt_header) { + printk(BIOS_ERR, "%s: no FDT found!\n", __func__); + return 0; + } + + offset = fdt_node_offset_by_compatible(fdt_header, 0, compatible); + if (offset < 0) { + printk(BIOS_ERR, "%s: no %s node found!\n", + __func__, compatible); + return 0; + } + + if (fdt_get_base_addr(fdt_header, offset, &flashrom_base) < 0) { + printk(BIOS_ERR, "%s: no base address in node name!\n", + __func__); + return 0; + } + + offset = fdt_subnode_offset(fdt_header, offset, subnode); + if (offset < 0) { + printk(BIOS_ERR, "%s: no %s found!\n", __func__, subnode); + return 0; + } + + fdtp = fdt_get_property(fdt_header, offset, property, &len); + if (!fdtp || (len != 8)) { + printk(BIOS_ERR, "%s: property %s at %p, len %d!\n", + __func__, property, fdtp, len); + return 0; + } + + data = (u32 *)fdtp->data; + + // Calculate actual address of the MRC cache in memory + region_size = fdt32_to_cpu(data[1]); + mrc_region = (u8*)((unsigned long)flashrom_base + fdt32_to_cpu(data[0])); +#else + data = (u32 *)((void *)(CONFIG_MRC_CACHE_BASE + CONFIG_MRC_CACHE_LOCATION + 12)); + + region_size = CONFIG_MRC_CACHE_SIZE; + mrc_region = (u8*)(CONFIG_MRC_CACHE_BASE + be32_to_cpu(data[0])); +#endif + + *mrc_region_ptr = (struct mrc_data_container *)mrc_region; + + return region_size; +} + +/* find the first empty field in the MRC cache area. If there's none, return + * the first region. By testing for emptiness caller can detect if flash + * needs to be erased. + * + * FIXME: that interface is crap + */ +struct mrc_data_container *find_next_mrc_cache(void) +{ + u32 entry_id = 0; + struct mrc_data_container *mrc_cache = NULL; + u32 region_size = get_mrc_cache_region(&mrc_cache); + void *mrc_region = (void*)mrc_cache; + + if (mrc_cache == NULL) { + printk(BIOS_ERR, "%s: could not find mrc cache area\n", __func__); + return NULL; + } + + /* Search for the first empty entry in the region */ + while (is_mrc_cache(mrc_cache)) { + entry_id++; + mrc_cache = next_mrc_block(mrc_cache); + /* If we exceed the defined area, move to front */ + if ((void*)mrc_cache >= (void*)(mrc_region + region_size)) { + mrc_cache = (struct mrc_data_container *)mrc_region; + break; + } + } + + printk(BIOS_DEBUG, "picked entry %u from cache block when looking for empty block\n", entry_id); + + return mrc_cache; +} + +struct mrc_data_container *find_current_mrc_cache(void) +{ + u32 entry_id = 0; + struct mrc_data_container *mrc_next, *mrc_cache = NULL; + u32 region_size = get_mrc_cache_region(&mrc_cache); + void *mrc_region = (void*)mrc_cache; + mrc_next = mrc_cache; + + if (mrc_cache == NULL) { + printk(BIOS_ERR, "%s: could not find mrc cache area\n", __func__); + return NULL; + } + + if (mrc_cache->mrc_data_size == -1UL) { + printk(BIOS_ERR, "%s: MRC cache not initialized?\n", __func__); + /* return non-initialized cache, so we can discern this + * from having no cache area at all + */ + return mrc_cache; + } else { + /* Search for the last filled entry in the region */ + while (is_mrc_cache(mrc_next)) { + entry_id++; + mrc_cache = mrc_next; + mrc_next = next_mrc_block(mrc_cache); + /* Stay in the mrcdata region defined in fdt */ + if ((void*)mrc_next >= (void*)(mrc_region + region_size)) + break; + } + entry_id--; + } + + /* Verify checksum */ + if (mrc_cache->mrc_checksum != + compute_ip_checksum(mrc_cache->mrc_data, + mrc_cache->mrc_data_size)) { + printk(BIOS_ERR, "%s: MRC cache checksum mismatch\n", __func__); + return NULL; + } + + printk(BIOS_DEBUG, "picked entry %u from cache block\n", entry_id); + + return mrc_cache; +} + +/* SPI code needs malloc/free. + * Also unknown if writing flash from XIP-flash code is a good idea + */ +#if !defined(__PRE_RAM__) +void update_mrc_cache(void) +{ + struct mrc_data_container *current = cbmem_find(CBMEM_ID_MRCDATA); + if (!current) { + printk(BIOS_ERR, "No MRC cache in cbmem. Can't update flash.\n"); + return; + } + if (current->mrc_data_size == -1) { + printk(BIOS_ERR, "MRC cache data in cbmem invalid.\n"); + return; + } + + /* + * we need to: + */ + // 0. compare MRC data to last mrc-cache block (exit if same) + struct mrc_data_container *cache; + if ((cache = find_current_mrc_cache()) == NULL) { + printk(BIOS_DEBUG, "Failure looking for current last block\n"); + return; + } + + if ((cache->mrc_data_size == current->mrc_data_size) && (memcmp(cache, current, cache->mrc_data_size) == 0)) { + printk(BIOS_DEBUG, "MRC data in flash is up to date. No update.\n"); + return; + } + + // 1. use spi_flash_probe() to find the flash, then + spi_init(); + struct spi_flash *flash = spi_flash_probe(0, 0, 1000000, SPI_MODE_3); + if (!flash) { + printk(BIOS_DEBUG, "Could not find SPI device\n"); + return; + } + + // 2. look up the first unused block + cache = find_next_mrc_cache(); + if (!cache) { + printk(BIOS_DEBUG, "Could not find MRC cache area\n"); + return; + } + + // 3. if no such place exists, erase entire mrc-cache range & use block 0 + if (cache->mrc_data_size != -1) { + printk(BIOS_DEBUG, "We need to erase the MRC cache region\n"); + flash->erase(flash, CONFIG_MRC_CACHE_LOCATION, CONFIG_MRC_CACHE_SIZE); + /* we know we can start at the beginning again */ + get_mrc_cache_region(&cache); + } + // 4. write mrc data with flash->write() + printk(BIOS_DEBUG, "Finally: write MRC cache update to flash\n"); + flash->write(flash, (u32)(((void*)cache)-CONFIG_MRC_CACHE_BASE), current->mrc_data_size + sizeof(*current), current); +} +#endif + diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 6548b32..0df86d6 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -36,9 +36,8 @@ #include "southbridge/intel/bd82x6x/me.h" #if CONFIG_CHROMEOS #include -#endif -#if 0 -#include +#else +#define recovery_mode_enabled(x) 0 #endif /* @@ -56,17 +55,6 @@ #define CMOS_OFFSET_MRC_SEED_CHK 120 #endif -#define MRC_DATA_ALIGN 0x1000 -#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24)) - -struct mrc_data_container { - u32 mrc_signature; // "MRCD" - u32 mrc_data_size; // Actual total size of this structure - u32 mrc_checksum; // IP style checksum - u32 reserved; // For header alignment - u8 mrc_data[0]; // Variable size, platform/run time dependent. -} __attribute__ ((packed)); - static void save_mrc_data(struct pei_data *pei_data) { u16 c1, c2, checksum; @@ -119,22 +107,10 @@ static void save_mrc_data(struct pei_data *pei_data) cmos_write((checksum >> 8) & 0xff, CMOS_OFFSET_MRC_SEED_CHK+1); } -#if CONFIG_CHROMEOS static void prepare_mrc_cache(struct pei_data *pei_data) { -#if 0 - const struct fdt_header *fdt_header; - const struct fdt_property *fdtp; - int offset, len; - const char *compatible = "chromeos,flashmap"; - const char *subnode = "rw-mrc-cache"; - const char *property = "reg"; - u32 *data; - struct mrc_data_container *mrc_cache, *mrc_next; - u8 *mrc_region, *region_ptr; + struct mrc_data_container *mrc_cache; u16 c1, c2, checksum, seed_checksum; - u32 region_size, entry_id = 0; - u64 flashrom_base = 0; // preset just in case there is an error pei_data->mrc_input = NULL; @@ -166,96 +142,18 @@ static void prepare_mrc_cache(struct pei_data *pei_data) return; } - fdt_header = cbfs_find_file(CONFIG_FDT_FILE_NAME, CBFS_TYPE_FDT); - - if (!fdt_header) { - printk(BIOS_ERR, "%s: no FDT found!\n", __func__); - return; - } - - offset = fdt_node_offset_by_compatible(fdt_header, 0, compatible); - if (offset < 0) { - printk(BIOS_ERR, "%s: no %s node found!\n", - __func__, compatible); - return; - } - - if (fdt_get_base_addr(fdt_header, offset, &flashrom_base) < 0) { - printk(BIOS_ERR, "%s: no base address in node name!\n", - __func__); - return; - } - - offset = fdt_subnode_offset(fdt_header, offset, subnode); - if (offset < 0) { - printk(BIOS_ERR, "%s: no %s found!\n", __func__, subnode); - return; - } - - fdtp = fdt_get_property(fdt_header, offset, property, &len); - if (!fdtp || (len != 8)) { - printk(BIOS_ERR, "%s: property %s at %p, len %d!\n", - __func__, property, fdtp, len); - return; - } - - data = (u32 *)fdtp->data; - - // Calculate actual address of the MRC cache in memory - region_size = fdt32_to_cpu(data[1]); - mrc_region = region_ptr = (u8*) - ((unsigned long)flashrom_base + fdt32_to_cpu(data[0])); - mrc_cache = mrc_next = (struct mrc_data_container *)mrc_region; - - if (!mrc_cache || mrc_cache->mrc_signature != MRC_DATA_SIGNATURE) { - printk(BIOS_ERR, "%s: invalid MRC data\n", __func__); - return; - } - - if (mrc_cache->mrc_data_size == -1UL) { - printk(BIOS_ERR, "%s: MRC cache not initialized?\n", __func__); - return; - } else { - /* MRC data blocks are aligned within the region */ - u32 mrc_size = sizeof(*mrc_cache) + mrc_cache->mrc_data_size; - if (mrc_size & (MRC_DATA_ALIGN - 1UL)) { - mrc_size &= ~(MRC_DATA_ALIGN - 1UL); - mrc_size += MRC_DATA_ALIGN; - } - - /* Search for the last filled entry in the region */ - while (mrc_next && - mrc_next->mrc_signature == MRC_DATA_SIGNATURE) { - entry_id++; - mrc_cache = mrc_next; - /* Stay in the mrcdata region defined in fdt */ - if ((entry_id * mrc_size) > region_size) - break; - region_ptr += mrc_size; - mrc_next = (struct mrc_data_container *)region_ptr; - } - entry_id--; - } - - /* Verify checksum */ - if (mrc_cache->mrc_checksum != - compute_ip_checksum(mrc_cache->mrc_data, - mrc_cache->mrc_data_size)) { - printk(BIOS_ERR, "%s: MRC cache checksum mismatch\n", __func__); + if ((mrc_cache = find_current_mrc_cache()) == NULL) { + /* error message printed in find_current_mrc_cache */ return; } pei_data->mrc_input = mrc_cache->mrc_data; pei_data->mrc_input_len = mrc_cache->mrc_data_size; - printk(BIOS_DEBUG, "%s: at %p, entry %u size %x checksum %04x\n", - __func__, pei_data->mrc_input, entry_id, + printk(BIOS_DEBUG, "%s: at %p, size %x checksum %04x\n", + __func__, pei_data->mrc_input, pei_data->mrc_input_len, mrc_cache->mrc_checksum); -#else - printk(BIOS_ERR, "MRC cache handling code has to be redone.\n"); -#endif } -#endif static const char* ecc_decoder[] = { "inactive", @@ -315,7 +213,6 @@ static void report_memory_config(void) void sdram_initialize(struct pei_data *pei_data) { struct sys_info sysinfo; - const char *target = "mrc.bin"; unsigned long entry; report_platform_info(); @@ -330,7 +227,6 @@ void sdram_initialize(struct pei_data *pei_data) sysinfo.boot_path = pei_data->boot_mode; -#if CONFIG_CHROMEOS /* * Do not pass MRC data in for recovery mode boot, * Always pass it in for S3 resume. @@ -344,17 +240,16 @@ void sdram_initialize(struct pei_data *pei_data) outb(0x6, 0xcf9); hlt(); } -#endif /* Locate and call UEFI System Agent binary. */ - entry = (unsigned long)cbfs_find_file(target, 0xab); + entry = (unsigned long)cbfs_find_file("mrc.bin", 0xab); if (entry) { int rv; asm volatile ( "call *%%ecx\n\t" :"=a" (rv) : "c" (entry), "a" (pei_data)); if (rv) { - printk(BIOS_ERR, "MRC returned %d\n", rv); + printk(BIOS_ERR, "MRC returned %x\n", rv); die("Nonzero MRC return value\n"); } } else { diff --git a/src/northbridge/intel/sandybridge/sandybridge.h b/src/northbridge/intel/sandybridge/sandybridge.h index aa62021..7e12416 100644 --- a/src/northbridge/intel/sandybridge/sandybridge.h +++ b/src/northbridge/intel/sandybridge/sandybridge.h @@ -221,6 +221,28 @@ void dump_spd_registers(void); void dump_mem(unsigned start, unsigned end); void report_platform_info(void); #endif /* !__SMM__ */ + + +#define MRC_DATA_ALIGN 0x1000 +#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24)) + +struct mrc_data_container { + u32 mrc_signature; // "MRCD" + u32 mrc_data_size; // Actual total size of this structure + u32 mrc_checksum; // IP style checksum + u32 reserved; // For header alignment + u8 mrc_data[0]; // Variable size, platform/run time dependent. +} __attribute__ ((packed)); + +struct mrc_data_container *next_mrc_block(struct mrc_data_container *mrc_cache); +int is_mrc_cache(struct mrc_data_container *mrc_cache); +u32 get_mrc_cache_region(struct mrc_data_container **mrc_region_ptr); +struct mrc_data_container *find_next_mrc_cache(void); +struct mrc_data_container *find_current_mrc_cache(void); +#if !defined(__PRE_RAM__) +void update_mrc_cache(void); +#endif + #endif #endif #endif From gerrit at coreboot.org Fri May 4 21:26:59 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Fri, 4 May 2012 21:26:59 +0200 Subject: [coreboot] Patch set updated for coreboot: ceb11f7 Hook up MRC cache update References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1002 -gerrit commit ceb11f76b4099fdde0210ed6eb1967dffc79ff73 Author: Stefan Reinauer Date: Thu May 3 16:40:41 2012 -0700 Hook up MRC cache update This one is a WIP: - should not depend on CONFIG_CHROMEOS - There might be a better place for it. Requirements: - must be in ramstage (locking flash while executing code from there might not work) - must be after cbmem is reinitialized (so the mrc cache copy of the current run can be found) Change-Id: I8028fb073349ce2b027ef5f8397dc1a1b8b31c02 Signed-off-by: Patrick Georgi --- src/arch/x86/boot/tables.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/src/arch/x86/boot/tables.c b/src/arch/x86/boot/tables.c index 4fefc7d..ff57422 100644 --- a/src/arch/x86/boot/tables.c +++ b/src/arch/x86/boot/tables.c @@ -53,6 +53,11 @@ struct lb_memory *write_tables(void) */ unsigned long high_table_pointer; +#if CONFIG_CHROMEOS + void update_mrc_cache(void); + update_mrc_cache(); +#endif + if (!high_tables_base) { printk(BIOS_ERR, "ERROR: High Tables Base is not set.\n"); // Are there any boards without? From gerrit at coreboot.org Fri May 4 21:26:59 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Fri, 4 May 2012 21:26:59 +0200 Subject: [coreboot] Patch set updated for coreboot: 1aad3f4 Add SPI driver References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/997 -gerrit commit 1aad3f4c80e904066bcf86e826995789bcf6aacc Author: Stefan Reinauer Date: Wed May 2 17:07:05 2012 -0700 Add SPI driver This driver is taken from u-boot and adapted to match coreboot. It still contains some hacks and is ICH specific at places. Change-Id: I97dd8096f7db3b62f8f4f4e4d08bdee10d88f689 Signed-off-by: Patrick Georgi --- src/drivers/Kconfig | 1 + src/drivers/Makefile.inc | 1 + src/drivers/spi/Kconfig | 82 +++ src/drivers/spi/Makefile.inc | 12 + src/drivers/spi/eon.c | 161 ++++++ src/drivers/spi/macronix.c | 220 +++++++++ src/drivers/spi/ramtron.c | 315 ++++++++++++ src/drivers/spi/spansion.c | 241 +++++++++ src/drivers/spi/spi_flash.c | 320 ++++++++++++ src/drivers/spi/spi_flash_internal.h | 81 +++ src/drivers/spi/sst.c | 268 ++++++++++ src/drivers/spi/stmicro.c | 250 ++++++++++ src/drivers/spi/winbond.c | 218 ++++++++ src/include/device/pci_ids.h | 4 + src/include/spi.h | 203 ++++++++ src/include/spi_flash.h | 91 ++++ src/northbridge/intel/sandybridge/raminit.c | 1 + src/southbridge/intel/bd82x6x/Kconfig | 1 + src/southbridge/intel/bd82x6x/Makefile.inc | 2 + src/southbridge/intel/bd82x6x/spi.c | 712 +++++++++++++++++++++++++++ 20 files changed, 3184 insertions(+), 0 deletions(-) diff --git a/src/drivers/Kconfig b/src/drivers/Kconfig index 259bc29..60e5b65 100644 --- a/src/drivers/Kconfig +++ b/src/drivers/Kconfig @@ -26,3 +26,4 @@ source src/drivers/oxford/Kconfig source src/drivers/sil/Kconfig source src/drivers/trident/Kconfig source src/drivers/ics/Kconfig +source src/drivers/spi/Kconfig diff --git a/src/drivers/Makefile.inc b/src/drivers/Makefile.inc index 5f6dadf..851a4df 100644 --- a/src/drivers/Makefile.inc +++ b/src/drivers/Makefile.inc @@ -26,4 +26,5 @@ subdirs-y += oxford subdirs-y += sil subdirs-y += trident subdirs-y += ics +subdirs-y += spi subdirs-$(CONFIG_ARCH_X86) += pc80 diff --git a/src/drivers/spi/Kconfig b/src/drivers/spi/Kconfig new file mode 100644 index 0000000..97340e1 --- /dev/null +++ b/src/drivers/spi/Kconfig @@ -0,0 +1,82 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2012 The Chromium OS Authors. +## +## 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; version 2 of the License. +## +## 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +config SPI + bool + default n + help + Select this option if your chipset driver needs to store certain + data in the SPI flash. + +config SPI_FLASH_EON + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by EON. + +config SPI_FLASH_MACRONIX + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by Macronix. + +config SPI_FLASH_SPANSION + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by Spansion. + +config SPI_FLASH_SST + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by SST. + +config SPI_FLASH_STMICRO + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by ST MICRO. + + +config SPI_FLASH_WINBOND + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by Winbond. + +config SPI_FRAM_RAMTRON + bool + default n + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by RAMTRON. diff --git a/src/drivers/spi/Makefile.inc b/src/drivers/spi/Makefile.inc new file mode 100644 index 0000000..6cdf398 --- /dev/null +++ b/src/drivers/spi/Makefile.inc @@ -0,0 +1,12 @@ +# SPI driver interface +ramstage-$(CONFIG_SPI) += spi_flash.c + +# drivers +ramstage-$(CONFIG_SPI_FLASH_EON) += eon.c +ramstage-$(CONFIG_SPI_FLASH_MACRONIX) += macronix.c +ramstage-$(CONFIG_SPI_FLASH_SPANSION) += spansion.c +ramstage-$(CONFIG_SPI_FLASH_SST) += sst.c +ramstage-$(CONFIG_SPI_FLASH_STMICRO) += stmicro.c +ramstage-$(CONFIG_SPI_FLASH_WINBOND) += winbond.c +ramstage-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.c + diff --git a/src/drivers/spi/eon.c b/src/drivers/spi/eon.c new file mode 100644 index 0000000..4056953 --- /dev/null +++ b/src/drivers/spi/eon.c @@ -0,0 +1,161 @@ +/* + * (C) Copyright 2010, ucRobotics Inc. + * Author: Chong Huang + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* EN25Q128-specific commands */ +#define CMD_EN25Q128_WREN 0x06 /* Write Enable */ +#define CMD_EN25Q128_WRDI 0x04 /* Write Disable */ +#define CMD_EN25Q128_RDSR 0x05 /* Read Status Register */ +#define CMD_EN25Q128_WRSR 0x01 /* Write Status Register */ +#define CMD_EN25Q128_READ 0x03 /* Read Data Bytes */ +#define CMD_EN25Q128_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_EN25Q128_PP 0x02 /* Page Program */ +#define CMD_EN25Q128_SE 0x20 /* Sector Erase */ +#define CMD_EN25Q128_BE 0xd8 /* Block Erase */ +#define CMD_EN25Q128_DP 0xb9 /* Deep Power-down */ +#define CMD_EN25Q128_RES 0xab /* Release from DP, and Read Signature */ + +#define EON_ID_EN25Q128 0x18 + +struct eon_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 sectors_per_block; + u16 nr_sectors; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct eon_spi_flash { + struct spi_flash flash; + const struct eon_spi_flash_params *params; +}; + +static inline struct eon_spi_flash *to_eon_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct eon_spi_flash, flash); +} + +static const struct eon_spi_flash_params eon_spi_flash_table[] = { + { + .idcode1 = EON_ID_EN25Q128, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_sectors = 4096, + .name = "EN25Q128", + }, +}; + +static int eon_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct eon_spi_flash *eon = to_eon_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = eon->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_EN25Q128_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, + "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_EN25Q128_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: EON Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: EON: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int eon_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_EN25Q128_BE, offset, len); +} + +struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode) +{ + const struct eon_spi_flash_params *params; + struct eon_spi_flash *eon; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(eon_spi_flash_table); ++i) { + params = &eon_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(eon_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported EON ID %02x\n", idcode[1]); + return NULL; + } + + eon = malloc(sizeof(*eon)); + if (!eon) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + eon->params = params; + eon->flash.spi = spi; + eon->flash.name = params->name; + + eon->flash.write = eon_write; + eon->flash.erase = eon_erase; + eon->flash.read = spi_flash_cmd_read_fast; + eon->flash.sector_size = params->page_size * params->pages_per_sector + * params->sectors_per_block; + eon->flash.size = params->page_size * params->pages_per_sector + * params->nr_sectors; + + return &eon->flash; +} diff --git a/src/drivers/spi/macronix.c b/src/drivers/spi/macronix.c new file mode 100644 index 0000000..130e746 --- /dev/null +++ b/src/drivers/spi/macronix.c @@ -0,0 +1,220 @@ +/* + * Copyright 2009(C) Marvell International Ltd. and its affiliates + * Prafulla Wadaskar + * + * Based on drivers/mtd/spi/stmicro.c + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* MX25xx-specific commands */ +#define CMD_MX25XX_WREN 0x06 /* Write Enable */ +#define CMD_MX25XX_WRDI 0x04 /* Write Disable */ +#define CMD_MX25XX_RDSR 0x05 /* Read Status Register */ +#define CMD_MX25XX_WRSR 0x01 /* Write Status Register */ +#define CMD_MX25XX_READ 0x03 /* Read Data Bytes */ +#define CMD_MX25XX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_MX25XX_PP 0x02 /* Page Program */ +#define CMD_MX25XX_SE 0x20 /* Sector Erase */ +#define CMD_MX25XX_BE 0xD8 /* Block Erase */ +#define CMD_MX25XX_CE 0xc7 /* Chip Erase */ +#define CMD_MX25XX_DP 0xb9 /* Deep Power-down */ +#define CMD_MX25XX_RES 0xab /* Release from DP, and Read Signature */ + +#define MACRONIX_SR_WIP (1 << 0) /* Write-in-Progress */ + +struct macronix_spi_flash_params { + u16 idcode; + u16 page_size; + u16 pages_per_sector; + u16 sectors_per_block; + u16 nr_blocks; + const char *name; +}; + +struct macronix_spi_flash { + struct spi_flash flash; + const struct macronix_spi_flash_params *params; +}; + +static inline struct macronix_spi_flash *to_macronix_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct macronix_spi_flash, flash); +} + +static const struct macronix_spi_flash_params macronix_spi_flash_table[] = { + { + .idcode = 0x2015, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "MX25L1605D", + }, + { + .idcode = 0x2016, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "MX25L3205D", + }, + { + .idcode = 0x2017, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "MX25L6405D", + }, + { + .idcode = 0x2018, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "MX25L12805D", + }, + { + .idcode = 0x2618, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "MX25L12855E", + }, +}; + +static int macronix_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct macronix_spi_flash *mcx = to_macronix_spi_flash(flash); + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = min(mcx->params->page_size, CONTROLLER_PAGE_LIMIT); + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_MX25XX_PP; + cmd[1] = (offset >> 16) & 0xff; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_MX25XX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Macronix Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + offset += chunk_len; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: Macronix: Successfully programmed %zu bytes @ 0x%lx\n", + len, offset - len); + + spi_release_bus(flash->spi); + return ret; +} + +static int macronix_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_MX25XX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode) +{ + const struct macronix_spi_flash_params *params; + struct macronix_spi_flash *mcx; + unsigned int i; + u16 id = idcode[2] | idcode[1] << 8; + + for (i = 0; i < ARRAY_SIZE(macronix_spi_flash_table); i++) { + params = ¯onix_spi_flash_table[i]; + if (params->idcode == id) + break; + } + + if (i == ARRAY_SIZE(macronix_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported Macronix ID %04x\n", id); + return NULL; + } + + mcx = malloc(sizeof(*mcx)); + if (!mcx) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + mcx->params = params; + mcx->flash.spi = spi; + mcx->flash.name = params->name; + + mcx->flash.write = macronix_write; + mcx->flash.erase = macronix_erase; +#ifdef CONFIG_SPI_FLASH_NO_FAST_READ + mcx->flash.read = spi_flash_cmd_read_slow; +#else + mcx->flash.read = spi_flash_cmd_read_fast; +#endif + mcx->flash.sector_size = params->page_size * params->pages_per_sector; + mcx->flash.size = mcx->flash.sector_size * params->sectors_per_block * + params->nr_blocks; + + return &mcx->flash; +} diff --git a/src/drivers/spi/ramtron.c b/src/drivers/spi/ramtron.c new file mode 100644 index 0000000..2d50b85 --- /dev/null +++ b/src/drivers/spi/ramtron.c @@ -0,0 +1,315 @@ +/* + * (C) Copyright 2010 + * Reinhard Meyer, EMK Elektronik, reinhard.meyer at emk-elektronik.de + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Note: RAMTRON SPI FRAMs are ferroelectric, nonvolatile RAMs + * with an interface identical to SPI flash devices. + * However since they behave like RAM there are no delays or + * busy polls required. They can sustain read or write at the + * allowed SPI bus speed, which can be 40 MHz for some devices. + * + * Unfortunately some RAMTRON devices do not have a means of + * identifying them. They will leave the SO line undriven when + * the READ-ID command is issued. It is therefore mandatory + * that the MISO line has a proper pull-up, so that READ-ID + * will return a row of 0xff. This 0xff pseudo-id will cause + * probes by all vendor specific functions that are designed + * to handle it. If the MISO line is not pulled up, READ-ID + * could return any random noise, even mimicking another + * device. + * + * We use CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + * to define which device will be assumed after a simple status + * register verify. This method is prone to false positive + * detection and should therefore be the last to be tried. + * Enter it in the last position in the table in spi_flash.c! + * + * The define CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC both activates + * compilation of the special handler and defines the device + * to assume. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* RAMTRON commands common to all devices */ +#define CMD_RAMTRON_WREN 0x06 /* Write Enable */ +#define CMD_RAMTRON_WRDI 0x04 /* Write Disable */ +#define CMD_RAMTRON_RDSR 0x05 /* Read Status Register */ +#define CMD_RAMTRON_WRSR 0x01 /* Write Status Register */ +#define CMD_RAMTRON_READ 0x03 /* Read Data Bytes */ +#define CMD_RAMTRON_WRITE 0x02 /* Write Data Bytes */ +/* not all have those: */ +#define CMD_RAMTRON_FSTRD 0x0b /* Fast Read (for compatibility - not used here) */ +#define CMD_RAMTRON_SLEEP 0xb9 /* Enter Sleep Mode */ +#define CMD_RAMTRON_RDID 0x9f /* Read ID */ +#define CMD_RAMTRON_SNR 0xc3 /* Read Serial Number */ + +/* + * Properties of supported FRAMs + * Note: speed is currently not used because we have no method to deliver that + * value to the upper layers + */ +struct ramtron_spi_fram_params { + u32 size; /* size in bytes */ + u8 addr_len; /* number of address bytes */ + u8 merge_cmd; /* some address bits are in the command byte */ + u8 id1; /* device ID 1 (family, density) */ + u8 id2; /* device ID 2 (sub, rev, rsvd) */ + u32 speed; /* max. SPI clock in Hz */ + const char *name; /* name for display and/or matching */ +}; + +struct ramtron_spi_fram { + struct spi_flash flash; + const struct ramtron_spi_fram_params *params; +}; + +static inline struct ramtron_spi_fram *to_ramtron_spi_fram(struct spi_flash + *flash) +{ + return container_of(flash, struct ramtron_spi_fram, flash); +} + +/* + * table describing supported FRAM chips: + * chips without RDID command must have the values 0xff for id1 and id2 + */ +static const struct ramtron_spi_fram_params ramtron_spi_fram_table[] = { + { + .size = 32*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x22, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V02", + }, + { + .size = 32*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x22, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN02", + }, + { + .size = 64*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x23, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V05", + }, + { + .size = 64*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x23, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN05", + }, + { + .size = 128*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0x24, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V10", + }, + { + .size = 128*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0x24, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN10", + }, +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + { + .size = 256*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0xff, + .id2 = 0xff, + .speed = 40000000, + .name = "FM25H20", + }, +#endif +}; + +static int ramtron_common(struct spi_flash *flash, + u32 offset, size_t len, void *buf, u8 command) +{ + struct ramtron_spi_fram *sn = to_ramtron_spi_fram(flash); + u8 cmd[4]; + int cmd_len; + int ret; + + if (sn->params->addr_len == 3 && sn->params->merge_cmd == 0) { + cmd[0] = command; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + cmd_len = 4; + } else if (sn->params->addr_len == 2 && sn->params->merge_cmd == 0) { + cmd[0] = command; + cmd[1] = offset >> 8; + cmd[2] = offset; + cmd_len = 3; + } else { + printk(BIOS_WARNING, "SF: unsupported addr_len or merge_cmd\n"); + return -1; + } + + /* claim the bus */ + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + if (command == CMD_RAMTRON_WRITE) { + /* send WREN */ + ret = spi_flash_cmd(flash->spi, CMD_RAMTRON_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + goto releasebus; + } + } + + /* do the transaction */ + if (command == CMD_RAMTRON_WRITE) + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, buf, len); + else + ret = spi_flash_cmd_read(flash->spi, cmd, cmd_len, buf, len); + if (ret < 0) + printk(BIOS_WARNING, "SF: Transaction failed\n"); + +releasebus: + /* release the bus */ + spi_release_bus(flash->spi); + return ret; +} + +static int ramtron_read(struct spi_flash *flash, + u32 offset, size_t len, void *buf) +{ + return ramtron_common(flash, offset, len, buf, + CMD_RAMTRON_READ); +} + +static int ramtron_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + return ramtron_common(flash, offset, len, (void *)buf, + CMD_RAMTRON_WRITE); +} + +static int ramtron_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + printk(BIOS_SPEW, "SF: Erase of RAMTRON FRAMs is pointless\n"); + return -1; +} + +/* + * nore: we are called here with idcode pointing to the first non-0x7f byte + * already! + */ +struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode) +{ + const struct ramtron_spi_fram_params *params; + struct ramtron_spi_fram *sn; + unsigned int i; +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + int ret; + u8 sr; +#endif + + /* NOTE: the bus has been claimed before this function is called! */ + switch (idcode[0]) { + case 0xc2: + /* JEDEC conformant RAMTRON id */ + for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) { + params = &ramtron_spi_fram_table[i]; + if (idcode[1] == params->id1 && idcode[2] == params->id2) + goto found; + } + break; +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + case 0xff: + /* + * probably open MISO line, pulled up. + * We COULD have a non JEDEC conformant FRAM here, + * read the status register to verify + */ + ret = spi_flash_cmd(spi, CMD_RAMTRON_RDSR, &sr, 1); + if (ret) + return NULL; + + /* Bits 5,4,0 are fixed 0 for all devices */ + if ((sr & 0x31) != 0x00) + return NULL; + /* now find the device */ + for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) { + params = &ramtron_spi_fram_table[i]; + if (!strcmp(params->name, CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC)) + goto found; + } + printk(BIOS_WARNING, "SF: Unsupported non-JEDEC RAMTRON device " + CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC "\n"); + break; +#endif + default: + break; + } + + /* arriving here means no method has found a device we can handle */ + printk(BIOS_WARNING, "SF/ramtron: unsupported device id0=%02x id1=%02x id2=%02x\n", + idcode[0], idcode[1], idcode[2]); + return NULL; + +found: + sn = malloc(sizeof(*sn)); + if (!sn) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + sn->params = params; + sn->flash.spi = spi; + sn->flash.name = params->name; + + sn->flash.write = ramtron_write; + sn->flash.read = ramtron_read; + sn->flash.erase = ramtron_erase; + sn->flash.size = params->size; + + return &sn->flash; +} diff --git a/src/drivers/spi/spansion.c b/src/drivers/spi/spansion.c new file mode 100644 index 0000000..a4f370a --- /dev/null +++ b/src/drivers/spi/spansion.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2009 Freescale Semiconductor, Inc. + * + * Author: Mingkai Hu (Mingkai.hu at freescale.com) + * Based on stmicro.c by Wolfgang Denk (wd at denx.de), + * TsiChung Liew (Tsi-Chung.Liew at freescale.com), + * and Jason McMullan (mcmullan at netapp.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* S25FLxx-specific commands */ +#define CMD_S25FLXX_READ 0x03 /* Read Data Bytes */ +#define CMD_S25FLXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_S25FLXX_READID 0x90 /* Read Manufacture ID and Device ID */ +#define CMD_S25FLXX_WREN 0x06 /* Write Enable */ +#define CMD_S25FLXX_WRDI 0x04 /* Write Disable */ +#define CMD_S25FLXX_RDSR 0x05 /* Read Status Register */ +#define CMD_S25FLXX_WRSR 0x01 /* Write Status Register */ +#define CMD_S25FLXX_PP 0x02 /* Page Program */ +#define CMD_S25FLXX_SE 0xd8 /* Sector Erase */ +#define CMD_S25FLXX_BE 0xc7 /* Bulk Erase */ +#define CMD_S25FLXX_DP 0xb9 /* Deep Power-down */ +#define CMD_S25FLXX_RES 0xab /* Release from DP, and Read Signature */ + +#define SPSN_ID_S25FL008A 0x0213 +#define SPSN_ID_S25FL016A 0x0214 +#define SPSN_ID_S25FL032A 0x0215 +#define SPSN_ID_S25FL064A 0x0216 +#define SPSN_ID_S25FL128P 0x2018 +#define SPSN_EXT_ID_S25FL128P_256KB 0x0300 +#define SPSN_EXT_ID_S25FL128P_64KB 0x0301 +#define SPSN_EXT_ID_S25FL032P 0x4d00 + +struct spansion_spi_flash_params { + u16 idcode1; + u16 idcode2; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +struct spansion_spi_flash { + struct spi_flash flash; + const struct spansion_spi_flash_params *params; +}; + +static inline struct spansion_spi_flash *to_spansion_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct spansion_spi_flash, flash); +} + +static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { + { + .idcode1 = SPSN_ID_S25FL008A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "S25FL008A", + }, + { + .idcode1 = SPSN_ID_S25FL016A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "S25FL016A", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032A", + }, + { + .idcode1 = SPSN_ID_S25FL064A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "S25FL064A", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_64KB, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 256, + .name = "S25FL128P_64K", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_256KB, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "S25FL128P_256K", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = SPSN_EXT_ID_S25FL032P, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032P", + }, +}; + +static int spansion_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct spansion_spi_flash *spsn = to_spansion_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = spsn->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_S25FLXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_S25FLXX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: SPANSION Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: SPANSION: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int spansion_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_S25FLXX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) +{ + const struct spansion_spi_flash_params *params; + struct spansion_spi_flash *spsn; + unsigned int i; + unsigned short jedec, ext_jedec; + + jedec = idcode[1] << 8 | idcode[2]; + ext_jedec = idcode[3] << 8 | idcode[4]; + + for (i = 0; i < ARRAY_SIZE(spansion_spi_flash_table); i++) { + params = &spansion_spi_flash_table[i]; + if (params->idcode1 == jedec) { + if (params->idcode2 == ext_jedec) + break; + } + } + + if (i == ARRAY_SIZE(spansion_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported SPANSION ID %04x %04x\n", jedec, ext_jedec); + return NULL; + } + + spsn = malloc(sizeof(struct spansion_spi_flash)); + if (!spsn) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + spsn->params = params; + spsn->flash.spi = spi; + spsn->flash.name = params->name; + + spsn->flash.write = spansion_write; + spsn->flash.erase = spansion_erase; + spsn->flash.read = spi_flash_cmd_read_fast; + spsn->flash.sector_size = params->page_size * params->pages_per_sector; + spsn->flash.size = spsn->flash.sector_size * params->nr_sectors; + + return &spsn->flash; +} diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c new file mode 100644 index 0000000..39f577d --- /dev/null +++ b/src/drivers/spi/spi_flash.c @@ -0,0 +1,320 @@ +/* + * SPI flash interface + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include "spi_flash_internal.h" + +static void spi_flash_addr(u32 addr, u8 *cmd) +{ + /* cmd[0] is actual command */ + cmd[1] = addr >> 16; + cmd[2] = addr >> 8; + cmd[3] = addr >> 0; +} + +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) +{ + int ret = spi_xfer(spi, &cmd, 8, response, len * 8); + if (ret) + printk(BIOS_WARNING, "SF: Failed to send command %02x: %d\n", cmd, ret); + + return ret; +} + +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + int ret = spi_xfer(spi, cmd, cmd_len * 8, data, data_len * 8); + if (ret) { + printk(BIOS_WARNING, "SF: Failed to send read command (%zu bytes): %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len) +{ + int ret; + u8 buff[cmd_len + data_len]; + memcpy(buff, cmd, cmd_len); + memcpy(buff + cmd_len, data, data_len); + + ret = spi_xfer(spi, buff, (cmd_len + data_len) * 8, NULL, 0); + if (ret) { + printk(BIOS_WARNING, "SF: Failed to send write command (%zu bytes): %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + struct spi_slave *spi = flash->spi; + int ret; + + spi_claim_bus(spi); + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + spi_release_bus(spi); + + return ret; +} + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[5]; + + cmd[0] = CMD_READ_ARRAY_FAST; + spi_flash_addr(offset, cmd); + cmd[4] = 0x00; + + return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); +} + +int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[4]; + + cmd[0] = CMD_READ_ARRAY_SLOW; + spi_flash_addr(offset, cmd); + + return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); +} + +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 status; + + timebase = timeout; + do { + ret = spi_flash_cmd_read(spi, &cmd, 1, &status, 1); + if (ret) + return -1; + + if ((status & poll_bit) == 0) + break; + + mdelay(1); + } while (timebase--); + + if ((status & poll_bit) == 0) + return 0; + + /* Timed out */ + printk(BIOS_DEBUG, "SF: time out!\n"); + return -1; +} + +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + return spi_flash_cmd_poll_bit(flash, timeout, + CMD_READ_STATUS, STATUS_WIP); +} + +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 offset, size_t len) +{ + u32 start, end, erase_size; + int ret; + u8 cmd[4]; + + erase_size = flash->sector_size; + if (offset % erase_size || len % erase_size) { + printk(BIOS_WARNING, "SF: Erase offset/length not multiple of erase size\n"); + return -1; + } + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + cmd[0] = erase_cmd; + start = offset; + end = start + len; + + while (offset < end) { + spi_flash_addr(offset, cmd); + offset += erase_size; + + printk(BIOS_SPEW, "SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) + goto out; + } + + printk(BIOS_DEBUG, "SF: Successfully erased %zu bytes @ %#x\n", len, start); + + out: + spi_release_bus(flash->spi); + return ret; +} + +/* + * The following table holds all device probe functions + * + * shift: number of continuation bytes before the ID + * idcode: the expected IDCODE or 0xff for non JEDEC devices + * probe: the function to call + * + * Non JEDEC devices should be ordered in the table such that + * the probe functions with best detection algorithms come first. + * + * Several matching entries are permitted, they will be tried + * in sequence until a probe function returns non NULL. + * + * IDCODE_CONT_LEN may be redefined if a device needs to declare a + * larger "shift" value. IDCODE_PART_LEN generally shouldn't be + * changed. This is the max number of bytes probe functions may + * examine when looking up part-specific identification info. + * + * Probe functions will be given the idcode buffer starting at their + * manu id byte (the "idcode" in the table below). In other words, + * all of the continuation bytes will be skipped (the "shift" below). + */ +#define IDCODE_CONT_LEN 0 +#define IDCODE_PART_LEN 5 +static const struct { + const u8 shift; + const u8 idcode; + struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); +} flashes[] = { + /* Keep it sorted by define name */ +#ifdef CONFIG_SPI_FLASH_ATMEL + { 0, 0x1f, spi_flash_probe_atmel, }, +#endif +#ifdef CONFIG_SPI_FLASH_EON + { 0, 0x1c, spi_flash_probe_eon, }, +#endif +#ifdef CONFIG_SPI_FLASH_MACRONIX + { 0, 0xc2, spi_flash_probe_macronix, }, +#endif +#ifdef CONFIG_SPI_FLASH_SPANSION + { 0, 0x01, spi_flash_probe_spansion, }, +#endif +#ifdef CONFIG_SPI_FLASH_SST + { 0, 0xbf, spi_flash_probe_sst, }, +#endif +#ifdef CONFIG_SPI_FLASH_STMICRO + { 0, 0x20, spi_flash_probe_stmicro, }, +#endif +#ifdef CONFIG_SPI_FLASH_WINBOND + { 0, 0xef, spi_flash_probe_winbond, }, +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON + { 6, 0xc2, spi_fram_probe_ramtron, }, +# undef IDCODE_CONT_LEN +# define IDCODE_CONT_LEN 6 +#endif + /* Keep it sorted by best detection */ +#ifdef CONFIG_SPI_FLASH_STMICRO + { 0, 0xff, spi_flash_probe_stmicro, }, +#endif +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + { 0, 0xff, spi_fram_probe_ramtron, }, +#endif +}; +#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_slave *spi; + struct spi_flash *flash = NULL; + int ret, i, shift; + u8 idcode[IDCODE_LEN], *idp; + + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); + if (!spi) { + printk(BIOS_WARNING, "SF: Failed to set up slave\n"); + return NULL; + } + + ret = spi_claim_bus(spi); + if (ret) { + printk(BIOS_WARNING, "SF: Failed to claim SPI bus: %d\n", ret); + goto err_claim_bus; + } + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); + if (ret) + goto err_read_id; + +#ifdef DEBUG + printk(BIOS_SPEW, "SF: Got idcodes\n"); + print_buffer(0, idcode, 1, sizeof(idcode), 0); +#endif + + /* count the number of continuation bytes */ + for (shift = 0, idp = idcode; + shift < IDCODE_CONT_LEN && *idp == 0x7f; + ++shift, ++idp) + continue; + + /* search the table for matches in shift and id */ + for (i = 0; i < ARRAY_SIZE(flashes); ++i) + if (flashes[i].shift == shift && flashes[i].idcode == *idp) { + /* we have a match, call probe */ + flash = flashes[i].probe(spi, idp); + if (flash) + break; + } + + if (!flash) { + printk(BIOS_WARNING, "SF: Unsupported manufacturer %02x\n", *idp); + goto err_manufacturer_probe; + } + + printk(BIOS_INFO, "SF: Detected %s with page size %x, total %x\n", + flash->name, flash->sector_size, flash->size); + + spi_release_bus(spi); + + return flash; + +err_manufacturer_probe: +err_read_id: + spi_release_bus(spi); +err_claim_bus: + spi_free_slave(spi); + return NULL; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_free_slave(flash->spi); + free(flash); +} diff --git a/src/drivers/spi/spi_flash_internal.h b/src/drivers/spi/spi_flash_internal.h new file mode 100644 index 0000000..b895e2b --- /dev/null +++ b/src/drivers/spi/spi_flash_internal.h @@ -0,0 +1,81 @@ +/* + * SPI flash internal definitions + * + * Copyright (C) 2008 Atmel Corporation + */ + +/* Common parameters -- kind of high, but they should only occur when there + * is a problem (and well your system already is broken), so err on the side + * of caution in case we're dealing with slower SPI buses and/or processors. + */ +#define CONFIG_SYS_HZ 100 +#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) +#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) +#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) + +/* Common commands */ +#define CMD_READ_ID 0x9f + +#define CMD_READ_ARRAY_SLOW 0x03 +#define CMD_READ_ARRAY_FAST 0x0b +#define CMD_READ_ARRAY_LEGACY 0xe8 + +#define CMD_READ_STATUS 0x05 +#define CMD_WRITE_ENABLE 0x06 + +/* Common status */ +#define STATUS_WIP 0x01 + +/* Send a single-byte command to the device and read the response */ +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); + +/* + * Send a multi-byte command to the device and read the response. Used + * for flash array reads, etc. + */ +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +/* + * Send a multi-byte command to the device followed by (optional) + * data. Used for programming the flash array, etc. + */ +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len); + +/* + * Same as spi_flash_cmd_read() except it also claims/releases the SPI + * bus. Used as common part of the ->read() operation. + */ +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* Send a command to the device and wait for some bit to clear itself. */ +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit); + +/* + * Send the read status command to the device and wait for the wip + * (write-in-progress) bit to clear itself. + */ +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); + +/* Erase sectors. */ +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 offset, size_t len); + +/* Manufacturer-specific probe functions */ +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode); diff --git a/src/drivers/spi/sst.c b/src/drivers/spi/sst.c new file mode 100644 index 0000000..56cc851 --- /dev/null +++ b/src/drivers/spi/sst.c @@ -0,0 +1,268 @@ +/* + * Driver for SST serial flashes + * + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd at denx.de. + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +#define CMD_SST_WREN 0x06 /* Write Enable */ +#define CMD_SST_WRDI 0x04 /* Write Disable */ +#define CMD_SST_RDSR 0x05 /* Read Status Register */ +#define CMD_SST_WRSR 0x01 /* Write Status Register */ +#define CMD_SST_READ 0x03 /* Read Data Bytes */ +#define CMD_SST_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_SST_BP 0x02 /* Byte Program */ +#define CMD_SST_AAI_WP 0xAD /* Auto Address Increment Word Program */ +#define CMD_SST_SE 0x20 /* Sector Erase */ + +#define SST_SR_WIP (1 << 0) /* Write-in-Progress */ +#define SST_SR_WEL (1 << 1) /* Write enable */ +#define SST_SR_BP0 (1 << 2) /* Block Protection 0 */ +#define SST_SR_BP1 (1 << 3) /* Block Protection 1 */ +#define SST_SR_BP2 (1 << 4) /* Block Protection 2 */ +#define SST_SR_AAI (1 << 6) /* Addressing mode */ +#define SST_SR_BPL (1 << 7) /* BP bits lock */ + +struct sst_spi_flash_params { + u8 idcode1; + u16 nr_sectors; + const char *name; +}; + +struct sst_spi_flash { + struct spi_flash flash; + const struct sst_spi_flash_params *params; +}; + +static inline struct sst_spi_flash *to_sst_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct sst_spi_flash, flash); +} + +#define SST_SECTOR_SIZE (4 * 1024) +static const struct sst_spi_flash_params sst_spi_flash_table[] = { + { + .idcode1 = 0x8d, + .nr_sectors = 128, + .name = "SST25VF040B", + },{ + .idcode1 = 0x8e, + .nr_sectors = 256, + .name = "SST25VF080B", + },{ + .idcode1 = 0x41, + .nr_sectors = 512, + .name = "SST25VF016B", + },{ + .idcode1 = 0x4a, + .nr_sectors = 1024, + .name = "SST25VF032B", + },{ + .idcode1 = 0x4b, + .nr_sectors = 2048, + .name = "SST25VF064C", + },{ + .idcode1 = 0x01, + .nr_sectors = 16, + .name = "SST25WF512", + },{ + .idcode1 = 0x02, + .nr_sectors = 32, + .name = "SST25WF010", + },{ + .idcode1 = 0x03, + .nr_sectors = 64, + .name = "SST25WF020", + },{ + .idcode1 = 0x04, + .nr_sectors = 128, + .name = "SST25WF040", + }, +}; + +static int +sst_enable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WREN, NULL, 0); + if (ret) + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + return ret; +} + +static int +sst_disable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WRDI, NULL, 0); + if (ret) + printk(BIOS_WARNING, "SF: Disabling Write failed\n"); + return ret; +} + +static int +sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) +{ + int ret; + u8 cmd[4] = { + CMD_SST_BP, + offset >> 16, + offset >> 8, + offset, + }; + + printk(BIOS_SPEW, "BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf, cmd[0], offset); + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); + if (ret) + return ret; + + return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); +} + +static int +sst_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) +{ + size_t actual, cmd_len; + int ret; + u8 cmd[4]; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + /* If the data is not word aligned, write out leading single byte */ + actual = offset % 2; + if (actual) { + ret = sst_byte_write(flash, offset, buf); + if (ret) + goto done; + } + offset += actual; + + ret = sst_enable_writing(flash); + if (ret) + goto done; + + cmd_len = 4; + cmd[0] = CMD_SST_AAI_WP; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + + for (; actual < len - 1; actual += 2) { + printk(BIOS_SPEW, "WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf + actual, cmd[0], + offset); + + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, + buf + actual, 2); + if (ret) { + printk(BIOS_WARNING, "SF: SST word program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + cmd_len = 1; + offset += 2; + } + + if (!ret) + ret = sst_disable_writing(flash); + + /* If there is a single trailing byte, write it out */ + if (!ret && actual != len) + ret = sst_byte_write(flash, offset, buf + actual); + + done: + printk(BIOS_INFO, "SF: SST: program %s %zu bytes @ 0x%lx\n", + ret ? "failure" : "success", len, offset - actual); + + spi_release_bus(flash->spi); + return ret; +} + +static int sst_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_SST_SE, offset, len); +} + +static int +sst_unlock(struct spi_flash *flash) +{ + int ret; + u8 cmd, status; + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + cmd = CMD_SST_WRSR; + status = 0; + ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &status, 1); + if (ret) + printk(BIOS_WARNING, "SF: Unable to set status byte\n"); + + printk(BIOS_INFO, "SF: SST: status = %x\n", spi_w8r8(flash->spi, CMD_SST_RDSR)); + + return ret; +} + +struct spi_flash * +spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode) +{ + const struct sst_spi_flash_params *params; + struct sst_spi_flash *stm; + size_t i; + + for (i = 0; i < ARRAY_SIZE(sst_spi_flash_table); ++i) { + params = &sst_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(sst_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported SST ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(*stm)); + if (!stm) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = sst_write; + stm->flash.erase = sst_erase; + stm->flash.read = spi_flash_cmd_read_fast; + stm->flash.sector_size = SST_SECTOR_SIZE; + stm->flash.size = stm->flash.sector_size * params->nr_sectors; + + /* Flash powers up read-only, so clear BP# bits */ + sst_unlock(&stm->flash); + + return &stm->flash; +} diff --git a/src/drivers/spi/stmicro.c b/src/drivers/spi/stmicro.c new file mode 100644 index 0000000..8cbdad5 --- /dev/null +++ b/src/drivers/spi/stmicro.c @@ -0,0 +1,250 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd at denx.de. + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_M25PXX_WREN 0x06 /* Write Enable */ +#define CMD_M25PXX_WRDI 0x04 /* Write Disable */ +#define CMD_M25PXX_RDSR 0x05 /* Read Status Register */ +#define CMD_M25PXX_WRSR 0x01 /* Write Status Register */ +#define CMD_M25PXX_READ 0x03 /* Read Data Bytes */ +#define CMD_M25PXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_M25PXX_PP 0x02 /* Page Program */ +#define CMD_M25PXX_SE 0xd8 /* Sector Erase */ +#define CMD_M25PXX_BE 0xc7 /* Bulk Erase */ +#define CMD_M25PXX_DP 0xb9 /* Deep Power-down */ +#define CMD_M25PXX_RES 0xab /* Release from DP, and Read Signature */ + +#define STM_ID_M25P10 0x11 +#define STM_ID_M25P16 0x15 +#define STM_ID_M25P20 0x12 +#define STM_ID_M25P32 0x16 +#define STM_ID_M25P40 0x13 +#define STM_ID_M25P64 0x17 +#define STM_ID_M25P80 0x14 +#define STM_ID_M25P128 0x18 + +struct stmicro_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct stmicro_spi_flash { + struct spi_flash flash; + const struct stmicro_spi_flash_params *params; +}; + +static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct stmicro_spi_flash, flash); +} + +static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { + { + .idcode1 = STM_ID_M25P10, + .page_size = 256, + .pages_per_sector = 128, + .nr_sectors = 4, + .name = "M25P10", + }, + { + .idcode1 = STM_ID_M25P16, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "M25P16", + }, + { + .idcode1 = STM_ID_M25P20, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 4, + .name = "M25P20", + }, + { + .idcode1 = STM_ID_M25P32, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "M25P32", + }, + { + .idcode1 = STM_ID_M25P40, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 8, + .name = "M25P40", + }, + { + .idcode1 = STM_ID_M25P64, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "M25P64", + }, + { + .idcode1 = STM_ID_M25P80, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "M25P80", + }, + { + .idcode1 = STM_ID_M25P128, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "M25P128", + }, +}; + +static int stmicro_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = stm->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_M25PXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: STMicro Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: STMicro: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_M25PXX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) +{ + const struct stmicro_spi_flash_params *params; + struct stmicro_spi_flash *stm; + unsigned int i; + + if (idcode[0] == 0xff) { + i = spi_flash_cmd(spi, CMD_M25PXX_RES, + idcode, 4); + if (i) + return NULL; + if ((idcode[3] & 0xf0) == 0x10) { + idcode[0] = 0x20; + idcode[1] = 0x20; + idcode[2] = idcode[3] + 1; + } else + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) { + params = &stmicro_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) { + break; + } + } + + if (i == ARRAY_SIZE(stmicro_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported STMicro ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(struct stmicro_spi_flash)); + if (!stm) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = stmicro_write; + stm->flash.erase = stmicro_erase; + stm->flash.read = spi_flash_cmd_read_fast; + stm->flash.sector_size = params->page_size * params->pages_per_sector; + stm->flash.size = stm->flash.sector_size * params->nr_sectors; + + return &stm->flash; +} diff --git a/src/drivers/spi/winbond.c b/src/drivers/spi/winbond.c new file mode 100644 index 0000000..65818d5 --- /dev/null +++ b/src/drivers/spi/winbond.c @@ -0,0 +1,218 @@ +/* + * Copyright 2008, Network Appliance Inc. + * Author: Jason McMullan netapp.com> + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_W25_WREN 0x06 /* Write Enable */ +#define CMD_W25_WRDI 0x04 /* Write Disable */ +#define CMD_W25_RDSR 0x05 /* Read Status Register */ +#define CMD_W25_WRSR 0x01 /* Write Status Register */ +#define CMD_W25_READ 0x03 /* Read Data Bytes */ +#define CMD_W25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_W25_PP 0x02 /* Page Program */ +#define CMD_W25_SE 0x20 /* Sector (4K) Erase */ +#define CMD_W25_BE 0xd8 /* Block (64K) Erase */ +#define CMD_W25_CE 0xc7 /* Chip Erase */ +#define CMD_W25_DP 0xb9 /* Deep Power-down */ +#define CMD_W25_RES 0xab /* Release from DP, and Read Signature */ + +struct winbond_spi_flash_params { + uint16_t id; + /* Log2 of page size in power-of-two mode */ + uint8_t l2_page_size; + uint16_t pages_per_sector; + uint16_t sectors_per_block; + uint16_t nr_blocks; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct winbond_spi_flash { + struct spi_flash flash; + const struct winbond_spi_flash_params *params; +}; + +static inline struct winbond_spi_flash * +to_winbond_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct winbond_spi_flash, flash); +} + +static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { + { + .id = 0x3015, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "W25X16", + }, + { + .id = 0x3016, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "W25X32", + }, + { + .id = 0x3017, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "W25X64", + }, + { + .id = 0x4015, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "W25Q16", + }, + { + .id = 0x4016, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "W25Q32", + }, + { + .id = 0x4017, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "W25Q64", + }, + { + .id = 0x4018, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "W25Q128", + }, +}; + +static int winbond_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct winbond_spi_flash *stm = to_winbond_spi_flash(flash); + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT); + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_W25_PP; + cmd[1] = (offset >> 16) & 0xff; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %ld\n", + buf + actual, + cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_W25_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + goto out; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Winbond Page Program failed\n"); + goto out; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + goto out; + + offset += chunk_len; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: Winbond: Successfully programmed %zu bytes @ 0x%lx\n", + len, offset - len); + ret = 0; + +out: + spi_release_bus(flash->spi); + return ret; +} + +static int winbond_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_W25_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) +{ + const struct winbond_spi_flash_params *params; + unsigned page_size; + struct winbond_spi_flash *stm; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(winbond_spi_flash_table); i++) { + params = &winbond_spi_flash_table[i]; + if (params->id == ((idcode[1] << 8) | idcode[2])) + break; + } + + if (i == ARRAY_SIZE(winbond_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported Winbond ID %02x%02x\n", + idcode[1], idcode[2]); + return NULL; + } + + stm = malloc(sizeof(struct winbond_spi_flash)); + if (!stm) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + /* Assuming power-of-two page size initially. */ + page_size = 1 << params->l2_page_size; + + stm->flash.write = winbond_write; + stm->flash.erase = winbond_erase; +#ifdef CONFIG_SPI_FLASH_NO_FAST_READ + stm->flash.read = spi_flash_cmd_read_slow; +#else + stm->flash.read = spi_flash_cmd_read_fast; +#endif + stm->flash.sector_size = (1 << stm->params->l2_page_size) * + stm->params->pages_per_sector; + stm->flash.size = page_size * params->pages_per_sector + * params->sectors_per_block + * params->nr_blocks; + + return &stm->flash; +} diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h index a2d6884..1765293 100644 --- a/src/include/device/pci_ids.h +++ b/src/include/device/pci_ids.h @@ -2502,6 +2502,10 @@ #define PCI_DEVICE_ID_INTEL_82801IO_LPC 0x2914 #define PCI_DEVICE_ID_INTEL_82801IH_LPC 0x2912 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f +#define PCI_DEVICE_ID_INTEL_TGP_LPC 0x27bc + /* Intel 82801E (C-ICH) */ #define PCI_DEVICE_ID_INTEL_82801E_LPC 0x2450 #define PCI_DEVICE_ID_INTEL_82801E_USB 0x2452 diff --git a/src/include/spi.h b/src/include/spi.h new file mode 100644 index 0000000..bb84258 --- /dev/null +++ b/src/include/spi.h @@ -0,0 +1,203 @@ +/* + * (C) Copyright 2001 + * Gerald Van Baren, Custom IDEAS, vanbaren at cideas.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _SPI_H_ +#define _SPI_H_ + +#include + +/* Controller-specific definitions: */ + +/* SPI mode flags */ +#define SPI_CPHA 0x01 /* clock phase */ +#define SPI_CPOL 0x02 /* clock polarity */ +#define SPI_MODE_0 (0|0) /* (original MicroWire) */ +#define SPI_MODE_1 (0|SPI_CPHA) +#define SPI_MODE_2 (SPI_CPOL|0) +#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) +#define SPI_CS_HIGH 0x04 /* CS active high */ +#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ +#define SPI_3WIRE 0x10 /* SI/SO signals shared */ +#define SPI_LOOP 0x20 /* loopback mode */ + +/* SPI transfer flags */ +#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ +#define SPI_XFER_END 0x02 /* Deassert CS after transfer */ + +/*----------------------------------------------------------------------- + * Representation of a SPI slave, i.e. what we're communicating with. + * + * Drivers are expected to extend this with controller-specific data. + * + * bus: ID of the bus that the slave is attached to. + * cs: ID of the chip select connected to the slave. + */ +struct spi_slave { + unsigned int bus; + unsigned int cs; +}; + +/*----------------------------------------------------------------------- + * Initialization, must be called once on start up. + * + * TODO: I don't think we really need this. + */ +void spi_init(void); + +/*----------------------------------------------------------------------- + * Set up communications parameters for a SPI slave. + * + * This must be called once for each slave. Note that this function + * usually doesn't touch any actual hardware, it only initializes the + * contents of spi_slave so that the hardware can be easily + * initialized later. + * + * bus: Bus ID of the slave chip. + * cs: Chip select ID of the slave chip on the specified bus. + * max_hz: Maximum SCK rate in Hz. + * mode: Clock polarity, clock phase and other parameters. + * + * Returns: A spi_slave reference that can be used in subsequent SPI + * calls, or NULL if one or more of the parameters are not supported. + */ +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode); + +/*----------------------------------------------------------------------- + * Free any memory associated with a SPI slave. + * + * slave: The SPI slave + */ +void spi_free_slave(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Claim the bus and prepare it for communication with a given slave. + * + * This must be called before doing any transfers with a SPI slave. It + * will enable and initialize any SPI hardware as necessary, and make + * sure that the SCK line is in the correct idle state. It is not + * allowed to claim the same bus for several slaves without releasing + * the bus in between. + * + * slave: The SPI slave + * + * Returns: 0 if the bus was claimed successfully, or a negative value + * if it wasn't. + */ +int spi_claim_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Release the SPI bus + * + * This must be called once for every call to spi_claim_bus() after + * all transfers have finished. It may disable any SPI hardware as + * appropriate. + * + * slave: The SPI slave + */ +void spi_release_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * SPI transfer + * + * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks + * "bitlen" bits in the SPI MISO port. That's just the way SPI works. + * + * The source of the outgoing bits is the "dout" parameter and the + * destination of the input bits is the "din" parameter. Note that "dout" + * and "din" can point to the same memory location, in which case the + * input data overwrites the output data (since both are buffered by + * temporary variables, this is OK). + * + * spi_xfer() interface: + * slave: The SPI slave which will be sending/receiving the data. + * dout: Pointer to a string of bits to send out. The bits are + * held in a byte array and are sent MSB first. + * bitsout: How many bits to write. + * din: Pointer to a string of bits that will be filled in. + * bitsin: How many bits to read. + * + * Returns: 0 on success, not 0 on failure + */ +int spi_xfer(struct spi_slave *slave, const void *dout, unsigned int bitsout, + void *din, unsigned int bitsin); + +/*----------------------------------------------------------------------- + * Determine if a SPI chipselect is valid. + * This function is provided by the board if the low-level SPI driver + * needs it to determine if a given chipselect is actually valid. + * + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 + * otherwise. + */ +int spi_cs_is_valid(unsigned int bus, unsigned int cs); + +/*----------------------------------------------------------------------- + * Activate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should activate the chip select + * to the device identified by "slave". + */ +void spi_cs_activate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Deactivate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should deactivate the chip + * select to the device identified by "slave". + */ +void spi_cs_deactivate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Set transfer speed. + * This sets a new speed to be applied for next spi_xfer(). + * slave: The SPI slave + * hz: The transfer speed + */ +void spi_set_speed(struct spi_slave *slave, uint32_t hz); + +/*----------------------------------------------------------------------- + * Write 8 bits, then read 8 bits. + * slave: The SPI slave we're communicating with + * byte: Byte to be written + * + * Returns: The value that was read, or a negative value on error. + * + * TODO: This function probably shouldn't be inlined. + */ +static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) +{ + unsigned char dout[2]; + unsigned char din[2]; + int ret; + + dout[0] = byte; + dout[1] = 0; + + ret = spi_xfer(slave, dout, 16, din, 16); + return ret < 0 ? ret : din[1]; +} + +#endif /* _SPI_H_ */ diff --git a/src/include/spi_flash.h b/src/include/spi_flash.h new file mode 100644 index 0000000..2a1dcd4 --- /dev/null +++ b/src/include/spi_flash.h @@ -0,0 +1,91 @@ +/* + * Interface to SPI flash + * + * Copyright (C) 2008 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _SPI_FLASH_H_ +#define _SPI_FLASH_H_ + +#include +#include +#include +#include + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define min(a, b) ((a)<(b)?(a):(b)) + +#define CONFIG_ICH_SPI +#ifdef CONFIG_ICH_SPI +#define CONTROLLER_PAGE_LIMIT 64 +#else +/* any number larger than 4K would do, actually */ +#define CONTROLLER_PAGE_LIMIT ((int)(~0U>>1)) +#endif + +struct spi_flash { + struct spi_slave *spi; + + const char *name; + + u32 size; + + u32 sector_size; + + int (*read)(struct spi_flash *flash, u32 offset, + size_t len, void *buf); + int (*write)(struct spi_flash *flash, u32 offset, + size_t len, const void *buf); + int (*erase)(struct spi_flash *flash, u32 offset, + size_t len); +}; + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode); +void spi_flash_free(struct spi_flash *flash); + +static inline int spi_flash_read(struct spi_flash *flash, u32 offset, + size_t len, void *buf) +{ + return flash->read(flash, offset, len, buf); +} + +static inline int spi_flash_write(struct spi_flash *flash, u32 offset, + size_t len, const void *buf) +{ + return flash->write(flash, offset, len, buf); +} + +static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, + size_t len) +{ + return flash->erase(flash, offset, len); +} + +#endif /* _SPI_FLASH_H_ */ diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 8209980..6548b32 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -340,6 +340,7 @@ void sdram_initialize(struct pei_data *pei_data) /* If MRC data is not found we cannot continue S3 resume. */ if (pei_data->boot_mode == 2 && !pei_data->mrc_input) { + printk(BIOS_DEBUG, "Giving up in sdram_initialize: No MRC data\n"); outb(0x6, 0xcf9); hlt(); } diff --git a/src/southbridge/intel/bd82x6x/Kconfig b/src/southbridge/intel/bd82x6x/Kconfig index 3891be1..f105ee3 100644 --- a/src/southbridge/intel/bd82x6x/Kconfig +++ b/src/southbridge/intel/bd82x6x/Kconfig @@ -33,6 +33,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy select USE_WATCHDOG_ON_BOOT select PCIEXP_ASPM select PCIEXP_COMMON_CLOCK + select SPI config EHCI_BAR hex diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc index 5732254..f086426 100644 --- a/src/southbridge/intel/bd82x6x/Makefile.inc +++ b/src/southbridge/intel/bd82x6x/Makefile.inc @@ -34,6 +34,8 @@ ramstage-y += me_status.c ramstage-y += reset.c ramstage-y += watchdog.c +ramstage-y += spi.c + ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c $(me-src-y) finalize.c diff --git a/src/southbridge/intel/bd82x6x/spi.c b/src/southbridge/intel/bd82x6x/spi.c new file mode 100644 index 0000000..c54a325 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/spi.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* This file is derived from the flashrom project. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define min(a, b) ((a)<(b)?(a):(b)) + +typedef device_t pci_dev_t; +#define pci_read_config_byte(dev, reg, targ) *(targ) = pci_read_config8(dev, reg) +#define pci_read_config_word(dev, reg, targ) *(targ) = pci_read_config16(dev, reg) +#define pci_read_config_dword(dev, reg, targ) *(targ) = pci_read_config32(dev, reg) +#define pci_write_config_byte(dev, reg, val) pci_write_config8(dev, reg, val) +#define pci_write_config_word(dev, reg, val) pci_write_config16(dev, reg, val) +#define pci_write_config_dword(dev, reg, val) pci_write_config32(dev, reg, val) + +typedef struct spi_slave ich_spi_slave; + +static int ichspi_lock = 0; + +typedef struct ich7_spi_regs { + uint16_t spis; + uint16_t spic; + uint32_t spia; + uint64_t spid[8]; + uint64_t _pad; + uint32_t bbar; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; +} __attribute__((packed)) ich7_spi_regs; + +typedef struct ich9_spi_regs { + uint32_t bfpr; + uint16_t hsfs; + uint16_t hsfc; + uint32_t faddr; + uint32_t _reserved0; + uint32_t fdata[16]; + uint32_t frap; + uint32_t freg[5]; + uint32_t _reserved1[3]; + uint32_t pr[5]; + uint32_t _reserved2[2]; + uint8_t ssfs; + uint8_t ssfc[3]; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; + uint32_t bbar; + uint8_t _reserved3[12]; + uint32_t fdoc; + uint32_t fdod; + uint8_t _reserved4[8]; + uint32_t afc; + uint32_t lvscc; + uint32_t uvscc; + uint8_t _reserved5[4]; + uint32_t fpb; + uint8_t _reserved6[28]; + uint32_t srdl; + uint32_t srdc; + uint32_t srd; +} __attribute__((packed)) ich9_spi_regs; + +typedef struct ich_spi_controller { + int locked; + + uint8_t *opmenu; + int menubytes; + uint16_t *preop; + uint16_t *optype; + uint32_t *addr; + uint8_t *data; + unsigned databytes; + uint8_t *status; + uint16_t *control; + uint32_t *bbar; +} ich_spi_controller; + +static ich_spi_controller cntlr; + +enum { + SPIS_SCIP = 0x0001, + SPIS_GRANT = 0x0002, + SPIS_CDS = 0x0004, + SPIS_FCERR = 0x0008, + SSFS_AEL = 0x0010, + SPIS_LOCK = 0x8000, + SPIS_RESERVED_MASK = 0x7ff0, + SSFS_RESERVED_MASK = 0x7fe2 +}; + +enum { + SPIC_SCGO = 0x000002, + SPIC_ACS = 0x000004, + SPIC_SPOP = 0x000008, + SPIC_DBC = 0x003f00, + SPIC_DS = 0x004000, + SPIC_SME = 0x008000, + SSFC_SCF_MASK = 0x070000, + SSFC_RESERVED = 0xf80000 +}; + +enum { + HSFS_FDONE = 0x0001, + HSFS_FCERR = 0x0002, + HSFS_AEL = 0x0004, + HSFS_BERASE_MASK = 0x0018, + HSFS_BERASE_SHIFT = 3, + HSFS_SCIP = 0x0020, + HSFS_FDOPSS = 0x2000, + HSFS_FDV = 0x4000, + HSFS_FLOCKDN = 0x8000 +}; + +enum { + HSFC_FGO = 0x0001, + HSFC_FCYCLE_MASK = 0x0006, + HSFC_FCYCLE_SHIFT = 1, + HSFC_FDBC_MASK = 0x3f00, + HSFC_FDBC_SHIFT = 8, + HSFC_FSMIE = 0x8000 +}; + +enum { + SPI_OPCODE_TYPE_READ_NO_ADDRESS = 0, + SPI_OPCODE_TYPE_WRITE_NO_ADDRESS = 1, + SPI_OPCODE_TYPE_READ_WITH_ADDRESS = 2, + SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS = 3 +}; + +#ifdef DEBUG + +static u8 readb_(const void *addr) +{ + u8 v = readb(addr); + printk(BIOS_DEBUG, "read %2.2x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u16 readw_(const void *addr) +{ + u16 v = readw(addr); + printk(BIOS_DEBUG, "read %4.4x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u32 readl_(const void *addr) +{ + u32 v = readl(addr); + printk(BIOS_DEBUG, "read %8.8x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static void writeb_(u8 b, const void *addr) +{ + writeb(b, addr); + printk(BIOS_DEBUG, "wrote %2.2x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writew_(u16 b, const void *addr) +{ + writew(b, addr); + printk(BIOS_DEBUG, "wrote %4.4x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writel_(u32 b, const void *addr) +{ + writel(b, addr); + printk(BIOS_DEBUG, "wrote %8.8x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +#else /* DEBUG ^^^ defined vvv NOT defined */ + +#define readb_(a) read8((uint32_t)a) +#define readw_(a) read16((uint32_t)a) +#define readl_(a) read32((uint32_t)a) +#define writeb_(val, addr) write8((uint32_t)addr, val) +#define writew_(val, addr) write16((uint32_t)addr, val) +#define writel_(val, addr) write32((uint32_t)addr, val) + +#endif /* DEBUG ^^^ NOT defined */ + +static void write_reg(const void *value, void *dest, uint32_t size) +{ + const uint8_t *bvalue = value; + uint8_t *bdest = dest; + + while (size >= 4) { + writel_(*(const uint32_t *)bvalue, bdest); + bdest += 4; bvalue += 4; size -= 4; + } + while (size) { + writeb_(*bvalue, bdest); + bdest++; bvalue++; size--; + } +} + +static void read_reg(const void *src, void *value, uint32_t size) +{ + const uint8_t *bsrc = src; + uint8_t *bvalue = value; + + while (size >= 4) { + *(uint32_t *)bvalue = readl_(bsrc); + bsrc += 4; bvalue += 4; size -= 4; + } + while (size) { + *bvalue = readb_(bsrc); + bsrc++; bvalue++; size--; + } +} + +static void ich_set_bbar(uint32_t minaddr) +{ + const uint32_t bbar_mask = 0x00ffff00; + uint32_t ichspi_bbar; + + minaddr &= bbar_mask; + ichspi_bbar = readl_(cntlr.bbar) & ~bbar_mask; + ichspi_bbar |= minaddr; + writel_(ichspi_bbar, cntlr.bbar); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + printk(BIOS_DEBUG, "spi_cs_is_valid used but not implemented\n"); + return 0; +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + ich_spi_slave *slave = malloc(sizeof(*slave)); + + if (!slave) { + printk(BIOS_DEBUG, "ICH SPI: Bad allocation\n"); + return NULL; + } + + memset(slave, 0, sizeof(*slave)); + + slave->bus = bus; + slave->cs = cs; + return slave; +} + +void spi_free_slave(struct spi_slave *_slave) +{ + ich_spi_slave *slave = (ich_spi_slave *)_slave; + free(slave); +} + +static inline int spi_is_cougarpoint_lpc(uint16_t device_id) +{ + return device_id >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN && + device_id <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX; +}; + +void spi_init(void) +{ + int ich_version = 0; + + uint8_t *rcrb; /* Root Complex Register Block */ + uint32_t rcba; /* Root Complex Base Address */ + uint8_t bios_cntl; + pci_dev_t dev; + + int bus; + int last_bus = 1; //FIXME: pci_last_busno(); + + if (last_bus == -1) { + printk(BIOS_DEBUG, "No PCI busses?\n"); + return; + } + + for (bus = 0; bus <= last_bus; bus++) { + uint32_t ids; + uint16_t vendor_id, device_id; + + dev = dev_find_slot(bus, PCI_DEVFN(31, 0)); + pci_read_config_dword(dev, 0, &ids); + vendor_id = ids; + device_id = (ids >> 16); + + if (vendor_id != PCI_VENDOR_ID_INTEL) + continue; + + if (device_id == PCI_DEVICE_ID_INTEL_TGP_LPC) { + ich_version = 7; + break; + } else if (spi_is_cougarpoint_lpc(device_id)) { + ich_version = 9; + break; + } + } + + if (!ich_version) { + printk(BIOS_DEBUG, "ICH SPI: No ICH found.\n"); + return; + } + + pci_read_config_dword(dev, 0xf0, &rcba); + /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable. */ + rcrb = (uint8_t *)(rcba & 0xffffc000); + switch (ich_version) { + case 7: + { + const uint16_t ich7_spibar_offset = 0x3020; + ich7_spi_regs *ich7_spi = + (ich7_spi_regs *)(rcrb + ich7_spibar_offset); + + ichspi_lock = readw_(&ich7_spi->spis) & SPIS_LOCK; + cntlr.opmenu = ich7_spi->opmenu; + cntlr.menubytes = sizeof(ich7_spi->opmenu); + cntlr.optype = &ich7_spi->optype; + cntlr.addr = &ich7_spi->spia; + cntlr.data = (uint8_t *)ich7_spi->spid; + cntlr.databytes = sizeof(ich7_spi->spid); + cntlr.status = (uint8_t *)&ich7_spi->spis; + cntlr.control = &ich7_spi->spic; + cntlr.bbar = &ich7_spi->bbar; + cntlr.preop = &ich7_spi->preop; + break; + } + case 9: + { + const uint16_t ich9_spibar_offset = 0x3800; + ich9_spi_regs *ich9_spi = + (ich9_spi_regs *)(rcrb + ich9_spibar_offset); + ichspi_lock = readw_(&ich9_spi->hsfs) & HSFS_FLOCKDN; + cntlr.opmenu = ich9_spi->opmenu; + cntlr.menubytes = sizeof(ich9_spi->opmenu); + cntlr.optype = &ich9_spi->optype; + cntlr.addr = &ich9_spi->faddr; + cntlr.data = (uint8_t *)ich9_spi->fdata; + cntlr.databytes = sizeof(ich9_spi->fdata); + cntlr.status = &ich9_spi->ssfs; + cntlr.control = (uint16_t *)ich9_spi->ssfc; + cntlr.bbar = &ich9_spi->bbar; + cntlr.preop = &ich9_spi->preop; + break; + } + default: + printk(BIOS_DEBUG, "ICH SPI: Unrecognized ICH version %d.\n", ich_version); + } + + ich_set_bbar(0); + + /* Disable the BIOS write protect so write commands are allowed. */ + pci_read_config_byte(dev, 0xdc, &bios_cntl); + switch (ich_version) { + case 9: + /* Deassert SMM BIOS Write Protect Disable. */ + bios_cntl &= ~(1 << 5); + break; + + default: + break; + } + pci_write_config_byte(dev, 0xdc, bios_cntl | 0x1); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_activate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +typedef struct spi_transaction { + const uint8_t *out; + uint32_t bytesout; + uint8_t *in; + uint32_t bytesin; + uint8_t type; + uint8_t opcode; + uint32_t offset; +} spi_transaction; + +static inline void spi_use_out(spi_transaction *trans, unsigned bytes) +{ + trans->out += bytes; + trans->bytesout -= bytes; +} + +static inline void spi_use_in(spi_transaction *trans, unsigned bytes) +{ + trans->in += bytes; + trans->bytesin -= bytes; +} + +static void spi_setup_type(spi_transaction *trans) +{ + trans->type = 0xFF; + + /* Try to guess spi type from read/write sizes. */ + if (trans->bytesin == 0) { + if (trans->bytesout > 4) + /* + * If bytesin = 0 and bytesout > 4, we presume this is + * a write data operation, which is accompanied by an + * address. + */ + trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS; + else + trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS; + return; + } + + if (trans->bytesout == 1) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS; + return; + } + + if (trans->bytesout == 4) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS; + } +} + +static int spi_setup_opcode(spi_transaction *trans) +{ + uint16_t optypes; + uint8_t opmenu[cntlr.menubytes]; + + trans->opcode = trans->out[0]; + spi_use_out(trans, 1); + if (!ichspi_lock) { + /* The lock is off, so just use index 0. */ + writeb_(trans->opcode, cntlr.opmenu); + optypes = readw_(cntlr.optype); + optypes = (optypes & 0xfffc) | (trans->type & 0x3); + writew_(optypes, cntlr.optype); + return 0; + } else { + /* The lock is on. See if what we need is on the menu. */ + uint8_t optype; + uint16_t opcode_index; + + read_reg(cntlr.opmenu, opmenu, sizeof(opmenu)); + for (opcode_index = 0; opcode_index < cntlr.menubytes; + opcode_index++) { + if (opmenu[opcode_index] == trans->opcode) + break; + } + + if (opcode_index == cntlr.menubytes) { + printk(BIOS_DEBUG, "ICH SPI: Opcode %x not found\n", + trans->opcode); + return -1; + } + + optypes = readw_(cntlr.optype); + optype = (optypes >> (opcode_index * 2)) & 0x3; + if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS && + optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS && + trans->bytesout >= 3) { + /* We guessed wrong earlier. Fix it up. */ + trans->type = optype; + } + if (optype != trans->type) { + printk(BIOS_DEBUG, "ICH SPI: Transaction doesn't fit type %d\n", + optype); + return -1; + } + return opcode_index; + } +} + +static int spi_setup_offset(spi_transaction *trans) +{ + /* Separate the SPI address and data. */ + switch (trans->type) { + case SPI_OPCODE_TYPE_READ_NO_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_NO_ADDRESS: + return 0; + case SPI_OPCODE_TYPE_READ_WITH_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS: + trans->offset = ((uint32_t)trans->out[0] << 16) | + ((uint32_t)trans->out[1] << 8) | + ((uint32_t)trans->out[2] << 0); + spi_use_out(trans, 3); + return 1; + default: + printk(BIOS_DEBUG, "Unrecognized SPI transaction type %#x\n", trans->type); + return -1; + } +} + +/* + * Wait for up to 60ms til status register bit(s) turn 1 (in case wait_til_set + * below is True) or 0. In case the wait was for the bit(s) to set - write + * those bits back, which would cause resetting them. + * + * Return the last read status value on success or -1 on failure. + */ +static int ich_status_poll(u16 bitmask, int wait_til_set) +{ + int timeout = 6000; /* This will result in 60 ms */ + u16 status = 0; + + while (timeout--) { + status = readw_(cntlr.status); + if (wait_til_set ^ ((status & bitmask) == 0)) { + if (wait_til_set) + writew_((status & bitmask), cntlr.status); + return status; + } + udelay(10); + } + + printk(BIOS_DEBUG, "ICH SPI: SCIP timeout, read %x, expected %x\n", + status, bitmask); + return -1; +} + +int spi_xfer(struct spi_slave *slave, const void *dout, + unsigned int bitsout, void *din, unsigned int bitsin) +{ + uint16_t control; + int16_t opcode_index; + int with_address; + int status; + + spi_transaction trans = { + dout, bitsout / 8, + din, bitsin / 8, + 0xff, 0xff, 0 + }; + + /* There has to always at least be an opcode. */ + if (!bitsout || !dout) { + printk(BIOS_DEBUG, "ICH SPI: No opcode for transfer\n"); + return -1; + } + /* Make sure if we read something we have a place to put it. */ + if (bitsin != 0 && !din) { + printk(BIOS_DEBUG, "ICH SPI: Read but no target buffer\n"); + return -1; + } + /* Right now we don't support writing partial bytes. */ + if (bitsout % 8 || bitsin % 8) { + printk(BIOS_DEBUG, "ICH SPI: Accessing partial bytes not supported\n"); + return -1; + } + + if (ich_status_poll(SPIS_SCIP, 0) == -1) + return -1; + + writew_(SPIS_CDS | SPIS_FCERR, cntlr.status); + + spi_setup_type(&trans); + if ((opcode_index = spi_setup_opcode(&trans)) < 0) + return -1; + if ((with_address = spi_setup_offset(&trans)) < 0) + return -1; + + if (!ichspi_lock && trans.opcode == 0x06) { + /* + * Treat Write Enable as Atomic Pre-Op if possible + * in order to prevent the Management Engine from + * issuing a transaction between WREN and DATA. + */ + writew_(trans.opcode, cntlr.preop); + return 0; + } + + /* Preset control fields */ + control = SPIC_SCGO | ((opcode_index & 0x07) << 4); + + /* Issue atomic preop cycle if needed */ + if (readw_(cntlr.preop)) + control |= SPIC_ACS; + + if (!trans.bytesout && !trans.bytesin) { + /* + * This is a 'no data' command (like Write Enable), its + * bitesout size was 1, decremented to zero while executing + * spi_setup_opcode() above. Tell the chip to send the + * command. + */ + writew_(control, cntlr.control); + + /* wait for the result */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Command transaction error\n"); + return -1; + } + + return 0; + } + + /* + * Check if this is a write command atempting to transfer more bytes + * than the controller can handle. Iterations for writes are not + * supported here because each SPI write command needs to be preceded + * and followed by other SPI commands, and this sequence is controlled + * by the SPI chip driver. + */ + if (trans.bytesout > cntlr.databytes) { + printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use" + " CONTROLLER_PAGE_LIMIT?\n"); + return -1; + } + + /* + * Read or write up to databytes bytes at a time until everything has + * been sent. + */ + while (trans.bytesout || trans.bytesin) { + uint32_t data_length; + + /* SPI addresses are 24 bit only */ + writel_(trans.offset & 0x00FFFFFF, cntlr.addr); + + if (trans.bytesout) + data_length = min(trans.bytesout, cntlr.databytes); + else + data_length = min(trans.bytesin, cntlr.databytes); + + /* Program data into FDATA0 to N */ + if (trans.bytesout) { + write_reg(trans.out, cntlr.data, data_length); + spi_use_out(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + + /* Add proper control fields' values */ + control &= ~((cntlr.databytes - 1) << 8); + control |= SPIC_DS; + control |= (data_length - 1) << 8; + + /* write it */ + writew_(control, cntlr.control); + + /* Wait for Cycle Done Status or Flash Cycle Error. */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Data transaction error\n"); + return -1; + } + + if (trans.bytesin) { + read_reg(cntlr.data, trans.in, data_length); + spi_use_in(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + } + + /* Clear atomic preop now that xfer is done */ + writew_(0, cntlr.preop); + + return 0; +} From gerrit at coreboot.org Fri May 4 23:15:05 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Fri, 4 May 2012 23:15:05 +0200 Subject: [coreboot] Patch set updated for coreboot: d67e4ed Rework Sandybridge MRC cache handling References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1001 -gerrit commit d67e4edfc60ed59dfd783587daf287ed4420f134 Author: Stefan Reinauer Date: Thu May 3 16:38:09 2012 -0700 Rework Sandybridge MRC cache handling - Separate Sandybridge from ChromeOS a bit The Sandybridge code depends on chromeos features a whole lot. As a first step, provide a code path to look up the MRC cache without depending on u-boot. - Move mrc cache handling to separate file This enables us to handle the MRC cache from ramstage, where we can write the flash safely (eg. to update the cache). Also teach it to lookup the current MRC cache from CBMEM, as the original data block isn't available anymore. After all the preparations, finally write to the SPI as necessary. It's a simple round robin wear levelling that erases the entire MRC cache region when it's full and starts from the beginning. Change-Id: I4751385574cf709b03d5c9d153b7481ffc90ce12 Signed-off-by: Patrick Georgi --- src/northbridge/intel/sandybridge/Kconfig | 17 ++ src/northbridge/intel/sandybridge/Makefile.inc | 2 + src/northbridge/intel/sandybridge/mrccache.c | 265 +++++++++++++++++++++++ src/northbridge/intel/sandybridge/raminit.c | 123 +---------- src/northbridge/intel/sandybridge/sandybridge.h | 22 ++ 5 files changed, 315 insertions(+), 114 deletions(-) diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig index 8cf0a49..67b3def 100644 --- a/src/northbridge/intel/sandybridge/Kconfig +++ b/src/northbridge/intel/sandybridge/Kconfig @@ -37,6 +37,23 @@ config CACHE_MRC_SIZE_KB int default 256 +# FIXME: build from rom size +config MRC_CACHE_BASE + hex + default 0xff800000 + +config MRC_CACHE_LOCATION + hex + default 0x1ec000 + +config MRC_CACHE_SIZE + hex + default 0x10000 + +config MRC_CACHE_ALIGNMENT + hex + default 0x1000 + config DCACHE_RAM_BASE hex default 0xff7f0000 diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index 87a0b2e..824700e 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -21,9 +21,11 @@ driver-y += northbridge.c driver-y += gma.c ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c +ramstage-y += mrccache.c romstage-y += udelay.c romstage-y += raminit.c +romstage-y += mrccache.c romstage-y += early_init.c romstage-y += report_platform.c romstage-y += ../../../arch/x86/lib/walkcbfs.S diff --git a/src/northbridge/intel/sandybridge/mrccache.c b/src/northbridge/intel/sandybridge/mrccache.c new file mode 100644 index 0000000..5c4c382 --- /dev/null +++ b/src/northbridge/intel/sandybridge/mrccache.c @@ -0,0 +1,265 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Google Inc. + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include "pei_data.h" +#include "sandybridge.h" +#include +#include +/* Using the FDT FMAP for finding the MRC cache area requires including FDT + * support in coreboot, which we would like to avoid. There are a number of + * options: + * - Have each mainboard Kconfig supply a hard-coded offset + * - For ChromeOS devices: implement native FMAP + * - For non-ChromeOS devices: use CBFS + * For now let's leave this code in here until the issue is sorted out in + * a way that works for everyone. + */ +#undef USE_FDT_FMAP_FOR_MRC_CACHE +#ifdef USE_FDT_FMAP_FOR_MRC_CACHE +#include +#endif + +struct mrc_data_container *next_mrc_block(struct mrc_data_container *mrc_cache) +{ + /* MRC data blocks are aligned within the region */ + u32 mrc_size = sizeof(*mrc_cache) + mrc_cache->mrc_data_size; + if (mrc_size & (MRC_DATA_ALIGN - 1UL)) { + mrc_size &= ~(MRC_DATA_ALIGN - 1UL); + mrc_size += MRC_DATA_ALIGN; + } + + u8 *region_ptr = (u8*)mrc_cache; + region_ptr += mrc_size; + return (struct mrc_data_container *)region_ptr; +} + +int is_mrc_cache(struct mrc_data_container *mrc_cache) +{ + return (!!mrc_cache) && (mrc_cache->mrc_signature == MRC_DATA_SIGNATURE); +} + +u32 get_mrc_cache_region(struct mrc_data_container **mrc_region_ptr) +{ + u8 *mrc_region; + u32 region_size; + u32 *data; +#ifdef USE_FDT_FMAP_FOR_MRC_CACHE + const struct fdt_header *fdt_header; + const struct fdt_property *fdtp; + int offset, len; + const char *compatible = "chromeos,flashmap"; + const char *subnode = "rw-mrc-cache"; + const char *property = "reg"; + u64 flashrom_base = 0; + + fdt_header = cbfs_find_file(CONFIG_FDT_FILE_NAME, CBFS_TYPE_FDT); + + if (!fdt_header) { + printk(BIOS_ERR, "%s: no FDT found!\n", __func__); + return 0; + } + + offset = fdt_node_offset_by_compatible(fdt_header, 0, compatible); + if (offset < 0) { + printk(BIOS_ERR, "%s: no %s node found!\n", + __func__, compatible); + return 0; + } + + if (fdt_get_base_addr(fdt_header, offset, &flashrom_base) < 0) { + printk(BIOS_ERR, "%s: no base address in node name!\n", + __func__); + return 0; + } + + offset = fdt_subnode_offset(fdt_header, offset, subnode); + if (offset < 0) { + printk(BIOS_ERR, "%s: no %s found!\n", __func__, subnode); + return 0; + } + + fdtp = fdt_get_property(fdt_header, offset, property, &len); + if (!fdtp || (len != 8)) { + printk(BIOS_ERR, "%s: property %s at %p, len %d!\n", + __func__, property, fdtp, len); + return 0; + } + + data = (u32 *)fdtp->data; + + // Calculate actual address of the MRC cache in memory + region_size = fdt32_to_cpu(data[1]); + mrc_region = (u8*)((unsigned long)flashrom_base + fdt32_to_cpu(data[0])); +#else + data = (u32 *)((void *)(CONFIG_MRC_CACHE_BASE + CONFIG_MRC_CACHE_LOCATION + 12)); + + region_size = CONFIG_MRC_CACHE_SIZE; + mrc_region = (u8*)(CONFIG_MRC_CACHE_BASE + be32_to_cpu(data[0])); +#endif + + *mrc_region_ptr = (struct mrc_data_container *)mrc_region; + + return region_size; +} + +/* find the first empty field in the MRC cache area. If there's none, return + * the first region. By testing for emptiness caller can detect if flash + * needs to be erased. + * + * FIXME: that interface is crap + */ +struct mrc_data_container *find_next_mrc_cache(void) +{ + u32 entry_id = 0; + struct mrc_data_container *mrc_cache = NULL; + u32 region_size = get_mrc_cache_region(&mrc_cache); + void *mrc_region = (void*)mrc_cache; + + if (mrc_cache == NULL) { + printk(BIOS_ERR, "%s: could not find mrc cache area\n", __func__); + return NULL; + } + + /* Search for the first empty entry in the region */ + while (is_mrc_cache(mrc_cache)) { + entry_id++; + mrc_cache = next_mrc_block(mrc_cache); + /* If we exceed the defined area, move to front */ + if ((void*)mrc_cache >= (void*)(mrc_region + region_size)) { + mrc_cache = (struct mrc_data_container *)mrc_region; + break; + } + } + + printk(BIOS_DEBUG, "picked entry %u from cache block when looking for empty block\n", entry_id); + + return mrc_cache; +} + +struct mrc_data_container *find_current_mrc_cache(void) +{ + u32 entry_id = 0; + struct mrc_data_container *mrc_next, *mrc_cache = NULL; + u32 region_size = get_mrc_cache_region(&mrc_cache); + void *mrc_region = (void*)mrc_cache; + mrc_next = mrc_cache; + + if (mrc_cache == NULL) { + printk(BIOS_ERR, "%s: could not find mrc cache area\n", __func__); + return NULL; + } + + if (mrc_cache->mrc_data_size == -1UL) { + printk(BIOS_ERR, "%s: MRC cache not initialized?\n", __func__); + /* return non-initialized cache, so we can discern this + * from having no cache area at all + */ + return mrc_cache; + } else { + /* Search for the last filled entry in the region */ + while (is_mrc_cache(mrc_next)) { + entry_id++; + mrc_cache = mrc_next; + mrc_next = next_mrc_block(mrc_cache); + /* Stay in the mrcdata region defined in fdt */ + if ((void*)mrc_next >= (void*)(mrc_region + region_size)) + break; + } + entry_id--; + } + + /* Verify checksum */ + if (mrc_cache->mrc_checksum != + compute_ip_checksum(mrc_cache->mrc_data, + mrc_cache->mrc_data_size)) { + printk(BIOS_ERR, "%s: MRC cache checksum mismatch\n", __func__); + return NULL; + } + + printk(BIOS_DEBUG, "picked entry %u from cache block\n", entry_id); + + return mrc_cache; +} + +/* SPI code needs malloc/free. + * Also unknown if writing flash from XIP-flash code is a good idea + */ +#if !defined(__PRE_RAM__) +void update_mrc_cache(void) +{ + struct mrc_data_container *current = cbmem_find(CBMEM_ID_MRCDATA); + if (!current) { + printk(BIOS_ERR, "No MRC cache in cbmem. Can't update flash.\n"); + return; + } + if (current->mrc_data_size == -1) { + printk(BIOS_ERR, "MRC cache data in cbmem invalid.\n"); + return; + } + + /* + * we need to: + */ + // 0. compare MRC data to last mrc-cache block (exit if same) + struct mrc_data_container *cache; + if ((cache = find_current_mrc_cache()) == NULL) { + printk(BIOS_DEBUG, "Failure looking for current last block\n"); + return; + } + + if ((cache->mrc_data_size == current->mrc_data_size) && (memcmp(cache, current, cache->mrc_data_size) == 0)) { + printk(BIOS_DEBUG, "MRC data in flash is up to date. No update.\n"); + return; + } + + // 1. use spi_flash_probe() to find the flash, then + spi_init(); + struct spi_flash *flash = spi_flash_probe(0, 0, 1000000, SPI_MODE_3); + if (!flash) { + printk(BIOS_DEBUG, "Could not find SPI device\n"); + return; + } + + // 2. look up the first unused block + cache = find_next_mrc_cache(); + if (!cache) { + printk(BIOS_DEBUG, "Could not find MRC cache area\n"); + return; + } + + // 3. if no such place exists, erase entire mrc-cache range & use block 0 + if (cache->mrc_data_size != -1) { + printk(BIOS_DEBUG, "We need to erase the MRC cache region\n"); + flash->erase(flash, CONFIG_MRC_CACHE_LOCATION, CONFIG_MRC_CACHE_SIZE); + /* we know we can start at the beginning again */ + get_mrc_cache_region(&cache); + } + // 4. write mrc data with flash->write() + printk(BIOS_DEBUG, "Finally: write MRC cache update to flash\n"); + flash->write(flash, (u32)(((void*)cache)-CONFIG_MRC_CACHE_BASE), current->mrc_data_size + sizeof(*current), current); +} +#endif + diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 6548b32..0df86d6 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -36,9 +36,8 @@ #include "southbridge/intel/bd82x6x/me.h" #if CONFIG_CHROMEOS #include -#endif -#if 0 -#include +#else +#define recovery_mode_enabled(x) 0 #endif /* @@ -56,17 +55,6 @@ #define CMOS_OFFSET_MRC_SEED_CHK 120 #endif -#define MRC_DATA_ALIGN 0x1000 -#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24)) - -struct mrc_data_container { - u32 mrc_signature; // "MRCD" - u32 mrc_data_size; // Actual total size of this structure - u32 mrc_checksum; // IP style checksum - u32 reserved; // For header alignment - u8 mrc_data[0]; // Variable size, platform/run time dependent. -} __attribute__ ((packed)); - static void save_mrc_data(struct pei_data *pei_data) { u16 c1, c2, checksum; @@ -119,22 +107,10 @@ static void save_mrc_data(struct pei_data *pei_data) cmos_write((checksum >> 8) & 0xff, CMOS_OFFSET_MRC_SEED_CHK+1); } -#if CONFIG_CHROMEOS static void prepare_mrc_cache(struct pei_data *pei_data) { -#if 0 - const struct fdt_header *fdt_header; - const struct fdt_property *fdtp; - int offset, len; - const char *compatible = "chromeos,flashmap"; - const char *subnode = "rw-mrc-cache"; - const char *property = "reg"; - u32 *data; - struct mrc_data_container *mrc_cache, *mrc_next; - u8 *mrc_region, *region_ptr; + struct mrc_data_container *mrc_cache; u16 c1, c2, checksum, seed_checksum; - u32 region_size, entry_id = 0; - u64 flashrom_base = 0; // preset just in case there is an error pei_data->mrc_input = NULL; @@ -166,96 +142,18 @@ static void prepare_mrc_cache(struct pei_data *pei_data) return; } - fdt_header = cbfs_find_file(CONFIG_FDT_FILE_NAME, CBFS_TYPE_FDT); - - if (!fdt_header) { - printk(BIOS_ERR, "%s: no FDT found!\n", __func__); - return; - } - - offset = fdt_node_offset_by_compatible(fdt_header, 0, compatible); - if (offset < 0) { - printk(BIOS_ERR, "%s: no %s node found!\n", - __func__, compatible); - return; - } - - if (fdt_get_base_addr(fdt_header, offset, &flashrom_base) < 0) { - printk(BIOS_ERR, "%s: no base address in node name!\n", - __func__); - return; - } - - offset = fdt_subnode_offset(fdt_header, offset, subnode); - if (offset < 0) { - printk(BIOS_ERR, "%s: no %s found!\n", __func__, subnode); - return; - } - - fdtp = fdt_get_property(fdt_header, offset, property, &len); - if (!fdtp || (len != 8)) { - printk(BIOS_ERR, "%s: property %s at %p, len %d!\n", - __func__, property, fdtp, len); - return; - } - - data = (u32 *)fdtp->data; - - // Calculate actual address of the MRC cache in memory - region_size = fdt32_to_cpu(data[1]); - mrc_region = region_ptr = (u8*) - ((unsigned long)flashrom_base + fdt32_to_cpu(data[0])); - mrc_cache = mrc_next = (struct mrc_data_container *)mrc_region; - - if (!mrc_cache || mrc_cache->mrc_signature != MRC_DATA_SIGNATURE) { - printk(BIOS_ERR, "%s: invalid MRC data\n", __func__); - return; - } - - if (mrc_cache->mrc_data_size == -1UL) { - printk(BIOS_ERR, "%s: MRC cache not initialized?\n", __func__); - return; - } else { - /* MRC data blocks are aligned within the region */ - u32 mrc_size = sizeof(*mrc_cache) + mrc_cache->mrc_data_size; - if (mrc_size & (MRC_DATA_ALIGN - 1UL)) { - mrc_size &= ~(MRC_DATA_ALIGN - 1UL); - mrc_size += MRC_DATA_ALIGN; - } - - /* Search for the last filled entry in the region */ - while (mrc_next && - mrc_next->mrc_signature == MRC_DATA_SIGNATURE) { - entry_id++; - mrc_cache = mrc_next; - /* Stay in the mrcdata region defined in fdt */ - if ((entry_id * mrc_size) > region_size) - break; - region_ptr += mrc_size; - mrc_next = (struct mrc_data_container *)region_ptr; - } - entry_id--; - } - - /* Verify checksum */ - if (mrc_cache->mrc_checksum != - compute_ip_checksum(mrc_cache->mrc_data, - mrc_cache->mrc_data_size)) { - printk(BIOS_ERR, "%s: MRC cache checksum mismatch\n", __func__); + if ((mrc_cache = find_current_mrc_cache()) == NULL) { + /* error message printed in find_current_mrc_cache */ return; } pei_data->mrc_input = mrc_cache->mrc_data; pei_data->mrc_input_len = mrc_cache->mrc_data_size; - printk(BIOS_DEBUG, "%s: at %p, entry %u size %x checksum %04x\n", - __func__, pei_data->mrc_input, entry_id, + printk(BIOS_DEBUG, "%s: at %p, size %x checksum %04x\n", + __func__, pei_data->mrc_input, pei_data->mrc_input_len, mrc_cache->mrc_checksum); -#else - printk(BIOS_ERR, "MRC cache handling code has to be redone.\n"); -#endif } -#endif static const char* ecc_decoder[] = { "inactive", @@ -315,7 +213,6 @@ static void report_memory_config(void) void sdram_initialize(struct pei_data *pei_data) { struct sys_info sysinfo; - const char *target = "mrc.bin"; unsigned long entry; report_platform_info(); @@ -330,7 +227,6 @@ void sdram_initialize(struct pei_data *pei_data) sysinfo.boot_path = pei_data->boot_mode; -#if CONFIG_CHROMEOS /* * Do not pass MRC data in for recovery mode boot, * Always pass it in for S3 resume. @@ -344,17 +240,16 @@ void sdram_initialize(struct pei_data *pei_data) outb(0x6, 0xcf9); hlt(); } -#endif /* Locate and call UEFI System Agent binary. */ - entry = (unsigned long)cbfs_find_file(target, 0xab); + entry = (unsigned long)cbfs_find_file("mrc.bin", 0xab); if (entry) { int rv; asm volatile ( "call *%%ecx\n\t" :"=a" (rv) : "c" (entry), "a" (pei_data)); if (rv) { - printk(BIOS_ERR, "MRC returned %d\n", rv); + printk(BIOS_ERR, "MRC returned %x\n", rv); die("Nonzero MRC return value\n"); } } else { diff --git a/src/northbridge/intel/sandybridge/sandybridge.h b/src/northbridge/intel/sandybridge/sandybridge.h index aa62021..7e12416 100644 --- a/src/northbridge/intel/sandybridge/sandybridge.h +++ b/src/northbridge/intel/sandybridge/sandybridge.h @@ -221,6 +221,28 @@ void dump_spd_registers(void); void dump_mem(unsigned start, unsigned end); void report_platform_info(void); #endif /* !__SMM__ */ + + +#define MRC_DATA_ALIGN 0x1000 +#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24)) + +struct mrc_data_container { + u32 mrc_signature; // "MRCD" + u32 mrc_data_size; // Actual total size of this structure + u32 mrc_checksum; // IP style checksum + u32 reserved; // For header alignment + u8 mrc_data[0]; // Variable size, platform/run time dependent. +} __attribute__ ((packed)); + +struct mrc_data_container *next_mrc_block(struct mrc_data_container *mrc_cache); +int is_mrc_cache(struct mrc_data_container *mrc_cache); +u32 get_mrc_cache_region(struct mrc_data_container **mrc_region_ptr); +struct mrc_data_container *find_next_mrc_cache(void); +struct mrc_data_container *find_current_mrc_cache(void); +#if !defined(__PRE_RAM__) +void update_mrc_cache(void); +#endif + #endif #endif #endif From gerrit at coreboot.org Fri May 4 23:15:06 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Fri, 4 May 2012 23:15:06 +0200 Subject: [coreboot] Patch set updated for coreboot: 4cbf030 Hook up MRC cache update References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1002 -gerrit commit 4cbf030d80f801c86949d86dcf781c32d1fb46d9 Author: Stefan Reinauer Date: Thu May 3 16:40:41 2012 -0700 Hook up MRC cache update This one is a WIP: - should not depend on CONFIG_CHROMEOS - There might be a better place for it. Requirements: - must be in ramstage (locking flash while executing code from there might not work) - must be after cbmem is reinitialized (so the mrc cache copy of the current run can be found) Change-Id: I8028fb073349ce2b027ef5f8397dc1a1b8b31c02 Signed-off-by: Patrick Georgi --- src/arch/x86/boot/tables.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/src/arch/x86/boot/tables.c b/src/arch/x86/boot/tables.c index 4fefc7d..ff57422 100644 --- a/src/arch/x86/boot/tables.c +++ b/src/arch/x86/boot/tables.c @@ -53,6 +53,11 @@ struct lb_memory *write_tables(void) */ unsigned long high_table_pointer; +#if CONFIG_CHROMEOS + void update_mrc_cache(void); + update_mrc_cache(); +#endif + if (!high_tables_base) { printk(BIOS_ERR, "ERROR: High Tables Base is not set.\n"); // Are there any boards without? From gerrit at coreboot.org Fri May 4 23:15:07 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Fri, 4 May 2012 23:15:07 +0200 Subject: [coreboot] Patch set updated for coreboot: ab95893 Add SPI driver References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/997 -gerrit commit ab95893b42595782c73210c11f8d28f0a6d35c69 Author: Stefan Reinauer Date: Wed May 2 17:07:05 2012 -0700 Add SPI driver This driver is taken from u-boot and adapted to match coreboot. It still contains some hacks and is ICH specific at places. Change-Id: I97dd8096f7db3b62f8f4f4e4d08bdee10d88f689 Signed-off-by: Patrick Georgi --- src/drivers/Kconfig | 1 + src/drivers/Makefile.inc | 1 + src/drivers/spi/Kconfig | 73 +++ src/drivers/spi/Makefile.inc | 12 + src/drivers/spi/eon.c | 161 ++++++ src/drivers/spi/macronix.c | 220 +++++++++ src/drivers/spi/ramtron.c | 315 ++++++++++++ src/drivers/spi/spansion.c | 241 +++++++++ src/drivers/spi/spi_flash.c | 309 ++++++++++++ src/drivers/spi/spi_flash_internal.h | 81 +++ src/drivers/spi/sst.c | 268 ++++++++++ src/drivers/spi/stmicro.c | 250 ++++++++++ src/drivers/spi/winbond.c | 218 ++++++++ src/include/device/pci_ids.h | 4 + src/include/spi.h | 203 ++++++++ src/include/spi_flash.h | 91 ++++ src/northbridge/intel/sandybridge/raminit.c | 1 + src/southbridge/intel/bd82x6x/Kconfig | 1 + src/southbridge/intel/bd82x6x/Makefile.inc | 2 + src/southbridge/intel/bd82x6x/spi.c | 712 +++++++++++++++++++++++++++ 20 files changed, 3164 insertions(+), 0 deletions(-) diff --git a/src/drivers/Kconfig b/src/drivers/Kconfig index 259bc29..60e5b65 100644 --- a/src/drivers/Kconfig +++ b/src/drivers/Kconfig @@ -26,3 +26,4 @@ source src/drivers/oxford/Kconfig source src/drivers/sil/Kconfig source src/drivers/trident/Kconfig source src/drivers/ics/Kconfig +source src/drivers/spi/Kconfig diff --git a/src/drivers/Makefile.inc b/src/drivers/Makefile.inc index 5f6dadf..851a4df 100644 --- a/src/drivers/Makefile.inc +++ b/src/drivers/Makefile.inc @@ -26,4 +26,5 @@ subdirs-y += oxford subdirs-y += sil subdirs-y += trident subdirs-y += ics +subdirs-y += spi subdirs-$(CONFIG_ARCH_X86) += pc80 diff --git a/src/drivers/spi/Kconfig b/src/drivers/spi/Kconfig new file mode 100644 index 0000000..849d0ac --- /dev/null +++ b/src/drivers/spi/Kconfig @@ -0,0 +1,73 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2012 The Chromium OS Authors. +## +## 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; version 2 of the License. +## +## 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +config SPI + bool + default n + help + Select this option if your chipset driver needs to store certain + data in the SPI flash. + +config SPI_FLASH_EON + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by EON. + +config SPI_FLASH_MACRONIX + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by Macronix. + +config SPI_FLASH_SPANSION + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by Spansion. + +config SPI_FLASH_SST + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by SST. + +config SPI_FLASH_STMICRO + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by ST MICRO. + +config SPI_FLASH_WINBOND + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by Winbond. diff --git a/src/drivers/spi/Makefile.inc b/src/drivers/spi/Makefile.inc new file mode 100644 index 0000000..6cdf398 --- /dev/null +++ b/src/drivers/spi/Makefile.inc @@ -0,0 +1,12 @@ +# SPI driver interface +ramstage-$(CONFIG_SPI) += spi_flash.c + +# drivers +ramstage-$(CONFIG_SPI_FLASH_EON) += eon.c +ramstage-$(CONFIG_SPI_FLASH_MACRONIX) += macronix.c +ramstage-$(CONFIG_SPI_FLASH_SPANSION) += spansion.c +ramstage-$(CONFIG_SPI_FLASH_SST) += sst.c +ramstage-$(CONFIG_SPI_FLASH_STMICRO) += stmicro.c +ramstage-$(CONFIG_SPI_FLASH_WINBOND) += winbond.c +ramstage-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.c + diff --git a/src/drivers/spi/eon.c b/src/drivers/spi/eon.c new file mode 100644 index 0000000..4056953 --- /dev/null +++ b/src/drivers/spi/eon.c @@ -0,0 +1,161 @@ +/* + * (C) Copyright 2010, ucRobotics Inc. + * Author: Chong Huang + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* EN25Q128-specific commands */ +#define CMD_EN25Q128_WREN 0x06 /* Write Enable */ +#define CMD_EN25Q128_WRDI 0x04 /* Write Disable */ +#define CMD_EN25Q128_RDSR 0x05 /* Read Status Register */ +#define CMD_EN25Q128_WRSR 0x01 /* Write Status Register */ +#define CMD_EN25Q128_READ 0x03 /* Read Data Bytes */ +#define CMD_EN25Q128_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_EN25Q128_PP 0x02 /* Page Program */ +#define CMD_EN25Q128_SE 0x20 /* Sector Erase */ +#define CMD_EN25Q128_BE 0xd8 /* Block Erase */ +#define CMD_EN25Q128_DP 0xb9 /* Deep Power-down */ +#define CMD_EN25Q128_RES 0xab /* Release from DP, and Read Signature */ + +#define EON_ID_EN25Q128 0x18 + +struct eon_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 sectors_per_block; + u16 nr_sectors; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct eon_spi_flash { + struct spi_flash flash; + const struct eon_spi_flash_params *params; +}; + +static inline struct eon_spi_flash *to_eon_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct eon_spi_flash, flash); +} + +static const struct eon_spi_flash_params eon_spi_flash_table[] = { + { + .idcode1 = EON_ID_EN25Q128, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_sectors = 4096, + .name = "EN25Q128", + }, +}; + +static int eon_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct eon_spi_flash *eon = to_eon_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = eon->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_EN25Q128_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, + "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_EN25Q128_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: EON Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: EON: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int eon_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_EN25Q128_BE, offset, len); +} + +struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode) +{ + const struct eon_spi_flash_params *params; + struct eon_spi_flash *eon; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(eon_spi_flash_table); ++i) { + params = &eon_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(eon_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported EON ID %02x\n", idcode[1]); + return NULL; + } + + eon = malloc(sizeof(*eon)); + if (!eon) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + eon->params = params; + eon->flash.spi = spi; + eon->flash.name = params->name; + + eon->flash.write = eon_write; + eon->flash.erase = eon_erase; + eon->flash.read = spi_flash_cmd_read_fast; + eon->flash.sector_size = params->page_size * params->pages_per_sector + * params->sectors_per_block; + eon->flash.size = params->page_size * params->pages_per_sector + * params->nr_sectors; + + return &eon->flash; +} diff --git a/src/drivers/spi/macronix.c b/src/drivers/spi/macronix.c new file mode 100644 index 0000000..130e746 --- /dev/null +++ b/src/drivers/spi/macronix.c @@ -0,0 +1,220 @@ +/* + * Copyright 2009(C) Marvell International Ltd. and its affiliates + * Prafulla Wadaskar + * + * Based on drivers/mtd/spi/stmicro.c + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* MX25xx-specific commands */ +#define CMD_MX25XX_WREN 0x06 /* Write Enable */ +#define CMD_MX25XX_WRDI 0x04 /* Write Disable */ +#define CMD_MX25XX_RDSR 0x05 /* Read Status Register */ +#define CMD_MX25XX_WRSR 0x01 /* Write Status Register */ +#define CMD_MX25XX_READ 0x03 /* Read Data Bytes */ +#define CMD_MX25XX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_MX25XX_PP 0x02 /* Page Program */ +#define CMD_MX25XX_SE 0x20 /* Sector Erase */ +#define CMD_MX25XX_BE 0xD8 /* Block Erase */ +#define CMD_MX25XX_CE 0xc7 /* Chip Erase */ +#define CMD_MX25XX_DP 0xb9 /* Deep Power-down */ +#define CMD_MX25XX_RES 0xab /* Release from DP, and Read Signature */ + +#define MACRONIX_SR_WIP (1 << 0) /* Write-in-Progress */ + +struct macronix_spi_flash_params { + u16 idcode; + u16 page_size; + u16 pages_per_sector; + u16 sectors_per_block; + u16 nr_blocks; + const char *name; +}; + +struct macronix_spi_flash { + struct spi_flash flash; + const struct macronix_spi_flash_params *params; +}; + +static inline struct macronix_spi_flash *to_macronix_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct macronix_spi_flash, flash); +} + +static const struct macronix_spi_flash_params macronix_spi_flash_table[] = { + { + .idcode = 0x2015, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "MX25L1605D", + }, + { + .idcode = 0x2016, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "MX25L3205D", + }, + { + .idcode = 0x2017, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "MX25L6405D", + }, + { + .idcode = 0x2018, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "MX25L12805D", + }, + { + .idcode = 0x2618, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "MX25L12855E", + }, +}; + +static int macronix_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct macronix_spi_flash *mcx = to_macronix_spi_flash(flash); + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = min(mcx->params->page_size, CONTROLLER_PAGE_LIMIT); + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_MX25XX_PP; + cmd[1] = (offset >> 16) & 0xff; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_MX25XX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Macronix Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + offset += chunk_len; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: Macronix: Successfully programmed %zu bytes @ 0x%lx\n", + len, offset - len); + + spi_release_bus(flash->spi); + return ret; +} + +static int macronix_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_MX25XX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode) +{ + const struct macronix_spi_flash_params *params; + struct macronix_spi_flash *mcx; + unsigned int i; + u16 id = idcode[2] | idcode[1] << 8; + + for (i = 0; i < ARRAY_SIZE(macronix_spi_flash_table); i++) { + params = ¯onix_spi_flash_table[i]; + if (params->idcode == id) + break; + } + + if (i == ARRAY_SIZE(macronix_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported Macronix ID %04x\n", id); + return NULL; + } + + mcx = malloc(sizeof(*mcx)); + if (!mcx) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + mcx->params = params; + mcx->flash.spi = spi; + mcx->flash.name = params->name; + + mcx->flash.write = macronix_write; + mcx->flash.erase = macronix_erase; +#ifdef CONFIG_SPI_FLASH_NO_FAST_READ + mcx->flash.read = spi_flash_cmd_read_slow; +#else + mcx->flash.read = spi_flash_cmd_read_fast; +#endif + mcx->flash.sector_size = params->page_size * params->pages_per_sector; + mcx->flash.size = mcx->flash.sector_size * params->sectors_per_block * + params->nr_blocks; + + return &mcx->flash; +} diff --git a/src/drivers/spi/ramtron.c b/src/drivers/spi/ramtron.c new file mode 100644 index 0000000..2d50b85 --- /dev/null +++ b/src/drivers/spi/ramtron.c @@ -0,0 +1,315 @@ +/* + * (C) Copyright 2010 + * Reinhard Meyer, EMK Elektronik, reinhard.meyer at emk-elektronik.de + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Note: RAMTRON SPI FRAMs are ferroelectric, nonvolatile RAMs + * with an interface identical to SPI flash devices. + * However since they behave like RAM there are no delays or + * busy polls required. They can sustain read or write at the + * allowed SPI bus speed, which can be 40 MHz for some devices. + * + * Unfortunately some RAMTRON devices do not have a means of + * identifying them. They will leave the SO line undriven when + * the READ-ID command is issued. It is therefore mandatory + * that the MISO line has a proper pull-up, so that READ-ID + * will return a row of 0xff. This 0xff pseudo-id will cause + * probes by all vendor specific functions that are designed + * to handle it. If the MISO line is not pulled up, READ-ID + * could return any random noise, even mimicking another + * device. + * + * We use CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + * to define which device will be assumed after a simple status + * register verify. This method is prone to false positive + * detection and should therefore be the last to be tried. + * Enter it in the last position in the table in spi_flash.c! + * + * The define CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC both activates + * compilation of the special handler and defines the device + * to assume. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* RAMTRON commands common to all devices */ +#define CMD_RAMTRON_WREN 0x06 /* Write Enable */ +#define CMD_RAMTRON_WRDI 0x04 /* Write Disable */ +#define CMD_RAMTRON_RDSR 0x05 /* Read Status Register */ +#define CMD_RAMTRON_WRSR 0x01 /* Write Status Register */ +#define CMD_RAMTRON_READ 0x03 /* Read Data Bytes */ +#define CMD_RAMTRON_WRITE 0x02 /* Write Data Bytes */ +/* not all have those: */ +#define CMD_RAMTRON_FSTRD 0x0b /* Fast Read (for compatibility - not used here) */ +#define CMD_RAMTRON_SLEEP 0xb9 /* Enter Sleep Mode */ +#define CMD_RAMTRON_RDID 0x9f /* Read ID */ +#define CMD_RAMTRON_SNR 0xc3 /* Read Serial Number */ + +/* + * Properties of supported FRAMs + * Note: speed is currently not used because we have no method to deliver that + * value to the upper layers + */ +struct ramtron_spi_fram_params { + u32 size; /* size in bytes */ + u8 addr_len; /* number of address bytes */ + u8 merge_cmd; /* some address bits are in the command byte */ + u8 id1; /* device ID 1 (family, density) */ + u8 id2; /* device ID 2 (sub, rev, rsvd) */ + u32 speed; /* max. SPI clock in Hz */ + const char *name; /* name for display and/or matching */ +}; + +struct ramtron_spi_fram { + struct spi_flash flash; + const struct ramtron_spi_fram_params *params; +}; + +static inline struct ramtron_spi_fram *to_ramtron_spi_fram(struct spi_flash + *flash) +{ + return container_of(flash, struct ramtron_spi_fram, flash); +} + +/* + * table describing supported FRAM chips: + * chips without RDID command must have the values 0xff for id1 and id2 + */ +static const struct ramtron_spi_fram_params ramtron_spi_fram_table[] = { + { + .size = 32*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x22, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V02", + }, + { + .size = 32*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x22, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN02", + }, + { + .size = 64*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x23, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V05", + }, + { + .size = 64*1024, + .addr_len = 2, + .merge_cmd = 0, + .id1 = 0x23, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN05", + }, + { + .size = 128*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0x24, + .id2 = 0x00, + .speed = 40000000, + .name = "FM25V10", + }, + { + .size = 128*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0x24, + .id2 = 0x01, + .speed = 40000000, + .name = "FM25VN10", + }, +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + { + .size = 256*1024, + .addr_len = 3, + .merge_cmd = 0, + .id1 = 0xff, + .id2 = 0xff, + .speed = 40000000, + .name = "FM25H20", + }, +#endif +}; + +static int ramtron_common(struct spi_flash *flash, + u32 offset, size_t len, void *buf, u8 command) +{ + struct ramtron_spi_fram *sn = to_ramtron_spi_fram(flash); + u8 cmd[4]; + int cmd_len; + int ret; + + if (sn->params->addr_len == 3 && sn->params->merge_cmd == 0) { + cmd[0] = command; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + cmd_len = 4; + } else if (sn->params->addr_len == 2 && sn->params->merge_cmd == 0) { + cmd[0] = command; + cmd[1] = offset >> 8; + cmd[2] = offset; + cmd_len = 3; + } else { + printk(BIOS_WARNING, "SF: unsupported addr_len or merge_cmd\n"); + return -1; + } + + /* claim the bus */ + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + if (command == CMD_RAMTRON_WRITE) { + /* send WREN */ + ret = spi_flash_cmd(flash->spi, CMD_RAMTRON_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + goto releasebus; + } + } + + /* do the transaction */ + if (command == CMD_RAMTRON_WRITE) + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, buf, len); + else + ret = spi_flash_cmd_read(flash->spi, cmd, cmd_len, buf, len); + if (ret < 0) + printk(BIOS_WARNING, "SF: Transaction failed\n"); + +releasebus: + /* release the bus */ + spi_release_bus(flash->spi); + return ret; +} + +static int ramtron_read(struct spi_flash *flash, + u32 offset, size_t len, void *buf) +{ + return ramtron_common(flash, offset, len, buf, + CMD_RAMTRON_READ); +} + +static int ramtron_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + return ramtron_common(flash, offset, len, (void *)buf, + CMD_RAMTRON_WRITE); +} + +static int ramtron_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + printk(BIOS_SPEW, "SF: Erase of RAMTRON FRAMs is pointless\n"); + return -1; +} + +/* + * nore: we are called here with idcode pointing to the first non-0x7f byte + * already! + */ +struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode) +{ + const struct ramtron_spi_fram_params *params; + struct ramtron_spi_fram *sn; + unsigned int i; +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + int ret; + u8 sr; +#endif + + /* NOTE: the bus has been claimed before this function is called! */ + switch (idcode[0]) { + case 0xc2: + /* JEDEC conformant RAMTRON id */ + for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) { + params = &ramtron_spi_fram_table[i]; + if (idcode[1] == params->id1 && idcode[2] == params->id2) + goto found; + } + break; +#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC + case 0xff: + /* + * probably open MISO line, pulled up. + * We COULD have a non JEDEC conformant FRAM here, + * read the status register to verify + */ + ret = spi_flash_cmd(spi, CMD_RAMTRON_RDSR, &sr, 1); + if (ret) + return NULL; + + /* Bits 5,4,0 are fixed 0 for all devices */ + if ((sr & 0x31) != 0x00) + return NULL; + /* now find the device */ + for (i = 0; i < ARRAY_SIZE(ramtron_spi_fram_table); i++) { + params = &ramtron_spi_fram_table[i]; + if (!strcmp(params->name, CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC)) + goto found; + } + printk(BIOS_WARNING, "SF: Unsupported non-JEDEC RAMTRON device " + CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC "\n"); + break; +#endif + default: + break; + } + + /* arriving here means no method has found a device we can handle */ + printk(BIOS_WARNING, "SF/ramtron: unsupported device id0=%02x id1=%02x id2=%02x\n", + idcode[0], idcode[1], idcode[2]); + return NULL; + +found: + sn = malloc(sizeof(*sn)); + if (!sn) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + sn->params = params; + sn->flash.spi = spi; + sn->flash.name = params->name; + + sn->flash.write = ramtron_write; + sn->flash.read = ramtron_read; + sn->flash.erase = ramtron_erase; + sn->flash.size = params->size; + + return &sn->flash; +} diff --git a/src/drivers/spi/spansion.c b/src/drivers/spi/spansion.c new file mode 100644 index 0000000..a4f370a --- /dev/null +++ b/src/drivers/spi/spansion.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2009 Freescale Semiconductor, Inc. + * + * Author: Mingkai Hu (Mingkai.hu at freescale.com) + * Based on stmicro.c by Wolfgang Denk (wd at denx.de), + * TsiChung Liew (Tsi-Chung.Liew at freescale.com), + * and Jason McMullan (mcmullan at netapp.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* S25FLxx-specific commands */ +#define CMD_S25FLXX_READ 0x03 /* Read Data Bytes */ +#define CMD_S25FLXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_S25FLXX_READID 0x90 /* Read Manufacture ID and Device ID */ +#define CMD_S25FLXX_WREN 0x06 /* Write Enable */ +#define CMD_S25FLXX_WRDI 0x04 /* Write Disable */ +#define CMD_S25FLXX_RDSR 0x05 /* Read Status Register */ +#define CMD_S25FLXX_WRSR 0x01 /* Write Status Register */ +#define CMD_S25FLXX_PP 0x02 /* Page Program */ +#define CMD_S25FLXX_SE 0xd8 /* Sector Erase */ +#define CMD_S25FLXX_BE 0xc7 /* Bulk Erase */ +#define CMD_S25FLXX_DP 0xb9 /* Deep Power-down */ +#define CMD_S25FLXX_RES 0xab /* Release from DP, and Read Signature */ + +#define SPSN_ID_S25FL008A 0x0213 +#define SPSN_ID_S25FL016A 0x0214 +#define SPSN_ID_S25FL032A 0x0215 +#define SPSN_ID_S25FL064A 0x0216 +#define SPSN_ID_S25FL128P 0x2018 +#define SPSN_EXT_ID_S25FL128P_256KB 0x0300 +#define SPSN_EXT_ID_S25FL128P_64KB 0x0301 +#define SPSN_EXT_ID_S25FL032P 0x4d00 + +struct spansion_spi_flash_params { + u16 idcode1; + u16 idcode2; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +struct spansion_spi_flash { + struct spi_flash flash; + const struct spansion_spi_flash_params *params; +}; + +static inline struct spansion_spi_flash *to_spansion_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct spansion_spi_flash, flash); +} + +static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { + { + .idcode1 = SPSN_ID_S25FL008A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "S25FL008A", + }, + { + .idcode1 = SPSN_ID_S25FL016A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "S25FL016A", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032A", + }, + { + .idcode1 = SPSN_ID_S25FL064A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "S25FL064A", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_64KB, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 256, + .name = "S25FL128P_64K", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_256KB, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "S25FL128P_256K", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = SPSN_EXT_ID_S25FL032P, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032P", + }, +}; + +static int spansion_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct spansion_spi_flash *spsn = to_spansion_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = spsn->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_S25FLXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_S25FLXX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: SPANSION Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: SPANSION: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int spansion_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_S25FLXX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) +{ + const struct spansion_spi_flash_params *params; + struct spansion_spi_flash *spsn; + unsigned int i; + unsigned short jedec, ext_jedec; + + jedec = idcode[1] << 8 | idcode[2]; + ext_jedec = idcode[3] << 8 | idcode[4]; + + for (i = 0; i < ARRAY_SIZE(spansion_spi_flash_table); i++) { + params = &spansion_spi_flash_table[i]; + if (params->idcode1 == jedec) { + if (params->idcode2 == ext_jedec) + break; + } + } + + if (i == ARRAY_SIZE(spansion_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported SPANSION ID %04x %04x\n", jedec, ext_jedec); + return NULL; + } + + spsn = malloc(sizeof(struct spansion_spi_flash)); + if (!spsn) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + spsn->params = params; + spsn->flash.spi = spi; + spsn->flash.name = params->name; + + spsn->flash.write = spansion_write; + spsn->flash.erase = spansion_erase; + spsn->flash.read = spi_flash_cmd_read_fast; + spsn->flash.sector_size = params->page_size * params->pages_per_sector; + spsn->flash.size = spsn->flash.sector_size * params->nr_sectors; + + return &spsn->flash; +} diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c new file mode 100644 index 0000000..33cb4d2 --- /dev/null +++ b/src/drivers/spi/spi_flash.c @@ -0,0 +1,309 @@ +/* + * SPI flash interface + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include "spi_flash_internal.h" + +static void spi_flash_addr(u32 addr, u8 *cmd) +{ + /* cmd[0] is actual command */ + cmd[1] = addr >> 16; + cmd[2] = addr >> 8; + cmd[3] = addr >> 0; +} + +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) +{ + int ret = spi_xfer(spi, &cmd, 8, response, len * 8); + if (ret) + printk(BIOS_WARNING, "SF: Failed to send command %02x: %d\n", cmd, ret); + + return ret; +} + +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + int ret = spi_xfer(spi, cmd, cmd_len * 8, data, data_len * 8); + if (ret) { + printk(BIOS_WARNING, "SF: Failed to send read command (%zu bytes): %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len) +{ + int ret; + u8 buff[cmd_len + data_len]; + memcpy(buff, cmd, cmd_len); + memcpy(buff + cmd_len, data, data_len); + + ret = spi_xfer(spi, buff, (cmd_len + data_len) * 8, NULL, 0); + if (ret) { + printk(BIOS_WARNING, "SF: Failed to send write command (%zu bytes): %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + struct spi_slave *spi = flash->spi; + int ret; + + spi_claim_bus(spi); + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + spi_release_bus(spi); + + return ret; +} + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[5]; + + cmd[0] = CMD_READ_ARRAY_FAST; + spi_flash_addr(offset, cmd); + cmd[4] = 0x00; + + return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); +} + +int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[4]; + + cmd[0] = CMD_READ_ARRAY_SLOW; + spi_flash_addr(offset, cmd); + + return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); +} + +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 status; + + timebase = timeout; + do { + ret = spi_flash_cmd_read(spi, &cmd, 1, &status, 1); + if (ret) + return -1; + + if ((status & poll_bit) == 0) + break; + + mdelay(1); + } while (timebase--); + + if ((status & poll_bit) == 0) + return 0; + + /* Timed out */ + printk(BIOS_DEBUG, "SF: time out!\n"); + return -1; +} + +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + return spi_flash_cmd_poll_bit(flash, timeout, + CMD_READ_STATUS, STATUS_WIP); +} + +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 offset, size_t len) +{ + u32 start, end, erase_size; + int ret; + u8 cmd[4]; + + erase_size = flash->sector_size; + if (offset % erase_size || len % erase_size) { + printk(BIOS_WARNING, "SF: Erase offset/length not multiple of erase size\n"); + return -1; + } + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + cmd[0] = erase_cmd; + start = offset; + end = start + len; + + while (offset < end) { + spi_flash_addr(offset, cmd); + offset += erase_size; + + printk(BIOS_SPEW, "SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) + goto out; + } + + printk(BIOS_DEBUG, "SF: Successfully erased %zu bytes @ %#x\n", len, start); + + out: + spi_release_bus(flash->spi); + return ret; +} + +/* + * The following table holds all device probe functions + * + * shift: number of continuation bytes before the ID + * idcode: the expected IDCODE or 0xff for non JEDEC devices + * probe: the function to call + * + * Non JEDEC devices should be ordered in the table such that + * the probe functions with best detection algorithms come first. + * + * Several matching entries are permitted, they will be tried + * in sequence until a probe function returns non NULL. + * + * IDCODE_CONT_LEN may be redefined if a device needs to declare a + * larger "shift" value. IDCODE_PART_LEN generally shouldn't be + * changed. This is the max number of bytes probe functions may + * examine when looking up part-specific identification info. + * + * Probe functions will be given the idcode buffer starting at their + * manu id byte (the "idcode" in the table below). In other words, + * all of the continuation bytes will be skipped (the "shift" below). + */ +#define IDCODE_CONT_LEN 0 +#define IDCODE_PART_LEN 5 +static const struct { + const u8 shift; + const u8 idcode; + struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); +} flashes[] = { + /* Keep it sorted by define name */ +#if CONFIG_SPI_FLASH_EON + { 0, 0x1c, spi_flash_probe_eon, }, +#endif +#if CONFIG_SPI_FLASH_MACRONIX + { 0, 0xc2, spi_flash_probe_macronix, }, +#endif +#if CONFIG_SPI_FLASH_SPANSION + { 0, 0x01, spi_flash_probe_spansion, }, +#endif +#if CONFIG_SPI_FLASH_SST + { 0, 0xbf, spi_flash_probe_sst, }, +#endif +#if CONFIG_SPI_FLASH_STMICRO + { 0, 0x20, spi_flash_probe_stmicro, }, +#endif +#if CONFIG_SPI_FLASH_WINBOND + { 0, 0xef, spi_flash_probe_winbond, }, +#endif + /* Keep it sorted by best detection */ +#if CONFIG_SPI_FLASH_STMICRO + { 0, 0xff, spi_flash_probe_stmicro, }, +#endif +}; +#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_slave *spi; + struct spi_flash *flash = NULL; + int ret, i, shift; + u8 idcode[IDCODE_LEN], *idp; + + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); + if (!spi) { + printk(BIOS_WARNING, "SF: Failed to set up slave\n"); + return NULL; + } + + ret = spi_claim_bus(spi); + if (ret) { + printk(BIOS_WARNING, "SF: Failed to claim SPI bus: %d\n", ret); + goto err_claim_bus; + } + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); + if (ret) + goto err_read_id; + +#ifdef DEBUG + printk(BIOS_SPEW, "SF: Got idcodes\n"); + print_buffer(0, idcode, 1, sizeof(idcode), 0); +#endif + + /* count the number of continuation bytes */ + for (shift = 0, idp = idcode; + shift < IDCODE_CONT_LEN && *idp == 0x7f; + ++shift, ++idp) + continue; + + /* search the table for matches in shift and id */ + for (i = 0; i < ARRAY_SIZE(flashes); ++i) + if (flashes[i].shift == shift && flashes[i].idcode == *idp) { + /* we have a match, call probe */ + flash = flashes[i].probe(spi, idp); + if (flash) + break; + } + + if (!flash) { + printk(BIOS_WARNING, "SF: Unsupported manufacturer %02x\n", *idp); + goto err_manufacturer_probe; + } + + printk(BIOS_INFO, "SF: Detected %s with page size %x, total %x\n", + flash->name, flash->sector_size, flash->size); + + spi_release_bus(spi); + + return flash; + +err_manufacturer_probe: +err_read_id: + spi_release_bus(spi); +err_claim_bus: + spi_free_slave(spi); + return NULL; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_free_slave(flash->spi); + free(flash); +} diff --git a/src/drivers/spi/spi_flash_internal.h b/src/drivers/spi/spi_flash_internal.h new file mode 100644 index 0000000..b895e2b --- /dev/null +++ b/src/drivers/spi/spi_flash_internal.h @@ -0,0 +1,81 @@ +/* + * SPI flash internal definitions + * + * Copyright (C) 2008 Atmel Corporation + */ + +/* Common parameters -- kind of high, but they should only occur when there + * is a problem (and well your system already is broken), so err on the side + * of caution in case we're dealing with slower SPI buses and/or processors. + */ +#define CONFIG_SYS_HZ 100 +#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) +#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) +#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) + +/* Common commands */ +#define CMD_READ_ID 0x9f + +#define CMD_READ_ARRAY_SLOW 0x03 +#define CMD_READ_ARRAY_FAST 0x0b +#define CMD_READ_ARRAY_LEGACY 0xe8 + +#define CMD_READ_STATUS 0x05 +#define CMD_WRITE_ENABLE 0x06 + +/* Common status */ +#define STATUS_WIP 0x01 + +/* Send a single-byte command to the device and read the response */ +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); + +/* + * Send a multi-byte command to the device and read the response. Used + * for flash array reads, etc. + */ +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +/* + * Send a multi-byte command to the device followed by (optional) + * data. Used for programming the flash array, etc. + */ +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len); + +/* + * Same as spi_flash_cmd_read() except it also claims/releases the SPI + * bus. Used as common part of the ->read() operation. + */ +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* Send a command to the device and wait for some bit to clear itself. */ +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit); + +/* + * Send the read status command to the device and wait for the wip + * (write-in-progress) bit to clear itself. + */ +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); + +/* Erase sectors. */ +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 offset, size_t len); + +/* Manufacturer-specific probe functions */ +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode); diff --git a/src/drivers/spi/sst.c b/src/drivers/spi/sst.c new file mode 100644 index 0000000..56cc851 --- /dev/null +++ b/src/drivers/spi/sst.c @@ -0,0 +1,268 @@ +/* + * Driver for SST serial flashes + * + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd at denx.de. + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +#define CMD_SST_WREN 0x06 /* Write Enable */ +#define CMD_SST_WRDI 0x04 /* Write Disable */ +#define CMD_SST_RDSR 0x05 /* Read Status Register */ +#define CMD_SST_WRSR 0x01 /* Write Status Register */ +#define CMD_SST_READ 0x03 /* Read Data Bytes */ +#define CMD_SST_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_SST_BP 0x02 /* Byte Program */ +#define CMD_SST_AAI_WP 0xAD /* Auto Address Increment Word Program */ +#define CMD_SST_SE 0x20 /* Sector Erase */ + +#define SST_SR_WIP (1 << 0) /* Write-in-Progress */ +#define SST_SR_WEL (1 << 1) /* Write enable */ +#define SST_SR_BP0 (1 << 2) /* Block Protection 0 */ +#define SST_SR_BP1 (1 << 3) /* Block Protection 1 */ +#define SST_SR_BP2 (1 << 4) /* Block Protection 2 */ +#define SST_SR_AAI (1 << 6) /* Addressing mode */ +#define SST_SR_BPL (1 << 7) /* BP bits lock */ + +struct sst_spi_flash_params { + u8 idcode1; + u16 nr_sectors; + const char *name; +}; + +struct sst_spi_flash { + struct spi_flash flash; + const struct sst_spi_flash_params *params; +}; + +static inline struct sst_spi_flash *to_sst_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct sst_spi_flash, flash); +} + +#define SST_SECTOR_SIZE (4 * 1024) +static const struct sst_spi_flash_params sst_spi_flash_table[] = { + { + .idcode1 = 0x8d, + .nr_sectors = 128, + .name = "SST25VF040B", + },{ + .idcode1 = 0x8e, + .nr_sectors = 256, + .name = "SST25VF080B", + },{ + .idcode1 = 0x41, + .nr_sectors = 512, + .name = "SST25VF016B", + },{ + .idcode1 = 0x4a, + .nr_sectors = 1024, + .name = "SST25VF032B", + },{ + .idcode1 = 0x4b, + .nr_sectors = 2048, + .name = "SST25VF064C", + },{ + .idcode1 = 0x01, + .nr_sectors = 16, + .name = "SST25WF512", + },{ + .idcode1 = 0x02, + .nr_sectors = 32, + .name = "SST25WF010", + },{ + .idcode1 = 0x03, + .nr_sectors = 64, + .name = "SST25WF020", + },{ + .idcode1 = 0x04, + .nr_sectors = 128, + .name = "SST25WF040", + }, +}; + +static int +sst_enable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WREN, NULL, 0); + if (ret) + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + return ret; +} + +static int +sst_disable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WRDI, NULL, 0); + if (ret) + printk(BIOS_WARNING, "SF: Disabling Write failed\n"); + return ret; +} + +static int +sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) +{ + int ret; + u8 cmd[4] = { + CMD_SST_BP, + offset >> 16, + offset >> 8, + offset, + }; + + printk(BIOS_SPEW, "BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf, cmd[0], offset); + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); + if (ret) + return ret; + + return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); +} + +static int +sst_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) +{ + size_t actual, cmd_len; + int ret; + u8 cmd[4]; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + /* If the data is not word aligned, write out leading single byte */ + actual = offset % 2; + if (actual) { + ret = sst_byte_write(flash, offset, buf); + if (ret) + goto done; + } + offset += actual; + + ret = sst_enable_writing(flash); + if (ret) + goto done; + + cmd_len = 4; + cmd[0] = CMD_SST_AAI_WP; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + + for (; actual < len - 1; actual += 2) { + printk(BIOS_SPEW, "WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf + actual, cmd[0], + offset); + + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, + buf + actual, 2); + if (ret) { + printk(BIOS_WARNING, "SF: SST word program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + cmd_len = 1; + offset += 2; + } + + if (!ret) + ret = sst_disable_writing(flash); + + /* If there is a single trailing byte, write it out */ + if (!ret && actual != len) + ret = sst_byte_write(flash, offset, buf + actual); + + done: + printk(BIOS_INFO, "SF: SST: program %s %zu bytes @ 0x%lx\n", + ret ? "failure" : "success", len, offset - actual); + + spi_release_bus(flash->spi); + return ret; +} + +static int sst_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_SST_SE, offset, len); +} + +static int +sst_unlock(struct spi_flash *flash) +{ + int ret; + u8 cmd, status; + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + cmd = CMD_SST_WRSR; + status = 0; + ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &status, 1); + if (ret) + printk(BIOS_WARNING, "SF: Unable to set status byte\n"); + + printk(BIOS_INFO, "SF: SST: status = %x\n", spi_w8r8(flash->spi, CMD_SST_RDSR)); + + return ret; +} + +struct spi_flash * +spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode) +{ + const struct sst_spi_flash_params *params; + struct sst_spi_flash *stm; + size_t i; + + for (i = 0; i < ARRAY_SIZE(sst_spi_flash_table); ++i) { + params = &sst_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(sst_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported SST ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(*stm)); + if (!stm) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = sst_write; + stm->flash.erase = sst_erase; + stm->flash.read = spi_flash_cmd_read_fast; + stm->flash.sector_size = SST_SECTOR_SIZE; + stm->flash.size = stm->flash.sector_size * params->nr_sectors; + + /* Flash powers up read-only, so clear BP# bits */ + sst_unlock(&stm->flash); + + return &stm->flash; +} diff --git a/src/drivers/spi/stmicro.c b/src/drivers/spi/stmicro.c new file mode 100644 index 0000000..8cbdad5 --- /dev/null +++ b/src/drivers/spi/stmicro.c @@ -0,0 +1,250 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd at denx.de. + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_M25PXX_WREN 0x06 /* Write Enable */ +#define CMD_M25PXX_WRDI 0x04 /* Write Disable */ +#define CMD_M25PXX_RDSR 0x05 /* Read Status Register */ +#define CMD_M25PXX_WRSR 0x01 /* Write Status Register */ +#define CMD_M25PXX_READ 0x03 /* Read Data Bytes */ +#define CMD_M25PXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_M25PXX_PP 0x02 /* Page Program */ +#define CMD_M25PXX_SE 0xd8 /* Sector Erase */ +#define CMD_M25PXX_BE 0xc7 /* Bulk Erase */ +#define CMD_M25PXX_DP 0xb9 /* Deep Power-down */ +#define CMD_M25PXX_RES 0xab /* Release from DP, and Read Signature */ + +#define STM_ID_M25P10 0x11 +#define STM_ID_M25P16 0x15 +#define STM_ID_M25P20 0x12 +#define STM_ID_M25P32 0x16 +#define STM_ID_M25P40 0x13 +#define STM_ID_M25P64 0x17 +#define STM_ID_M25P80 0x14 +#define STM_ID_M25P128 0x18 + +struct stmicro_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct stmicro_spi_flash { + struct spi_flash flash; + const struct stmicro_spi_flash_params *params; +}; + +static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct stmicro_spi_flash, flash); +} + +static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { + { + .idcode1 = STM_ID_M25P10, + .page_size = 256, + .pages_per_sector = 128, + .nr_sectors = 4, + .name = "M25P10", + }, + { + .idcode1 = STM_ID_M25P16, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "M25P16", + }, + { + .idcode1 = STM_ID_M25P20, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 4, + .name = "M25P20", + }, + { + .idcode1 = STM_ID_M25P32, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "M25P32", + }, + { + .idcode1 = STM_ID_M25P40, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 8, + .name = "M25P40", + }, + { + .idcode1 = STM_ID_M25P64, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "M25P64", + }, + { + .idcode1 = STM_ID_M25P80, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "M25P80", + }, + { + .idcode1 = STM_ID_M25P128, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "M25P128", + }, +}; + +static int stmicro_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = stm->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_M25PXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: STMicro Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: STMicro: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_M25PXX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) +{ + const struct stmicro_spi_flash_params *params; + struct stmicro_spi_flash *stm; + unsigned int i; + + if (idcode[0] == 0xff) { + i = spi_flash_cmd(spi, CMD_M25PXX_RES, + idcode, 4); + if (i) + return NULL; + if ((idcode[3] & 0xf0) == 0x10) { + idcode[0] = 0x20; + idcode[1] = 0x20; + idcode[2] = idcode[3] + 1; + } else + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) { + params = &stmicro_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) { + break; + } + } + + if (i == ARRAY_SIZE(stmicro_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported STMicro ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(struct stmicro_spi_flash)); + if (!stm) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = stmicro_write; + stm->flash.erase = stmicro_erase; + stm->flash.read = spi_flash_cmd_read_fast; + stm->flash.sector_size = params->page_size * params->pages_per_sector; + stm->flash.size = stm->flash.sector_size * params->nr_sectors; + + return &stm->flash; +} diff --git a/src/drivers/spi/winbond.c b/src/drivers/spi/winbond.c new file mode 100644 index 0000000..65818d5 --- /dev/null +++ b/src/drivers/spi/winbond.c @@ -0,0 +1,218 @@ +/* + * Copyright 2008, Network Appliance Inc. + * Author: Jason McMullan netapp.com> + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_W25_WREN 0x06 /* Write Enable */ +#define CMD_W25_WRDI 0x04 /* Write Disable */ +#define CMD_W25_RDSR 0x05 /* Read Status Register */ +#define CMD_W25_WRSR 0x01 /* Write Status Register */ +#define CMD_W25_READ 0x03 /* Read Data Bytes */ +#define CMD_W25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_W25_PP 0x02 /* Page Program */ +#define CMD_W25_SE 0x20 /* Sector (4K) Erase */ +#define CMD_W25_BE 0xd8 /* Block (64K) Erase */ +#define CMD_W25_CE 0xc7 /* Chip Erase */ +#define CMD_W25_DP 0xb9 /* Deep Power-down */ +#define CMD_W25_RES 0xab /* Release from DP, and Read Signature */ + +struct winbond_spi_flash_params { + uint16_t id; + /* Log2 of page size in power-of-two mode */ + uint8_t l2_page_size; + uint16_t pages_per_sector; + uint16_t sectors_per_block; + uint16_t nr_blocks; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct winbond_spi_flash { + struct spi_flash flash; + const struct winbond_spi_flash_params *params; +}; + +static inline struct winbond_spi_flash * +to_winbond_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct winbond_spi_flash, flash); +} + +static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { + { + .id = 0x3015, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "W25X16", + }, + { + .id = 0x3016, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "W25X32", + }, + { + .id = 0x3017, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "W25X64", + }, + { + .id = 0x4015, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "W25Q16", + }, + { + .id = 0x4016, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "W25Q32", + }, + { + .id = 0x4017, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "W25Q64", + }, + { + .id = 0x4018, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "W25Q128", + }, +}; + +static int winbond_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct winbond_spi_flash *stm = to_winbond_spi_flash(flash); + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT); + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_W25_PP; + cmd[1] = (offset >> 16) & 0xff; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %ld\n", + buf + actual, + cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_W25_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + goto out; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Winbond Page Program failed\n"); + goto out; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + goto out; + + offset += chunk_len; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: Winbond: Successfully programmed %zu bytes @ 0x%lx\n", + len, offset - len); + ret = 0; + +out: + spi_release_bus(flash->spi); + return ret; +} + +static int winbond_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_W25_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) +{ + const struct winbond_spi_flash_params *params; + unsigned page_size; + struct winbond_spi_flash *stm; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(winbond_spi_flash_table); i++) { + params = &winbond_spi_flash_table[i]; + if (params->id == ((idcode[1] << 8) | idcode[2])) + break; + } + + if (i == ARRAY_SIZE(winbond_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported Winbond ID %02x%02x\n", + idcode[1], idcode[2]); + return NULL; + } + + stm = malloc(sizeof(struct winbond_spi_flash)); + if (!stm) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + /* Assuming power-of-two page size initially. */ + page_size = 1 << params->l2_page_size; + + stm->flash.write = winbond_write; + stm->flash.erase = winbond_erase; +#ifdef CONFIG_SPI_FLASH_NO_FAST_READ + stm->flash.read = spi_flash_cmd_read_slow; +#else + stm->flash.read = spi_flash_cmd_read_fast; +#endif + stm->flash.sector_size = (1 << stm->params->l2_page_size) * + stm->params->pages_per_sector; + stm->flash.size = page_size * params->pages_per_sector + * params->sectors_per_block + * params->nr_blocks; + + return &stm->flash; +} diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h index a2d6884..1765293 100644 --- a/src/include/device/pci_ids.h +++ b/src/include/device/pci_ids.h @@ -2502,6 +2502,10 @@ #define PCI_DEVICE_ID_INTEL_82801IO_LPC 0x2914 #define PCI_DEVICE_ID_INTEL_82801IH_LPC 0x2912 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f +#define PCI_DEVICE_ID_INTEL_TGP_LPC 0x27bc + /* Intel 82801E (C-ICH) */ #define PCI_DEVICE_ID_INTEL_82801E_LPC 0x2450 #define PCI_DEVICE_ID_INTEL_82801E_USB 0x2452 diff --git a/src/include/spi.h b/src/include/spi.h new file mode 100644 index 0000000..bb84258 --- /dev/null +++ b/src/include/spi.h @@ -0,0 +1,203 @@ +/* + * (C) Copyright 2001 + * Gerald Van Baren, Custom IDEAS, vanbaren at cideas.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _SPI_H_ +#define _SPI_H_ + +#include + +/* Controller-specific definitions: */ + +/* SPI mode flags */ +#define SPI_CPHA 0x01 /* clock phase */ +#define SPI_CPOL 0x02 /* clock polarity */ +#define SPI_MODE_0 (0|0) /* (original MicroWire) */ +#define SPI_MODE_1 (0|SPI_CPHA) +#define SPI_MODE_2 (SPI_CPOL|0) +#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) +#define SPI_CS_HIGH 0x04 /* CS active high */ +#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ +#define SPI_3WIRE 0x10 /* SI/SO signals shared */ +#define SPI_LOOP 0x20 /* loopback mode */ + +/* SPI transfer flags */ +#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ +#define SPI_XFER_END 0x02 /* Deassert CS after transfer */ + +/*----------------------------------------------------------------------- + * Representation of a SPI slave, i.e. what we're communicating with. + * + * Drivers are expected to extend this with controller-specific data. + * + * bus: ID of the bus that the slave is attached to. + * cs: ID of the chip select connected to the slave. + */ +struct spi_slave { + unsigned int bus; + unsigned int cs; +}; + +/*----------------------------------------------------------------------- + * Initialization, must be called once on start up. + * + * TODO: I don't think we really need this. + */ +void spi_init(void); + +/*----------------------------------------------------------------------- + * Set up communications parameters for a SPI slave. + * + * This must be called once for each slave. Note that this function + * usually doesn't touch any actual hardware, it only initializes the + * contents of spi_slave so that the hardware can be easily + * initialized later. + * + * bus: Bus ID of the slave chip. + * cs: Chip select ID of the slave chip on the specified bus. + * max_hz: Maximum SCK rate in Hz. + * mode: Clock polarity, clock phase and other parameters. + * + * Returns: A spi_slave reference that can be used in subsequent SPI + * calls, or NULL if one or more of the parameters are not supported. + */ +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode); + +/*----------------------------------------------------------------------- + * Free any memory associated with a SPI slave. + * + * slave: The SPI slave + */ +void spi_free_slave(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Claim the bus and prepare it for communication with a given slave. + * + * This must be called before doing any transfers with a SPI slave. It + * will enable and initialize any SPI hardware as necessary, and make + * sure that the SCK line is in the correct idle state. It is not + * allowed to claim the same bus for several slaves without releasing + * the bus in between. + * + * slave: The SPI slave + * + * Returns: 0 if the bus was claimed successfully, or a negative value + * if it wasn't. + */ +int spi_claim_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Release the SPI bus + * + * This must be called once for every call to spi_claim_bus() after + * all transfers have finished. It may disable any SPI hardware as + * appropriate. + * + * slave: The SPI slave + */ +void spi_release_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * SPI transfer + * + * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks + * "bitlen" bits in the SPI MISO port. That's just the way SPI works. + * + * The source of the outgoing bits is the "dout" parameter and the + * destination of the input bits is the "din" parameter. Note that "dout" + * and "din" can point to the same memory location, in which case the + * input data overwrites the output data (since both are buffered by + * temporary variables, this is OK). + * + * spi_xfer() interface: + * slave: The SPI slave which will be sending/receiving the data. + * dout: Pointer to a string of bits to send out. The bits are + * held in a byte array and are sent MSB first. + * bitsout: How many bits to write. + * din: Pointer to a string of bits that will be filled in. + * bitsin: How many bits to read. + * + * Returns: 0 on success, not 0 on failure + */ +int spi_xfer(struct spi_slave *slave, const void *dout, unsigned int bitsout, + void *din, unsigned int bitsin); + +/*----------------------------------------------------------------------- + * Determine if a SPI chipselect is valid. + * This function is provided by the board if the low-level SPI driver + * needs it to determine if a given chipselect is actually valid. + * + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 + * otherwise. + */ +int spi_cs_is_valid(unsigned int bus, unsigned int cs); + +/*----------------------------------------------------------------------- + * Activate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should activate the chip select + * to the device identified by "slave". + */ +void spi_cs_activate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Deactivate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should deactivate the chip + * select to the device identified by "slave". + */ +void spi_cs_deactivate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Set transfer speed. + * This sets a new speed to be applied for next spi_xfer(). + * slave: The SPI slave + * hz: The transfer speed + */ +void spi_set_speed(struct spi_slave *slave, uint32_t hz); + +/*----------------------------------------------------------------------- + * Write 8 bits, then read 8 bits. + * slave: The SPI slave we're communicating with + * byte: Byte to be written + * + * Returns: The value that was read, or a negative value on error. + * + * TODO: This function probably shouldn't be inlined. + */ +static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) +{ + unsigned char dout[2]; + unsigned char din[2]; + int ret; + + dout[0] = byte; + dout[1] = 0; + + ret = spi_xfer(slave, dout, 16, din, 16); + return ret < 0 ? ret : din[1]; +} + +#endif /* _SPI_H_ */ diff --git a/src/include/spi_flash.h b/src/include/spi_flash.h new file mode 100644 index 0000000..2a1dcd4 --- /dev/null +++ b/src/include/spi_flash.h @@ -0,0 +1,91 @@ +/* + * Interface to SPI flash + * + * Copyright (C) 2008 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _SPI_FLASH_H_ +#define _SPI_FLASH_H_ + +#include +#include +#include +#include + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define min(a, b) ((a)<(b)?(a):(b)) + +#define CONFIG_ICH_SPI +#ifdef CONFIG_ICH_SPI +#define CONTROLLER_PAGE_LIMIT 64 +#else +/* any number larger than 4K would do, actually */ +#define CONTROLLER_PAGE_LIMIT ((int)(~0U>>1)) +#endif + +struct spi_flash { + struct spi_slave *spi; + + const char *name; + + u32 size; + + u32 sector_size; + + int (*read)(struct spi_flash *flash, u32 offset, + size_t len, void *buf); + int (*write)(struct spi_flash *flash, u32 offset, + size_t len, const void *buf); + int (*erase)(struct spi_flash *flash, u32 offset, + size_t len); +}; + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode); +void spi_flash_free(struct spi_flash *flash); + +static inline int spi_flash_read(struct spi_flash *flash, u32 offset, + size_t len, void *buf) +{ + return flash->read(flash, offset, len, buf); +} + +static inline int spi_flash_write(struct spi_flash *flash, u32 offset, + size_t len, const void *buf) +{ + return flash->write(flash, offset, len, buf); +} + +static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, + size_t len) +{ + return flash->erase(flash, offset, len); +} + +#endif /* _SPI_FLASH_H_ */ diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 8209980..6548b32 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -340,6 +340,7 @@ void sdram_initialize(struct pei_data *pei_data) /* If MRC data is not found we cannot continue S3 resume. */ if (pei_data->boot_mode == 2 && !pei_data->mrc_input) { + printk(BIOS_DEBUG, "Giving up in sdram_initialize: No MRC data\n"); outb(0x6, 0xcf9); hlt(); } diff --git a/src/southbridge/intel/bd82x6x/Kconfig b/src/southbridge/intel/bd82x6x/Kconfig index 3891be1..f105ee3 100644 --- a/src/southbridge/intel/bd82x6x/Kconfig +++ b/src/southbridge/intel/bd82x6x/Kconfig @@ -33,6 +33,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy select USE_WATCHDOG_ON_BOOT select PCIEXP_ASPM select PCIEXP_COMMON_CLOCK + select SPI config EHCI_BAR hex diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc index 5732254..f086426 100644 --- a/src/southbridge/intel/bd82x6x/Makefile.inc +++ b/src/southbridge/intel/bd82x6x/Makefile.inc @@ -34,6 +34,8 @@ ramstage-y += me_status.c ramstage-y += reset.c ramstage-y += watchdog.c +ramstage-y += spi.c + ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c $(me-src-y) finalize.c diff --git a/src/southbridge/intel/bd82x6x/spi.c b/src/southbridge/intel/bd82x6x/spi.c new file mode 100644 index 0000000..c54a325 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/spi.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* This file is derived from the flashrom project. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define min(a, b) ((a)<(b)?(a):(b)) + +typedef device_t pci_dev_t; +#define pci_read_config_byte(dev, reg, targ) *(targ) = pci_read_config8(dev, reg) +#define pci_read_config_word(dev, reg, targ) *(targ) = pci_read_config16(dev, reg) +#define pci_read_config_dword(dev, reg, targ) *(targ) = pci_read_config32(dev, reg) +#define pci_write_config_byte(dev, reg, val) pci_write_config8(dev, reg, val) +#define pci_write_config_word(dev, reg, val) pci_write_config16(dev, reg, val) +#define pci_write_config_dword(dev, reg, val) pci_write_config32(dev, reg, val) + +typedef struct spi_slave ich_spi_slave; + +static int ichspi_lock = 0; + +typedef struct ich7_spi_regs { + uint16_t spis; + uint16_t spic; + uint32_t spia; + uint64_t spid[8]; + uint64_t _pad; + uint32_t bbar; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; +} __attribute__((packed)) ich7_spi_regs; + +typedef struct ich9_spi_regs { + uint32_t bfpr; + uint16_t hsfs; + uint16_t hsfc; + uint32_t faddr; + uint32_t _reserved0; + uint32_t fdata[16]; + uint32_t frap; + uint32_t freg[5]; + uint32_t _reserved1[3]; + uint32_t pr[5]; + uint32_t _reserved2[2]; + uint8_t ssfs; + uint8_t ssfc[3]; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; + uint32_t bbar; + uint8_t _reserved3[12]; + uint32_t fdoc; + uint32_t fdod; + uint8_t _reserved4[8]; + uint32_t afc; + uint32_t lvscc; + uint32_t uvscc; + uint8_t _reserved5[4]; + uint32_t fpb; + uint8_t _reserved6[28]; + uint32_t srdl; + uint32_t srdc; + uint32_t srd; +} __attribute__((packed)) ich9_spi_regs; + +typedef struct ich_spi_controller { + int locked; + + uint8_t *opmenu; + int menubytes; + uint16_t *preop; + uint16_t *optype; + uint32_t *addr; + uint8_t *data; + unsigned databytes; + uint8_t *status; + uint16_t *control; + uint32_t *bbar; +} ich_spi_controller; + +static ich_spi_controller cntlr; + +enum { + SPIS_SCIP = 0x0001, + SPIS_GRANT = 0x0002, + SPIS_CDS = 0x0004, + SPIS_FCERR = 0x0008, + SSFS_AEL = 0x0010, + SPIS_LOCK = 0x8000, + SPIS_RESERVED_MASK = 0x7ff0, + SSFS_RESERVED_MASK = 0x7fe2 +}; + +enum { + SPIC_SCGO = 0x000002, + SPIC_ACS = 0x000004, + SPIC_SPOP = 0x000008, + SPIC_DBC = 0x003f00, + SPIC_DS = 0x004000, + SPIC_SME = 0x008000, + SSFC_SCF_MASK = 0x070000, + SSFC_RESERVED = 0xf80000 +}; + +enum { + HSFS_FDONE = 0x0001, + HSFS_FCERR = 0x0002, + HSFS_AEL = 0x0004, + HSFS_BERASE_MASK = 0x0018, + HSFS_BERASE_SHIFT = 3, + HSFS_SCIP = 0x0020, + HSFS_FDOPSS = 0x2000, + HSFS_FDV = 0x4000, + HSFS_FLOCKDN = 0x8000 +}; + +enum { + HSFC_FGO = 0x0001, + HSFC_FCYCLE_MASK = 0x0006, + HSFC_FCYCLE_SHIFT = 1, + HSFC_FDBC_MASK = 0x3f00, + HSFC_FDBC_SHIFT = 8, + HSFC_FSMIE = 0x8000 +}; + +enum { + SPI_OPCODE_TYPE_READ_NO_ADDRESS = 0, + SPI_OPCODE_TYPE_WRITE_NO_ADDRESS = 1, + SPI_OPCODE_TYPE_READ_WITH_ADDRESS = 2, + SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS = 3 +}; + +#ifdef DEBUG + +static u8 readb_(const void *addr) +{ + u8 v = readb(addr); + printk(BIOS_DEBUG, "read %2.2x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u16 readw_(const void *addr) +{ + u16 v = readw(addr); + printk(BIOS_DEBUG, "read %4.4x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u32 readl_(const void *addr) +{ + u32 v = readl(addr); + printk(BIOS_DEBUG, "read %8.8x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static void writeb_(u8 b, const void *addr) +{ + writeb(b, addr); + printk(BIOS_DEBUG, "wrote %2.2x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writew_(u16 b, const void *addr) +{ + writew(b, addr); + printk(BIOS_DEBUG, "wrote %4.4x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writel_(u32 b, const void *addr) +{ + writel(b, addr); + printk(BIOS_DEBUG, "wrote %8.8x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +#else /* DEBUG ^^^ defined vvv NOT defined */ + +#define readb_(a) read8((uint32_t)a) +#define readw_(a) read16((uint32_t)a) +#define readl_(a) read32((uint32_t)a) +#define writeb_(val, addr) write8((uint32_t)addr, val) +#define writew_(val, addr) write16((uint32_t)addr, val) +#define writel_(val, addr) write32((uint32_t)addr, val) + +#endif /* DEBUG ^^^ NOT defined */ + +static void write_reg(const void *value, void *dest, uint32_t size) +{ + const uint8_t *bvalue = value; + uint8_t *bdest = dest; + + while (size >= 4) { + writel_(*(const uint32_t *)bvalue, bdest); + bdest += 4; bvalue += 4; size -= 4; + } + while (size) { + writeb_(*bvalue, bdest); + bdest++; bvalue++; size--; + } +} + +static void read_reg(const void *src, void *value, uint32_t size) +{ + const uint8_t *bsrc = src; + uint8_t *bvalue = value; + + while (size >= 4) { + *(uint32_t *)bvalue = readl_(bsrc); + bsrc += 4; bvalue += 4; size -= 4; + } + while (size) { + *bvalue = readb_(bsrc); + bsrc++; bvalue++; size--; + } +} + +static void ich_set_bbar(uint32_t minaddr) +{ + const uint32_t bbar_mask = 0x00ffff00; + uint32_t ichspi_bbar; + + minaddr &= bbar_mask; + ichspi_bbar = readl_(cntlr.bbar) & ~bbar_mask; + ichspi_bbar |= minaddr; + writel_(ichspi_bbar, cntlr.bbar); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + printk(BIOS_DEBUG, "spi_cs_is_valid used but not implemented\n"); + return 0; +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + ich_spi_slave *slave = malloc(sizeof(*slave)); + + if (!slave) { + printk(BIOS_DEBUG, "ICH SPI: Bad allocation\n"); + return NULL; + } + + memset(slave, 0, sizeof(*slave)); + + slave->bus = bus; + slave->cs = cs; + return slave; +} + +void spi_free_slave(struct spi_slave *_slave) +{ + ich_spi_slave *slave = (ich_spi_slave *)_slave; + free(slave); +} + +static inline int spi_is_cougarpoint_lpc(uint16_t device_id) +{ + return device_id >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN && + device_id <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX; +}; + +void spi_init(void) +{ + int ich_version = 0; + + uint8_t *rcrb; /* Root Complex Register Block */ + uint32_t rcba; /* Root Complex Base Address */ + uint8_t bios_cntl; + pci_dev_t dev; + + int bus; + int last_bus = 1; //FIXME: pci_last_busno(); + + if (last_bus == -1) { + printk(BIOS_DEBUG, "No PCI busses?\n"); + return; + } + + for (bus = 0; bus <= last_bus; bus++) { + uint32_t ids; + uint16_t vendor_id, device_id; + + dev = dev_find_slot(bus, PCI_DEVFN(31, 0)); + pci_read_config_dword(dev, 0, &ids); + vendor_id = ids; + device_id = (ids >> 16); + + if (vendor_id != PCI_VENDOR_ID_INTEL) + continue; + + if (device_id == PCI_DEVICE_ID_INTEL_TGP_LPC) { + ich_version = 7; + break; + } else if (spi_is_cougarpoint_lpc(device_id)) { + ich_version = 9; + break; + } + } + + if (!ich_version) { + printk(BIOS_DEBUG, "ICH SPI: No ICH found.\n"); + return; + } + + pci_read_config_dword(dev, 0xf0, &rcba); + /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable. */ + rcrb = (uint8_t *)(rcba & 0xffffc000); + switch (ich_version) { + case 7: + { + const uint16_t ich7_spibar_offset = 0x3020; + ich7_spi_regs *ich7_spi = + (ich7_spi_regs *)(rcrb + ich7_spibar_offset); + + ichspi_lock = readw_(&ich7_spi->spis) & SPIS_LOCK; + cntlr.opmenu = ich7_spi->opmenu; + cntlr.menubytes = sizeof(ich7_spi->opmenu); + cntlr.optype = &ich7_spi->optype; + cntlr.addr = &ich7_spi->spia; + cntlr.data = (uint8_t *)ich7_spi->spid; + cntlr.databytes = sizeof(ich7_spi->spid); + cntlr.status = (uint8_t *)&ich7_spi->spis; + cntlr.control = &ich7_spi->spic; + cntlr.bbar = &ich7_spi->bbar; + cntlr.preop = &ich7_spi->preop; + break; + } + case 9: + { + const uint16_t ich9_spibar_offset = 0x3800; + ich9_spi_regs *ich9_spi = + (ich9_spi_regs *)(rcrb + ich9_spibar_offset); + ichspi_lock = readw_(&ich9_spi->hsfs) & HSFS_FLOCKDN; + cntlr.opmenu = ich9_spi->opmenu; + cntlr.menubytes = sizeof(ich9_spi->opmenu); + cntlr.optype = &ich9_spi->optype; + cntlr.addr = &ich9_spi->faddr; + cntlr.data = (uint8_t *)ich9_spi->fdata; + cntlr.databytes = sizeof(ich9_spi->fdata); + cntlr.status = &ich9_spi->ssfs; + cntlr.control = (uint16_t *)ich9_spi->ssfc; + cntlr.bbar = &ich9_spi->bbar; + cntlr.preop = &ich9_spi->preop; + break; + } + default: + printk(BIOS_DEBUG, "ICH SPI: Unrecognized ICH version %d.\n", ich_version); + } + + ich_set_bbar(0); + + /* Disable the BIOS write protect so write commands are allowed. */ + pci_read_config_byte(dev, 0xdc, &bios_cntl); + switch (ich_version) { + case 9: + /* Deassert SMM BIOS Write Protect Disable. */ + bios_cntl &= ~(1 << 5); + break; + + default: + break; + } + pci_write_config_byte(dev, 0xdc, bios_cntl | 0x1); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_activate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +typedef struct spi_transaction { + const uint8_t *out; + uint32_t bytesout; + uint8_t *in; + uint32_t bytesin; + uint8_t type; + uint8_t opcode; + uint32_t offset; +} spi_transaction; + +static inline void spi_use_out(spi_transaction *trans, unsigned bytes) +{ + trans->out += bytes; + trans->bytesout -= bytes; +} + +static inline void spi_use_in(spi_transaction *trans, unsigned bytes) +{ + trans->in += bytes; + trans->bytesin -= bytes; +} + +static void spi_setup_type(spi_transaction *trans) +{ + trans->type = 0xFF; + + /* Try to guess spi type from read/write sizes. */ + if (trans->bytesin == 0) { + if (trans->bytesout > 4) + /* + * If bytesin = 0 and bytesout > 4, we presume this is + * a write data operation, which is accompanied by an + * address. + */ + trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS; + else + trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS; + return; + } + + if (trans->bytesout == 1) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS; + return; + } + + if (trans->bytesout == 4) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS; + } +} + +static int spi_setup_opcode(spi_transaction *trans) +{ + uint16_t optypes; + uint8_t opmenu[cntlr.menubytes]; + + trans->opcode = trans->out[0]; + spi_use_out(trans, 1); + if (!ichspi_lock) { + /* The lock is off, so just use index 0. */ + writeb_(trans->opcode, cntlr.opmenu); + optypes = readw_(cntlr.optype); + optypes = (optypes & 0xfffc) | (trans->type & 0x3); + writew_(optypes, cntlr.optype); + return 0; + } else { + /* The lock is on. See if what we need is on the menu. */ + uint8_t optype; + uint16_t opcode_index; + + read_reg(cntlr.opmenu, opmenu, sizeof(opmenu)); + for (opcode_index = 0; opcode_index < cntlr.menubytes; + opcode_index++) { + if (opmenu[opcode_index] == trans->opcode) + break; + } + + if (opcode_index == cntlr.menubytes) { + printk(BIOS_DEBUG, "ICH SPI: Opcode %x not found\n", + trans->opcode); + return -1; + } + + optypes = readw_(cntlr.optype); + optype = (optypes >> (opcode_index * 2)) & 0x3; + if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS && + optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS && + trans->bytesout >= 3) { + /* We guessed wrong earlier. Fix it up. */ + trans->type = optype; + } + if (optype != trans->type) { + printk(BIOS_DEBUG, "ICH SPI: Transaction doesn't fit type %d\n", + optype); + return -1; + } + return opcode_index; + } +} + +static int spi_setup_offset(spi_transaction *trans) +{ + /* Separate the SPI address and data. */ + switch (trans->type) { + case SPI_OPCODE_TYPE_READ_NO_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_NO_ADDRESS: + return 0; + case SPI_OPCODE_TYPE_READ_WITH_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS: + trans->offset = ((uint32_t)trans->out[0] << 16) | + ((uint32_t)trans->out[1] << 8) | + ((uint32_t)trans->out[2] << 0); + spi_use_out(trans, 3); + return 1; + default: + printk(BIOS_DEBUG, "Unrecognized SPI transaction type %#x\n", trans->type); + return -1; + } +} + +/* + * Wait for up to 60ms til status register bit(s) turn 1 (in case wait_til_set + * below is True) or 0. In case the wait was for the bit(s) to set - write + * those bits back, which would cause resetting them. + * + * Return the last read status value on success or -1 on failure. + */ +static int ich_status_poll(u16 bitmask, int wait_til_set) +{ + int timeout = 6000; /* This will result in 60 ms */ + u16 status = 0; + + while (timeout--) { + status = readw_(cntlr.status); + if (wait_til_set ^ ((status & bitmask) == 0)) { + if (wait_til_set) + writew_((status & bitmask), cntlr.status); + return status; + } + udelay(10); + } + + printk(BIOS_DEBUG, "ICH SPI: SCIP timeout, read %x, expected %x\n", + status, bitmask); + return -1; +} + +int spi_xfer(struct spi_slave *slave, const void *dout, + unsigned int bitsout, void *din, unsigned int bitsin) +{ + uint16_t control; + int16_t opcode_index; + int with_address; + int status; + + spi_transaction trans = { + dout, bitsout / 8, + din, bitsin / 8, + 0xff, 0xff, 0 + }; + + /* There has to always at least be an opcode. */ + if (!bitsout || !dout) { + printk(BIOS_DEBUG, "ICH SPI: No opcode for transfer\n"); + return -1; + } + /* Make sure if we read something we have a place to put it. */ + if (bitsin != 0 && !din) { + printk(BIOS_DEBUG, "ICH SPI: Read but no target buffer\n"); + return -1; + } + /* Right now we don't support writing partial bytes. */ + if (bitsout % 8 || bitsin % 8) { + printk(BIOS_DEBUG, "ICH SPI: Accessing partial bytes not supported\n"); + return -1; + } + + if (ich_status_poll(SPIS_SCIP, 0) == -1) + return -1; + + writew_(SPIS_CDS | SPIS_FCERR, cntlr.status); + + spi_setup_type(&trans); + if ((opcode_index = spi_setup_opcode(&trans)) < 0) + return -1; + if ((with_address = spi_setup_offset(&trans)) < 0) + return -1; + + if (!ichspi_lock && trans.opcode == 0x06) { + /* + * Treat Write Enable as Atomic Pre-Op if possible + * in order to prevent the Management Engine from + * issuing a transaction between WREN and DATA. + */ + writew_(trans.opcode, cntlr.preop); + return 0; + } + + /* Preset control fields */ + control = SPIC_SCGO | ((opcode_index & 0x07) << 4); + + /* Issue atomic preop cycle if needed */ + if (readw_(cntlr.preop)) + control |= SPIC_ACS; + + if (!trans.bytesout && !trans.bytesin) { + /* + * This is a 'no data' command (like Write Enable), its + * bitesout size was 1, decremented to zero while executing + * spi_setup_opcode() above. Tell the chip to send the + * command. + */ + writew_(control, cntlr.control); + + /* wait for the result */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Command transaction error\n"); + return -1; + } + + return 0; + } + + /* + * Check if this is a write command atempting to transfer more bytes + * than the controller can handle. Iterations for writes are not + * supported here because each SPI write command needs to be preceded + * and followed by other SPI commands, and this sequence is controlled + * by the SPI chip driver. + */ + if (trans.bytesout > cntlr.databytes) { + printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use" + " CONTROLLER_PAGE_LIMIT?\n"); + return -1; + } + + /* + * Read or write up to databytes bytes at a time until everything has + * been sent. + */ + while (trans.bytesout || trans.bytesin) { + uint32_t data_length; + + /* SPI addresses are 24 bit only */ + writel_(trans.offset & 0x00FFFFFF, cntlr.addr); + + if (trans.bytesout) + data_length = min(trans.bytesout, cntlr.databytes); + else + data_length = min(trans.bytesin, cntlr.databytes); + + /* Program data into FDATA0 to N */ + if (trans.bytesout) { + write_reg(trans.out, cntlr.data, data_length); + spi_use_out(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + + /* Add proper control fields' values */ + control &= ~((cntlr.databytes - 1) << 8); + control |= SPIC_DS; + control |= (data_length - 1) << 8; + + /* write it */ + writew_(control, cntlr.control); + + /* Wait for Cycle Done Status or Flash Cycle Error. */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Data transaction error\n"); + return -1; + } + + if (trans.bytesin) { + read_reg(cntlr.data, trans.in, data_length); + spi_use_in(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + } + + /* Clear atomic preop now that xfer is done */ + writew_(0, cntlr.preop); + + return 0; +} From gerrit at coreboot.org Fri May 4 23:23:42 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Fri, 4 May 2012 23:23:42 +0200 Subject: [coreboot] Patch set updated for coreboot: 09ccbc4 Rework Sandybridge MRC cache handling References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1001 -gerrit commit 09ccbc48859f06bcda97e8b04b7c38a6e8b36640 Author: Stefan Reinauer Date: Thu May 3 16:38:09 2012 -0700 Rework Sandybridge MRC cache handling - Separate Sandybridge from ChromeOS a bit The Sandybridge code depends on chromeos features a whole lot. As a first step, provide a code path to look up the MRC cache without depending on u-boot. - Move mrc cache handling to separate file This enables us to handle the MRC cache from ramstage, where we can write the flash safely (eg. to update the cache). Also teach it to lookup the current MRC cache from CBMEM, as the original data block isn't available anymore. After all the preparations, finally write to the SPI as necessary. It's a simple round robin wear levelling that erases the entire MRC cache region when it's full and starts from the beginning. Change-Id: I4751385574cf709b03d5c9d153b7481ffc90ce12 Signed-off-by: Patrick Georgi --- src/northbridge/intel/sandybridge/Kconfig | 17 ++ src/northbridge/intel/sandybridge/Makefile.inc | 2 + src/northbridge/intel/sandybridge/mrccache.c | 265 +++++++++++++++++++++++ src/northbridge/intel/sandybridge/raminit.c | 123 +---------- src/northbridge/intel/sandybridge/sandybridge.h | 22 ++ 5 files changed, 315 insertions(+), 114 deletions(-) diff --git a/src/northbridge/intel/sandybridge/Kconfig b/src/northbridge/intel/sandybridge/Kconfig index 8cf0a49..67b3def 100644 --- a/src/northbridge/intel/sandybridge/Kconfig +++ b/src/northbridge/intel/sandybridge/Kconfig @@ -37,6 +37,23 @@ config CACHE_MRC_SIZE_KB int default 256 +# FIXME: build from rom size +config MRC_CACHE_BASE + hex + default 0xff800000 + +config MRC_CACHE_LOCATION + hex + default 0x1ec000 + +config MRC_CACHE_SIZE + hex + default 0x10000 + +config MRC_CACHE_ALIGNMENT + hex + default 0x1000 + config DCACHE_RAM_BASE hex default 0xff7f0000 diff --git a/src/northbridge/intel/sandybridge/Makefile.inc b/src/northbridge/intel/sandybridge/Makefile.inc index 87a0b2e..824700e 100644 --- a/src/northbridge/intel/sandybridge/Makefile.inc +++ b/src/northbridge/intel/sandybridge/Makefile.inc @@ -21,9 +21,11 @@ driver-y += northbridge.c driver-y += gma.c ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += acpi.c +ramstage-y += mrccache.c romstage-y += udelay.c romstage-y += raminit.c +romstage-y += mrccache.c romstage-y += early_init.c romstage-y += report_platform.c romstage-y += ../../../arch/x86/lib/walkcbfs.S diff --git a/src/northbridge/intel/sandybridge/mrccache.c b/src/northbridge/intel/sandybridge/mrccache.c new file mode 100644 index 0000000..5c4c382 --- /dev/null +++ b/src/northbridge/intel/sandybridge/mrccache.c @@ -0,0 +1,265 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Google Inc. + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include "pei_data.h" +#include "sandybridge.h" +#include +#include +/* Using the FDT FMAP for finding the MRC cache area requires including FDT + * support in coreboot, which we would like to avoid. There are a number of + * options: + * - Have each mainboard Kconfig supply a hard-coded offset + * - For ChromeOS devices: implement native FMAP + * - For non-ChromeOS devices: use CBFS + * For now let's leave this code in here until the issue is sorted out in + * a way that works for everyone. + */ +#undef USE_FDT_FMAP_FOR_MRC_CACHE +#ifdef USE_FDT_FMAP_FOR_MRC_CACHE +#include +#endif + +struct mrc_data_container *next_mrc_block(struct mrc_data_container *mrc_cache) +{ + /* MRC data blocks are aligned within the region */ + u32 mrc_size = sizeof(*mrc_cache) + mrc_cache->mrc_data_size; + if (mrc_size & (MRC_DATA_ALIGN - 1UL)) { + mrc_size &= ~(MRC_DATA_ALIGN - 1UL); + mrc_size += MRC_DATA_ALIGN; + } + + u8 *region_ptr = (u8*)mrc_cache; + region_ptr += mrc_size; + return (struct mrc_data_container *)region_ptr; +} + +int is_mrc_cache(struct mrc_data_container *mrc_cache) +{ + return (!!mrc_cache) && (mrc_cache->mrc_signature == MRC_DATA_SIGNATURE); +} + +u32 get_mrc_cache_region(struct mrc_data_container **mrc_region_ptr) +{ + u8 *mrc_region; + u32 region_size; + u32 *data; +#ifdef USE_FDT_FMAP_FOR_MRC_CACHE + const struct fdt_header *fdt_header; + const struct fdt_property *fdtp; + int offset, len; + const char *compatible = "chromeos,flashmap"; + const char *subnode = "rw-mrc-cache"; + const char *property = "reg"; + u64 flashrom_base = 0; + + fdt_header = cbfs_find_file(CONFIG_FDT_FILE_NAME, CBFS_TYPE_FDT); + + if (!fdt_header) { + printk(BIOS_ERR, "%s: no FDT found!\n", __func__); + return 0; + } + + offset = fdt_node_offset_by_compatible(fdt_header, 0, compatible); + if (offset < 0) { + printk(BIOS_ERR, "%s: no %s node found!\n", + __func__, compatible); + return 0; + } + + if (fdt_get_base_addr(fdt_header, offset, &flashrom_base) < 0) { + printk(BIOS_ERR, "%s: no base address in node name!\n", + __func__); + return 0; + } + + offset = fdt_subnode_offset(fdt_header, offset, subnode); + if (offset < 0) { + printk(BIOS_ERR, "%s: no %s found!\n", __func__, subnode); + return 0; + } + + fdtp = fdt_get_property(fdt_header, offset, property, &len); + if (!fdtp || (len != 8)) { + printk(BIOS_ERR, "%s: property %s at %p, len %d!\n", + __func__, property, fdtp, len); + return 0; + } + + data = (u32 *)fdtp->data; + + // Calculate actual address of the MRC cache in memory + region_size = fdt32_to_cpu(data[1]); + mrc_region = (u8*)((unsigned long)flashrom_base + fdt32_to_cpu(data[0])); +#else + data = (u32 *)((void *)(CONFIG_MRC_CACHE_BASE + CONFIG_MRC_CACHE_LOCATION + 12)); + + region_size = CONFIG_MRC_CACHE_SIZE; + mrc_region = (u8*)(CONFIG_MRC_CACHE_BASE + be32_to_cpu(data[0])); +#endif + + *mrc_region_ptr = (struct mrc_data_container *)mrc_region; + + return region_size; +} + +/* find the first empty field in the MRC cache area. If there's none, return + * the first region. By testing for emptiness caller can detect if flash + * needs to be erased. + * + * FIXME: that interface is crap + */ +struct mrc_data_container *find_next_mrc_cache(void) +{ + u32 entry_id = 0; + struct mrc_data_container *mrc_cache = NULL; + u32 region_size = get_mrc_cache_region(&mrc_cache); + void *mrc_region = (void*)mrc_cache; + + if (mrc_cache == NULL) { + printk(BIOS_ERR, "%s: could not find mrc cache area\n", __func__); + return NULL; + } + + /* Search for the first empty entry in the region */ + while (is_mrc_cache(mrc_cache)) { + entry_id++; + mrc_cache = next_mrc_block(mrc_cache); + /* If we exceed the defined area, move to front */ + if ((void*)mrc_cache >= (void*)(mrc_region + region_size)) { + mrc_cache = (struct mrc_data_container *)mrc_region; + break; + } + } + + printk(BIOS_DEBUG, "picked entry %u from cache block when looking for empty block\n", entry_id); + + return mrc_cache; +} + +struct mrc_data_container *find_current_mrc_cache(void) +{ + u32 entry_id = 0; + struct mrc_data_container *mrc_next, *mrc_cache = NULL; + u32 region_size = get_mrc_cache_region(&mrc_cache); + void *mrc_region = (void*)mrc_cache; + mrc_next = mrc_cache; + + if (mrc_cache == NULL) { + printk(BIOS_ERR, "%s: could not find mrc cache area\n", __func__); + return NULL; + } + + if (mrc_cache->mrc_data_size == -1UL) { + printk(BIOS_ERR, "%s: MRC cache not initialized?\n", __func__); + /* return non-initialized cache, so we can discern this + * from having no cache area at all + */ + return mrc_cache; + } else { + /* Search for the last filled entry in the region */ + while (is_mrc_cache(mrc_next)) { + entry_id++; + mrc_cache = mrc_next; + mrc_next = next_mrc_block(mrc_cache); + /* Stay in the mrcdata region defined in fdt */ + if ((void*)mrc_next >= (void*)(mrc_region + region_size)) + break; + } + entry_id--; + } + + /* Verify checksum */ + if (mrc_cache->mrc_checksum != + compute_ip_checksum(mrc_cache->mrc_data, + mrc_cache->mrc_data_size)) { + printk(BIOS_ERR, "%s: MRC cache checksum mismatch\n", __func__); + return NULL; + } + + printk(BIOS_DEBUG, "picked entry %u from cache block\n", entry_id); + + return mrc_cache; +} + +/* SPI code needs malloc/free. + * Also unknown if writing flash from XIP-flash code is a good idea + */ +#if !defined(__PRE_RAM__) +void update_mrc_cache(void) +{ + struct mrc_data_container *current = cbmem_find(CBMEM_ID_MRCDATA); + if (!current) { + printk(BIOS_ERR, "No MRC cache in cbmem. Can't update flash.\n"); + return; + } + if (current->mrc_data_size == -1) { + printk(BIOS_ERR, "MRC cache data in cbmem invalid.\n"); + return; + } + + /* + * we need to: + */ + // 0. compare MRC data to last mrc-cache block (exit if same) + struct mrc_data_container *cache; + if ((cache = find_current_mrc_cache()) == NULL) { + printk(BIOS_DEBUG, "Failure looking for current last block\n"); + return; + } + + if ((cache->mrc_data_size == current->mrc_data_size) && (memcmp(cache, current, cache->mrc_data_size) == 0)) { + printk(BIOS_DEBUG, "MRC data in flash is up to date. No update.\n"); + return; + } + + // 1. use spi_flash_probe() to find the flash, then + spi_init(); + struct spi_flash *flash = spi_flash_probe(0, 0, 1000000, SPI_MODE_3); + if (!flash) { + printk(BIOS_DEBUG, "Could not find SPI device\n"); + return; + } + + // 2. look up the first unused block + cache = find_next_mrc_cache(); + if (!cache) { + printk(BIOS_DEBUG, "Could not find MRC cache area\n"); + return; + } + + // 3. if no such place exists, erase entire mrc-cache range & use block 0 + if (cache->mrc_data_size != -1) { + printk(BIOS_DEBUG, "We need to erase the MRC cache region\n"); + flash->erase(flash, CONFIG_MRC_CACHE_LOCATION, CONFIG_MRC_CACHE_SIZE); + /* we know we can start at the beginning again */ + get_mrc_cache_region(&cache); + } + // 4. write mrc data with flash->write() + printk(BIOS_DEBUG, "Finally: write MRC cache update to flash\n"); + flash->write(flash, (u32)(((void*)cache)-CONFIG_MRC_CACHE_BASE), current->mrc_data_size + sizeof(*current), current); +} +#endif + diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 6548b32..0df86d6 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -36,9 +36,8 @@ #include "southbridge/intel/bd82x6x/me.h" #if CONFIG_CHROMEOS #include -#endif -#if 0 -#include +#else +#define recovery_mode_enabled(x) 0 #endif /* @@ -56,17 +55,6 @@ #define CMOS_OFFSET_MRC_SEED_CHK 120 #endif -#define MRC_DATA_ALIGN 0x1000 -#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24)) - -struct mrc_data_container { - u32 mrc_signature; // "MRCD" - u32 mrc_data_size; // Actual total size of this structure - u32 mrc_checksum; // IP style checksum - u32 reserved; // For header alignment - u8 mrc_data[0]; // Variable size, platform/run time dependent. -} __attribute__ ((packed)); - static void save_mrc_data(struct pei_data *pei_data) { u16 c1, c2, checksum; @@ -119,22 +107,10 @@ static void save_mrc_data(struct pei_data *pei_data) cmos_write((checksum >> 8) & 0xff, CMOS_OFFSET_MRC_SEED_CHK+1); } -#if CONFIG_CHROMEOS static void prepare_mrc_cache(struct pei_data *pei_data) { -#if 0 - const struct fdt_header *fdt_header; - const struct fdt_property *fdtp; - int offset, len; - const char *compatible = "chromeos,flashmap"; - const char *subnode = "rw-mrc-cache"; - const char *property = "reg"; - u32 *data; - struct mrc_data_container *mrc_cache, *mrc_next; - u8 *mrc_region, *region_ptr; + struct mrc_data_container *mrc_cache; u16 c1, c2, checksum, seed_checksum; - u32 region_size, entry_id = 0; - u64 flashrom_base = 0; // preset just in case there is an error pei_data->mrc_input = NULL; @@ -166,96 +142,18 @@ static void prepare_mrc_cache(struct pei_data *pei_data) return; } - fdt_header = cbfs_find_file(CONFIG_FDT_FILE_NAME, CBFS_TYPE_FDT); - - if (!fdt_header) { - printk(BIOS_ERR, "%s: no FDT found!\n", __func__); - return; - } - - offset = fdt_node_offset_by_compatible(fdt_header, 0, compatible); - if (offset < 0) { - printk(BIOS_ERR, "%s: no %s node found!\n", - __func__, compatible); - return; - } - - if (fdt_get_base_addr(fdt_header, offset, &flashrom_base) < 0) { - printk(BIOS_ERR, "%s: no base address in node name!\n", - __func__); - return; - } - - offset = fdt_subnode_offset(fdt_header, offset, subnode); - if (offset < 0) { - printk(BIOS_ERR, "%s: no %s found!\n", __func__, subnode); - return; - } - - fdtp = fdt_get_property(fdt_header, offset, property, &len); - if (!fdtp || (len != 8)) { - printk(BIOS_ERR, "%s: property %s at %p, len %d!\n", - __func__, property, fdtp, len); - return; - } - - data = (u32 *)fdtp->data; - - // Calculate actual address of the MRC cache in memory - region_size = fdt32_to_cpu(data[1]); - mrc_region = region_ptr = (u8*) - ((unsigned long)flashrom_base + fdt32_to_cpu(data[0])); - mrc_cache = mrc_next = (struct mrc_data_container *)mrc_region; - - if (!mrc_cache || mrc_cache->mrc_signature != MRC_DATA_SIGNATURE) { - printk(BIOS_ERR, "%s: invalid MRC data\n", __func__); - return; - } - - if (mrc_cache->mrc_data_size == -1UL) { - printk(BIOS_ERR, "%s: MRC cache not initialized?\n", __func__); - return; - } else { - /* MRC data blocks are aligned within the region */ - u32 mrc_size = sizeof(*mrc_cache) + mrc_cache->mrc_data_size; - if (mrc_size & (MRC_DATA_ALIGN - 1UL)) { - mrc_size &= ~(MRC_DATA_ALIGN - 1UL); - mrc_size += MRC_DATA_ALIGN; - } - - /* Search for the last filled entry in the region */ - while (mrc_next && - mrc_next->mrc_signature == MRC_DATA_SIGNATURE) { - entry_id++; - mrc_cache = mrc_next; - /* Stay in the mrcdata region defined in fdt */ - if ((entry_id * mrc_size) > region_size) - break; - region_ptr += mrc_size; - mrc_next = (struct mrc_data_container *)region_ptr; - } - entry_id--; - } - - /* Verify checksum */ - if (mrc_cache->mrc_checksum != - compute_ip_checksum(mrc_cache->mrc_data, - mrc_cache->mrc_data_size)) { - printk(BIOS_ERR, "%s: MRC cache checksum mismatch\n", __func__); + if ((mrc_cache = find_current_mrc_cache()) == NULL) { + /* error message printed in find_current_mrc_cache */ return; } pei_data->mrc_input = mrc_cache->mrc_data; pei_data->mrc_input_len = mrc_cache->mrc_data_size; - printk(BIOS_DEBUG, "%s: at %p, entry %u size %x checksum %04x\n", - __func__, pei_data->mrc_input, entry_id, + printk(BIOS_DEBUG, "%s: at %p, size %x checksum %04x\n", + __func__, pei_data->mrc_input, pei_data->mrc_input_len, mrc_cache->mrc_checksum); -#else - printk(BIOS_ERR, "MRC cache handling code has to be redone.\n"); -#endif } -#endif static const char* ecc_decoder[] = { "inactive", @@ -315,7 +213,6 @@ static void report_memory_config(void) void sdram_initialize(struct pei_data *pei_data) { struct sys_info sysinfo; - const char *target = "mrc.bin"; unsigned long entry; report_platform_info(); @@ -330,7 +227,6 @@ void sdram_initialize(struct pei_data *pei_data) sysinfo.boot_path = pei_data->boot_mode; -#if CONFIG_CHROMEOS /* * Do not pass MRC data in for recovery mode boot, * Always pass it in for S3 resume. @@ -344,17 +240,16 @@ void sdram_initialize(struct pei_data *pei_data) outb(0x6, 0xcf9); hlt(); } -#endif /* Locate and call UEFI System Agent binary. */ - entry = (unsigned long)cbfs_find_file(target, 0xab); + entry = (unsigned long)cbfs_find_file("mrc.bin", 0xab); if (entry) { int rv; asm volatile ( "call *%%ecx\n\t" :"=a" (rv) : "c" (entry), "a" (pei_data)); if (rv) { - printk(BIOS_ERR, "MRC returned %d\n", rv); + printk(BIOS_ERR, "MRC returned %x\n", rv); die("Nonzero MRC return value\n"); } } else { diff --git a/src/northbridge/intel/sandybridge/sandybridge.h b/src/northbridge/intel/sandybridge/sandybridge.h index aa62021..7e12416 100644 --- a/src/northbridge/intel/sandybridge/sandybridge.h +++ b/src/northbridge/intel/sandybridge/sandybridge.h @@ -221,6 +221,28 @@ void dump_spd_registers(void); void dump_mem(unsigned start, unsigned end); void report_platform_info(void); #endif /* !__SMM__ */ + + +#define MRC_DATA_ALIGN 0x1000 +#define MRC_DATA_SIGNATURE (('M'<<0)|('R'<<8)|('C'<<16)|('D'<<24)) + +struct mrc_data_container { + u32 mrc_signature; // "MRCD" + u32 mrc_data_size; // Actual total size of this structure + u32 mrc_checksum; // IP style checksum + u32 reserved; // For header alignment + u8 mrc_data[0]; // Variable size, platform/run time dependent. +} __attribute__ ((packed)); + +struct mrc_data_container *next_mrc_block(struct mrc_data_container *mrc_cache); +int is_mrc_cache(struct mrc_data_container *mrc_cache); +u32 get_mrc_cache_region(struct mrc_data_container **mrc_region_ptr); +struct mrc_data_container *find_next_mrc_cache(void); +struct mrc_data_container *find_current_mrc_cache(void); +#if !defined(__PRE_RAM__) +void update_mrc_cache(void); +#endif + #endif #endif #endif From gerrit at coreboot.org Fri May 4 23:24:27 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Fri, 4 May 2012 23:24:27 +0200 Subject: [coreboot] Patch set updated for coreboot: 2635d03 Hook up MRC cache update References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1002 -gerrit commit 2635d031351d17a21bc37a8e79ed0dbbfae7db15 Author: Stefan Reinauer Date: Thu May 3 16:40:41 2012 -0700 Hook up MRC cache update This one is a WIP: - should not depend on CONFIG_CHROMEOS - There might be a better place for it. Requirements: - must be in ramstage (locking flash while executing code from there might not work) - must be after cbmem is reinitialized (so the mrc cache copy of the current run can be found) Change-Id: I8028fb073349ce2b027ef5f8397dc1a1b8b31c02 Signed-off-by: Patrick Georgi --- src/arch/x86/boot/tables.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/src/arch/x86/boot/tables.c b/src/arch/x86/boot/tables.c index 4fefc7d..ff57422 100644 --- a/src/arch/x86/boot/tables.c +++ b/src/arch/x86/boot/tables.c @@ -53,6 +53,11 @@ struct lb_memory *write_tables(void) */ unsigned long high_table_pointer; +#if CONFIG_CHROMEOS + void update_mrc_cache(void); + update_mrc_cache(); +#endif + if (!high_tables_base) { printk(BIOS_ERR, "ERROR: High Tables Base is not set.\n"); // Are there any boards without? From gerrit at coreboot.org Fri May 4 23:24:59 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Fri, 4 May 2012 23:24:59 +0200 Subject: [coreboot] Patch set updated for coreboot: ce910c0 Add SPI driver References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/997 -gerrit commit ce910c08abdc68d5e5e3e7e62628ae361b3db83b Author: Stefan Reinauer Date: Wed May 2 17:07:05 2012 -0700 Add SPI driver This driver is taken from u-boot and adapted to match coreboot. It still contains some hacks and is ICH specific at places. Change-Id: I97dd8096f7db3b62f8f4f4e4d08bdee10d88f689 Signed-off-by: Patrick Georgi --- src/drivers/Kconfig | 1 + src/drivers/Makefile.inc | 1 + src/drivers/spi/Kconfig | 73 +++ src/drivers/spi/Makefile.inc | 12 + src/drivers/spi/eon.c | 161 ++++++ src/drivers/spi/macronix.c | 220 +++++++++ src/drivers/spi/spansion.c | 241 +++++++++ src/drivers/spi/spi_flash.c | 309 ++++++++++++ src/drivers/spi/spi_flash_internal.h | 81 +++ src/drivers/spi/sst.c | 268 ++++++++++ src/drivers/spi/stmicro.c | 250 ++++++++++ src/drivers/spi/winbond.c | 218 ++++++++ src/include/device/pci_ids.h | 4 + src/include/spi.h | 203 ++++++++ src/include/spi_flash.h | 91 ++++ src/northbridge/intel/sandybridge/raminit.c | 1 + src/southbridge/intel/bd82x6x/Kconfig | 1 + src/southbridge/intel/bd82x6x/Makefile.inc | 2 + src/southbridge/intel/bd82x6x/spi.c | 712 +++++++++++++++++++++++++++ 19 files changed, 2849 insertions(+), 0 deletions(-) diff --git a/src/drivers/Kconfig b/src/drivers/Kconfig index 259bc29..60e5b65 100644 --- a/src/drivers/Kconfig +++ b/src/drivers/Kconfig @@ -26,3 +26,4 @@ source src/drivers/oxford/Kconfig source src/drivers/sil/Kconfig source src/drivers/trident/Kconfig source src/drivers/ics/Kconfig +source src/drivers/spi/Kconfig diff --git a/src/drivers/Makefile.inc b/src/drivers/Makefile.inc index 5f6dadf..851a4df 100644 --- a/src/drivers/Makefile.inc +++ b/src/drivers/Makefile.inc @@ -26,4 +26,5 @@ subdirs-y += oxford subdirs-y += sil subdirs-y += trident subdirs-y += ics +subdirs-y += spi subdirs-$(CONFIG_ARCH_X86) += pc80 diff --git a/src/drivers/spi/Kconfig b/src/drivers/spi/Kconfig new file mode 100644 index 0000000..849d0ac --- /dev/null +++ b/src/drivers/spi/Kconfig @@ -0,0 +1,73 @@ +## +## This file is part of the coreboot project. +## +## Copyright (C) 2012 The Chromium OS Authors. +## +## 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; version 2 of the License. +## +## 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +## + +config SPI + bool + default n + help + Select this option if your chipset driver needs to store certain + data in the SPI flash. + +config SPI_FLASH_EON + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by EON. + +config SPI_FLASH_MACRONIX + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by Macronix. + +config SPI_FLASH_SPANSION + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by Spansion. + +config SPI_FLASH_SST + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by SST. + +config SPI_FLASH_STMICRO + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by ST MICRO. + +config SPI_FLASH_WINBOND + bool + default y + depends on SPI + help + Select this option if your chipset driver needs to store certain + data in the SPI flash and your SPI flash is made by Winbond. diff --git a/src/drivers/spi/Makefile.inc b/src/drivers/spi/Makefile.inc new file mode 100644 index 0000000..6cdf398 --- /dev/null +++ b/src/drivers/spi/Makefile.inc @@ -0,0 +1,12 @@ +# SPI driver interface +ramstage-$(CONFIG_SPI) += spi_flash.c + +# drivers +ramstage-$(CONFIG_SPI_FLASH_EON) += eon.c +ramstage-$(CONFIG_SPI_FLASH_MACRONIX) += macronix.c +ramstage-$(CONFIG_SPI_FLASH_SPANSION) += spansion.c +ramstage-$(CONFIG_SPI_FLASH_SST) += sst.c +ramstage-$(CONFIG_SPI_FLASH_STMICRO) += stmicro.c +ramstage-$(CONFIG_SPI_FLASH_WINBOND) += winbond.c +ramstage-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.c + diff --git a/src/drivers/spi/eon.c b/src/drivers/spi/eon.c new file mode 100644 index 0000000..4056953 --- /dev/null +++ b/src/drivers/spi/eon.c @@ -0,0 +1,161 @@ +/* + * (C) Copyright 2010, ucRobotics Inc. + * Author: Chong Huang + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* EN25Q128-specific commands */ +#define CMD_EN25Q128_WREN 0x06 /* Write Enable */ +#define CMD_EN25Q128_WRDI 0x04 /* Write Disable */ +#define CMD_EN25Q128_RDSR 0x05 /* Read Status Register */ +#define CMD_EN25Q128_WRSR 0x01 /* Write Status Register */ +#define CMD_EN25Q128_READ 0x03 /* Read Data Bytes */ +#define CMD_EN25Q128_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_EN25Q128_PP 0x02 /* Page Program */ +#define CMD_EN25Q128_SE 0x20 /* Sector Erase */ +#define CMD_EN25Q128_BE 0xd8 /* Block Erase */ +#define CMD_EN25Q128_DP 0xb9 /* Deep Power-down */ +#define CMD_EN25Q128_RES 0xab /* Release from DP, and Read Signature */ + +#define EON_ID_EN25Q128 0x18 + +struct eon_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 sectors_per_block; + u16 nr_sectors; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct eon_spi_flash { + struct spi_flash flash; + const struct eon_spi_flash_params *params; +}; + +static inline struct eon_spi_flash *to_eon_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct eon_spi_flash, flash); +} + +static const struct eon_spi_flash_params eon_spi_flash_table[] = { + { + .idcode1 = EON_ID_EN25Q128, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_sectors = 4096, + .name = "EN25Q128", + }, +}; + +static int eon_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct eon_spi_flash *eon = to_eon_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = eon->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_EN25Q128_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, + "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_EN25Q128_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: EON Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: EON: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int eon_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_EN25Q128_BE, offset, len); +} + +struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode) +{ + const struct eon_spi_flash_params *params; + struct eon_spi_flash *eon; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(eon_spi_flash_table); ++i) { + params = &eon_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(eon_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported EON ID %02x\n", idcode[1]); + return NULL; + } + + eon = malloc(sizeof(*eon)); + if (!eon) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + eon->params = params; + eon->flash.spi = spi; + eon->flash.name = params->name; + + eon->flash.write = eon_write; + eon->flash.erase = eon_erase; + eon->flash.read = spi_flash_cmd_read_fast; + eon->flash.sector_size = params->page_size * params->pages_per_sector + * params->sectors_per_block; + eon->flash.size = params->page_size * params->pages_per_sector + * params->nr_sectors; + + return &eon->flash; +} diff --git a/src/drivers/spi/macronix.c b/src/drivers/spi/macronix.c new file mode 100644 index 0000000..130e746 --- /dev/null +++ b/src/drivers/spi/macronix.c @@ -0,0 +1,220 @@ +/* + * Copyright 2009(C) Marvell International Ltd. and its affiliates + * Prafulla Wadaskar + * + * Based on drivers/mtd/spi/stmicro.c + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* MX25xx-specific commands */ +#define CMD_MX25XX_WREN 0x06 /* Write Enable */ +#define CMD_MX25XX_WRDI 0x04 /* Write Disable */ +#define CMD_MX25XX_RDSR 0x05 /* Read Status Register */ +#define CMD_MX25XX_WRSR 0x01 /* Write Status Register */ +#define CMD_MX25XX_READ 0x03 /* Read Data Bytes */ +#define CMD_MX25XX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_MX25XX_PP 0x02 /* Page Program */ +#define CMD_MX25XX_SE 0x20 /* Sector Erase */ +#define CMD_MX25XX_BE 0xD8 /* Block Erase */ +#define CMD_MX25XX_CE 0xc7 /* Chip Erase */ +#define CMD_MX25XX_DP 0xb9 /* Deep Power-down */ +#define CMD_MX25XX_RES 0xab /* Release from DP, and Read Signature */ + +#define MACRONIX_SR_WIP (1 << 0) /* Write-in-Progress */ + +struct macronix_spi_flash_params { + u16 idcode; + u16 page_size; + u16 pages_per_sector; + u16 sectors_per_block; + u16 nr_blocks; + const char *name; +}; + +struct macronix_spi_flash { + struct spi_flash flash; + const struct macronix_spi_flash_params *params; +}; + +static inline struct macronix_spi_flash *to_macronix_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct macronix_spi_flash, flash); +} + +static const struct macronix_spi_flash_params macronix_spi_flash_table[] = { + { + .idcode = 0x2015, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "MX25L1605D", + }, + { + .idcode = 0x2016, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "MX25L3205D", + }, + { + .idcode = 0x2017, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "MX25L6405D", + }, + { + .idcode = 0x2018, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "MX25L12805D", + }, + { + .idcode = 0x2618, + .page_size = 256, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "MX25L12855E", + }, +}; + +static int macronix_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct macronix_spi_flash *mcx = to_macronix_spi_flash(flash); + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = min(mcx->params->page_size, CONTROLLER_PAGE_LIMIT); + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_MX25XX_PP; + cmd[1] = (offset >> 16) & 0xff; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_MX25XX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Macronix Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + offset += chunk_len; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: Macronix: Successfully programmed %zu bytes @ 0x%lx\n", + len, offset - len); + + spi_release_bus(flash->spi); + return ret; +} + +static int macronix_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_MX25XX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode) +{ + const struct macronix_spi_flash_params *params; + struct macronix_spi_flash *mcx; + unsigned int i; + u16 id = idcode[2] | idcode[1] << 8; + + for (i = 0; i < ARRAY_SIZE(macronix_spi_flash_table); i++) { + params = ¯onix_spi_flash_table[i]; + if (params->idcode == id) + break; + } + + if (i == ARRAY_SIZE(macronix_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported Macronix ID %04x\n", id); + return NULL; + } + + mcx = malloc(sizeof(*mcx)); + if (!mcx) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + mcx->params = params; + mcx->flash.spi = spi; + mcx->flash.name = params->name; + + mcx->flash.write = macronix_write; + mcx->flash.erase = macronix_erase; +#ifdef CONFIG_SPI_FLASH_NO_FAST_READ + mcx->flash.read = spi_flash_cmd_read_slow; +#else + mcx->flash.read = spi_flash_cmd_read_fast; +#endif + mcx->flash.sector_size = params->page_size * params->pages_per_sector; + mcx->flash.size = mcx->flash.sector_size * params->sectors_per_block * + params->nr_blocks; + + return &mcx->flash; +} diff --git a/src/drivers/spi/spansion.c b/src/drivers/spi/spansion.c new file mode 100644 index 0000000..a4f370a --- /dev/null +++ b/src/drivers/spi/spansion.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2009 Freescale Semiconductor, Inc. + * + * Author: Mingkai Hu (Mingkai.hu at freescale.com) + * Based on stmicro.c by Wolfgang Denk (wd at denx.de), + * TsiChung Liew (Tsi-Chung.Liew at freescale.com), + * and Jason McMullan (mcmullan at netapp.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* S25FLxx-specific commands */ +#define CMD_S25FLXX_READ 0x03 /* Read Data Bytes */ +#define CMD_S25FLXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_S25FLXX_READID 0x90 /* Read Manufacture ID and Device ID */ +#define CMD_S25FLXX_WREN 0x06 /* Write Enable */ +#define CMD_S25FLXX_WRDI 0x04 /* Write Disable */ +#define CMD_S25FLXX_RDSR 0x05 /* Read Status Register */ +#define CMD_S25FLXX_WRSR 0x01 /* Write Status Register */ +#define CMD_S25FLXX_PP 0x02 /* Page Program */ +#define CMD_S25FLXX_SE 0xd8 /* Sector Erase */ +#define CMD_S25FLXX_BE 0xc7 /* Bulk Erase */ +#define CMD_S25FLXX_DP 0xb9 /* Deep Power-down */ +#define CMD_S25FLXX_RES 0xab /* Release from DP, and Read Signature */ + +#define SPSN_ID_S25FL008A 0x0213 +#define SPSN_ID_S25FL016A 0x0214 +#define SPSN_ID_S25FL032A 0x0215 +#define SPSN_ID_S25FL064A 0x0216 +#define SPSN_ID_S25FL128P 0x2018 +#define SPSN_EXT_ID_S25FL128P_256KB 0x0300 +#define SPSN_EXT_ID_S25FL128P_64KB 0x0301 +#define SPSN_EXT_ID_S25FL032P 0x4d00 + +struct spansion_spi_flash_params { + u16 idcode1; + u16 idcode2; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +struct spansion_spi_flash { + struct spi_flash flash; + const struct spansion_spi_flash_params *params; +}; + +static inline struct spansion_spi_flash *to_spansion_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct spansion_spi_flash, flash); +} + +static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { + { + .idcode1 = SPSN_ID_S25FL008A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "S25FL008A", + }, + { + .idcode1 = SPSN_ID_S25FL016A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "S25FL016A", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032A", + }, + { + .idcode1 = SPSN_ID_S25FL064A, + .idcode2 = 0, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "S25FL064A", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_64KB, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 256, + .name = "S25FL128P_64K", + }, + { + .idcode1 = SPSN_ID_S25FL128P, + .idcode2 = SPSN_EXT_ID_S25FL128P_256KB, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "S25FL128P_256K", + }, + { + .idcode1 = SPSN_ID_S25FL032A, + .idcode2 = SPSN_EXT_ID_S25FL032P, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "S25FL032P", + }, +}; + +static int spansion_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct spansion_spi_flash *spsn = to_spansion_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = spsn->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_S25FLXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_S25FLXX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: SPANSION Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: SPANSION: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int spansion_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_S25FLXX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) +{ + const struct spansion_spi_flash_params *params; + struct spansion_spi_flash *spsn; + unsigned int i; + unsigned short jedec, ext_jedec; + + jedec = idcode[1] << 8 | idcode[2]; + ext_jedec = idcode[3] << 8 | idcode[4]; + + for (i = 0; i < ARRAY_SIZE(spansion_spi_flash_table); i++) { + params = &spansion_spi_flash_table[i]; + if (params->idcode1 == jedec) { + if (params->idcode2 == ext_jedec) + break; + } + } + + if (i == ARRAY_SIZE(spansion_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported SPANSION ID %04x %04x\n", jedec, ext_jedec); + return NULL; + } + + spsn = malloc(sizeof(struct spansion_spi_flash)); + if (!spsn) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + spsn->params = params; + spsn->flash.spi = spi; + spsn->flash.name = params->name; + + spsn->flash.write = spansion_write; + spsn->flash.erase = spansion_erase; + spsn->flash.read = spi_flash_cmd_read_fast; + spsn->flash.sector_size = params->page_size * params->pages_per_sector; + spsn->flash.size = spsn->flash.sector_size * params->nr_sectors; + + return &spsn->flash; +} diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c new file mode 100644 index 0000000..33cb4d2 --- /dev/null +++ b/src/drivers/spi/spi_flash.c @@ -0,0 +1,309 @@ +/* + * SPI flash interface + * + * Copyright (C) 2008 Atmel Corporation + * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include "spi_flash_internal.h" + +static void spi_flash_addr(u32 addr, u8 *cmd) +{ + /* cmd[0] is actual command */ + cmd[1] = addr >> 16; + cmd[2] = addr >> 8; + cmd[3] = addr >> 0; +} + +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) +{ + int ret = spi_xfer(spi, &cmd, 8, response, len * 8); + if (ret) + printk(BIOS_WARNING, "SF: Failed to send command %02x: %d\n", cmd, ret); + + return ret; +} + +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + int ret = spi_xfer(spi, cmd, cmd_len * 8, data, data_len * 8); + if (ret) { + printk(BIOS_WARNING, "SF: Failed to send read command (%zu bytes): %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len) +{ + int ret; + u8 buff[cmd_len + data_len]; + memcpy(buff, cmd, cmd_len); + memcpy(buff + cmd_len, data, data_len); + + ret = spi_xfer(spi, buff, (cmd_len + data_len) * 8, NULL, 0); + if (ret) { + printk(BIOS_WARNING, "SF: Failed to send write command (%zu bytes): %d\n", + data_len, ret); + } + + return ret; +} + +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + struct spi_slave *spi = flash->spi; + int ret; + + spi_claim_bus(spi); + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + spi_release_bus(spi); + + return ret; +} + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[5]; + + cmd[0] = CMD_READ_ARRAY_FAST; + spi_flash_addr(offset, cmd); + cmd[4] = 0x00; + + return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); +} + +int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, + size_t len, void *data) +{ + struct spi_slave *spi = flash->spi; + u8 cmd[4]; + + cmd[0] = CMD_READ_ARRAY_SLOW; + spi_flash_addr(offset, cmd); + + return spi_flash_cmd_read(spi, cmd, sizeof(cmd), data, len); +} + +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit) +{ + struct spi_slave *spi = flash->spi; + unsigned long timebase; + int ret; + u8 status; + + timebase = timeout; + do { + ret = spi_flash_cmd_read(spi, &cmd, 1, &status, 1); + if (ret) + return -1; + + if ((status & poll_bit) == 0) + break; + + mdelay(1); + } while (timebase--); + + if ((status & poll_bit) == 0) + return 0; + + /* Timed out */ + printk(BIOS_DEBUG, "SF: time out!\n"); + return -1; +} + +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) +{ + return spi_flash_cmd_poll_bit(flash, timeout, + CMD_READ_STATUS, STATUS_WIP); +} + +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 offset, size_t len) +{ + u32 start, end, erase_size; + int ret; + u8 cmd[4]; + + erase_size = flash->sector_size; + if (offset % erase_size || len % erase_size) { + printk(BIOS_WARNING, "SF: Erase offset/length not multiple of erase size\n"); + return -1; + } + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + cmd[0] = erase_cmd; + start = offset; + end = start + len; + + while (offset < end) { + spi_flash_addr(offset, cmd); + offset += erase_size; + + printk(BIOS_SPEW, "SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); + if (ret) + goto out; + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); + if (ret) + goto out; + } + + printk(BIOS_DEBUG, "SF: Successfully erased %zu bytes @ %#x\n", len, start); + + out: + spi_release_bus(flash->spi); + return ret; +} + +/* + * The following table holds all device probe functions + * + * shift: number of continuation bytes before the ID + * idcode: the expected IDCODE or 0xff for non JEDEC devices + * probe: the function to call + * + * Non JEDEC devices should be ordered in the table such that + * the probe functions with best detection algorithms come first. + * + * Several matching entries are permitted, they will be tried + * in sequence until a probe function returns non NULL. + * + * IDCODE_CONT_LEN may be redefined if a device needs to declare a + * larger "shift" value. IDCODE_PART_LEN generally shouldn't be + * changed. This is the max number of bytes probe functions may + * examine when looking up part-specific identification info. + * + * Probe functions will be given the idcode buffer starting at their + * manu id byte (the "idcode" in the table below). In other words, + * all of the continuation bytes will be skipped (the "shift" below). + */ +#define IDCODE_CONT_LEN 0 +#define IDCODE_PART_LEN 5 +static const struct { + const u8 shift; + const u8 idcode; + struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode); +} flashes[] = { + /* Keep it sorted by define name */ +#if CONFIG_SPI_FLASH_EON + { 0, 0x1c, spi_flash_probe_eon, }, +#endif +#if CONFIG_SPI_FLASH_MACRONIX + { 0, 0xc2, spi_flash_probe_macronix, }, +#endif +#if CONFIG_SPI_FLASH_SPANSION + { 0, 0x01, spi_flash_probe_spansion, }, +#endif +#if CONFIG_SPI_FLASH_SST + { 0, 0xbf, spi_flash_probe_sst, }, +#endif +#if CONFIG_SPI_FLASH_STMICRO + { 0, 0x20, spi_flash_probe_stmicro, }, +#endif +#if CONFIG_SPI_FLASH_WINBOND + { 0, 0xef, spi_flash_probe_winbond, }, +#endif + /* Keep it sorted by best detection */ +#if CONFIG_SPI_FLASH_STMICRO + { 0, 0xff, spi_flash_probe_stmicro, }, +#endif +}; +#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN) + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode) +{ + struct spi_slave *spi; + struct spi_flash *flash = NULL; + int ret, i, shift; + u8 idcode[IDCODE_LEN], *idp; + + spi = spi_setup_slave(bus, cs, max_hz, spi_mode); + if (!spi) { + printk(BIOS_WARNING, "SF: Failed to set up slave\n"); + return NULL; + } + + ret = spi_claim_bus(spi); + if (ret) { + printk(BIOS_WARNING, "SF: Failed to claim SPI bus: %d\n", ret); + goto err_claim_bus; + } + + /* Read the ID codes */ + ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); + if (ret) + goto err_read_id; + +#ifdef DEBUG + printk(BIOS_SPEW, "SF: Got idcodes\n"); + print_buffer(0, idcode, 1, sizeof(idcode), 0); +#endif + + /* count the number of continuation bytes */ + for (shift = 0, idp = idcode; + shift < IDCODE_CONT_LEN && *idp == 0x7f; + ++shift, ++idp) + continue; + + /* search the table for matches in shift and id */ + for (i = 0; i < ARRAY_SIZE(flashes); ++i) + if (flashes[i].shift == shift && flashes[i].idcode == *idp) { + /* we have a match, call probe */ + flash = flashes[i].probe(spi, idp); + if (flash) + break; + } + + if (!flash) { + printk(BIOS_WARNING, "SF: Unsupported manufacturer %02x\n", *idp); + goto err_manufacturer_probe; + } + + printk(BIOS_INFO, "SF: Detected %s with page size %x, total %x\n", + flash->name, flash->sector_size, flash->size); + + spi_release_bus(spi); + + return flash; + +err_manufacturer_probe: +err_read_id: + spi_release_bus(spi); +err_claim_bus: + spi_free_slave(spi); + return NULL; +} + +void spi_flash_free(struct spi_flash *flash) +{ + spi_free_slave(flash->spi); + free(flash); +} diff --git a/src/drivers/spi/spi_flash_internal.h b/src/drivers/spi/spi_flash_internal.h new file mode 100644 index 0000000..b895e2b --- /dev/null +++ b/src/drivers/spi/spi_flash_internal.h @@ -0,0 +1,81 @@ +/* + * SPI flash internal definitions + * + * Copyright (C) 2008 Atmel Corporation + */ + +/* Common parameters -- kind of high, but they should only occur when there + * is a problem (and well your system already is broken), so err on the side + * of caution in case we're dealing with slower SPI buses and/or processors. + */ +#define CONFIG_SYS_HZ 100 +#define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) +#define SPI_FLASH_PAGE_ERASE_TIMEOUT (5 * CONFIG_SYS_HZ) +#define SPI_FLASH_SECTOR_ERASE_TIMEOUT (10 * CONFIG_SYS_HZ) + +/* Common commands */ +#define CMD_READ_ID 0x9f + +#define CMD_READ_ARRAY_SLOW 0x03 +#define CMD_READ_ARRAY_FAST 0x0b +#define CMD_READ_ARRAY_LEGACY 0xe8 + +#define CMD_READ_STATUS 0x05 +#define CMD_WRITE_ENABLE 0x06 + +/* Common status */ +#define STATUS_WIP 0x01 + +/* Send a single-byte command to the device and read the response */ +int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); + +/* + * Send a multi-byte command to the device and read the response. Used + * for flash array reads, etc. + */ +int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +int spi_flash_cmd_read_slow(struct spi_flash *flash, u32 offset, + size_t len, void *data); + +/* + * Send a multi-byte command to the device followed by (optional) + * data. Used for programming the flash array, etc. + */ +int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, + const void *data, size_t data_len); + +/* + * Same as spi_flash_cmd_read() except it also claims/releases the SPI + * bus. Used as common part of the ->read() operation. + */ +int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + +/* Send a command to the device and wait for some bit to clear itself. */ +int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, + u8 cmd, u8 poll_bit); + +/* + * Send the read status command to the device and wait for the wip + * (write-in-progress) bit to clear itself. + */ +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout); + +/* Erase sectors. */ +int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd, + u32 offset, size_t len); + +/* Manufacturer-specific probe functions */ +struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_eon(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode); +struct spi_flash *spi_fram_probe_ramtron(struct spi_slave *spi, u8 *idcode); diff --git a/src/drivers/spi/sst.c b/src/drivers/spi/sst.c new file mode 100644 index 0000000..56cc851 --- /dev/null +++ b/src/drivers/spi/sst.c @@ -0,0 +1,268 @@ +/* + * Driver for SST serial flashes + * + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd at denx.de. + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * Copyright (c) 2008-2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +#define CMD_SST_WREN 0x06 /* Write Enable */ +#define CMD_SST_WRDI 0x04 /* Write Disable */ +#define CMD_SST_RDSR 0x05 /* Read Status Register */ +#define CMD_SST_WRSR 0x01 /* Write Status Register */ +#define CMD_SST_READ 0x03 /* Read Data Bytes */ +#define CMD_SST_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_SST_BP 0x02 /* Byte Program */ +#define CMD_SST_AAI_WP 0xAD /* Auto Address Increment Word Program */ +#define CMD_SST_SE 0x20 /* Sector Erase */ + +#define SST_SR_WIP (1 << 0) /* Write-in-Progress */ +#define SST_SR_WEL (1 << 1) /* Write enable */ +#define SST_SR_BP0 (1 << 2) /* Block Protection 0 */ +#define SST_SR_BP1 (1 << 3) /* Block Protection 1 */ +#define SST_SR_BP2 (1 << 4) /* Block Protection 2 */ +#define SST_SR_AAI (1 << 6) /* Addressing mode */ +#define SST_SR_BPL (1 << 7) /* BP bits lock */ + +struct sst_spi_flash_params { + u8 idcode1; + u16 nr_sectors; + const char *name; +}; + +struct sst_spi_flash { + struct spi_flash flash; + const struct sst_spi_flash_params *params; +}; + +static inline struct sst_spi_flash *to_sst_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct sst_spi_flash, flash); +} + +#define SST_SECTOR_SIZE (4 * 1024) +static const struct sst_spi_flash_params sst_spi_flash_table[] = { + { + .idcode1 = 0x8d, + .nr_sectors = 128, + .name = "SST25VF040B", + },{ + .idcode1 = 0x8e, + .nr_sectors = 256, + .name = "SST25VF080B", + },{ + .idcode1 = 0x41, + .nr_sectors = 512, + .name = "SST25VF016B", + },{ + .idcode1 = 0x4a, + .nr_sectors = 1024, + .name = "SST25VF032B", + },{ + .idcode1 = 0x4b, + .nr_sectors = 2048, + .name = "SST25VF064C", + },{ + .idcode1 = 0x01, + .nr_sectors = 16, + .name = "SST25WF512", + },{ + .idcode1 = 0x02, + .nr_sectors = 32, + .name = "SST25WF010", + },{ + .idcode1 = 0x03, + .nr_sectors = 64, + .name = "SST25WF020", + },{ + .idcode1 = 0x04, + .nr_sectors = 128, + .name = "SST25WF040", + }, +}; + +static int +sst_enable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WREN, NULL, 0); + if (ret) + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + return ret; +} + +static int +sst_disable_writing(struct spi_flash *flash) +{ + int ret = spi_flash_cmd(flash->spi, CMD_SST_WRDI, NULL, 0); + if (ret) + printk(BIOS_WARNING, "SF: Disabling Write failed\n"); + return ret; +} + +static int +sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) +{ + int ret; + u8 cmd[4] = { + CMD_SST_BP, + offset >> 16, + offset >> 8, + offset, + }; + + printk(BIOS_SPEW, "BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf, cmd[0], offset); + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, 1); + if (ret) + return ret; + + return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); +} + +static int +sst_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf) +{ + size_t actual, cmd_len; + int ret; + u8 cmd[4]; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + /* If the data is not word aligned, write out leading single byte */ + actual = offset % 2; + if (actual) { + ret = sst_byte_write(flash, offset, buf); + if (ret) + goto done; + } + offset += actual; + + ret = sst_enable_writing(flash); + if (ret) + goto done; + + cmd_len = 4; + cmd[0] = CMD_SST_AAI_WP; + cmd[1] = offset >> 16; + cmd[2] = offset >> 8; + cmd[3] = offset; + + for (; actual < len - 1; actual += 2) { + printk(BIOS_SPEW, "WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", + spi_w8r8(flash->spi, CMD_SST_RDSR), buf + actual, cmd[0], + offset); + + ret = spi_flash_cmd_write(flash->spi, cmd, cmd_len, + buf + actual, 2); + if (ret) { + printk(BIOS_WARNING, "SF: SST word program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + cmd_len = 1; + offset += 2; + } + + if (!ret) + ret = sst_disable_writing(flash); + + /* If there is a single trailing byte, write it out */ + if (!ret && actual != len) + ret = sst_byte_write(flash, offset, buf + actual); + + done: + printk(BIOS_INFO, "SF: SST: program %s %zu bytes @ 0x%lx\n", + ret ? "failure" : "success", len, offset - actual); + + spi_release_bus(flash->spi); + return ret; +} + +static int sst_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_SST_SE, offset, len); +} + +static int +sst_unlock(struct spi_flash *flash) +{ + int ret; + u8 cmd, status; + + ret = sst_enable_writing(flash); + if (ret) + return ret; + + cmd = CMD_SST_WRSR; + status = 0; + ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &status, 1); + if (ret) + printk(BIOS_WARNING, "SF: Unable to set status byte\n"); + + printk(BIOS_INFO, "SF: SST: status = %x\n", spi_w8r8(flash->spi, CMD_SST_RDSR)); + + return ret; +} + +struct spi_flash * +spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode) +{ + const struct sst_spi_flash_params *params; + struct sst_spi_flash *stm; + size_t i; + + for (i = 0; i < ARRAY_SIZE(sst_spi_flash_table); ++i) { + params = &sst_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) + break; + } + + if (i == ARRAY_SIZE(sst_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported SST ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(*stm)); + if (!stm) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = sst_write; + stm->flash.erase = sst_erase; + stm->flash.read = spi_flash_cmd_read_fast; + stm->flash.sector_size = SST_SECTOR_SIZE; + stm->flash.size = stm->flash.sector_size * params->nr_sectors; + + /* Flash powers up read-only, so clear BP# bits */ + sst_unlock(&stm->flash); + + return &stm->flash; +} diff --git a/src/drivers/spi/stmicro.c b/src/drivers/spi/stmicro.c new file mode 100644 index 0000000..8cbdad5 --- /dev/null +++ b/src/drivers/spi/stmicro.c @@ -0,0 +1,250 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd at denx.de. + * + * Copyright 2008, Network Appliance Inc. + * Jason McMullan + * + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. + * TsiChung Liew (Tsi-Chung.Liew at freescale.com) + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_M25PXX_WREN 0x06 /* Write Enable */ +#define CMD_M25PXX_WRDI 0x04 /* Write Disable */ +#define CMD_M25PXX_RDSR 0x05 /* Read Status Register */ +#define CMD_M25PXX_WRSR 0x01 /* Write Status Register */ +#define CMD_M25PXX_READ 0x03 /* Read Data Bytes */ +#define CMD_M25PXX_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_M25PXX_PP 0x02 /* Page Program */ +#define CMD_M25PXX_SE 0xd8 /* Sector Erase */ +#define CMD_M25PXX_BE 0xc7 /* Bulk Erase */ +#define CMD_M25PXX_DP 0xb9 /* Deep Power-down */ +#define CMD_M25PXX_RES 0xab /* Release from DP, and Read Signature */ + +#define STM_ID_M25P10 0x11 +#define STM_ID_M25P16 0x15 +#define STM_ID_M25P20 0x12 +#define STM_ID_M25P32 0x16 +#define STM_ID_M25P40 0x13 +#define STM_ID_M25P64 0x17 +#define STM_ID_M25P80 0x14 +#define STM_ID_M25P128 0x18 + +struct stmicro_spi_flash_params { + u8 idcode1; + u16 page_size; + u16 pages_per_sector; + u16 nr_sectors; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct stmicro_spi_flash { + struct spi_flash flash; + const struct stmicro_spi_flash_params *params; +}; + +static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash + *flash) +{ + return container_of(flash, struct stmicro_spi_flash, flash); +} + +static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { + { + .idcode1 = STM_ID_M25P10, + .page_size = 256, + .pages_per_sector = 128, + .nr_sectors = 4, + .name = "M25P10", + }, + { + .idcode1 = STM_ID_M25P16, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 32, + .name = "M25P16", + }, + { + .idcode1 = STM_ID_M25P20, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 4, + .name = "M25P20", + }, + { + .idcode1 = STM_ID_M25P32, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 64, + .name = "M25P32", + }, + { + .idcode1 = STM_ID_M25P40, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 8, + .name = "M25P40", + }, + { + .idcode1 = STM_ID_M25P64, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "M25P64", + }, + { + .idcode1 = STM_ID_M25P80, + .page_size = 256, + .pages_per_sector = 256, + .nr_sectors = 16, + .name = "M25P80", + }, + { + .idcode1 = STM_ID_M25P128, + .page_size = 256, + .pages_per_sector = 1024, + .nr_sectors = 64, + .name = "M25P128", + }, +}; + +static int stmicro_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash); + unsigned long page_addr; + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = stm->params->page_size; + page_addr = offset / page_size; + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + ret = 0; + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_M25PXX_PP; + cmd[1] = page_addr >> 8; + cmd[2] = page_addr; + cmd[3] = byte_addr; + + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zd\n", + buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + break; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: STMicro Page Program failed\n"); + break; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + break; + + page_addr++; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: STMicro: Successfully programmed %zu bytes @ 0x%x\n", + len, offset); + + spi_release_bus(flash->spi); + return ret; +} + +static int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_M25PXX_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) +{ + const struct stmicro_spi_flash_params *params; + struct stmicro_spi_flash *stm; + unsigned int i; + + if (idcode[0] == 0xff) { + i = spi_flash_cmd(spi, CMD_M25PXX_RES, + idcode, 4); + if (i) + return NULL; + if ((idcode[3] & 0xf0) == 0x10) { + idcode[0] = 0x20; + idcode[1] = 0x20; + idcode[2] = idcode[3] + 1; + } else + return NULL; + } + + for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) { + params = &stmicro_spi_flash_table[i]; + if (params->idcode1 == idcode[2]) { + break; + } + } + + if (i == ARRAY_SIZE(stmicro_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported STMicro ID %02x\n", idcode[1]); + return NULL; + } + + stm = malloc(sizeof(struct stmicro_spi_flash)); + if (!stm) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + stm->flash.write = stmicro_write; + stm->flash.erase = stmicro_erase; + stm->flash.read = spi_flash_cmd_read_fast; + stm->flash.sector_size = params->page_size * params->pages_per_sector; + stm->flash.size = stm->flash.sector_size * params->nr_sectors; + + return &stm->flash; +} diff --git a/src/drivers/spi/winbond.c b/src/drivers/spi/winbond.c new file mode 100644 index 0000000..65818d5 --- /dev/null +++ b/src/drivers/spi/winbond.c @@ -0,0 +1,218 @@ +/* + * Copyright 2008, Network Appliance Inc. + * Author: Jason McMullan netapp.com> + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include "spi_flash_internal.h" + +/* M25Pxx-specific commands */ +#define CMD_W25_WREN 0x06 /* Write Enable */ +#define CMD_W25_WRDI 0x04 /* Write Disable */ +#define CMD_W25_RDSR 0x05 /* Read Status Register */ +#define CMD_W25_WRSR 0x01 /* Write Status Register */ +#define CMD_W25_READ 0x03 /* Read Data Bytes */ +#define CMD_W25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */ +#define CMD_W25_PP 0x02 /* Page Program */ +#define CMD_W25_SE 0x20 /* Sector (4K) Erase */ +#define CMD_W25_BE 0xd8 /* Block (64K) Erase */ +#define CMD_W25_CE 0xc7 /* Chip Erase */ +#define CMD_W25_DP 0xb9 /* Deep Power-down */ +#define CMD_W25_RES 0xab /* Release from DP, and Read Signature */ + +struct winbond_spi_flash_params { + uint16_t id; + /* Log2 of page size in power-of-two mode */ + uint8_t l2_page_size; + uint16_t pages_per_sector; + uint16_t sectors_per_block; + uint16_t nr_blocks; + const char *name; +}; + +/* spi_flash needs to be first so upper layers can free() it */ +struct winbond_spi_flash { + struct spi_flash flash; + const struct winbond_spi_flash_params *params; +}; + +static inline struct winbond_spi_flash * +to_winbond_spi_flash(struct spi_flash *flash) +{ + return container_of(flash, struct winbond_spi_flash, flash); +} + +static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { + { + .id = 0x3015, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "W25X16", + }, + { + .id = 0x3016, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "W25X32", + }, + { + .id = 0x3017, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "W25X64", + }, + { + .id = 0x4015, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 32, + .name = "W25Q16", + }, + { + .id = 0x4016, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 64, + .name = "W25Q32", + }, + { + .id = 0x4017, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 128, + .name = "W25Q64", + }, + { + .id = 0x4018, + .l2_page_size = 8, + .pages_per_sector = 16, + .sectors_per_block = 16, + .nr_blocks = 256, + .name = "W25Q128", + }, +}; + +static int winbond_write(struct spi_flash *flash, + u32 offset, size_t len, const void *buf) +{ + struct winbond_spi_flash *stm = to_winbond_spi_flash(flash); + unsigned long byte_addr; + unsigned long page_size; + size_t chunk_len; + size_t actual; + int ret; + u8 cmd[4]; + + page_size = min(1 << stm->params->l2_page_size, CONTROLLER_PAGE_LIMIT); + byte_addr = offset % page_size; + + ret = spi_claim_bus(flash->spi); + if (ret) { + printk(BIOS_WARNING, "SF: Unable to claim SPI bus\n"); + return ret; + } + + for (actual = 0; actual < len; actual += chunk_len) { + chunk_len = min(len - actual, page_size - byte_addr); + + cmd[0] = CMD_W25_PP; + cmd[1] = (offset >> 16) & 0xff; + cmd[2] = (offset >> 8) & 0xff; + cmd[3] = offset & 0xff; + printk(BIOS_SPEW, "PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %ld\n", + buf + actual, + cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); + + ret = spi_flash_cmd(flash->spi, CMD_W25_WREN, NULL, 0); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Enabling Write failed\n"); + goto out; + } + + ret = spi_flash_cmd_write(flash->spi, cmd, 4, + buf + actual, chunk_len); + if (ret < 0) { + printk(BIOS_WARNING, "SF: Winbond Page Program failed\n"); + goto out; + } + + ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); + if (ret) + goto out; + + offset += chunk_len; + byte_addr = 0; + } + + printk(BIOS_INFO, "SF: Winbond: Successfully programmed %zu bytes @ 0x%lx\n", + len, offset - len); + ret = 0; + +out: + spi_release_bus(flash->spi); + return ret; +} + +static int winbond_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + return spi_flash_cmd_erase(flash, CMD_W25_SE, offset, len); +} + +struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) +{ + const struct winbond_spi_flash_params *params; + unsigned page_size; + struct winbond_spi_flash *stm; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(winbond_spi_flash_table); i++) { + params = &winbond_spi_flash_table[i]; + if (params->id == ((idcode[1] << 8) | idcode[2])) + break; + } + + if (i == ARRAY_SIZE(winbond_spi_flash_table)) { + printk(BIOS_WARNING, "SF: Unsupported Winbond ID %02x%02x\n", + idcode[1], idcode[2]); + return NULL; + } + + stm = malloc(sizeof(struct winbond_spi_flash)); + if (!stm) { + printk(BIOS_WARNING, "SF: Failed to allocate memory\n"); + return NULL; + } + + stm->params = params; + stm->flash.spi = spi; + stm->flash.name = params->name; + + /* Assuming power-of-two page size initially. */ + page_size = 1 << params->l2_page_size; + + stm->flash.write = winbond_write; + stm->flash.erase = winbond_erase; +#ifdef CONFIG_SPI_FLASH_NO_FAST_READ + stm->flash.read = spi_flash_cmd_read_slow; +#else + stm->flash.read = spi_flash_cmd_read_fast; +#endif + stm->flash.sector_size = (1 << stm->params->l2_page_size) * + stm->params->pages_per_sector; + stm->flash.size = page_size * params->pages_per_sector + * params->sectors_per_block + * params->nr_blocks; + + return &stm->flash; +} diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h index a2d6884..1765293 100644 --- a/src/include/device/pci_ids.h +++ b/src/include/device/pci_ids.h @@ -2502,6 +2502,10 @@ #define PCI_DEVICE_ID_INTEL_82801IO_LPC 0x2914 #define PCI_DEVICE_ID_INTEL_82801IH_LPC 0x2912 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f +#define PCI_DEVICE_ID_INTEL_TGP_LPC 0x27bc + /* Intel 82801E (C-ICH) */ #define PCI_DEVICE_ID_INTEL_82801E_LPC 0x2450 #define PCI_DEVICE_ID_INTEL_82801E_USB 0x2452 diff --git a/src/include/spi.h b/src/include/spi.h new file mode 100644 index 0000000..bb84258 --- /dev/null +++ b/src/include/spi.h @@ -0,0 +1,203 @@ +/* + * (C) Copyright 2001 + * Gerald Van Baren, Custom IDEAS, vanbaren at cideas.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _SPI_H_ +#define _SPI_H_ + +#include + +/* Controller-specific definitions: */ + +/* SPI mode flags */ +#define SPI_CPHA 0x01 /* clock phase */ +#define SPI_CPOL 0x02 /* clock polarity */ +#define SPI_MODE_0 (0|0) /* (original MicroWire) */ +#define SPI_MODE_1 (0|SPI_CPHA) +#define SPI_MODE_2 (SPI_CPOL|0) +#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) +#define SPI_CS_HIGH 0x04 /* CS active high */ +#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ +#define SPI_3WIRE 0x10 /* SI/SO signals shared */ +#define SPI_LOOP 0x20 /* loopback mode */ + +/* SPI transfer flags */ +#define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ +#define SPI_XFER_END 0x02 /* Deassert CS after transfer */ + +/*----------------------------------------------------------------------- + * Representation of a SPI slave, i.e. what we're communicating with. + * + * Drivers are expected to extend this with controller-specific data. + * + * bus: ID of the bus that the slave is attached to. + * cs: ID of the chip select connected to the slave. + */ +struct spi_slave { + unsigned int bus; + unsigned int cs; +}; + +/*----------------------------------------------------------------------- + * Initialization, must be called once on start up. + * + * TODO: I don't think we really need this. + */ +void spi_init(void); + +/*----------------------------------------------------------------------- + * Set up communications parameters for a SPI slave. + * + * This must be called once for each slave. Note that this function + * usually doesn't touch any actual hardware, it only initializes the + * contents of spi_slave so that the hardware can be easily + * initialized later. + * + * bus: Bus ID of the slave chip. + * cs: Chip select ID of the slave chip on the specified bus. + * max_hz: Maximum SCK rate in Hz. + * mode: Clock polarity, clock phase and other parameters. + * + * Returns: A spi_slave reference that can be used in subsequent SPI + * calls, or NULL if one or more of the parameters are not supported. + */ +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode); + +/*----------------------------------------------------------------------- + * Free any memory associated with a SPI slave. + * + * slave: The SPI slave + */ +void spi_free_slave(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Claim the bus and prepare it for communication with a given slave. + * + * This must be called before doing any transfers with a SPI slave. It + * will enable and initialize any SPI hardware as necessary, and make + * sure that the SCK line is in the correct idle state. It is not + * allowed to claim the same bus for several slaves without releasing + * the bus in between. + * + * slave: The SPI slave + * + * Returns: 0 if the bus was claimed successfully, or a negative value + * if it wasn't. + */ +int spi_claim_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Release the SPI bus + * + * This must be called once for every call to spi_claim_bus() after + * all transfers have finished. It may disable any SPI hardware as + * appropriate. + * + * slave: The SPI slave + */ +void spi_release_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * SPI transfer + * + * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks + * "bitlen" bits in the SPI MISO port. That's just the way SPI works. + * + * The source of the outgoing bits is the "dout" parameter and the + * destination of the input bits is the "din" parameter. Note that "dout" + * and "din" can point to the same memory location, in which case the + * input data overwrites the output data (since both are buffered by + * temporary variables, this is OK). + * + * spi_xfer() interface: + * slave: The SPI slave which will be sending/receiving the data. + * dout: Pointer to a string of bits to send out. The bits are + * held in a byte array and are sent MSB first. + * bitsout: How many bits to write. + * din: Pointer to a string of bits that will be filled in. + * bitsin: How many bits to read. + * + * Returns: 0 on success, not 0 on failure + */ +int spi_xfer(struct spi_slave *slave, const void *dout, unsigned int bitsout, + void *din, unsigned int bitsin); + +/*----------------------------------------------------------------------- + * Determine if a SPI chipselect is valid. + * This function is provided by the board if the low-level SPI driver + * needs it to determine if a given chipselect is actually valid. + * + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 + * otherwise. + */ +int spi_cs_is_valid(unsigned int bus, unsigned int cs); + +/*----------------------------------------------------------------------- + * Activate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should activate the chip select + * to the device identified by "slave". + */ +void spi_cs_activate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Deactivate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should deactivate the chip + * select to the device identified by "slave". + */ +void spi_cs_deactivate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Set transfer speed. + * This sets a new speed to be applied for next spi_xfer(). + * slave: The SPI slave + * hz: The transfer speed + */ +void spi_set_speed(struct spi_slave *slave, uint32_t hz); + +/*----------------------------------------------------------------------- + * Write 8 bits, then read 8 bits. + * slave: The SPI slave we're communicating with + * byte: Byte to be written + * + * Returns: The value that was read, or a negative value on error. + * + * TODO: This function probably shouldn't be inlined. + */ +static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) +{ + unsigned char dout[2]; + unsigned char din[2]; + int ret; + + dout[0] = byte; + dout[1] = 0; + + ret = spi_xfer(slave, dout, 16, din, 16); + return ret < 0 ? ret : din[1]; +} + +#endif /* _SPI_H_ */ diff --git a/src/include/spi_flash.h b/src/include/spi_flash.h new file mode 100644 index 0000000..2a1dcd4 --- /dev/null +++ b/src/include/spi_flash.h @@ -0,0 +1,91 @@ +/* + * Interface to SPI flash + * + * Copyright (C) 2008 Atmel Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _SPI_FLASH_H_ +#define _SPI_FLASH_H_ + +#include +#include +#include +#include + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define min(a, b) ((a)<(b)?(a):(b)) + +#define CONFIG_ICH_SPI +#ifdef CONFIG_ICH_SPI +#define CONTROLLER_PAGE_LIMIT 64 +#else +/* any number larger than 4K would do, actually */ +#define CONTROLLER_PAGE_LIMIT ((int)(~0U>>1)) +#endif + +struct spi_flash { + struct spi_slave *spi; + + const char *name; + + u32 size; + + u32 sector_size; + + int (*read)(struct spi_flash *flash, u32 offset, + size_t len, void *buf); + int (*write)(struct spi_flash *flash, u32 offset, + size_t len, const void *buf); + int (*erase)(struct spi_flash *flash, u32 offset, + size_t len); +}; + +struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int spi_mode); +void spi_flash_free(struct spi_flash *flash); + +static inline int spi_flash_read(struct spi_flash *flash, u32 offset, + size_t len, void *buf) +{ + return flash->read(flash, offset, len, buf); +} + +static inline int spi_flash_write(struct spi_flash *flash, u32 offset, + size_t len, const void *buf) +{ + return flash->write(flash, offset, len, buf); +} + +static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, + size_t len) +{ + return flash->erase(flash, offset, len); +} + +#endif /* _SPI_FLASH_H_ */ diff --git a/src/northbridge/intel/sandybridge/raminit.c b/src/northbridge/intel/sandybridge/raminit.c index 8209980..6548b32 100644 --- a/src/northbridge/intel/sandybridge/raminit.c +++ b/src/northbridge/intel/sandybridge/raminit.c @@ -340,6 +340,7 @@ void sdram_initialize(struct pei_data *pei_data) /* If MRC data is not found we cannot continue S3 resume. */ if (pei_data->boot_mode == 2 && !pei_data->mrc_input) { + printk(BIOS_DEBUG, "Giving up in sdram_initialize: No MRC data\n"); outb(0x6, 0xcf9); hlt(); } diff --git a/src/southbridge/intel/bd82x6x/Kconfig b/src/southbridge/intel/bd82x6x/Kconfig index 3891be1..f105ee3 100644 --- a/src/southbridge/intel/bd82x6x/Kconfig +++ b/src/southbridge/intel/bd82x6x/Kconfig @@ -33,6 +33,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy select USE_WATCHDOG_ON_BOOT select PCIEXP_ASPM select PCIEXP_COMMON_CLOCK + select SPI config EHCI_BAR hex diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc index 5732254..f086426 100644 --- a/src/southbridge/intel/bd82x6x/Makefile.inc +++ b/src/southbridge/intel/bd82x6x/Makefile.inc @@ -34,6 +34,8 @@ ramstage-y += me_status.c ramstage-y += reset.c ramstage-y += watchdog.c +ramstage-y += spi.c + ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c $(me-src-y) finalize.c diff --git a/src/southbridge/intel/bd82x6x/spi.c b/src/southbridge/intel/bd82x6x/spi.c new file mode 100644 index 0000000..c54a325 --- /dev/null +++ b/src/southbridge/intel/bd82x6x/spi.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* This file is derived from the flashrom project. */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define min(a, b) ((a)<(b)?(a):(b)) + +typedef device_t pci_dev_t; +#define pci_read_config_byte(dev, reg, targ) *(targ) = pci_read_config8(dev, reg) +#define pci_read_config_word(dev, reg, targ) *(targ) = pci_read_config16(dev, reg) +#define pci_read_config_dword(dev, reg, targ) *(targ) = pci_read_config32(dev, reg) +#define pci_write_config_byte(dev, reg, val) pci_write_config8(dev, reg, val) +#define pci_write_config_word(dev, reg, val) pci_write_config16(dev, reg, val) +#define pci_write_config_dword(dev, reg, val) pci_write_config32(dev, reg, val) + +typedef struct spi_slave ich_spi_slave; + +static int ichspi_lock = 0; + +typedef struct ich7_spi_regs { + uint16_t spis; + uint16_t spic; + uint32_t spia; + uint64_t spid[8]; + uint64_t _pad; + uint32_t bbar; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; +} __attribute__((packed)) ich7_spi_regs; + +typedef struct ich9_spi_regs { + uint32_t bfpr; + uint16_t hsfs; + uint16_t hsfc; + uint32_t faddr; + uint32_t _reserved0; + uint32_t fdata[16]; + uint32_t frap; + uint32_t freg[5]; + uint32_t _reserved1[3]; + uint32_t pr[5]; + uint32_t _reserved2[2]; + uint8_t ssfs; + uint8_t ssfc[3]; + uint16_t preop; + uint16_t optype; + uint8_t opmenu[8]; + uint32_t bbar; + uint8_t _reserved3[12]; + uint32_t fdoc; + uint32_t fdod; + uint8_t _reserved4[8]; + uint32_t afc; + uint32_t lvscc; + uint32_t uvscc; + uint8_t _reserved5[4]; + uint32_t fpb; + uint8_t _reserved6[28]; + uint32_t srdl; + uint32_t srdc; + uint32_t srd; +} __attribute__((packed)) ich9_spi_regs; + +typedef struct ich_spi_controller { + int locked; + + uint8_t *opmenu; + int menubytes; + uint16_t *preop; + uint16_t *optype; + uint32_t *addr; + uint8_t *data; + unsigned databytes; + uint8_t *status; + uint16_t *control; + uint32_t *bbar; +} ich_spi_controller; + +static ich_spi_controller cntlr; + +enum { + SPIS_SCIP = 0x0001, + SPIS_GRANT = 0x0002, + SPIS_CDS = 0x0004, + SPIS_FCERR = 0x0008, + SSFS_AEL = 0x0010, + SPIS_LOCK = 0x8000, + SPIS_RESERVED_MASK = 0x7ff0, + SSFS_RESERVED_MASK = 0x7fe2 +}; + +enum { + SPIC_SCGO = 0x000002, + SPIC_ACS = 0x000004, + SPIC_SPOP = 0x000008, + SPIC_DBC = 0x003f00, + SPIC_DS = 0x004000, + SPIC_SME = 0x008000, + SSFC_SCF_MASK = 0x070000, + SSFC_RESERVED = 0xf80000 +}; + +enum { + HSFS_FDONE = 0x0001, + HSFS_FCERR = 0x0002, + HSFS_AEL = 0x0004, + HSFS_BERASE_MASK = 0x0018, + HSFS_BERASE_SHIFT = 3, + HSFS_SCIP = 0x0020, + HSFS_FDOPSS = 0x2000, + HSFS_FDV = 0x4000, + HSFS_FLOCKDN = 0x8000 +}; + +enum { + HSFC_FGO = 0x0001, + HSFC_FCYCLE_MASK = 0x0006, + HSFC_FCYCLE_SHIFT = 1, + HSFC_FDBC_MASK = 0x3f00, + HSFC_FDBC_SHIFT = 8, + HSFC_FSMIE = 0x8000 +}; + +enum { + SPI_OPCODE_TYPE_READ_NO_ADDRESS = 0, + SPI_OPCODE_TYPE_WRITE_NO_ADDRESS = 1, + SPI_OPCODE_TYPE_READ_WITH_ADDRESS = 2, + SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS = 3 +}; + +#ifdef DEBUG + +static u8 readb_(const void *addr) +{ + u8 v = readb(addr); + printk(BIOS_DEBUG, "read %2.2x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u16 readw_(const void *addr) +{ + u16 v = readw(addr); + printk(BIOS_DEBUG, "read %4.4x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static u32 readl_(const void *addr) +{ + u32 v = readl(addr); + printk(BIOS_DEBUG, "read %8.8x from %4.4x\n", + v, ((unsigned) addr & 0xffff) - 0xf020); + return v; +} + +static void writeb_(u8 b, const void *addr) +{ + writeb(b, addr); + printk(BIOS_DEBUG, "wrote %2.2x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writew_(u16 b, const void *addr) +{ + writew(b, addr); + printk(BIOS_DEBUG, "wrote %4.4x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +static void writel_(u32 b, const void *addr) +{ + writel(b, addr); + printk(BIOS_DEBUG, "wrote %8.8x to %4.4x\n", + b, ((unsigned) addr & 0xffff) - 0xf020); +} + +#else /* DEBUG ^^^ defined vvv NOT defined */ + +#define readb_(a) read8((uint32_t)a) +#define readw_(a) read16((uint32_t)a) +#define readl_(a) read32((uint32_t)a) +#define writeb_(val, addr) write8((uint32_t)addr, val) +#define writew_(val, addr) write16((uint32_t)addr, val) +#define writel_(val, addr) write32((uint32_t)addr, val) + +#endif /* DEBUG ^^^ NOT defined */ + +static void write_reg(const void *value, void *dest, uint32_t size) +{ + const uint8_t *bvalue = value; + uint8_t *bdest = dest; + + while (size >= 4) { + writel_(*(const uint32_t *)bvalue, bdest); + bdest += 4; bvalue += 4; size -= 4; + } + while (size) { + writeb_(*bvalue, bdest); + bdest++; bvalue++; size--; + } +} + +static void read_reg(const void *src, void *value, uint32_t size) +{ + const uint8_t *bsrc = src; + uint8_t *bvalue = value; + + while (size >= 4) { + *(uint32_t *)bvalue = readl_(bsrc); + bsrc += 4; bvalue += 4; size -= 4; + } + while (size) { + *bvalue = readb_(bsrc); + bsrc++; bvalue++; size--; + } +} + +static void ich_set_bbar(uint32_t minaddr) +{ + const uint32_t bbar_mask = 0x00ffff00; + uint32_t ichspi_bbar; + + minaddr &= bbar_mask; + ichspi_bbar = readl_(cntlr.bbar) & ~bbar_mask; + ichspi_bbar |= minaddr; + writel_(ichspi_bbar, cntlr.bbar); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + printk(BIOS_DEBUG, "spi_cs_is_valid used but not implemented\n"); + return 0; +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + ich_spi_slave *slave = malloc(sizeof(*slave)); + + if (!slave) { + printk(BIOS_DEBUG, "ICH SPI: Bad allocation\n"); + return NULL; + } + + memset(slave, 0, sizeof(*slave)); + + slave->bus = bus; + slave->cs = cs; + return slave; +} + +void spi_free_slave(struct spi_slave *_slave) +{ + ich_spi_slave *slave = (ich_spi_slave *)_slave; + free(slave); +} + +static inline int spi_is_cougarpoint_lpc(uint16_t device_id) +{ + return device_id >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN && + device_id <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX; +}; + +void spi_init(void) +{ + int ich_version = 0; + + uint8_t *rcrb; /* Root Complex Register Block */ + uint32_t rcba; /* Root Complex Base Address */ + uint8_t bios_cntl; + pci_dev_t dev; + + int bus; + int last_bus = 1; //FIXME: pci_last_busno(); + + if (last_bus == -1) { + printk(BIOS_DEBUG, "No PCI busses?\n"); + return; + } + + for (bus = 0; bus <= last_bus; bus++) { + uint32_t ids; + uint16_t vendor_id, device_id; + + dev = dev_find_slot(bus, PCI_DEVFN(31, 0)); + pci_read_config_dword(dev, 0, &ids); + vendor_id = ids; + device_id = (ids >> 16); + + if (vendor_id != PCI_VENDOR_ID_INTEL) + continue; + + if (device_id == PCI_DEVICE_ID_INTEL_TGP_LPC) { + ich_version = 7; + break; + } else if (spi_is_cougarpoint_lpc(device_id)) { + ich_version = 9; + break; + } + } + + if (!ich_version) { + printk(BIOS_DEBUG, "ICH SPI: No ICH found.\n"); + return; + } + + pci_read_config_dword(dev, 0xf0, &rcba); + /* Bits 31-14 are the base address, 13-1 are reserved, 0 is enable. */ + rcrb = (uint8_t *)(rcba & 0xffffc000); + switch (ich_version) { + case 7: + { + const uint16_t ich7_spibar_offset = 0x3020; + ich7_spi_regs *ich7_spi = + (ich7_spi_regs *)(rcrb + ich7_spibar_offset); + + ichspi_lock = readw_(&ich7_spi->spis) & SPIS_LOCK; + cntlr.opmenu = ich7_spi->opmenu; + cntlr.menubytes = sizeof(ich7_spi->opmenu); + cntlr.optype = &ich7_spi->optype; + cntlr.addr = &ich7_spi->spia; + cntlr.data = (uint8_t *)ich7_spi->spid; + cntlr.databytes = sizeof(ich7_spi->spid); + cntlr.status = (uint8_t *)&ich7_spi->spis; + cntlr.control = &ich7_spi->spic; + cntlr.bbar = &ich7_spi->bbar; + cntlr.preop = &ich7_spi->preop; + break; + } + case 9: + { + const uint16_t ich9_spibar_offset = 0x3800; + ich9_spi_regs *ich9_spi = + (ich9_spi_regs *)(rcrb + ich9_spibar_offset); + ichspi_lock = readw_(&ich9_spi->hsfs) & HSFS_FLOCKDN; + cntlr.opmenu = ich9_spi->opmenu; + cntlr.menubytes = sizeof(ich9_spi->opmenu); + cntlr.optype = &ich9_spi->optype; + cntlr.addr = &ich9_spi->faddr; + cntlr.data = (uint8_t *)ich9_spi->fdata; + cntlr.databytes = sizeof(ich9_spi->fdata); + cntlr.status = &ich9_spi->ssfs; + cntlr.control = (uint16_t *)ich9_spi->ssfc; + cntlr.bbar = &ich9_spi->bbar; + cntlr.preop = &ich9_spi->preop; + break; + } + default: + printk(BIOS_DEBUG, "ICH SPI: Unrecognized ICH version %d.\n", ich_version); + } + + ich_set_bbar(0); + + /* Disable the BIOS write protect so write commands are allowed. */ + pci_read_config_byte(dev, 0xdc, &bios_cntl); + switch (ich_version) { + case 9: + /* Deassert SMM BIOS Write Protect Disable. */ + bios_cntl &= ~(1 << 5); + break; + + default: + break; + } + pci_write_config_byte(dev, 0xdc, bios_cntl | 0x1); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_activate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + /* Handled by ICH automatically. */ +} + +typedef struct spi_transaction { + const uint8_t *out; + uint32_t bytesout; + uint8_t *in; + uint32_t bytesin; + uint8_t type; + uint8_t opcode; + uint32_t offset; +} spi_transaction; + +static inline void spi_use_out(spi_transaction *trans, unsigned bytes) +{ + trans->out += bytes; + trans->bytesout -= bytes; +} + +static inline void spi_use_in(spi_transaction *trans, unsigned bytes) +{ + trans->in += bytes; + trans->bytesin -= bytes; +} + +static void spi_setup_type(spi_transaction *trans) +{ + trans->type = 0xFF; + + /* Try to guess spi type from read/write sizes. */ + if (trans->bytesin == 0) { + if (trans->bytesout > 4) + /* + * If bytesin = 0 and bytesout > 4, we presume this is + * a write data operation, which is accompanied by an + * address. + */ + trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS; + else + trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS; + return; + } + + if (trans->bytesout == 1) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS; + return; + } + + if (trans->bytesout == 4) { /* and bytesin is > 0 */ + trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS; + } +} + +static int spi_setup_opcode(spi_transaction *trans) +{ + uint16_t optypes; + uint8_t opmenu[cntlr.menubytes]; + + trans->opcode = trans->out[0]; + spi_use_out(trans, 1); + if (!ichspi_lock) { + /* The lock is off, so just use index 0. */ + writeb_(trans->opcode, cntlr.opmenu); + optypes = readw_(cntlr.optype); + optypes = (optypes & 0xfffc) | (trans->type & 0x3); + writew_(optypes, cntlr.optype); + return 0; + } else { + /* The lock is on. See if what we need is on the menu. */ + uint8_t optype; + uint16_t opcode_index; + + read_reg(cntlr.opmenu, opmenu, sizeof(opmenu)); + for (opcode_index = 0; opcode_index < cntlr.menubytes; + opcode_index++) { + if (opmenu[opcode_index] == trans->opcode) + break; + } + + if (opcode_index == cntlr.menubytes) { + printk(BIOS_DEBUG, "ICH SPI: Opcode %x not found\n", + trans->opcode); + return -1; + } + + optypes = readw_(cntlr.optype); + optype = (optypes >> (opcode_index * 2)) & 0x3; + if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS && + optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS && + trans->bytesout >= 3) { + /* We guessed wrong earlier. Fix it up. */ + trans->type = optype; + } + if (optype != trans->type) { + printk(BIOS_DEBUG, "ICH SPI: Transaction doesn't fit type %d\n", + optype); + return -1; + } + return opcode_index; + } +} + +static int spi_setup_offset(spi_transaction *trans) +{ + /* Separate the SPI address and data. */ + switch (trans->type) { + case SPI_OPCODE_TYPE_READ_NO_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_NO_ADDRESS: + return 0; + case SPI_OPCODE_TYPE_READ_WITH_ADDRESS: + case SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS: + trans->offset = ((uint32_t)trans->out[0] << 16) | + ((uint32_t)trans->out[1] << 8) | + ((uint32_t)trans->out[2] << 0); + spi_use_out(trans, 3); + return 1; + default: + printk(BIOS_DEBUG, "Unrecognized SPI transaction type %#x\n", trans->type); + return -1; + } +} + +/* + * Wait for up to 60ms til status register bit(s) turn 1 (in case wait_til_set + * below is True) or 0. In case the wait was for the bit(s) to set - write + * those bits back, which would cause resetting them. + * + * Return the last read status value on success or -1 on failure. + */ +static int ich_status_poll(u16 bitmask, int wait_til_set) +{ + int timeout = 6000; /* This will result in 60 ms */ + u16 status = 0; + + while (timeout--) { + status = readw_(cntlr.status); + if (wait_til_set ^ ((status & bitmask) == 0)) { + if (wait_til_set) + writew_((status & bitmask), cntlr.status); + return status; + } + udelay(10); + } + + printk(BIOS_DEBUG, "ICH SPI: SCIP timeout, read %x, expected %x\n", + status, bitmask); + return -1; +} + +int spi_xfer(struct spi_slave *slave, const void *dout, + unsigned int bitsout, void *din, unsigned int bitsin) +{ + uint16_t control; + int16_t opcode_index; + int with_address; + int status; + + spi_transaction trans = { + dout, bitsout / 8, + din, bitsin / 8, + 0xff, 0xff, 0 + }; + + /* There has to always at least be an opcode. */ + if (!bitsout || !dout) { + printk(BIOS_DEBUG, "ICH SPI: No opcode for transfer\n"); + return -1; + } + /* Make sure if we read something we have a place to put it. */ + if (bitsin != 0 && !din) { + printk(BIOS_DEBUG, "ICH SPI: Read but no target buffer\n"); + return -1; + } + /* Right now we don't support writing partial bytes. */ + if (bitsout % 8 || bitsin % 8) { + printk(BIOS_DEBUG, "ICH SPI: Accessing partial bytes not supported\n"); + return -1; + } + + if (ich_status_poll(SPIS_SCIP, 0) == -1) + return -1; + + writew_(SPIS_CDS | SPIS_FCERR, cntlr.status); + + spi_setup_type(&trans); + if ((opcode_index = spi_setup_opcode(&trans)) < 0) + return -1; + if ((with_address = spi_setup_offset(&trans)) < 0) + return -1; + + if (!ichspi_lock && trans.opcode == 0x06) { + /* + * Treat Write Enable as Atomic Pre-Op if possible + * in order to prevent the Management Engine from + * issuing a transaction between WREN and DATA. + */ + writew_(trans.opcode, cntlr.preop); + return 0; + } + + /* Preset control fields */ + control = SPIC_SCGO | ((opcode_index & 0x07) << 4); + + /* Issue atomic preop cycle if needed */ + if (readw_(cntlr.preop)) + control |= SPIC_ACS; + + if (!trans.bytesout && !trans.bytesin) { + /* + * This is a 'no data' command (like Write Enable), its + * bitesout size was 1, decremented to zero while executing + * spi_setup_opcode() above. Tell the chip to send the + * command. + */ + writew_(control, cntlr.control); + + /* wait for the result */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Command transaction error\n"); + return -1; + } + + return 0; + } + + /* + * Check if this is a write command atempting to transfer more bytes + * than the controller can handle. Iterations for writes are not + * supported here because each SPI write command needs to be preceded + * and followed by other SPI commands, and this sequence is controlled + * by the SPI chip driver. + */ + if (trans.bytesout > cntlr.databytes) { + printk(BIOS_DEBUG, "ICH SPI: Too much to write. Does your SPI chip driver use" + " CONTROLLER_PAGE_LIMIT?\n"); + return -1; + } + + /* + * Read or write up to databytes bytes at a time until everything has + * been sent. + */ + while (trans.bytesout || trans.bytesin) { + uint32_t data_length; + + /* SPI addresses are 24 bit only */ + writel_(trans.offset & 0x00FFFFFF, cntlr.addr); + + if (trans.bytesout) + data_length = min(trans.bytesout, cntlr.databytes); + else + data_length = min(trans.bytesin, cntlr.databytes); + + /* Program data into FDATA0 to N */ + if (trans.bytesout) { + write_reg(trans.out, cntlr.data, data_length); + spi_use_out(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + + /* Add proper control fields' values */ + control &= ~((cntlr.databytes - 1) << 8); + control |= SPIC_DS; + control |= (data_length - 1) << 8; + + /* write it */ + writew_(control, cntlr.control); + + /* Wait for Cycle Done Status or Flash Cycle Error. */ + status = ich_status_poll(SPIS_CDS | SPIS_FCERR, 1); + if (status == -1) + return -1; + + if (status & SPIS_FCERR) { + printk(BIOS_DEBUG, "ICH SPI: Data transaction error\n"); + return -1; + } + + if (trans.bytesin) { + read_reg(cntlr.data, trans.in, data_length); + spi_use_in(&trans, data_length); + if (with_address) + trans.offset += data_length; + } + } + + /* Clear atomic preop now that xfer is done */ + writew_(0, cntlr.preop); + + return 0; +} From gerrit at coreboot.org Sat May 5 00:38:58 2012 From: gerrit at coreboot.org (Stefan Reinauer (stefan.reinauer@coreboot.org)) Date: Sat, 5 May 2012 00:38:58 +0200 Subject: [coreboot] New patch to review for coreboot: e9bfd63 Add a tool to work on i915 hardware in user mode References: Message-ID: Stefan Reinauer (stefan.reinauer at coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1003 -gerrit commit e9bfd63e863eb3a57e697e10e84c211a2ee4a7e5 Author: Stefan Reinauer Date: Fri May 4 15:37:18 2012 -0700 Add a tool to work on i915 hardware in user mode This is the beginning of a tool that transforms the i9x5 code to user mode code. Consider this a very early stage although it does produce two programs. Requires spatch 1.0 or greater. To try it out, assuming you have an up-to-date spatch, sh transform make make broken Please don't fall to the temptation to auto-magicize this process. It's primitive for a reason. That said, suggestions welcome of course. Change-Id: I0188e36637b198b06c17f6d3c714d990e88bd57d Signed-off-by: Ronald G. Minnich --- util/i915tool/Makefile | 20 + util/i915tool/README | 11 + util/i915tool/main.c | 255 +++++++++++++ util/i915tool/pci.c | 97 +++++ util/i915tool/plusplusplus | 3 + util/i915tool/spatches/deldev.cocci | 29 ++ util/i915tool/spatches/drm_crtc.cocci | 32 ++ util/i915tool/spatches/fixcalls.cocci | 148 ++++++++ util/i915tool/spatches/fx.cocci | 10 + util/i915tool/spatches/getdrmmodefn.cocci | 6 + util/i915tool/spatches/getfn.cocci | 61 +++ util/i915tool/spatches/i915_dma.c.cocci | 3 + util/i915tool/spatches/i915_drv.c.cocci | 8 + util/i915tool/spatches/i915_drv.cocci | 178 +++++++++ util/i915tool/spatches/intel_bios.cocci | 7 + util/i915tool/spatches/intel_display.c.cocci | 507 ++++++++++++++++++++++++++ util/i915tool/spatches/removeinclude.cocci | 6 + util/i915tool/spatches/ringbuffer.cocci | 14 + util/i915tool/transform | 151 ++++++++ util/i915tool/video.h | 133 +++++++ 20 files changed, 1679 insertions(+), 0 deletions(-) diff --git a/util/i915tool/Makefile b/util/i915tool/Makefile new file mode 100644 index 0000000..4cd807a --- /dev/null +++ b/util/i915tool/Makefile @@ -0,0 +1,20 @@ +source=main.c pci.c final/intel_bios.c final/drm_modes.c final/i915_drv.c + +all: probe + +broken: video + +video: $(source) final/intel_display.c + cc -include video.h -Iinputs -static -g -o video $(source) \ + -lpci final/intel_display.c + +probe: $(source) + cc -include video.h -Iinputs -static -g -o probe $(source) -lpci +clean: + rm -f *.o video probe + +moreclean: clean + rm final/* per-file-changes/* tmp/* + +superclean: moreclean + rm inputs/* diff --git a/util/i915tool/README b/util/i915tool/README new file mode 100644 index 0000000..cb5f986 --- /dev/null +++ b/util/i915tool/README @@ -0,0 +1,11 @@ +spatches are the semantic patches +tmp is just tmp +inputs are copied from $LINUX +per-file-changes contain input files that have specific transforms +final contains the final form of the file, with 'global' changes applied (e.g. kzalloc -> calloc) + +transform copies files from $LINUX and then transforms them for use by stand-alone program/coreboot + +The Makefile is simple; this runs 'fast enough' that a complicated Makefile is not worth it. + +There's still some duct tape here but it's getting there. diff --git a/util/i915tool/main.c b/util/i915tool/main.c new file mode 100644 index 0000000..cb828e1 --- /dev/null +++ b/util/i915tool/main.c @@ -0,0 +1,255 @@ +/* + * This file is part of i915tool + * + * Copyright (C) 2012 The ChromiumOS Authors. All rights reserved. + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "video.h" + +int verbose = 1; +static unsigned short addrport, dataport; +struct drm_device *i915; +unsigned short vendor=0x8086, device=0x0116; +struct pci_dev fake = {.vendor_id=0x8086, .device_id = 0x0116}; +int dofake = 0; +u8 *bios_image = NULL; +u8 *mmiobase; +u32 mmiophys; +int mmiosize; +size_t bios_image_size; +/* temporary */ +unsigned int i915_lvds_downclock = 0; +int i915_vbt_sdvo_panel_type = -1; + +/* */ + +/* not sure how we want to do this so let's guess */ +/* to make it easy, we start at zero and assume 250 hz. */ +unsigned long msecs(void) +{ + struct timeval start, now; + static int first = 0; + unsigned long j; + if (! first++) + gettimeofday(&start, NULL); + gettimeofday(&now, NULL); + j = (now.tv_sec - start.tv_sec)*1000 + (now.tv_usec-start.tv_usec)/1000; + return j; +} + +void +mdelay(unsigned long ms) +{ + unsigned long start; + start = msecs(); + while (msecs() < (start + ms)) + ; +} + +void +hexdump(u8 *base, int size) +{ + int i, j; + for(i = 0; i < size/sizeof(u32); i += 8) { + printf("%#x: ", i); + for(j = 0; j < 8; j++) + printf("%08x", base[i+j]); + printf("\n"); + } +} +void udelay(int i) +{ + printf("UDELAY!\n"); +} + +unsigned long io_I915_READ(unsigned long addr) +{ + unsigned long val; + if (dofake) + return 0xcafebabe; + outl(addr, addrport); + val = inl(dataport); + if (verbose) + fprintf(stderr, "%s: %x <- %x\n", __func__, val, addr); + return val; +} + +void io_I915_WRITE(unsigned long addr, unsigned long val) +{ + if (dofake) + return; + outl(addr, addrport); + outl(val, dataport); + if (verbose) + fprintf(stderr, "%s: %x -> %x\n", __func__, val, addr); +} + +unsigned long I915_READ(unsigned long addr) +{ + volatile u32 *ptr = (u32 *)(mmiobase + addr); + unsigned long val; + if (dofake) + return 0xcafebabe; + val = *ptr; + if (verbose) + fprintf(stderr, "%s: %x <- %x\n", __func__, val, addr); + return val; +} + +void I915_WRITE(unsigned long addr, unsigned long val) +{ + volatile u32 *ptr = (u32 *)(mmiobase + addr); + if (dofake) + return; + *ptr = val; + if (verbose) + fprintf(stderr, "%s: %x -> %x\n", __func__, val, addr); +} + +u16 I915_READ16(unsigned long addr) +{ + volatile u16 *ptr = (u16 *)(mmiobase + addr); + unsigned long val; + if (dofake) + return 0xbabe; + val = *ptr; + if (verbose) + fprintf(stderr, "%s: %x <- %x\n", __func__, val, addr); + return val; +} + +void I915_WRITE16(unsigned long addr, u16 val) +{ + volatile u16 *ptr = (u16 *)(mmiobase + addr); + if (dofake) + return; + *ptr = val; + if (verbose) + fprintf(stderr, "%s: %x -> %x\n", __func__, val, addr); +} + +#define GTT_RETRY 1000 +static int gtt_poll(u32 reg, u32 mask, u32 value) +{ + unsigned try = GTT_RETRY; + u32 data; + + while (try--) { + data = I915_READ(reg); + if ((data & mask) == value){ + printf("succeeds after %d tries\n", GTT_RETRY-try); + return 1; + } + udelay(10); + } + + fprintf(stderr, "GT init timeout\n"); + return 0; +} +void *pci_map_rom(struct pci_dev *dev, size_t *size) +{ + *size = bios_image_size; + return bios_image; +} + +void *pci_unmap_rom(struct pci_dev *dev, void *bios) +{ + return NULL; +} + +void *dmi_check_system(unsigned long ignore) +{ + return NULL; +} + +void +mapit(void) +{ + int kfd; + kfd = open("/dev/mem", O_RDWR); + if (kfd < 0) + errx(1, "/dev/kmem"); + mmiobase = mmap(NULL, mmiosize, PROT_WRITE|PROT_READ, MAP_SHARED, kfd, + mmiophys); + if ((void *)-1 == mmiobase) + errx(1, "mmap"); +} + +void +devinit() +{ + u32 val; + /* force wake. */ + I915_WRITE(0xa18c, 1); + gtt_poll(0x130090, 1, 1); +} +int main(int argc, char *argv[]) +{ + struct pci_dev *pci_dev_find(struct drm_device *dev); + + for(argc--, argv++; argc; argc--, argv++) { + if (argv[0][0] != '-') + break; + if (!strcmp(argv[0], "-f")) + dofake++; + } + i915 = calloc(1, sizeof(*i915)); + i915->dev_private = calloc(1, sizeof(*i915->dev_private)); + /* until we do a bit more w/ coccinelle */ + i915->dev_private->dev = i915; + + if (dofake) { + i915->pdev = &fake; + if (! find_idlist(i915, vendor, device)) + errx(1, "can't find fake device in pciidlist"); + } else { + if (! pci_dev_find(i915)) + errx(1, "No VGA device of any kind found\n"); + } + + if (argc) { + FILE *fd; + int amt; + /* size it later */ + bios_image = malloc(8*1048576); + fd = fopen(argv[0], "r"); + amt = fread(bios_image, 65536, 128, fd); + if (amt < 1) { + free(bios_image); + } else { + i915->bios_bin = bios_image; + i915->dev_private->opregion.vbt = bios_image; + bios_image_size = amt * 65536; + fclose(fd); + } + } + /* get the base address for the mmio indirection registers -- BAR 2 */ + addrport = i915->pdev->base_addr[4] & ~3; + dataport = addrport + 4; + printf("Addrport is at %x, dataport at %x\n", addrport, dataport); + /* get the base of the mmio space */ + mmiophys = i915->pdev->base_addr[0] & ~0xf; + mmiosize = i915->pdev->size[0]; + printf("phys base is %#x, size %d\n", mmiophys, mmiosize); + mapit(); + devinit(); + //hexdump(mmiobase, mmiosize); + /* we should use ioperm but hey ... it's had troubles */ + iopl(3); + intel_setup_bios(i915); + if (i915->bios_bin) + intel_parse_bios(i915); +} diff --git a/util/i915tool/pci.c b/util/i915tool/pci.c new file mode 100644 index 0000000..ca942dc --- /dev/null +++ b/util/i915tool/pci.c @@ -0,0 +1,97 @@ +/* + * This file is part of i915tool + * + * Copyright (C) 2012 The ChromiumOS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "video.h" + +int find_idlist(struct drm_device *dev, u16 vendor, u16 device) +{ + extern const struct pci_device_id pciidlist[]; + int succ = 0; + int i; + for(i = 0; pciidlist[i].vendor && !succ; i++){ + if (vendor == pciidlist[i].vendor && device == + pciidlist[i].device){ + dev->dev_private->info = + (void *)(pciidlist[i].driver_data); + succ = 1; + } + } + return succ; +} + +/* there's only going to be one device ... */ +int pci_dev_find(struct drm_device *dev) +{ + struct pci_access *pacc = NULL; + struct pci_dev *temp; + int succ = 0; + pacc = pci_alloc(); + if (! pacc) + return 0; + pci_init(pacc); + pci_scan_bus(pacc); + + for (temp = pacc->devices; temp && ! dev->pdev; temp = temp->next){ + if ((temp->device_class & 0xff00) == PCI_CLASS_DISPLAY_VGA ) { + pci_fill_info(temp, PCI_FILL_IDENT | + PCI_FILL_BASES | PCI_FILL_CLASS); + dev->pdev = temp; + } + } + + if (dev->pdev) + succ = find_idlist(dev, dev->pdev->vendor_id, + dev->pdev->device_id); + return succ; +} + +/* Support library for kernel style pci functions. We could do a semantic + * patch for it but this is easier to debug as we can fill it with prints + * if we want. And no cpp abuse here. Keep it simple. + */ + +void pci_read_config_byte(struct pci_dev *dev, unsigned long offset, u8 *val) +{ + *val = pci_read_byte(dev, offset); +} + +void pci_write_config_byte(struct pci_dev *dev, unsigned long offset, u8 val) +{ + pci_write_byte(dev, offset, val); +} + +void pci_read_config_word(struct pci_dev *dev, unsigned long offset, u16 *val) +{ + *val = pci_read_word(dev, offset); +} + +void pci_write_config_word(struct pci_dev *dev, unsigned long offset, u16 val) +{ + pci_write_word(dev, offset, val); +} + +void pci_read_config_dword(struct pci_dev *dev, unsigned long offset, u32 *val) +{ + *val = pci_read_long(dev, offset); +} + +void pci_write_config_dword(struct pci_dev *dev, unsigned long offset, u32 val) +{ + pci_write_long(dev, offset, val); +} diff --git a/util/i915tool/plusplusplus b/util/i915tool/plusplusplus new file mode 100644 index 0000000..a5dcd19 --- /dev/null +++ b/util/i915tool/plusplusplus @@ -0,0 +1,3 @@ +#!/bin/bash +sed 's,^\+\+\+.*,+++ '$2',' < $1 > $1.pat + diff --git a/util/i915tool/spatches/deldev.cocci b/util/i915tool/spatches/deldev.cocci new file mode 100644 index 0000000..504dae7 --- /dev/null +++ b/util/i915tool/spatches/deldev.cocci @@ -0,0 +1,29 @@ +@@ +identifier dev; +expression i; +@@ +-struct drm_i915_private *dev = i; ++extern struct drm_device *i915; struct drm_i915_private *dev = i915->dev_private; +@@ +identifier dev; +expression i; +@@ +-struct pci_dev *dev = i; ++extern struct drm_device *i915; struct pci_dev *dev = i915->pdev; +@@ +@@ +-#include "i915_drm.h" +@@ +@@ +-#include "drm.h" +@@ +@@ +-#include "drmP.h" +@@ +@@ +-#include "i915_trace.h" +@@ +identifier d; +@@ +-(d)->pci_device ++(d)->pdev->device_id diff --git a/util/i915tool/spatches/drm_crtc.cocci b/util/i915tool/spatches/drm_crtc.cocci new file mode 100644 index 0000000..662f253 --- /dev/null +++ b/util/i915tool/spatches/drm_crtc.cocci @@ -0,0 +1,32 @@ +@@ +identifier s; +identifier head; +@@ +struct s {... +- struct list_head head; +...}; +@@ +@@ +-#include <...> +@@ +@@ +( +-struct drm_crtc_funcs{...}; +| +-struct drm_crtc{...}; +| +-struct drm_connector_funcs{...}; +| +-struct drm_encoder_funcs{...}; +| +-struct drm_encoder{...}; +| +-struct drm_connector{...}; +| +-struct drm_mode_config_funcs{...}; +| +-struct drm_mode_config{...}; +| +-struct drm_framebuffer_funcs{...}; +) + diff --git a/util/i915tool/spatches/fixcalls.cocci b/util/i915tool/spatches/fixcalls.cocci new file mode 100644 index 0000000..50e6458 --- /dev/null +++ b/util/i915tool/spatches/fixcalls.cocci @@ -0,0 +1,148 @@ +@@ +identifier f; +type T; +@@ +T f(...){<... +-vga_get_uninterruptible(...); +...>} +@@ +identifier f; +type T; +@@ +T f(...){<... +-vga_put(...); +...>} +@@ +identifier f; +type T; +@@ +T f(...){<... +-intel_init_quirks(...); +...>} +@@ +identifier f; +type T; +@@ +T f(...){<... +-drm_mode_config_init(...); +...>} +@@ +identifier f; +type T; +@@ +T f(...){<... +-INIT_WORK(...); +...>} +@@ +identifier f; +type T; +@@ +T f(...){<... +-setup_timer(...); +...>} +@@ +identifier f; +type T; +@@ +T f(...){<... +-DRM_DEBUG_KMS( ++fprintf(stderr, +...); +...>} +@@ +identifier f; +type T; +@@ +T f(...){<... +-DRM_ERROR( ++fprintf(stderr, +...); +...>} +@@ +identifier f; +type T; +@@ +T f(...){<... +-DRM_DEBUG( ++fprintf(stderr, +...); +...>} +@@ +identifier f; +type T; +@@ +T f(...){<... +-DRM_DEBUG_DRIVER( ++fprintf(stderr, +...); +...>} +@@ +identifier f; +type T; +@@ +T f(...){<... +-intel_init_display(...); +...>} +@ rulekz @ +identifier t; +identifier f; +expression E1, E2; +type T; +@@ +T f(...){<... +t = kzalloc(E1, E2); +...>} +@@ +identifier rulekz.f; +expression E1, E2; +@@ + +- kzalloc(E1 ++ calloc(1, E1 +- ,E2 + ) +@@ +identifier d; +@@ +-static +const struct pci_device_id d[] = {...}; +@@ +expression E1; +@@ +-WARN( ++if ( +E1 +-, ++) fprintf(stderr, +...); +@@ +expression E1; +@@ +-BUG_ON( ++assert( +E1); +@@ +@@ +-jiffies ++msecs() +@@ +expression E1; +@@ +-jiffies_to_msecs( +E1 +-) +@@ +expression E1; +@@ +-msecs_to_jiffies( +E1 +-) +@@ +expression E1, E2; +@@ +-time_after( ++( +E1 +-, ++> +E2) diff --git a/util/i915tool/spatches/fx.cocci b/util/i915tool/spatches/fx.cocci new file mode 100644 index 0000000..e47ddca --- /dev/null +++ b/util/i915tool/spatches/fx.cocci @@ -0,0 +1,10 @@ +@@ +identifier f; +type T; +@@ +T f(...){... +-\(DRM_DEBUG_KMS|DRM_ERRRO\)( ++fprintf(stderr, +...); +...} + diff --git a/util/i915tool/spatches/getdrmmodefn.cocci b/util/i915tool/spatches/getdrmmodefn.cocci new file mode 100644 index 0000000..d5cd17e --- /dev/null +++ b/util/i915tool/spatches/getdrmmodefn.cocci @@ -0,0 +1,6 @@ +@@ +@@ +- drm_mode_set_name(...) {...} +@@ +@@ +- drm_mode_debug_printmodeline(...) {...} diff --git a/util/i915tool/spatches/getfn.cocci b/util/i915tool/spatches/getfn.cocci new file mode 100644 index 0000000..8dea561 --- /dev/null +++ b/util/i915tool/spatches/getfn.cocci @@ -0,0 +1,61 @@ +@@ +@@ +- get_blocksize(...) {...} +@@ +@@ +- lvds_dvo_timing_equal_size(...) {...} +@@ +@@ +- fill_detail_timing_data(...) {...} +@@ +@@ +- intel_setup_bios(...) {...} +@@ +@@ +- intel_parse_bios(...){...} +@@ +@@ +- init_vbt_defaults(...){...} +@@ +@@ +- parse_general_features(...){...} +@@ +@@ +- parse_general_definitions(...){...} +@@ +@@ +- parse_lfp_panel_data(...){...} +@@ +@@ +- parse_sdvo_panel_data(...){...} +@@ +@@ +- parse_sdvo_device_mapping(...){...} +@@ +@@ +- parse_device_mapping(...){...} +@@ +@@ +- parse_driver_features(...){...} +@@ +@@ +- parse_edp(...){...} +@@ +@@ +- find_section(...){...} +@@ +@@ +- get_lvds_dvo_timing(...){...} +@@ +@@ +- intel_bios_ssc_frequency(...){...} +@@ +identifier d; +type T; +@@ +- static T d; +@@ +expression S; +identifier d; +@@ +-#define d S diff --git a/util/i915tool/spatches/i915_dma.c.cocci b/util/i915tool/spatches/i915_dma.c.cocci new file mode 100644 index 0000000..0ae2d55 --- /dev/null +++ b/util/i915tool/spatches/i915_dma.c.cocci @@ -0,0 +1,3 @@ +@@ +@@ +- i915_driver_load(...) {...} diff --git a/util/i915tool/spatches/i915_drv.c.cocci b/util/i915tool/spatches/i915_drv.c.cocci new file mode 100644 index 0000000..0d64d93 --- /dev/null +++ b/util/i915tool/spatches/i915_drv.c.cocci @@ -0,0 +1,8 @@ + at inteldeviceinfo@ +identifier d; +@@ +-const struct intel_device_info d = {...}; +@@ +identifier d; +@@ +-static const struct pci_device_id d[] = {...}; diff --git a/util/i915tool/spatches/i915_drv.cocci b/util/i915tool/spatches/i915_drv.cocci new file mode 100644 index 0000000..633e270 --- /dev/null +++ b/util/i915tool/spatches/i915_drv.cocci @@ -0,0 +1,178 @@ +@@ +identifier d; +@@ +( +-struct drm_i915_fence_reg{...}; +| +-struct drm_i915_error_state{...}; +| +-struct drm_i915_gem_object{...}; +| +-struct drm_i915_display_funcs {...}; +| +-struct drm_i915_gem_phys_object{...}; +| +-struct mem_block{...}; +| +-struct drm_i915_gem_request{...}; +| +-struct drm_i915_file_private{...}; +| +-struct drm_i915_master_private{...}; +| +-struct intel_gmbus{...}; +| +-struct work_struct d; +| +-struct mem_*d; +| +-struct timer_list d; +| +-struct intel_fbc_work *d; +| +-struct drm_i915_error_state *d; +| +-struct i2c_adapter d; +| +-struct i2c_adapter *d; +| +-struct intel_hw_status_page{...}; +| +-struct intel_hw_status_page d; +) +@@ +@@ +-#include<...> +@@ +identifier d; +@@ +struct s {... +- struct drm_i915_display_funcs d; +... +}; +@@ +identifier d; +@@ +struct s {... +-struct notifier_block d; +... +}; +@@ +identifier s; +identifier d; +@@ +struct s {... +-spinlock_t d; +... +}; +@@ +identifier s; +identifier d; +@@ +struct s {... +-atomic_t d; +... +}; +@@ +identifier s; +identifier d; +@@ +struct s {... +-drm_dma_handle_t *d; +... +}; +@@ +identifier s; +identifier d; +@@ +struct s {... +-drm_local_map_t d; +... +}; +@@ +identifier s; +identifier d; +@@ +struct s {... +-spinlock_t *d; +... +}; +@@ +identifier s; +identifier d; +@@ +struct s {... +-struct i2c_adapter d; +... +}; +@@ +identifier s; +identifier d; +@@ +struct s {... +-struct i2c_adapter *d; +... +}; +@@ +identifier s; +identifier d; +@@ +struct s {... +( +-struct inteL_gmbus {...} *d; +| +-struct drm_i915_gem_object *d; +) +... +}; +@@ +identifier s; +identifier d; +@@ +struct s {... +-struct work_struct d; +... +}; +@@ +identifier s; +identifier d; +@@ +struct s {... +-struct resource d; +... +}; +@@ +identifier s; +identifier d; +@@ +struct s {... +-struct timer_list d; +... +}; +@@ +identifier s; +identifier d; +@@ +struct s {... +-wait_queue_head_t d; +... +}; +@@ +identifier s; +identifier d; +constant c; +@@ +struct s {... +-struct intel_ring_buffer d[c]; +... +}; +@@ +identifier s; +identifier d; +constant c; +@@ +struct s {... +-struct drm_i915_fence_reg d[c]; +... +}; + diff --git a/util/i915tool/spatches/intel_bios.cocci b/util/i915tool/spatches/intel_bios.cocci new file mode 100644 index 0000000..2e71363 --- /dev/null +++ b/util/i915tool/spatches/intel_bios.cocci @@ -0,0 +1,7 @@ +@@ +@@ +-#include<...> ++#include "video.h" +@@ +@@ +-#include"..." diff --git a/util/i915tool/spatches/intel_display.c.cocci b/util/i915tool/spatches/intel_display.c.cocci new file mode 100644 index 0000000..d7d87d3 --- /dev/null +++ b/util/i915tool/spatches/intel_display.c.cocci @@ -0,0 +1,507 @@ +@@ +@@ +-struct intel_limit {... }; +@@ +identifier d; +@@ +- intel_limit_t d = {...}; +@@ +@@ +- intel_connector_attach_encoder(...){...} +@@ +@@ +- intel_modeset_cleanup(...){...} +@@ +@@ +- intel_modeset_gem_init(...){...} +@@ +@@ +- intel_modeset_init(...){...} +@@ +@@ +- i915_disable_vga(...){...} +@@ +@@ +- intel_init_quirks(...){...} +@@ +@@ +- quirk_ssc_force_disable(...){...} +@@ +@@ +- quirk_pipea_force (...){...} +@@ +@@ +- intel_init_display(...){...} +@@ +@@ +- intel_init_clock_gating(...){...} +@@ +@@ +- ironlake_enable_rc6(...){...} +@@ +@@ +- ironlake_disable_rc6(...){...} +@@ +@@ +- ironlake_teardown_rc6(...){...} +@@ +@@ +- cpt_init_clock_gating(...){...} +@@ +@@ +- ibx_init_clock_gating(...){...} +@@ +@@ +- i830_init_clock_gating(...){...} +@@ +@@ +- i85x_init_clock_gating(...){...} +@@ +@@ +- gen3_init_clock_gating(...){...} +@@ +@@ +- broadwater_init_clock_gating(...){...} +@@ +@@ +- crestline_init_clock_gating(...){...} +@@ +@@ +- g4x_init_clock_gating(...){...} +@@ +@@ +- ivybridge_init_clock_gating(...){...} +@@ +@@ +- gen6_init_clock_gating(...){...} +@@ +@@ +- ironlake_init_clock_gating(...){...} +@@ +@@ +- gen6_update_ring_freq(...){...} +@@ +@@ +- gen6_enable_rps(...){...} +@@ +@@ +- intel_init_emon(...){...} +@@ +@@ +- gen6_disable_rps(...){...} +@@ +@@ +- gen6_set_rps(...){...} +@@ +@@ +- ironlake_disable_drps(...){...} +@@ +@@ +- ironlake_enable_drps(...){...} +@@ +@@ +- intel_user_framebuffer_destroy(...){...} +@@ +@@ +- intel_setup_outputs(...){...} +@@ +@@ +- intel_crtc_init(...){...} +@@ +@@ +- intel_crtc_reset(...){...} +@@ +@@ +- intel_prepare_page_flip(...){...} +@@ +@@ +- intel_finish_page_flip_plane(...){...} +@@ +@@ +- intel_finish_page_flip(...){...} +@@ +@@ +- intel_unpin_work_fn(...){...} +@@ +@@ +- intel_crtc_destroy(...){...} +@@ +@@ +- intel_mark_busy(...){...} +@@ +@@ +- intel_idle_update(...){...} +@@ +@@ +- intel_decrease_pllclock(...){...} +@@ +@@ +- intel_increase_pllclock(...){...} +@@ +@@ +- intel_crtc_idle_timer(...){...} +@@ +@@ +- intel_gpu_idle_timer(...){...} +@@ +@@ +- ivb_update_cursor(...){...} +@@ +@@ +- i9xx_update_cursor(...){...} +@@ +@@ +- i845_update_cursor(...){...} +@@ +@@ +- intel_crtc_load_lut(...){...} +@@ +@@ +- ironlake_update_pch_refclk(...){...} +@@ +@@ +- intel_update_watermarks(...){...} +@@ +@@ +- sandybridge_update_wm(...){...} +@@ +@@ +- ironlake_update_wm(...){...} +@@ +@@ +- i830_update_wm(...){...} +@@ +@@ +- i9xx_update_wm(...){...} +@@ +@@ +- i965_update_wm(...){...} +@@ +@@ +- g4x_update_wm(...){...} +@@ +@@ +- pineview_update_wm(...){...} +@@ +@@ +- pineview_disable_cxsr(...){...} +@@ +@@ +- intel_encoder_destroy(...){...} +@@ +@@ +- intel_encoder_commit (...){...} +@@ +@@ +- intel_encoder_prepare (...){...} +@@ +@@ +- ironlake_crtc_commit(...){...} +@@ +@@ +- ironlake_crtc_prepare(...){...} +@@ +@@ +- i9xx_crtc_commit(...){...} +@@ +@@ +- i9xx_crtc_prepare(...){...} +@@ +@@ +- intel_crtc_disable(...){...} +@@ +@@ +- intel_crtc_dpms(...){...} +@@ +@@ +- i9xx_crtc_dpms(...){...} +@@ +@@ +- i9xx_crtc_disable(...){...} +@@ +@@ +- i9xx_crtc_enable(...){...} +@@ +@@ +- intel_crtc_dpms_overlay(...){...} +@@ +@@ +- ironlake_crtc_dpms(...){...} +@@ +@@ +- ironlake_crtc_disable(...){...} +@@ +@@ +- ironlake_crtc_enable(...){...} +@@ +@@ +- intel_cpt_verify_modeset(...){...} +@@ +@@ +- ironlake_pch_enable(...){...} +@@ +@@ +- intel_crtc_wait_for_pending_flips(...){...} +@@ +@@ +- intel_clear_scanline_wait(...){...} +@@ +@@ +- ironlake_fdi_disable(...){...} +@@ +@@ +- cpt_phase_pointer_disable(...){...} +@@ +@@ +- ironlake_fdi_pll_enable(...){...} +@@ +@@ +- ivb_manual_fdi_link_train(...){...} +@@ +@@ +- gen6_fdi_link_train(...){...} +@@ +@@ +- ironlake_fdi_link_train(...){...} +@@ +@@ +- cpt_phase_pointer_enable(...){...} +@@ +@@ +- intel_fdi_normal_train(...){...} +@@ +@@ +- ironlake_set_pll_edp(...){...} +@@ +@@ +- intel_update_fbc(...){...} +@@ +@@ +- intel_disable_fbc(...){...} +@@ +@@ +- intel_enable_fbc(...){...} +@@ +@@ +- intel_cancel_fbc_work(...){...} +@@ +@@ +- intel_fbc_work_fn(...){...} +@@ +@@ +- ironlake_disable_fbc(...){...} +@@ +@@ +- ironlake_enable_fbc(...){...} +@@ +@@ +- sandybridge_blit_fbc_update(...){...} +@@ +@@ +- g4x_disable_fbc(...){...} +@@ +@@ +- g4x_enable_fbc(...){...} +@@ +@@ +- i8xx_enable_fbc(...){...} +@@ +@@ +- i8xx_disable_fbc(...){...} +@@ +@@ +- intel_disable_pll(...){...} +@@ +@@ +- intel_enable_pll(...){...} +@@ +@@ +- intel_clock(...){...} +@@ +@@ +- pineview_clock(...){...} +@@ +@@ +- intel_ironlake_limit(...){...} +@@ +@@ +- intel_g4x_limit(...){...} +@@ +@@ +- intel_limit(...){...} +@@ +@@ +- intel_pipe_has_type(...){...} +@@ +@@ +- intel_PLL_is_valid(...){...} +@@ +@@ +- intel_find_best_PLL(...){...} +@@ +@@ +- intel_g4x_find_best_PLL(...){...} +@@ +@@ +- intel_find_pll_ironlake_dp(...){...} +@@ +@@ +- intel_fbc_enabled(...){...} +@@ +@@ +- intel_pin_and_fence_fb_obj(...){...} +@@ +@@ +- i9xx_update_plane(...){...} +@@ +@@ +- ironlake_update_plane(...){...} +@@ +@@ +- intel_pipe_set_base_atomic(...){...} +@@ +@@ +- intel_pipe_set_base(...){...} +@@ +@@ +- intel_crtc_driving_pch(...){...} +@@ +@@ +- intel_crtc_mode_fixup(...){...} +@@ +@@ +- single_enabled_crtc(...){...} +@@ +@@ +- g4x_compute_wm0(...){...} +@@ +@@ +- g4x_compute_srwm(...){...} +@@ +@@ +- ironlake_compute_srwm(...){...} +@@ +@@ +- intel_panel_use_ssc(...){...} +@@ +@@ +- intel_choose_pipe_bpp_dither(...){...} +@@ +@@ +- i9xx_crtc_mode_set(...){...} +@@ +@@ +- ironlake_crtc_mode_set(...){...} +@@ +@@ +- intel_crtc_mode_set(...){...} +@@ +@@ +- intel_crtc_update_cursor(...){...} +@@ +@@ +- intel_crtc_cursor_set(...){...} +@@ +@@ +- intel_crtc_cursor_move(...){...} +@@ +@@ +- intel_crtc_fb_gamma_set(...){...} +@@ +@@ +- intel_crtc_fb_gamma_get(...){...} +@@ +@@ +- intel_crtc_gamma_set(...){...} +@@ +@@ +- intel_framebuffer_create(...){...} +@@ +@@ +- intel_framebuffer_size_for_mode(...){...} +@@ +@@ +- intel_framebuffer_create_for_mode(...){...} +@@ +@@ +- mode_fits_in_fbdev(...){...} +@@ +@@ +- intel_get_load_detect_pipe(...){...} +@@ +@@ +- intel_release_load_detect_pipe(...){...} +@@ +@@ +- intel_crtc_clock_get(...){...} +@@ +@@ +- intel_crtc_mode_get(...){...} +@@ +@@ +- do_intel_finish_page_flip(...){...} +@@ +@@ +- intel_gen2_queue_flip(...){...} +@@ +@@ +- intel_gen3_queue_flip(...){...} +@@ +@@ +- intel_gen4_queue_flip(...){...} +@@ +@@ +- intel_gen6_queue_flip(...){...} +@@ +@@ +- intel_gen7_queue_flip(...){...} +@@ +@@ +- intel_default_queue_flip(...){...} +@@ +@@ +- intel_crtc_page_flip(...){...} +@@ +@@ +- intel_get_pipe_from_crtc_id(...){...} +@@ +@@ +- intel_encoder_clones(...){...} +@@ +@@ +- intel_user_framebuffer_create_handle(...){...} +@@ +@@ +- intel_framebuffer_init(...){...} +@@ +@@ +- intel_user_framebuffer_create(...){...} +@@ +@@ +- intel_alloc_context_page(...){...} +@@ +@@ +- ironlake_setup_rc6(...){...} +@@ +@@ +- intel_best_encoder(...){...} +@@ +identifier d; +@@ +- struct drm_framebuffer_funcs d = {...}; +@@ +identifier d; +@@ +- struct drm_mode_config_funcs d = {...}; +@@ +identifier d; +@@ +-static struct drm_crtc_helper_funcs d = {...}; +@@ +identifier d; +@@ +-static struct drm_crtc_funcs d = {...}; +@@ +identifier d; +@@ +- struct intel_quirk d[] = {...}; diff --git a/util/i915tool/spatches/removeinclude.cocci b/util/i915tool/spatches/removeinclude.cocci new file mode 100644 index 0000000..ff1bfea --- /dev/null +++ b/util/i915tool/spatches/removeinclude.cocci @@ -0,0 +1,6 @@ +@@ +@@ +-#include<...> +@@ +@@ +-#include"..." diff --git a/util/i915tool/spatches/ringbuffer.cocci b/util/i915tool/spatches/ringbuffer.cocci new file mode 100644 index 0000000..68f0c98 --- /dev/null +++ b/util/i915tool/spatches/ringbuffer.cocci @@ -0,0 +1,14 @@ +@@ +identifier d; +type T; +@@ +-T d(...){...} +@@ +identifier d; +type T; +@@ +-T d(...); +@@ +identifier d; +@@ +-struct d{...}; diff --git a/util/i915tool/transform b/util/i915tool/transform new file mode 100644 index 0000000..3e191cb --- /dev/null +++ b/util/i915tool/transform @@ -0,0 +1,151 @@ +#!/bin/bash +# This script has been honed over quite a few iterations. The trick is to make +# it easy for you to see what transformations occur +# without burying you in files. +# Also, coccinelle is not perfect, so we have to help her at times. As she +# gets smarter, we can shrink thigns we do in here. +# So we get input files, then do per-file changes, then do all-file changes +# I've deliberately made this script simple. Please don't decide it needs to +# be automagic. Just let it work in its simple way. Also, if you change even +# one simple thing, ALWAYS rerun this script do make sure you did not make a +# global test. NEVER test one little thing in isolation. That way +# lies madness. +# The only thing you need to set is +# export LINUX=/path/to/your/linux/tree. +# Order in which we do things. +# 1. Get source files into inputs. +# 2. cp them to per-file-changes +# Note that we even copy ones that might not currently need per-file +# changes. Because they may in future and it keeps the script simple. +# We tried both ways and like this best. +# 3. run 'ed' across a few files that need it +# 4. run coccinelle with any per-file changes +# There is some ugliness here as we have to do a reverse patch step. Sorry. +# 5. cp per-file-changes/* to final +# 6. run coccinelle files that apply to more than one file +# it's best to run coccinelle on as many files as possible, she's pretty +# smart about +# certain transformations, e.g. if you remove a function definition she can +# remove all calls to that function (usually) +# +# Now you can +# make (will build all working tools) +# or +# make broken +# for things that don't build yet. + +# Step 1 +rm inputs/* per-file-changes/* final/* tmp/* +cp $LINUX/drivers/gpu/drm/i915/i915_reg.h inputs +cp $LINUX/drivers/gpu/drm/i915/i915_drv.? inputs +cp $LINUX/drivers/gpu/drm/i915/intel_display.c inputs +cp $LINUX/drivers/gpu/drm/i915/intel_bios.c inputs +cp $LINUX/drivers/gpu/drm/i915/intel_bios.h inputs +cp $LINUX/drivers/gpu/drm/i915/intel_ringbuffer.h inputs +cp $LINUX/drivers/gpu/drm/i915/i915_dma.c inputs +cp $LINUX/include/drm/drm_crtc.h inputs +cp $LINUX/include/drm/drm_mode.h inputs +cp $LINUX/include/drm/drm_dp_helper.h inputs +cp $LINUX/drivers/gpu/drm/drm_modes.c inputs + +# Step 2 +cp inputs/* per-file-changes + +# Step 3 +# We tried sed but it had some issues that ed did not +# coccinelle can't handle anonymous structs +# also some stuff is easier with ed. +# also there are bugs spatches/in coccinelle it seems :-( +# the literal deletes below suck and we need to figure +# out wtf went wrong. +ed per-file-changes/i915_drv.h << EOF +/intel_gtt/ +. +?struct *{?,/mm;/d +. +/i915_trace.h/ +. +.,/#define POSTING_READ16/d +/struct *intel_gmbus/ +.,/\*gmb/d +. +g/notifier_block/d +g/struct *drm_i915_display_funcs *display;/d +g/struct *completion *[a-z].*;/d +w +q +EOF + +ed per-file-changes/drm_crtc.h <per-file-changes/intel_bios.c +spatch -sp_file spatches/getfn.cocci inputs/intel_bios.c -U 0 > tmp/res +./plusplusplus tmp/res per-file-changes/intel_bios.c +(cd per-file-changes/; patch -p1 -R ) < tmp/res.pat + +>per-file-changes/drm_modes.c +spatch -sp_file spatches/getdrmmodefn.cocci inputs/drm_modes.c -U 0 \ + > tmp/drm_modes +./plusplusplus tmp/drm_modes per-file-changes/drm_modes.c +(cd per-file-changes/; patch -p1 -R ) < tmp/drm_modes.pat + +spatch -sp_file spatches/i915_dma.c.cocci inputs/i915_dma.c -U 0 \ + > tmp/i915_dma.c.patch +./plusplusplus tmp/i915_dma.c.patch per-file-changes/i915_dma.c +# This is the only way I can make sure the right file gets patched! +# someone tell me why. It keeps picking the wrong one. +(cd per-file-changes/; patch -p1 -R ) < tmp/i915_dma.c.patch.pat +spatch --in-place -sp_file spatches/fixcalls.cocci per-file-changes/i915_dma.c +#patch -p0 -R < tmp/i915_dma.c.patch.pat + +#echo '#include "video.h"' +>per-file-changes/i915_drv.c +spatch -sp_file spatches/i915_drv.c.cocci inputs/i915_drv.c -U 0 \ + > tmp/i915_drv.c.patch +./plusplusplus tmp/i915_drv.c.patch per-file-changes/i915_drv.c +# This is the only way I can make sure the right file gets patched! +# someone tell me why. It keeps picking the wrong one. +(cd per-file-changes/; patch -p1 -R ) < tmp/i915_drv.c.patch.pat +spatch --in-place -sp_file spatches/fixcalls.cocci per-file-changes/i915_drv.c + +# Finally, a basic spatch sequence! + +spatch --in-place -sp_file \ + spatches/intel_display.c.cocci per-file-changes/intel_display.c \ + > /dev/null + +spatch --in-place -sp_file spatches/i915_drv.cocci \ + per-file-changes/i915_drv.h >/dev/null + +# Now do the common changes to all files. +cp per-file-changes/* final +spatch --in-place -sp_file spatches/ringbuffer.cocci \ + final/intel_ringbuffer.h >/dev/null +spatch --in-place -sp_file spatches/removeinclude.cocci \ + final/intel_display.c > /dev/null +spatch --in-place -sp_file spatches/fixcalls.cocci final/intel_display.c \ + >/dev/null +spatch --in-place -sp_file spatches/ringbuffer.cocci final/drm_dp_helper.h\ + >/dev/null +spatch --in-place -sp_file spatches/removeinclude.cocci final/drm_dp_helper.h\ + >/dev/null +spatch --in-place -sp_file spatches/i915_drv.cocci final/intel_ringbuffer.h\ + >/dev/null +spatch --in-place -sp_file spatches/deldev.cocci final/intel_bios.c \ + final/intel_bios.h final/i915_drv.h final/intel_ringbuffer.h>/dev/null +spatch --in-place -sp_file spatches/fixcalls.cocci final/intel_bios.c \ + >/dev/null +spatch --in-place -sp_file spatches/drm_crtc.cocci final/drm_crtc.h >/dev/null diff --git a/util/i915tool/video.h b/util/i915tool/video.h new file mode 100644 index 0000000..6919830 --- /dev/null +++ b/util/i915tool/video.h @@ -0,0 +1,133 @@ +/* cocci issues ;-( */ +#ifndef VIDEO_H +#define VIDEO_H 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* stuff we can't get coccinelle to do yet */ +#define __iomem +#define __read_mostly +#define __always_unused +#define module_param_named(a, b, c, d) +#define MODULE_PARM_DESC(a, b) +#define DRM_DEBUG_KMS printf +#define CONFIG_DRM_I915_KMS 1 +#define module_init(x); +#define module_exit(x); + +#define MODULE_AUTHOR(x) +#define MODULE_DESCRIPTION(x) +#define MODULE_LICENSE(a) +#define MODULE_DEVICE_TABLE(a, b) + +/* constants that will never change from linux/vga.h */ +/* Legacy VGA regions */ +#define VGA_RSRC_NONE 0x00 +#define VGA_RSRC_LEGACY_IO 0x01 +#define VGA_RSRC_LEGACY_MEM 0x02 +#define VGA_RSRC_LEGACY_MASK (VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM) +/* Non-legacy access */ +#define VGA_RSRC_NORMAL_IO 0x04 +#define VGA_RSRC_NORMAL_MEM 0x08 + + +/* define in pci.h! */ +#include +/* idiocy. how many names to we need for a type? */ +typedef u32 uint32_t; +typedef u64 uint64_t; +/* WTF */ +typedef int bool; +enum {false = 0, true}; + +/* we define our own. The kernel one is too full of stuff. */ +struct mode_config { + int num_fb; + int num_connector; + int num_crtc; + int num_encoder; + int min_width, min_height, max_width, max_height; +}; + +struct drm_device { + struct pci_dev *pdev; + u8 *bios_bin; + struct drm_i915_private *dev_private; + struct mode_config mode_config; +}; + +/* we're willing to define our own here because it's relatively unchanging */ +#define PCI_ANY_ID (~0) + +struct pci_device_id { + u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/ + u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ + u32 class, class_mask; /* (class,subclass,prog-if) triplet */ + unsigned long driver_data; /* Data private to the driver */ +}; + + +/* per the cocinelle people, they can't handle this. + * It also almost never changes */ +#define INTEL_VGA_DEVICE(id, info) { \ + .class = PCI_CLASS_DISPLAY_VGA << 8, \ + .class_mask = 0xff0000, \ + .vendor = 0x8086, \ + .device = id, \ + .subvendor = PCI_ANY_ID, \ + .subdevice = PCI_ANY_ID, \ + .driver_data = (unsigned long) info } + +#define wait_for(condition, time) (sleep(1+time/50) && (!condition)) + + +/* random crap from kernel.h. + * Kernel.h is a catch-all for all kinds of junk and it's + * not worth using coccinelle (yet) to pull it apart. Maybe later. + * And, yes, gcc still does not have nelem! + */ +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) +#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) +#define __ALIGN_MASK(x, mask) __ALIGN_KERNEL_MASK((x), (mask)) +#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a))) +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) + + +/* temporary. */ +void *dmi_check_system(unsigned long); + +#include "final/drm_dp_helper.h" +#include "final/i915_reg.h" +#include "final/i915_drv.h" +#include "final/drm_mode.h" +#include "final/drm_crtc.h" + +unsigned long I915_READ(unsigned long addr); +void I915_WRITE(unsigned long addr, unsigned long val); +u16 I915_READ16(unsigned long addr); +void I915_WRITE16(unsigned long addr, u16 val); +unsigned long msecs(void); +void mdelay(unsigned long ms); + +/* these should be the same. */ +#define POSTING_READ I915_READ +#define POSTING_READ16 I915_READ16 + +void *pci_map_rom(struct pci_dev *dev, size_t *size); +void *pci_unmap_rom(struct pci_dev *dev, void *p); +extern unsigned int i915_lvds_downclock; +extern int i915_vbt_sdvo_panel_type; +unsigned long lvds_do_not_use_alternate_frequency; +#endif /* VIDEO_H */ From gerrit at coreboot.org Sat May 5 15:41:04 2012 From: gerrit at coreboot.org (Patrick Georgi (patrick@georgi-clan.de)) Date: Sat, 5 May 2012 15:41:04 +0200 Subject: [coreboot] New patch to review for coreboot: a683bce Clean up #ifs References: Message-ID: Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1004 -gerrit commit a683bce1f9db7f5fc57daf613572a73d80412cc3 Author: Patrick Georgi Date: Sat May 5 15:29:32 2012 +0200 Clean up #ifs Replace #if CONFIG_FOO==1 with #if CONFIG_FOO: find src -name \*.[ch] -exec sed -i "s,#if[[:space:]]*\(CONFIG_[A-Z0-9_]*\)[[:space:]]*==[[:space:]]*1[[:space:]]*\$,#if \1," {} + Replace #if (CONFIG_FOO==1) with #if CONFIG_FOO: find src -name \*.[ch] -exec sed -i "s,#if[[:space:]]*(\(CONFIG_[A-Z0-9_]*\)[[:space:]]*==[[:space:]]*1)[[:space:]]*\$,#if \1," {} + Replace #if CONFIG_FOO==0 with #if !CONFIG_FOO: find src -name \*.[ch] -exec sed -i "s,#if[[:space:]]*\(CONFIG_[A-Z0-9_]*\)[[:space:]]*==[[:space:]]*0[[:space:]]*\$,#if \!\1," {} + Replace #if (CONFIG_FOO==0) with #if !CONFIG_FOO: find src -name \*.[ch] -exec sed -i "s,#if[[:space:]]*(\(CONFIG_[A-Z0-9_]*\)[[:space:]]*==[[:space:]]*0)[[:space:]]*\$,#if \!\1," {} + Change-Id: Iac6ca7605a5f99885258cf1a9a2473a92de27c42 Signed-off-by: Patrick Georgi --- src/arch/x86/boot/acpi.c | 2 +- src/arch/x86/boot/coreboot_table.c | 2 +- src/arch/x86/boot/tables.c | 6 +- src/arch/x86/include/arch/acpi.h | 2 +- src/arch/x86/include/arch/pci_ops.h | 2 +- src/arch/x86/include/arch/pciconf.h | 2 +- src/arch/x86/include/arch/pirq_routing.h | 4 +- src/arch/x86/include/arch/romcc_io.h | 12 ++-- src/arch/x86/lib/cbfs_and_run.c | 2 +- src/arch/x86/lib/exception.c | 2 +- src/arch/x86/lib/pci_ops_conf1.c | 2 +- src/boot/hardwaremain.c | 4 +- src/cpu/amd/agesa/family10/model_10_init.c | 4 +- src/cpu/amd/agesa/family12/model_12_init.c | 4 +- src/cpu/amd/agesa/family14/model_14_init.c | 6 +- src/cpu/amd/agesa/family15/model_15_init.c | 4 +- src/cpu/amd/car/post_cache_as_ram.c | 12 ++-- src/cpu/amd/dualcore/dualcore.c | 2 +- src/cpu/amd/model_10xxx/init_cpus.c | 10 ++-- src/cpu/amd/model_10xxx/model_10xxx_init.c | 4 +- src/cpu/amd/model_fxx/init_cpus.c | 16 +++--- src/cpu/amd/model_fxx/model_fxx_init.c | 22 ++++---- src/cpu/amd/model_fxx/model_fxx_update_microcode.c | 8 ++-- src/cpu/amd/model_fxx/powernow_acpi.c | 2 +- src/cpu/amd/model_fxx/processor_name.c | 12 ++-- src/cpu/amd/mtrr/amd_mtrr.c | 4 +- src/cpu/intel/hyperthreading/intel_sibling.c | 2 +- src/cpu/x86/lapic/lapic_cpu_init.c | 26 +++++----- src/devices/device.c | 8 ++-- src/devices/hypertransport.c | 6 +- src/devices/pci_device.c | 26 +++++----- src/devices/pci_rom.c | 2 +- src/drivers/ati/ragexl/atyfb.h | 6 +- src/drivers/ati/ragexl/mach64_ct.c | 2 +- src/drivers/ati/ragexl/xlinit.c | 18 +++--- src/include/cpu/amd/model_fxx_rev.h | 4 +- src/include/cpu/x86/lapic.h | 2 +- src/include/delay.h | 2 +- src/include/reset.h | 2 +- src/include/smp/atomic.h | 2 +- src/include/smp/spinlock.h | 2 +- src/include/watchdog.h | 2 +- src/mainboard/advansus/a785e-i/acpi_tables.c | 2 +- src/mainboard/advansus/a785e-i/get_bus_conf.c | 4 +- src/mainboard/advansus/a785e-i/mainboard.c | 4 +- src/mainboard/advansus/a785e-i/mptable.c | 2 +- src/mainboard/advansus/a785e-i/platform_cfg.h | 2 +- src/mainboard/advansus/a785e-i/romstage.c | 4 +- src/mainboard/amd/bimini_fam10/get_bus_conf.c | 4 +- src/mainboard/amd/bimini_fam10/mainboard.c | 4 +- src/mainboard/amd/bimini_fam10/mptable.c | 2 +- src/mainboard/amd/bimini_fam10/romstage.c | 2 +- src/mainboard/amd/dbm690t/get_bus_conf.c | 4 +- src/mainboard/amd/dbm690t/mainboard.c | 4 +- src/mainboard/amd/dbm690t/mptable.c | 2 +- src/mainboard/amd/dbm690t/romstage.c | 2 +- src/mainboard/amd/dinar/mainboard.c | 4 +- src/mainboard/amd/dinar/rd890_cfg.h | 4 +- src/mainboard/amd/dinar/sb700_cfg.h | 2 +- src/mainboard/amd/inagua/mainboard.c | 4 +- src/mainboard/amd/inagua/mptable.c | 2 +- src/mainboard/amd/inagua/platform_cfg.h | 2 +- src/mainboard/amd/mahogany/get_bus_conf.c | 4 +- src/mainboard/amd/mahogany/mainboard.c | 4 +- src/mainboard/amd/mahogany/mptable.c | 2 +- src/mainboard/amd/mahogany/romstage.c | 2 +- src/mainboard/amd/mahogany_fam10/get_bus_conf.c | 4 +- src/mainboard/amd/mahogany_fam10/mainboard.c | 4 +- src/mainboard/amd/mahogany_fam10/mptable.c | 2 +- src/mainboard/amd/mahogany_fam10/romstage.c | 2 +- src/mainboard/amd/persimmon/agesawrapper.c | 2 +- src/mainboard/amd/persimmon/get_bus_conf.c | 4 +- src/mainboard/amd/persimmon/mainboard.c | 6 +- src/mainboard/amd/persimmon/mptable.c | 2 +- src/mainboard/amd/persimmon/platform_cfg.h | 2 +- src/mainboard/amd/persimmon/romstage.c | 6 +- src/mainboard/amd/pistachio/get_bus_conf.c | 4 +- src/mainboard/amd/pistachio/mainboard.c | 4 +- src/mainboard/amd/pistachio/mptable.c | 2 +- src/mainboard/amd/pistachio/romstage.c | 2 +- src/mainboard/amd/serengeti_cheetah/get_bus_conf.c | 4 +- src/mainboard/amd/serengeti_cheetah/mptable.c | 2 +- src/mainboard/amd/serengeti_cheetah/romstage.c | 6 +- .../amd/serengeti_cheetah_fam10/get_bus_conf.c | 2 +- .../amd/serengeti_cheetah_fam10/mptable.c | 2 +- .../amd/serengeti_cheetah_fam10/romstage.c | 2 +- src/mainboard/amd/south_station/mainboard.c | 4 +- src/mainboard/amd/south_station/mptable.c | 2 +- src/mainboard/amd/south_station/platform_cfg.h | 2 +- src/mainboard/amd/tilapia_fam10/get_bus_conf.c | 4 +- src/mainboard/amd/tilapia_fam10/mainboard.c | 4 +- src/mainboard/amd/tilapia_fam10/mptable.c | 2 +- src/mainboard/amd/tilapia_fam10/romstage.c | 2 +- src/mainboard/amd/torpedo/Oem.h | 2 +- src/mainboard/amd/torpedo/mainboard.c | 4 +- src/mainboard/amd/torpedo/mptable.c | 2 +- src/mainboard/amd/torpedo/platform_cfg.h | 6 +- src/mainboard/amd/union_station/mainboard.c | 4 +- src/mainboard/amd/union_station/mptable.c | 2 +- src/mainboard/amd/union_station/platform_cfg.h | 2 +- src/mainboard/arima/hdama/romstage.c | 2 +- src/mainboard/asrock/939a785gmh/get_bus_conf.c | 4 +- src/mainboard/asrock/939a785gmh/mainboard.c | 4 +- src/mainboard/asrock/939a785gmh/mptable.c | 2 +- src/mainboard/asrock/939a785gmh/romstage.c | 2 +- src/mainboard/asrock/e350m1/mainboard.c | 4 +- src/mainboard/asrock/e350m1/mptable.c | 2 +- src/mainboard/asrock/e350m1/platform_cfg.h | 2 +- src/mainboard/asus/a8n_e/get_bus_conf.c | 4 +- src/mainboard/asus/a8n_e/romstage.c | 2 +- src/mainboard/asus/a8v-e_deluxe/romstage.c | 2 +- src/mainboard/asus/a8v-e_se/romstage.c | 2 +- src/mainboard/asus/k8v-x/romstage.c | 2 +- src/mainboard/asus/m2n-e/get_bus_conf.c | 4 +- src/mainboard/asus/m2n-e/romstage.c | 6 +- src/mainboard/asus/m2v-mx_se/mainboard.c | 2 +- src/mainboard/asus/m2v-mx_se/romstage.c | 4 +- src/mainboard/asus/m2v/romstage.c | 4 +- src/mainboard/asus/m4a78-em/get_bus_conf.c | 4 +- src/mainboard/asus/m4a78-em/mainboard.c | 2 +- src/mainboard/asus/m4a78-em/mptable.c | 2 +- src/mainboard/asus/m4a78-em/romstage.c | 2 +- src/mainboard/asus/m4a785-m/get_bus_conf.c | 4 +- src/mainboard/asus/m4a785-m/mainboard.c | 2 +- src/mainboard/asus/m4a785-m/mptable.c | 2 +- src/mainboard/asus/m4a785-m/romstage.c | 2 +- src/mainboard/asus/m5a88-v/acpi_tables.c | 2 +- src/mainboard/asus/m5a88-v/get_bus_conf.c | 4 +- src/mainboard/asus/m5a88-v/mainboard.c | 4 +- src/mainboard/asus/m5a88-v/mptable.c | 2 +- src/mainboard/asus/m5a88-v/platform_cfg.h | 2 +- src/mainboard/asus/m5a88-v/romstage.c | 4 +- src/mainboard/avalue/eax-785e/acpi_tables.c | 2 +- src/mainboard/avalue/eax-785e/get_bus_conf.c | 8 ++-- src/mainboard/avalue/eax-785e/mainboard.c | 4 +- src/mainboard/avalue/eax-785e/mptable.c | 2 +- src/mainboard/avalue/eax-785e/platform_cfg.h | 2 +- src/mainboard/avalue/eax-785e/romstage.c | 4 +- src/mainboard/broadcom/blast/get_bus_conf.c | 4 +- src/mainboard/broadcom/blast/mptable.c | 2 +- src/mainboard/broadcom/blast/romstage.c | 2 +- src/mainboard/emulation/qemu-x86/northbridge.c | 4 +- src/mainboard/getac/p470/romstage.c | 2 +- src/mainboard/gigabyte/ga_2761gxdk/get_bus_conf.c | 4 +- src/mainboard/gigabyte/ga_2761gxdk/romstage.c | 6 +- src/mainboard/gigabyte/m57sli/get_bus_conf.c | 4 +- src/mainboard/gigabyte/m57sli/romstage.c | 6 +- src/mainboard/gigabyte/ma785gm/get_bus_conf.c | 4 +- src/mainboard/gigabyte/ma785gm/mainboard.c | 4 +- src/mainboard/gigabyte/ma785gm/mptable.c | 2 +- src/mainboard/gigabyte/ma785gm/romstage.c | 2 +- src/mainboard/gigabyte/ma785gmt/get_bus_conf.c | 4 +- src/mainboard/gigabyte/ma785gmt/mainboard.c | 4 +- src/mainboard/gigabyte/ma785gmt/mptable.c | 2 +- src/mainboard/gigabyte/ma785gmt/romstage.c | 2 +- src/mainboard/gigabyte/ma78gm/get_bus_conf.c | 4 +- src/mainboard/gigabyte/ma78gm/mainboard.c | 4 +- src/mainboard/gigabyte/ma78gm/mptable.c | 2 +- src/mainboard/gigabyte/ma78gm/romstage.c | 2 +- src/mainboard/hp/dl145_g1/get_bus_conf.c | 4 +- src/mainboard/hp/dl145_g1/romstage.c | 4 +- src/mainboard/hp/dl145_g3/get_bus_conf.c | 4 +- src/mainboard/hp/dl145_g3/mptable.c | 2 +- src/mainboard/hp/dl145_g3/romstage.c | 6 +- src/mainboard/hp/dl165_g6_fam10/get_bus_conf.c | 2 +- src/mainboard/hp/dl165_g6_fam10/mptable.c | 2 +- src/mainboard/hp/dl165_g6_fam10/romstage.c | 2 +- src/mainboard/ibm/e325/romstage.c | 2 +- src/mainboard/ibm/e326/romstage.c | 2 +- src/mainboard/iei/kino-780am2-fam10/get_bus_conf.c | 4 +- src/mainboard/iei/kino-780am2-fam10/mainboard.c | 4 +- src/mainboard/iei/kino-780am2-fam10/mptable.c | 2 +- src/mainboard/iei/kino-780am2-fam10/romstage.c | 2 +- src/mainboard/intel/eagleheights/fadt.c | 2 +- src/mainboard/iwill/dk8_htx/get_bus_conf.c | 4 +- src/mainboard/iwill/dk8_htx/mptable.c | 2 +- src/mainboard/iwill/dk8_htx/romstage.c | 6 +- src/mainboard/iwill/dk8s2/romstage.c | 6 +- src/mainboard/iwill/dk8x/romstage.c | 6 +- src/mainboard/jetway/pa78vm5/get_bus_conf.c | 4 +- src/mainboard/jetway/pa78vm5/mainboard.c | 4 +- src/mainboard/jetway/pa78vm5/mptable.c | 2 +- src/mainboard/jetway/pa78vm5/romstage.c | 2 +- src/mainboard/kontron/kt690/get_bus_conf.c | 4 +- src/mainboard/kontron/kt690/mainboard.c | 4 +- src/mainboard/kontron/kt690/mptable.c | 2 +- src/mainboard/kontron/kt690/romstage.c | 2 +- src/mainboard/msi/ms7135/get_bus_conf.c | 4 +- src/mainboard/msi/ms7135/romstage.c | 2 +- src/mainboard/msi/ms7260/get_bus_conf.c | 4 +- src/mainboard/msi/ms7260/romstage.c | 6 +- src/mainboard/msi/ms9185/get_bus_conf.c | 4 +- src/mainboard/msi/ms9185/mptable.c | 2 +- src/mainboard/msi/ms9185/romstage.c | 2 +- src/mainboard/msi/ms9282/get_bus_conf.c | 4 +- src/mainboard/msi/ms9282/romstage.c | 2 +- src/mainboard/msi/ms9652_fam10/get_bus_conf.c | 4 +- src/mainboard/msi/ms9652_fam10/romstage.c | 2 +- src/mainboard/newisys/khepri/romstage.c | 2 +- src/mainboard/nvidia/l1_2pvv/get_bus_conf.c | 4 +- src/mainboard/nvidia/l1_2pvv/romstage.c | 6 +- src/mainboard/siemens/sitemp_g1p1/acpi_tables.c | 2 +- src/mainboard/siemens/sitemp_g1p1/get_bus_conf.c | 4 +- src/mainboard/siemens/sitemp_g1p1/mainboard.c | 8 ++-- src/mainboard/siemens/sitemp_g1p1/romstage.c | 2 +- src/mainboard/sunw/ultra40/get_bus_conf.c | 4 +- src/mainboard/sunw/ultra40/romstage.c | 2 +- src/mainboard/supermicro/h8dme/get_bus_conf.c | 4 +- src/mainboard/supermicro/h8dme/romstage.c | 6 +- src/mainboard/supermicro/h8dmr/get_bus_conf.c | 4 +- src/mainboard/supermicro/h8dmr/romstage.c | 6 +- .../supermicro/h8dmr_fam10/get_bus_conf.c | 4 +- src/mainboard/supermicro/h8dmr_fam10/romstage.c | 2 +- src/mainboard/supermicro/h8qgi/buildOpts.c | 6 +- src/mainboard/supermicro/h8qgi/mainboard.c | 2 +- src/mainboard/supermicro/h8qgi/rd890_cfg.h | 4 +- src/mainboard/supermicro/h8qgi/sb700_cfg.h | 2 +- .../supermicro/h8qme_fam10/get_bus_conf.c | 4 +- src/mainboard/supermicro/h8qme_fam10/romstage.c | 2 +- .../supermicro/h8scm_fam10/get_bus_conf.c | 4 +- src/mainboard/supermicro/h8scm_fam10/mainboard.c | 2 +- src/mainboard/supermicro/h8scm_fam10/mptable.c | 2 +- src/mainboard/supermicro/h8scm_fam10/romstage.c | 2 +- src/mainboard/technexion/tim5690/get_bus_conf.c | 4 +- src/mainboard/technexion/tim5690/mainboard.c | 4 +- src/mainboard/technexion/tim5690/mptable.c | 2 +- src/mainboard/technexion/tim5690/romstage.c | 2 +- src/mainboard/technexion/tim8690/get_bus_conf.c | 4 +- src/mainboard/technexion/tim8690/mainboard.c | 4 +- src/mainboard/technexion/tim8690/mptable.c | 2 +- src/mainboard/technexion/tim8690/romstage.c | 2 +- src/mainboard/tyan/s2850/mptable.c | 4 +- src/mainboard/tyan/s2850/romstage.c | 2 +- src/mainboard/tyan/s2875/mptable.c | 4 +- src/mainboard/tyan/s2875/romstage.c | 2 +- src/mainboard/tyan/s2880/mptable.c | 4 +- src/mainboard/tyan/s2880/romstage.c | 2 +- src/mainboard/tyan/s2881/get_bus_conf.c | 4 +- src/mainboard/tyan/s2881/romstage.c | 2 +- src/mainboard/tyan/s2882/mptable.c | 4 +- src/mainboard/tyan/s2882/romstage.c | 2 +- src/mainboard/tyan/s2885/get_bus_conf.c | 4 +- src/mainboard/tyan/s2885/romstage.c | 2 +- src/mainboard/tyan/s2891/get_bus_conf.c | 4 +- src/mainboard/tyan/s2891/romstage.c | 2 +- src/mainboard/tyan/s2892/get_bus_conf.c | 4 +- src/mainboard/tyan/s2892/romstage.c | 2 +- src/mainboard/tyan/s2895/get_bus_conf.c | 4 +- src/mainboard/tyan/s2912/get_bus_conf.c | 4 +- src/mainboard/tyan/s2912/romstage.c | 6 +- src/mainboard/tyan/s2912_fam10/get_bus_conf.c | 4 +- src/mainboard/tyan/s2912_fam10/romstage.c | 2 +- src/mainboard/tyan/s4880/mptable.c | 4 +- src/mainboard/tyan/s4880/romstage.c | 2 +- src/mainboard/tyan/s4882/mptable.c | 4 +- src/mainboard/tyan/s4882/romstage.c | 2 +- src/mainboard/via/epia-n/mainboard.c | 2 +- src/northbridge/amd/agesa/family10/northbridge.c | 38 +++++++------- src/northbridge/amd/agesa/family12/northbridge.c | 24 ++++---- src/northbridge/amd/agesa/family14/northbridge.c | 24 ++++---- src/northbridge/amd/agesa/family15/northbridge.c | 24 ++++---- src/northbridge/amd/amdfam10/amdfam10.h | 8 ++-- src/northbridge/amd/amdfam10/conf.c | 10 ++-- src/northbridge/amd/amdfam10/debug.c | 2 +- src/northbridge/amd/amdfam10/early_ht.c | 4 +- src/northbridge/amd/amdfam10/northbridge.c | 54 ++++++++++---------- src/northbridge/amd/amdfam10/reset_test.c | 2 +- src/northbridge/amd/amdht/ht_wrapper.c | 2 +- src/northbridge/amd/amdk8/amdk8.h | 2 +- src/northbridge/amd/amdk8/coherent_ht.c | 24 ++++---- src/northbridge/amd/amdk8/debug.c | 2 +- src/northbridge/amd/amdk8/incoherent_ht.c | 12 ++-- src/northbridge/amd/amdk8/misc_control.c | 2 +- src/northbridge/amd/amdk8/northbridge.c | 42 ++++++++-------- src/northbridge/amd/amdk8/raminit.c | 4 +- src/northbridge/amd/amdk8/raminit_f.c | 10 ++-- src/northbridge/amd/amdk8/raminit_f_dqs.c | 22 ++++---- src/northbridge/amd/amdmct/wrappers/mcti_d.c | 10 ++-- src/northbridge/amd/gx1/northbridge.c | 4 +- src/northbridge/amd/gx2/northbridge.c | 4 +- src/northbridge/amd/lx/northbridge.c | 4 +- src/northbridge/intel/e7501/northbridge.c | 4 +- src/northbridge/intel/e7505/northbridge.c | 4 +- src/northbridge/intel/e7520/northbridge.c | 4 +- src/northbridge/intel/e7525/northbridge.c | 4 +- src/northbridge/intel/i3100/northbridge.c | 4 +- src/northbridge/intel/i3100/raminit.c | 2 +- src/northbridge/intel/i440bx/northbridge.c | 4 +- src/northbridge/intel/i440lx/northbridge.c | 4 +- src/northbridge/intel/i82810/northbridge.c | 4 +- src/northbridge/intel/i82830/northbridge.c | 4 +- src/northbridge/intel/i855/northbridge.c | 4 +- src/northbridge/intel/i945/northbridge.c | 4 +- src/northbridge/intel/sandybridge/northbridge.c | 4 +- src/northbridge/intel/sch/northbridge.c | 4 +- src/northbridge/rdc/r8610/northbridge.c | 4 +- src/northbridge/via/cn400/northbridge.c | 4 +- src/northbridge/via/cn700/northbridge.c | 4 +- src/northbridge/via/cx700/northbridge.c | 4 +- src/northbridge/via/vt8601/northbridge.c | 4 +- src/northbridge/via/vt8623/northbridge.c | 4 +- src/northbridge/via/vx800/examples/chipset_init.c | 4 +- src/southbridge/amd/amd8111/acpi.c | 4 +- src/southbridge/amd/cimx/sb700/bootblock.c | 2 +- src/southbridge/amd/cimx/sb700/early.c | 2 +- src/southbridge/amd/cimx/sb700/sb_cimx.h | 2 +- src/southbridge/amd/cimx/sb800/SBPLATFORM.h | 2 +- src/southbridge/amd/cimx/sb800/cfg.c | 4 +- src/southbridge/amd/cimx/sb800/early.c | 4 +- src/southbridge/amd/cimx/sb800/late.c | 4 +- src/southbridge/amd/cimx/sb800/sb_cimx.h | 2 +- src/southbridge/amd/cimx/sb900/bootblock.c | 2 +- src/southbridge/amd/cs5530/vga.c | 4 +- src/southbridge/amd/rs690/ht.c | 6 +- src/southbridge/amd/rs780/early_setup.c | 2 +- src/southbridge/amd/rs780/gfx.c | 6 +- src/southbridge/amd/rs780/rs780.c | 2 +- src/southbridge/amd/sb600/ide.c | 2 +- src/southbridge/amd/sb700/early_setup.c | 2 +- src/southbridge/amd/sb700/ide.c | 2 +- src/southbridge/amd/sb700/lpc.c | 2 +- src/southbridge/amd/sb700/sb700.h | 2 +- src/southbridge/amd/sb800/early_setup.c | 2 +- src/southbridge/amd/sb800/ide.c | 2 +- src/southbridge/broadcom/bcm5780/nic.c | 2 +- src/southbridge/intel/i82371eb/smbus.c | 4 +- src/southbridge/nvidia/ck804/early_setup.c | 2 +- src/southbridge/nvidia/ck804/early_setup_car.c | 2 +- src/southbridge/nvidia/ck804/ide.c | 2 +- src/southbridge/nvidia/ck804/nic.c | 2 +- src/southbridge/nvidia/mcp55/ide.c | 2 +- src/southbridge/nvidia/mcp55/nic.c | 2 +- src/southbridge/nvidia/mcp55/smbus.c | 4 +- src/southbridge/sis/sis966/ide.c | 2 +- src/southbridge/via/vt8237r/early_smbus.c | 2 +- src/southbridge/via/vt8237r/lpc.c | 2 +- src/superio/via/vt1211/vt1211.c | 2 +- 337 files changed, 729 insertions(+), 729 deletions(-) diff --git a/src/arch/x86/boot/acpi.c b/src/arch/x86/boot/acpi.c index 010ba9f..6932208 100644 --- a/src/arch/x86/boot/acpi.c +++ b/src/arch/x86/boot/acpi.c @@ -550,7 +550,7 @@ void acpi_write_hest(acpi_hest_t *hest) header->checksum = acpi_checksum((void *)hest, header->length); } -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME void suspend_resume(void) { void *wake_vec; diff --git a/src/arch/x86/boot/coreboot_table.c b/src/arch/x86/boot/coreboot_table.c index 9ceca45..5b5834a 100644 --- a/src/arch/x86/boot/coreboot_table.c +++ b/src/arch/x86/boot/coreboot_table.c @@ -324,7 +324,7 @@ static void lb_strings(struct lb_header *header) } -#if CONFIG_WRITE_HIGH_TABLES == 1 +#if CONFIG_WRITE_HIGH_TABLES static struct lb_forward *lb_forward(struct lb_header *header, struct lb_header *next_header) { struct lb_record *rec; diff --git a/src/arch/x86/boot/tables.c b/src/arch/x86/boot/tables.c index 4fefc7d..72aa979 100644 --- a/src/arch/x86/boot/tables.c +++ b/src/arch/x86/boot/tables.c @@ -71,7 +71,7 @@ struct lb_memory *write_tables(void) low_table_start = 0; low_table_end = 0x500; -#if CONFIG_GENERATE_PIRQ_TABLE == 1 +#if CONFIG_GENERATE_PIRQ_TABLE #define MAX_PIRQ_TABLE_SIZE (4 * 1024) post_code(0x9a); @@ -97,7 +97,7 @@ struct lb_memory *write_tables(void) #endif -#if CONFIG_GENERATE_MP_TABLE == 1 +#if CONFIG_GENERATE_MP_TABLE #define MAX_MP_TABLE_SIZE (4 * 1024) post_code(0x9b); @@ -120,7 +120,7 @@ struct lb_memory *write_tables(void) } #endif /* CONFIG_GENERATE_MP_TABLE */ -#if CONFIG_GENERATE_ACPI_TABLES == 1 +#if CONFIG_GENERATE_ACPI_TABLES #define MAX_ACPI_SIZE (45 * 1024) post_code(0x9c); diff --git a/src/arch/x86/include/arch/acpi.h b/src/arch/x86/include/arch/acpi.h index be62008..9f790cc 100644 --- a/src/arch/x86/include/arch/acpi.h +++ b/src/arch/x86/include/arch/acpi.h @@ -27,7 +27,7 @@ #ifndef __ASM_ACPI_H #define __ASM_ACPI_H -#if CONFIG_GENERATE_ACPI_TABLES==1 +#if CONFIG_GENERATE_ACPI_TABLES #include diff --git a/src/arch/x86/include/arch/pci_ops.h b/src/arch/x86/include/arch/pci_ops.h index 9c4e029..955ccd3 100644 --- a/src/arch/x86/include/arch/pci_ops.h +++ b/src/arch/x86/include/arch/pci_ops.h @@ -4,7 +4,7 @@ extern const struct pci_bus_operations pci_cf8_conf1; extern const struct pci_bus_operations pci_cf8_conf2; -#if CONFIG_MMCONF_SUPPORT==1 +#if CONFIG_MMCONF_SUPPORT extern const struct pci_bus_operations pci_ops_mmconf; #endif diff --git a/src/arch/x86/include/arch/pciconf.h b/src/arch/x86/include/arch/pciconf.h index a356935..df21817 100644 --- a/src/arch/x86/include/arch/pciconf.h +++ b/src/arch/x86/include/arch/pciconf.h @@ -5,7 +5,7 @@ #define PCI_CONF_REG_INDEX 0xcf8 #define PCI_CONF_REG_DATA 0xcfc -#if CONFIG_PCI_IO_CFG_EXT == 0 +#if !CONFIG_PCI_IO_CFG_EXT #define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where)) #else #define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where & 0xff) | ((where & 0xf00)<<16) ) diff --git a/src/arch/x86/include/arch/pirq_routing.h b/src/arch/x86/include/arch/pirq_routing.h index 0b65eac..08ba535 100644 --- a/src/arch/x86/include/arch/pirq_routing.h +++ b/src/arch/x86/include/arch/pirq_routing.h @@ -1,7 +1,7 @@ #ifndef ARCH_PIRQ_ROUTING_H #define ARCH_PIRQ_ROUTING_H -#if CONFIG_GENERATE_PIRQ_TABLE==1 +#if CONFIG_GENERATE_PIRQ_TABLE #include #define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) @@ -39,7 +39,7 @@ extern const struct irq_routing_table intel_irq_routing_table; unsigned long copy_pirq_routing_table(unsigned long start); unsigned long write_pirq_routing_table(unsigned long start); -#if CONFIG_PIRQ_ROUTE==1 +#if CONFIG_PIRQ_ROUTE void pirq_routing_irqs(unsigned long start); void pirq_assign_irqs(const unsigned char pIntAtoD[4]); #else diff --git a/src/arch/x86/include/arch/romcc_io.h b/src/arch/x86/include/arch/romcc_io.h index b0c8f65..37fb7ab 100644 --- a/src/arch/x86/include/arch/romcc_io.h +++ b/src/arch/x86/include/arch/romcc_io.h @@ -65,7 +65,7 @@ typedef unsigned device_t; /* pci and pci_mmio need to have different ways to ha static inline __attribute__((always_inline)) uint8_t pci_io_read_config8(device_t dev, unsigned where) { unsigned addr; -#if CONFIG_PCI_IO_CFG_EXT == 0 +#if !CONFIG_PCI_IO_CFG_EXT addr = (dev>>4) | where; #else addr = (dev>>4) | (where & 0xff) | ((where & 0xf00)<<16); //seg == 0 @@ -94,7 +94,7 @@ static inline __attribute__((always_inline)) uint8_t pci_read_config8(device_t d static inline __attribute__((always_inline)) uint16_t pci_io_read_config16(device_t dev, unsigned where) { unsigned addr; -#if CONFIG_PCI_IO_CFG_EXT == 0 +#if !CONFIG_PCI_IO_CFG_EXT addr = (dev>>4) | where; #else addr = (dev>>4) | (where & 0xff) | ((where & 0xf00)<<16); @@ -125,7 +125,7 @@ static inline __attribute__((always_inline)) uint16_t pci_read_config16(device_t static inline __attribute__((always_inline)) uint32_t pci_io_read_config32(device_t dev, unsigned where) { unsigned addr; -#if CONFIG_PCI_IO_CFG_EXT == 0 +#if !CONFIG_PCI_IO_CFG_EXT addr = (dev>>4) | where; #else addr = (dev>>4) | (where & 0xff) | ((where & 0xf00)<<16); @@ -155,7 +155,7 @@ static inline __attribute__((always_inline)) uint32_t pci_read_config32(device_t static inline __attribute__((always_inline)) void pci_io_write_config8(device_t dev, unsigned where, uint8_t value) { unsigned addr; -#if CONFIG_PCI_IO_CFG_EXT == 0 +#if !CONFIG_PCI_IO_CFG_EXT addr = (dev>>4) | where; #else addr = (dev>>4) | (where & 0xff) | ((where & 0xf00)<<16); @@ -186,7 +186,7 @@ static inline __attribute__((always_inline)) void pci_write_config8(device_t dev static inline __attribute__((always_inline)) void pci_io_write_config16(device_t dev, unsigned where, uint16_t value) { unsigned addr; -#if CONFIG_PCI_IO_CFG_EXT == 0 +#if !CONFIG_PCI_IO_CFG_EXT addr = (dev>>4) | where; #else addr = (dev>>4) | (where & 0xff) | ((where & 0xf00)<<16); @@ -217,7 +217,7 @@ static inline __attribute__((always_inline)) void pci_write_config16(device_t de static inline __attribute__((always_inline)) void pci_io_write_config32(device_t dev, unsigned where, uint32_t value) { unsigned addr; -#if CONFIG_PCI_IO_CFG_EXT == 0 +#if !CONFIG_PCI_IO_CFG_EXT addr = (dev>>4) | where; #else addr = (dev>>4) | (where & 0xff) | ((where & 0xf00)<<16); diff --git a/src/arch/x86/lib/cbfs_and_run.c b/src/arch/x86/lib/cbfs_and_run.c index 53f06ee..62b2789 100644 --- a/src/arch/x86/lib/cbfs_and_run.c +++ b/src/arch/x86/lib/cbfs_and_run.c @@ -50,7 +50,7 @@ void __attribute__((regparm(0))) copy_and_run(unsigned cpu_reset) cbfs_and_run_core(CONFIG_CBFS_PREFIX "/coreboot_ram", cpu_reset); } -#if CONFIG_AP_CODE_IN_CAR == 1 +#if CONFIG_AP_CODE_IN_CAR void __attribute__((regparm(0))) copy_and_run_ap_code_in_car(unsigned ret_addr) { cbfs_and_run_core(CONFIG_CBFS_PREFIX "/coreboot_ap", ret_addr); diff --git a/src/arch/x86/lib/exception.c b/src/arch/x86/lib/exception.c index 91525d5..4721bc8 100644 --- a/src/arch/x86/lib/exception.c +++ b/src/arch/x86/lib/exception.c @@ -365,7 +365,7 @@ void x86_exception(struct eregs *info); void x86_exception(struct eregs *info) { -#if CONFIG_GDB_STUB == 1 +#if CONFIG_GDB_STUB int signo; memcpy(gdb_stub_registers, info, 8*sizeof(uint32_t)); gdb_stub_registers[PC] = info->eip; diff --git a/src/arch/x86/lib/pci_ops_conf1.c b/src/arch/x86/lib/pci_ops_conf1.c index 266a9cc..77df4b3 100644 --- a/src/arch/x86/lib/pci_ops_conf1.c +++ b/src/arch/x86/lib/pci_ops_conf1.c @@ -8,7 +8,7 @@ * Functions for accessing PCI configuration space with type 1 accesses */ -#if CONFIG_PCI_IO_CFG_EXT == 0 +#if !CONFIG_PCI_IO_CFG_EXT #define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | \ (devfn << 8) | (where & ~3)) #else diff --git a/src/boot/hardwaremain.c b/src/boot/hardwaremain.c index 532135f..f0853ec 100644 --- a/src/boot/hardwaremain.c +++ b/src/boot/hardwaremain.c @@ -113,13 +113,13 @@ void hardwaremain(int boot_complete) timestamps[5] = rdtsc(); #endif -#if CONFIG_WRITE_HIGH_TABLES == 1 +#if CONFIG_WRITE_HIGH_TABLES cbmem_initialize(); #if CONFIG_CONSOLE_CBMEM cbmemc_reinit(); #endif #endif -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME suspend_resume(); post_code(0x8a); #endif diff --git a/src/cpu/amd/agesa/family10/model_10_init.c b/src/cpu/amd/agesa/family10/model_10_init.c index 8c1cfad..c216a81 100644 --- a/src/cpu/amd/agesa/family10/model_10_init.c +++ b/src/cpu/amd/agesa/family10/model_10_init.c @@ -61,7 +61,7 @@ static void model_10_init(device_t dev) u8 i; msr_t msr; -#if CONFIG_LOGICAL_CPUS == 1 +#if CONFIG_LOGICAL_CPUS u32 siblings; #endif @@ -88,7 +88,7 @@ static void model_10_init(device_t dev) // init_processor_name(); -#if CONFIG_LOGICAL_CPUS == 1 +#if CONFIG_LOGICAL_CPUS siblings = cpuid_ecx(0x80000008) & 0xff; if (siblings > 0) { diff --git a/src/cpu/amd/agesa/family12/model_12_init.c b/src/cpu/amd/agesa/family12/model_12_init.c index 3a12db3..4ed477c 100644 --- a/src/cpu/amd/agesa/family12/model_12_init.c +++ b/src/cpu/amd/agesa/family12/model_12_init.c @@ -63,7 +63,7 @@ static void model_12_init(device_t dev) u8 i; msr_t msr; -#if CONFIG_LOGICAL_CPUS == 1 +#if CONFIG_LOGICAL_CPUS u32 siblings; #endif @@ -94,7 +94,7 @@ static void model_12_init(device_t dev) // init_processor_name(); -#if CONFIG_LOGICAL_CPUS == 1 +#if CONFIG_LOGICAL_CPUS siblings = cpuid_ecx(0x80000008) & 0xff; if (siblings > 0) { diff --git a/src/cpu/amd/agesa/family14/model_14_init.c b/src/cpu/amd/agesa/family14/model_14_init.c index d90695a..9cc36e2 100644 --- a/src/cpu/amd/agesa/family14/model_14_init.c +++ b/src/cpu/amd/agesa/family14/model_14_init.c @@ -61,7 +61,7 @@ static void model_14_init(device_t dev) { u32 i; msr_t msr; -#if CONFIG_LOGICAL_CPUS == 1 +#if CONFIG_LOGICAL_CPUS u32 siblings; #endif printk(BIOS_DEBUG, "Model 14 Init.\n"); @@ -94,7 +94,7 @@ static void model_14_init(device_t dev) msr.lo |= SYSCFG_MSR_MtrrFixDramEn; wrmsr(SYSCFG_MSR, msr); -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME if (acpi_slp_type == 3) restore_mtrr(); #endif @@ -112,7 +112,7 @@ static void model_14_init(device_t dev) /* Enable the local cpu apics */ setup_lapic(); -#if CONFIG_LOGICAL_CPUS == 1 +#if CONFIG_LOGICAL_CPUS siblings = cpuid_ecx(0x80000008) & 0xff; if (siblings > 0) { diff --git a/src/cpu/amd/agesa/family15/model_15_init.c b/src/cpu/amd/agesa/family15/model_15_init.c index d100338..39775ba 100644 --- a/src/cpu/amd/agesa/family15/model_15_init.c +++ b/src/cpu/amd/agesa/family15/model_15_init.c @@ -59,7 +59,7 @@ static void model_15_init(device_t dev) u8 i; msr_t msr; int msrno; -#if CONFIG_LOGICAL_CPUS == 1 +#if CONFIG_LOGICAL_CPUS u32 siblings; #endif @@ -95,7 +95,7 @@ static void model_15_init(device_t dev) /* Enable the local cpu apics */ setup_lapic(); -#if CONFIG_LOGICAL_CPUS == 1 +#if CONFIG_LOGICAL_CPUS siblings = cpuid_ecx(0x80000008) & 0xff; if (siblings > 0) { diff --git a/src/cpu/amd/car/post_cache_as_ram.c b/src/cpu/amd/car/post_cache_as_ram.c index 270c542..d99be48 100644 --- a/src/cpu/amd/car/post_cache_as_ram.c +++ b/src/cpu/amd/car/post_cache_as_ram.c @@ -29,7 +29,7 @@ static void inline __attribute__((always_inline)) memcopy(void *dest, const voi : "memory", "cc"); } -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME static inline void *backup_resume(void) { unsigned long high_ram_base; @@ -83,7 +83,7 @@ static void vErrata343(void) static void post_cache_as_ram(void) { -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME void *resume_backup_memory; #endif #if 1 @@ -108,7 +108,7 @@ static void post_cache_as_ram(void) #error "You need to set CONFIG_RAMTOP greater than 1M" #endif -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME resume_backup_memory = backup_resume(); #endif @@ -142,7 +142,7 @@ static void post_cache_as_ram(void) set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK); enable_cache(); -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME /* now copy the rest of the area, using the WB method because we already run normal RAM */ if (resume_backup_memory) { @@ -154,7 +154,7 @@ static void post_cache_as_ram(void) print_debug("Clearing initial memory region: "); -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME /* clear only coreboot used region of memory. Note: this may break ECC enabled boards */ memset((void*) CONFIG_RAMBASE, 0, (CONFIG_RAMTOP) - CONFIG_RAMBASE - CONFIG_DCACHE_RAM_SIZE); #else @@ -164,7 +164,7 @@ static void post_cache_as_ram(void) set_sysinfo_in_ram(1); // So other core0 could start to train mem -#if CONFIG_MEM_TRAIN_SEQ == 1 +#if CONFIG_MEM_TRAIN_SEQ // struct sys_info *sysinfox = ((CONFIG_RAMTOP) - CONFIG_DCACHE_RAM_GLOBAL_VAR_SIZE); // wait for ap memory to trained diff --git a/src/cpu/amd/dualcore/dualcore.c b/src/cpu/amd/dualcore/dualcore.c index 9c2583f..69ce56a 100644 --- a/src/cpu/amd/dualcore/dualcore.c +++ b/src/cpu/amd/dualcore/dualcore.c @@ -17,7 +17,7 @@ static inline unsigned get_core_num_in_bsp(unsigned nodeid) static inline uint8_t set_apicid_cpuid_lo(void) { -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT if(is_cpu_pre_e0()) return 0; // pre_e0 can not be set #endif diff --git a/src/cpu/amd/model_10xxx/init_cpus.c b/src/cpu/amd/model_10xxx/init_cpus.c index e0538af..edc016a 100644 --- a/src/cpu/amd/model_10xxx/init_cpus.c +++ b/src/cpu/amd/model_10xxx/init_cpus.c @@ -33,7 +33,7 @@ static void prep_fid_change(void); static void init_fidvid_stage2(u32 apicid, u32 nodeid); void cpuSetAMDMSR(void); -#if CONFIG_PCI_IO_CFG_EXT == 1 +#if CONFIG_PCI_IO_CFG_EXT static void set_EnableCf8ExtCfg(void) { // set the NB_CFG[46]=1; @@ -112,7 +112,7 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t process_ap, j * (nb_cfg_54 ? 1 : 64); #if (CONFIG_ENABLE_APIC_EXT_ID == 1) && (CONFIG_APIC_ID_OFFSET > 0) -#if CONFIG_LIFT_BSP_APIC_ID == 0 +#if !CONFIG_LIFT_BSP_APIC_ID if ((i != 0) || (j != 0)) /* except bsp */ #endif ap_apicid += CONFIG_APIC_ID_OFFSET; @@ -267,7 +267,7 @@ static u32 init_cpus(u32 cpu_init_detectedx) if (id.coreid == 0) { set_apicid_cpuid_lo(); /* only set it on core0 */ set_EnableCf8ExtCfg(); /* only set it on core0 */ -#if (CONFIG_ENABLE_APIC_EXT_ID == 1) +#if CONFIG_ENABLE_APIC_EXT_ID enable_apic_ext_id(id.nodeid); #endif } @@ -277,7 +277,7 @@ static u32 init_cpus(u32 cpu_init_detectedx) #if (CONFIG_ENABLE_APIC_EXT_ID == 1) && (CONFIG_APIC_ID_OFFSET > 0) u32 initial_apicid = get_initial_apicid(); -#if CONFIG_LIFT_BSP_APIC_ID == 0 +#if !CONFIG_LIFT_BSP_APIC_ID if (initial_apicid != 0) // other than bsp #endif { @@ -289,7 +289,7 @@ static u32 init_cpus(u32 cpu_init_detectedx) lapic_write(LAPIC_ID, dword); } -#if CONFIG_LIFT_BSP_APIC_ID == 1 +#if CONFIG_LIFT_BSP_APIC_ID bsp_apicid += CONFIG_APIC_ID_OFFSET; #endif diff --git a/src/cpu/amd/model_10xxx/model_10xxx_init.c b/src/cpu/amd/model_10xxx/model_10xxx_init.c index cf11135..27f56c2 100644 --- a/src/cpu/amd/model_10xxx/model_10xxx_init.c +++ b/src/cpu/amd/model_10xxx/model_10xxx_init.c @@ -63,7 +63,7 @@ static void model_10xxx_init(device_t dev) u8 i; msr_t msr; struct node_core_id id; -#if CONFIG_LOGICAL_CPUS == 1 +#if CONFIG_LOGICAL_CPUS u32 siblings; #endif @@ -92,7 +92,7 @@ static void model_10xxx_init(device_t dev) /* Set the processor name string */ init_processor_name(); -#if CONFIG_LOGICAL_CPUS == 1 +#if CONFIG_LOGICAL_CPUS siblings = cpuid_ecx(0x80000008) & 0xff; if (siblings > 0) { diff --git a/src/cpu/amd/model_fxx/init_cpus.c b/src/cpu/amd/model_fxx/init_cpus.c index 0036277..ed1c830 100644 --- a/src/cpu/amd/model_fxx/init_cpus.c +++ b/src/cpu/amd/model_fxx/init_cpus.c @@ -40,7 +40,7 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t process_ap, 3); if (nb_cfg_54) { if (j == 0) { // if it is single core, we need to increase siblings for apic calculation -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT e0_later_single_core = is_e0_later_in_bsp(i); // single core #else e0_later_single_core = is_cpu_f0_in_bsp(i); // We can read cpuid(1) from Func3 @@ -72,8 +72,8 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t process_ap, i * (nb_cfg_54 ? (siblings + 1) : 1) + j * (nb_cfg_54 ? 1 : 8); -#if (CONFIG_ENABLE_APIC_EXT_ID == 1) -#if CONFIG_LIFT_BSP_APIC_ID == 0 +#if CONFIG_ENABLE_APIC_EXT_ID +#if !CONFIG_LIFT_BSP_APIC_ID if ((i != 0) || (j != 0)) /* except bsp */ #endif ap_apicid += CONFIG_APIC_ID_OFFSET; @@ -215,7 +215,7 @@ static u32 init_cpus(u32 cpu_init_detectedx) core0 is done at first --- use wait_all_core0_started */ if (id.coreid == 0) { set_apicid_cpuid_lo(); /* only set it on core0 */ -#if (CONFIG_ENABLE_APIC_EXT_ID == 1) +#if CONFIG_ENABLE_APIC_EXT_ID enable_apic_ext_id(id.nodeid); #endif } @@ -223,10 +223,10 @@ static u32 init_cpus(u32 cpu_init_detectedx) enable_lapic(); // init_timer(); // We need TMICT to pass msg for FID/VID change -#if (CONFIG_ENABLE_APIC_EXT_ID == 1) +#if CONFIG_ENABLE_APIC_EXT_ID u32 initial_apicid = get_initial_apicid(); -#if CONFIG_LIFT_BSP_APIC_ID == 0 +#if !CONFIG_LIFT_BSP_APIC_ID if (initial_apicid != 0) // other than bsp #endif { @@ -238,7 +238,7 @@ static u32 init_cpus(u32 cpu_init_detectedx) lapic_write(LAPIC_ID, dword); } -#if CONFIG_LIFT_BSP_APIC_ID == 1 +#if CONFIG_LIFT_BSP_APIC_ID bsp_apicid += CONFIG_APIC_ID_OFFSET; #endif @@ -293,7 +293,7 @@ static u32 init_cpus(u32 cpu_init_detectedx) } lapic_write(LAPIC_MSG_REG, (apicid << 24) | 0x44); // bsp can not check it before stop_this_cpu set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK); -#if CONFIG_MEM_TRAIN_SEQ == 1 +#if CONFIG_MEM_TRAIN_SEQ train_ram_on_node(id.nodeid, id.coreid, sysinfo, (unsigned)STOP_CAR_AND_CPU); #endif diff --git a/src/cpu/amd/model_fxx/model_fxx_init.c b/src/cpu/amd/model_fxx/model_fxx_init.c index ae5429d..7084606 100644 --- a/src/cpu/amd/model_fxx/model_fxx_init.c +++ b/src/cpu/amd/model_fxx/model_fxx_init.c @@ -31,7 +31,7 @@ #if CONFIG_WAIT_BEFORE_CPUS_INIT void cpus_ready_for_init(void) { -#if CONFIG_MEM_TRAIN_SEQ == 1 +#if CONFIG_MEM_TRAIN_SEQ struct sys_info *sysinfox = (struct sys_info *)((CONFIG_RAMTOP) - CONFIG_DCACHE_RAM_GLOBAL_VAR_SIZE); // wait for ap memory to trained wait_all_core0_mem_trained(sysinfox); @@ -39,7 +39,7 @@ void cpus_ready_for_init(void) } #endif -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT int is_e0_later_in_bsp(int nodeid) { uint32_t val; @@ -67,7 +67,7 @@ int is_e0_later_in_bsp(int nodeid) } #endif -#if CONFIG_K8_REV_F_SUPPORT == 1 +#if CONFIG_K8_REV_F_SUPPORT int is_cpu_f0_in_bsp(int nodeid) { uint32_t dword; @@ -298,7 +298,7 @@ static void init_ecc_memory(unsigned node_id) #if CONFIG_HW_MEM_HOLE_SIZEK != 0 unsigned long hole_startk = 0; -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT if (!is_cpu_pre_e0()) { #endif @@ -307,7 +307,7 @@ static void init_ecc_memory(unsigned node_id) if (val & 1) { hole_startk = ((val & (0xff << 24)) >> 10); } -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT } #endif #endif @@ -370,7 +370,7 @@ static void init_ecc_memory(unsigned node_id) static inline void k8_errata(void) { msr_t msr; -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT if (is_cpu_pre_c0()) { /* Erratum 63... */ msr = rdmsr(HWCR_MSR); @@ -437,14 +437,14 @@ static inline void k8_errata(void) #endif -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT /* I can't touch this msr on early buggy cpus */ if (!is_cpu_pre_b3()) #endif { msr = rdmsr(NB_CFG_MSR); -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT if (!is_cpu_pre_c0() && is_cpu_pre_d0()) { /* D0 later don't need it */ /* Erratum 86 Disable data masking on C0 and @@ -523,7 +523,7 @@ static void model_fxx_init(device_t dev) /* Enable the local cpu apics */ setup_lapic(); -#if CONFIG_LOGICAL_CPUS == 1 +#if CONFIG_LOGICAL_CPUS u32 siblings = cpuid_ecx(0x80000008) & 0xff; if (siblings > 0) { @@ -570,7 +570,7 @@ static struct device_operations cpu_dev_ops = { }; static struct cpu_device_id cpu_table[] = { -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT { X86_VENDOR_AMD, 0xf40 }, /* SH-B0 (socket 754) */ { X86_VENDOR_AMD, 0xf50 }, /* SH-B0 (socket 940) */ { X86_VENDOR_AMD, 0xf51 }, /* SH-B3 (socket 940) */ @@ -612,7 +612,7 @@ static struct cpu_device_id cpu_table[] = { { X86_VENDOR_AMD, 0x30ff2 }, /* E4 ? */ #endif -#if CONFIG_K8_REV_F_SUPPORT == 1 +#if CONFIG_K8_REV_F_SUPPORT /* * AMD F0 support. * diff --git a/src/cpu/amd/model_fxx/model_fxx_update_microcode.c b/src/cpu/amd/model_fxx/model_fxx_update_microcode.c index 5cc0fba..69769c9 100644 --- a/src/cpu/amd/model_fxx/model_fxx_update_microcode.c +++ b/src/cpu/amd/model_fxx/model_fxx_update_microcode.c @@ -27,13 +27,13 @@ static uint8_t microcode_updates[] __attribute__ ((aligned(16))) = { -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT #include "microcode_rev_c.h" #include "microcode_rev_d.h" #include "microcode_rev_e.h" #endif -#if CONFIG_K8_REV_F_SUPPORT == 1 +#if CONFIG_K8_REV_F_SUPPORT // #include "microcode_rev_f.h" #endif /* Dummy terminator */ @@ -45,7 +45,7 @@ static uint8_t microcode_updates[] __attribute__ ((aligned(16))) = { static unsigned get_equivalent_processor_rev_id(unsigned orig_id) { static unsigned id_mapping_table[] = { - #if CONFIG_K8_REV_F_SUPPORT == 0 + #if !CONFIG_K8_REV_F_SUPPORT 0x0f48, 0x0048, 0x0f58, 0x0048, @@ -68,7 +68,7 @@ static unsigned get_equivalent_processor_rev_id(unsigned orig_id) { 0x20fb1, 0x0210, #endif - #if CONFIG_K8_REV_F_SUPPORT == 1 + #if CONFIG_K8_REV_F_SUPPORT #endif diff --git a/src/cpu/amd/model_fxx/powernow_acpi.c b/src/cpu/amd/model_fxx/powernow_acpi.c index 83d34f1..81b1067 100644 --- a/src/cpu/amd/model_fxx/powernow_acpi.c +++ b/src/cpu/amd/model_fxx/powernow_acpi.c @@ -632,7 +632,7 @@ static int pstates_algorithm(u32 pcontrol_blk, u8 plen, u8 onlyBSP) return 0; } -#if CONFIG_MAX_PHYSICAL_CPUS==1 +#if CONFIG_MAX_PHYSICAL_CPUS /* IRT 80us RVO = 50mV PLL_LOCK_TIME 2us, MVS 25mv, VST 100us */ control = (3 << 30) | (2 << 28) | (2 << 20) | (0 << 18) | (5 << 11); #else diff --git a/src/cpu/amd/model_fxx/processor_name.c b/src/cpu/amd/model_fxx/processor_name.c index 3f3d973..6f45b0f 100644 --- a/src/cpu/amd/model_fxx/processor_name.c +++ b/src/cpu/amd/model_fxx/processor_name.c @@ -42,7 +42,7 @@ * your mainboard will not be posted on the AMD Recommended Motherboard Website */ -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT static const char *processor_names[]={ /* 0x00 */ "AMD Engineering Sample", /* 0x01-0x03 */ NULL, NULL, NULL, @@ -113,7 +113,7 @@ static inline void wrmsr_amd(unsigned index, msr_t msr) int init_processor_name(void) { -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT u32 EightBitBrandId; #endif u32 BrandId; @@ -127,7 +127,7 @@ int init_processor_name(void) char program_string[48]; unsigned int *program_values = (unsigned int *)program_string; -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT /* Find out which CPU brand it is */ EightBitBrandId = cpuid_ebx(0x00000001) & 0xff; BrandId = cpuid_ebx(0x80000001) & 0xffff; @@ -151,7 +151,7 @@ int init_processor_name(void) processor_name_string = "AMD Processor model unknown"; #endif -#if CONFIG_K8_REV_F_SUPPORT == 1 +#if CONFIG_K8_REV_F_SUPPORT u32 Socket; u32 CmpCap; u32 PwrLmt; @@ -407,7 +407,7 @@ int init_processor_name(void) for (i=0; i<47; i++) { // 48 -1 if(program_string[i] == program_string[i+1]) { switch (program_string[i]) { -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT case 'X': ModelNumber = 22+ NN; break; case 'Y': ModelNumber = 38 + (2*NN); break; case 'Z': @@ -416,7 +416,7 @@ int init_processor_name(void) case 'V': ModelNumber = 9 + NN; break; #endif -#if CONFIG_K8_REV_F_SUPPORT == 1 +#if CONFIG_K8_REV_F_SUPPORT case 'R': ModelNumber = NN - 1; break; case 'P': ModelNumber = 26 + NN; break; case 'T': ModelNumber = 15 + (CmpCap * 10) + NN; break; diff --git a/src/cpu/amd/mtrr/amd_mtrr.c b/src/cpu/amd/mtrr/amd_mtrr.c index 54a70e2..5c48cfd 100644 --- a/src/cpu/amd/mtrr/amd_mtrr.c +++ b/src/cpu/amd/mtrr/amd_mtrr.c @@ -6,7 +6,7 @@ #include #include -#if CONFIG_GFXUMA == 1 +#if CONFIG_GFXUMA extern uint64_t uma_memory_size; #endif @@ -163,7 +163,7 @@ void amd_setup_mtrrs(void) * has been deducted from the size of memory below 4GB. * When setting TOM, include UMA DRAM */ - #if CONFIG_GFXUMA == 1 + #if CONFIG_GFXUMA msr.lo += uma_memory_size; #endif wrmsr(TOP_MEM, msr); diff --git a/src/cpu/intel/hyperthreading/intel_sibling.c b/src/cpu/intel/hyperthreading/intel_sibling.c index e988664..2d2e105 100644 --- a/src/cpu/intel/hyperthreading/intel_sibling.c +++ b/src/cpu/intel/hyperthreading/intel_sibling.c @@ -7,7 +7,7 @@ #include #include -#if CONFIG_SERIAL_CPU_INIT==0 +#if !CONFIG_SERIAL_CPU_INIT #error Intel hyper-threading requires serialized cpu init #endif diff --git a/src/cpu/x86/lapic/lapic_cpu_init.c b/src/cpu/x86/lapic/lapic_cpu_init.c index f823981..e491d46 100644 --- a/src/cpu/x86/lapic/lapic_cpu_init.c +++ b/src/cpu/x86/lapic/lapic_cpu_init.c @@ -16,7 +16,7 @@ #include #include -#if CONFIG_SMP == 1 +#if CONFIG_SMP /* This is a lot more paranoid now, since Linux can NOT handle * being told there is a CPU when none exists. So any errors * will return 0, meaning no CPU. @@ -29,7 +29,7 @@ static unsigned long get_valid_start_eip(unsigned long orig_start_eip) return (unsigned long)orig_start_eip & 0xffff; // 16 bit to avoid 0xa0000 } -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME char *lowmem_backup; char *lowmem_backup_ptr; int lowmem_backup_size; @@ -49,7 +49,7 @@ static void copy_secondary_start_to_1m_below(void) start_eip = get_valid_start_eip((unsigned long)_secondary_start); code_size = (unsigned long)_secondary_start_end - (unsigned long)_secondary_start; -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME /* need to save it for RAM resume */ lowmem_backup_size = code_size; lowmem_backup = malloc(code_size); @@ -277,7 +277,7 @@ int start_cpu(device_t cpu) return result; } -#if CONFIG_AP_IN_SIPI_WAIT == 1 +#if CONFIG_AP_IN_SIPI_WAIT /** * Sending INIT IPI to self is equivalent of asserting #INIT with a bit of delay. @@ -384,7 +384,7 @@ static __inline__ __attribute__((always_inline)) void writecr4(unsigned long Dat void secondary_cpu_init(void) { atomic_inc(&active_cpus); -#if CONFIG_SERIAL_CPU_INIT == 1 +#if CONFIG_SERIAL_CPU_INIT spin_lock(&start_cpu_lock); #endif @@ -399,7 +399,7 @@ void secondary_cpu_init(void) writecr4(cr4_val); #endif cpu_initialize(); -#if CONFIG_SERIAL_CPU_INIT == 1 +#if CONFIG_SERIAL_CPU_INIT spin_unlock(&start_cpu_lock); #endif @@ -417,7 +417,7 @@ static void start_other_cpus(struct bus *cpu_bus, device_t bsp_cpu) if (cpu->path.type != DEVICE_PATH_APIC) { continue; } - #if CONFIG_SERIAL_CPU_INIT == 0 + #if !CONFIG_SERIAL_CPU_INIT if(cpu==bsp_cpu) { continue; } @@ -436,7 +436,7 @@ static void start_other_cpus(struct bus *cpu_bus, device_t bsp_cpu) printk(BIOS_ERR, "CPU 0x%02x would not start!\n", cpu->path.apic.apic_id); } -#if CONFIG_SERIAL_CPU_INIT == 1 +#if CONFIG_SERIAL_CPU_INIT udelay(10); #endif } @@ -502,7 +502,7 @@ void initialize_cpus(struct bus *cpu_bus) /* Find the device structure for the boot cpu */ info->cpu = alloc_find_dev(cpu_bus, &cpu_path); -#if CONFIG_SMP == 1 +#if CONFIG_SMP copy_secondary_start_to_1m_below(); // why here? In case some day we can start core1 in amd_sibling_init #endif @@ -512,8 +512,8 @@ void initialize_cpus(struct bus *cpu_bus) cpus_ready_for_init(); -#if CONFIG_SMP == 1 - #if CONFIG_SERIAL_CPU_INIT == 0 +#if CONFIG_SMP + #if !CONFIG_SERIAL_CPU_INIT /* start all aps at first, so we can init ECC all together */ start_other_cpus(cpu_bus, info->cpu); #endif @@ -522,8 +522,8 @@ void initialize_cpus(struct bus *cpu_bus) /* Initialize the bootstrap processor */ cpu_initialize(); -#if CONFIG_SMP == 1 - #if CONFIG_SERIAL_CPU_INIT == 1 +#if CONFIG_SMP + #if CONFIG_SERIAL_CPU_INIT start_other_cpus(cpu_bus, info->cpu); #endif diff --git a/src/devices/device.c b/src/devices/device.c index 0e9c39e..ebac1a0 100644 --- a/src/devices/device.c +++ b/src/devices/device.c @@ -536,7 +536,7 @@ static void allocate_resources(struct bus *bus, struct resource *bridge, } } -#if CONFIG_PCI_64BIT_PREF_MEM == 1 +#if CONFIG_PCI_64BIT_PREF_MEM #define MEM_MASK (IORESOURCE_PREFETCH | IORESOURCE_MEM) #else #define MEM_MASK (IORESOURCE_MEM) @@ -676,7 +676,7 @@ static void avoid_fixed_resources(struct device *dev) } } -#if CONFIG_VGA_BRIDGE_SETUP == 1 +#if CONFIG_VGA_BRIDGE_SETUP device_t vga_pri = 0; static void set_vga_bridge_bits(void) { @@ -725,7 +725,7 @@ static void set_vga_bridge_bits(void) if (!vga) vga = vga_first; -#if CONFIG_ONBOARD_VGA_IS_PRIMARY == 1 +#if CONFIG_ONBOARD_VGA_IS_PRIMARY if (vga_onboard) /* Will use onboard VGA as primary. */ #else if (!vga) /* Will use last add-on adapter as primary. */ @@ -935,7 +935,7 @@ void dev_configure(void) struct device *root; struct device *child; -#if CONFIG_VGA_BRIDGE_SETUP == 1 +#if CONFIG_VGA_BRIDGE_SETUP set_vga_bridge_bits(); #endif diff --git a/src/devices/hypertransport.c b/src/devices/hypertransport.c index 9267291..420054e 100644 --- a/src/devices/hypertransport.c +++ b/src/devices/hypertransport.c @@ -103,9 +103,9 @@ static unsigned ht_read_freq_cap(device_t dev, unsigned pos) /* AMD K8 unsupported 1GHz? */ if ((dev->vendor == PCI_VENDOR_ID_AMD) && (dev->device == 0x1100)) { -#if CONFIG_K8_HT_FREQ_1G_SUPPORT == 1 +#if CONFIG_K8_HT_FREQ_1G_SUPPORT -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT /* Only e0 later suupport 1GHz HT. */ if (is_cpu_pre_e0()) freq_cap &= ~(1 << HT_FREQ_1000Mhz); @@ -351,7 +351,7 @@ static void ht_collapse_early_enumeration(struct bus *bus, } while ((ctrl & (1 << 5)) == 0); /* Actually, only for one HT device HT chain, and unitid is 0. */ -#if CONFIG_HT_CHAIN_UNITID_BASE == 0 +#if !CONFIG_HT_CHAIN_UNITID_BASE if (offset_unitid) return; #endif diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c index c9af7c4..7fa7384 100644 --- a/src/devices/pci_device.c +++ b/src/devices/pci_device.c @@ -33,22 +33,22 @@ #include #include #include -#if CONFIG_HYPERTRANSPORT_PLUGIN_SUPPORT == 1 +#if CONFIG_HYPERTRANSPORT_PLUGIN_SUPPORT #include #endif -#if CONFIG_PCIX_PLUGIN_SUPPORT == 1 +#if CONFIG_PCIX_PLUGIN_SUPPORT #include #endif -#if CONFIG_PCIEXP_PLUGIN_SUPPORT == 1 +#if CONFIG_PCIEXP_PLUGIN_SUPPORT #include #endif -#if CONFIG_AGP_PLUGIN_SUPPORT == 1 +#if CONFIG_AGP_PLUGIN_SUPPORT #include #endif -#if CONFIG_CARDBUS_PLUGIN_SUPPORT == 1 +#if CONFIG_CARDBUS_PLUGIN_SUPPORT #include #endif -#if CONFIG_PC80_SYSTEM == 1 +#if CONFIG_PC80_SYSTEM #include #endif #if CONFIG_HAVE_ACPI_RESUME && !CONFIG_S3_VGA_ROM_RUN @@ -748,17 +748,17 @@ static struct device_operations *get_pci_bridge_ops(device_t dev) { unsigned int pos; -#if CONFIG_PCIX_PLUGIN_SUPPORT == 1 +#if CONFIG_PCIX_PLUGIN_SUPPORT pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (pos) { printk(BIOS_DEBUG, "%s subordinate bus PCI-X\n", dev_path(dev)); return &default_pcix_ops_bus; } #endif -#if CONFIG_AGP_PLUGIN_SUPPORT == 1 +#if CONFIG_AGP_PLUGIN_SUPPORT /* How do I detect a PCI to AGP bridge? */ #endif -#if CONFIG_HYPERTRANSPORT_PLUGIN_SUPPORT == 1 +#if CONFIG_HYPERTRANSPORT_PLUGIN_SUPPORT pos = 0; while ((pos = pci_find_next_capability(dev, PCI_CAP_ID_HT, pos))) { u16 flags; @@ -771,7 +771,7 @@ static struct device_operations *get_pci_bridge_ops(device_t dev) } } #endif -#if CONFIG_PCIEXP_PLUGIN_SUPPORT == 1 +#if CONFIG_PCIEXP_PLUGIN_SUPPORT pos = pci_find_capability(dev, PCI_CAP_ID_PCIE); if (pos) { u16 flags; @@ -860,7 +860,7 @@ static void set_pci_ops(struct device *dev) goto bad; dev->ops = get_pci_bridge_ops(dev); break; -#if CONFIG_CARDBUS_PLUGIN_SUPPORT == 1 +#if CONFIG_CARDBUS_PLUGIN_SUPPORT case PCI_HEADER_TYPE_CARDBUS: dev->ops = &default_cardbus_ops_bus; break; @@ -1256,7 +1256,7 @@ unsigned int pci_domain_scan_bus(device_t dev, unsigned int max) return max; } -#if CONFIG_PC80_SYSTEM == 1 +#if CONFIG_PC80_SYSTEM /** * Assign IRQ numbers. * @@ -1305,7 +1305,7 @@ void pci_assign_irqs(unsigned bus, unsigned slot, printk(BIOS_DEBUG, " Readback = %d\n", irq); #endif -#if CONFIG_PC80_SYSTEM == 1 +#if CONFIG_PC80_SYSTEM /* Change to level triggered. */ i8259_configure_irq_trigger(pIntAtoD[line - 1], IRQ_LEVEL_TRIGGERED); diff --git a/src/devices/pci_rom.c b/src/devices/pci_rom.c index e7933eb..fe67515 100644 --- a/src/devices/pci_rom.c +++ b/src/devices/pci_rom.c @@ -151,7 +151,7 @@ struct rom_header *pci_rom_load(struct device *dev, * devices have a mismatch between the hardware and the ROM. */ if (PCI_CLASS_DISPLAY_VGA == (dev->class >> 8)) { -#if CONFIG_MULTIPLE_VGA_ADAPTERS == 0 +#if !CONFIG_MULTIPLE_VGA_ADAPTERS extern device_t vga_pri; /* Primary VGA device (device.c). */ if (dev != vga_pri) return NULL; /* Only one VGA supported. */ #endif diff --git a/src/drivers/ati/ragexl/atyfb.h b/src/drivers/ati/ragexl/atyfb.h index 99a87b3..557ead7 100644 --- a/src/drivers/ati/ragexl/atyfb.h +++ b/src/drivers/ati/ragexl/atyfb.h @@ -8,7 +8,7 @@ #define max(x,y) (x>=y)?x:y -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT /* * Elements of the hardware specific atyfb_par structure */ @@ -73,7 +73,7 @@ union aty_pll { * The hardware parameters for each card */ struct atyfb_par { -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT struct crtc crtc; #endif union aty_pll pll; @@ -97,7 +97,7 @@ struct aty_cursor { }; #endif struct fb_info_aty { -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT #if PLL_CRTC_DECODE==1 struct fb_info fb_info; #endif diff --git a/src/drivers/ati/ragexl/mach64_ct.c b/src/drivers/ati/ragexl/mach64_ct.c index b34be82..9b45f2a 100644 --- a/src/drivers/ati/ragexl/mach64_ct.c +++ b/src/drivers/ati/ragexl/mach64_ct.c @@ -284,7 +284,7 @@ int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per, aty_calc_pll_ct(info, &pll->ct); return 0; } -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT #if PLL_CRTC_DECODE==1 u32 aty_pll_ct_to_var(const struct fb_info_aty *info, const union aty_pll *pll) diff --git a/src/drivers/ati/ragexl/xlinit.c b/src/drivers/ati/ragexl/xlinit.c index 747b343..36a0619 100644 --- a/src/drivers/ati/ragexl/xlinit.c +++ b/src/drivers/ati/ragexl/xlinit.c @@ -28,7 +28,7 @@ // Hence do only remove this if you fix the code. #define CONFIG_CONSOLE_BTEXT 0 -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT #define PLL_CRTC_DECODE 0 #define SUPPORT_8_BPP_ABOVE 0 @@ -393,7 +393,7 @@ static char m64n_xl_33[] = "3D RAGE (XL PCI-33MHz)"; static char m64n_xl_66[] = "3D RAGE (XL PCI-66MHz)"; -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT static void aty_set_crtc(const struct fb_info_aty *info, const struct crtc *crtc); static int aty_var_to_crtc(const struct fb_info_aty *info, @@ -455,7 +455,7 @@ static struct { /* 3D RAGE XL PCI-33/BGA */ { 0x4752, 0x4752, 0x00, 0x00, m64n_xl_33, 230, 83, 63, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_XL_DLL | M64F_MFB_TIMES_4 }, }; -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT static void aty_calc_mem_refresh(struct fb_info_aty *info, u16 id, int xclk) { int i, size; @@ -502,7 +502,7 @@ static void ati_ragexl_init(device_t dev) #endif int pll, mclk, xclk; -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT #if 0 int gtb_memsize, k; @@ -532,7 +532,7 @@ static void ati_ragexl_init(device_t dev) res = res->next; } -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT info->frame_buffer = res->base; #endif /* CONFIG_CONSOLE_BTEXT */ @@ -548,7 +548,7 @@ static void ati_ragexl_init(device_t dev) #endif -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0); #endif @@ -581,7 +581,7 @@ found: mclk = 63; } #endif -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT aty_calc_mem_refresh(info, type, xclk); #endif /* CONFIG_CONSOLE_BTEXT */ @@ -596,7 +596,7 @@ found: atyfb_xl_init(info); -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07); @@ -803,7 +803,7 @@ found: } -#if CONFIG_CONSOLE_BTEXT==1 +#if CONFIG_CONSOLE_BTEXT static int atyfb_decode_var(const struct fb_var_screeninfo *var, struct atyfb_par *par, diff --git a/src/include/cpu/amd/model_fxx_rev.h b/src/include/cpu/amd/model_fxx_rev.h index 56381e3..1e85596 100644 --- a/src/include/cpu/amd/model_fxx_rev.h +++ b/src/include/cpu/amd/model_fxx_rev.h @@ -2,7 +2,7 @@ int init_processor_name(void); -#if CONFIG_K8_REV_F_SUPPORT == 0 +#if !CONFIG_K8_REV_F_SUPPORT static inline int is_cpu_rev_a0(void) { return (cpuid_eax(1) & 0xfffef) == 0x0f00; @@ -79,7 +79,7 @@ int is_e0_later_in_bsp(int nodeid); //defined model_fxx_init.c #endif -#if CONFIG_K8_REV_F_SUPPORT == 1 +#if CONFIG_K8_REV_F_SUPPORT //AMD_F0_SUPPORT static inline int is_cpu_pre_f0(void) { diff --git a/src/include/cpu/x86/lapic.h b/src/include/cpu/x86/lapic.h index 2215ec7..078f2a7 100644 --- a/src/include/cpu/x86/lapic.h +++ b/src/include/cpu/x86/lapic.h @@ -147,7 +147,7 @@ static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue) void setup_lapic(void); -#if CONFIG_SMP == 1 +#if CONFIG_SMP struct device; int start_cpu(struct device *cpu); #endif /* CONFIG_SMP */ diff --git a/src/include/delay.h b/src/include/delay.h index 5d0dc01..0333879 100644 --- a/src/include/delay.h +++ b/src/include/delay.h @@ -3,7 +3,7 @@ #if !defined( __ROMCC__) -#if CONFIG_HAVE_INIT_TIMER == 1 +#if CONFIG_HAVE_INIT_TIMER void init_timer(void); #else #define init_timer() do{} while(0) diff --git a/src/include/reset.h b/src/include/reset.h index 3d72a8c..79bf6d5 100644 --- a/src/include/reset.h +++ b/src/include/reset.h @@ -4,7 +4,7 @@ #if !defined( __ROMCC__ ) /* ROMCC can't do function prototypes... */ -#if CONFIG_HAVE_HARD_RESET == 1 +#if CONFIG_HAVE_HARD_RESET void hard_reset(void); #else #define hard_reset() do {} while(0) diff --git a/src/include/smp/atomic.h b/src/include/smp/atomic.h index 8da08a2..44be4c5 100644 --- a/src/include/smp/atomic.h +++ b/src/include/smp/atomic.h @@ -1,7 +1,7 @@ #ifndef SMP_ATOMIC_H #define SMP_ATOMIC_H -#if CONFIG_SMP == 1 +#if CONFIG_SMP #include #else diff --git a/src/include/smp/spinlock.h b/src/include/smp/spinlock.h index 1b0b4fd..87298b1 100644 --- a/src/include/smp/spinlock.h +++ b/src/include/smp/spinlock.h @@ -1,7 +1,7 @@ #ifndef SMP_SPINLOCK_H #define SMP_SPINLOCK_H -#if CONFIG_SMP == 1 +#if CONFIG_SMP #include #else /* !CONFIG_SMP */ diff --git a/src/include/watchdog.h b/src/include/watchdog.h index 98d6d51..d626737 100644 --- a/src/include/watchdog.h +++ b/src/include/watchdog.h @@ -1,7 +1,7 @@ #ifndef WATCHDOG_H #define WATCHDOG_H -#if CONFIG_USE_WATCHDOG_ON_BOOT == 1 +#if CONFIG_USE_WATCHDOG_ON_BOOT void watchdog_off(void); #else #define watchdog_off() diff --git a/src/mainboard/advansus/a785e-i/acpi_tables.c b/src/mainboard/advansus/a785e-i/acpi_tables.c index 9642bb4..fa93842 100644 --- a/src/mainboard/advansus/a785e-i/acpi_tables.c +++ b/src/mainboard/advansus/a785e-i/acpi_tables.c @@ -236,7 +236,7 @@ unsigned long write_acpi_tables(unsigned long start) acpi_create_facs(facs); /* FDAT */ -#if CONFIG_BOARD_HAS_FADT == 1 +#if CONFIG_BOARD_HAS_FADT current = ALIGN(current, 8); printk(BIOS_DEBUG, "ACPI: * FADT at %lx\n", current); fadt = (acpi_fadt_t *) current; diff --git a/src/mainboard/advansus/a785e-i/get_bus_conf.c b/src/mainboard/advansus/a785e-i/get_bus_conf.c index 5c21e09..fcf0bd9 100644 --- a/src/mainboard/advansus/a785e-i/get_bus_conf.c +++ b/src/mainboard/advansus/a785e-i/get_bus_conf.c @@ -23,7 +23,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS #include #endif #include @@ -141,7 +141,7 @@ void get_bus_conf(void) /* I/O APICs: APIC ID Version State Address */ bus_isa = 10; -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS apicid_base = get_apicid_base(1); #else apicid_base = CONFIG_MAX_PHYSICAL_CPUS; diff --git a/src/mainboard/advansus/a785e-i/mainboard.c b/src/mainboard/advansus/a785e-i/mainboard.c index ff2d395..afa82f3 100644 --- a/src/mainboard/advansus/a785e-i/mainboard.c +++ b/src/mainboard/advansus/a785e-i/mainboard.c @@ -84,7 +84,7 @@ static void a785e_i_enable(device_t dev) printk(BIOS_INFO, "Mainboard A785E-I Enable. dev=0x%p\n", dev); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; /* TOP_MEM: the top of DRAM below 4G */ @@ -133,7 +133,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/advansus/a785e-i/mptable.c b/src/mainboard/advansus/a785e-i/mptable.c index 8643320..818d4be 100644 --- a/src/mainboard/advansus/a785e-i/mptable.c +++ b/src/mainboard/advansus/a785e-i/mptable.c @@ -79,7 +79,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb800, (pin)) #else diff --git a/src/mainboard/advansus/a785e-i/platform_cfg.h b/src/mainboard/advansus/a785e-i/platform_cfg.h index 5fd49d6..98e2c94 100644 --- a/src/mainboard/advansus/a785e-i/platform_cfg.h +++ b/src/mainboard/advansus/a785e-i/platform_cfg.h @@ -36,7 +36,7 @@ * bigger than 1M you have to set the ROM size outside CIMx module and * before AGESA module get call. */ -#if CONFIG_COREBOOT_ROMSIZE_KB_1024 == 1 +#if CONFIG_COREBOOT_ROMSIZE_KB_1024 #define BIOS_SIZE BIOS_SIZE_1M #elif CONFIG_COREBOOT_ROMSIZE_KB_2048 == 1 #define BIOS_SIZE BIOS_SIZE_2M diff --git a/src/mainboard/advansus/a785e-i/romstage.c b/src/mainboard/advansus/a785e-i/romstage.c index 3a33b5f..dcc3ba5 100644 --- a/src/mainboard/advansus/a785e-i/romstage.c +++ b/src/mainboard/advansus/a785e-i/romstage.c @@ -160,7 +160,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) */ wait_all_core0_started(); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS /* Core0 on each node is configured. Now setup any additional cores. */ printk(BIOS_DEBUG, "start_other_cores()\n"); start_other_cores(); @@ -173,7 +173,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) /* run _early_setup before soft-reset. */ rs780_early_setup(); -#if CONFIG_SET_FIDVID == 1 +#if CONFIG_SET_FIDVID msr = rdmsr(0xc0010071); printk(BIOS_DEBUG, "\nBegin FIDVID MSR 0xc0010071 0x%08x 0x%08x \n", msr.hi, msr.lo); post_code(0x39); diff --git a/src/mainboard/amd/bimini_fam10/get_bus_conf.c b/src/mainboard/amd/bimini_fam10/get_bus_conf.c index e53aef5..41a2fe7 100644 --- a/src/mainboard/amd/bimini_fam10/get_bus_conf.c +++ b/src/mainboard/amd/bimini_fam10/get_bus_conf.c @@ -23,7 +23,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS #include #endif #include @@ -138,7 +138,7 @@ void get_bus_conf(void) /* I/O APICs: APIC ID Version State Address */ bus_isa = 10; -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS apicid_base = get_apicid_base(1); #else apicid_base = CONFIG_MAX_PHYSICAL_CPUS; diff --git a/src/mainboard/amd/bimini_fam10/mainboard.c b/src/mainboard/amd/bimini_fam10/mainboard.c index 1fd0eeb..241d905 100644 --- a/src/mainboard/amd/bimini_fam10/mainboard.c +++ b/src/mainboard/amd/bimini_fam10/mainboard.c @@ -134,7 +134,7 @@ static void bimini_enable(device_t dev) printk(BIOS_INFO, "Mainboard BIMINI Enable. dev=0x%p\n", dev); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; /* TOP_MEM: the top of DRAM below 4G */ @@ -184,7 +184,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/amd/bimini_fam10/mptable.c b/src/mainboard/amd/bimini_fam10/mptable.c index ae81411..ec60b35 100644 --- a/src/mainboard/amd/bimini_fam10/mptable.c +++ b/src/mainboard/amd/bimini_fam10/mptable.c @@ -83,7 +83,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb800, (pin)) #else diff --git a/src/mainboard/amd/bimini_fam10/romstage.c b/src/mainboard/amd/bimini_fam10/romstage.c index 732e033..5980ca2 100644 --- a/src/mainboard/amd/bimini_fam10/romstage.c +++ b/src/mainboard/amd/bimini_fam10/romstage.c @@ -151,7 +151,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) */ wait_all_core0_started(); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS /* Core0 on each node is configured. Now setup any additional cores. */ printk(BIOS_DEBUG, "start_other_cores()\n"); start_other_cores(); diff --git a/src/mainboard/amd/dbm690t/get_bus_conf.c b/src/mainboard/amd/dbm690t/get_bus_conf.c index 2b0fca7..d4152a1 100644 --- a/src/mainboard/amd/dbm690t/get_bus_conf.c +++ b/src/mainboard/amd/dbm690t/get_bus_conf.c @@ -23,7 +23,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS #include #endif @@ -107,7 +107,7 @@ void get_bus_conf(void) } /* I/O APICs: APIC ID Version State Address */ -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS apicid_base = get_apicid_base(1); #else apicid_base = CONFIG_MAX_PHYSICAL_CPUS; diff --git a/src/mainboard/amd/dbm690t/mainboard.c b/src/mainboard/amd/dbm690t/mainboard.c index 2f54bfd..8841291 100644 --- a/src/mainboard/amd/dbm690t/mainboard.c +++ b/src/mainboard/amd/dbm690t/mainboard.c @@ -187,7 +187,7 @@ static void dbm690t_enable(device_t dev) { printk(BIOS_INFO, "Mainboard DBM690T Enable. dev=0x%p\n", dev); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; /* TOP_MEM: the top of DRAM below 4G */ @@ -238,7 +238,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_base=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, diff --git a/src/mainboard/amd/dbm690t/mptable.c b/src/mainboard/amd/dbm690t/mptable.c index cf98ae3..f34918f 100644 --- a/src/mainboard/amd/dbm690t/mptable.c +++ b/src/mainboard/amd/dbm690t/mptable.c @@ -100,7 +100,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb600, (pin)) #else diff --git a/src/mainboard/amd/dbm690t/romstage.c b/src/mainboard/amd/dbm690t/romstage.c index 66637a8..459aa47 100644 --- a/src/mainboard/amd/dbm690t/romstage.c +++ b/src/mainboard/amd/dbm690t/romstage.c @@ -102,7 +102,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) setup_coherent_ht_domain(); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS /* It is said that we should start core1 after all core0 launched */ wait_all_core0_started(); start_other_cores(); diff --git a/src/mainboard/amd/dinar/mainboard.c b/src/mainboard/amd/dinar/mainboard.c index 9d10390..360e1df 100644 --- a/src/mainboard/amd/dinar/mainboard.c +++ b/src/mainboard/amd/dinar/mainboard.c @@ -75,7 +75,7 @@ uint64_t uma_memory_base, uma_memory_size; static void dinar_enable(device_t dev) { printk(BIOS_INFO, "Mainboard Dinar Enable. dev=0x%p\n", dev); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; uint32_t sys_mem; @@ -124,7 +124,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/amd/dinar/rd890_cfg.h b/src/mainboard/amd/dinar/rd890_cfg.h index a4f4e1a..aaab1f3 100644 --- a/src/mainboard/amd/dinar/rd890_cfg.h +++ b/src/mainboard/amd/dinar/rd890_cfg.h @@ -32,10 +32,10 @@ * [12..15] - Sublink (1..2), If NB connected to full link than Sublink should be set to 0. */ #ifndef DEFAULT_HT_PATH -#if CONFIG_CPU_AMD_AGESA_FAMILY10 == 1 +#if CONFIG_CPU_AMD_AGESA_FAMILY10 #define DEFAULT_HT_PATH {0x0, 0x3} #endif -#if CONFIG_CPU_AMD_AGESA_FAMILY15 == 1 +#if CONFIG_CPU_AMD_AGESA_FAMILY15 #define DEFAULT_HT_PATH {0x0, 0x1} #endif #endif diff --git a/src/mainboard/amd/dinar/sb700_cfg.h b/src/mainboard/amd/dinar/sb700_cfg.h index b405f0e..038e7e7 100644 --- a/src/mainboard/amd/dinar/sb700_cfg.h +++ b/src/mainboard/amd/dinar/sb700_cfg.h @@ -40,7 +40,7 @@ * before AGESA module get call. */ #ifndef BIOS_SIZE -#if CONFIG_COREBOOT_ROMSIZE_KB_1024 == 1 +#if CONFIG_COREBOOT_ROMSIZE_KB_1024 #define BIOS_SIZE BIOS_SIZE_1M #elif CONFIG_COREBOOT_ROMSIZE_KB_2048 == 1 #define BIOS_SIZE BIOS_SIZE_2M diff --git a/src/mainboard/amd/inagua/mainboard.c b/src/mainboard/amd/inagua/mainboard.c index 17c985d..d35b175 100644 --- a/src/mainboard/amd/inagua/mainboard.c +++ b/src/mainboard/amd/inagua/mainboard.c @@ -80,7 +80,7 @@ static void inagua_enable(device_t dev) { printk(BIOS_INFO, "Mainboard " CONFIG_MAINBOARD_PART_NUMBER " Enable.\n"); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; uint32_t sys_mem; @@ -128,7 +128,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/amd/inagua/mptable.c b/src/mainboard/amd/inagua/mptable.c index b5a507f..393eb9e 100644 --- a/src/mainboard/amd/inagua/mptable.c +++ b/src/mainboard/amd/inagua/mptable.c @@ -87,7 +87,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb800, (pin)) #else diff --git a/src/mainboard/amd/inagua/platform_cfg.h b/src/mainboard/amd/inagua/platform_cfg.h index 2a3342c..dd0251f 100644 --- a/src/mainboard/amd/inagua/platform_cfg.h +++ b/src/mainboard/amd/inagua/platform_cfg.h @@ -37,7 +37,7 @@ * before AGESA module get call. */ #ifndef BIOS_SIZE -#if CONFIG_COREBOOT_ROMSIZE_KB_1024 == 1 +#if CONFIG_COREBOOT_ROMSIZE_KB_1024 #define BIOS_SIZE BIOS_SIZE_1M #elif CONFIG_COREBOOT_ROMSIZE_KB_2048 == 1 #define BIOS_SIZE BIOS_SIZE_2M diff --git a/src/mainboard/amd/mahogany/get_bus_conf.c b/src/mainboard/amd/mahogany/get_bus_conf.c index bed7606..149e163 100644 --- a/src/mainboard/amd/mahogany/get_bus_conf.c +++ b/src/mainboard/amd/mahogany/get_bus_conf.c @@ -23,7 +23,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS #include #endif @@ -107,7 +107,7 @@ void get_bus_conf(void) } /* I/O APICs: APIC ID Version State Address */ -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS apicid_base = get_apicid_base(1); #else apicid_base = CONFIG_MAX_PHYSICAL_CPUS; diff --git a/src/mainboard/amd/mahogany/mainboard.c b/src/mainboard/amd/mahogany/mainboard.c index 0ccef10..989070c 100644 --- a/src/mainboard/amd/mahogany/mainboard.c +++ b/src/mainboard/amd/mahogany/mainboard.c @@ -105,7 +105,7 @@ static void mahogany_enable(device_t dev) { printk(BIOS_INFO, "Mainboard MAHOGANY Enable. dev=0x%p\n", dev); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; /* TOP_MEM: the top of DRAM below 4G */ @@ -154,7 +154,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/amd/mahogany/mptable.c b/src/mainboard/amd/mahogany/mptable.c index dabd2ed..376e043 100644 --- a/src/mainboard/amd/mahogany/mptable.c +++ b/src/mainboard/amd/mahogany/mptable.c @@ -101,7 +101,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb700, (pin)) #else diff --git a/src/mainboard/amd/mahogany/romstage.c b/src/mainboard/amd/mahogany/romstage.c index 104652a..9d913e9 100644 --- a/src/mainboard/amd/mahogany/romstage.c +++ b/src/mainboard/amd/mahogany/romstage.c @@ -102,7 +102,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) setup_coherent_ht_domain(); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS /* It is said that we should start core1 after all core0 launched */ wait_all_core0_started(); start_other_cores(); diff --git a/src/mainboard/amd/mahogany_fam10/get_bus_conf.c b/src/mainboard/amd/mahogany_fam10/get_bus_conf.c index b169775..563a87e 100644 --- a/src/mainboard/amd/mahogany_fam10/get_bus_conf.c +++ b/src/mainboard/amd/mahogany_fam10/get_bus_conf.c @@ -23,7 +23,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS #include #endif @@ -107,7 +107,7 @@ void get_bus_conf(void) } /* I/O APICs: APIC ID Version State Address */ -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS apicid_base = get_apicid_base(1); #else apicid_base = CONFIG_MAX_PHYSICAL_CPUS; diff --git a/src/mainboard/amd/mahogany_fam10/mainboard.c b/src/mainboard/amd/mahogany_fam10/mainboard.c index 2cbeaf1..1f1941b 100644 --- a/src/mainboard/amd/mahogany_fam10/mainboard.c +++ b/src/mainboard/amd/mahogany_fam10/mainboard.c @@ -106,7 +106,7 @@ static void mahogany_enable(device_t dev) { printk(BIOS_INFO, "Mainboard MAHOGANY Enable. dev=0x%p\n", dev); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; /* TOP_MEM: the top of DRAM below 4G */ @@ -155,7 +155,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/amd/mahogany_fam10/mptable.c b/src/mainboard/amd/mahogany_fam10/mptable.c index c56952e..d69c7b7 100644 --- a/src/mainboard/amd/mahogany_fam10/mptable.c +++ b/src/mainboard/amd/mahogany_fam10/mptable.c @@ -100,7 +100,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb700, (pin)) #else diff --git a/src/mainboard/amd/mahogany_fam10/romstage.c b/src/mainboard/amd/mahogany_fam10/romstage.c index dce9baa..d48b69d 100644 --- a/src/mainboard/amd/mahogany_fam10/romstage.c +++ b/src/mainboard/amd/mahogany_fam10/romstage.c @@ -147,7 +147,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) */ wait_all_core0_started(); - #if CONFIG_LOGICAL_CPUS==1 + #if CONFIG_LOGICAL_CPUS /* Core0 on each node is configured. Now setup any additional cores. */ printk(BIOS_DEBUG, "start_other_cores()\n"); start_other_cores(); diff --git a/src/mainboard/amd/persimmon/agesawrapper.c b/src/mainboard/amd/persimmon/agesawrapper.c index e60673e..0d63abb 100644 --- a/src/mainboard/amd/persimmon/agesawrapper.c +++ b/src/mainboard/amd/persimmon/agesawrapper.c @@ -515,7 +515,7 @@ agesawrapper_amdinitlate ( return (UINT32)Status; } -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME UINT32 agesawrapper_amdinitresume ( VOID diff --git a/src/mainboard/amd/persimmon/get_bus_conf.c b/src/mainboard/amd/persimmon/get_bus_conf.c index 4c094ae..1d5842a 100644 --- a/src/mainboard/amd/persimmon/get_bus_conf.c +++ b/src/mainboard/amd/persimmon/get_bus_conf.c @@ -51,7 +51,7 @@ u32 sbdn_sb800; static u32 get_bus_conf_done = 0; -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME extern u8 acpi_slp_type; #endif @@ -83,7 +83,7 @@ void get_bus_conf(void) * of each of the write functions called prior to the ACPI write functions, so this * becomes the best place for this call. */ -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME if (acpi_slp_type != 3) { status = agesawrapper_amdinitlate(); if(status) diff --git a/src/mainboard/amd/persimmon/mainboard.c b/src/mainboard/amd/persimmon/mainboard.c index 9a8428e..76a9ae6 100644 --- a/src/mainboard/amd/persimmon/mainboard.c +++ b/src/mainboard/amd/persimmon/mainboard.c @@ -63,11 +63,11 @@ static void persimmon_enable(device_t dev) * The mainboard is the first place that we get control in ramstage. Check * for S3 resume and call the approriate AGESA/CIMx resume functions. */ -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME acpi_slp_type = acpi_get_sleep_type(); #endif -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; uint32_t sys_mem; @@ -113,7 +113,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/amd/persimmon/mptable.c b/src/mainboard/amd/persimmon/mptable.c index 61ddef1..d0c31f0 100644 --- a/src/mainboard/amd/persimmon/mptable.c +++ b/src/mainboard/amd/persimmon/mptable.c @@ -83,7 +83,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb800, (pin)) #else diff --git a/src/mainboard/amd/persimmon/platform_cfg.h b/src/mainboard/amd/persimmon/platform_cfg.h index 97aa47e..db3fc15 100644 --- a/src/mainboard/amd/persimmon/platform_cfg.h +++ b/src/mainboard/amd/persimmon/platform_cfg.h @@ -37,7 +37,7 @@ * before AGESA module get call. */ #ifndef BIOS_SIZE -#if CONFIG_COREBOOT_ROMSIZE_KB_1024 == 1 +#if CONFIG_COREBOOT_ROMSIZE_KB_1024 #define BIOS_SIZE BIOS_SIZE_1M #elif CONFIG_COREBOOT_ROMSIZE_KB_2048 == 1 #define BIOS_SIZE BIOS_SIZE_2M diff --git a/src/mainboard/amd/persimmon/romstage.c b/src/mainboard/amd/persimmon/romstage.c index 55d0516..56a6788 100644 --- a/src/mainboard/amd/persimmon/romstage.c +++ b/src/mainboard/amd/persimmon/romstage.c @@ -51,7 +51,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) { u32 val; -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME void *resume_backup_memory; #endif @@ -107,7 +107,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) else printk(BIOS_DEBUG, "passed.\n"); -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME if (!acpi_is_wakeup_early()) { /* Check for S3 resume */ #endif post_code(0x40); @@ -126,7 +126,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) else printk(BIOS_DEBUG, "passed.\n"); -#if CONFIG_HAVE_ACPI_RESUME == 1 +#if CONFIG_HAVE_ACPI_RESUME } else { /* S3 detect */ printk(BIOS_INFO, "S3 detected\n"); diff --git a/src/mainboard/amd/pistachio/get_bus_conf.c b/src/mainboard/amd/pistachio/get_bus_conf.c index 2b0fca7..d4152a1 100644 --- a/src/mainboard/amd/pistachio/get_bus_conf.c +++ b/src/mainboard/amd/pistachio/get_bus_conf.c @@ -23,7 +23,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS #include #endif @@ -107,7 +107,7 @@ void get_bus_conf(void) } /* I/O APICs: APIC ID Version State Address */ -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS apicid_base = get_apicid_base(1); #else apicid_base = CONFIG_MAX_PHYSICAL_CPUS; diff --git a/src/mainboard/amd/pistachio/mainboard.c b/src/mainboard/amd/pistachio/mainboard.c index d1d9a84..e5d0efa 100644 --- a/src/mainboard/amd/pistachio/mainboard.c +++ b/src/mainboard/amd/pistachio/mainboard.c @@ -257,7 +257,7 @@ static void pistachio_enable(device_t dev) { printk(BIOS_INFO, "Mainboard Pistachio Enable. dev=0x%p\n", dev); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; /* TOP_MEM: the top of DRAM below 4G */ @@ -308,7 +308,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_base=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, diff --git a/src/mainboard/amd/pistachio/mptable.c b/src/mainboard/amd/pistachio/mptable.c index cf98ae3..f34918f 100644 --- a/src/mainboard/amd/pistachio/mptable.c +++ b/src/mainboard/amd/pistachio/mptable.c @@ -100,7 +100,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb600, (pin)) #else diff --git a/src/mainboard/amd/pistachio/romstage.c b/src/mainboard/amd/pistachio/romstage.c index 5d6e7a8..45c94c8 100644 --- a/src/mainboard/amd/pistachio/romstage.c +++ b/src/mainboard/amd/pistachio/romstage.c @@ -101,7 +101,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) setup_coherent_ht_domain(); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS /* It is said that we should start core1 after all core0 launched */ wait_all_core0_started(); start_other_cores(); diff --git a/src/mainboard/amd/serengeti_cheetah/get_bus_conf.c b/src/mainboard/amd/serengeti_cheetah/get_bus_conf.c index 36b5776..d4f44c0 100644 --- a/src/mainboard/amd/serengeti_cheetah/get_bus_conf.c +++ b/src/mainboard/amd/serengeti_cheetah/get_bus_conf.c @@ -3,7 +3,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS #include #endif @@ -192,7 +192,7 @@ void get_bus_conf(void) /*I/O APICs: APIC ID Version State Address*/ -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS apicid_base = get_apicid_base(3); #else apicid_base = CONFIG_MAX_PHYSICAL_CPUS; diff --git a/src/mainboard/amd/serengeti_cheetah/mptable.c b/src/mainboard/amd/serengeti_cheetah/mptable.c index 4214408..866875d 100644 --- a/src/mainboard/amd/serengeti_cheetah/mptable.c +++ b/src/mainboard/amd/serengeti_cheetah/mptable.c @@ -4,7 +4,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS #include #endif #include diff --git a/src/mainboard/amd/serengeti_cheetah/romstage.c b/src/mainboard/amd/serengeti_cheetah/romstage.c index 8378ca4..7378130 100644 --- a/src/mainboard/amd/serengeti_cheetah/romstage.c +++ b/src/mainboard/amd/serengeti_cheetah/romstage.c @@ -1,4 +1,4 @@ -#if CONFIG_K8_REV_F_SUPPORT == 1 +#if CONFIG_K8_REV_F_SUPPORT #define K8_REV_F_SUPPORT_F0_F1_WORKAROUND 0 #endif @@ -139,13 +139,13 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) print_debug("bsp_apicid="); print_debug_hex8(bsp_apicid); print_debug("\n"); -#if CONFIG_MEM_TRAIN_SEQ == 1 +#if CONFIG_MEM_TRAIN_SEQ set_sysinfo_in_ram(0); // in BSP so could hold all ap until sysinfo is in ram #endif setup_coherent_ht_domain(); // routing table and start other core0 wait_all_core0_started(); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS // It is said that we should start core1 after all core0 launched /* becase optimize_link_coherent_ht is moved out from setup_coherent_ht_domain, * So here need to make sure last core0 is started, esp for two way system, diff --git a/src/mainboard/amd/serengeti_cheetah_fam10/get_bus_conf.c b/src/mainboard/amd/serengeti_cheetah_fam10/get_bus_conf.c index b595473..da7efe6 100644 --- a/src/mainboard/amd/serengeti_cheetah_fam10/get_bus_conf.c +++ b/src/mainboard/amd/serengeti_cheetah_fam10/get_bus_conf.c @@ -22,7 +22,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS #include #endif diff --git a/src/mainboard/amd/serengeti_cheetah_fam10/mptable.c b/src/mainboard/amd/serengeti_cheetah_fam10/mptable.c index e90b348..d19b3c6 100644 --- a/src/mainboard/amd/serengeti_cheetah_fam10/mptable.c +++ b/src/mainboard/amd/serengeti_cheetah_fam10/mptable.c @@ -23,7 +23,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS #include #endif #include diff --git a/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c b/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c index 29b00b2..09447a6 100644 --- a/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c +++ b/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c @@ -255,7 +255,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) */ wait_all_core0_started(); - #if CONFIG_LOGICAL_CPUS==1 + #if CONFIG_LOGICAL_CPUS /* Core0 on each node is configured. Now setup any additional cores. */ printk(BIOS_DEBUG, "start_other_cores()\n"); start_other_cores(); diff --git a/src/mainboard/amd/south_station/mainboard.c b/src/mainboard/amd/south_station/mainboard.c index 990c8b9..ed65b34 100644 --- a/src/mainboard/amd/south_station/mainboard.c +++ b/src/mainboard/amd/south_station/mainboard.c @@ -82,7 +82,7 @@ static void southstation_enable(device_t dev) { printk(BIOS_INFO, "Mainboard " CONFIG_MAINBOARD_PART_NUMBER " Enable.\n"); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; uint32_t sys_mem; @@ -129,7 +129,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/amd/south_station/mptable.c b/src/mainboard/amd/south_station/mptable.c index 99004b3..ba73ce0 100644 --- a/src/mainboard/amd/south_station/mptable.c +++ b/src/mainboard/amd/south_station/mptable.c @@ -83,7 +83,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb800, (pin)) #else diff --git a/src/mainboard/amd/south_station/platform_cfg.h b/src/mainboard/amd/south_station/platform_cfg.h index 66aab8b..1c8506b 100644 --- a/src/mainboard/amd/south_station/platform_cfg.h +++ b/src/mainboard/amd/south_station/platform_cfg.h @@ -37,7 +37,7 @@ * before AGESA module get call. */ #ifndef BIOS_SIZE -#if CONFIG_COREBOOT_ROMSIZE_KB_1024 == 1 +#if CONFIG_COREBOOT_ROMSIZE_KB_1024 #define BIOS_SIZE BIOS_SIZE_1M #elif CONFIG_COREBOOT_ROMSIZE_KB_2048 == 1 #define BIOS_SIZE BIOS_SIZE_2M diff --git a/src/mainboard/amd/tilapia_fam10/get_bus_conf.c b/src/mainboard/amd/tilapia_fam10/get_bus_conf.c index b169775..563a87e 100644 --- a/src/mainboard/amd/tilapia_fam10/get_bus_conf.c +++ b/src/mainboard/amd/tilapia_fam10/get_bus_conf.c @@ -23,7 +23,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS #include #endif @@ -107,7 +107,7 @@ void get_bus_conf(void) } /* I/O APICs: APIC ID Version State Address */ -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS apicid_base = get_apicid_base(1); #else apicid_base = CONFIG_MAX_PHYSICAL_CPUS; diff --git a/src/mainboard/amd/tilapia_fam10/mainboard.c b/src/mainboard/amd/tilapia_fam10/mainboard.c index 357bdac..e2ef3f9 100644 --- a/src/mainboard/amd/tilapia_fam10/mainboard.c +++ b/src/mainboard/amd/tilapia_fam10/mainboard.c @@ -281,7 +281,7 @@ static void tilapia_enable(device_t dev) { printk(BIOS_INFO, "Mainboard TILAPIA Enable. dev=0x%p\n", dev); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; /* TOP_MEM: the top of DRAM below 4G */ @@ -331,7 +331,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/amd/tilapia_fam10/mptable.c b/src/mainboard/amd/tilapia_fam10/mptable.c index 4a276fb..d7951cf 100644 --- a/src/mainboard/amd/tilapia_fam10/mptable.c +++ b/src/mainboard/amd/tilapia_fam10/mptable.c @@ -100,7 +100,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb700, (pin)) #else diff --git a/src/mainboard/amd/tilapia_fam10/romstage.c b/src/mainboard/amd/tilapia_fam10/romstage.c index f316395..9919cce 100644 --- a/src/mainboard/amd/tilapia_fam10/romstage.c +++ b/src/mainboard/amd/tilapia_fam10/romstage.c @@ -147,7 +147,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) */ wait_all_core0_started(); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS /* Core0 on each node is configured. Now setup any additional cores. */ printk(BIOS_DEBUG, "start_other_cores()\n"); start_other_cores(); diff --git a/src/mainboard/amd/torpedo/Oem.h b/src/mainboard/amd/torpedo/Oem.h index 037ce94..4acc136 100644 --- a/src/mainboard/amd/torpedo/Oem.h +++ b/src/mainboard/amd/torpedo/Oem.h @@ -20,7 +20,7 @@ #define BIOS_SIZE 0x04 //04 - 1MB #endif #define LEGACY_FREE 0x00 -#if CONFIG_ONBOARD_USB30 == 0 +#if !CONFIG_ONBOARD_USB30 #define XHCI_SUPPORT 0x01 #endif diff --git a/src/mainboard/amd/torpedo/mainboard.c b/src/mainboard/amd/torpedo/mainboard.c index 2152153..7248bfb 100644 --- a/src/mainboard/amd/torpedo/mainboard.c +++ b/src/mainboard/amd/torpedo/mainboard.c @@ -58,7 +58,7 @@ uint64_t uma_memory_base, uma_memory_size; static void torpedo_enable(device_t dev) { printk(BIOS_INFO, "Mainboard " CONFIG_MAINBOARD_PART_NUMBER " Enable. dev=0x%p\n", dev); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; uint32_t sys_mem; @@ -107,7 +107,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/amd/torpedo/mptable.c b/src/mainboard/amd/torpedo/mptable.c index 936a417..9513741 100644 --- a/src/mainboard/amd/torpedo/mptable.c +++ b/src/mainboard/amd/torpedo/mptable.c @@ -164,7 +164,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, int_sign, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(int_sign)), apicid_sb900, (pin)) #else diff --git a/src/mainboard/amd/torpedo/platform_cfg.h b/src/mainboard/amd/torpedo/platform_cfg.h index cf31c6a..a6d02e8 100644 --- a/src/mainboard/amd/torpedo/platform_cfg.h +++ b/src/mainboard/amd/torpedo/platform_cfg.h @@ -39,7 +39,7 @@ #define BIOS_SIZE_4M 3 #define BIOS_SIZE_8M 7 -#if CONFIG_COREBOOT_ROMSIZE_KB_1024 == 1 +#if CONFIG_COREBOOT_ROMSIZE_KB_1024 #define BIOS_SIZE BIOS_SIZE_1M #elif CONFIG_COREBOOT_ROMSIZE_KB_2048 == 1 #define BIOS_SIZE BIOS_SIZE_2M @@ -311,7 +311,7 @@ #define INCHIP_USB_CINFIG 0x7F #define INCHIP_USB_OHCI1_CINFIG 0x01 #define INCHIP_USB_OHCI2_CINFIG 0x01 -#if CONFIG_ONBOARD_USB30 == 1 +#if CONFIG_ONBOARD_USB30 #define INCHIP_USB_OHCI3_CINFIG 0x00 #else #define INCHIP_USB_OHCI3_CINFIG 0x01 @@ -985,7 +985,7 @@ * @li 0 - Disable * @li 1 - Enable */ -#if CONFIG_ONBOARD_USB30 == 1 +#if CONFIG_ONBOARD_USB30 #define SB_XHCI_SWITCH 0 #else #define SB_XHCI_SWITCH 1 diff --git a/src/mainboard/amd/union_station/mainboard.c b/src/mainboard/amd/union_station/mainboard.c index 800d64d..c5b481d 100644 --- a/src/mainboard/amd/union_station/mainboard.c +++ b/src/mainboard/amd/union_station/mainboard.c @@ -56,7 +56,7 @@ static void unionstation_enable(device_t dev) { printk(BIOS_INFO, "Mainboard " CONFIG_MAINBOARD_PART_NUMBER " Enable.\n"); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; uint32_t sys_mem; @@ -103,7 +103,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/amd/union_station/mptable.c b/src/mainboard/amd/union_station/mptable.c index 99004b3..ba73ce0 100644 --- a/src/mainboard/amd/union_station/mptable.c +++ b/src/mainboard/amd/union_station/mptable.c @@ -83,7 +83,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb800, (pin)) #else diff --git a/src/mainboard/amd/union_station/platform_cfg.h b/src/mainboard/amd/union_station/platform_cfg.h index 66aab8b..1c8506b 100644 --- a/src/mainboard/amd/union_station/platform_cfg.h +++ b/src/mainboard/amd/union_station/platform_cfg.h @@ -37,7 +37,7 @@ * before AGESA module get call. */ #ifndef BIOS_SIZE -#if CONFIG_COREBOOT_ROMSIZE_KB_1024 == 1 +#if CONFIG_COREBOOT_ROMSIZE_KB_1024 #define BIOS_SIZE BIOS_SIZE_1M #elif CONFIG_COREBOOT_ROMSIZE_KB_2048 == 1 #define BIOS_SIZE BIOS_SIZE_2M diff --git a/src/mainboard/arima/hdama/romstage.c b/src/mainboard/arima/hdama/romstage.c index c334fa5..cd08389 100644 --- a/src/mainboard/arima/hdama/romstage.c +++ b/src/mainboard/arima/hdama/romstage.c @@ -93,7 +93,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) needs_reset = setup_coherent_ht_domain(); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS // It is said that we should start core1 after all core0 launched start_other_cores(); wait_all_other_cores_started(bsp_apicid); diff --git a/src/mainboard/asrock/939a785gmh/get_bus_conf.c b/src/mainboard/asrock/939a785gmh/get_bus_conf.c index bed7606..149e163 100644 --- a/src/mainboard/asrock/939a785gmh/get_bus_conf.c +++ b/src/mainboard/asrock/939a785gmh/get_bus_conf.c @@ -23,7 +23,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS #include #endif @@ -107,7 +107,7 @@ void get_bus_conf(void) } /* I/O APICs: APIC ID Version State Address */ -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS apicid_base = get_apicid_base(1); #else apicid_base = CONFIG_MAX_PHYSICAL_CPUS; diff --git a/src/mainboard/asrock/939a785gmh/mainboard.c b/src/mainboard/asrock/939a785gmh/mainboard.c index 945a19f..0b566e4 100644 --- a/src/mainboard/asrock/939a785gmh/mainboard.c +++ b/src/mainboard/asrock/939a785gmh/mainboard.c @@ -103,7 +103,7 @@ static void mb_enable(device_t dev) { printk(BIOS_INFO, "Mainboard 939A785GMH/128M Enable. dev=0x%p\n", dev); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; /* TOP_MEM: the top of DRAM below 4G */ @@ -152,7 +152,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/asrock/939a785gmh/mptable.c b/src/mainboard/asrock/939a785gmh/mptable.c index c0ca550..5b73b20 100644 --- a/src/mainboard/asrock/939a785gmh/mptable.c +++ b/src/mainboard/asrock/939a785gmh/mptable.c @@ -99,7 +99,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb700, (pin)) #else diff --git a/src/mainboard/asrock/939a785gmh/romstage.c b/src/mainboard/asrock/939a785gmh/romstage.c index 4a1b1c3..51b7519 100644 --- a/src/mainboard/asrock/939a785gmh/romstage.c +++ b/src/mainboard/asrock/939a785gmh/romstage.c @@ -169,7 +169,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) setup_coherent_ht_domain(); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS /* It is said that we should start core1 after all core0 launched */ wait_all_core0_started(); start_other_cores(); diff --git a/src/mainboard/asrock/e350m1/mainboard.c b/src/mainboard/asrock/e350m1/mainboard.c index 4e58324..8642e28 100644 --- a/src/mainboard/asrock/e350m1/mainboard.c +++ b/src/mainboard/asrock/e350m1/mainboard.c @@ -54,7 +54,7 @@ uint64_t uma_memory_base, uma_memory_size; static void e350m1_enable(device_t dev) { printk(BIOS_INFO, "Mainboard " CONFIG_MAINBOARD_PART_NUMBER " Enable.\n"); -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA msr_t msr, msr2; uint32_t sys_mem; @@ -101,7 +101,7 @@ int add_mainboard_resources(struct lb_memory *mem) /* UMA is removed from system memory in the northbridge code, but * in some circumstances we want the memory mentioned as reserved. */ -#if (CONFIG_GFXUMA == 1) +#if CONFIG_GFXUMA printk(BIOS_INFO, "uma_memory_start=0x%llx, uma_memory_size=0x%llx \n", uma_memory_base, uma_memory_size); lb_add_memory_range(mem, LB_MEM_RESERVED, uma_memory_base, diff --git a/src/mainboard/asrock/e350m1/mptable.c b/src/mainboard/asrock/e350m1/mptable.c index 7e8c947..81fe0bd 100644 --- a/src/mainboard/asrock/e350m1/mptable.c +++ b/src/mainboard/asrock/e350m1/mptable.c @@ -83,7 +83,7 @@ static void *smp_write_config_table(void *v) /* PCI interrupts are level triggered, and are * associated with a specific bus/device/function tuple. */ -#if CONFIG_GENERATE_ACPI_TABLES == 0 +#if !CONFIG_GENERATE_ACPI_TABLES #define PCI_INT(bus, dev, fn, pin) \ smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, (bus), (((dev)<<2)|(fn)), apicid_sb800, (pin)) #else diff --git a/src/mainboard/asrock/e350m1/platform_cfg.h b/src/mainboard/asrock/e350m1/platform_cfg.h index 6aa31d2..7fa9c23 100644 --- a/src/mainboard/asrock/e350m1/platform_cfg.h +++ b/src/mainboard/asrock/e350m1/platform_cfg.h @@ -37,7 +37,7 @@ * before AGESA module get call. */ #ifndef BIOS_SIZE - #if CONFIG_COREBOOT_ROMSIZE_KB_1024 == 1 + #if CONFIG_COREBOOT_ROMSIZE_KB_1024 #define BIOS_SIZE BIOS_SIZE_1M #elif CONFIG_COREBOOT_ROMSIZE_KB_2048 == 1 #define BIOS_SIZE BIOS_SIZE_2M diff --git a/src/mainboard/asus/a8n_e/get_bus_conf.c b/src/mainboard/asus/a8n_e/get_bus_conf.c index 75741fd..ce1448d 100644 --- a/src/mainboard/asus/a8n_e/get_bus_conf.c +++ b/src/mainboard/asus/a8n_e/get_bus_conf.c @@ -27,7 +27,7 @@ #include #include #include -#if CONFIG_LOGICAL_CPUS == 1 +#if CONFIG_LOGICAL_CPUS #include #endif #include @@ -114,7 +114,7 @@ void get_bus_conf(void) } } -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS apicid_base = get_apicid_base(3); #else apicid_base = CONFIG_MAX_PHYSICAL_CPUS; diff --git a/src/mainboard/asus/a8n_e/romstage.c b/src/mainboard/asus/a8n_e/romstage.c index b3e85b7..fcbe86d 100644 --- a/src/mainboard/asus/a8n_e/romstage.c +++ b/src/mainboard/asus/a8n_e/romstage.c @@ -121,7 +121,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) needs_reset = setup_coherent_ht_domain(); wait_all_core0_started(); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS /* It is said that we should start core1 after all core0 launched. */ start_other_cores(); wait_all_other_cores_started(bsp_apicid); diff --git a/src/mainboard/asus/a8v-e_deluxe/romstage.c b/src/mainboard/asus/a8v-e_deluxe/romstage.c index 47a0e65..53a1fbc 100644 --- a/src/mainboard/asus/a8v-e_deluxe/romstage.c +++ b/src/mainboard/asus/a8v-e_deluxe/romstage.c @@ -190,7 +190,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) print_info("now booting... Core0 started\n"); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS /* It is said that we should start core1 after all core0 launched. */ start_other_cores(); wait_all_other_cores_started(bsp_apicid); diff --git a/src/mainboard/asus/a8v-e_se/romstage.c b/src/mainboard/asus/a8v-e_se/romstage.c index 4193452..7539a80 100644 --- a/src/mainboard/asus/a8v-e_se/romstage.c +++ b/src/mainboard/asus/a8v-e_se/romstage.c @@ -192,7 +192,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) print_info("now booting... Core0 started\n"); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS /* It is said that we should start core1 after all core0 launched. */ start_other_cores(); wait_all_other_cores_started(bsp_apicid); diff --git a/src/mainboard/asus/k8v-x/romstage.c b/src/mainboard/asus/k8v-x/romstage.c index f24c4d4..82b0636 100644 --- a/src/mainboard/asus/k8v-x/romstage.c +++ b/src/mainboard/asus/k8v-x/romstage.c @@ -163,7 +163,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx) print_info("now booting... Core0 started\n"); -#if CONFIG_LOGICAL_CPUS==1 +#if CONFIG_LOGICAL_CPUS /* It is said that we should start core1 after all core0 launched. */ start_other_cores(); wait_all_other_cores_started(bsp_apicid); diff --git a/src/mainboard/asus/m2n-e/get_bus_conf.c b/src/mainboard/asus/m2n-e/get_bus_conf.c index a39ac22..031b673 100644 --- a/src/mainboard/asus/m2n-e/get_bus_conf.c +++ b/