summaryrefslogtreecommitdiffstats
path: root/src/occ_405/firdata/lpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/occ_405/firdata/lpc.c')
-rw-r--r--src/occ_405/firdata/lpc.c297
1 files changed, 193 insertions, 104 deletions
diff --git a/src/occ_405/firdata/lpc.c b/src/occ_405/firdata/lpc.c
index fe69efc..ffe2b48 100644
--- a/src/occ_405/firdata/lpc.c
+++ b/src/occ_405/firdata/lpc.c
@@ -1,11 +1,11 @@
/* IBM_PROLOG_BEGIN_TAG */
/* This is an automatically generated prolog. */
/* */
-/* $Source: src/occ/firdata/lpc.C $ */
+/* $Source: src/occ_405/firdata/lpc.c $ */
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2015 */
+/* Contributors Listed Below - COPYRIGHT 2015,2017 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -26,14 +26,19 @@
#include <native.h>
#include <lpc.h>
#include <trac_interface.h>
+#include <scom_util.h>
#define LPCHC_FW_SPACE 0xF0000000 /**< LPC Host Controller FW Space */
#define LPCHC_MEM_SPACE 0xE0000000 /**< LPC Host Controller Mem Space */
#define LPCHC_IO_SPACE 0xD0010000 /**< LPC Host Controller I/O Space */
#define LPCHC_REG_SPACE 0xC0012000 /**< LPC Host Ctlr Register Space */
-
#define ECCB_NON_FW_RESET_REG 0x000B0001 /**< ECCB Reset Reg (non-FW) */
+#define LPC_BASE_REG 0x00090040 /**< LPC Base Address Register */
+#define LPC_CMD_REG 0x00090041 /**< LPC Command Register */
+#define LPC_DATA_REG 0x00090042 /**< LPC Data Register */
+#define LPC_STATUS_REG 0x00090043 /**< LPC Status Register */
+
#define ECCB_CTL_REG 0x000B0020 /**< ECCB Control Reg (FW) */
#define ECCB_RESET_REG 0x000B0021 /**< ECCB Reset Reg (FW) */
#define ECCB_STAT_REG 0x000B0022 /**< ECCB Status Reg (FW) */
@@ -43,8 +48,8 @@
1101.0100.0000.000x.0000.0001.0000.0000.<address> */
#define ECCB_CTL_REG_DEFAULT 0xD400010000000000
-/* Error bits: 41-43 56 (52cmd complete) (not 57: only non-fw use) */
-#define ECCB_STAT_REG_ERROR_MASK 0x0000000000700080 /**< Error Bits */
+/* Error bits: wh_todo comments here */
+#define LPC_STAT_REG_ERROR_MASK 0x0000000000000000 /**< Error Bits */ //wh_todo correctly set mask
/**< OPB LPCM Sync FIR Reg - used to read the FIR*/
#define OPB_LPCM_FIR_REG 0x01010C00
@@ -63,67 +68,65 @@
#define ECCB_RESET_LPC_FAST_RESET (1ULL << 62) /**< bit 1 Fast reset */
-#define ECCB_POLL_TIME_NS 400000 /**< max time should be 400ms */
-//dc99 #define ECCB_POLL_INCR_NS 10 /**< minimum increment during poll */
-#define ECCB_POLL_INCR_NS 100000 /**< increase for testing */
+#define LPC_POLL_TIME_NS 400000 /**< max time should be 400ms */
+#define LPC_POLL_INCR_NS 100000 /**< increase for testing */
#define LPCHC_SYNC_CYCLE_COUNTER_INFINITE 0xFF000000
-int TRACE_LPC = 0;
-#define TRACZCOMP(args...) if(TRACE_LPC){TRACFCOMP(args);}
+/**
+ * @brief LPC Base Register Layout
+*/
+typedef union
+{
+
+ uint64_t data64;
-/* Set to enable LPC tracing. */
-/* #define LPC_TRACING 1 */
-#ifdef LPC_TRACING
-#define LPC_TRACFCOMP(des,printf_string,args...) \
- TRACFCOMP(des,printf_string,##args) /* FIX FIRDATA */
-#else
-#define LPC_TRACFCOMP(args...)
-#endif
+ struct
+ {
+ /* unused sections should be set to zero */
+ uint64_t unused0 : 8; /**< 0:7 */
+ uint64_t base_addr : 24; /**< 8:31 */
+ uint64_t unused1 : 31; /**< 32:62 */
+ uint64_t disable : 1; /**< 63 */
+ };
+} BaseReg_t;
/**
- * @brief ECCB Control Register Layout
+ * @brief LPC Control Register Layout
*/
typedef union
{
+
uint64_t data64;
+
struct
{
/* unused sections should be set to zero */
- uint64_t magic1 : 4; /**< 0:3 = b1101 per spec */
- uint64_t data_len : 4; /**< 4:7 = b0100 means 4 byte */
- uint64_t unused1 : 7; /**< 8:14 */
- uint64_t read_op : 1; /**< 15 = set for read operation */
- uint64_t unused2 : 7; /**< 16:22 */
- uint64_t addr_len : 3; /**< 23:25 = b100 means 4 byte */
- uint64_t unused3 : 6; /**< 26:31 */
- uint64_t address : 32; /**< 32:63 = LPC Address */
+ // rnw == read not write
+ uint64_t rnw : 1; /**< 0 = Setting to 1 causes read */
+ uint64_t unused0 : 4; /**< 1:4 */
+ uint64_t size : 7; /**< 5:11 */
+ uint64_t unused1 : 20; /**< 12:31 */
+ uint64_t address : 32; /**< 32:63 = LPC Address */
};
-} ControlReg_t;
+} CommandReg_t;
/**
- * @brief ECCB Status Register Layout
+ * @brief LPC Status Register Layout
*/
typedef union
{
uint64_t data64;
struct
{
- uint64_t unused : 6; /**< 0:5 */
- uint64_t read_data : 32; /**< 6:37 */
- uint64_t unused1 : 3; /**< 38:40 */
- uint64_t eccb_err : 3; /**< 41:43 = ECCB_Error_Info */
- uint64_t busy : 1; /**< 44 = Operation Busy */
- uint64_t unused2 : 7; /**< 45:51 */
- uint64_t op_done : 1; /**< 52 = Command Complete */
- uint64_t unused3 : 3; /**< 53:55 */
- uint64_t addr_parity_err : 1; /**< 56 = ECC Address Register
- Parity Error */
- uint64_t unused4 : 7; /**< 57:63 */
+ uint64_t op_done : 1; /**< 0 */
+ uint64_t unused0 : 9; /**< 1:9 */
+ uint64_t opb_valid : 1; /**< 10 */
+ uint64_t opb_ack : 1; /**< 11 */
+ uint64_t unused1 : 52; /**< 12:63 */
};
} StatusReg_t;
-
uint32_t checkAddr(LpcTransType i_type,
uint32_t i_addr)
{
@@ -141,8 +144,8 @@ uint32_t checkAddr(LpcTransType i_type,
}
-errorHndl_t pollComplete(const ControlReg_t* i_ctrl,
- StatusReg_t* o_stat)
+errorHndl_t pollComplete(CommandReg_t* i_ctrl,
+ StatusReg_t* o_stat)
{
errorHndl_t l_err = NO_ERROR;
@@ -151,11 +154,11 @@ errorHndl_t pollComplete(const ControlReg_t* i_ctrl,
uint64_t loop = 0;
do
{
- xscom_read( ECCB_STAT_REG, &(o_stat->data64) );
- LPC_TRACFCOMP( "writeLPC> Poll on ECCB Status, "
- "poll_time=0x%.16x, stat=0x%.16x",
- poll_time,
- o_stat->data64 );
+ SCOM_Trgt_t l_target;
+ l_target.type = TRGT_PROC;
+ l_target.isMaster = TRUE;
+ l_err = SCOM_getScom(l_target, LPC_STATUS_REG, &(o_stat->data64));
+
if( l_err )
{
break;
@@ -166,19 +169,19 @@ errorHndl_t pollComplete(const ControlReg_t* i_ctrl,
break;
}
- /* want to start out incrementing by small numbers then get bigger
+ /* Want to start out incrementing by small numbers then get bigger
to avoid a really tight loop in an error case so we'll increase
the wait each time through */
- sleep( ECCB_POLL_INCR_NS*(++loop) );
- poll_time += ECCB_POLL_INCR_NS * loop;
- } while ( poll_time < ECCB_POLL_TIME_NS );
+ sleep( LPC_POLL_INCR_NS*(++loop) );
+ poll_time += LPC_POLL_INCR_NS * loop;
+ } while ( poll_time < LPC_POLL_TIME_NS );
/* Check for hw errors or timeout if no previous logs */
if( (l_err == NO_ERROR) &&
- ((o_stat->data64 & ECCB_STAT_REG_ERROR_MASK)
+ ((o_stat->data64 & LPC_STAT_REG_ERROR_MASK)
|| (!o_stat->op_done)) )
{
- TRACFCOMP( "LpcDD::pollComplete> LPC error or timeout: addr=0x%.8X, status=0x%.8X%.8X",
+ TRAC_ERR( "LpcDD::pollComplete> LPC error or timeout: addr=0x%.8X, status=0x%.8X%.8X",
i_ctrl->address, (uint32_t)(o_stat->data64>>32), (uint32_t)o_stat->data64 );
l_err = -1;
break;
@@ -186,6 +189,7 @@ errorHndl_t pollComplete(const ControlReg_t* i_ctrl,
} while(0);
return l_err;
+
}
@@ -197,7 +201,10 @@ errorHndl_t lpc_read( LpcTransType i_type,
size_t i_size )
{
errorHndl_t l_err = NO_ERROR;
- uint32_t l_addr = 0;
+ int32_t l_addr = 0;
+ uint64_t l_ret;
+ uint32_t l_shift_amount;
+ uint64_t l_temp_data;
do {
if( o_data == NULL )
@@ -207,40 +214,85 @@ errorHndl_t lpc_read( LpcTransType i_type,
break;
}
+
/* Generate the full absolute LPC address */
l_addr = checkAddr( i_type, i_addr );
- /* Execute command. */
- ControlReg_t eccb_cmd;
- eccb_cmd.data64 = ECCB_CTL_REG_DEFAULT;
- eccb_cmd.data_len = i_size;
- eccb_cmd.read_op = 1;
- eccb_cmd.addr_len = sizeof(l_addr);
- eccb_cmd.address = l_addr;
- xscom_write( ECCB_CTL_REG, eccb_cmd.data64 );
+ /* Setup command */
+ CommandReg_t lpc_cmd;
+ lpc_cmd.rnw = 1; //Indicate read not write
+ lpc_cmd.size = i_size;
+ lpc_cmd.address = l_addr;
+
+ /* Execute command via Scom */
+ SCOM_Trgt_t l_target;
+ l_target.type = TRGT_PROC;
+ l_target.isMaster = TRUE;
+
+ //First write the address we want to read from in the
+ //LPC_CMD_REG scom address
+ l_err = SCOM_putScom(l_target, LPC_CMD_REG, lpc_cmd.data64);
+ if(l_err != SUCCESS)
+ {
+ TRAC_ERR("lpc_read: SCOM_putScom failed to write to LPC_CMD_REG command rc=0x%08x",
+ (uint32_t)l_err);
+ break;
+ }
/* Poll for completion */
- StatusReg_t eccb_stat;
- l_err = pollComplete( &eccb_cmd, &eccb_stat );
+ StatusReg_t lpc_status;
+ l_err = pollComplete( &lpc_cmd, &lpc_status );
if( l_err ) { break; }
- /* Copy data out to caller's buffer. */
- if( i_size <= sizeof(uint32_t) )
+ // Read data from the LPC_DATA_REG
+ l_err = SCOM_getScom(l_target, LPC_DATA_REG, &l_ret);
+ if(l_err != SUCCESS)
+ {
+ TRAC_ERR("lpc_read: SCOM_getScom failed rc=0x%08x", (uint32_t)l_err);
+ break;
+ }
+
+ //The scom returns the data in the byte offset represented by last
+ //3 bits of the address. For example, addr 0x21 will have have data
+ //starting in byte1 on value returned from scom.
+ //addr & 0x7 <-- this gives the byte offset
+ //7 - (addr & 0x7) <-- subratcing from 7 as the data is left aligned
+ //adding (size - 1) <-- to incorporate reading more than one byte
+ //multiply by 8 to convert from byte to bits
+ l_shift_amount = (7 - ((l_addr & 0x7) + (i_size-1))) * 8;
+ l_temp_data = l_ret >> l_shift_amount;
+
+ //Had some weird problems with memcpy, that's why typecasting
+ //to the size of data asked.
+ if (i_size == sizeof(uint8_t))
+ {
+ uint8_t* l_temp_ptr = (uint8_t*)(o_data);
+ *l_temp_ptr = l_temp_data;
+ }
+ else if (i_size == sizeof(uint16_t))
+ {
+ uint16_t* l_temp_ptr = (uint16_t*)(o_data);
+ *l_temp_ptr = l_temp_data;
+ }
+ else if (i_size == sizeof(uint32_t))
+ {
+ uint32_t* l_temp_ptr = (uint32_t*)(o_data);
+ *l_temp_ptr = l_temp_data;
+ }
+ else if (i_size == sizeof(uint64_t))
{
- uint32_t tmpbuf = eccb_stat.read_data;
- memcpy( o_data, &tmpbuf, i_size );
+ uint64_t* l_temp_ptr = (uint64_t*)(o_data);
+ *l_temp_ptr = l_temp_data;
}
else
{
- TRACFCOMP( "readLPC> Unsupported buffer size : %d", i_size );
+ TRAC_ERR("lpc_read: unsupported size length");
l_err = -1;
break;
}
} while(0);
- LPC_TRACFCOMP( "readLPC> %08X[%d] = %08X", l_addr, i_size, *reinterpret_cast<uint32_t*>( o_data ) >> (8 * (4 - i_size)) );
-
return l_err;
}
@@ -251,51 +303,88 @@ errorHndl_t lpc_write( LpcTransType i_type,
{
errorHndl_t l_err = NO_ERROR;
uint32_t l_addr = 0;
+ uint64_t l_write_data = 0;
+ uint64_t l_data = 0;
+ uint32_t l_shift_amount;
do {
/* Generate the full absolute LPC address */
l_addr = checkAddr( i_type, i_addr );
- uint64_t eccb_data = 0;
- /* Left-justify user data into data register. */
- switch ( i_size )
+ /* Setup Write Command */
+ CommandReg_t lpc_cmd;
+ lpc_cmd.rnw = 0; //Indicate write
+ lpc_cmd.size = i_size;
+ lpc_cmd.address = l_addr;
+
+ /* Setup Write command via Scom */
+ SCOM_Trgt_t l_target;
+ l_target.type = TRGT_PROC;
+ l_target.isMaster = TRUE;
+
+ //First write the address we want to write to in LPC_CMD_REG
+ l_err = SCOM_putScom(l_target, LPC_CMD_REG, lpc_cmd.data64);
+ if(l_err != SUCCESS)
{
- case 1:
- eccb_data = (uint64_t)
- (*(const uint8_t*)(i_data)) << 56;
- break;
- case 2:
- eccb_data = (uint64_t)
- (*(const uint16_t*)( i_data ) ) << 48;
- break;
- case 4:
- eccb_data = (uint64_t)
- (*(const uint32_t*)( i_data ) ) << 32;
- break;
- default:
- TRACFCOMP( "writeLPC> Unsupported buffer size : %d", i_size );
- break;
+ TRAC_ERR("ERROR> lpc_write: SCOM_putScom failed to write to LPC_CMD_REG command: rc=0x%08x",
+ (uint32_t)l_err);
+ break;
}
- /* Write data out */
- TRACZCOMP("ECCB_DATA_REG=%.8X%.8X",(uint32_t)(eccb_data>>32),(uint32_t)eccb_data);
- xscom_write( ECCB_DATA_REG, eccb_data );
+ //There were some weird memcpy problems. That's why, typecasting
+ //to the size of data requested to write
+ if (i_size == sizeof(uint8_t))
+ {
+ l_write_data = (*i_data);
+ }
+ else if (i_size == sizeof(uint16_t))
+ {
+ uint16_t* l_temp_ptr = (uint16_t*)(i_data);
+ l_write_data = *l_temp_ptr;
+ }
+ else if (i_size == sizeof(uint32_t))
+ {
+ uint32_t* l_temp_ptr = (uint32_t*)(i_data);
+ l_write_data = *l_temp_ptr;
+ }
+ else if (i_size == sizeof(uint64_t))
+ {
+ uint64_t* l_temp_ptr = (uint64_t*)(i_data);
+ l_write_data = *l_temp_ptr;
+ }
+ else
+ {
+ TRAC_ERR("lpc_write: unsupported size length");
+ l_err = -1;
+ break;
+ }
- /* Execute command. */
- ControlReg_t eccb_cmd;
- eccb_cmd.data64 = ECCB_CTL_REG_DEFAULT;
- eccb_cmd.data_len = i_size;
- eccb_cmd.read_op = 0;
- eccb_cmd.addr_len = sizeof(l_addr);
- eccb_cmd.address = l_addr;
- xscom_write( ECCB_CTL_REG, eccb_cmd.data64 );
- TRACZCOMP("ECCB_CTL_REG=%.8X%.8X",(uint32_t)(eccb_cmd.data64>>32),(uint32_t)eccb_cmd.data64);
+ //The scom expects the data in the byte offset represented by last
+ //3 bits of the address. For example, addr 0x21 will have have data
+ //starting in byte1 on value returned from scom.
+ //addr & 0x7 <-- this gives the byte offset
+ //7 - (addr & 0x7) <-- subratcing from 7 as the data in the scom reg
+ //is expected to be left aligned
+ //adding (size - 1) <-- to incorporate reading more than one byte
+ //multiply by 8 to convert from byte to bits
+ l_shift_amount = (7 - ((l_addr & 0x7) + (i_size-1))) * 8;
+ l_data = (l_write_data << l_shift_amount);
+
+ //Write the value to the LPC_DATA_REG
+ l_err = SCOM_putScom(l_target, LPC_DATA_REG, l_data);
+ if(l_err != SUCCESS)
+ {
+ TRAC_ERR("ERROR> lpc_write: SCOM_putScom failed to write to LPC_DATA_REG data: rc=0x%08x",
+ (uint32_t)l_err);
+ break;
+ }
/* Poll for completion */
- StatusReg_t eccb_stat;
- l_err = pollComplete( &eccb_cmd, &eccb_stat );
+ StatusReg_t lpc_stat;
+ l_err = pollComplete( &lpc_cmd, &lpc_stat );
if( l_err ) { break; }
+
} while(0);
return l_err;
OpenPOWER on IntegriCloud