From 008cb0bc5f1acc593d73d78c712bd531c3feef00 Mon Sep 17 00:00:00 2001 From: Chris Cain Date: Fri, 28 Sep 2018 15:23:22 -0500 Subject: 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 Reviewed-by: William A. Bryan Reviewed-by: Christopher J. Cain Tested-by: Christopher J. Cain --- src/common/mca_addresses.h | 36 ++++++----- src/occ_405/occbuildname.c | 2 +- src/occ_gpe1/gpe1_dimm_control.c | 133 +++++++++++++++++++++++++++++++++++---- 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"))) = /**/ "op_occ_180926a\0" /**/ ; +volatile const char G_occ_buildname[16] __attribute__((section(".buildname"))) = /**/ "op_occ_181001a\0" /**/ ; #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, ®Value); + 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 -- cgit v1.2.1