Skip to content

Commit

Permalink
Assert ddr_resetn during EPOW on NVDIMMs
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
cjcain committed Oct 4, 2018
1 parent b67db9d commit 008cb0b
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 30 deletions.
36 changes: 20 additions & 16 deletions src/common/mca_addresses.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -63,29 +66,30 @@

// 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))

#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
/*
Expand Down
2 changes: 1 addition & 1 deletion src/occ_405/occbuildname.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
133 changes: 120 additions & 13 deletions src/occ_gpe1/gpe1_dimm_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
*
Expand Down Expand Up @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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);
Expand All @@ -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)
{
Expand All @@ -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,
Expand All @@ -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
Expand Down

0 comments on commit 008cb0b

Please sign in to comment.