summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Cain <cjcain@us.ibm.com>2018-09-28 15:23:22 -0500
committerChristopher J. Cain <cjcain@us.ibm.com>2018-10-04 08:49:54 -0500
commit008cb0bc5f1acc593d73d78c712bd531c3feef00 (patch)
treea19f6ef8373b5c15028730b3f0ccd97e70ac9348
parentb67db9d09b181dfe8bd0a77cfdca511d124b291e (diff)
downloadtalos-occ-008cb0bc5f1acc593d73d78c712bd531c3feef00.tar.gz
talos-occ-008cb0bc5f1acc593d73d78c712bd531c3feef00.zip
Assert ddr_resetn during EPOW on NVDIMMs
Change-Id: I34d3c1a6f0c2f0a1fb95a1fb77af00c176b4e000 RTC: 173789 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/66827 Reviewed-by: Martha Broyles <mbroyles@us.ibm.com> Reviewed-by: William A. Bryan <wilbryan@us.ibm.com> Reviewed-by: Christopher J. Cain <cjcain@us.ibm.com> Tested-by: Christopher J. Cain <cjcain@us.ibm.com>
-rw-r--r--src/common/mca_addresses.h36
-rwxr-xr-xsrc/occ_405/occbuildname.c2
-rw-r--r--src/occ_gpe1/gpe1_dimm_control.c133
3 files changed, 141 insertions, 30 deletions
diff --git a/src/common/mca_addresses.h b/src/common/mca_addresses.h
index d6eced3..b3917cb 100644
--- a/src/common/mca_addresses.h
+++ b/src/common/mca_addresses.h
@@ -44,12 +44,15 @@
#define STR_REG0_OFFSET 0x0135
#define STR_REG0_ADDRESS (DIMM_MCA_BASE_ADDRESS + STR_REG0_OFFSET)
-#define PERF_MON_COUNTS0_OFFSET 0x0137
-#define PERF_MON_COUNTS0_ADDRESS (DIMM_MCA_BASE_ADDRESS + PERF_MON_COUNTS0_OFFSET)
+#define PERF_MON_COUNTS0_OFFSET 0x0137
+#define PERF_MON_COUNTS0_ADDRESS (DIMM_MCA_BASE_ADDRESS + PERF_MON_COUNTS0_OFFSET)
#define N_M_TCR_OFFSET 0x0116
#define N_M_TCR_ADDRESS (DIMM_MCA_BASE_ADDRESS + N_M_TCR_OFFSET)
+#define DDR_IF_SCOM_CTRL_OFFSET 0x0118
+#define DDR_IF_SCOM_CTRL_ADDRESS (DIMM_MCA_BASE_ADDRESS + DDR_IF_SCOM_CTRL_OFFSET)
+
#define PERF_MON_COUNTS_IDLE_OFFSET 0x013C
#define PERF_MON_COUNTS_IDLE_ADDRESS (DIMM_MCA_BASE_ADDRESS + PERF_MON_COUNTS_IDLE_OFFSET)
@@ -63,22 +66,22 @@
// Memory Power Control
-//Power Control Register 0 and STR Register 0 there are 4 each (1 per MCU port)
+//Power Control Register 0: MC#.PORT#.SRQ.PC.MBARPC0Q
+//STR Register 0: MC#.PORT#.SRQ.PC.MBASTR0Q
+//DDR Interface SCOM Control: MC#.PORT#.SRQ.MBA_FARB5Q
+//there are 4 each (1 per MCU port)
//OCC knows present MCU ports from the memory throttle config packet
-//Power control reg 0: MCP.PORT#.SRQ.PC.MBARPC0Q
-//STR reg 0: MCP.PORT#.SRQ.PC.MBASTR0Q
-
-/* PWR_CTRL/STR REG Power Ctl reg 0 STR reg 0
-MC/Port Address MCA Port Address Control Addr SCOM Address SCOM Address
-mc01.port0 0x07010800 + 0x00000134/5 = 0x07010934 = 0x07010935
-mc01.port1 0x07010840 + 0x00000134/5 = 0x07010974 = 0x07010975
-mc01.port2 0x07010880 + 0x00000134/5 = 0x070109B4 = 0x070109B5
-mc01.port3 0x070108C0 + 0x00000134/5 = 0x070109F4 = 0x070109F5
-mc23.port0 0x08010800 + 0x00000134/5 = 0x08010934 = 0x08010935
-mc23.port1 0x08010840 + 0x00000134/5 = 0x08010974 = 0x08010975
-mc23.port2 0x08010880 + 0x00000134/5 = 0x080109B4 = 0x080109B5
-mc23.port3 0x080108C0 + 0x00000134/5 = 0x080109F4 = 0x080109F5
+/* PC / STR / SCtl Power Ctl reg 0 STR reg 0 DDR IF SCOM CTRL
+MC/Port Address MCA Port Address Control Addr SCOM Address SCOM Address SCOM Address
+mc01.port0 0x07010800 + 0x134/135/118 = 0x07010934 = 0x07010935 = 0x07010918
+mc01.port1 0x07010840 + 0x134/135/118 = 0x07010974 = 0x07010975 = 0x07010958
+mc01.port2 0x07010880 + 0x134/135/118 = 0x070109B4 = 0x070109B5 = 0x07010998
+mc01.port3 0x070108C0 + 0x134/135/118 = 0x070109F4 = 0x070109F5 = 0x070109d8
+mc23.port0 0x08010800 + 0x134/135/118 = 0x08010934 = 0x08010935 = 0x08010918
+mc23.port1 0x08010840 + 0x134/135/118 = 0x08010974 = 0x08010975 = 0x08010958
+mc23.port2 0x08010880 + 0x134/135/118 = 0x080109B4 = 0x080109B5 = 0x08010998
+mc23.port3 0x080108C0 + 0x134/135/118 = 0x080109F4 = 0x080109F5 = 0x080109d8
*/
#define POWER_CTRL_REG0(mc,port) (POWER_CTRL_REG0_ADDRESS + MC_PORT_SPACE(mc,port))
@@ -86,6 +89,7 @@ mc23.port3 0x080108C0 + 0x00000134/5 = 0x080109F4 = 0x0801
#define STR_REG0(mc,port) (STR_REG0_ADDRESS + MC_PORT_SPACE(mc,port))
#define STR_REG0_MCA(mca) (STR_REG0_ADDRESS + MC_PORT_SPACE((mca>>2),(mca&3)))
+#define DDR_IF_SCOM_CTRL(mc,port) (DDR_IF_SCOM_CTRL_ADDRESS + MC_PORT_SPACE(mc,port))
// DIMM Control
/*
diff --git a/src/occ_405/occbuildname.c b/src/occ_405/occbuildname.c
index 757dfa5..ed2d432 100755
--- a/src/occ_405/occbuildname.c
+++ b/src/occ_405/occbuildname.c
@@ -34,6 +34,6 @@ volatile const char G_occ_buildname[16] __attribute__((section(".buildname"))) =
#else
-volatile const char G_occ_buildname[16] __attribute__((section(".buildname"))) = /*<BuildName>*/ "op_occ_180926a\0" /*</BuildName>*/ ;
+volatile const char G_occ_buildname[16] __attribute__((section(".buildname"))) = /*<BuildName>*/ "op_occ_181001a\0" /*</BuildName>*/ ;
#endif
diff --git a/src/occ_gpe1/gpe1_dimm_control.c b/src/occ_gpe1/gpe1_dimm_control.c
index 7a0a492..d36247f 100644
--- a/src/occ_gpe1/gpe1_dimm_control.c
+++ b/src/occ_gpe1/gpe1_dimm_control.c
@@ -34,6 +34,55 @@
#include "gpe1.h"
#include "gpe1_dimm.h"
+
+/*
+ * Function Specification:
+ *
+ * Name: gpe1_sleep
+ *
+ * Description: Delay for a specified period of time.
+ *
+ * Inputs: i_microseconds: time to sleep in microseconds
+ *
+ * Note: i_microseconds must be < (2^16)/nest_freq microseconds.
+ * (about 114 seconds for the fastest nest_freq supported)
+ *
+ * return: none
+ *
+ * End Function Specification
+ */
+void gpe1_sleep(uint32_t i_microseconds)
+{
+ uint32_t current_count = pk_timebase32_get();
+ uint32_t prev_count = current_count;
+ uint32_t timebase_zero_adjust = -current_count;
+ uint32_t change_timeout = 0;
+ uint32_t end_count = PK_INTERVAL_SCALE((uint32_t)PK_MICROSECONDS(i_microseconds));
+
+ while((current_count + timebase_zero_adjust) < end_count)
+ {
+ prev_count = current_count;
+
+ current_count = pk_timebase32_get();
+
+ if(prev_count == current_count)
+ {
+ ++change_timeout;
+ if(change_timeout > 32)
+ {
+ PK_TRACE("TIMEBASE is not moving!");
+ // timebase is not moving
+ break;
+ }
+ }
+ else
+ {
+ change_timeout = 0;
+ }
+ }
+}
+
+
/*
* Function Specifications:
*
@@ -73,12 +122,6 @@ void gpe_scom_nvdimms_nimbus(ipc_msg_t* cmd, void* arg)
PK_TRACE("gpe_scom_nvdimms_nimbus: scoms for mc: %d, port: %d", mc, port);
const uint32_t reg_MBARPC0Q = POWER_CTRL_REG0(mc,port);
- // Step 1 - In MBARPC0Q, disable power domain control, set domain
- // to MAXALL_MINALL(0b000), and enable minimum domain
- // reduction
- // bit 2 - power domain control,
- // bits 3:5 - min/max domains
- // bit 22 - domain reduction
rc = getscom_abs(reg_MBARPC0Q, &mbarpc_regValue);
if (rc)
{
@@ -87,8 +130,11 @@ void gpe_scom_nvdimms_nimbus(ipc_msg_t* cmd, void* arg)
}
else
{
- mbarpc_regValue &= 0xC3FFFFFFFFFFFFFF; // zero out bits 2-5
- mbarpc_regValue |= 0x0000020000000000; // set bit 22
+ // Step 1 - In MBARPC0Q, disable power domain control
+ // (must be done first, before domains are set)
+ //
+ // bit 2 - power domain control,
+ mbarpc_regValue &= 0xDFFFFFFFFFFFFFFF; // disable power control (clear bit 2)
rc = putscom_abs(reg_MBARPC0Q, mbarpc_regValue);
if (rc)
{
@@ -99,7 +145,25 @@ void gpe_scom_nvdimms_nimbus(ipc_msg_t* cmd, void* arg)
GPE_RC_SCOM_PUT_FAILED, rc);
}
- // Step 2 - In MBASTR0Q, enable STR entry
+ // Step 2 - In MBARPC0Q, set domain to MAXALL_MINALL(0b000),
+ // and enable minimum domain reduction
+ //
+ // bits 3:5 - min/max domains
+ // bit 22 - domain reduction
+ mbarpc_regValue &= 0xE3FFFFFFFFFFFFFF; // zero out bits 3-5
+ mbarpc_regValue |= 0x0000020000000000; // set bit 22
+ rc = putscom_abs(reg_MBARPC0Q, mbarpc_regValue);
+ if (rc)
+ {
+ PK_TRACE("E>gpe_scom_nvdimms_nimbus: Failed to set domains (MBARPC0Q)"
+ " Reg:0x%08X, Data:0x%08X %08X, rc:0x%08x",
+ reg_MBARPC0Q, WORD_HIGH(mbarpc_regValue), WORD_LOW(mbarpc_regValue), rc);
+ gpe_set_ffdc(&(args->error), reg_MBARPC0Q,
+ GPE_RC_SCOM_PUT_FAILED, rc);
+ }
+
+ // Step 3 - In MBASTR0Q, enable STR entry
+ //
// bit 0 - STR enable
const uint32_t reg_MBASTR0Q = STR_REG0(mc,port);
rc = getscom_abs(reg_MBASTR0Q, &mbastr_regValue);
@@ -110,7 +174,7 @@ void gpe_scom_nvdimms_nimbus(ipc_msg_t* cmd, void* arg)
}
else
{
- mbastr_regValue |= 0x8000000000000000; // set bit 0
+ mbastr_regValue |= 0x8000000000000000; // enable STR (set bit 0)
rc = putscom_abs(reg_MBASTR0Q, mbastr_regValue);
if (rc)
{
@@ -122,13 +186,14 @@ void gpe_scom_nvdimms_nimbus(ipc_msg_t* cmd, void* arg)
}
}
- // Step 3 - In MBARPC0Q, re-enable power domain control
+ // Step 4 - In MBARPC0Q, re-enable power domain control
+ //
// bit 2 - power domain control
- mbarpc_regValue |= 0x2000000000000000; // set bit 2
+ mbarpc_regValue |= 0x2000000000000000; // enable power control (set bit 2)
rc = putscom_abs(reg_MBARPC0Q, mbarpc_regValue);
if (rc)
{
- PK_TRACE(">gpe_scom_nvdimms_nimbus: Failed to re-enable power domain control (MBARPC0Q)"
+ PK_TRACE("E>gpe_scom_nvdimms_nimbus: Failed to re-enable power domain control (MBARPC0Q)"
" Reg:0x%08X, Data:0x%08X %08X, rc:0x%08x",
reg_MBARPC0Q, WORD_HIGH(mbarpc_regValue), WORD_LOW(mbarpc_regValue), rc);
gpe_set_ffdc(&(args->error), reg_MBARPC0Q,
@@ -140,6 +205,48 @@ void gpe_scom_nvdimms_nimbus(ipc_msg_t* cmd, void* arg)
} // for each MBA port
} // for each MC
+ // Delay 1us before triggering DIMM reset
+ PK_TRACE("gpe_scom_nvdimms_nimbus: Delay 1us");
+ gpe1_sleep(1);
+
+ // Trigger DIMM resets (will probably cause system checkstop)
+ PK_TRACE("gpe_scom_nvdimms_nimbus: Triggering DIMM resets");
+ mask = 0x8000;
+ for (mc = 0; mc < NUM_MBAS_NIMBUS; mc++)
+ {
+ for (port = 0; port < NUM_PORTS_PER_MBA; port++)
+ {
+ if (args->configured_mbas & mask)
+ {
+ // Step 5 - In FARB5Q (DDR Interface SCOM Control), assert ddr_resetn
+ //
+ // bit 4 - assert ddr_resetn
+ uint64_t regValue = 0;
+ const uint32_t reg_FARB5Q = DDR_IF_SCOM_CTRL(mc,port);
+ rc = getscom_abs(reg_FARB5Q, &regValue);
+ if (rc)
+ {
+ PK_TRACE("E>gpe_scom_nvdimms_nimbus: Failed to read (FARB5Q) Reg:0x%08X, rc:0x%08x",
+ reg_FARB5Q, rc);
+ }
+ else
+ {
+ regValue &= 0xF7FFFFFFFFFFFFFF; // assert ddr_resetn (clear bit 4)
+ rc = putscom_abs(reg_FARB5Q, regValue);
+ if (rc)
+ {
+ PK_TRACE("E>gpe_scom_nvdimms_nimbus: Failed to assert ddr_resetn (FARB5Q)"
+ " Reg:0x%08X, Data:0x%08X %08X, rc:0x%08x",
+ reg_FARB5Q, WORD_HIGH(regValue), WORD_LOW(regValue), rc);
+ gpe_set_ffdc(&(args->error), reg_FARB5Q,
+ GPE_RC_SCOM_PUT_FAILED, rc);
+ }
+ }
+ }
+ mask = mask >> 1;
+ } // for each MBA port
+ } // for each MC
+
PK_TRACE("gpe_scom_nvdimms_nimbus: completed (rc=%d)", rc);
// Always send back success
OpenPOWER on IntegriCloud