Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8405
-gerrit
commit dcab66dbb628f8223b87926d3d7f86a3077c8b1b
Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com>
Date: Tue Feb 10 13:13:39 2015 -0600
northbridge/amd/amdfam10: Allow mainboards to set maximum HT link frequency
Most K10 mainboards are designed to a maximum HT frequency specification.
Coreboot supports CPUs that were released after mainboard production;
these CPUs may support and autodetect HT link frequencies beyond the
mainboard design capabilities. This patch allows mainboards to set
an HT frequency limit if needed.
Change-Id: If7ff40dccb4c22829062511ca0046aa2caf15580
Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com>
---
src/northbridge/amd/Kconfig | 132 ----------------------
src/northbridge/amd/amdfam10/Kconfig | 209 +++++++++++++++++++++++++++++++++++
2 files changed, 209 insertions(+), 132 deletions(-)
diff --git a/src/northbridge/amd/Kconfig b/src/northbridge/amd/Kconfig
index 17f15c3..98a0e9e 100644
--- a/src/northbridge/amd/Kconfig
+++ b/src/northbridge/amd/Kconfig
@@ -5,135 +5,3 @@ source src/northbridge/amd/lx/Kconfig
source src/northbridge/amd/agesa/Kconfig
source src/northbridge/amd/cimx/Kconfig
source src/northbridge/amd/pi/Kconfig
-
-menu "HyperTransport setup"
- #could be implemented for K8 (NORTHBRIDGE_AMD_AMDK8)
- depends on (NORTHBRIDGE_AMD_AMDFAM10) && EXPERT
-
-choice
- prompt "HyperTransport frequency"
- default LIMIT_HT_SPEED_AUTO
- help
- This option sets the maximum permissible HyperTransport link
- frequency.
-
- Use of this option will only limit the autodetected HT frequency.
- It will not (and cannot) increase the frequency beyond the
- autodetected limits.
-
- This is primarily used to work around poorly designed or laid out
- HT traces on certain motherboards.
-
-config LIMIT_HT_SPEED_200
- bool "Limit HT frequency to 200MHz"
-config LIMIT_HT_SPEED_300
- bool "Limit HT frequency to 300MHz"
-config LIMIT_HT_SPEED_400
- bool "Limit HT frequency to 400MHz"
-config LIMIT_HT_SPEED_500
- bool "Limit HT frequency to 500MHz"
-config LIMIT_HT_SPEED_600
- bool "Limit HT frequency to 600MHz"
-config LIMIT_HT_SPEED_800
- bool "Limit HT frequency to 800MHz"
-config LIMIT_HT_SPEED_1000
- bool "Limit HT frequency to 1.0GHz"
-config LIMIT_HT_SPEED_1200
- bool "Limit HT frequency to 1.2GHz"
-config LIMIT_HT_SPEED_1400
- bool "Limit HT frequency to 1.4GHz"
-config LIMIT_HT_SPEED_1600
- bool "Limit HT frequency to 1.6GHz"
-config LIMIT_HT_SPEED_1800
- bool "Limit HT frequency to 1.8GHz"
-config LIMIT_HT_SPEED_2000
- bool "Limit HT frequency to 2.0GHz"
-config LIMIT_HT_SPEED_2200
- bool "Limit HT frequency to 2.2GHz"
-config LIMIT_HT_SPEED_2400
- bool "Limit HT frequency to 2.4GHz"
-config LIMIT_HT_SPEED_2600
- bool "Limit HT frequency to 2.6GHz"
-config LIMIT_HT_SPEED_AUTO
- bool "Autodetect HT frequency"
-endchoice
-
-choice
- prompt "HyperTransport downlink width"
- default LIMIT_HT_DOWN_WIDTH_16
- help
- This option sets the maximum permissible HyperTransport
- downlink width.
-
- Use of this option will only limit the autodetected HT width.
- It will not (and cannot) increase the width beyond the autodetected
- limits.
-
- This is primarily used to work around poorly designed or laid out HT
- traces on certain motherboards.
-
-config LIMIT_HT_DOWN_WIDTH_8
- bool "8 bits"
-config LIMIT_HT_DOWN_WIDTH_16
- bool "16 bits"
-endchoice
-
-choice
- prompt "HyperTransport uplink width"
- default LIMIT_HT_UP_WIDTH_16
- help
- This option sets the maximum permissible HyperTransport
- uplink width.
-
- Use of this option will only limit the autodetected HT width.
- It will not (and cannot) increase the width beyond the autodetected
- limits.
-
- This is primarily used to work around poorly designed or laid out HT
- traces on certain motherboards.
-
-config LIMIT_HT_UP_WIDTH_8
- bool "8 bits"
-config LIMIT_HT_UP_WIDTH_16
- bool "16 bits"
-endchoice
-
-config AMDMCT_ENABLE_ECC_REDIR
- bool
- depends on CPU_AMD_MODEL_10XXX
- default n
-
-config AMDMCT_BACKGROUND_SCRUB_RATE
- hex
- depends on CPU_AMD_MODEL_10XXX
- default 0x00
- help
- This option sets the background ECC memory scub rate
-
- Permissible values are:
-
- 0x00; Disabled
- 0x01; 40ns
- 0x02; 80ns
- 0x03; 160ns
- 0x04; 320ns
- 0x05; 640ns
- 0x06; 1.28us
- 0x07; 2.56us
- 0x08; 5.12us
- 0x09; 10.2us
- 0x0a; 20.5us
- 0x0b; 41us
- 0x0c; 81.9us
- 0x0d; 163.8us
- 0x0e; 327.7us
- 0x0f; 655.4us
- 0x10; 1.31ms
- 0x11; 2.62ms
- 0x12; 5.24ms
- 0x13; 10.49ms
- 0x14; 20.97sms
- 0x15; 42ms
- 0x16; 84ms
-
-endmenu
diff --git a/src/northbridge/amd/amdfam10/Kconfig b/src/northbridge/amd/amdfam10/Kconfig
index 13b912e..5fc7584 100644
--- a/src/northbridge/amd/amdfam10/Kconfig
+++ b/src/northbridge/amd/amdfam10/Kconfig
@@ -124,4 +124,213 @@ config SVI_HIGH_FREQ
Select this for boards with a Voltage Regulator able to operate
at 3.4 MHz in SVI mode. Ignored unless the AMD CPU is rev C3.
+config FORCE_LIMIT_HT_SPEED_200
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_300
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_400
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_500
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_600
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_800
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_1000
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_1200
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_1400
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_1600
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_1800
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_2000
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_2200
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_2400
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_2600
+ bool
+ default n
+
+menu "HyperTransport setup"
+ #could be implemented for K8 (NORTHBRIDGE_AMD_AMDK8)
+ depends on (NORTHBRIDGE_AMD_AMDFAM10)
+ # FIXME uncomment when coreboot gains "visible if" support
+ # visible if EXPERT
+
+choice
+ prompt "HyperTransport frequency"
+ default LIMIT_HT_SPEED_AUTO if (!FORCE_LIMIT_HT_SPEED_200 && !FORCE_LIMIT_HT_SPEED_300 && !FORCE_LIMIT_HT_SPEED_400 && !FORCE_LIMIT_HT_SPEED_500 && !FORCE_LIMIT_HT_SPEED_600 && !FORCE_LIMIT_HT_SPEED_800 && !FORCE_LIMIT_HT_SPEED_1000 && !FORCE_LIMIT_HT_SPEED_1200 && !FORCE_LIMIT_HT_SPEED_1400 && !FORCE_LIMIT_HT_SPEED_1600 && !FORCE_LIMIT_HT_SPEED_1800 && !FORCE_LIMIT_HT_SPEED_2000 && !FORCE_LIMIT_HT_SPEED_2200 && !FORCE_LIMIT_HT_SPEED_2400 && !FORCE_LIMIT_HT_SPEED_2600)
+ default LIMIT_HT_SPEED_200 if FORCE_LIMIT_HT_SPEED_200
+ default LIMIT_HT_SPEED_300 if FORCE_LIMIT_HT_SPEED_300
+ default LIMIT_HT_SPEED_400 if FORCE_LIMIT_HT_SPEED_400
+ default LIMIT_HT_SPEED_500 if FORCE_LIMIT_HT_SPEED_500
+ default LIMIT_HT_SPEED_600 if FORCE_LIMIT_HT_SPEED_600
+ default LIMIT_HT_SPEED_800 if FORCE_LIMIT_HT_SPEED_800
+ default LIMIT_HT_SPEED_1000 if FORCE_LIMIT_HT_SPEED_1000
+ default LIMIT_HT_SPEED_1200 if FORCE_LIMIT_HT_SPEED_1200
+ default LIMIT_HT_SPEED_1400 if FORCE_LIMIT_HT_SPEED_1400
+ default LIMIT_HT_SPEED_1600 if FORCE_LIMIT_HT_SPEED_1600
+ default LIMIT_HT_SPEED_1800 if FORCE_LIMIT_HT_SPEED_1800
+ default LIMIT_HT_SPEED_2000 if FORCE_LIMIT_HT_SPEED_2000
+ default LIMIT_HT_SPEED_2200 if FORCE_LIMIT_HT_SPEED_2200
+ default LIMIT_HT_SPEED_2400 if FORCE_LIMIT_HT_SPEED_2400
+ default LIMIT_HT_SPEED_2600 if FORCE_LIMIT_HT_SPEED_2600
+ help
+ This option sets the maximum permissible HyperTransport link
+ frequency.
+
+ Use of this option will only limit the autodetected HT frequency.
+ It will not (and cannot) increase the frequency beyond the
+ autodetected limits.
+
+ This is primarily used to work around poorly designed or laid out
+ HT traces on certain motherboards.
+
+config LIMIT_HT_SPEED_200
+ bool "Limit HT frequency to 200MHz"
+config LIMIT_HT_SPEED_300
+ bool "Limit HT frequency to 300MHz"
+config LIMIT_HT_SPEED_400
+ bool "Limit HT frequency to 400MHz"
+config LIMIT_HT_SPEED_500
+ bool "Limit HT frequency to 500MHz"
+config LIMIT_HT_SPEED_600
+ bool "Limit HT frequency to 600MHz"
+config LIMIT_HT_SPEED_800
+ bool "Limit HT frequency to 800MHz"
+config LIMIT_HT_SPEED_1000
+ bool "Limit HT frequency to 1.0GHz"
+config LIMIT_HT_SPEED_1200
+ bool "Limit HT frequency to 1.2GHz"
+config LIMIT_HT_SPEED_1400
+ bool "Limit HT frequency to 1.4GHz"
+config LIMIT_HT_SPEED_1600
+ bool "Limit HT frequency to 1.6GHz"
+config LIMIT_HT_SPEED_1800
+ bool "Limit HT frequency to 1.8GHz"
+config LIMIT_HT_SPEED_2000
+ bool "Limit HT frequency to 2.0GHz"
+config LIMIT_HT_SPEED_2200
+ bool "Limit HT frequency to 2.2GHz"
+config LIMIT_HT_SPEED_2400
+ bool "Limit HT frequency to 2.4GHz"
+config LIMIT_HT_SPEED_2600
+ bool "Limit HT frequency to 2.6GHz"
+config LIMIT_HT_SPEED_AUTO
+ bool "Autodetect HT frequency"
+endchoice
+
+choice
+ prompt "HyperTransport downlink width"
+ default LIMIT_HT_DOWN_WIDTH_16
+ help
+ This option sets the maximum permissible HyperTransport
+ downlink width.
+
+ Use of this option will only limit the autodetected HT width.
+ It will not (and cannot) increase the width beyond the autodetected
+ limits.
+
+ This is primarily used to work around poorly designed or laid out HT
+ traces on certain motherboards.
+
+config LIMIT_HT_DOWN_WIDTH_8
+ bool "8 bits"
+config LIMIT_HT_DOWN_WIDTH_16
+ bool "16 bits"
+endchoice
+
+choice
+ prompt "HyperTransport uplink width"
+ default LIMIT_HT_UP_WIDTH_16
+ help
+ This option sets the maximum permissible HyperTransport
+ uplink width.
+
+ Use of this option will only limit the autodetected HT width.
+ It will not (and cannot) increase the width beyond the autodetected
+ limits.
+
+ This is primarily used to work around poorly designed or laid out HT
+ traces on certain motherboards.
+
+config LIMIT_HT_UP_WIDTH_8
+ bool "8 bits"
+config LIMIT_HT_UP_WIDTH_16
+ bool "16 bits"
+endchoice
+
+config AMDMCT_ENABLE_ECC_REDIR
+ bool
+ depends on CPU_AMD_MODEL_10XXX
+ default n
+
+config AMDMCT_BACKGROUND_SCRUB_RATE
+ hex
+ depends on CPU_AMD_MODEL_10XXX
+ default 0x00
+ help
+ This option sets the background ECC memory scub rate
+
+ Permissible values are:
+
+ 0x00; Disabled
+ 0x01; 40ns
+ 0x02; 80ns
+ 0x03; 160ns
+ 0x04; 320ns
+ 0x05; 640ns
+ 0x06; 1.28us
+ 0x07; 2.56us
+ 0x08; 5.12us
+ 0x09; 10.2us
+ 0x0a; 20.5us
+ 0x0b; 41us
+ 0x0c; 81.9us
+ 0x0d; 163.8us
+ 0x0e; 327.7us
+ 0x0f; 655.4us
+ 0x10; 1.31ms
+ 0x11; 2.62ms
+ 0x12; 5.24ms
+ 0x13; 10.49ms
+ 0x14; 20.97sms
+ 0x15; 42ms
+ 0x16; 84ms
+
+endmenu
+
endif # NORTHBRIDGE_AMD_AMDFAM10
Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8405
-gerrit
commit 45457eb5d0a89466b46da2e9e64b61ad510f6f43
Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com>
Date: Tue Feb 10 13:13:39 2015 -0600
northbridge/amd: Allow mainboards to set maximum HT link frequency
Most mainboards are designed to a maximum HT frequency specification.
Coreboot supports CPUs that were released after mainboard production;
these CPUs may support and autodetect HT link frequencies beyond the
mainboard design capabilities. This patch allows mainboards to set
an HT frequency limit if needed.
Change-Id: If7ff40dccb4c22829062511ca0046aa2caf15580
Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com>
---
src/northbridge/amd/Kconfig | 80 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 78 insertions(+), 2 deletions(-)
diff --git a/src/northbridge/amd/Kconfig b/src/northbridge/amd/Kconfig
index 17f15c3..2a178ca 100644
--- a/src/northbridge/amd/Kconfig
+++ b/src/northbridge/amd/Kconfig
@@ -6,13 +6,89 @@ source src/northbridge/amd/agesa/Kconfig
source src/northbridge/amd/cimx/Kconfig
source src/northbridge/amd/pi/Kconfig
+config FORCE_LIMIT_HT_SPEED_200
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_300
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_400
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_500
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_600
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_800
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_1000
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_1200
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_1400
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_1600
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_1800
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_2000
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_2200
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_2400
+ bool
+ default n
+
+config FORCE_LIMIT_HT_SPEED_2600
+ bool
+ default n
+
menu "HyperTransport setup"
#could be implemented for K8 (NORTHBRIDGE_AMD_AMDK8)
- depends on (NORTHBRIDGE_AMD_AMDFAM10) && EXPERT
+ depends on (NORTHBRIDGE_AMD_AMDFAM10)
+ # visible if EXPERT
choice
prompt "HyperTransport frequency"
- default LIMIT_HT_SPEED_AUTO
+ default LIMIT_HT_SPEED_AUTO if (!FORCE_LIMIT_HT_SPEED_200 && !FORCE_LIMIT_HT_SPEED_300 && !FORCE_LIMIT_HT_SPEED_400 && !FORCE_LIMIT_HT_SPEED_500 && !FORCE_LIMIT_HT_SPEED_600 && !FORCE_LIMIT_HT_SPEED_800 && !FORCE_LIMIT_HT_SPEED_1000 && !FORCE_LIMIT_HT_SPEED_1200 && !FORCE_LIMIT_HT_SPEED_1400 && !FORCE_LIMIT_HT_SPEED_1600 && !FORCE_LIMIT_HT_SPEED_1800 && !FORCE_LIMIT_HT_SPEED_2000 && !FORCE_LIMIT_HT_SPEED_2200 && !FORCE_LIMIT_HT_SPEED_2400 && !FORCE_LIMIT_HT_SPEED_2600)
+ default LIMIT_HT_SPEED_200 if FORCE_LIMIT_HT_SPEED_200
+ default LIMIT_HT_SPEED_300 if FORCE_LIMIT_HT_SPEED_300
+ default LIMIT_HT_SPEED_400 if FORCE_LIMIT_HT_SPEED_400
+ default LIMIT_HT_SPEED_500 if FORCE_LIMIT_HT_SPEED_500
+ default LIMIT_HT_SPEED_600 if FORCE_LIMIT_HT_SPEED_600
+ default LIMIT_HT_SPEED_800 if FORCE_LIMIT_HT_SPEED_800
+ default LIMIT_HT_SPEED_1000 if FORCE_LIMIT_HT_SPEED_1000
+ default LIMIT_HT_SPEED_1200 if FORCE_LIMIT_HT_SPEED_1200
+ default LIMIT_HT_SPEED_1400 if FORCE_LIMIT_HT_SPEED_1400
+ default LIMIT_HT_SPEED_1600 if FORCE_LIMIT_HT_SPEED_1600
+ default LIMIT_HT_SPEED_1800 if FORCE_LIMIT_HT_SPEED_1800
+ default LIMIT_HT_SPEED_2000 if FORCE_LIMIT_HT_SPEED_2000
+ default LIMIT_HT_SPEED_2200 if FORCE_LIMIT_HT_SPEED_2200
+ default LIMIT_HT_SPEED_2400 if FORCE_LIMIT_HT_SPEED_2400
+ default LIMIT_HT_SPEED_2600 if FORCE_LIMIT_HT_SPEED_2600
help
This option sets the maximum permissible HyperTransport link
frequency.
Werner Zeh (werner.zeh(a)siemens.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8404
-gerrit
commit 8541d21cc33dc1fd84242c37ec5f4ec3a2647a2b
Author: Werner Zeh <werner.zeh(a)siemens.com>
Date: Tue Feb 10 15:09:00 2015 +0100
drivers/intel/i210: Add new driver for Intel i210 MACPHY
Add a new driver for Intel i210 MACPHY with the goal to
update the MAC address in i210 if it is found
during PCI scan.
Change-Id: I4d4e797543a9f278fb649596f63ae8e1f285b3c3
Signed-off-by: Werner Zeh <werner.zeh(a)siemens.com>
---
src/drivers/intel/Makefile.inc | 1 +
src/drivers/intel/i210/Makefile.inc | 1 +
src/drivers/intel/i210/i210.c | 238 ++++++++++++++++++++++++++++++++++++
src/drivers/intel/i210/i210.h | 58 +++++++++
4 files changed, 298 insertions(+)
diff --git a/src/drivers/intel/Makefile.inc b/src/drivers/intel/Makefile.inc
index 7bc6dd5..f12511c 100644
--- a/src/drivers/intel/Makefile.inc
+++ b/src/drivers/intel/Makefile.inc
@@ -1,3 +1,4 @@
subdirs-y += gma
subdirs-y += wifi
subdirs-$(CONFIG_PLATFORM_USES_FSP) += fsp
+subdirs-y += i210
diff --git a/src/drivers/intel/i210/Makefile.inc b/src/drivers/intel/i210/Makefile.inc
new file mode 100644
index 0000000..a1f15de
--- /dev/null
+++ b/src/drivers/intel/i210/Makefile.inc
@@ -0,0 +1 @@
+ramstage-y += i210.c
\ No newline at end of file
diff --git a/src/drivers/intel/i210/i210.c b/src/drivers/intel/i210/i210.c
new file mode 100644
index 0000000..5094999
--- /dev/null
+++ b/src/drivers/intel/i210/i210.c
@@ -0,0 +1,238 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Siemens AG.
+ *
+ * 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 "i210.h"
+#include <device/device.h>
+#include <console/console.h>
+#include <string.h>
+
+/* We need one function we can call to get a MAC-address to use*/
+/* This function can be coded somewhere else but must exist.*/
+extern u8* get_mac_address(u32 pci_bdf);
+
+/* This is a private function to wait for a bit mask in a given register*/
+/* To avoid endless loops, a timeout is implemented here.*/
+static int i210_wait_done(u32* reg, u32 mask)
+{
+ u32 timeout = I210_POLL_TIMEOUT;
+ do {
+ if (!(*reg & mask)) {
+ udelay(1);
+ timeout--;
+ }
+ } while((!(*reg & mask)) && timeout);
+ return timeout ? I210_NO_ERROR:I210_NOT_READY;
+}
+
+/** \brief This function is the driver entry point for the init phase
+ * of the PCI bus allocator. It will program a MAC-address
+ * into the MACPHY.
+ * @param *dev Pointer to the used PCI device
+ * @return void Nothing is given back
+ */
+void i210_init(struct device *dev)
+{
+ u8 cur_adr[6];
+ u8 *adr_to_set;
+
+ /*Check first whether there is a valid MAC address available*/
+ adr_to_set=get_mac_address((dev->bus->subordinate <<8)|dev->path.pci.devfn);
+ if (adr_to_set == NULL) {
+ printk(BIOS_ERR, "I210: No valid MAC-Address found\n");
+ return;
+ }
+ /* Before we will write a new address, check the existing one*/
+ if (i210_read_mac_adr(dev, cur_adr)) {
+ printk(BIOS_ERR, "I210: Not able to read current MAC-Address.\n");
+ return;
+ }
+ if (memcmp(cur_adr, adr_to_set, 6)) {
+ if (i210_write_mac_adr(dev, adr_to_set)) {
+ printk(BIOS_ERR, "I210: Error while setting MAC-Address\n");
+ } else {
+ printk(BIOS_INFO, "I210: MAC-Address successfully changed.\n");
+ }
+ } else {
+ printk(BIOS_INFO, "I210: MAC-Address is up to date, nothing to do.\n");
+ }
+ return;
+}
+
+/** \brief This function can read the MAC-address out of the MACPHY
+ * @param *dev Pointer to the PCI device of this MACPHY
+ * @param *MACAdr Pointer to the buffer where to store read MAC-address
+ * @return void I210_NO_ERROR or an error code
+ */
+u32 i210_read_mac_adr(struct device *dev, u8 *MACAdr)
+{
+ u16 adr[3];
+ if (!dev || !MACAdr)
+ return I210_INVALID_PARAM;
+ if (i210_read_flash(dev, 0, 3, adr))
+ return I210_READ_ERROR;
+ /* Copy the address into destination. This is done because of possible*/
+ /* not matching alignment for destination to u16 boundary*/
+ memcpy(MACAdr, (u8*)adr, 6);
+ return I210_NO_ERROR;
+}
+
+/** \brief This function can write the MAC-address to the MACPHY
+ * @param *dev Pointer to the PCI device of this MACPHY
+ * @param *MACAdr Pointer to the buffer where the desired MAC-address is
+ * @return void I210_NO_ERROR or an error code
+ */
+u32 i210_write_mac_adr(struct device *dev, u8 *MACAdr)
+{
+ u16 adr[3];
+ if (!dev || !MACAdr)
+ return I210_INVALID_PARAM;
+ /* Copy desired address into a local buffer to avoid alignment issues*/
+ memcpy((u8*)adr, MACAdr, 6);
+ return i210_write_flash(dev, 0, 3, adr);
+}
+
+/** \brief This function can read the configuration space of the MACPHY
+ * For this purpose, the EEPROM interface is used. No direct access
+ * to the flash memory will be done.
+ * @param *dev Pointer to the PCI device of this MACPHY
+ * @param address Address inside the flash where reading will start
+ * @param count Number of words (16 bit values) to read
+ * @param *buffer Pointer to the buffer where to store read data
+ * @return void I210_NO_ERROR or an error code
+ */
+u32 i210_read_flash(struct device *dev, u32 address, u32 count, u16 *buffer)
+{
+ u32 bar;
+ u32 *eeprd;
+ u32 i;
+
+ /* Get the BAR to memory mapped space*/
+ bar = pci_read_config32(dev, 0x10);
+ if ((!bar) || ((address + count) > 0x40))
+ return I210_INVALID_PARAM;
+ eeprd = (u32*)(bar + I210_REG_EEREAD);
+ /*Prior to start, ensure flash interface is ready by checking DONE-bit*/
+ if (i210_wait_done(eeprd, I210_DONE))
+ return I210_NOT_READY;
+
+ /*OK, interface is ready, we can use it now*/
+ for (i = 0; i < count; i++) {
+ /* To start a read cycle, write desired address in bits 12..2*/
+ *eeprd = ((address + i) << 2) & 0x1FFC;
+ /* Wait until read is done and check for timeout*/
+ if (i210_wait_done(eeprd, I210_DONE))
+ return I210_READ_ERROR;
+ /* Here, we can read back desired word in bits 31..16*/
+ buffer[i] = (*eeprd & 0xffff0000) >> 16;
+ }
+ return I210_NO_ERROR;
+}
+
+/** \brief This function can write the configuration space of the MACPHY
+ * For this purpose, the EEPROM interface is used. No direct access
+ * to the flash memory will be done. This function will update
+ * the checksum after a value was changed.
+ * @param *dev Pointer to the PCI device of this MACPHY
+ * @param address Address inside the flash where writing will start
+ * @param count Number of words (16 bit values) to write
+ * @param *buffer Pointer to the buffer where data to write is stored in
+ * @return void I210_NO_ERROR or an error code
+ */
+u32 i210_write_flash(struct device *dev, u32 address, u32 count, u16 *buffer)
+{
+ u32 bar;
+ u32 *eepwr;
+ u32 *eectrl;
+ u16 checksum;
+ u32 i;
+
+ /* Get the BAR to memory mapped space*/
+ bar = pci_read_config32(dev, 0x10);
+ if ((!bar) || ((address + count) > 0x40))
+ return I210_INVALID_PARAM;
+ eepwr = (u32*)(bar + I210_REG_EEWRITE);
+ eectrl = (u32*)(bar + I210_REG_EECTRL);
+ /* Prior to start, ensure flash interface is ready by checking DONE-bit*/
+ if (i210_wait_done(eepwr, I210_DONE))
+ return I210_NOT_READY;
+
+ /* OK, interface is ready, we can use it now*/
+ for (i = 0; i < count; i++) {
+ /* To start a write cycle, write desired address in bits 12..2*/
+ /* and data to write in bits 31..16 into EEWRITE-register*/
+ *eepwr = ((((address + i) << 2) & 0x1FFC) | (buffer[i] << 16));
+ /* Wait until write is done and check for timeout*/
+ if (i210_wait_done(eepwr, I210_DONE))
+ return I210_WRITE_ERROR;
+ }
+ /* Since we have modified data, we need to update the checksum*/
+ if (i210_compute_checksum(dev, &checksum))
+ return I210_CHECKSUM_ERROR;
+ *eepwr = (0x3f << 2) | checksum << 16;
+ if (i210_wait_done(eepwr, I210_DONE))
+ return I210_WRITE_ERROR;
+ /* Up to now, desired data was written into shadowed RAM. We now need*/
+ /* to perform a flash cycle to bring the shadowed RAM into flash memory*/
+ /* To start a flash cycle, we need to set FLUPD-bit and wait for FLDONE*/
+ *eectrl = *eectrl | I210_FLUPD;
+ if (i210_wait_done(eectrl, I210_FLUDONE))
+ return I210_FLASH_UPDATE_ERROR;
+ else
+ return I210_NO_ERROR;
+}
+
+/** \brief This function computes the checksum for the configuration space.
+ * The address range for the checksum is 0x00..0x3e.
+ * @param *dev Pointer to the PCI device of this MACPHY
+ * @param *checksum Pointer to the buffer where to store the checksum
+ * @return void I210_NO_ERROR or an error code
+ */
+u32 i210_compute_checksum(struct device *dev, u16 *checksum)
+{
+ u16 eep_data[0x40];
+ u32 i;
+
+ /* First read back data to compute the checksum for*/
+ if (i210_read_flash(dev, 0, 0x3f, eep_data))
+ return I210_READ_ERROR;
+ /* The checksum is computed in that way that after summarize all the data*/
+ /* from word address 0 to 0x3f the result is 0xBABA.*/
+ *checksum = 0;
+ for (i = 0; i < 0x3f; i++)
+ *checksum += eep_data[i];
+ *checksum = I210_TARGET_CHECKSUM - *checksum;
+ return I210_NO_ERROR;
+}
+
+static struct device_operations i210_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = i210_init,
+ .scan_bus = 0,
+ .ops_pci = 0,
+};
+
+static const unsigned short i210_device_ids[] = { 0x1538, 0x1533, 0 };
+
+static const struct pci_driver i210_driver __pci_driver = {
+ .ops = &i210_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .devices = i210_device_ids,
+};
diff --git a/src/drivers/intel/i210/i210.h b/src/drivers/intel/i210/i210.h
new file mode 100644
index 0000000..ae8867d
--- /dev/null
+++ b/src/drivers/intel/i210/i210.h
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Siemens AG.
+ *
+ * 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 _INTEL_I210_H_
+#define _INTEL_I210_H_
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <delay.h>
+
+#define I210_PCI_MEM_BAR_OFFSET 0x10
+#define I210_REG_EECTRL 0x12010 /* Offset for EEPROM control reg*/
+#define I210_FLUPD 0x800000 /* Start flash update bit*/
+#define I210_FLUDONE 0x4000000 /* Flash update done indicator*/
+#define I210_REG_EEREAD 0x12014 /* Offset for EEPROM read reg*/
+#define I210_REG_EEWRITE 0x12018 /* Offset for EEPROM write reg*/
+#define I210_CMDV 0x01 /* Command valid bit*/
+#define I210_DONE 0x02 /* command done bit*/
+#define I210_TARGET_CHECKSUM 0xBABA /* resulting checksum*/
+
+
+/*define some other useful values here*/
+#define I210_POLL_TIMEOUT 300000 /* use 300 ms as timeout*/
+/*Define some error states here*/
+#define I210_NO_ERROR 0x00000000
+#define I210_INVALID_PARAM 0x00000001
+#define I210_NOT_READY 0x00000002
+#define I210_READ_ERROR 0x00000004
+#define I210_WRITE_ERROR 0x00000008
+#define I210_CHECKSUM_ERROR 0x00000010
+#define I210_FLASH_UPDATE_ERROR 0x00000020
+
+void i210_init(struct device *dev);
+u32 i210_read_mac_adr(struct device *dev, u8 *MACAdr);
+u32 i210_write_mac_adr(struct device *dev, u8 *MACAdr);
+u32 i210_read_flash(struct device *dev, u32 address, u32 count, u16 *buffer);
+u32 i210_write_flash(struct device *dev, u32 address, u32 count, u16 *buffer);
+u32 i210_compute_checksum(struct device *dev, u16 *checksum);
+
+
+
+#endif /* _INTEL_I210_H_ */
Werner Zeh (werner.zeh(a)siemens.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8403
-gerrit
commit ef9119908e317ccd8ed05eef0941d8be9d7ed52e
Author: Werner Zeh <werner.zeh(a)siemens.com>
Date: Tue Feb 10 14:34:17 2015 +0100
lint: exclude *.hex files from whitespace checking
If one needs raw binary files, .bin extension cannot
be used due to settings in .gitignore. This patch
allows to use .hex files. To avoid lint checks on these
files, exculde the .hex extension from the test.
Change-Id: I4b503229d63694c48cce12ca8cd33ea58172af01
Signed-off-by: Werner Zeh <werner.zeh(a)siemens.com>
---
util/lint/lint-stable-003-whitespace | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/util/lint/lint-stable-003-whitespace b/util/lint/lint-stable-003-whitespace
index 47853ba..f13aa98 100755
--- a/util/lint/lint-stable-003-whitespace
+++ b/util/lint/lint-stable-003-whitespace
@@ -19,6 +19,6 @@
# DESCR: Check for superfluous whitespace in the tree
LC_ALL=C export LC_ALL
-grep -l "[[:space:]][[:space:]]*$" `git ls-files src util |egrep -v "(^3rdparty|^src/vendorcode/|^util/kconfig/|^util/nvidia/cbootimage$|\<COPYING\>|\<LICENSE\>|\<README\>|_shipped$|\.patch|\.bin$)"` | \
+grep -l "[[:space:]][[:space:]]*$" `git ls-files src util |egrep -v "(^3rdparty|^src/vendorcode/|^util/kconfig/|^util/nvidia/cbootimage$|\<COPYING\>|\<LICENSE\>|\<README\>|_shipped$|\.patch$|\.bin$|\.hex$)"` | \
sed -e "s,^.*$,File & has lines ending with whitespace.,"
Werner Zeh (werner.zeh(a)siemens.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8372
-gerrit
commit 2c011f2e6671f8d78b81a7c97adfa44bc444feed
Author: Patrick Georgi <patrick(a)georgi-clan.de>
Date: Thu Feb 5 23:38:45 2015 +0100
lint: exclude nvidia submodule from file list
From git's point of view submodules are a weird third thing between file
and directory. Avoid trying to apply file handling on a directory.
Change-Id: Ibbc9c28e1657d96413c5fb08705d30e25171254d
Signed-off-by: Patrick Georgi <patrick(a)georgi-clan.de>
---
util/lint/lint-stable-003-whitespace | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/util/lint/lint-stable-003-whitespace b/util/lint/lint-stable-003-whitespace
index 22c5c3c..47853ba 100755
--- a/util/lint/lint-stable-003-whitespace
+++ b/util/lint/lint-stable-003-whitespace
@@ -19,6 +19,6 @@
# DESCR: Check for superfluous whitespace in the tree
LC_ALL=C export LC_ALL
-grep -l "[[:space:]][[:space:]]*$" `git ls-files src util |egrep -v "(^3rdparty|^src/vendorcode/|^util/kconfig/|\<COPYING\>|\<LICENSE\>|\<README\>|_shipped$|\.patch|\.bin$)"` | \
+grep -l "[[:space:]][[:space:]]*$" `git ls-files src util |egrep -v "(^3rdparty|^src/vendorcode/|^util/kconfig/|^util/nvidia/cbootimage$|\<COPYING\>|\<LICENSE\>|\<README\>|_shipped$|\.patch|\.bin$)"` | \
sed -e "s,^.*$,File & has lines ending with whitespace.,"
Werner Zeh (werner.zeh(a)siemens.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8401
-gerrit
commit ed0f4138e8c6a01bf031cbf0565881dde6b84ddd
Author: Werner Zeh <werner.zeh(a)siemens.com>
Date: Tue Feb 10 13:02:34 2015 +0100
fsp_baytrail: Add I2C driver
Add a driver wich can handle the internal I2C controllers
of Baytrail SoC. This driver is not suitable for the
SMBUS-controller.
Change-Id: I841c3991a2fb0f8b92b8e59ec02d62f5866f5bdf
Signed-off-by: Werner Zeh <werner.zeh(a)siemens.com>
---
src/soc/intel/fsp_baytrail/Makefile.inc | 1 +
src/soc/intel/fsp_baytrail/baytrail/i2c.h | 138 +++++++++++++++
src/soc/intel/fsp_baytrail/i2c.c | 269 ++++++++++++++++++++++++++++++
3 files changed, 408 insertions(+)
diff --git a/src/soc/intel/fsp_baytrail/Makefile.inc b/src/soc/intel/fsp_baytrail/Makefile.inc
index 3896e85..2dfb9cb 100644
--- a/src/soc/intel/fsp_baytrail/Makefile.inc
+++ b/src/soc/intel/fsp_baytrail/Makefile.inc
@@ -54,6 +54,7 @@ smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c
ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smm.c
ramstage-y += placeholders.c
+ramstage-y += i2c.c
CPPFLAGS_common += -I$(src)/soc/intel/fsp_baytrail/
CPPFLAGS_common += -I$(src)/soc/intel/fsp_baytrail/fsp
diff --git a/src/soc/intel/fsp_baytrail/baytrail/i2c.h b/src/soc/intel/fsp_baytrail/baytrail/i2c.h
new file mode 100644
index 0000000..3799fbb
--- /dev/null
+++ b/src/soc/intel/fsp_baytrail/baytrail/i2c.h
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Siemens AG
+ *
+ * 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 __SOC_INTEL_FSP_BAYTRAIL_I2C_H__
+#define __SOC_INTEL_FSP_BAYTRAIL_I2C_H__
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <device/pci_ids.h>
+#include <device/pci_def.h>
+
+/* SMBus controller settings in PCI configuration space*/
+#define I2C_PCI_VENDOR_ID 0x8086
+#define I2C0_PCI_DEV_ID 0x0f41
+#define I2C1_PCI_DEV_ID 0x0f42
+#define I2C2_PCI_DEV_ID 0x0f43
+#define I2C3_PCI_DEV_ID 0x0f44
+#define I2C4_PCI_DEV_ID 0x0f45
+#define I2C5_PCI_DEV_ID 0x0f46
+#define I2C6_PCI_DEV_ID 0x0f47
+
+#define I2C0_MEM_BASE 0xd0921000
+#define I2C1_MEM_BASE 0xd0923000
+#define I2C2_MEM_BASE 0xd0925000
+#define I2C3_MEM_BASE 0xd0927000
+#define I2C4_MEM_BASE 0xd0929000
+#define I2C5_MEM_BASE 0xd092b000
+#define I2C6_MEM_BASE 0xd092d000
+
+#define I2C_STANDARD_MODE 0x1
+#define I2C_FAST_MODE 0x2
+
+/* Define relevant registers in PCI space.*/
+#define I2C_PCI_COMMAND 0x4
+#define I2C_PCI_STATUS 0x6
+
+/* Define memory mapped registers.*/
+#define I2C_CTRL 0x0
+#define I2C_SLAVE_DISABLE 0x40
+#define I2C_RESTART_EN 0x20
+#define I2C_ADR_MODE 0x10
+#define I2C_SPEED_MASK 0x6
+#define I2C_STD_MODE 0x1
+#define I2C_FAST_MODE 0x2
+#define I2C_MASTER_ENABLE 0x1
+
+#define I2C_TARGET_ADR 0x4
+#define I2C_TARGET_ADR_MASK 0x3ff
+
+#define I2C_DATA_CMD 0x10
+#define I2C_RESTART 0x400
+#define I2C_STOP 0x200
+#define I2C_RW_CMD 0x100
+
+#define I2C_SS_SCL_HCNT 0x14 /* Counter for high period for 100 kHz SCL*/
+#define I2C_SS_SCL_LCNT 0x18 /* Counter for low period for 100 kHz SCL*/
+#define I2C_FS_SCL_HCNT 0x1c /* Counter for high period for 400 kHz SCL*/
+#define I2C_FS_SCL_LCNT 0x20 /* Counter for low period for 400 kHz SCL*/
+
+#define I2C_INTR_STAT 0x2c /* Interrupt status register, read only*/
+#define I2C_INTR_MASK 0x30 /*Interrupt mask register*/
+#define I2C_RAW_INTR_STAT 0x34 /* Raw interrupt status, read only*/
+#define I2C_START_DETECT 0x400
+#define I2C_STOP_DETECT 0x200
+#define I2C_ACTIVITY 0x100
+#define I2C_TX_ABORT 0x40
+#define I2C_RD_REQ 0x20 /* Read request in slave mode*/
+#define I2C_TX_EMPTY 0x10
+#define I2C_TX_OVERFLOW 0x8
+#define I2C_RX_FULL 0x4
+#define I2C_RX_OVERFLOW 0x2
+#define I2C_RX_UNDERFLOW 0x1
+
+#define I2C_RX_TL 0x38 /* Rx FIFO threshold level 0..255*/
+#define I2C_TX_TL 0x3c /* Tx FIFO threshold level 0..255*/
+#define I2C_CLR_INTR 0x40 /* Clear all events with a read*/
+#define I2C_CLR_TX_ABRT 0x54 /* Clear TX-Abort event with a read*/
+
+/*There are a bunch of interrupt clearing registers now which I do not use!*/
+/*So proceed somewhat later with definition*/
+#define I2C_ENABLE 0x6c /* 0: disable I2C controller, 1: enable*/
+#define I2C_STATUS 0x70
+#define I2C_MST_ACTIVITY 0x20 /* Master FSM activity*/
+#define I2C_RFF 0x10 /* Receive FIFO completely full*/
+#define I2C_RFNE 0x8 /* Receive FIFO not empty*/
+#define I2C_TFE 0x4 /* Transmit FIFO completely empty*/
+#define I2C_TFNF 0x2 /* Transmit FIFO not full*/
+#define I2C_ACTIVE 0x1 /* 1: I2C currently in operation*/
+
+#define I2C_TXFLR 0x74 /* Current transmit FIFO level*/
+#define I2C_RXFLR 0x78 /* Current receive FIFO level*/
+#define I2C_SDA_HOLD 0x7c /* Data hold time after SCL goes low*/
+#define I2C_ABORT_SOURCE 0x80
+#define I2C_ARB_LOST 0x1000 /* Arbitration lost*/
+#define I2C_MASTER_DIS 0x800 /* Master was disabled by user*/
+#define I2C_10B_RD_NORSTRT 0x400 /* 10 bit address read and RESTART disabled*/
+#define I2C_SBYTE_NORSTRT 0x200 /* START with RESTART disabled*/
+#define I2C_START_ACKDET 0x80 /* START byte was acknowledged*/
+#define I2C_TX_DATA_NOACK 0x8 /* TX data not acknowledged*/
+#define I2C_10B_ADR2_NOACK 0x4 /* Second address byte in 10 bit mode NACK*/
+#define I2C_10B_ADR1_NOACK 0x2 /* First address byte in 10 bit not ACK*/
+#define I2C_7B_ADDR_NACK 0x1 /* 7 bit address byte not acknowledged*/
+
+#define I2C_ENABLE_STATUS 0x9c
+
+/* Define some status and error values*/
+#define I2C_ERR_INVALID_ADR 0x1000000
+#define I2C_ERR_TIMEOUT 0x2000000
+#define I2C_ERR_ABORT 0x4000000
+#define I2C_NO_ERROR 0x0000000
+
+
+#define I2C_TIMEOUT 2000 /* Use 2000 us as timeout for the bus*/
+
+/* Prototype section*/
+int i2c_init(unsigned bus);
+int i2c_read(unsigned bus, unsigned chip, unsigned addr,
+ uint8_t *buf, unsigned len);
+int i2c_write(unsigned bus, unsigned chip, unsigned addr,
+ const uint8_t *buf, unsigned len);
+
+#endif /* __SOC_INTEL_FSP_BAYTRAIL_I2C_H__ */
diff --git a/src/soc/intel/fsp_baytrail/i2c.c b/src/soc/intel/fsp_baytrail/i2c.c
new file mode 100644
index 0000000..05c21a3
--- /dev/null
+++ b/src/soc/intel/fsp_baytrail/i2c.c
@@ -0,0 +1,269 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Siemens AG
+ *
+ * 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 <device/pci.h>
+#include <baytrail/baytrail.h>
+#include <baytrail/pci_devs.h>
+#include <baytrail/iosf.h>
+#include <delay.h>
+#include <baytrail/i2c.h>
+
+/* Wait for the transmit FIFO till there is at least one slot empty.
+ * FIFO stall due to transmit abort will be checked and resolved
+ */
+static int wait_tx_fifo(char *base_adr) {
+ int i;
+
+ if (*((unsigned int *)(base_adr + I2C_ABORT_SOURCE)) & 0x1ffff) {
+ /*Reading back I2C_CLR_TX_ABRT resets abort lock on TX FIFO*/
+ i = *((volatile unsigned int *)(base_adr + I2C_CLR_TX_ABRT));
+ return I2C_ERR_ABORT |
+ (*((unsigned int *)(base_adr + I2C_ABORT_SOURCE)) & 0x1ffff);
+ }
+
+ /*Wait here for a free slot in TX-FIFO */
+ i = I2C_TIMEOUT;
+ while ((!(*((volatile unsigned int *)(base_adr + I2C_STATUS)) & I2C_TFNF))
+ && (i)) {
+ udelay(1);
+ i--;
+ }
+
+ if (i == 0) {
+ return I2C_ERR_TIMEOUT;
+ } else {
+ return I2C_NO_ERROR;
+ }
+}
+
+/* Wait for the receive FIFO till there is at least one valid entry to read.
+ * FIFO stall due to transmit abort will be checked and resolved
+ */
+static int wait_rx_fifo(char *base_adr) {
+ int i;
+
+ if (*((unsigned int *)(base_adr + I2C_ABORT_SOURCE)) & 0x1ffff) {
+ /*Reading back I2C_CLR_TX_ABRT resets abort lock on TX FIFO*/
+ i = *((volatile unsigned int *)(base_adr + I2C_CLR_TX_ABRT));
+ return I2C_ERR_ABORT |
+ (*((unsigned int *)(base_adr + I2C_ABORT_SOURCE)) & 0x1ffff);
+ }
+
+ /*Wait here for a received entry in RX-FIFO */
+ i = I2C_TIMEOUT;
+ while ((!(*((volatile unsigned int *)(base_adr + I2C_STATUS)) & I2C_RFNE))
+ && (i)) {
+ udelay(1);
+ i--;
+ }
+
+ if (i == 0) {
+ return I2C_ERR_TIMEOUT;
+ } else {
+ return I2C_NO_ERROR;
+ }
+}
+
+/* When there will be a fast switch between send and receive, one have
+ * to wait until the first operation is completely finished
+ * before starting the second operation
+ */
+static int wait_for_idle(char *base_adr)
+{
+ int i;
+ volatile int status;
+
+ /*For IDLE, increase timeout by ten times*/
+ i = I2C_TIMEOUT * 10;
+ status = *((volatile unsigned int *)(base_adr + I2C_STATUS));
+ while(((status & I2C_MST_ACTIVITY) || (!(status & I2C_TFE))) && (i)) {
+ status = *((volatile unsigned int *)(base_adr + I2C_STATUS));
+ udelay(1);
+ i--;
+ }
+
+ if (i == 0) {
+ return I2C_ERR_TIMEOUT;
+ } else {
+ return I2C_NO_ERROR;
+ }
+}
+
+/** \brief Enables I2C-controller, sets up BAR and timing parameters
+ * @param bus Number of the I2C-controller to use (0...6)
+ * @return 0 on success, otherwise error code
+ */
+int i2c_init(unsigned bus)
+{
+ device_t dev;
+ int base_adr[7] = {I2C0_MEM_BASE, I2C1_MEM_BASE, I2C2_MEM_BASE,
+ I2C3_MEM_BASE, I2C4_MEM_BASE, I2C5_MEM_BASE,
+ I2C6_MEM_BASE};
+ char *base_ptr = (char*)base_adr[bus];
+ /* Ensure the desired device is valid*/
+ if (bus > 6) {
+ printk (BIOS_ERR, "I2C: Only I2C controllers 0...6 are available");
+ return 1;
+ }
+
+ /*Set the I2C-device the user wants to use */
+ dev = dev_find_slot(0, PCI_DEVFN(I2C1_DEV, bus + 1));
+
+ /* Ensure we have the right PCI device */
+ if ((pci_read_config16(dev, 0x0) != I2C_PCI_VENDOR_ID) ||
+ (pci_read_config16(dev, 0x2) != (I2C0_PCI_DEV_ID + bus))) {
+ printk(BIOS_ERR, "I2C: Controller %d not found!", bus);
+ return 2;
+ }
+
+ /* Set memory base*/
+ pci_write_config32(dev, PCI_BASE_ADDRESS_0,(int)base_ptr);
+
+ /* Enable memory space*/
+ pci_write_config32(dev, PCI_COMMAND,
+ (pci_read_config32(dev, PCI_COMMAND) | 0x2));
+
+ /*Set up some settings of I2C controller*/
+ *((unsigned int *)(base_ptr + I2C_CTRL)) = (I2C_RESTART_EN
+ | (I2C_STANDARD_MODE << 1)
+ | I2C_MASTER_ENABLE);
+ /*Adjust frequency for standard mode to 100 kHz*/
+ /*The counter value can be computed by N=100MHz/2/I2C_CLK*/
+ /*Thus, for 100 kHz I2C_CLK, N is 0x1F4*/
+ *((unsigned int *)(base_ptr + I2C_SS_SCL_HCNT)) = 0x1f4;
+ *((unsigned int *)(base_ptr + I2C_SS_SCL_LCNT)) = 0x1f4;
+ /*For 400 kHz, the counter value is 0x7d*/
+ *((unsigned int *)(base_ptr + I2C_FS_SCL_HCNT)) = 0x7d;
+ *((unsigned int *)(base_ptr + I2C_FS_SCL_LCNT)) = 0x7d;
+
+ /* Enable the I2C controller for operation*/
+ *((unsigned int *)(base_ptr + I2C_ENABLE)) = 0x1;
+
+ printk(BIOS_INFO, "I2C: Controller %d enabled.\n", bus);
+ return I2C_NO_ERROR;
+}
+
+/** \brief Read bytes over I2C-Bus from a slave. This function tries only one
+ * time to transmit data. In case of an error (abort) error code is
+ * returned. Retransmission has to be done from caller!
+ * @param bus Number of the I2C-controller to use (0...6)
+ * @param chip 7 Bit of the slave address on I2C bus
+ * @param addr Address inside slave where to read from
+ * @param *buf Pointer to the buffer where to store read data
+ * @param len Number of bytes to read
+ * @return I2C_NO_ERROR when read was successful, otherwise error code
+ */
+int i2c_read(unsigned bus, unsigned chip, unsigned addr,
+ uint8_t *buf, unsigned len)
+{
+ int i = 0;
+ char *base_ptr = NULL;
+ device_t dev;
+ unsigned int val;
+ int stat;
+
+ /*Get base address of desired I2C-controller*/
+ dev = dev_find_slot(0, PCI_DEVFN(I2C1_DEV, bus + 1));
+ base_ptr = (char *)pci_read_config32(dev, PCI_BASE_ADDRESS_0);
+ if (base_ptr == NULL) {
+ printk(BIOS_INFO, "I2C: Invalid Base address\n");
+ return I2C_ERR_INVALID_ADR;
+ }
+
+ /*Ensure I2C controller is not active before setting slave address*/
+ stat = wait_for_idle(base_ptr);
+ if (stat != I2C_NO_ERROR) {
+ return stat;
+ }
+ /* Now we can program the desired slave address and start transfer*/
+ *((unsigned int *)(base_ptr + I2C_TARGET_ADR)) = (chip & 0xff);
+ /* Send address inside slave to read from*/
+ *((unsigned int *)(base_ptr + I2C_DATA_CMD)) = (addr & 0xff);
+
+ /* For the next byte we need a repeated start condition*/
+ val = I2C_RW_CMD | I2C_RESTART;
+ /* Now we can read desired amount of data over I2C*/
+ for (i = 0; i < len; i++) {
+ /*A read is initiated by writing dummy data to the DATA-register*/
+ *((unsigned int *)(base_ptr + I2C_DATA_CMD)) = val;
+ stat = wait_rx_fifo(base_ptr);
+ if (stat) {
+ return stat;
+ }
+ buf[i] = (*((unsigned int *)(base_ptr + I2C_DATA_CMD))) & 0xff;
+ val = I2C_RW_CMD;
+ if (i == (len -2)) {
+ /* For the last byte we need a stop condition to be generated*/
+ val |= I2C_STOP;
+ }
+ }
+ return I2C_NO_ERROR;
+}
+
+/** \brief Write bytes over I2C-Bus from a slave. This function tries only one
+ * time to transmit data. In case of an error (abort) error code is
+ * returned. Retransmission has to be done from caller!
+ * @param bus Number of the I2C-controller to use (0...6)
+ * @param chip 7 Bit of the slave address on I2C bus
+ * @param addr Address inside slave where to write to
+ * @param *buf Pointer to the buffer where data to write is stored
+ * @param len Number of bytes to write
+ * @return I2C_NO_ERROR when read was successful, otherwise error code
+ */
+int i2c_write(unsigned bus, unsigned chip, unsigned addr,
+ const uint8_t *buf, unsigned len)
+{
+ int i;
+ char *base_ptr;
+ device_t dev;
+ unsigned int val;
+ int stat;
+
+ /*Get base address of desired I2C-controller*/
+ dev = dev_find_slot(0, PCI_DEVFN(I2C1_DEV, bus + 1));
+ base_ptr = (char *)pci_read_config32(dev, PCI_BASE_ADDRESS_0);
+ if (base_ptr == NULL) {
+ return I2C_ERR_INVALID_ADR;
+ }
+
+ /*Ensure I2C controller is not active jet*/
+ stat = wait_for_idle(base_ptr);
+ if (stat) {
+ return stat;
+ }
+ /*Program slave address to use for this transfer*/
+ *((unsigned int *)(base_ptr + I2C_TARGET_ADR)) = (chip & 0xff);
+
+ /* Send address inside slave to write data to*/
+ *((unsigned int *)(base_ptr + I2C_DATA_CMD)) = (addr & 0xff);
+
+ for (i = 0; i < len; i++) {
+ val = (unsigned int)(buf[i] & 0xff); /* Take only 8 bits*/
+ if (i == (len -1)) {
+ /* For the last byte we need a stop condition to be generated*/
+ val |= I2C_STOP;
+ }
+ stat = wait_tx_fifo(base_ptr);
+ if (stat) {
+ return stat;
+ }
+ *((unsigned int *)(base_ptr + I2C_DATA_CMD)) = val;
+ }
+ return I2C_NO_ERROR;
+}
Alexander Couzens (lynxis(a)fe80.eu) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8400
-gerrit
commit 08a838c02755b066e2279c60b1f9d99da6f821c5
Author: Alexander Couzens <lynxis(a)fe80.eu>
Date: Sun Feb 8 12:00:28 2015 +0100
add amdtool: an opponent to inteltool
This first version only dumps the index register space
for AMD 14h.
Change-Id: I86627ef319f9732f9188161551bdcd0605c4c112
Signed-off-by: Alexander Couzens <lynxis(a)fe80.eu>
---
util/amdtool/Makefile | 39 ++++++++++++
util/amdtool/amdtool.c | 38 ++++++++++++
util/amdtool/amdtool.h | 37 ++++++++++++
util/amdtool/cmn.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++
util/amdtool/cmn.h | 42 +++++++++++++
util/amdtool/index.c | 98 ++++++++++++++++++++++++++++++
6 files changed, 414 insertions(+)
diff --git a/util/amdtool/Makefile b/util/amdtool/Makefile
new file mode 100644
index 0000000..21350c4
--- /dev/null
+++ b/util/amdtool/Makefile
@@ -0,0 +1,39 @@
+##
+## Makefile for amd_10h_tool
+##
+## Copyright (C) 2014 Alexander Couzens <lynxis(a)fe80.eu>
+##
+## 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
+##
+
+CC = gcc
+CFLAGS = -O2 -Wall -W -std=c99
+PROGRAM = amdtool
+INSTALL = /usr/bin/install
+PREFIX = /usr/local
+LDFLAGS = -lpci
+
+all: $(PROGRAM)
+
+$(PROGRAM): amdtool.o cmn.o index.o
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+install: $(PROGRAM)
+ $(INSTALL) $(PROGRAM) $(PREFIX)/sbin
+
+clean:
+ rm *.o $(PROGRAM)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $^ -I. -o $@
diff --git a/util/amdtool/amdtool.c b/util/amdtool/amdtool.c
new file mode 100644
index 0000000..f6ef7ac
--- /dev/null
+++ b/util/amdtool/amdtool.c
@@ -0,0 +1,38 @@
+/*
+ * amdtool - dump all registers on an AMD CPU + chipset based system.
+ *
+ * Copyright (C) 2015 Alexander Couzens <lynxis(a)fe80.eu>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <pci/pci.h>
+
+#include "amdtool.h"
+#include "cmn.h"
+
+int main() {
+ struct pci_access *pci_acc = pci_alloc();
+ struct pci_dev *dev = NULL;
+
+ pci_init(pci_acc);
+ dev = pci_get_dev(pci_acc, 0, 0, 0, 0);
+ pci_fill_info(dev, PCI_FILL_CLASS|PCI_FILL_IDENT|PCI_FILL_BASES|PCI_FILL_SIZES|PCI_FILL_CLASS);
+
+ print_index(dev);
+
+ return 0;
+}
diff --git a/util/amdtool/amdtool.h b/util/amdtool/amdtool.h
new file mode 100644
index 0000000..b9a7eb9
--- /dev/null
+++ b/util/amdtool/amdtool.h
@@ -0,0 +1,37 @@
+/*
+ * amdtool - dump all registers on an AMD CPU + chipset based system.
+ *
+ * Copyright (C) 2015 Alexander Couzens <lynxis(a)fe80.eu>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef AMDTOOL_H_
+#define AMDTOOL_H_
+
+#include <stdint.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+#define PCI_VENDOR_ID_AMD 0x1022
+
+#define PCI_VENDOR_ID_AMD_NB_14H 0x1510
+
+typedef struct { uint32_t addr; int size; char *name; } io_register_t;
+
+void print_index(struct pci_dev *nb);
+
+#endif /* AMDTOOL_H_ */
diff --git a/util/amdtool/cmn.c b/util/amdtool/cmn.c
new file mode 100644
index 0000000..4795e5a
--- /dev/null
+++ b/util/amdtool/cmn.c
@@ -0,0 +1,160 @@
+/*
+ * amdtool - dump all registers on an AMD CPU + chipset based system.
+ *
+ * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <pci/pci.h>
+
+#define NBMISC_INDEX 0x60
+#define NBPCIE_INDEX 0xE0
+#define NBMC_INDEX 0xE8
+#define NBHTIU_INDEX 0x94
+
+#define pci_read_config32 pci_read_long
+#define pci_read_config8 pci_read_byte
+#define pci_write_config32 pci_write_long
+#define pci_write_config8 pci_write_byte
+
+static u32 nb_read_index(struct pci_dev * dev, u32 index_reg, u32 index)
+{
+ pci_write_config32(dev, index_reg, index);
+ return pci_read_config32(dev, index_reg + 0x4);
+}
+
+static void nb_write_index(struct pci_dev * dev, u32 index_reg, u32 index, u32 data)
+{
+ pci_write_config32(dev, index_reg, index);
+ pci_write_config32(dev, index_reg + 0x4, data);
+}
+
+
+u32 nbmisc_read_index(struct pci_dev * nb_dev, u32 index)
+{
+ return nb_read_index((nb_dev), NBMISC_INDEX, (index));
+}
+
+void nbmisc_write_index(struct pci_dev * nb_dev, u32 index, u32 data)
+{
+ nb_write_index((nb_dev), NBMISC_INDEX, ((index) | 0x80), (data));
+}
+
+u32 nbpcie_p_read_index(struct pci_dev * dev, u32 index)
+{
+ return nb_read_index((dev), NBPCIE_INDEX, (index));
+}
+
+void nbpcie_p_write_index(struct pci_dev * dev, u32 index, u32 data)
+{
+ nb_write_index((dev), NBPCIE_INDEX, (index), (data));
+}
+
+u32 nbpcie_ind_read_index(struct pci_dev * nb_dev, u32 index)
+{
+ return nb_read_index((nb_dev), NBPCIE_INDEX, (index));
+}
+
+void nbpcie_ind_write_index(struct pci_dev * nb_dev, u32 index, u32 data)
+{
+ nb_write_index((nb_dev), NBPCIE_INDEX, (index), (data));
+}
+
+u32 htiu_read_index(struct pci_dev * nb_dev, u32 index)
+{
+ return nb_read_index((nb_dev), NBHTIU_INDEX, (index));
+}
+
+void htiu_write_index(struct pci_dev * nb_dev, u32 index, u32 data)
+{
+ nb_write_index((nb_dev), NBHTIU_INDEX, ((index) | 0x100), (data));
+}
+
+u32 nbmc_read_index(struct pci_dev * nb_dev, u32 index)
+{
+ return nb_read_index((nb_dev), NBMC_INDEX, (index));
+}
+
+void nbmc_write_index(struct pci_dev * nb_dev, u32 index, u32 data)
+{
+ nb_write_index((nb_dev), NBMC_INDEX, ((index) | 1 << 9), (data));
+}
+
+void set_nbcfg_enable_bits(struct pci_dev * nb_dev, u32 reg_pos, u32 mask, u32 val)
+{
+ u32 reg_old, reg;
+ reg = reg_old = pci_read_config32(nb_dev, reg_pos);
+ reg &= ~mask;
+ reg |= val;
+ if (reg != reg_old) {
+ pci_write_config32(nb_dev, reg_pos, reg);
+ }
+}
+
+void set_nbcfg_enable_bits_8(struct pci_dev * nb_dev, u32 reg_pos, u8 mask, u8 val)
+{
+ u8 reg_old, reg;
+ reg = reg_old = pci_read_config8(nb_dev, reg_pos);
+ reg &= ~mask;
+ reg |= val;
+ if (reg != reg_old) {
+ pci_write_config8(nb_dev, reg_pos, reg);
+ }
+}
+
+void set_nbmc_enable_bits(struct pci_dev * nb_dev, u32 reg_pos, u32 mask, u32 val)
+{
+ u32 reg_old, reg;
+ reg = reg_old = nbmc_read_index(nb_dev, reg_pos);
+ reg &= ~mask;
+ reg |= val;
+ if (reg != reg_old) {
+ nbmc_write_index(nb_dev, reg_pos, reg);
+ }
+}
+
+void set_htiu_enable_bits(struct pci_dev * nb_dev, u32 reg_pos, u32 mask, u32 val)
+{
+ u32 reg_old, reg;
+ reg = reg_old = htiu_read_index(nb_dev, reg_pos);
+ reg &= ~mask;
+ reg |= val;
+ if (reg != reg_old) {
+ htiu_write_index(nb_dev, reg_pos, reg);
+ }
+}
+
+void set_nbmisc_enable_bits(struct pci_dev * nb_dev, u32 reg_pos, u32 mask, u32 val)
+{
+ u32 reg_old, reg;
+ reg = reg_old = nbmisc_read_index(nb_dev, reg_pos);
+ reg &= ~mask;
+ reg |= val;
+ if (reg != reg_old) {
+ nbmisc_write_index(nb_dev, reg_pos, reg);
+ }
+}
+
+void set_pcie_enable_bits(struct pci_dev * dev, u32 reg_pos, u32 mask, u32 val)
+{
+ u32 reg_old, reg;
+ reg = reg_old = nb_read_index(dev, NBPCIE_INDEX, reg_pos);
+ reg &= ~mask;
+ reg |= val;
+ if (reg != reg_old) {
+ nb_write_index(dev, NBPCIE_INDEX, reg_pos, reg);
+ }
+}
diff --git a/util/amdtool/cmn.h b/util/amdtool/cmn.h
new file mode 100644
index 0000000..b78254f
--- /dev/null
+++ b/util/amdtool/cmn.h
@@ -0,0 +1,42 @@
+/*
+ * amdtool - dump all registers on an AMD CPU + chipset based system.
+ *
+ * Copyright (C) 2008 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef CMN_H__H_
+#define CMN_H__H_
+
+struct pci_dev;
+
+u32 nbmisc_read_index(struct pci_dev * nb_dev, u32 index);
+void nbmisc_write_index(struct pci_dev * nb_dev, u32 index, u32 data);
+u32 nbpcie_p_read_index(struct pci_dev * dev, u32 index);
+void nbpcie_p_write_index(struct pci_dev * dev, u32 index, u32 data);
+u32 nbpcie_ind_read_index(struct pci_dev * nb_dev, u32 index);
+void nbpcie_ind_write_index(struct pci_dev * nb_dev, u32 index, u32 data);
+u32 htiu_read_index(struct pci_dev * nb_dev, u32 index);
+void htiu_write_index(struct pci_dev * nb_dev, u32 index, u32 data);
+u32 nbmc_read_index(struct pci_dev * nb_dev, u32 index);
+void nbmc_write_index(struct pci_dev * nb_dev, u32 index, u32 data);
+void set_nbcfg_enable_bits(struct pci_dev * nb_dev, u32 reg_pos, u32 mask, u32 val);
+void set_nbcfg_enable_bits_8(struct pci_dev * nb_dev, u32 reg_pos, u8 mask, u8 val);
+void set_nbmc_enable_bits(struct pci_dev * nb_dev, u32 reg_pos, u32 mask, u32 val);
+void set_htiu_enable_bits(struct pci_dev * nb_dev, u32 reg_pos, u32 mask, u32 val);
+void set_nbmisc_enable_bits(struct pci_dev * nb_dev, u32 reg_pos, u32 mask, u32 val);
+void set_pcie_enable_bits(struct pci_dev * dev, u32 reg_pos, u32 mask, u32 val);
+
+#endif /* CMN_H__H_ */
diff --git a/util/amdtool/index.c b/util/amdtool/index.c
new file mode 100644
index 0000000..b2d870e
--- /dev/null
+++ b/util/amdtool/index.c
@@ -0,0 +1,98 @@
+/*
+ * amdtool - dump all registers on an AMD CPU + chipset based system.
+ *
+ * Copyright (C) 2015 Alexander Couzens <lynxis(a)fe80.eu>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <pci/pci.h>
+
+#include "amdtool.h"
+#include "cmn.h"
+
+/* AMD 14h documentation based on
+ * BIOS and Kernel Developer’s Guide (BKDG) for AMD Family 14h Models 00h-0Fh Processors
+ * 43170 Rev 3.13 - February 17, 2012
+ */
+
+static const io_register_t amd_14_e4[] = {
+ /* IO Link */
+ { 0x01010002, 4, "IO Link Hardware Debug"},
+ { 0x01010010, 4, "IO Link Control 1"},
+ { 0x01010011, 4, "IO Link Config Control"},
+ { 0x0101001C, 4, "IO Link Control 2"},
+ { 0x01010020, 4, "IO Link Chip Interface Control"},
+ { 0x01010040, 4, "IO Link Phy Control"},
+ { 0x010100B0, 4, "IO Link Strap Control"},
+ { 0x010100C0, 4, "IO Link Strap Miscellaneous"},
+ { 0x010100C1, 4, "IO Link Strap Miscellaneous"},
+ /* Impedance Controller Registers */
+ { 0x01088071, 4, "Receiver Impedance Adjustment"},
+ { 0x01088072, 4, "Transmitter Impedance Adjustment"},
+ /* TODO: PIF Registers */
+ /* Wrapper Registers */
+ { 0x01300000, 4, "BIF Core Feature Enable"},
+ { 0x01300002, 4, "Link Speed Control"},
+ { 0x01300080, 4, "Link Configuration"},
+ { 0x01300800, 4, "Device 8 Link Training Control"},
+ { 0x01300803, 4, "Device 8 Link De-emphasis Control"},
+ { 0x01300900, 4, "Device 4 Link Training Control"},
+ { 0x01300903, 4, "Device 4 Link De-emphasis Control"},
+ { 0x01300a00, 4, "Device 5 Link Training Control"},
+ { 0x01300a03, 4, "Device 5 Link De-emphasis Control"},
+ { 0x01300b00, 4, "Device 6 Link Training Control"},
+ { 0x01300b03, 4, "Device 6 Link De-emphasis Control"},
+ { 0x01300c00, 4, "Device 7 Link Training Control"},
+ { 0x01300c03, 4, "Device 7 Link De-emphasis Control"},
+ { 0x01308002, 4, "Subsystem and Subvendor ID Control"},
+ { 0x01308011, 4, "Link Transmit Clock Gating Control"},
+ { 0x01308012, 4, "Link Transmit Clock Gating Control 2"},
+ { 0x01308013, 4, "Transmit Clock PLL Control"},
+ { 0x01308016, 4, "Link Clock Switching Control"},
+ { 0x01308021, 4, "Transmitter Lane Mux"},
+ { 0x01308022, 4, "Receiver Lane Mux"},
+ { 0x01308023, 4, "Lane Enable"},
+ { 0x01308025, 4, "Lane Mux Power Sequence Control 0"},
+ { 0x01308031, 4, "Lane Counter Status"},
+ { 0x01308060, 4, "Soft Reset Command 0"},
+ { 0x01308061, 4, "Soft Reset Command 1"},
+ { 0x01308062, 4, "Soft Reset Control 0"},
+ { 0x013080F0, 4, "BIOS Timer"},
+ { 0x013080F1, 4, "BIOS Timer Control"},
+};
+
+void print_index(struct pci_dev *nb)
+{
+ int index_size = 0;
+ const io_register_t *index;
+
+ printf("=== Index Register Space ===\n");
+ switch (nb->device_id) {
+ case PCI_VENDOR_ID_AMD_NB_14H:
+ index_size = ARRAY_SIZE(amd_14_e4);
+ index = amd_14_e4;
+ break;
+ default:
+ printf("Unsupported Northbridge pci %x\n", nb->device_id);
+ return;
+ break;
+ }
+
+ for (int i=0; i < index_size; i++) {
+ printf("0x%08x = 0x%08x - %s\n", index[i].addr, nbpcie_p_read_index(nb, index[i].addr), index[i].name);
+ }
+}