Stefan Reinauer (stefan.reinauer(a)coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2783
-gerrit
commit 39fea1b80814d32d3a1d5b70123dc37aab475fe8
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Tue Jan 22 13:54:12 2013 -0600
lynxpoint: Add cbfs_load_payload() implementation
SPI accesses can be slow depending on the setup and the access pattern.
The current SPI hardware setup to cache and prefetch. The alternative
cbfs_load_payload() function takes advantage of the caching in the CPU
because the ROM is cached as write protected as well as the SPI's
hardware's caching/prefetching implementation. The CPU will fetch
consecutive aligned cachelines which will hit the ROM as
cacheline-aligned addresses. Once the payload is mirrored into RAM the
segment loading can take place by reading RAM instead of ROM.
With the alternative cbfs_load_payload() the boot time on a baskingridge
board saves ~100ms. This savings is observed using cbmem.py after
performing warm reboots and looking at TS_SELFBOOT_JUMP (99) entries.
This is booting with a depthcharge payload whose payload file fits
within the SMM_DEFAULT_SIZE (0x10000 bytes).
Datapoints with TS_LOAD_PAYLOAD (90) & TS_SELFBOOT_JUMP (99) cbmem entries:
Baseline Alt
-------- --------
90:3,859,310 (473) 90:3,863,647 (454)
99:3,989,578 (130,268) 99:3,888,709 (25,062)
90:3,899,450 (477) 90:3,860,926 (463)
99:4,029,459 (130,008) 99:3,890,583 (29,657)
90:3,834,600 (466) 90:3,890,564 (465)
99:3,964,535 (129,934) 99:3,920,213 (29,649)
Booted baskingridge many times and observed 100ms reduction in
TS_SELFBOOT_JUMP times (time to load payload).
Change-Id: I27b2dec59ecd469a4906b4179b39928e9201db81
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/southbridge/intel/lynxpoint/Kconfig | 1 +
src/southbridge/intel/lynxpoint/Makefile.inc | 1 +
src/southbridge/intel/lynxpoint/spi_loading.c | 85 +++++++++++++++++++++++++++
3 files changed, 87 insertions(+)
diff --git a/src/southbridge/intel/lynxpoint/Kconfig b/src/southbridge/intel/lynxpoint/Kconfig
index 6f5bfe2..f79e963 100644
--- a/src/southbridge/intel/lynxpoint/Kconfig
+++ b/src/southbridge/intel/lynxpoint/Kconfig
@@ -31,6 +31,7 @@ config SOUTH_BRIDGE_OPTIONS # dummy
select PCIEXP_ASPM
select PCIEXP_COMMON_CLOCK
select SPI_FLASH
+ select ALT_CBFS_LOAD_PAYLOAD
config INTEL_LYNXPOINT_LP
bool
diff --git a/src/southbridge/intel/lynxpoint/Makefile.inc b/src/southbridge/intel/lynxpoint/Makefile.inc
index 6e84ce6..51bb428 100644
--- a/src/southbridge/intel/lynxpoint/Makefile.inc
+++ b/src/southbridge/intel/lynxpoint/Makefile.inc
@@ -37,6 +37,7 @@ ramstage-y += me_status.c
ramstage-y += reset.c
ramstage-y += watchdog.c
ramstage-y += acpi.c
+ramstage-$(CONFIG_ALT_CBFS_LOAD_PAYLOAD) += spi_loading.c
ramstage-$(CONFIG_ELOG) += elog.c
ramstage-y += spi.c
diff --git a/src/southbridge/intel/lynxpoint/spi_loading.c b/src/southbridge/intel/lynxpoint/spi_loading.c
new file mode 100644
index 0000000..eb3082b
--- /dev/null
+++ b/src/southbridge/intel/lynxpoint/spi_loading.c
@@ -0,0 +1,85 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 ChromeOS 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
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <arch/byteorder.h>
+#include <cbfs.h>
+#include <console/console.h>
+#include <cpu/x86/smm.h>
+
+#define CACHELINE_SIZE 64
+#define INTRA_CACHELINE_MASK (CACHELINE_SIZE - 1)
+#define CACHELINE_MASK (~INTRA_CACHELINE_MASK)
+
+/* Mirror the payload file to the default SMM location if it is small enough.
+ * The default SMM region can be used since no one is using the memory at this
+ * location at this stage in the boot. */
+static inline void *spi_mirror(void *file_start, int file_len)
+{
+ int alignment_diff;
+ char *src;
+ char *dest = (void *)SMM_DEFAULT_BASE;
+
+ alignment_diff = (INTRA_CACHELINE_MASK & (long)file_start);
+
+ /* Adjust file length so that the start and end points are aligned to a
+ * cacheline. Coupled with the ROM caching in the CPU the SPI hardware
+ * will read and cache full length cachelines. It will also prefetch
+ * data as well. Once things are mirrored in memory all accesses should
+ * hit the CPUs cache. */
+ file_len += alignment_diff;
+ file_len = ALIGN(file_len, CACHELINE_SIZE);
+
+ printk(BIOS_DEBUG, "Payload aligned size: 0x%x\n", file_len);
+
+ /* Just pass back the pointer to ROM space if the file is larger
+ * than the RAM mirror region. */
+ if (file_len > SMM_DEFAULT_SIZE)
+ return file_start;
+
+ src = (void *)(CACHELINE_MASK & (long)file_start);
+ /* Note that if mempcy is not using 32-bit moves the performance will
+ * degrade because the SPI hardware prefetchers look for
+ * cacheline-aligned 32-bit accesses to kick in. */
+ memcpy(dest, src, file_len);
+
+ /* Provide pointer into mirrored space. */
+ return &dest[alignment_diff];
+}
+
+void *cbfs_load_payload(struct cbfs_media *media, const char *name)
+{
+ int file_len;
+ void *file_start;
+ struct cbfs_file *file = cbfs_get_file(media, name);
+
+ if (file == NULL)
+ return NULL;
+
+ if (ntohl(file->type) != CBFS_TYPE_PAYLOAD)
+ return NULL;
+
+ file_len = ntohl(file->len);
+
+ file_start = CBFS_SUBHEADER(file);
+
+ return spi_mirror(file_start, file_len);
+}
the following patch was just integrated into master:
commit 81108b90593e1c8a459c499307404955771c54f3
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Tue Jan 22 13:22:02 2013 -0600
cbfs: alternative support for cbfs_load_payload()
In certain situations boot speed can be increased by providing an
alternative implementation to cbfs_load_payload(). The
ALT_CBFS_LOAD_PAYLOAD option allows for the mainboard or chipset to
provide its own implementation.
Booted baskingridge board with alternative and regular
cbfs_load_payload().
Change-Id: I547ac9881a82bacbdb3bbdf38088dfcc22fd0c2c
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
Reviewed-on: http://review.coreboot.org/2782
Tested-by: build bot (Jenkins)
Reviewed-by: Marc Jones <marc.jones(a)se-eng.com>
Build-Tested: build bot (Jenkins) at Tue Mar 19 02:54:26 2013, giving +1
See http://review.coreboot.org/2782 for details.
-gerrit
Stefan Reinauer (stefan.reinauer(a)coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2831
-gerrit
commit dd29a846063c7ced16b6a7ca2dfff0c2e2c5bef3
Author: Jens Rottmann <JRottmann(a)LiPPERTembedded.de>
Date: Fri Mar 1 19:41:41 2013 +0100
AMD Inagua: add GEC firmware, document Broadcom BCM57xx Selfboot Patch format
The Broadcom BCM5785 GbE MAC integrated in the AMD Hudson-E1 requires a
secret sauce firmware blob to work. As Broadcom wasn't willing to send us
any documentation (or a firmware adapted to our Micrel PHY) I had to figure
out everything by myself in many weeks of hard detective work.
In the end we had to settle for a different solution, the modified firmware
I devised for the Micrel KSZ9021 PHY on our early FrontRunner-AF prototypes
is no longer needed for the production version. However the information
contained here might be very useful for others who'd like to use a
competing PHY instead of Broadcom's 50610, so it should not get lost.
And of course the unmodified, but now in large parts documented Selfboot
Patch is needed to get Ethernet on AMD Inagua. The code introduced here
should make the Hudson's internal MAC usable without having to add the
proprietary firmware blob. - At least in theory.
Unfortunately we've been unable to actually test this patch on Inagua,
therefore the broadcom_init() call in mainboard.c was left commented out.
If you have the hardware and can confirm it works please enable it.
The fun thing is: as Broadcom refused to do any business with us at all,
or send us any documentation, we never had to sign an NDA with them. This
leaves me free to publish everything I have found out. :-)
Change-Id: I94868250591862b376049c76bd21cb7e85f82569
Signed-off-by: Jens Rottmann <JRottmann(a)LiPPERTembedded.de>
---
src/mainboard/amd/inagua/Makefile.inc | 2 +-
src/mainboard/amd/inagua/broadcom.c | 360 ++++++++++++++++++++++++++++++++++
src/mainboard/amd/inagua/mainboard.c | 5 +
3 files changed, 366 insertions(+), 1 deletion(-)
diff --git a/src/mainboard/amd/inagua/Makefile.inc b/src/mainboard/amd/inagua/Makefile.inc
index 17443bc..b84a03a 100644
--- a/src/mainboard/amd/inagua/Makefile.inc
+++ b/src/mainboard/amd/inagua/Makefile.inc
@@ -35,4 +35,4 @@ ramstage-y += BiosCallOuts.c
ramstage-y += PlatformGnbPcie.c
ramstage-y += reset.c
-
+ramstage-y += broadcom.c
diff --git a/src/mainboard/amd/inagua/broadcom.c b/src/mainboard/amd/inagua/broadcom.c
new file mode 100644
index 0000000..357fdbc
--- /dev/null
+++ b/src/mainboard/amd/inagua/broadcom.c
@@ -0,0 +1,360 @@
+/*
+ * Initialize Broadcom 5785 GbE MAC embedded in AMD A55E (Hudson-E1) Southbridge
+ * by uploading a Selfboot Patch to the A55E's shadow ROM area. The patch
+ * itself supports the Broadcom 50610(M) PHY on the AMD Inagua. It is
+ * equivalent to Broadcom's SelfBoot patch V1.11 (sb5785m1.11).
+ * A modified variant, selected by CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF supports
+ * the Micrel KSZ9021 PHY that was used on LiPPERT FrontRunner-AF (CFR-AF)
+ * revision 0v0, the first prototype. The board is history and this code now
+ * serves only to document the proprietary Selfboot Patch format and how to
+ * adapt it to a PHY unsupported by Broadcom.
+ *
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 LiPPERT ADLINK Technology GmbH
+ * (Written by Jens Rottmann <JRottmann(a)LiPPERTembedded.de>)
+ *
+ * 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 <types.h>
+#include <arch/byteorder.h>
+#include <console/console.h>
+#include <device/device.h> //Coreboot device access
+#include <device/pci.h>
+#include <delay.h>
+
+#define be16(x) cpu_to_be16(x) //a little easier to type
+#define be(x) cpu_to_be32(x) //this is used a lot!
+
+/* C forces us to specify these before defining struct selfboot_patch :-( */
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+#define INIT1_LENGTH 9
+#define INIT2_LENGTH 10
+#define INIT3_LENGTH 3
+#define INIT4_LENGTH 7 //this one may be 0
+#define PWRDN_LENGTH 5
+#else
+#define INIT1_LENGTH 13
+#define INIT2_LENGTH 6
+#define INIT3_LENGTH 3
+#define INIT4_LENGTH 11 //this one may be 0
+#define PWRDN_LENGTH 4
+#endif
+
+
+/* The AMD A55E (Hudson-E1) Southbridge contains an integrated Gigabit Ethernet
+ * MAC, however AMD's documentation merely defines the related balls (without
+ * fully describing their function) and states that only Broadcom 50610(M) PHYs
+ * will be supported, that's all. The Hudson register reference skips all MAC
+ * registers entirely, even AMD support doesn't seem to know more about it.
+ *
+ * As Broadcom refused to sell us any 50610 chips or provide any docs (or indeed
+ * even a price list) below $100K expected sales we had to figure out everything
+ * by ourselves. *Everything* below is the result of months of detective work,
+ * documented here lest it get lost:
+ *
+ * The AMD A55E's GbE MAC is a Broadcom 5785, which AMD obviously licensed as IP
+ * core. It uses a standard RGMII/MII interface and the Broadcom drivers will
+ * recognize it by its unchanged PCI ID 14E4:1699, however there are some
+ * specialties.
+ *
+ * The 5785 MAC can detect the link with 4 additional inputs, "phy_status[3:0]",
+ * 'snooping' on the PHY's LED outputs. Interpretation of the LEDs' patterns is
+ * programmed with register 0x5A4 of the MAC. AMD renamed them to "GBE_STAT" and
+ * won't say anything about their purpose. Appearently hardware designers are
+ * expected to blindly copy the Inagua reference schematic: GBE_STAT2:
+ * 0=activity; GBE_STAT[1:0]: 11=no link, 10=10Mbit, 01=100Mbit, 00=1Gbit.
+ *
+ * For package processing the 5785 also features a MIPS-based RISC CPU, booting
+ * from an internal ROM. The firmware loads config data and supplements (e.g. to
+ * support specific PHYs), named "Selfboot Patches", via the "NVRAM Interface",
+ * usually from an external EEPROM. The A55E doesn't have any balls for an ext.
+ * EEPROM, instead AMD added a small internal RAM. The BIOS is expected to copy
+ * the correct contents into this RAM (which only supports byte access!) upon
+ * each powerup. The A55E can trigger an SMI upon writes, enabling the BIOS to
+ * forward any changes to an actually 'NV' location, e.g. the BIOS's SPI flash,
+ * behind the scenes. AMD calls it "GEC shadow ROM", not describing what it's
+ * for nor mentioning the term "NVRAM". broadcom_init() below documents a
+ * procedure how to upload the patch. No SMI magic is installed, therefore
+ * 'NV'RAM writes won't be persistent.
+ *
+ * The "Selfboot Patch" can execute simple commands at various points during
+ * main firmware execution. This can be used to change config registers,
+ * initialize a specific PHY or work around firmware bugs. Broadcom provides
+ * suitable Patches only for their AC131 and 50610 PHYs (as binary blobs). I
+ * found them in DOS\sb_patch\5785\*\sb5785*.* in Driver_14_6_4_2.zip. (Note
+ * that every 32bit-word of these files must be byte-swapped before uploading
+ * them to the A55E.)
+ *
+ * Below is a derived Patch supporting the Micrel KSZ9021 PHY used on the
+ * LiPPERT CFR-AF PC/104 SBC instead, with detailled description of the format.
+ * (Here in correct order for upload.)
+ *
+ * This Patch made Ethernet work with Linux 3.3 - without having to modify the
+ * tg3.ko driver. Broadcom's Windows-Drivers still fail with "Code 10" however;
+ * disassembly showed they check the PHY ID and abort, because the Micrel PHY is
+ * not supported.
+ */
+
+static struct selfboot_patch { //Watch out: all values are *BIG-ENDIAN*!
+
+ struct { /* Global header */
+ u8 signature; //0xA5
+ u8 format; //bits 7-3: patch format; 2-0: revision
+ u8 mac_addr[6];
+ u16 subsys_device; //IDs will be loaded into PCI config space
+ u16 subsys_vendor;
+ u16 pci_device; //PCI device ID; vendor is always Broadcom (0x14E4)
+ u8 unknown1[8]; //?, noticed no effect
+ u16 basic_config; //?, see below
+ u8 checksum; //byte sum of header == 0
+ u8 unknown2; //?, patch rejected if changed
+ u16 patch_version; //10-8: major; 7-0: minor; 15-11: variant (1=a, 2=b, ...)
+ } header;
+
+ struct { /* Init code */
+ u8 checksum; //byte sum of init == 0
+ u8 unknown; //?, looks unused
+ u8 num_hunks; //0x60 = 3 hunks, 0x80 = 4 hunks, other values not supported
+ u8 size; //total size of all hunk#_code[] in bytes
+ u8 hunk1_when; //mark when hunk1_code gets executed
+ u8 hunk1_size; //sizeof(hunk1_code)
+ u8 hunk2_when;
+ u8 hunk2_size;
+ u8 hunk3_when;
+ u8 hunk3_size;
+ u8 hunk4_when; //0x00 (padding) if only 3 hunks
+ u8 hunk4_size; //dito
+ u32 hunk1_code[INIT1_LENGTH]; //actual commands, see below
+ u32 hunk2_code[INIT2_LENGTH];
+ u32 hunk3_code[INIT3_LENGTH];
+ u32 hunk4_code[INIT4_LENGTH]; //missing (zero length) if only 3 hunks
+ } init;
+
+ struct { /* Power down code */
+ u8 checksum; //byte sum of powerdown == 0
+ u8 unknown; //?, looks unused
+ u8 num_hunks; //0x20 = 1 hunk, other values not supported
+ u8 size; //total size of all hunk#_code[] in bytes
+ u8 hunk1_when; //mark when hunk1_code gets executed
+ u8 hunk1_size; //sizeof(hunk1_code)
+ u16 padding; //0x0000, hunk2 is not supported
+ u32 hunk1_code[PWRDN_LENGTH]; //commands, see below
+ } powerdown;
+
+} selfboot_patch = {
+
+/* Keep the following invariant for valid Selfboot patches */
+ .header.signature = 0xA5,
+ .header.format = 0x23, //format 1 revision 3
+ .header.unknown1 = { 0x61, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .header.checksum = 0, //calculated later
+ .header.unknown2 = 0x30,
+ .init.checksum = 0, //calculated later
+ .init.unknown = 0x00,
+ .init.num_hunks = sizeof(selfboot_patch.init.hunk4_code) ? 0x80 : 0x60,
+ .init.size = sizeof(selfboot_patch.init.hunk1_code)
+ + sizeof(selfboot_patch.init.hunk2_code)
+ + sizeof(selfboot_patch.init.hunk3_code)
+ + sizeof(selfboot_patch.init.hunk4_code),
+ .init.hunk1_size = sizeof(selfboot_patch.init.hunk1_code),
+ .init.hunk2_size = sizeof(selfboot_patch.init.hunk2_code),
+ .init.hunk3_size = sizeof(selfboot_patch.init.hunk3_code),
+ .init.hunk4_size = sizeof(selfboot_patch.init.hunk4_code),
+ .powerdown.checksum = 0, //calculated later
+ .powerdown.unknown = 0x00,
+ .powerdown.num_hunks = 0x20,
+ .powerdown.size = sizeof(selfboot_patch.powerdown.hunk1_code),
+ .powerdown.hunk1_size = sizeof(selfboot_patch.powerdown.hunk1_code),
+ .powerdown.padding = be16(0x0000),
+
+/* Only the lines below may be adapted to your needs ... */
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ .header.mac_addr = { 0x00, 0x10, 0x18, 0x00, 0x00, 0x00 }, //Broadcom
+ .header.subsys_device = be16(0x1699), //same as pci_device
+ .header.subsys_vendor = be16(0x14E4), //Broadcom
+#else
+ .header.mac_addr = { 0x00, 0x20, 0x9D, 0x00, 0x00, 0x00 }, //LiPPERT
+ .header.subsys_device = be16(0x1699), //simply kept this
+ .header.subsys_vendor = be16(0x121D), //LiPPERT
+#endif
+ .header.pci_device = be16(0x1699), //Broadcom 5785 with GbE PHY
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ .header.patch_version = be16(0x010B), //1.11 (Broadcom's sb5785m1.11)
+#else
+ .header.patch_version = be16(0x110B), //1.11b, i.e. hacked :-)
+#endif
+ /* Bitfield enabling general features/codepaths in the firmware or
+ * selecting support for one of several supported PHYs?
+ * Bits not listed had no appearent effect:
+ * 14-11: any bit 1=firmware execution seemed delayed
+ * 10: 0=firmware execution seemed delayed
+ * 9,2,0: select PHY type, affects these registers, probably more
+ * 9 2 0 | reg 0x05A4 PHY reg 31 PHY 23,24,28 Notes
+ * -------+----------------------------------------------------------
+ * 0 0 0 | 0x331C71C1 - changed Inband Status enabled
+ * 0 1 0 | 0x3210C500 - changed -
+ * 0 X 1 | 0x33FF66C0 changed - 10/100 Mbit only
+ * 1 X 0 | 0x330C5180 - - -
+ * 1 X 1 | 0x391C6140 - - -
+ */
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ .header.basic_config = be16(0x0404), //original for B50610
+#else
+ .header.basic_config = be16(0x0604), //bit 9 set so not to mess up PHY regs, kept other bits unchanged
+#endif
+
+ /* Tag that defines when / on what occasion the commands are interpreted.
+ * Bits 2-0 = 0 i.e. possible values are 0x00, 08, 10, ..., F8.
+ * On a RISC CPU reset every tag except 0x38, A0, F0, F8 is used. 0x38
+ * seems to be run before a reset is performed(?), the other 3 I have
+ * never seen used. Generally, lower values appear to be run earlier.
+ * An "ifconfig up" with Linux' "tg3" driver causes the tags 0x50, 60,
+ * 68, 20, 70, 80 to be interpreted in this order.
+ * All tests were performed with .basic_config=0x0604.
+ */
+ .init.hunk1_when = 0x10, //only once at RISC CPU reset?
+ /* Instructions are obviously a specialized bytecode interpreted by the
+ * main firmware, rather than MIPS machine code. Commands consist of 1-3
+ * 32-bit words. In the following, 0-9,A-F = hex literals, a-z,_ = variable
+ * parts, each character = 4 bits.
+ * 0610offs newvalue: write (32-bit) <newvalue> to 5785-internal shared mem at <offs>
+ * 08rgvalu: write <valu> to PHY register, <rg> = 0x20 + register number
+ * C610rgnr newvalue: write <newvalue> to MAC register <rgnr>
+ * C1F0rgnr andvalue or_value: modify MAC register <rgnr> by ANDing with <andvalue> and then ORing with <or_value>
+ * C4btrgnr: clear bit in 32-bit MAC register <rgnr>, <bt> = bit number << 3
+ * C3btrgnr: set bit, see C4...; example: command 0xC3200454 sets bit 4 of 32-bit register 0x0454
+ * CBbtrgnr: run next command only if bit (see C4...) == 1 (so far only seen before F7F0...)
+ * F7F0skip: unconditional jump i.e. skip next <skip> code bytes (only seen small positive <skip>)
+ * F7Fxaddr: call function at <addr> in main firmware? <x> = 3 or 4, bool parameter?? Wild guess!
+ * F7FFFadr somvalue: also call func. at <adr>, but with <somvalue> as parameter?? More guessing!
+ * More commands probably exist, but all code I've ever seen was kept
+ * included below, commented out if not suitable for the CFR-AF. v1.xx
+ * is Broadcom's Selfboot patch version sb5785m1.xx where the command
+ * was added, for reference see Broadcom's changelog.
+ */
+ .init.hunk1_code = {
+#if CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ be(0x082B8104), //CFR-AF: PHY0B: KSZ9021 select PHY104
+ be(0x082CF0F0), //CFR-AF: PHY0C: KSZ9021 clk/ctl skew (advised by Micrel)
+ be(0x082B8105), //CFR-AF: PHY0B: KSZ9021 select PHY105
+ be(0x082C3333), //CFR-AF: PHY0C: KSZ9021 RX data skew (empirical)
+#endif
+ be(0xC1F005A0), be(0xFEFFEFFF), be(0x01001000), //v1.05 : 5A0.24,12=1: auto-clock-switch
+ be(0x06100D34), be(0x00000000), //v1.03 : MemD34: clear config vars
+ be(0x06100D38), be(0x00000000), //v1.03 : - |
+ be(0x06100D3C), be(0x00000000), //v1.03 : MemD3F|
+ }, //-->INIT1_LENGTH!
+
+ .init.hunk2_when = 0x30, //after global reset, PHY reset
+ .init.hunk2_code = {
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ be(0x08370F08), //v1.06 : PHY17: B50610 select reg. 08
+ be(0x08350001), //v1.06 : PHY15: B50610 slow link fix
+ be(0x08370F00), //v1.06 : PHY17: B50610 disable reg. 08
+ be(0x083C2C00), //v1.11 : PHY1C: B50610 Shadow 0B
+#endif
+ be(0xF7F301E6), //v1.09+: ?: subroutine calls to
+ be(0xF7FFF0B6), be(0x0000FFE7), //v1.09+: ?| restore Port Mode ???
+ be(0xF7FFF0F6), be(0x00008000), //v1.09+: ?|
+ be(0xF7F401E6), //v1.09+: ?|
+ }, //-->INIT2_LENGTH!
+
+ .init.hunk3_when = 0xA8, //?, I'd guess quite late
+ .init.hunk3_code = {
+ be(0xC1F03604), be(0xFFE0FFFF), be(0x00110000), //v1.08 : 3604.20-16: 10Mb clock = 12.5MHz
+ }, //-->INIT3_LENGTH!
+
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ .init.hunk4_when = 0xD8, //original for B50610
+#else
+ .init.hunk4_when = 0x80, //run last, after Linux' "ifconfig up"
+#endif
+ .init.hunk4_code = {
+#if CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ be(0x083F4300), //CFR-AF: PHY1F: IRQ active high
+ be(0x083C0000), //CFR-AF: PHY1C: revert driver writes
+ be(0x08380000), //CFR-AF: PHY18|
+ be(0x083C0000), //CFR-AF: PHY1C|
+#endif
+ be(0xCB0005A4), be(0xF7F0000C), //v1.01 : if 5A4.0==1 -->skip next 12 bytes
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ be(0xC61005A4), be(0x3210C500), //v1.01 : 5A4: PHY LED mode
+#else
+ be(0xC61005A4), be(0x331C71CE), //CFR-AF: 5A4: fake LED mode
+#endif
+ be(0xF7F00008), //v1.01 : -->skip next 8 bytes
+ be(0xC61005A4), be(0x331C71C1), //v1.01 : 5A4: inband LED mode
+ //be(0xC3200454), //CFR-AF: 454.4: auto link polling
+ }, //-->INIT4_LENGTH!
+
+ .powerdown.hunk1_when = 0x50, //prior to IDDQ MAC
+ .powerdown.hunk1_code = {
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ be(0x083CB001), //v1.10 : PHY1C: IDDQ B50610 PHY
+#endif
+ be(0xF7F30116), // IDDQ PHY
+ be(0xC40005A0), //v1.09 : 5A0.0=0: Port Mode = MII
+ be(0xC4180400), //v1.09 : 400.3=0|
+ be(0xC3100400), //v1.09 : 400.2=1|
+ }, //-->PWRDN_LENGTH!
+
+};
+
+/* Upload 'NV'RAM contents for BCM5785 GbE MAC integrated in A55E.
+ * Call this from mainboard.c.
+ */
+void broadcom_init(void)
+{
+ volatile u32 *gec_base; //Gigabit Ethernet Controller base addr
+ u8 *gec_shadow; //base addr of shadow 'NV'RAM for GbE MAC in A55E
+ u8 sum;
+ int i;
+
+ gec_base = (u32*)(long)dev_find_slot(0, PCI_DEVFN(0x14, 6))->resource_list->base;
+ gec_shadow = (u8*)(pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x14, 3)), 0x9C) & 0xFFFFFC00);
+ printk(BIOS_DEBUG, "Upload GbE 'NV'RAM contents @ 0x%08lx\n", (unsigned long)gec_shadow);
+
+ /* Halt RISC CPU before uploading the firmware patch */
+ for (i=10000; i > 0; i--) {
+ gec_base[0x5004/4] = 0xFFFFFFFF; //clear CPU state
+ gec_base[0x5000/4] |= (1<<10); //issue RISC halt
+ if (gec_base[0x5000/4] | (1<<10))
+ break;
+ udelay(10);
+ }
+ if (!i)
+ printk(BIOS_ERR, "Failed to halt RISC CPU!\n");
+
+ /* Calculate checksums (standard byte sum) */
+ for (sum = 0, i = 0; i < sizeof(selfboot_patch.header); i++)
+ sum -= ((u8*)&selfboot_patch.header)[i];
+ selfboot_patch.header.checksum = sum;
+ for (sum = 0, i = 0; i < sizeof(selfboot_patch.init); i++)
+ sum -= ((u8*)&selfboot_patch.init)[i];
+ selfboot_patch.init.checksum = sum;
+ for (sum = 0, i = 0; i < sizeof(selfboot_patch.powerdown); i++)
+ sum -= ((u8*)&selfboot_patch.powerdown)[i];
+ selfboot_patch.powerdown.checksum = sum;
+
+ /* Upload firmware patch to shadow 'NV'RAM */
+ for (i = 0; i < sizeof(selfboot_patch); i++)
+ gec_shadow[i] = ((u8*)&selfboot_patch)[i]; //access byte-wise!
+
+ /* Restart BCM5785's CPU */
+ gec_base[0x5004/4] = 0xFFFFFFFF; //clear CPU state
+ gec_base[0x5000/4] = 0x00000001; //reset RISC processor
+ //usually we'd have to wait for the reset bit to clear again ...
+}
diff --git a/src/mainboard/amd/inagua/mainboard.c b/src/mainboard/amd/inagua/mainboard.c
index 8e92d6a..dc23007 100644
--- a/src/mainboard/amd/inagua/mainboard.c
+++ b/src/mainboard/amd/inagua/mainboard.c
@@ -27,6 +27,7 @@
#include <southbridge/amd/sb800/sb800.h>
#include "SBPLATFORM.h" /* Platfrom Specific Definitions */
+void broadcom_init(void);
void set_pcie_reset(void);
void set_pcie_dereset(void);
@@ -88,6 +89,10 @@ static void mainboard_enable(device_t dev)
*/
pm_iowrite(0x29, 0x80);
pm_iowrite(0x28, 0x61);
+
+ /* Upload AMD A55E GbE 'NV'RAM contents. Still untested on Inagua.
+ * After anyone can confirm it works please uncomment the call. */
+ //broadcom_init();
}
struct chip_operations mainboard_ops = {
Jens Rottmann (JRottmann(a)LiPPERTembedded.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2581
-gerrit
commit 37bd1d9510f08f60b4f87477fbc70a6ae1e6ed51
Author: Jens Rottmann <JRottmann(a)LiPPERTembedded.de>
Date: Fri Mar 1 19:41:41 2013 +0100
AMD Inagua: add GEC firmware, document Broadcom BCM57xx Selfboot Patch format
The Broadcom BCM5785 GbE MAC integrated in the AMD Hudson-E1 requires a
secret sauce firmware blob to work. As Broadcom wasn't willing to send us
any documentation (or a firmware adapted to our Micrel PHY) I had to figure
out everything by myself in many weeks of hard detective work.
In the end we had to settle for a different solution, the modified firmware
I devised for the Micrel KSZ9021 PHY on our early FrontRunner-AF prototypes
is no longer needed for the production version. However the information
contained here might be very useful for others who'd like to use a
competing PHY instead of Broadcom's 50610, so it should not get lost.
And of course the unmodified, but now in large parts documented Selfboot
Patch is needed to get Ethernet on AMD Inagua. The code introduced here
should make the Hudson's internal MAC usable without having to add the
proprietary firmware blob. - At least in theory.
Unfortunately we've been unable to actually test this patch on Inagua,
therefore the broadcom_init() call in mainboard.c was left commented out.
If you have the hardware and can confirm it works please enable it.
The fun thing is: as Broadcom refused to do any business with us at all,
or send us any documentation, we never had to sign an NDA with them. This
leaves me free to publish everything I have found out. :-)
Change-Id: Ifa628751d14143f277b27cfd34b1d2771ca1302f
Signed-off-by: Jens Rottmann <JRottmann(a)LiPPERTembedded.de>
---
src/mainboard/amd/inagua/Makefile.inc | 2 +-
src/mainboard/amd/inagua/broadcom.c | 360 ++++++++++++++++++++++++++++++++++
src/mainboard/amd/inagua/mainboard.c | 5 +
3 files changed, 366 insertions(+), 1 deletion(-)
diff --git a/src/mainboard/amd/inagua/Makefile.inc b/src/mainboard/amd/inagua/Makefile.inc
index 17443bc..b84a03a 100644
--- a/src/mainboard/amd/inagua/Makefile.inc
+++ b/src/mainboard/amd/inagua/Makefile.inc
@@ -35,4 +35,4 @@ ramstage-y += BiosCallOuts.c
ramstage-y += PlatformGnbPcie.c
ramstage-y += reset.c
-
+ramstage-y += broadcom.c
diff --git a/src/mainboard/amd/inagua/broadcom.c b/src/mainboard/amd/inagua/broadcom.c
new file mode 100644
index 0000000..357fdbc
--- /dev/null
+++ b/src/mainboard/amd/inagua/broadcom.c
@@ -0,0 +1,360 @@
+/*
+ * Initialize Broadcom 5785 GbE MAC embedded in AMD A55E (Hudson-E1) Southbridge
+ * by uploading a Selfboot Patch to the A55E's shadow ROM area. The patch
+ * itself supports the Broadcom 50610(M) PHY on the AMD Inagua. It is
+ * equivalent to Broadcom's SelfBoot patch V1.11 (sb5785m1.11).
+ * A modified variant, selected by CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF supports
+ * the Micrel KSZ9021 PHY that was used on LiPPERT FrontRunner-AF (CFR-AF)
+ * revision 0v0, the first prototype. The board is history and this code now
+ * serves only to document the proprietary Selfboot Patch format and how to
+ * adapt it to a PHY unsupported by Broadcom.
+ *
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 LiPPERT ADLINK Technology GmbH
+ * (Written by Jens Rottmann <JRottmann(a)LiPPERTembedded.de>)
+ *
+ * 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 <types.h>
+#include <arch/byteorder.h>
+#include <console/console.h>
+#include <device/device.h> //Coreboot device access
+#include <device/pci.h>
+#include <delay.h>
+
+#define be16(x) cpu_to_be16(x) //a little easier to type
+#define be(x) cpu_to_be32(x) //this is used a lot!
+
+/* C forces us to specify these before defining struct selfboot_patch :-( */
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+#define INIT1_LENGTH 9
+#define INIT2_LENGTH 10
+#define INIT3_LENGTH 3
+#define INIT4_LENGTH 7 //this one may be 0
+#define PWRDN_LENGTH 5
+#else
+#define INIT1_LENGTH 13
+#define INIT2_LENGTH 6
+#define INIT3_LENGTH 3
+#define INIT4_LENGTH 11 //this one may be 0
+#define PWRDN_LENGTH 4
+#endif
+
+
+/* The AMD A55E (Hudson-E1) Southbridge contains an integrated Gigabit Ethernet
+ * MAC, however AMD's documentation merely defines the related balls (without
+ * fully describing their function) and states that only Broadcom 50610(M) PHYs
+ * will be supported, that's all. The Hudson register reference skips all MAC
+ * registers entirely, even AMD support doesn't seem to know more about it.
+ *
+ * As Broadcom refused to sell us any 50610 chips or provide any docs (or indeed
+ * even a price list) below $100K expected sales we had to figure out everything
+ * by ourselves. *Everything* below is the result of months of detective work,
+ * documented here lest it get lost:
+ *
+ * The AMD A55E's GbE MAC is a Broadcom 5785, which AMD obviously licensed as IP
+ * core. It uses a standard RGMII/MII interface and the Broadcom drivers will
+ * recognize it by its unchanged PCI ID 14E4:1699, however there are some
+ * specialties.
+ *
+ * The 5785 MAC can detect the link with 4 additional inputs, "phy_status[3:0]",
+ * 'snooping' on the PHY's LED outputs. Interpretation of the LEDs' patterns is
+ * programmed with register 0x5A4 of the MAC. AMD renamed them to "GBE_STAT" and
+ * won't say anything about their purpose. Appearently hardware designers are
+ * expected to blindly copy the Inagua reference schematic: GBE_STAT2:
+ * 0=activity; GBE_STAT[1:0]: 11=no link, 10=10Mbit, 01=100Mbit, 00=1Gbit.
+ *
+ * For package processing the 5785 also features a MIPS-based RISC CPU, booting
+ * from an internal ROM. The firmware loads config data and supplements (e.g. to
+ * support specific PHYs), named "Selfboot Patches", via the "NVRAM Interface",
+ * usually from an external EEPROM. The A55E doesn't have any balls for an ext.
+ * EEPROM, instead AMD added a small internal RAM. The BIOS is expected to copy
+ * the correct contents into this RAM (which only supports byte access!) upon
+ * each powerup. The A55E can trigger an SMI upon writes, enabling the BIOS to
+ * forward any changes to an actually 'NV' location, e.g. the BIOS's SPI flash,
+ * behind the scenes. AMD calls it "GEC shadow ROM", not describing what it's
+ * for nor mentioning the term "NVRAM". broadcom_init() below documents a
+ * procedure how to upload the patch. No SMI magic is installed, therefore
+ * 'NV'RAM writes won't be persistent.
+ *
+ * The "Selfboot Patch" can execute simple commands at various points during
+ * main firmware execution. This can be used to change config registers,
+ * initialize a specific PHY or work around firmware bugs. Broadcom provides
+ * suitable Patches only for their AC131 and 50610 PHYs (as binary blobs). I
+ * found them in DOS\sb_patch\5785\*\sb5785*.* in Driver_14_6_4_2.zip. (Note
+ * that every 32bit-word of these files must be byte-swapped before uploading
+ * them to the A55E.)
+ *
+ * Below is a derived Patch supporting the Micrel KSZ9021 PHY used on the
+ * LiPPERT CFR-AF PC/104 SBC instead, with detailled description of the format.
+ * (Here in correct order for upload.)
+ *
+ * This Patch made Ethernet work with Linux 3.3 - without having to modify the
+ * tg3.ko driver. Broadcom's Windows-Drivers still fail with "Code 10" however;
+ * disassembly showed they check the PHY ID and abort, because the Micrel PHY is
+ * not supported.
+ */
+
+static struct selfboot_patch { //Watch out: all values are *BIG-ENDIAN*!
+
+ struct { /* Global header */
+ u8 signature; //0xA5
+ u8 format; //bits 7-3: patch format; 2-0: revision
+ u8 mac_addr[6];
+ u16 subsys_device; //IDs will be loaded into PCI config space
+ u16 subsys_vendor;
+ u16 pci_device; //PCI device ID; vendor is always Broadcom (0x14E4)
+ u8 unknown1[8]; //?, noticed no effect
+ u16 basic_config; //?, see below
+ u8 checksum; //byte sum of header == 0
+ u8 unknown2; //?, patch rejected if changed
+ u16 patch_version; //10-8: major; 7-0: minor; 15-11: variant (1=a, 2=b, ...)
+ } header;
+
+ struct { /* Init code */
+ u8 checksum; //byte sum of init == 0
+ u8 unknown; //?, looks unused
+ u8 num_hunks; //0x60 = 3 hunks, 0x80 = 4 hunks, other values not supported
+ u8 size; //total size of all hunk#_code[] in bytes
+ u8 hunk1_when; //mark when hunk1_code gets executed
+ u8 hunk1_size; //sizeof(hunk1_code)
+ u8 hunk2_when;
+ u8 hunk2_size;
+ u8 hunk3_when;
+ u8 hunk3_size;
+ u8 hunk4_when; //0x00 (padding) if only 3 hunks
+ u8 hunk4_size; //dito
+ u32 hunk1_code[INIT1_LENGTH]; //actual commands, see below
+ u32 hunk2_code[INIT2_LENGTH];
+ u32 hunk3_code[INIT3_LENGTH];
+ u32 hunk4_code[INIT4_LENGTH]; //missing (zero length) if only 3 hunks
+ } init;
+
+ struct { /* Power down code */
+ u8 checksum; //byte sum of powerdown == 0
+ u8 unknown; //?, looks unused
+ u8 num_hunks; //0x20 = 1 hunk, other values not supported
+ u8 size; //total size of all hunk#_code[] in bytes
+ u8 hunk1_when; //mark when hunk1_code gets executed
+ u8 hunk1_size; //sizeof(hunk1_code)
+ u16 padding; //0x0000, hunk2 is not supported
+ u32 hunk1_code[PWRDN_LENGTH]; //commands, see below
+ } powerdown;
+
+} selfboot_patch = {
+
+/* Keep the following invariant for valid Selfboot patches */
+ .header.signature = 0xA5,
+ .header.format = 0x23, //format 1 revision 3
+ .header.unknown1 = { 0x61, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ .header.checksum = 0, //calculated later
+ .header.unknown2 = 0x30,
+ .init.checksum = 0, //calculated later
+ .init.unknown = 0x00,
+ .init.num_hunks = sizeof(selfboot_patch.init.hunk4_code) ? 0x80 : 0x60,
+ .init.size = sizeof(selfboot_patch.init.hunk1_code)
+ + sizeof(selfboot_patch.init.hunk2_code)
+ + sizeof(selfboot_patch.init.hunk3_code)
+ + sizeof(selfboot_patch.init.hunk4_code),
+ .init.hunk1_size = sizeof(selfboot_patch.init.hunk1_code),
+ .init.hunk2_size = sizeof(selfboot_patch.init.hunk2_code),
+ .init.hunk3_size = sizeof(selfboot_patch.init.hunk3_code),
+ .init.hunk4_size = sizeof(selfboot_patch.init.hunk4_code),
+ .powerdown.checksum = 0, //calculated later
+ .powerdown.unknown = 0x00,
+ .powerdown.num_hunks = 0x20,
+ .powerdown.size = sizeof(selfboot_patch.powerdown.hunk1_code),
+ .powerdown.hunk1_size = sizeof(selfboot_patch.powerdown.hunk1_code),
+ .powerdown.padding = be16(0x0000),
+
+/* Only the lines below may be adapted to your needs ... */
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ .header.mac_addr = { 0x00, 0x10, 0x18, 0x00, 0x00, 0x00 }, //Broadcom
+ .header.subsys_device = be16(0x1699), //same as pci_device
+ .header.subsys_vendor = be16(0x14E4), //Broadcom
+#else
+ .header.mac_addr = { 0x00, 0x20, 0x9D, 0x00, 0x00, 0x00 }, //LiPPERT
+ .header.subsys_device = be16(0x1699), //simply kept this
+ .header.subsys_vendor = be16(0x121D), //LiPPERT
+#endif
+ .header.pci_device = be16(0x1699), //Broadcom 5785 with GbE PHY
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ .header.patch_version = be16(0x010B), //1.11 (Broadcom's sb5785m1.11)
+#else
+ .header.patch_version = be16(0x110B), //1.11b, i.e. hacked :-)
+#endif
+ /* Bitfield enabling general features/codepaths in the firmware or
+ * selecting support for one of several supported PHYs?
+ * Bits not listed had no appearent effect:
+ * 14-11: any bit 1=firmware execution seemed delayed
+ * 10: 0=firmware execution seemed delayed
+ * 9,2,0: select PHY type, affects these registers, probably more
+ * 9 2 0 | reg 0x05A4 PHY reg 31 PHY 23,24,28 Notes
+ * -------+----------------------------------------------------------
+ * 0 0 0 | 0x331C71C1 - changed Inband Status enabled
+ * 0 1 0 | 0x3210C500 - changed -
+ * 0 X 1 | 0x33FF66C0 changed - 10/100 Mbit only
+ * 1 X 0 | 0x330C5180 - - -
+ * 1 X 1 | 0x391C6140 - - -
+ */
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ .header.basic_config = be16(0x0404), //original for B50610
+#else
+ .header.basic_config = be16(0x0604), //bit 9 set so not to mess up PHY regs, kept other bits unchanged
+#endif
+
+ /* Tag that defines when / on what occasion the commands are interpreted.
+ * Bits 2-0 = 0 i.e. possible values are 0x00, 08, 10, ..., F8.
+ * On a RISC CPU reset every tag except 0x38, A0, F0, F8 is used. 0x38
+ * seems to be run before a reset is performed(?), the other 3 I have
+ * never seen used. Generally, lower values appear to be run earlier.
+ * An "ifconfig up" with Linux' "tg3" driver causes the tags 0x50, 60,
+ * 68, 20, 70, 80 to be interpreted in this order.
+ * All tests were performed with .basic_config=0x0604.
+ */
+ .init.hunk1_when = 0x10, //only once at RISC CPU reset?
+ /* Instructions are obviously a specialized bytecode interpreted by the
+ * main firmware, rather than MIPS machine code. Commands consist of 1-3
+ * 32-bit words. In the following, 0-9,A-F = hex literals, a-z,_ = variable
+ * parts, each character = 4 bits.
+ * 0610offs newvalue: write (32-bit) <newvalue> to 5785-internal shared mem at <offs>
+ * 08rgvalu: write <valu> to PHY register, <rg> = 0x20 + register number
+ * C610rgnr newvalue: write <newvalue> to MAC register <rgnr>
+ * C1F0rgnr andvalue or_value: modify MAC register <rgnr> by ANDing with <andvalue> and then ORing with <or_value>
+ * C4btrgnr: clear bit in 32-bit MAC register <rgnr>, <bt> = bit number << 3
+ * C3btrgnr: set bit, see C4...; example: command 0xC3200454 sets bit 4 of 32-bit register 0x0454
+ * CBbtrgnr: run next command only if bit (see C4...) == 1 (so far only seen before F7F0...)
+ * F7F0skip: unconditional jump i.e. skip next <skip> code bytes (only seen small positive <skip>)
+ * F7Fxaddr: call function at <addr> in main firmware? <x> = 3 or 4, bool parameter?? Wild guess!
+ * F7FFFadr somvalue: also call func. at <adr>, but with <somvalue> as parameter?? More guessing!
+ * More commands probably exist, but all code I've ever seen was kept
+ * included below, commented out if not suitable for the CFR-AF. v1.xx
+ * is Broadcom's Selfboot patch version sb5785m1.xx where the command
+ * was added, for reference see Broadcom's changelog.
+ */
+ .init.hunk1_code = {
+#if CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ be(0x082B8104), //CFR-AF: PHY0B: KSZ9021 select PHY104
+ be(0x082CF0F0), //CFR-AF: PHY0C: KSZ9021 clk/ctl skew (advised by Micrel)
+ be(0x082B8105), //CFR-AF: PHY0B: KSZ9021 select PHY105
+ be(0x082C3333), //CFR-AF: PHY0C: KSZ9021 RX data skew (empirical)
+#endif
+ be(0xC1F005A0), be(0xFEFFEFFF), be(0x01001000), //v1.05 : 5A0.24,12=1: auto-clock-switch
+ be(0x06100D34), be(0x00000000), //v1.03 : MemD34: clear config vars
+ be(0x06100D38), be(0x00000000), //v1.03 : - |
+ be(0x06100D3C), be(0x00000000), //v1.03 : MemD3F|
+ }, //-->INIT1_LENGTH!
+
+ .init.hunk2_when = 0x30, //after global reset, PHY reset
+ .init.hunk2_code = {
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ be(0x08370F08), //v1.06 : PHY17: B50610 select reg. 08
+ be(0x08350001), //v1.06 : PHY15: B50610 slow link fix
+ be(0x08370F00), //v1.06 : PHY17: B50610 disable reg. 08
+ be(0x083C2C00), //v1.11 : PHY1C: B50610 Shadow 0B
+#endif
+ be(0xF7F301E6), //v1.09+: ?: subroutine calls to
+ be(0xF7FFF0B6), be(0x0000FFE7), //v1.09+: ?| restore Port Mode ???
+ be(0xF7FFF0F6), be(0x00008000), //v1.09+: ?|
+ be(0xF7F401E6), //v1.09+: ?|
+ }, //-->INIT2_LENGTH!
+
+ .init.hunk3_when = 0xA8, //?, I'd guess quite late
+ .init.hunk3_code = {
+ be(0xC1F03604), be(0xFFE0FFFF), be(0x00110000), //v1.08 : 3604.20-16: 10Mb clock = 12.5MHz
+ }, //-->INIT3_LENGTH!
+
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ .init.hunk4_when = 0xD8, //original for B50610
+#else
+ .init.hunk4_when = 0x80, //run last, after Linux' "ifconfig up"
+#endif
+ .init.hunk4_code = {
+#if CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ be(0x083F4300), //CFR-AF: PHY1F: IRQ active high
+ be(0x083C0000), //CFR-AF: PHY1C: revert driver writes
+ be(0x08380000), //CFR-AF: PHY18|
+ be(0x083C0000), //CFR-AF: PHY1C|
+#endif
+ be(0xCB0005A4), be(0xF7F0000C), //v1.01 : if 5A4.0==1 -->skip next 12 bytes
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ be(0xC61005A4), be(0x3210C500), //v1.01 : 5A4: PHY LED mode
+#else
+ be(0xC61005A4), be(0x331C71CE), //CFR-AF: 5A4: fake LED mode
+#endif
+ be(0xF7F00008), //v1.01 : -->skip next 8 bytes
+ be(0xC61005A4), be(0x331C71C1), //v1.01 : 5A4: inband LED mode
+ //be(0xC3200454), //CFR-AF: 454.4: auto link polling
+ }, //-->INIT4_LENGTH!
+
+ .powerdown.hunk1_when = 0x50, //prior to IDDQ MAC
+ .powerdown.hunk1_code = {
+#if !CONFIG_BOARD_LIPPERT_FRONTRUNNER_AF
+ be(0x083CB001), //v1.10 : PHY1C: IDDQ B50610 PHY
+#endif
+ be(0xF7F30116), // IDDQ PHY
+ be(0xC40005A0), //v1.09 : 5A0.0=0: Port Mode = MII
+ be(0xC4180400), //v1.09 : 400.3=0|
+ be(0xC3100400), //v1.09 : 400.2=1|
+ }, //-->PWRDN_LENGTH!
+
+};
+
+/* Upload 'NV'RAM contents for BCM5785 GbE MAC integrated in A55E.
+ * Call this from mainboard.c.
+ */
+void broadcom_init(void)
+{
+ volatile u32 *gec_base; //Gigabit Ethernet Controller base addr
+ u8 *gec_shadow; //base addr of shadow 'NV'RAM for GbE MAC in A55E
+ u8 sum;
+ int i;
+
+ gec_base = (u32*)(long)dev_find_slot(0, PCI_DEVFN(0x14, 6))->resource_list->base;
+ gec_shadow = (u8*)(pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x14, 3)), 0x9C) & 0xFFFFFC00);
+ printk(BIOS_DEBUG, "Upload GbE 'NV'RAM contents @ 0x%08lx\n", (unsigned long)gec_shadow);
+
+ /* Halt RISC CPU before uploading the firmware patch */
+ for (i=10000; i > 0; i--) {
+ gec_base[0x5004/4] = 0xFFFFFFFF; //clear CPU state
+ gec_base[0x5000/4] |= (1<<10); //issue RISC halt
+ if (gec_base[0x5000/4] | (1<<10))
+ break;
+ udelay(10);
+ }
+ if (!i)
+ printk(BIOS_ERR, "Failed to halt RISC CPU!\n");
+
+ /* Calculate checksums (standard byte sum) */
+ for (sum = 0, i = 0; i < sizeof(selfboot_patch.header); i++)
+ sum -= ((u8*)&selfboot_patch.header)[i];
+ selfboot_patch.header.checksum = sum;
+ for (sum = 0, i = 0; i < sizeof(selfboot_patch.init); i++)
+ sum -= ((u8*)&selfboot_patch.init)[i];
+ selfboot_patch.init.checksum = sum;
+ for (sum = 0, i = 0; i < sizeof(selfboot_patch.powerdown); i++)
+ sum -= ((u8*)&selfboot_patch.powerdown)[i];
+ selfboot_patch.powerdown.checksum = sum;
+
+ /* Upload firmware patch to shadow 'NV'RAM */
+ for (i = 0; i < sizeof(selfboot_patch); i++)
+ gec_shadow[i] = ((u8*)&selfboot_patch)[i]; //access byte-wise!
+
+ /* Restart BCM5785's CPU */
+ gec_base[0x5004/4] = 0xFFFFFFFF; //clear CPU state
+ gec_base[0x5000/4] = 0x00000001; //reset RISC processor
+ //usually we'd have to wait for the reset bit to clear again ...
+}
diff --git a/src/mainboard/amd/inagua/mainboard.c b/src/mainboard/amd/inagua/mainboard.c
index 8e92d6a..dc23007 100644
--- a/src/mainboard/amd/inagua/mainboard.c
+++ b/src/mainboard/amd/inagua/mainboard.c
@@ -27,6 +27,7 @@
#include <southbridge/amd/sb800/sb800.h>
#include "SBPLATFORM.h" /* Platfrom Specific Definitions */
+void broadcom_init(void);
void set_pcie_reset(void);
void set_pcie_dereset(void);
@@ -88,6 +89,10 @@ static void mainboard_enable(device_t dev)
*/
pm_iowrite(0x29, 0x80);
pm_iowrite(0x28, 0x61);
+
+ /* Upload AMD A55E GbE 'NV'RAM contents. Still untested on Inagua.
+ * After anyone can confirm it works please uncomment the call. */
+ //broadcom_init();
}
struct chip_operations mainboard_ops = {
Kimarie Hoot (kimarie.hoot(a)se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2830
-gerrit
commit 64d91936c509bd95c8d628d41eedf54ae8c6ea0d
Author: Kimarie Hoot <kimarie.hoot(a)se-eng.com>
Date: Thu Mar 7 17:12:36 2013 -0700
AMD Dinar: Use SPD read code from F15 wrapper
Changes:
- Get rid of the dinar mainboard specific code and use the
platform generic function wrapper that was added in change
http://review.coreboot.org/#/c/2777/
AMD Fam15: Add SPD read functions to wrapper code
- Move DIMM addresses into devicetree.cb
Notes:
- The DIMM reads only happen in romstage, so the function is not
available in ramstage. Point the read-SPD callback to a generic
function in ramstage.
- select_socket() and restore_socket() were created from code that
was removed from AmdMemoryReadSPD() in dimmSpd.c. The functionality
is specific to the dinar mainboard configuration and was therefore
split from the generic read SPD functionality.
Change-Id: I1e4b9a20dc497c15dbde6d89865bd5ee7501cdc0
Signed-off-by: Kimarie Hoot <kimarie.hoot(a)se-eng.com>
---
src/mainboard/amd/dinar/BiosCallOuts.c | 62 +++++-
src/mainboard/amd/dinar/Makefile.inc | 2 -
src/mainboard/amd/dinar/devicetree.cb | 6 +
src/mainboard/amd/dinar/dimmSpd.c | 333 ---------------------------------
4 files changed, 67 insertions(+), 336 deletions(-)
diff --git a/src/mainboard/amd/dinar/BiosCallOuts.c b/src/mainboard/amd/dinar/BiosCallOuts.c
index a1c89df..4fb3c66 100644
--- a/src/mainboard/amd/dinar/BiosCallOuts.c
+++ b/src/mainboard/amd/dinar/BiosCallOuts.c
@@ -24,6 +24,8 @@
#include "OptionsIds.h"
#include "heapManager.h"
#include "SB700.h"
+#include <northbridge/amd/agesa/family15/dimmSpd.h>
+#include "OEM.h" /* SMBUS0_BASE_ADDRESS */
#ifndef SB_GPIO_REG01
#define SB_GPIO_REG01 1
@@ -37,6 +39,53 @@
#define SB_GPIO_REG27 27
#endif
+#ifdef __PRE_RAM__
+/* This define is used when selecting the appropriate socket for the SPD read
+ * because this is a multi-socket design.
+ */
+#define LTC4305_SMBUS_ADDR (0x94)
+
+static void select_socket(UINT8 socket_id)
+{
+ AMD_CONFIG_PARAMS StdHeader;
+ UINT32 PciData32;
+ UINT8 PciData8;
+ PCI_ADDR PciAddress;
+
+ /* Set SMBus MMIO. */
+ PciAddress.AddressValue = MAKE_SBDFO (0, 0, 20, 0, 0x90);
+ PciData32 = (SMBUS0_BASE_ADDRESS & 0xFFFFFFF0) | BIT0;
+ LibAmdPciWrite(AccessWidth32, PciAddress, &PciData32, &StdHeader);
+
+ /* Enable SMBus MMIO. */
+ PciAddress.AddressValue = MAKE_SBDFO (0, 0, 20, 0, 0xD2);
+ LibAmdPciRead(AccessWidth8, PciAddress, &PciData8, &StdHeader); ;
+ PciData8 |= BIT0;
+ LibAmdPciWrite(AccessWidth8, PciAddress, &PciData8, &StdHeader);
+
+ switch (socket_id) {
+ case 0:
+ /* Switch onto the First CPU Socket SMBus */
+ writeSmbusByte(SMBUS0_BASE_ADDRESS, LTC4305_SMBUS_ADDR, 0x80, 0x03);
+ break;
+ case 1:
+ /* Switch onto the Second CPU Socket SMBus */
+ writeSmbusByte(SMBUS0_BASE_ADDRESS, LTC4305_SMBUS_ADDR, 0x40, 0x03);
+ break;
+ default:
+ /* Switch off two CPU Sockets SMBus */
+ writeSmbusByte(SMBUS0_BASE_ADDRESS, LTC4305_SMBUS_ADDR, 0x00, 0x03);
+ break;
+ }
+}
+
+static void restore_socket(void)
+{
+ /* Switch off two CPU Sockets SMBus */
+ writeSmbusByte(SMBUS0_BASE_ADDRESS, LTC4305_SMBUS_ADDR, 0x00, 0x03);
+}
+#endif
+
STATIC BIOS_CALLOUT_STRUCT BiosCallouts[] =
{
{AGESA_ALLOCATE_BUFFER,
@@ -500,7 +549,18 @@ AGESA_STATUS BiosReset (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
AGESA_STATUS BiosReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
{
AGESA_STATUS Status;
- Status = AmdMemoryReadSPD (Func, Data, (AGESA_READ_SPD_PARAMS *)ConfigPtr);
+#ifdef __PRE_RAM__
+ if (ConfigPtr == NULL)
+ return AGESA_ERROR;
+
+ select_socket(((AGESA_READ_SPD_PARAMS *)ConfigPtr)->SocketId);
+
+ Status = agesa_ReadSPD (Func, Data, ConfigPtr);
+
+ restore_socket();
+#else
+ Status = AGESA_UNSUPPORTED;
+#endif
return Status;
}
diff --git a/src/mainboard/amd/dinar/Makefile.inc b/src/mainboard/amd/dinar/Makefile.inc
index 0fbfe1f..42f458b 100644
--- a/src/mainboard/amd/dinar/Makefile.inc
+++ b/src/mainboard/amd/dinar/Makefile.inc
@@ -19,14 +19,12 @@
romstage-y += buildOpts.c
romstage-y += agesawrapper.c
-romstage-y += dimmSpd.c
romstage-y += BiosCallOuts.c
romstage-y += sb700_cfg.c
romstage-y += rd890_cfg.c
ramstage-y += buildOpts.c
ramstage-y += agesawrapper.c
-ramstage-y += dimmSpd.c
ramstage-y += BiosCallOuts.c
ramstage-y += sb700_cfg.c
ramstage-y += rd890_cfg.c
diff --git a/src/mainboard/amd/dinar/devicetree.cb b/src/mainboard/amd/dinar/devicetree.cb
index e84762e..09becd4 100644
--- a/src/mainboard/amd/dinar/devicetree.cb
+++ b/src/mainboard/amd/dinar/devicetree.cb
@@ -97,6 +97,12 @@ chip northbridge/amd/agesa/family15/root_complex
device pci 18.3 on end
device pci 18.4 on end
device pci 18.5 on end
+
+ register "spdAddrLookup" = "
+ {
+ { {0xAC, 0xAE}, {0xA8, 0xAA}, {0xA4, 0xA6}, {0xA0, 0xA2}, }, // socket 0 - Channel 0-3
+ { {0xAC, 0xAE}, {0xA8, 0xAA}, {0xA4, 0xA6}, {0xA0, 0xA2}, }, // socket 1 - Channel 0-3
+ }"
end #chip northbridge/amd/agesa/family15 # CPU side of HT root complex
end #domain
end #northbridge/amd/agesa/family15/root_complex
diff --git a/src/mainboard/amd/dinar/dimmSpd.c b/src/mainboard/amd/dinar/dimmSpd.c
deleted file mode 100644
index 10b26c2..0000000
--- a/src/mainboard/amd/dinar/dimmSpd.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2012 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
- */
-
-
-/*----------------------------------------------------------------------------------------
- * M O D U L E S U S E D
- *----------------------------------------------------------------------------------------
- */
-
-#include "Porting.h"
-#include "AGESA.h"
-#include "amdlib.h"
-
-/*----------------------------------------------------------------------------------------
- * D E F I N I T I O N S A N D M A C R O S
- *----------------------------------------------------------------------------------------
- */
-#define SMBUS_BASE_ADDR 0xB00
-#define DIMENSION(array)(sizeof (array)/ sizeof (array [0]))
-
-/*----------------------------------------------------------------------------------------
- * T Y P E D E F S A N D S T R U C T U R E S
- *----------------------------------------------------------------------------------------
- */
-#define LTC4305_SMBUS_ADDR 0x94
-
-typedef struct _DIMM_INFO_SMBUS{
- UINT8 SocketId;
- UINT8 MemChannelId;
- UINT8 DimmId;
- UINT8 SmbusAddress;
-} DIMM_INFO_SMBUS;
-/*
- * SPD address table - porting required
- */
-STATIC CONST DIMM_INFO_SMBUS SpdAddrLookup [] =
-{
- /* Socket, Channel, Dimm, Smbus */
- {0, 0, 0, 0xAC},
- {0, 0, 1, 0xAE},
- {0, 1, 0, 0xA8},
- {0, 1, 1, 0xAA},
- {0, 2, 0, 0xA4},
- {0, 2, 1, 0xA6},
- {0, 3, 0, 0xA0},
- {0, 3, 1, 0xA2},
- {1, 0, 0, 0xAC},
- {1, 0, 1, 0xAE},
- {1, 1, 0, 0xA8},
- {1, 1, 1, 0xAA},
- {1, 2, 0, 0xA4},
- {1, 2, 1, 0xA6},
- {1, 3, 0, 0xA0},
- {1, 3, 1, 0xA2}
-};
-
-/*----------------------------------------------------------------------------------------
- * P R O T O T Y P E S O F L O C A L F U N C T I O N S
- *----------------------------------------------------------------------------------------
- */
-
-AGESA_STATUS
-AmdMemoryReadSPD (
- IN UINT32 Func,
- IN UINT32 Data,
- IN OUT AGESA_READ_SPD_PARAMS *SpdData
- );
-
-/*----------------------------------------------------------------------------------------
- * E X P O R T E D F U N C T I O N S
- *----------------------------------------------------------------------------------------
- */
-
-
-/*---------------------------------------------------------------------------------------
- * L O C A L F U N C T I O N S
- *---------------------------------------------------------------------------------------
- */
-
-STATIC
-VOID
-WritePmReg (
- IN UINT8 Reg,
- IN UINT8 Data
- )
-{
- __outbyte (0xCD6, Reg);
- __outbyte (0xCD7, Data);
-}
-STATIC
-VOID
-SetupFch (
- IN UINT16
- IN IoBase
- )
-{
-
- AMD_CONFIG_PARAMS StdHeader;
- UINT32 PciData32;
- UINT8 PciData8;
- PCI_ADDR PciAddress;
-
- /* Set SMBUS MMIO. */
- PciAddress.AddressValue = MAKE_SBDFO (0, 0, 20, 0, 0x90);
- PciData32 = (SMBUS_BASE_ADDR & 0xFFFFFFF0) | BIT0;
- LibAmdPciWrite(AccessWidth32, PciAddress, &PciData32, &StdHeader);
-
- /* Enable SMBUS MMIO. */
- PciAddress.AddressValue = MAKE_SBDFO (0, 0, 20, 0, 0xD2);
- LibAmdPciRead(AccessWidth8, PciAddress, &PciData8, &StdHeader); ;
- PciData8 |= BIT0;
- LibAmdPciWrite(AccessWidth8, PciAddress, &PciData8, &StdHeader);
- /* set SMBus clock to 400 KHz */
- __outbyte (IoBase + 0x0E, 66000000 / 400000 / 4);
-}
-
-/*
- *
- * ReadSmbusByteData - read a single SPD byte from any offset
- *
- */
-
-STATIC
-AGESA_STATUS
-ReadSmbusByteData (
- IN UINT16 Iobase,
- IN UINT8 Address,
- OUT UINT8 *ByteData,
- IN UINTN Offset
- )
-{
- UINTN Status;
- UINT64 Limit;
-
- Address |= 1; // set read bit
-
- __outbyte (Iobase + 0, 0xFF); // clear error status
- __outbyte (Iobase + 1, 0x1F); // clear error status
- __outbyte (Iobase + 3, Offset); // offset in eeprom
- __outbyte (Iobase + 4, Address); // slave address and read bit
- __outbyte (Iobase + 2, 0x48); // read byte command
-
- /* time limit to avoid hanging for unexpected error status (should never happen) */
- Limit = __rdtsc () + 2000000000 / 10;
- for (;;) {
- Status = __inbyte (Iobase);
- if (__rdtsc () > Limit) break;
- if ((Status & 2) == 0) continue; // SMBusInterrupt not set, keep waiting
- if ((Status & 1) == 1) continue; // HostBusy set, keep waiting
- break;
- }
-
- *ByteData = __inbyte (Iobase + 5);
- if (Status == 2) Status = 0; // check for done with no errors
- return Status;
-}
-/*
- *
- * WriteSmbusByteData - Write a single SPD byte onto any offset
- *
- */
-STATIC
-AGESA_STATUS
-WriteSmbusByteData (
- IN UINT16 Iobase,
- IN UINT8 Address,
- IN UINT8 ByteData,
- IN UINTN Offset
- )
-{
- UINTN Status;
- UINT64 Limit;
- Address &= 0xFE; // set write bit
-
- __outbyte (Iobase + 0, 0xFF); // clear error status
- __outbyte (Iobase + 1, 0x1F); // clear error status
- __outbyte (Iobase + 3, Offset); // offset in eeprom
- __outbyte (Iobase + 4, Address); // slave address and write bit
- __outbyte (Iobase + 5, ByteData); // offset in byte data //
- __outbyte (Iobase + 2, 0x48); // write byte command
- /* time limit to avoid hanging for unexpected error status (should never happen) */
- Limit = __rdtsc () + 2000000000 / 10;
- for (;;) {
- Status = __inbyte (Iobase);
- if (__rdtsc () > Limit) break;
- if ((Status & 2) == 0) continue; // SMBusInterrupt not set, keep waiting
- if ((Status & 1) == 1) continue; // HostBusy set, keep waiting
- break;
- }
- if (Status == 2) Status = 0; // check for done with no errors
- return Status;
-}
-
-/*
- *
- * ReadSmbusByte - read a single SPD byte from the default offset
- * this function is faster function readSmbusByteData
- *
- */
-
-STATIC
-AGESA_STATUS
-ReadSmbusByte (
- IN UINT16 Iobase,
- IN UINT8 Address,
- OUT UINT8 *Buffer
- )
-{
- UINTN Status;
- UINT64 Limit;
-
- __outbyte (Iobase + 0, 0xFF); // clear error status
- __outbyte (Iobase + 1, 0x1F); // clear error status
- __outbyte (Iobase + 2, 0x44); // read command
-
- // time limit to avoid hanging for unexpected error status
- Limit = __rdtsc () + 2000000000 / 10;
- for (;;) {
- Status = __inbyte (Iobase);
- if (__rdtsc () > Limit) break;
- if ((Status & 2) == 0) continue; // SMBusInterrupt not set, keep waiting
- if ((Status & 1) == 1) continue; // HostBusy set, keep waiting
- break;
- }
-
- Buffer [0] = __inbyte (Iobase + 5);
- if (Status == 2) Status = 0; // check for done with no errors
- return Status;
-}
-
-/*
- *
- * ReadSpd - Read one or more SPD bytes from a DIMM.
- * Start with offset zero and read sequentially.
- * Optimization relies on autoincrement to avoid
- * sending offset for every byte.
- * Reads 128 bytes in 7-8 ms at 400 KHz.
- *
- */
-
-STATIC
-AGESA_STATUS
-ReadSpd (
- IN UINT16 IoBase,
- IN UINT8 SmbusSlaveAddress,
- OUT UINT8 *Buffer,
- IN UINTN Count
- )
-{
- UINTN Index, Status;
-
- /* read the first byte using offset zero */
- Status = ReadSmbusByteData (IoBase, SmbusSlaveAddress, Buffer, 0);
- if (Status) return Status;
-
- /* read the remaining bytes using auto-increment for speed */
- for (Index = 1; Index < Count; Index++){
- Status = ReadSmbusByte (IoBase, SmbusSlaveAddress, &Buffer [Index]);
- if (Status) return Status;
- }
- return 0;
-}
-
-AGESA_STATUS
-AmdMemoryReadSPD (
- IN UINT32 Func,
- IN UINT32 Data,
- IN OUT AGESA_READ_SPD_PARAMS *SpdData
- )
-{
- AGESA_STATUS Status;
- UINT8 SmBusAddress = 0;
- UINTN Index;
- UINTN MaxSocket = DIMENSION (SpdAddrLookup);
-
- for (Index = 0; Index < MaxSocket; Index ++){
- if ((SpdData->SocketId == SpdAddrLookup[Index].SocketId) &&
- (SpdData->MemChannelId == SpdAddrLookup[Index].MemChannelId) &&
- (SpdData->DimmId == SpdAddrLookup[Index].DimmId)) {
- SmBusAddress = SpdAddrLookup[Index].SmbusAddress;
- break;
- }
- }
-
-
- if (SmBusAddress == 0) return AGESA_ERROR;
-
- SetupFch (SMBUS_BASE_ADDR);
-
- Status = WriteSmbusByteData (SMBUS_BASE_ADDR, LTC4305_SMBUS_ADDR, 0x80, 0x03);
-
- switch (SpdData->SocketId) {
- case 0:
- /* Switch onto the First CPU Socket SMBUS */
- WriteSmbusByteData (SMBUS_BASE_ADDR, LTC4305_SMBUS_ADDR, 0x80, 0x03);
- break;
- case 1:
- /* Switch onto the Second CPU Socket SMBUS */
- WriteSmbusByteData (SMBUS_BASE_ADDR, LTC4305_SMBUS_ADDR, 0x40, 0x03);
- break;
- default:
- /* Switch off two CPU Sockets SMBUS */
- WriteSmbusByteData (SMBUS_BASE_ADDR, LTC4305_SMBUS_ADDR, 0x00, 0x03);
- break;
- }
- Status = ReadSpd (SMBUS_BASE_ADDR, SmBusAddress, SpdData->Buffer, 256);
-
- /*Output SPD Debug Message*/
- printk(BIOS_EMERG, "file '%s',line %d, %s()\n", __FILE__, __LINE__, __func__);
- printk(BIOS_DEBUG, " Status = %d\n",Status);
- printk(BIOS_DEBUG, "SocketId MemChannelId SpdData->DimmId SmBusAddress Buffer\n");
- printk(BIOS_DEBUG, "%x, %x, %x, %x, %x\n", SpdData->SocketId, SpdData->MemChannelId, SpdData->DimmId, SmBusAddress, SpdData->Buffer);
-
- /* Switch off two CPU Sockets SMBUS */
- WriteSmbusByteData (SMBUS_BASE_ADDR, LTC4305_SMBUS_ADDR, 0x00, 0x03);
- return Status;
-}
the following patch was just integrated into master:
commit 4063ede3fb571110c3e65c321049cc2687cc54fa
Author: Ronald G. Minnich <rminnich(a)google.com>
Date: Mon Feb 4 20:31:51 2013 -0800
bd82x6x: Fix compiling with USB debug port support
At some point, compiles with USB Debug port stopped working. This change makes
a trivial reordering in the code and adds two makefile entries to make it build
without errors. It also works on stout.
Build and boot as normal. Works. Enable CONFIG_USB, connect USB debug hardware
to the correct port (on stout, that's the one on the left nearest the back) and
watch for output.
Change-Id: I7fbb7983a19b0872e2d9e4248db8949e72beaaa0
Signed-off-by: Ronald G. Minnich <rminnich(a)google.com>
Reviewed-on: http://review.coreboot.org/2784
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter(a)users.sourceforge.net>
Reviewed-by: Marc Jones <marc.jones(a)se-eng.com>
Build-Tested: build bot (Jenkins) at Tue Mar 19 03:15:02 2013, giving +1
Reviewed-By: Marc Jones <marc.jones(a)se-eng.com> at Tue Mar 19 17:12:21 2013, giving +2
See http://review.coreboot.org/2784 for details.
-gerrit