[coreboot-gerrit] Patch set updated for coreboot: 5e17bc1 AGESA fam12 fam14 fam15: Use common agesa_readSpd()

Kyösti Mälkki (kyosti.malkki@gmail.com) gerrit at coreboot.org
Sat Oct 18 08:33:08 CEST 2014


Kyösti Mälkki (kyosti.malkki at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/7113

-gerrit

commit 5e17bc1c28bc05f8da4d6c4dccba0d857d20cf49
Author: Kyösti Mälkki <kyosti.malkki at gmail.com>
Date:   Fri Oct 17 22:33:22 2014 +0300

    AGESA fam12 fam14 fam15: Use common agesa_readSpd()
    
    Remove northbridge specific callouts for AGESA_READ_SPD.
    
    Move low-level SMBus code to southbridge.
    
    Change-Id: I5fc91c49d9ef8e0af1c4d8194f857c61ce417d1d
    Signed-off-by: Kyösti Mälkki <kyosti.malkki at gmail.com>
---
 src/mainboard/amd/dinar/BiosCallOuts.c             |   5 +-
 src/mainboard/amd/inagua/BiosCallOuts.c            |   3 +-
 src/mainboard/amd/persimmon/BiosCallOuts.c         |   3 +-
 src/mainboard/amd/south_station/BiosCallOuts.c     |   3 +-
 src/mainboard/amd/torpedo/BiosCallOuts.c           |   2 +-
 src/mainboard/amd/union_station/BiosCallOuts.c     |   3 +-
 src/mainboard/asrock/e350m1/BiosCallOuts.c         |   3 +-
 src/mainboard/jetway/nf81-t56n-lf/BiosCallOuts.c   |   3 +-
 .../lippert/frontrunner-af/BiosCallOuts.c          |   3 +-
 src/mainboard/lippert/toucan-af/BiosCallOuts.c     |   3 +-
 src/mainboard/supermicro/h8qgi/BiosCallOuts.c      |   3 +-
 src/mainboard/supermicro/h8scm/BiosCallOuts.c      |  19 +--
 src/mainboard/tyan/s8226/BiosCallOuts.c            |   3 +-
 src/northbridge/amd/agesa/def_callouts.c           |   2 +-
 src/northbridge/amd/agesa/family12/Makefile.inc    |   1 -
 src/northbridge/amd/agesa/family12/dimmSpd.c       | 177 +--------------------
 src/northbridge/amd/agesa/family12/dimmSpd.h       |  63 --------
 .../amd/agesa/family12/fam12_callouts.c            |   9 --
 .../amd/agesa/family12/fam12_callouts.h            |   2 -
 src/northbridge/amd/agesa/family14/dimmSpd.c       |  94 +----------
 src/northbridge/amd/agesa/family14/dimmSpd.h       |  83 ----------
 .../amd/agesa/family14/fam14_callouts.c            |  14 --
 .../amd/agesa/family14/fam14_callouts.h            |   2 -
 src/northbridge/amd/agesa/family15/dimmSpd.c       | 134 +---------------
 src/northbridge/amd/agesa/family15/dimmSpd.h       |  97 -----------
 .../amd/agesa/family15/fam15_callouts.c            |   1 -
 src/southbridge/amd/cimx/sb700/Makefile.inc        |   2 +-
 src/southbridge/amd/cimx/sb700/smbus_spd.c         | 164 +++++++++++++++++++
 src/southbridge/amd/cimx/sb700/smbus_spd.h         |  65 ++++++++
 src/southbridge/amd/cimx/sb800/Makefile.inc        |   2 +-
 src/southbridge/amd/cimx/sb800/smbus_spd.c         | 123 ++++++++++++++
 src/southbridge/amd/cimx/sb800/smbus_spd.h         |  51 ++++++
 src/southbridge/amd/cimx/sb900/Makefile.inc        |   2 +-
 src/southbridge/amd/cimx/sb900/smbus_spd.c         | 177 +++++++++++++++++++++
 34 files changed, 622 insertions(+), 699 deletions(-)

diff --git a/src/mainboard/amd/dinar/BiosCallOuts.c b/src/mainboard/amd/dinar/BiosCallOuts.c
index c5267dc..72424f8 100644
--- a/src/mainboard/amd/dinar/BiosCallOuts.c
+++ b/src/mainboard/amd/dinar/BiosCallOuts.c
@@ -24,10 +24,11 @@
 #include "OptionsIds.h"
 #include "heapManager.h"
 #include "SB700.h"
-#include <northbridge/amd/agesa/family15/dimmSpd.h>
 #include "OEM.h"		/* SMBUS0_BASE_ADDRESS */
 #include <stdlib.h>
 
+#include <southbridge/amd/cimx/sb700/smbus_spd.h>
+
 #ifndef SB_GPIO_REG01
 #define SB_GPIO_REG01   1
 #endif
@@ -117,7 +118,7 @@ static AGESA_STATUS board_ReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
 
 	select_socket(((AGESA_READ_SPD_PARAMS *)ConfigPtr)->SocketId);
 
-	Status = agesa_ReadSPD (Func, Data, ConfigPtr);
+	Status = agesa_ReadSpd (Func, Data, ConfigPtr);
 
 	restore_socket();
 #else
diff --git a/src/mainboard/amd/inagua/BiosCallOuts.c b/src/mainboard/amd/inagua/BiosCallOuts.c
index f67d879..5613012 100644
--- a/src/mainboard/amd/inagua/BiosCallOuts.c
+++ b/src/mainboard/amd/inagua/BiosCallOuts.c
@@ -22,7 +22,6 @@
 #include "BiosCallOuts.h"
 #include "heapManager.h"
 #include "SB800.h"
-#include <northbridge/amd/agesa/family14/dimmSpd.h>
 #include <stdlib.h>
 
 static AGESA_STATUS board_BeforeDramInit (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
@@ -34,7 +33,7 @@ const BIOS_CALLOUT_STRUCT BiosCallouts[] =
 	{AGESA_DEALLOCATE_BUFFER,		agesa_DeallocateBuffer },
 	{AGESA_LOCATE_BUFFER,			agesa_LocateBuffer },
 	{AGESA_DO_RESET,			agesa_Reset },
-	{AGESA_READ_SPD,			BiosReadSpd },
+	{AGESA_READ_SPD,			agesa_ReadSpd },
 	{AGESA_READ_SPD_RECOVERY,		agesa_NoopUnsupported },
 	{AGESA_RUNFUNC_ONAP,			agesa_RunFuncOnAp },
 	{AGESA_GNB_PCIE_SLOT_RESET,		board_GnbPcieSlotReset },
diff --git a/src/mainboard/amd/persimmon/BiosCallOuts.c b/src/mainboard/amd/persimmon/BiosCallOuts.c
index cfd9c6f..c700324 100644
--- a/src/mainboard/amd/persimmon/BiosCallOuts.c
+++ b/src/mainboard/amd/persimmon/BiosCallOuts.c
@@ -22,7 +22,6 @@
 #include "BiosCallOuts.h"
 #include "heapManager.h"
 #include "SB800.h"
-#include <northbridge/amd/agesa/family14/dimmSpd.h>
 #include <stdlib.h>
 
 static AGESA_STATUS board_BeforeDramInit (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
@@ -34,7 +33,7 @@ const BIOS_CALLOUT_STRUCT BiosCallouts[] =
 	{AGESA_DEALLOCATE_BUFFER,		agesa_DeallocateBuffer },
 	{AGESA_LOCATE_BUFFER,			agesa_LocateBuffer },
 	{AGESA_DO_RESET,			agesa_Reset },
-	{AGESA_READ_SPD,			BiosReadSpd },
+	{AGESA_READ_SPD,			agesa_ReadSpd },
 	{AGESA_READ_SPD_RECOVERY,		agesa_NoopUnsupported },
 	{AGESA_RUNFUNC_ONAP,			agesa_RunFuncOnAp },
 	{AGESA_GNB_PCIE_SLOT_RESET,		board_GnbPcieSlotReset },
diff --git a/src/mainboard/amd/south_station/BiosCallOuts.c b/src/mainboard/amd/south_station/BiosCallOuts.c
index 6dfad31..272a394 100644
--- a/src/mainboard/amd/south_station/BiosCallOuts.c
+++ b/src/mainboard/amd/south_station/BiosCallOuts.c
@@ -22,7 +22,6 @@
 #include "BiosCallOuts.h"
 #include "heapManager.h"
 #include "SB800.h"
-#include <northbridge/amd/agesa/family14/dimmSpd.h>
 #include <stdlib.h>
 
 static AGESA_STATUS board_BeforeDramInit (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
@@ -34,7 +33,7 @@ const BIOS_CALLOUT_STRUCT BiosCallouts[] =
 	{AGESA_DEALLOCATE_BUFFER,		agesa_DeallocateBuffer },
 	{AGESA_LOCATE_BUFFER,			agesa_LocateBuffer },
 	{AGESA_DO_RESET,			agesa_Reset },
-	{AGESA_READ_SPD,			BiosReadSpd },
+	{AGESA_READ_SPD,			agesa_ReadSpd },
 	{AGESA_READ_SPD_RECOVERY,		agesa_NoopUnsupported },
 	{AGESA_RUNFUNC_ONAP,			agesa_RunFuncOnAp },
 	{AGESA_GNB_PCIE_SLOT_RESET,		board_GnbPcieSlotReset },
diff --git a/src/mainboard/amd/torpedo/BiosCallOuts.c b/src/mainboard/amd/torpedo/BiosCallOuts.c
index 8422f1d..38d4003 100644
--- a/src/mainboard/amd/torpedo/BiosCallOuts.c
+++ b/src/mainboard/amd/torpedo/BiosCallOuts.c
@@ -47,7 +47,7 @@ const BIOS_CALLOUT_STRUCT BiosCallouts[] =
 	{AGESA_DEALLOCATE_BUFFER,		agesa_DeallocateBuffer },
 	{AGESA_LOCATE_BUFFER,			agesa_LocateBuffer },
 	{AGESA_DO_RESET,			agesa_Reset },
-	{AGESA_READ_SPD,			BiosReadSpd },
+	{AGESA_READ_SPD,			agesa_ReadSpd },
 	{AGESA_READ_SPD_RECOVERY,		agesa_NoopUnsupported },
 	{AGESA_RUNFUNC_ONAP,			agesa_RunFuncOnAp },
 	{AGESA_GNB_PCIE_SLOT_RESET,		board_GnbPcieSlotReset },
diff --git a/src/mainboard/amd/union_station/BiosCallOuts.c b/src/mainboard/amd/union_station/BiosCallOuts.c
index 6dfad31..272a394 100644
--- a/src/mainboard/amd/union_station/BiosCallOuts.c
+++ b/src/mainboard/amd/union_station/BiosCallOuts.c
@@ -22,7 +22,6 @@
 #include "BiosCallOuts.h"
 #include "heapManager.h"
 #include "SB800.h"
-#include <northbridge/amd/agesa/family14/dimmSpd.h>
 #include <stdlib.h>
 
 static AGESA_STATUS board_BeforeDramInit (UINT32 Func, UINT32 Data, VOID *ConfigPtr);
@@ -34,7 +33,7 @@ const BIOS_CALLOUT_STRUCT BiosCallouts[] =
 	{AGESA_DEALLOCATE_BUFFER,		agesa_DeallocateBuffer },
 	{AGESA_LOCATE_BUFFER,			agesa_LocateBuffer },
 	{AGESA_DO_RESET,			agesa_Reset },
-	{AGESA_READ_SPD,			BiosReadSpd },
+	{AGESA_READ_SPD,			agesa_ReadSpd },
 	{AGESA_READ_SPD_RECOVERY,		agesa_NoopUnsupported },
 	{AGESA_RUNFUNC_ONAP,			agesa_RunFuncOnAp },
 	{AGESA_GNB_PCIE_SLOT_RESET,		board_GnbPcieSlotReset },
diff --git a/src/mainboard/asrock/e350m1/BiosCallOuts.c b/src/mainboard/asrock/e350m1/BiosCallOuts.c
index 09571dd..4a39cd6 100644
--- a/src/mainboard/asrock/e350m1/BiosCallOuts.c
+++ b/src/mainboard/asrock/e350m1/BiosCallOuts.c
@@ -22,7 +22,6 @@
 #include "BiosCallOuts.h"
 #include "heapManager.h"
 #include "SB800.h"
-#include <northbridge/amd/agesa/family14/dimmSpd.h>
 #include <stdlib.h>
 
 /* Should AGESA_GNB_PCIE_SLOT_RESET use agesa_NoopSuccess?
@@ -39,7 +38,7 @@ const BIOS_CALLOUT_STRUCT BiosCallouts[] =
 	{AGESA_DEALLOCATE_BUFFER,		agesa_DeallocateBuffer },
 	{AGESA_LOCATE_BUFFER,			agesa_LocateBuffer },
 	{AGESA_DO_RESET,			agesa_Reset },
-	{AGESA_READ_SPD,			BiosReadSpd },
+	{AGESA_READ_SPD,			agesa_ReadSpd },
 	{AGESA_READ_SPD_RECOVERY,		agesa_NoopUnsupported },
 	{AGESA_RUNFUNC_ONAP,			agesa_RunFuncOnAp },
 	{AGESA_HOOKBEFORE_DQS_TRAINING,		agesa_NoopSuccess },
diff --git a/src/mainboard/jetway/nf81-t56n-lf/BiosCallOuts.c b/src/mainboard/jetway/nf81-t56n-lf/BiosCallOuts.c
index b3199ca..dd3d4cf 100644
--- a/src/mainboard/jetway/nf81-t56n-lf/BiosCallOuts.c
+++ b/src/mainboard/jetway/nf81-t56n-lf/BiosCallOuts.c
@@ -21,7 +21,6 @@
 #include "BiosCallOuts.h"
 
 #include <Lib/amdlib.h>
-#include <northbridge/amd/agesa/family14/dimmSpd.h>
 #include <vendorcode/amd/agesa/f14/Proc/CPU/heapManager.h>
 #include <vendorcode/amd/cimx/sb800/SB800.h>
 #include <stdint.h>
@@ -36,7 +35,7 @@ const BIOS_CALLOUT_STRUCT BiosCallouts[] =
 	{AGESA_DEALLOCATE_BUFFER,		agesa_DeallocateBuffer },
 	{AGESA_LOCATE_BUFFER,			agesa_LocateBuffer },
 	{AGESA_DO_RESET,			agesa_Reset },
-	{AGESA_READ_SPD,			BiosReadSpd },
+	{AGESA_READ_SPD,			agesa_ReadSpd },
 	{AGESA_READ_SPD_RECOVERY,		agesa_NoopUnsupported },
 	{AGESA_RUNFUNC_ONAP,			agesa_RunFuncOnAp },
 	{AGESA_GNB_PCIE_SLOT_RESET,		board_GnbPcieSlotReset },
diff --git a/src/mainboard/lippert/frontrunner-af/BiosCallOuts.c b/src/mainboard/lippert/frontrunner-af/BiosCallOuts.c
index 0264256..3104c24 100644
--- a/src/mainboard/lippert/frontrunner-af/BiosCallOuts.c
+++ b/src/mainboard/lippert/frontrunner-af/BiosCallOuts.c
@@ -21,7 +21,6 @@
 #include "amdlib.h"
 #include "BiosCallOuts.h"
 #include "heapManager.h"
-#include <northbridge/amd/agesa/family14/dimmSpd.h>
 #include <stdlib.h>
 
 /* Should AGESA_GNB_PCIE_SLOT_RESET use agesa_NoopSuccess?
@@ -37,7 +36,7 @@ const BIOS_CALLOUT_STRUCT BiosCallouts[] =
 	{AGESA_DEALLOCATE_BUFFER,		agesa_DeallocateBuffer },
 	{AGESA_LOCATE_BUFFER,			agesa_LocateBuffer },
 	{AGESA_DO_RESET,			agesa_Reset },
-	{AGESA_READ_SPD,			BiosReadSpd },
+	{AGESA_READ_SPD,			agesa_ReadSpd },
 	{AGESA_READ_SPD_RECOVERY,		agesa_NoopUnsupported },
 	{AGESA_RUNFUNC_ONAP,			agesa_RunFuncOnAp },
 	{AGESA_GNB_PCIE_SLOT_RESET,		agesa_NoopUnsupported },
diff --git a/src/mainboard/lippert/toucan-af/BiosCallOuts.c b/src/mainboard/lippert/toucan-af/BiosCallOuts.c
index f1ae168..da9ab1a 100644
--- a/src/mainboard/lippert/toucan-af/BiosCallOuts.c
+++ b/src/mainboard/lippert/toucan-af/BiosCallOuts.c
@@ -21,7 +21,6 @@
 #include "amdlib.h"
 #include "BiosCallOuts.h"
 #include "heapManager.h"
-#include <northbridge/amd/agesa/family14/dimmSpd.h>
 #include <stdlib.h>
 
 /* Should AGESA_GNB_PCIE_SLOT_RESET use agesa_NoopSuccess?
@@ -38,7 +37,7 @@ const BIOS_CALLOUT_STRUCT BiosCallouts[] =
 	{AGESA_DEALLOCATE_BUFFER,		agesa_DeallocateBuffer },
 	{AGESA_LOCATE_BUFFER,			agesa_LocateBuffer },
 	{AGESA_DO_RESET,			agesa_Reset },
-	{AGESA_READ_SPD,			BiosReadSpd },
+	{AGESA_READ_SPD,			agesa_ReadSpd },
 	{AGESA_READ_SPD_RECOVERY,		agesa_NoopUnsupported },
 	{AGESA_RUNFUNC_ONAP,			agesa_RunFuncOnAp },
 	{AGESA_GNB_PCIE_SLOT_RESET,		agesa_NoopUnsupported },
diff --git a/src/mainboard/supermicro/h8qgi/BiosCallOuts.c b/src/mainboard/supermicro/h8qgi/BiosCallOuts.c
index 6e6eb6a..7b7d5e1 100644
--- a/src/mainboard/supermicro/h8qgi/BiosCallOuts.c
+++ b/src/mainboard/supermicro/h8qgi/BiosCallOuts.c
@@ -23,7 +23,6 @@
 #include "Ids.h"
 #include "OptionsIds.h"
 #include "heapManager.h"
-#include <northbridge/amd/agesa/family15/dimmSpd.h>
 #include <arch/io.h>
 
 #ifdef __PRE_RAM__
@@ -101,7 +100,7 @@ static AGESA_STATUS board_ReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
 
 	original_value = select_socket(((AGESA_READ_SPD_PARAMS *)ConfigPtr)->SocketId);
 
-	Status = agesa_ReadSPD (Func, Data, ConfigPtr);
+	Status = agesa_ReadSpd (Func, Data, ConfigPtr);
 
 	restore_socket(original_value);
 #else
diff --git a/src/mainboard/supermicro/h8scm/BiosCallOuts.c b/src/mainboard/supermicro/h8scm/BiosCallOuts.c
index 5d0fd00..c891dbd 100644
--- a/src/mainboard/supermicro/h8scm/BiosCallOuts.c
+++ b/src/mainboard/supermicro/h8scm/BiosCallOuts.c
@@ -23,18 +23,15 @@
 #include "Ids.h"
 #include "OptionsIds.h"
 #include "heapManager.h"
-#include <northbridge/amd/agesa/family15/dimmSpd.h>
 #include <stdlib.h>
 
-static AGESA_STATUS board_ReadSpd (UINT32 Func,UINT32 Data, VOID *ConfigPtr);
-
 const BIOS_CALLOUT_STRUCT BiosCallouts[] =
 {
 	{AGESA_ALLOCATE_BUFFER,			agesa_AllocateBuffer },
 	{AGESA_DEALLOCATE_BUFFER,		agesa_DeallocateBuffer },
 	{AGESA_LOCATE_BUFFER,			agesa_LocateBuffer },
 	{AGESA_DO_RESET,			agesa_Reset },
-	{AGESA_READ_SPD,			board_ReadSpd },
+	{AGESA_READ_SPD,			agesa_ReadSpd },
 	{AGESA_READ_SPD_RECOVERY,		agesa_NoopUnsupported },
 	{AGESA_RUNFUNC_ONAP,			agesa_RunFuncOnAp },
 	{AGESA_GET_IDS_INIT_DATA,		agesa_EmptyIdsInitData },
@@ -43,17 +40,3 @@ const BIOS_CALLOUT_STRUCT BiosCallouts[] =
 	{AGESA_HOOKBEFORE_EXIT_SELF_REF,	agesa_NoopSuccess },
 };
 const int BiosCalloutsLen = ARRAY_SIZE(BiosCallouts);
-
-
-
-static AGESA_STATUS board_ReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
-{
-	AGESA_STATUS Status;
-#ifdef __PRE_RAM__
-	Status = agesa_ReadSPD (Func, Data, ConfigPtr);
-#else
-	Status = AGESA_UNSUPPORTED;
-#endif
-
-	return Status;
-}
diff --git a/src/mainboard/tyan/s8226/BiosCallOuts.c b/src/mainboard/tyan/s8226/BiosCallOuts.c
index ee64122..becb4d0 100644
--- a/src/mainboard/tyan/s8226/BiosCallOuts.c
+++ b/src/mainboard/tyan/s8226/BiosCallOuts.c
@@ -23,7 +23,6 @@
 #include "Ids.h"
 #include "OptionsIds.h"
 #include "heapManager.h"
-#include <northbridge/amd/agesa/family15/dimmSpd.h>
 #include <arch/io.h>
 #include <stdlib.h>
 
@@ -109,7 +108,7 @@ static AGESA_STATUS board_ReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
 
 	original_value = select_socket(((AGESA_READ_SPD_PARAMS *)ConfigPtr)->SocketId);
 
-	Status = agesa_ReadSPD (Func, Data, ConfigPtr);
+	Status = agesa_ReadSpd (Func, Data, ConfigPtr);
 
 	restore_socket(original_value);
 #else
diff --git a/src/northbridge/amd/agesa/def_callouts.c b/src/northbridge/amd/agesa/def_callouts.c
index 9975924..fd8e373 100644
--- a/src/northbridge/amd/agesa/def_callouts.c
+++ b/src/northbridge/amd/agesa/def_callouts.c
@@ -115,6 +115,7 @@ AGESA_STATUS agesa_GfxGetVbiosImage(UINT32 Func, UINT32 FchData, VOID *ConfigPrt
 	/* printk(BIOS_DEBUG, "IMGptr=%x\n", pVbiosImageInfo->ImagePtr); */
 	return pVbiosImageInfo->ImagePtr == NULL ? AGESA_WARNING : AGESA_SUCCESS;
 }
+#endif
 
 AGESA_STATUS agesa_ReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
 {
@@ -124,7 +125,6 @@ AGESA_STATUS agesa_ReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
 #endif
 	return Status;
 }
-#endif
 
 AGESA_STATUS agesa_ReadSpd_from_cbfs(UINT32 Func, UINT32 Data, VOID *ConfigPtr)
 {
diff --git a/src/northbridge/amd/agesa/family12/Makefile.inc b/src/northbridge/amd/agesa/family12/Makefile.inc
index ffadecd..af67f69 100644
--- a/src/northbridge/amd/agesa/family12/Makefile.inc
+++ b/src/northbridge/amd/agesa/family12/Makefile.inc
@@ -22,6 +22,5 @@ romstage-y += dimmSpd.c
 
 ramstage-y += northbridge.c
 ramstage-y += fam12_callouts.c
-ramstage-y += dimmSpd.c
 
 ramstage-$(CONFIG_HAVE_ACPI_TABLES) += ssdt.asl
diff --git a/src/northbridge/amd/agesa/family12/dimmSpd.c b/src/northbridge/amd/agesa/family12/dimmSpd.c
index 55fb2c3..3ac4d7d 100644
--- a/src/northbridge/amd/agesa/family12/dimmSpd.c
+++ b/src/northbridge/amd/agesa/family12/dimmSpd.c
@@ -27,27 +27,13 @@
  *
  ***************************************************************************/
 
-/*----------------------------------------------------------------------------------------
- *                             M O D U L E S    U S E D
- *----------------------------------------------------------------------------------------
- */
-
 #include "Porting.h"
 #include "AGESA.h"
 #include "amdlib.h"
-#include "dimmSpd.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]))
+#include <northbridge/amd/agesa/dimmSpd.h>
 
-/*----------------------------------------------------------------------------------------
- *                  T Y P E D E F S     A N D     S T R U C T U  R E S
- *----------------------------------------------------------------------------------------
- */
+#define DIMENSION(array)(sizeof (array)/ sizeof (array [0]))
 
 typedef struct _DIMM_INFO_SMBUS{
   UINT8   SocketId;
@@ -65,156 +51,6 @@ STATIC CONST DIMM_INFO_SMBUS SpdAddrLookup [] =
   {0, 1, 0, 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
- *----------------------------------------------------------------------------------------
- */
-
-/*----------------------------------------------------------------------------------------
- *                          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
-  )
-{
-   WritePmReg (0x2D, IoBase >> 8);
-   WritePmReg (0x2C, IoBase | 1);
-   WritePmReg (0x29, 0x80);
-   WritePmReg (0x28, 0x61);
-   /* 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 *Buffer,
-  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;
-   }
-
-   Buffer [0] = __inbyte (Iobase + 5);
-   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 + 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,
@@ -234,8 +70,11 @@ AmdMemoryReadSPD (
       }
    }
 
+	if (SmBusAddress == 0)
+		return AGESA_ERROR;
 
-   if (SmBusAddress == 0) return AGESA_ERROR;
-   SetupFch (SMBUS_BASE_ADDR);
-   return ReadSpd (SMBUS_BASE_ADDR, SmBusAddress, SpdData->Buffer, 128);
+	int err = smbus_readSpd(SmBusAddress, (char *) SpdData->Buffer, 128);
+	if (err)
+		return AGESA_ERROR;
+	return AGESA_SUCCESS;
 }
diff --git a/src/northbridge/amd/agesa/family12/dimmSpd.h b/src/northbridge/amd/agesa/family12/dimmSpd.h
deleted file mode 100644
index 81ab02e..0000000
--- a/src/northbridge/amd/agesa/family12/dimmSpd.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2011 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
- *----------------------------------------------------------------------------------------
- */
-
-#ifndef _DIMMSPD_H_
-#define _DIMMSPD_H_
-
-#include "Porting.h"
-#include "AGESA.h"
-
-/*----------------------------------------------------------------------------------------
- *                   D E F I N I T I O N S    A N D    M A C R O S
- *----------------------------------------------------------------------------------------
- */
-
-/*----------------------------------------------------------------------------------------
- *                  T Y P E D E F S     A N D     S T R U C T U  R E S
- *----------------------------------------------------------------------------------------
- */
-
-/*----------------------------------------------------------------------------------------
- *           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
- *----------------------------------------------------------------------------------------
- */
-
-/*----------------------------------------------------------------------------------------
- *                          E X P O R T E D    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
-  );
-
-/*---------------------------------------------------------------------------------------
- *                          L O C A L    F U N C T I O N S
- *---------------------------------------------------------------------------------------
- */
-
-#endif
diff --git a/src/northbridge/amd/agesa/family12/fam12_callouts.c b/src/northbridge/amd/agesa/family12/fam12_callouts.c
index 203c883..aa707a8 100644
--- a/src/northbridge/amd/agesa/family12/fam12_callouts.c
+++ b/src/northbridge/amd/agesa/family12/fam12_callouts.c
@@ -19,18 +19,9 @@
 
 #include "agesawrapper.h"
 #include "amdlib.h"
-#include "dimmSpd.h"
 #include "BiosCallOuts.h"
 #include "Ids.h"
 #include "OptionsIds.h"
 #include "heapManager.h"
 #include "Hudson-2.h"
 
-
-AGESA_STATUS BiosReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
-{
-	AGESA_STATUS Status;
-	Status = AmdMemoryReadSPD (Func, Data, (AGESA_READ_SPD_PARAMS *)ConfigPtr);
-
-	return Status;
-}
diff --git a/src/northbridge/amd/agesa/family12/fam12_callouts.h b/src/northbridge/amd/agesa/family12/fam12_callouts.h
index 6fb9fbb..46f4fe5 100644
--- a/src/northbridge/amd/agesa/family12/fam12_callouts.h
+++ b/src/northbridge/amd/agesa/family12/fam12_callouts.h
@@ -24,7 +24,5 @@
 #include "AGESA.h"
 
 
-/* AGESA ADVANCED CALLOUTS - MEMORY */
-AGESA_STATUS BiosReadSpd (UINT32 Func,UINT32	Data,VOID *ConfigPtr);
 
 #endif /* CALLOUTS_AMD_AGESA_FAM12_H */
diff --git a/src/northbridge/amd/agesa/family14/dimmSpd.c b/src/northbridge/amd/agesa/family14/dimmSpd.c
index a3f5bb3..4a0cd2a 100644
--- a/src/northbridge/amd/agesa/family14/dimmSpd.c
+++ b/src/northbridge/amd/agesa/family14/dimmSpd.c
@@ -26,102 +26,20 @@
 #include "Porting.h"
 #include "AGESA.h"
 #include "amdlib.h"
-#include "dimmSpd.h"
 #include "chip.h"
 
+#include <northbridge/amd/agesa/dimmSpd.h>
+
 /* uncomment for source level debug - GDB gets really confused otherwise. */
 //#pragma optimize ("", off)
 
 /**
- *	Read a single SPD byte.  If the first byte is being read, set up the
- *	address and offset. Following bytes auto increment.
- */
-static UINT8 readSmbusByte(UINT16 iobase, UINT8 address, char *buffer,
-						   int offset, int initial_offset)
-{
-	unsigned int status = -1;
-	UINT64 time_limit;
-
-	/* clear status register */
-	__outbyte(iobase + SMBUS_STATUS_REG, 0x1E);
-
-	if (offset == initial_offset) {
-		/* Clear slave status, set offset, set slave address and start reading */
-		__outbyte(iobase + SMBUS_SLAVE_STATUS_REG, 0x3E);
-		__outbyte(iobase + SMBUS_CONTROL_REG, offset);
-		__outbyte(iobase + SMBUS_HOST_CMD_REG, address | READ_BIT);
-		__outbyte(iobase + SMBUS_COMMAND_REG, SMBUS_READ_BYTE_COMMAND);
-	} else {
-		/* Issue read command - auto increments to next byte */
-		__outbyte(iobase + SMBUS_COMMAND_REG, SMBUS_READ_COMMAND);
-	}
-	/* time limit to avoid hanging for unexpected error status */
-	time_limit = __rdtsc() + MAX_READ_TSC_COUNT;
-	while (__rdtsc() <= time_limit) {
-		status = __inbyte(iobase + SMBUS_STATUS_REG);
-		if ((status & SMBUS_INTERRUPT_MASK) == 0)
-			continue;	/* SMBusInterrupt not set, keep waiting */
-		if ((status & HOSTBUSY_MASK) != 0)
-			continue;	/* HostBusy set, keep waiting */
-		break;
-	}
-
-	if (status != STATUS__COMPLETED_SUCCESSFULLY)
-		return AGESA_ERROR;
-
-	buffer[0] = __inbyte(iobase + SMBUS_DATA0_REG);
-	return AGESA_SUCCESS;
-}
-
-static void writePmReg(UINT8 reg, UINT8 data)
-{
-	__outbyte(PMIO_INDEX_REG, reg);
-	__outbyte(PMIO_DATA_REG, data);
-}
-
-static void setupFch(UINT16 ioBase)
-{
-	/* set up SMBUS - Set to SMBUS 0 & set base address */
-	/* For SB800 & Hudson1 to SB900 & Hudson 2/3 */
-	writePmReg(SMBUS_BAR_HIGH_BYTE, ioBase >> 8);
-	writePmReg(SMBUS_BAR_LOW_BYTE, (ioBase & 0xe0) | 1);
-
-	/* set SMBus clock to 400 KHz */
-	__outbyte(ioBase + SMBUS_CLOCK_REG, SMBUS_FREQUENCY_CONST / 400000);
-}
-
-/**
- *	Read one or more SPD bytes from a DIMM.
- *	Start with offset zero and read sequentially.
- *	Reads 128 bytes in 7-8 ms at 400 KHz.
- */
-static UINT8 readspd(UINT16 iobase, UINT8 SmbusSlaveAddress, char *buffer,
-					 UINT16 count)
-{
-	UINT16 index;
-	UINT8 status;
-	UINT8 initial_offset = 0;
-
-	setupFch(iobase);
-
-	for (index = initial_offset; index < count; index++) {
-		status = readSmbusByte(iobase, SmbusSlaveAddress, &buffer[index], index,
-				initial_offset);
-		if (status != AGESA_SUCCESS)
-			return status;
-	}
-
-	return status;
-}
-
-/**
  * Gets the SMBUS address for an SPD from the array in devicetree.cb
  * then read the SPD into the supplied buffer.
  */
-AGESA_STATUS agesa_ReadSPD(UINT32 unused1, UINT32 unused2, void *infoptr)
+AGESA_STATUS AmdMemoryReadSPD (UINT32 unused1, UINT32 unused2, AGESA_READ_SPD_PARAMS *info)
 {
 	UINT8 spdAddress;
-	AGESA_READ_SPD_PARAMS *info = infoptr;
 	ROMSTAGE_CONST struct device *dev = dev_find_slot(0, PCI_DEVFN(0x18, 2));
 	ROMSTAGE_CONST struct northbridge_amd_agesa_family14_config *config = NULL;
 
@@ -141,5 +59,9 @@ AGESA_STATUS agesa_ReadSPD(UINT32 unused1, UINT32 unused2, void *infoptr)
 
 	if (spdAddress == 0)
 		return AGESA_ERROR;
-	return readspd(SMBUS0_BASE_ADDRESS, spdAddress, (void *)info->Buffer, 128);
+
+	int err = smbus_readSpd(spdAddress, (void *) info->Buffer, 128);
+	if (err)
+		return AGESA_ERROR;
+	return AGESA_SUCCESS;
 }
diff --git a/src/northbridge/amd/agesa/family14/dimmSpd.h b/src/northbridge/amd/agesa/family14/dimmSpd.h
deleted file mode 100644
index 57512c7..0000000
--- a/src/northbridge/amd/agesa/family14/dimmSpd.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2011 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, MA02110-1301 USA
- */
-
-/*----------------------------------------------------------------------------------------
- *                             M O D U L E S    U S E D
- *----------------------------------------------------------------------------------------
- */
-
-#ifndef _DIMMSPD_H_
-#define _DIMMSPD_H_
-
-/*----------------------------------------------------------------------------------------
- *                   D E F I N I T I O N S    A N D    M A C R O S
- *----------------------------------------------------------------------------------------
- */
-
-#define READ_BIT				0x01
-
-#define SMBUS_INTERRUPT_MASK	0x02
-#define HOSTBUSY_MASK			0x01
-
-#define SMBUS_READ_BYTE_COMMAND	0x48
-#define SMBUS_READ_COMMAND		0x44
-
-#define MAX_READ_TSC_COUNT		(2000000000 / 10)
-
-#define PMIO_INDEX_REG			0xCD6
-#define PMIO_DATA_REG			0xCD7
-
-#define SMBUS_BAR_LOW_BYTE		0x2C
-#define SMBUS_BAR_HIGH_BYTE		0x2D
-
-#define SMBUS_STATUS_REG		0x00
-#define SMBUS_SLAVE_STATUS_REG	0x01
-#define SMBUS_COMMAND_REG		0x02
-#define SMBUS_CONTROL_REG		0x03
-#define SMBUS_HOST_CMD_REG		0x04
-#define SMBUS_DATA0_REG			0x05
-#define SMBUS_CLOCK_REG			0x0E
-
-#define STATUS__COMPLETED_SUCCESSFULLY	0x02
-
-#define SMBUS_FREQUENCY_CONST	66000000 / 4
-/*----------------------------------------------------------------------------------------
- *                  T Y P E D E F S     A N D     S T R U C T U  R E S
- *----------------------------------------------------------------------------------------
- */
-
-/*----------------------------------------------------------------------------------------
- *           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
- *----------------------------------------------------------------------------------------
- */
-
-/*----------------------------------------------------------------------------------------
- *                          E X P O R T E D    F U N C T I O N S
- *----------------------------------------------------------------------------------------
- */
-
-AGESA_STATUS
-agesa_ReadSPD (IN UINT32 Func, IN UINT32 Data, IN OUT void *SpdData);
-
-/*---------------------------------------------------------------------------------------
- *                          L O C A L    F U N C T I O N S
- *---------------------------------------------------------------------------------------
- */
-
-#endif
diff --git a/src/northbridge/amd/agesa/family14/fam14_callouts.c b/src/northbridge/amd/agesa/family14/fam14_callouts.c
index 3be5037..a00c25a 100644
--- a/src/northbridge/amd/agesa/family14/fam14_callouts.c
+++ b/src/northbridge/amd/agesa/family14/fam14_callouts.c
@@ -22,18 +22,4 @@
 #include "fam14_callouts.h"
 #include "heapManager.h"
 #include "SB800.h"
-#include "dimmSpd.h"
 
-
-
-AGESA_STATUS BiosReadSpd (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
-{
-	AGESA_STATUS Status;
-#ifdef __PRE_RAM__
-	Status = agesa_ReadSPD (Func, Data, ConfigPtr);
-#else
-	Status = AGESA_UNSUPPORTED;
-#endif
-
-	return Status;
-}
diff --git a/src/northbridge/amd/agesa/family14/fam14_callouts.h b/src/northbridge/amd/agesa/family14/fam14_callouts.h
index f58441a..b9a36fe 100644
--- a/src/northbridge/amd/agesa/family14/fam14_callouts.h
+++ b/src/northbridge/amd/agesa/family14/fam14_callouts.h
@@ -24,7 +24,5 @@
 #include "Porting.h"
 #include "AGESA.h"
 
-/* AGESA ADVANCED CALLOUTS - MEMORY */
-AGESA_STATUS BiosReadSpd (UINT32 Func,UINT32	Data,VOID *ConfigPtr);
 
 #endif /* CALLOUTS_AMD_AGESA_FAM14_H */
diff --git a/src/northbridge/amd/agesa/family15/dimmSpd.c b/src/northbridge/amd/agesa/family15/dimmSpd.c
index 294454c..375a968 100644
--- a/src/northbridge/amd/agesa/family15/dimmSpd.c
+++ b/src/northbridge/amd/agesa/family15/dimmSpd.c
@@ -25,143 +25,20 @@
 #include "Porting.h"
 #include "AGESA.h"
 #include "amdlib.h"
-#include "dimmSpd.h"
 #include "chip.h"
 
+#include <northbridge/amd/agesa/dimmSpd.h>
+
 /* uncomment for source level debug - GDB gets really confused otherwise. */
 //#pragma optimize ("", off)
 
 /**
- * Read a single SPD byte.  If the first byte is being read, set up the
- * address and offset. Following bytes auto increment.
- */
-static UINT8 readSmbusByte(UINT16 iobase, UINT8 address, char *buffer,
-						   int offset, int initial_offset)
-{
-	unsigned int status = -1;
-	UINT64 time_limit;
-
-	/* clear status register */
-	__outbyte(iobase + SMBUS_STATUS_REG, 0xFF);
-	__outbyte(iobase + SMBUS_SLAVE_STATUS_REG, 0x1F);
-
-	if (offset == initial_offset) {
-		/* Set offset, set slave address and start reading */
-		__outbyte(iobase + SMBUS_CONTROL_REG, offset);
-		__outbyte(iobase + SMBUS_HOST_CMD_REG, address | READ_BIT);
-		__outbyte(iobase + SMBUS_COMMAND_REG, SMBUS_READ_BYTE_COMMAND);
-	} else {
-		/* Issue read command - auto increments to next byte */
-		__outbyte(iobase + SMBUS_COMMAND_REG, SMBUS_READ_COMMAND);
-	}
-	/* time limit to avoid hanging for unexpected error status */
-	time_limit = __rdtsc() + MAX_READ_TSC_COUNT;
-	while (__rdtsc() <= time_limit) {
-		status = __inbyte(iobase + SMBUS_STATUS_REG);
-		if ((status & SMBUS_INTERRUPT_MASK) == 0)
-			continue;	/* SMBusInterrupt not set, keep waiting */
-		if ((status & HOSTBUSY_MASK) != 0)
-			continue;	/* HostBusy set, keep waiting */
-		break;
-	}
-
-	if (status != STATUS__COMPLETED_SUCCESSFULLY)
-		return AGESA_ERROR;
-
-	buffer[0] = __inbyte(iobase + SMBUS_DATA0_REG);
-	return AGESA_SUCCESS;
-}
-
-/**
- * Write a single smbus byte.
- */
-UINT8 writeSmbusByte(UINT16 iobase, UINT8 address, UINT8 buffer,
-					 int offset)
-{
-	unsigned int status = -1;
-	UINT64 time_limit;
-
-	/* clear status register */
-	__outbyte(iobase + SMBUS_STATUS_REG, 0xFF);
-	__outbyte(iobase + SMBUS_SLAVE_STATUS_REG, 0x1F);
-
-	/* set offset, set slave address, set data and start writing */
-	__outbyte(iobase + SMBUS_CONTROL_REG, offset);
-	__outbyte(iobase + SMBUS_HOST_CMD_REG, address & (~READ_BIT));
-	__outbyte(iobase + SMBUS_DATA0_REG, buffer);
-	__outbyte(iobase + SMBUS_COMMAND_REG, SMBUS_WRITE_BYTE_COMMAND);
-
-	/* time limit to avoid hanging for unexpected error status */
-	time_limit = __rdtsc() + MAX_READ_TSC_COUNT;
-	while (__rdtsc() <= time_limit) {
-		status = __inbyte(iobase + SMBUS_STATUS_REG);
-		if ((status & SMBUS_INTERRUPT_MASK) == 0)
-			continue;	/* SMBusInterrupt not set, keep waiting */
-		if ((status & HOSTBUSY_MASK) != 0)
-			continue;	/* HostBusy set, keep waiting */
-		break;
-	}
-
-	if (status != STATUS__COMPLETED_SUCCESSFULLY)
-		return AGESA_ERROR;
-
-	return AGESA_SUCCESS;
-}
-
-static void setupFch(UINT16 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 = (ioBase & 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 + SMBUS_CLOCK_REG, SMBUS_FREQUENCY_CONST / 400000);
-}
-
-/**
- * Read one or more SPD bytes from a DIMM.
- * Start with offset zero and read sequentially.
- * Reads 128 bytes in 7-8 ms at 400 KHz.
- */
-static UINT8 readspd(UINT16 iobase, UINT8 SmbusSlaveAddress, char *buffer,
-					 UINT16 count)
-{
-	UINT16 index;
-	UINT8 status;
-	UINT8 initial_offset = 0;
-
-	setupFch(iobase);
-
-	for (index = initial_offset; index < count; index++) {
-		status = readSmbusByte(iobase, SmbusSlaveAddress, &buffer[index], index,
-				initial_offset);
-		if (status != AGESA_SUCCESS)
-			return status;
-	}
-
-	return status;
-}
-
-/**
  * Gets the SMBus address for an SPD from the array in devicetree.cb
  * then read the SPD into the supplied buffer.
  */
-AGESA_STATUS agesa_ReadSPD(UINT32 unused1, UINT32 unused2, void *infoptr)
+AGESA_STATUS AmdMemoryReadSPD (UINT32 unused1, UINT32 unused2, AGESA_READ_SPD_PARAMS *info)
 {
 	UINT8 spdAddress;
-	AGESA_READ_SPD_PARAMS *info = infoptr;
 	ROMSTAGE_CONST struct device *dev = dev_find_slot(0, PCI_DEVFN(0x18, 2));
 	ROMSTAGE_CONST struct northbridge_amd_agesa_family15_config *config = NULL;
 
@@ -182,5 +59,8 @@ AGESA_STATUS agesa_ReadSPD(UINT32 unused1, UINT32 unused2, void *infoptr)
 	if (spdAddress == 0)
 		return AGESA_ERROR;
 
-	return readspd(SMBUS0_BASE_ADDRESS, spdAddress, (void *)info->Buffer, 256);
+	int err = smbus_readSpd(spdAddress, (void *) info->Buffer, 256);
+	if (err)
+		return AGESA_ERROR;
+	return AGESA_SUCCESS;
 }
diff --git a/src/northbridge/amd/agesa/family15/dimmSpd.h b/src/northbridge/amd/agesa/family15/dimmSpd.h
deleted file mode 100644
index 167b4a1..0000000
--- a/src/northbridge/amd/agesa/family15/dimmSpd.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2011 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, MA02110-1301 USA
- */
-
-/*----------------------------------------------------------------------------------------
- *                             M O D U L E S    U S E D
- *----------------------------------------------------------------------------------------
- */
-
-#ifndef _DIMMSPD_H_
-#define _DIMMSPD_H_
-
-/*----------------------------------------------------------------------------------------
- *                   D E F I N I T I O N S    A N D    M A C R O S
- *----------------------------------------------------------------------------------------
- */
-
-#define READ_BIT				0x01
-
-#define SMBUS_INTERRUPT_MASK	0x02
-#define HOSTBUSY_MASK			0x01
-
-#define SMBUS_READ_BYTE_COMMAND	0x48
-#define SMBUS_READ_COMMAND		0x44
-
-#define SMBUS_WRITE_BYTE_COMMAND	0x48
-
-#define MAX_READ_TSC_COUNT		(2000000000 / 10)
-
-#define PMIO_INDEX_REG			0xCD6
-#define PMIO_DATA_REG			0xCD7
-
-#define SMBUS_BAR_LOW_BYTE		0x2C
-#define SMBUS_BAR_HIGH_BYTE		0x2D
-
-#define SMBUS_STATUS_REG		0x00
-#define SMBUS_SLAVE_STATUS_REG	0x01
-#define SMBUS_COMMAND_REG		0x02
-#define SMBUS_CONTROL_REG		0x03
-#define SMBUS_HOST_CMD_REG		0x04
-#define SMBUS_DATA0_REG			0x05
-#define SMBUS_CLOCK_REG			0x0E
-
-#define STATUS__COMPLETED_SUCCESSFULLY	0x02
-
-#define SMBUS_FREQUENCY_CONST	66000000 / 4
-/*----------------------------------------------------------------------------------------
- *                  T Y P E D E F S     A N D     S T R U C T U  R E S
- *----------------------------------------------------------------------------------------
- */
-
-/*----------------------------------------------------------------------------------------
- *           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
- *----------------------------------------------------------------------------------------
- */
-
-/*----------------------------------------------------------------------------------------
- *                          E X P O R T E D    F U N C T I O N S
- *----------------------------------------------------------------------------------------
- */
-
-AGESA_STATUS
-agesa_ReadSPD (IN UINT32 Func, IN UINT32 Data, IN OUT void *SpdData);
-
-/*
- * This function prototype is only used by the AMD Dinar mainboard.  The SMBus
- * write is used to select which socket's SPD will be read by the subsequent
- * SPD read call.  This function is being placed in the F15 wrapper code with
- * the other SPD read functions because the next step of the SPD read clean-up
- * will be to move the SMBus read/write functions into the southbridge to make
- * them more generic.  Having the writeSmbusByte() function in the same file as
- * the readSmbusByte() function will ensure that the writeSmbusByte() function
- * is not overlooked.
- */
-UINT8 writeSmbusByte(UINT16 iobase, UINT8 address, UINT8 buffer, int offset);
-
-/*---------------------------------------------------------------------------------------
- *                          L O C A L    F U N C T I O N S
- *---------------------------------------------------------------------------------------
- */
-
-#endif
diff --git a/src/northbridge/amd/agesa/family15/fam15_callouts.c b/src/northbridge/amd/agesa/family15/fam15_callouts.c
index 3b65492..a049a0e 100644
--- a/src/northbridge/amd/agesa/family15/fam15_callouts.c
+++ b/src/northbridge/amd/agesa/family15/fam15_callouts.c
@@ -23,5 +23,4 @@
 #include "Ids.h"
 #include "OptionsIds.h"
 #include "heapManager.h"
-#include <northbridge/amd/agesa/family15/dimmSpd.h>
 #include <arch/io.h>
diff --git a/src/southbridge/amd/cimx/sb700/Makefile.inc b/src/southbridge/amd/cimx/sb700/Makefile.inc
index ff96ca6..7e878e3 100644
--- a/src/southbridge/amd/cimx/sb700/Makefile.inc
+++ b/src/southbridge/amd/cimx/sb700/Makefile.inc
@@ -21,7 +21,7 @@
 # SB700 Platform Files
 
 romstage-y += early.c
-romstage-y += smbus.c
+romstage-y += smbus.c smbus_spd.c
 romstage-y += reset.c
 
 ramstage-y += late.c
diff --git a/src/southbridge/amd/cimx/sb700/smbus_spd.c b/src/southbridge/amd/cimx/sb700/smbus_spd.c
new file mode 100644
index 0000000..5e3e689
--- /dev/null
+++ b/src/southbridge/amd/cimx/sb700/smbus_spd.c
@@ -0,0 +1,164 @@
+/*
+ * 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
+ */
+#include <device/pci_def.h>
+#include <device/device.h>
+#include <stdlib.h>
+#include "OEM.h"		/* SMBUS0_BASE_ADDRESS */
+
+/* warning: Porting.h includes an open #pragma pack(1) */
+#include "Porting.h"
+#include "AGESA.h"
+#include "amdlib.h"
+#include "chip.h"
+#include "smbus_spd.h"
+
+#include <northbridge/amd/agesa/dimmSpd.h>
+
+/* uncomment for source level debug - GDB gets really confused otherwise. */
+//#pragma optimize ("", off)
+
+/**
+ * Read a single SPD byte.  If the first byte is being read, set up the
+ * address and offset. Following bytes auto increment.
+ */
+static UINT8 readSmbusByte(UINT16 iobase, UINT8 address, char *buffer,
+						   int offset, int initial_offset)
+{
+	unsigned int status = -1;
+	UINT64 time_limit;
+
+	/* clear status register */
+	__outbyte(iobase + SMBUS_STATUS_REG, 0xFF);
+	__outbyte(iobase + SMBUS_SLAVE_STATUS_REG, 0x1F);
+
+	if (offset == initial_offset) {
+		/* Set offset, set slave address and start reading */
+		__outbyte(iobase + SMBUS_CONTROL_REG, offset);
+		__outbyte(iobase + SMBUS_HOST_CMD_REG, address | READ_BIT);
+		__outbyte(iobase + SMBUS_COMMAND_REG, SMBUS_READ_BYTE_COMMAND);
+	} else {
+		/* Issue read command - auto increments to next byte */
+		__outbyte(iobase + SMBUS_COMMAND_REG, SMBUS_READ_COMMAND);
+	}
+	/* time limit to avoid hanging for unexpected error status */
+	time_limit = __rdtsc() + MAX_READ_TSC_COUNT;
+	while (__rdtsc() <= time_limit) {
+		status = __inbyte(iobase + SMBUS_STATUS_REG);
+		if ((status & SMBUS_INTERRUPT_MASK) == 0)
+			continue;	/* SMBusInterrupt not set, keep waiting */
+		if ((status & HOSTBUSY_MASK) != 0)
+			continue;	/* HostBusy set, keep waiting */
+		break;
+	}
+
+	if (status != STATUS__COMPLETED_SUCCESSFULLY)
+		return AGESA_ERROR;
+
+	buffer[0] = __inbyte(iobase + SMBUS_DATA0_REG);
+	return AGESA_SUCCESS;
+}
+
+/**
+ * Write a single smbus byte.
+ */
+UINT8 writeSmbusByte(UINT16 iobase, UINT8 address, UINT8 buffer,
+					 int offset)
+{
+	unsigned int status = -1;
+	UINT64 time_limit;
+
+	/* clear status register */
+	__outbyte(iobase + SMBUS_STATUS_REG, 0xFF);
+	__outbyte(iobase + SMBUS_SLAVE_STATUS_REG, 0x1F);
+
+	/* set offset, set slave address, set data and start writing */
+	__outbyte(iobase + SMBUS_CONTROL_REG, offset);
+	__outbyte(iobase + SMBUS_HOST_CMD_REG, address & (~READ_BIT));
+	__outbyte(iobase + SMBUS_DATA0_REG, buffer);
+	__outbyte(iobase + SMBUS_COMMAND_REG, SMBUS_WRITE_BYTE_COMMAND);
+
+	/* time limit to avoid hanging for unexpected error status */
+	time_limit = __rdtsc() + MAX_READ_TSC_COUNT;
+	while (__rdtsc() <= time_limit) {
+		status = __inbyte(iobase + SMBUS_STATUS_REG);
+		if ((status & SMBUS_INTERRUPT_MASK) == 0)
+			continue;	/* SMBusInterrupt not set, keep waiting */
+		if ((status & HOSTBUSY_MASK) != 0)
+			continue;	/* HostBusy set, keep waiting */
+		break;
+	}
+
+	if (status != STATUS__COMPLETED_SUCCESSFULLY)
+		return AGESA_ERROR;
+
+	return AGESA_SUCCESS;
+}
+
+static void setupFch(UINT16 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 = (ioBase & 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 + SMBUS_CLOCK_REG, SMBUS_FREQUENCY_CONST / 400000);
+}
+
+/**
+ * Read one or more SPD bytes from a DIMM.
+ * Start with offset zero and read sequentially.
+ * Reads 128 bytes in 7-8 ms at 400 KHz.
+ */
+static UINT8 readspd(UINT16 iobase, UINT8 SmbusSlaveAddress, char *buffer,
+					 UINT16 count)
+{
+	UINT16 index;
+	UINT8 status;
+	UINT8 initial_offset = 0;
+
+	setupFch(iobase);
+
+	for (index = initial_offset; index < count; index++) {
+		status = readSmbusByte(iobase, SmbusSlaveAddress, &buffer[index], index,
+				initial_offset);
+		if (status != AGESA_SUCCESS)
+			return status;
+	}
+
+	return status;
+}
+
+int smbus_readSpd(int spdAddress, char *buf, size_t len)
+{
+	int ioBase = SMBUS0_BASE_ADDRESS;
+	setupFch (ioBase);
+	return readspd (ioBase, spdAddress, buf, len);
+}
diff --git a/src/southbridge/amd/cimx/sb700/smbus_spd.h b/src/southbridge/amd/cimx/sb700/smbus_spd.h
new file mode 100644
index 0000000..107c79f
--- /dev/null
+++ b/src/southbridge/amd/cimx/sb700/smbus_spd.h
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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, MA02110-1301 USA
+ */
+
+#ifndef _SMBUS_SPD_H_
+#define _SMBUS_SPD_H_
+
+#define READ_BIT				0x01
+
+#define SMBUS_INTERRUPT_MASK	0x02
+#define HOSTBUSY_MASK			0x01
+
+#define SMBUS_READ_BYTE_COMMAND	0x48
+#define SMBUS_READ_COMMAND		0x44
+
+#define SMBUS_WRITE_BYTE_COMMAND	0x48
+
+#define MAX_READ_TSC_COUNT		(2000000000 / 10)
+
+#define PMIO_INDEX_REG			0xCD6
+#define PMIO_DATA_REG			0xCD7
+
+#define SMBUS_BAR_LOW_BYTE		0x2C
+#define SMBUS_BAR_HIGH_BYTE		0x2D
+
+#define SMBUS_STATUS_REG		0x00
+#define SMBUS_SLAVE_STATUS_REG	0x01
+#define SMBUS_COMMAND_REG		0x02
+#define SMBUS_CONTROL_REG		0x03
+#define SMBUS_HOST_CMD_REG		0x04
+#define SMBUS_DATA0_REG			0x05
+#define SMBUS_CLOCK_REG			0x0E
+
+#define STATUS__COMPLETED_SUCCESSFULLY	0x02
+
+#define SMBUS_FREQUENCY_CONST	66000000 / 4
+
+/*
+ * This function prototype is only used by the AMD Dinar mainboard.  The SMBus
+ * write is used to select which socket's SPD will be read by the subsequent
+ * SPD read call.  This function is being placed in the F15 wrapper code with
+ * the other SPD read functions because the next step of the SPD read clean-up
+ * will be to move the SMBus read/write functions into the southbridge to make
+ * them more generic.  Having the writeSmbusByte() function in the same file as
+ * the readSmbusByte() function will ensure that the writeSmbusByte() function
+ * is not overlooked.
+ */
+UINT8 writeSmbusByte(UINT16 iobase, UINT8 address, UINT8 buffer, int offset);
+
+#endif
diff --git a/src/southbridge/amd/cimx/sb800/Makefile.inc b/src/southbridge/amd/cimx/sb800/Makefile.inc
index 1c65eee..95daf70 100644
--- a/src/southbridge/amd/cimx/sb800/Makefile.inc
+++ b/src/southbridge/amd/cimx/sb800/Makefile.inc
@@ -22,7 +22,7 @@
 
 romstage-y += cfg.c
 romstage-y += early.c
-romstage-y += smbus.c
+romstage-y += smbus.c smbus_spd.c
 romstage-y += reset.c
 
 ramstage-y += cfg.c
diff --git a/src/southbridge/amd/cimx/sb800/smbus_spd.c b/src/southbridge/amd/cimx/sb800/smbus_spd.c
new file mode 100644
index 0000000..e3f5acc
--- /dev/null
+++ b/src/southbridge/amd/cimx/sb800/smbus_spd.c
@@ -0,0 +1,123 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <device/pci_def.h>
+#include <device/device.h>
+#include <stdlib.h>
+#include "OEM.h"		/* SMBUS0_BASE_ADDRESS */
+
+/* warning: Porting.h includes an open #pragma pack(1) */
+#include "Porting.h"
+#include "AGESA.h"
+#include "chip.h"
+#include "smbus_spd.h"
+
+#include <northbridge/amd/agesa/dimmSpd.h>
+
+/* uncomment for source level debug - GDB gets really confused otherwise. */
+//#pragma optimize ("", off)
+
+/**
+ *	Read a single SPD byte.  If the first byte is being read, set up the
+ *	address and offset. Following bytes auto increment.
+ */
+static UINT8 readSmbusByte(UINT16 iobase, UINT8 address, char *buffer,
+						   int offset, int initial_offset)
+{
+	unsigned int status = -1;
+	UINT64 time_limit;
+
+	/* clear status register */
+	__outbyte(iobase + SMBUS_STATUS_REG, 0x1E);
+
+	if (offset == initial_offset) {
+		/* Clear slave status, set offset, set slave address and start reading */
+		__outbyte(iobase + SMBUS_SLAVE_STATUS_REG, 0x3E);
+		__outbyte(iobase + SMBUS_CONTROL_REG, offset);
+		__outbyte(iobase + SMBUS_HOST_CMD_REG, address | READ_BIT);
+		__outbyte(iobase + SMBUS_COMMAND_REG, SMBUS_READ_BYTE_COMMAND);
+	} else {
+		/* Issue read command - auto increments to next byte */
+		__outbyte(iobase + SMBUS_COMMAND_REG, SMBUS_READ_COMMAND);
+	}
+	/* time limit to avoid hanging for unexpected error status */
+	time_limit = __rdtsc() + MAX_READ_TSC_COUNT;
+	while (__rdtsc() <= time_limit) {
+		status = __inbyte(iobase + SMBUS_STATUS_REG);
+		if ((status & SMBUS_INTERRUPT_MASK) == 0)
+			continue;	/* SMBusInterrupt not set, keep waiting */
+		if ((status & HOSTBUSY_MASK) != 0)
+			continue;	/* HostBusy set, keep waiting */
+		break;
+	}
+
+	if (status != STATUS__COMPLETED_SUCCESSFULLY)
+		return AGESA_ERROR;
+
+	buffer[0] = __inbyte(iobase + SMBUS_DATA0_REG);
+	return AGESA_SUCCESS;
+}
+
+static void writePmReg(UINT8 reg, UINT8 data)
+{
+	__outbyte(PMIO_INDEX_REG, reg);
+	__outbyte(PMIO_DATA_REG, data);
+}
+
+static void setupFch(UINT16 ioBase)
+{
+	/* set up SMBUS - Set to SMBUS 0 & set base address */
+	/* For SB800 & Hudson1 to SB900 & Hudson 2/3 */
+	writePmReg(SMBUS_BAR_HIGH_BYTE, ioBase >> 8);
+	writePmReg(SMBUS_BAR_LOW_BYTE, (ioBase & 0xe0) | 1);
+
+	/* set SMBus clock to 400 KHz */
+	__outbyte(ioBase + SMBUS_CLOCK_REG, SMBUS_FREQUENCY_CONST / 400000);
+}
+
+/**
+ *	Read one or more SPD bytes from a DIMM.
+ *	Start with offset zero and read sequentially.
+ *	Reads 128 bytes in 7-8 ms at 400 KHz.
+ */
+static UINT8 readspd(UINT16 iobase, UINT8 SmbusSlaveAddress, char *buffer,
+					 UINT16 count)
+{
+	UINT16 index;
+	UINT8 status;
+	UINT8 initial_offset = 0;
+
+	setupFch(iobase);
+
+	for (index = initial_offset; index < count; index++) {
+		status = readSmbusByte(iobase, SmbusSlaveAddress, &buffer[index], index,
+				initial_offset);
+		if (status != AGESA_SUCCESS)
+			return status;
+	}
+
+	return status;
+}
+
+int smbus_readSpd(int spdAddress, char *buf, size_t len)
+{
+	int ioBase = SMBUS0_BASE_ADDRESS;
+	setupFch (ioBase);
+	return readspd (ioBase, spdAddress, buf, len);
+}
diff --git a/src/southbridge/amd/cimx/sb800/smbus_spd.h b/src/southbridge/amd/cimx/sb800/smbus_spd.h
new file mode 100644
index 0000000..30bf83f
--- /dev/null
+++ b/src/southbridge/amd/cimx/sb800/smbus_spd.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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, MA02110-1301 USA
+ */
+
+#ifndef _SMBUS_SPD_H_
+#define _SMBUS_SPD_H_
+
+#define READ_BIT				0x01
+
+#define SMBUS_INTERRUPT_MASK	0x02
+#define HOSTBUSY_MASK			0x01
+
+#define SMBUS_READ_BYTE_COMMAND	0x48
+#define SMBUS_READ_COMMAND		0x44
+
+#define MAX_READ_TSC_COUNT		(2000000000 / 10)
+
+#define PMIO_INDEX_REG			0xCD6
+#define PMIO_DATA_REG			0xCD7
+
+#define SMBUS_BAR_LOW_BYTE		0x2C
+#define SMBUS_BAR_HIGH_BYTE		0x2D
+
+#define SMBUS_STATUS_REG		0x00
+#define SMBUS_SLAVE_STATUS_REG	0x01
+#define SMBUS_COMMAND_REG		0x02
+#define SMBUS_CONTROL_REG		0x03
+#define SMBUS_HOST_CMD_REG		0x04
+#define SMBUS_DATA0_REG			0x05
+#define SMBUS_CLOCK_REG			0x0E
+
+#define STATUS__COMPLETED_SUCCESSFULLY	0x02
+
+#define SMBUS_FREQUENCY_CONST	66000000 / 4
+
+#endif
diff --git a/src/southbridge/amd/cimx/sb900/Makefile.inc b/src/southbridge/amd/cimx/sb900/Makefile.inc
index 6cd392f..c332948 100644
--- a/src/southbridge/amd/cimx/sb900/Makefile.inc
+++ b/src/southbridge/amd/cimx/sb900/Makefile.inc
@@ -22,7 +22,7 @@
 
 romstage-y += cfg.c
 romstage-y += early.c
-romstage-y += smbus.c
+romstage-y += smbus.c smbus_spd.c
 romstage-y += reset.c
 
 ramstage-y += cfg.c
diff --git a/src/southbridge/amd/cimx/sb900/smbus_spd.c b/src/southbridge/amd/cimx/sb900/smbus_spd.c
new file mode 100644
index 0000000..3fd4439
--- /dev/null
+++ b/src/southbridge/amd/cimx/sb900/smbus_spd.c
@@ -0,0 +1,177 @@
+/*****************************************************************************
+ *
+ * Copyright (c) 2011, Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
+ *       its contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#include "Porting.h"
+#include "AGESA.h"
+#include "amdlib.h"
+
+#include <northbridge/amd/agesa/dimmSpd.h>
+
+#define SMBUS_BASE_ADDR  0xB00
+
+STATIC
+VOID
+WritePmReg (
+  IN UINT8 Reg,
+  IN UINT8 Data
+  )
+{
+   __outbyte (0xCD6, Reg);
+   __outbyte (0xCD7, Data);
+}
+STATIC
+VOID
+SetupFch (
+  IN UINT16
+  IN IoBase
+  )
+{
+   WritePmReg (0x2D, IoBase >> 8);
+   WritePmReg (0x2C, IoBase | 1);
+   WritePmReg (0x29, 0x80);
+   WritePmReg (0x28, 0x61);
+   /* 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 *Buffer,
+  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;
+   }
+
+   Buffer [0] = __inbyte (Iobase + 5);
+   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 + 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;
+}
+
+int smbus_readSpd(int spdAddress, char *buf, size_t len)
+{
+   SetupFch (SMBUS_BASE_ADDR);
+   return ReadSpd (SMBUS_BASE_ADDR, spdAddress, (UINT8 *) buf, len);
+}



More information about the coreboot-gerrit mailing list