summaryrefslogtreecommitdiffstats
path: root/src/occ_gpe1
diff options
context:
space:
mode:
authorWael El-Essawy <welessa@us.ibm.com>2017-03-22 10:30:48 -0500
committerWael El-Essawy <welessa@us.ibm.com>2017-05-10 13:53:16 -0400
commitcf2258322bb72a2cd868f8eaef25e9a665077f4f (patch)
treef7a9b13ef36943246377ff623ed917fa4fd08ada /src/occ_gpe1
parentff3b5a1c08389bf766de21adcd033e3c7b86af87 (diff)
downloadtalos-occ-cf2258322bb72a2cd868f8eaef25e9a665077f4f.tar.gz
talos-occ-cf2258322bb72a2cd868f8eaef25e9a665077f4f.zip
Memory Power Control when entering and exiting IPS (Idle Power Save)
memory power control settings for IPS/default modes - as defined by memory config data packet version 0x21 - are applied to memory power control registers of all configured ports whenever the OCC enters/exits IPS, respectively. Change-Id: I56514bb8cbab80c6d4877edc74db96f3b011e523 RTC: 165546 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/38294 Reviewed-by: Martha Broyles <mbroyles@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Christopher J. Cain <cjcain@us.ibm.com> Reviewed-by: Wael El-Essawy <welessa@us.ibm.com>
Diffstat (limited to 'src/occ_gpe1')
-rw-r--r--src/occ_gpe1/gpe1_dimm_control.c6
-rw-r--r--src/occ_gpe1/gpe1_memory_power_control.c218
-rw-r--r--src/occ_gpe1/gpe1_memory_power_control.h47
-rw-r--r--src/occ_gpe1/ipc_func_tables.c25
-rw-r--r--src/occ_gpe1/topfiles.mk2
5 files changed, 281 insertions, 17 deletions
diff --git a/src/occ_gpe1/gpe1_dimm_control.c b/src/occ_gpe1/gpe1_dimm_control.c
index a87a464..5319913 100644
--- a/src/occ_gpe1/gpe1_dimm_control.c
+++ b/src/occ_gpe1/gpe1_dimm_control.c
@@ -30,6 +30,7 @@
#include "gpe_err.h"
#include "gpe_util.h"
#include "dimm_structs.h"
+#include "mca_addresses.h"
#include "gpe1.h"
/*
@@ -47,9 +48,6 @@
* End Function Specification
*/
-#define NUM_NIMBUS_MC_PAIRS 2
-#define MAX_NUM_MCU_PORTS 4
-
void gpe_dimm_control(ipc_msg_t* cmd, void* arg)
{
// Note: arg was set to 0 in ipc func table (ipc_func_tables.c), so don't use it.
@@ -96,7 +94,7 @@ void gpe_dimm_control(ipc_msg_t* cmd, void* arg)
N_M_DIMM_TCR(mc,port), regValue, rc);
gpe_set_ffdc(&(args->error), N_M_DIMM_TCR(mc,port),
- GPE_RC_SCOM_GET_FAILED, rc);
+ GPE_RC_SCOM_PUT_FAILED, rc);
break;
}
else
diff --git a/src/occ_gpe1/gpe1_memory_power_control.c b/src/occ_gpe1/gpe1_memory_power_control.c
new file mode 100644
index 0000000..a63ac75
--- /dev/null
+++ b/src/occ_gpe1/gpe1_memory_power_control.c
@@ -0,0 +1,218 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_gpe1/gpe1_memory_power_control.c $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#include "pk.h"
+#include "ppe42_scom.h"
+#include "ipc_api.h"
+#include "ipc_async_cmd.h"
+#include "gpe_err.h"
+#include "gpe_util.h"
+#include "mem_structs.h"
+#include "gpe1.h"
+#include "mca_addresses.h"
+#include "gpe1_memory_power_control.h"
+
+/*
+ * Function Specifications:
+ *
+ * Name: gpe_mem_power_control
+ *
+ * Description: memory power control code on the GPE
+ *
+ * Inputs: cmd is a pointer to IPC msg's cmd and cmd_data struct
+ *
+ * Outputs: error: sets rc, address, and ffdc in the cmd_data's
+ * GpeErrorStruct
+ *
+ * End Function Specification
+ */
+
+void gpe_mem_power_control(ipc_msg_t* cmd, void* arg)
+{
+ // Note: arg was set to 0 in ipc func table (ipc_func_tables.c), so don't use it.
+ // the ipc arguments passed through the ipc_msg_t structure, has a pointer
+ // to the mem_power_control_args_t struct.
+
+ int rc;
+ uint64_t pcrRegValue; // holds Power Control Register0
+ uint64_t strRegValue; // holds STR0 SCOM register value
+ ipc_async_cmd_t *async_cmd = (ipc_async_cmd_t*)cmd;
+ mem_power_control_args_t *args = (mem_power_control_args_t*)async_cmd->cmd_data;
+
+ uint8_t mc = args->mc, port = args->port; // memory controller pair and port
+
+ args->error.error = 0;
+ args->error.ffdc = 0;
+
+ do
+ { // For now, just loop through all ports amd MCs. May be time consuming, and
+ // if this is the case will change code to set only one port/mc register pair
+
+ // Read Power Control Register 0 SCOM
+ rc = getscom_abs(POWER_CTRL_REG0(mc,port), &pcrRegValue);
+
+ if(rc)
+ {
+ PK_TRACE("gpe_mem_power_control: Power Control Register 0 read fails"
+ "MC#|Port:0x%08x, Address:0x%08x, rc:0x%08x",
+ (uint32_t)((mc << 16) | port),
+ POWER_CTRL_REG0(mc,port), rc);
+
+ gpe_set_ffdc(&(args->error), POWER_CTRL_REG0(mc,port),
+ GPE_RC_SCOM_GET_FAILED, rc);
+ break;
+ }
+
+ // Read STR0 SCOM Register
+ rc = getscom_abs(STR_REG0(mc,port), &strRegValue);
+
+ if(rc)
+ {
+ PK_TRACE("gpe_mem_power_control: STR Register 0 read fails"
+ "MC#|Port:0x%08x, Address:0x%08x, rc:0x%08x",
+ (uint32_t)((mc << 16) | port),
+ STR_REG0(mc,port), rc);
+
+ gpe_set_ffdc(&(args->error), STR_REG0(mc,port),
+ GPE_RC_SCOM_GET_FAILED, rc);
+ break;
+ }
+
+ switch(args->mem_pwr_ctl)
+ {
+ // MEM_PWR_CTL_OFF: clears the following memory control bits:
+ // - master_enable (PCR0(2)),
+ // - power_down_enable (PCR0(22)),
+ // - STR_enable (STR(0)),
+ // - disable_memory_clocks (STR(1)).
+ case MEM_PWR_CTL_OFF:
+ pcrRegValue = CLR_2BITS(pcrRegValue, PCR0_MASTER_ENABLE_BIT, PCR0_POWERDOWN_ENABLE_BIT);
+ strRegValue = CLR_2BITS(strRegValue, STR0_STR_ENABLE_BIT, STR0_DISABLE_MEMORY_CLOCKS_BIT);
+ break;
+
+ // MEM_PWR_CTL_POWER_DOWN:
+ // sets:
+ // - master_enable (PCR0(2)),
+ // - power_down_enable (PCR0(22)),
+ // and clears:
+ // - STR_enable (STR(0)),
+ // - disable_memory_clocks (STR(1)).
+ case MEM_PWR_CTL_POWER_DOWN:
+ pcrRegValue = SET_2BITS(pcrRegValue, PCR0_MASTER_ENABLE_BIT, PCR0_POWERDOWN_ENABLE_BIT);
+
+ strRegValue = CLR_2BITS(strRegValue, STR0_STR_ENABLE_BIT, STR0_DISABLE_MEMORY_CLOCKS_BIT);
+ break;
+
+ // MEM_PWR_CTL_PD_AND_STR:
+ // sets:
+ // - master_enable (PCR0(2)),
+ // - power_down_enable (PCR0(22)),
+ // - STR_enable (STR(0)),
+ // and clears:
+ // - disable_memory_clocks (STR(1)).
+ case MEM_PWR_CTL_PD_AND_STR:
+ pcrRegValue = SET_2BITS(pcrRegValue, PCR0_MASTER_ENABLE_BIT, PCR0_POWERDOWN_ENABLE_BIT);
+ strRegValue = SET_BIT(strRegValue, STR0_STR_ENABLE_BIT);
+
+ strRegValue = CLR_BIT(strRegValue, STR0_DISABLE_MEMORY_CLOCKS_BIT);
+ break;
+
+ // MEM_PWR_CTL_PD_AND_STR_CLK_STOP: set the following memory power control bits
+ // - master_enable (PCR0(2)),
+ // - power_down_enable (PCR0(22)),
+ // - STR_enable (STR(0)),
+ // - disable_memory_clocks (STR(1)).
+ case MEM_PWR_CTL_PD_AND_STR_CLK_STOP:
+ pcrRegValue = SET_2BITS(pcrRegValue, PCR0_MASTER_ENABLE_BIT, PCR0_POWERDOWN_ENABLE_BIT);
+ strRegValue = SET_2BITS(strRegValue, STR0_STR_ENABLE_BIT, STR0_DISABLE_MEMORY_CLOCKS_BIT);
+ break;
+
+ default:
+ PK_TRACE("gpe_mem_power_control: Invalid memory power control command:0x%d",
+ args->mem_pwr_ctl);
+ rc = GPE_RC_INVALID_MEM_PWR_CTL;
+
+ gpe_set_ffdc(&(args->error), 0, rc, args->mem_pwr_ctl);
+ break;
+ }
+ if(rc)
+ {
+ break;
+ }
+
+ // Write Modified Power Control Register 0 SCOM
+ rc = putscom_abs(POWER_CTRL_REG0(mc,port), pcrRegValue);
+
+ if(rc)
+ {
+ PK_TRACE("gpe_mem_power_control: Power Control Register 0 write fails"
+ "MC#|Port:0x%08x, Address:0x%08x, rc:0x%08x",
+ (uint32_t)((mc << 16) | port),
+ POWER_CTRL_REG0(mc,port), rc);
+
+ gpe_set_ffdc(&(args->error), POWER_CTRL_REG0(mc,port),
+ GPE_RC_SCOM_PUT_FAILED, rc);
+ break;
+ }
+
+ // Write Modified STR0 SCOM Register
+ rc = putscom_abs(STR_REG0(mc,port), strRegValue);
+
+ if(rc)
+ {
+ PK_TRACE("gpe_mem_power_control: STR Register 0 write fails"
+ "MC#|Port:0x%08x, Address:0x%08x, rc:0x%08x",
+ (uint32_t)((mc << 16) | port),
+ STR_REG0(mc,port), rc);
+
+ gpe_set_ffdc(&(args->error), STR_REG0(mc,port),
+ GPE_RC_SCOM_PUT_FAILED, rc);
+ }
+ } while(0);
+
+
+ if(rc)
+ {
+ GPE1_DIMM_DBG("gpe_mem_power_control: Failed to apply memory power control");
+ }
+ else
+ {
+ GPE1_DIMM_DBG("gpe_mem_power_control: Memory Power Control Register successfully written"
+ "mc|port#:0x%04x, PCR0:0x%08x, STR0:0x%08x",
+ (uint16_t)((mc << 8) | port),
+ pcrRegValue, strRegValue);
+ }
+
+
+ // send back a response, IPC success even if ffdc/rc are non zeros
+ rc = ipc_send_rsp(cmd, IPC_RC_SUCCESS);
+ if(rc)
+ {
+ PK_TRACE("gpe_mem_power_control: Failed to send response back. Halting GPE1", rc);
+ gpe_set_ffdc(&(args->error), 0x00, GPE_RC_IPC_SEND_FAILED, rc);
+ pk_halt();
+ }
+
+}
diff --git a/src/occ_gpe1/gpe1_memory_power_control.h b/src/occ_gpe1/gpe1_memory_power_control.h
new file mode 100644
index 0000000..e5f704f
--- /dev/null
+++ b/src/occ_gpe1/gpe1_memory_power_control.h
@@ -0,0 +1,47 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/occ_gpe1/gpe1_memory_power_control.h $ */
+/* */
+/* OpenPOWER OnChipController Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2016 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+#ifndef _GPE1_MEMORY_POWER_CONTROL_H
+#define _GPE1_MEMORY_POWER_CONTROL_H
+
+#define PCR0_MASTER_ENABLE_BIT 2
+#define PCR0_POWERDOWN_ENABLE_BIT 22
+
+#define STR0_STR_ENABLE_BIT 0
+#define STR0_DISABLE_MEMORY_CLOCKS_BIT 1
+
+// Big Endian set/clear bit MACROS
+#define SET_BIT(var, bit) (var | (0x8000000000000000 >> bit) )
+
+#define CLR_BIT(var, bit) (var & ~(0x8000000000000000 >> bit) )
+
+
+// Big Endian set/clear 2 different bits MACROS
+#define SET_2BITS(var, bit1, bit2) SET_BIT(SET_BIT(var, bit1), bit2)
+
+#define CLR_2BITS(var, bit1, bit2) CLR_BIT(CLR_BIT(var, bit1), bit2)
+
+
+#endif // _GPE1_MEMORY_POWER_CONTROL_H
diff --git a/src/occ_gpe1/ipc_func_tables.c b/src/occ_gpe1/ipc_func_tables.c
index c2740e9..0e43fad 100644
--- a/src/occ_gpe1/ipc_func_tables.c
+++ b/src/occ_gpe1/ipc_func_tables.c
@@ -29,6 +29,7 @@ void gpe_dimm_control(ipc_msg_t* cmd, void* arg);
void gpe1_nop(ipc_msg_t* cmd, void* arg);
void gpe_reset_mem_deadman(ipc_msg_t* cmd, void* arg);
void gpe_24x7(ipc_msg_t* cmd, void* arg);
+void gpe_mem_power_control(ipc_msg_t* cmd, void* arg);
// Function table for multi target (common) functions
@@ -49,16 +50,16 @@ IPC_HANDLER(gpe_dimm_sm, 0) // 0 - IPC_ST_DIMM_SM_FUNCID
IPC_HANDLER(gpe_dimm_control, 0) // 1 - IPC_ST_DIMM_CONTROL_FUNCID
IPC_HANDLER(gpe1_nop, 0) // 2 - IPC_ST_GPE1_NOP
IPC_HANDLER(gpe_reset_mem_deadman, 0) // 3 - IPC_ST_RESET_MEM_DEADMAN
-IPC_HANDLER(gpe_24x7, 0) // 4 - IPC_ST_24_X_7_FUNCID
-IPC_HANDLER_DEFAULT // 5
-IPC_HANDLER_DEFAULT // 6
-IPC_HANDLER_DEFAULT // 7
-IPC_HANDLER_DEFAULT // 8
-IPC_HANDLER_DEFAULT // 9
-IPC_HANDLER_DEFAULT // 10
-IPC_HANDLER_DEFAULT // 11
-IPC_HANDLER_DEFAULT // 12
-IPC_HANDLER_DEFAULT // 13
-IPC_HANDLER_DEFAULT // 14
-IPC_HANDLER_DEFAULT // 15
+IPC_HANDLER(gpe_24x7, 0) // 4 - IPC_ST_24_X_7_FUNCID
+IPC_HANDLER(gpe_mem_power_control, 0) // 5 - IPC_ST_MEM_POWER_CONTROL_FUNCID
+IPC_HANDLER_DEFAULT // 6
+IPC_HANDLER_DEFAULT // 7
+IPC_HANDLER_DEFAULT // 8
+IPC_HANDLER_DEFAULT // 9
+IPC_HANDLER_DEFAULT // 10
+IPC_HANDLER_DEFAULT // 11
+IPC_HANDLER_DEFAULT // 12
+IPC_HANDLER_DEFAULT // 13
+IPC_HANDLER_DEFAULT // 14
+IPC_HANDLER_DEFAULT // 15
IPC_ST_FUNC_TABLE_END
diff --git a/src/occ_gpe1/topfiles.mk b/src/occ_gpe1/topfiles.mk
index 9983f69..6dbae16 100644
--- a/src/occ_gpe1/topfiles.mk
+++ b/src/occ_gpe1/topfiles.mk
@@ -25,7 +25,7 @@
TOP-C-SOURCES = gpe1_main.c gpe1_dimm_read.c gpe1_dimm_reset.c nop.c \
pk_app_irq_table.c ipc_func_tables.c gpe1_dimm_control.c \
- gpe1_24x7.c
+ gpe1_24x7.c gpe1_memory_power_control.c
TOP-S-SOURCES =
OpenPOWER on IntegriCloud