summaryrefslogtreecommitdiffstats
path: root/src/usr/sio
diff options
context:
space:
mode:
authorManali Kumar <mkkumar@us.ibm.com>2015-09-24 18:52:00 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2015-12-08 10:24:35 -0600
commit1fbe5e7bf5042ee9e7353a169d13eec54c270f04 (patch)
tree3cb9fc58e569fa0d22f7f16a6d8b32900e9de2da /src/usr/sio
parentdee70f6f25fb4ed099942b1b3b0a340bd643ff06 (diff)
downloadblackbird-hostboot-1fbe5e7bf5042ee9e7353a169d13eec54c270f04.tar.gz
blackbird-hostboot-1fbe5e7bf5042ee9e7353a169d13eec54c270f04.zip
superio driver to control accesss to SIO registers
The SuperIO driver makes accesses to the SIO chip from the console and pnor module thread safe. Change-Id: Ib07dea2867d14684806c56cd965b26c95810f7f3 RTC:115576 Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/20928 Tested-by: Jenkins Server Tested-by: Jenkins OP Build CI Tested-by: Jenkins OP HW Tested-by: FSP CI Jenkins Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com> Reviewed-by: PRACHI GUPTA <pragupta@us.ibm.com> Reviewed-by: Richard J. Knight <rjknight@us.ibm.com> Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/sio')
-rw-r--r--src/usr/sio/HBconfig4
-rwxr-xr-xsrc/usr/sio/makefile33
-rwxr-xr-xsrc/usr/sio/siodd.C434
-rw-r--r--src/usr/sio/siodd.H183
-rw-r--r--src/usr/sio/test/makefile30
-rw-r--r--src/usr/sio/test/sioddtest.H452
6 files changed, 1136 insertions, 0 deletions
diff --git a/src/usr/sio/HBconfig b/src/usr/sio/HBconfig
new file mode 100644
index 000000000..69a2f0b1c
--- /dev/null
+++ b/src/usr/sio/HBconfig
@@ -0,0 +1,4 @@
+config AST2400
+ default y if (BMC_AST2400 || SFC_IS_AST2400)
+ help
+ Enables superIO driver.
diff --git a/src/usr/sio/makefile b/src/usr/sio/makefile
new file mode 100755
index 000000000..2b751162c
--- /dev/null
+++ b/src/usr/sio/makefile
@@ -0,0 +1,33 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/sio/makefile $
+#
+# OpenPOWER HostBoot Project
+#
+# Contributors Listed Below - COPYRIGHT 2014,2015
+# [+] 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
+
+ROOTPATH = ../../..
+MODULE = sio
+
+SUBDIRS += test.d
+OBJS += siodd.o
+
+include $(ROOTPATH)/config.mk
+
diff --git a/src/usr/sio/siodd.C b/src/usr/sio/siodd.C
new file mode 100755
index 000000000..5301d9e1c
--- /dev/null
+++ b/src/usr/sio/siodd.C
@@ -0,0 +1,434 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/sio/siodd.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] 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 <sio/sio.H>
+#include "siodd.H"
+#include <errl/errlmanager.H>
+#include <errl/errlentry.H>
+#include <trace/interface.H>
+#include <sys/sync.h>
+#include <devicefw/userif.H>
+#include <lpc/lpcif.H>
+#include <kernel/console.H>
+#include <devicefw/driverif.H>
+#include <initservice/bootconfigif.H>
+#include <sys/time.h>
+#include <hbotcompid.H>
+#include <stdarg.h>
+#include <targeting/common/target.H>
+
+// Trace definition
+trace_desc_t* g_trac_sio = NULL;
+TRAC_INIT(&g_trac_sio, SIO_COMP_NAME, 2*KILOBYTE, TRACE::BUFFER_SLOW); //2K
+
+/**
+ * This function performs an SIO Read operation. It follows a pre-defined
+ * prototype functions in order to be registered with the device-driver
+ * framework.
+ *
+ * @param[in] i_opTypeOperation type, see DeviceFW::OperationType in
+ * driverif.H
+ * @param[in] i_targetSIO target
+ * @param[in/out] io_buffer Read: Pointer to output data storage
+ * Write: Pointer to input data storage
+ * @param[in/out] io_buflen Input: size of io_buffer (in bytes)
+ * Output: Read: Size of output data
+ * Write: Size of data written
+ * @param[in] i_accessTypeDeviceFW::AccessType enum (usrif.H)
+ * @param[in] i_args This is an argument list for DD framework.
+ * @return errlHndl_t
+ */
+errlHndl_t SIORead(DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* io_buffer,
+ size_t& io_buflen,
+ int64_t i_accessType, va_list i_args)
+{
+ assert(i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL);
+ errlHndl_t l_err = NULL;
+ uint8_t l_dev = va_arg(i_args,uint64_t);
+ uint8_t l_addr = va_arg(i_args,uint64_t);
+ l_err = Singleton<SioDD>::instance().readSIO(i_target, l_dev, l_addr,
+ static_cast<uint8_t*>(io_buffer));
+ return l_err;
+}
+
+/**
+ * This function performs an SIO Write operation. It follows a pre-defined
+ * prototype functions in order to be registered with the device-driver
+ * framework.
+ *
+ * param[in] i_opType Operation type, see DeviceFW::OperationType in
+ * driverif.H
+ * @param[in] i_targetSIO target
+ * @param[in/out] io_buffer Read: Pointer to output data storage
+ * Write: Pointer to input data storage
+ * @param[in/out] io_buflen Input: size of io_buffer (in bytes)
+ * Output: Read: Size of output data
+ * Write: Size of data written
+ * @param[in] i_accessTypeDeviceFW::AccessType enum (usrif.H)
+ * @param[in] i_args This is an argument list for DD framework.
+ * @return errlHndl_t
+ */
+errlHndl_t SIOWrite(DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* io_buffer,
+ size_t& io_buflen,
+ int64_t i_accessType,
+ va_list i_args)
+{
+ assert(i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL);
+ errlHndl_t l_err = NULL;
+ uint8_t l_dev = va_arg(i_args,uint64_t);
+ uint8_t l_addr = va_arg(i_args,uint64_t);
+ l_err = Singleton<SioDD>::instance().writeSIO(i_target, l_dev, l_addr,
+ static_cast<uint8_t*>(io_buffer));
+ return l_err;
+}
+
+/**
+ * This function performs an LPC to AHB read operation using superIO accesses.
+ * It follows a pre-defined prototype functions in order to be registered
+ * with the device-driver framework.
+ *
+ * @param[in] i_opType Operation type, see DeviceFW::OperationType in
+ * driverif.H
+ * @param[in] i_targetSIO target
+ * @param[in/out] io_buffer Read: Pointer to output data storage
+ * Write: Pointer to input data storage
+ * @param[in/out] io_buflen Input: size of io_buffer (in bytes)
+ * Output: Read: Size of output data
+ * Write: Size of data written
+ * @param[in] i_accessTypeDeviceFW::AccessType enum (usrif.H)
+ * @param[in] i_args This is an argument list for DD framework.
+ * @return errlHndl_t
+ */
+errlHndl_t ahbSioReadDD(DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* io_buffer,
+ size_t& io_buflen,
+ int64_t i_accessType,
+ va_list i_args)
+{
+ assert(i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL);
+ errlHndl_t l_err = NULL;
+ uint32_t l_reg = va_arg(i_args,uint64_t);
+ l_err = Singleton<SioDD>::instance().ahbSioRead(i_target, l_reg,
+ static_cast<uint32_t*>(io_buffer));
+ return l_err;
+}
+
+/**
+ * This function performs an LPC to AHB read operation using superIO accesses.
+ * It follows a pre-defined prototype functions in order to be registered
+ * with the device-driver framework.
+ *
+ * @param[in] i_opType Operation type, see DeviceFW::OperationType in
+ * driverif.H
+ * @param[in] i_targetSIO target
+ * @param[in/out] io_buffer Read: Pointer to output data storage
+ * Write: Pointer to input data storage
+ * @param[in/out] io_buflen Input: size of io_buffer (in bytes)
+ * Output: Read: Size of output data
+ * Write: Size of data written
+ * @param[in] i_accessTypeDeviceFW::AccessType enum (usrif.H)
+ * @param[in] i_args This is an argument list for DD framework.
+ * @return errlHndl_t
+ */
+errlHndl_t ahbSioWriteDD(DeviceFW::OperationType i_opType,
+ TARGETING::Target* i_target,
+ void* io_buffer,
+ size_t& io_buflen,
+ int64_t i_accessType,
+ va_list i_args)
+{
+ assert(i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL);
+ errlHndl_t l_err = NULL;
+ uint32_t l_reg = va_arg(i_args,uint64_t);
+ l_err = Singleton<SioDD>::instance().ahbSioWrite(i_target, l_reg,
+ static_cast<uint32_t*>(io_buffer));
+ return l_err;
+}
+
+// Register SIO access functions to DD framework
+DEVICE_REGISTER_ROUTE( DeviceFW::READ,
+ DeviceFW::SIO,
+ TARGETING::TYPE_PROC,
+ SIORead );
+DEVICE_REGISTER_ROUTE( DeviceFW::WRITE,
+ DeviceFW::SIO,
+ TARGETING::TYPE_PROC,
+ SIOWrite );
+
+// Register AHB_SIO access functions to DD framework
+DEVICE_REGISTER_ROUTE( DeviceFW::READ,
+ DeviceFW::AHB_SIO,
+ TARGETING::TYPE_PROC,
+ ahbSioReadDD );
+DEVICE_REGISTER_ROUTE( DeviceFW::WRITE,
+ DeviceFW::AHB_SIO,
+ TARGETING::TYPE_PROC,
+ ahbSioWriteDD );
+
+//function to unlock superIO password register
+void SioDD::unlock_SIO(TARGETING::Target* i_target)
+{
+ uint8_t l_byte = SIO::SIO_PASSWORD_REG;
+ errlHndl_t l_err = NULL;
+ do
+ {
+ // Unlock the SIO registers
+ // (write 0xA5 password to offset 0x2E two times)
+ size_t l_len = sizeof(uint8_t);
+ l_err = deviceWrite(i_target,
+ &l_byte,
+ l_len,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO::SIO_ADDR_REG_2E));
+ if(l_err) { break; }
+ l_err = deviceWrite(i_target,
+ &l_byte,
+ l_len,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO::SIO_ADDR_REG_2E));
+ } while(0);
+
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_sio,"Error in unlocking SIO password register\n");
+ errlCommit(l_err, SIO_COMP_ID);
+ }
+}
+
+//SioDD constructor
+SioDD::SioDD(TARGETING::Target* i_target)
+{
+ assert(i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL);
+ mutex_init(&iv_sio_mutex);
+ iv_prev_dev = 0x00;
+ unlock_SIO(i_target);
+}
+
+//SioDD destructor
+SioDD::~SioDD()
+{
+ mutex_destroy(&iv_sio_mutex);
+}
+
+//internal write function
+errlHndl_t SioDD::_writeSIO(TARGETING::Target* i_target,
+ uint8_t i_reg, uint8_t* i_data)
+{
+ errlHndl_t l_err = NULL;
+ do
+ {
+ size_t l_len = sizeof(uint8_t);
+ l_err = deviceWrite(i_target,
+ &i_reg,
+ l_len,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO::SIO_ADDR_REG_2E));
+ if(l_err) { break; }
+ l_err = deviceWrite(i_target,
+ i_data,
+ l_len,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO::SIO_DATA_REG_2F));
+ } while(0);
+ return l_err;
+}
+
+//internal read function
+errlHndl_t SioDD::_readSIO(TARGETING::Target* i_target,
+ uint8_t i_reg, uint8_t* o_byte)
+{
+ errlHndl_t l_err = NULL;
+ size_t l_len = sizeof(uint8_t);
+ do
+ {
+ l_err = deviceWrite(i_target,
+ &i_reg,
+ l_len,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO::SIO_ADDR_REG_2E));
+ if(l_err) { break; }
+ l_err = deviceRead(i_target,
+ o_byte,
+ l_len,
+ DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO::SIO_DATA_REG_2F));
+ } while(0);
+ return l_err;
+}
+
+//function to change logical device in SIO
+errlHndl_t SioDD::changeDevice(TARGETING::Target* i_target, uint8_t i_dev)
+{
+ uint8_t l_reg = SIO::SIO_DEVICE_SELECT_REG;
+ return _writeSIO(i_target, l_reg, &i_dev);
+}
+
+//function to read from SIO register
+errlHndl_t SioDD::readSIO(TARGETING::Target* i_target, uint8_t i_dev,
+ uint8_t i_reg, uint8_t* o_byte)
+{
+ mutex_lock(&iv_sio_mutex);
+ errlHndl_t l_err = NULL;
+
+ if(iv_prev_dev!=i_dev)
+ {
+ l_err = changeDevice(i_target, i_dev);
+ if(!l_err)
+ {
+ iv_prev_dev = i_dev;
+ l_err = _readSIO(i_target, i_reg, o_byte);
+ }
+ }
+ else
+ {
+ l_err = _readSIO(i_target, i_reg, o_byte);
+ }
+ mutex_unlock(&iv_sio_mutex);
+ return l_err;
+}
+
+
+//function to write to SIO register
+errlHndl_t SioDD::writeSIO(TARGETING::Target* i_target,
+ uint8_t i_dev, uint8_t i_reg, uint8_t* i_data)
+{
+ mutex_lock(&iv_sio_mutex);
+ errlHndl_t l_err = NULL;
+ if(iv_prev_dev!=i_dev)
+ {
+ l_err = changeDevice(i_target, i_dev);
+ if(!l_err)
+ {
+ iv_prev_dev = i_dev;
+ l_err = _writeSIO(i_target, i_reg, i_data);
+ }
+ }
+ else
+ {
+ l_err = _writeSIO(i_target, i_reg, i_data);
+ }
+ mutex_unlock(&iv_sio_mutex);
+ return l_err;
+}
+
+//function to translate address from LPC to AHB space
+errlHndl_t SioDD::_ahbSioAddrPrep(TARGETING::Target* i_target,
+ uint32_t i_addr)
+{
+ errlHndl_t l_err = NULL;
+ uint8_t l_dev = SIO::iLPC2AHB;
+ uint8_t l_data;
+ do
+ {
+ //select device 0x0D
+ l_err = changeDevice(i_target, l_dev);
+ if(l_err) { break; }
+
+ //write to f0-f3
+ for (size_t i = sizeof(i_addr); i>0; i--)
+ {
+ l_data = i_addr>>((i-1)*8);
+ l_err = _writeSIO(i_target, (0xF3-(i-1)), &l_data);
+ if( l_err ) { break; }
+ }
+
+ //byte length
+ l_data = SIO::SIO_iLPC2AHB_LENGTH;
+ l_err = _writeSIO(i_target, 0xF8, &l_data);
+ if( l_err ) { break; }
+ }
+ while(0);
+ return l_err;
+}
+
+errlHndl_t SioDD::_ahbSioRead(TARGETING::Target* i_target,
+ uint32_t i_reg, uint32_t* o_data)
+{
+ errlHndl_t l_err = NULL;
+ uint8_t tmp_data = 0;
+ do
+ {
+ l_err = _ahbSioAddrPrep(i_target, i_reg);
+ if( l_err ) { break; }
+
+ //trigger operation by reading from 0xFE
+ l_err = _readSIO(i_target, 0xFE, &tmp_data);
+ if( l_err ) { break; }
+ uint8_t* ptr8 = (uint8_t*)(o_data);
+ for( size_t i=0; i<sizeof(uint32_t); i++ )
+ {
+ l_err = _readSIO(i_target, 0xF4+i, &ptr8[i]);
+ if(l_err) { break; }
+ }
+ }
+ while(0);
+ return l_err;
+}
+
+errlHndl_t SioDD::_ahbSioWrite(TARGETING::Target* i_target,
+ uint32_t i_reg, uint32_t* i_val)
+{
+ errlHndl_t l_err = NULL;
+ uint8_t l_data;
+ do
+ {
+ l_err = _ahbSioAddrPrep(i_target, i_reg);
+ if( l_err ) { break; }
+
+ uint8_t* ptr8 = reinterpret_cast<uint8_t*>(i_val);
+ for (size_t i = 0; i<sizeof(uint32_t); i++)
+ {
+ l_err = _writeSIO(i_target, (0xF4+i), &ptr8[i]);
+ if( l_err ) { break; }
+ }
+ //trigger operation by writing to 0xFE
+ l_data = 0xCF;
+ l_err = _writeSIO(i_target, 0xFE, &l_data);
+ if( l_err ) { break; }
+ }
+ while(0);
+ return l_err;
+}
+
+//function to perform AHB to SIO read
+errlHndl_t SioDD::ahbSioRead(TARGETING::Target* i_target,
+ uint32_t i_reg, uint32_t* o_data)
+{
+ mutex_lock(&iv_sio_mutex);
+ errlHndl_t l_err = NULL;
+ l_err = _ahbSioRead(i_target, i_reg, o_data);
+ mutex_unlock(&iv_sio_mutex);
+ return l_err;
+}
+
+//function to perform AHB to SIO write
+errlHndl_t SioDD::ahbSioWrite(TARGETING::Target* i_target,
+ uint32_t i_reg, uint32_t* i_val)
+{
+ mutex_lock(&iv_sio_mutex);
+ errlHndl_t l_err = NULL;
+ l_err = _ahbSioWrite(i_target, i_reg, i_val);
+ mutex_unlock(&iv_sio_mutex);
+ return l_err;
+}
+
diff --git a/src/usr/sio/siodd.H b/src/usr/sio/siodd.H
new file mode 100644
index 000000000..664935921
--- /dev/null
+++ b/src/usr/sio/siodd.H
@@ -0,0 +1,183 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/sio/siodd.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015 */
+/* [+] 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 __SIO_SIODD_H
+#define __SIO_SIODD_H
+
+#include <limits.h>
+#include <sys/sync.h>
+#include <stdint.h>
+#include <errl/errlentry.H>
+#include <lpc/lpcif.H>
+#include <targeting/common/targetservice.H>
+
+/**
+ * class describing accesses to AST2400 BMC chip
+ */
+class SioDD
+{
+ public:
+ /** @brief Constructor
+ * @param[in] i_target: SIO target
+ */
+ SioDD(TARGETING::Target* i_target =
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL);
+
+ /* @brief Destructor */
+ ~SioDD();
+
+ /**
+ * @brief Read a single byte from a SIO register
+ * @param[in] i_target: SIO target
+ * @param[in] i_dev: Device to read from
+ * @param[in] i_reg: Register to read
+ * @param[in] o_byte: Data that was read
+ *
+ * @return Error from operation
+ */
+ errlHndl_t readSIO(TARGETING::Target* i_target,
+ uint8_t i_dev, uint8_t i_reg, uint8_t* o_byte);
+
+ /**
+ * @brief Write a single byte into a SIO register
+ * @param[in] i_target: SIO target
+ * @param[in] i_dev: Device to write to
+ * @param[in] i_reg: Register to write
+ * @param[in] i_data: Data to write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t writeSIO(TARGETING::Target* i_target,
+ uint8_t i_dev, uint8_t i_reg, uint8_t* i_data);
+
+ /**
+ * @brief AHB SIO read operation
+ * @param[in] i_target: SIO target
+ * @param[in] i_reg: Register to read
+ * @param[in] o_data: Data that was read
+ *
+ * @return Error from operation
+ */
+ errlHndl_t ahbSioRead(TARGETING::Target* i_target,
+ uint32_t i_reg, uint32_t* o_data);
+
+ /**
+ * @brief AHB SIO write operation
+ * @param[in] i_target: SIO target
+ * @param[in] i_reg: Register to write
+ * @param[in] i_val: Data to write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t ahbSioWrite(TARGETING::Target* i_target,
+ uint32_t i_reg, uint32_t* i_val);
+
+ friend class SioDDTest;
+
+ private:
+ /**
+ * @brief Change device pointed to by SIO
+ * @param[in] i_target: SIO target
+ * @param[in] i_dev: Device to point to
+ *
+ * @return Error from operation
+ */
+ errlHndl_t changeDevice(TARGETING::Target* i_target,
+ uint8_t i_dev);
+
+ /**
+ * @brief Internal write function
+ * assumes mutex is locked
+ * @param[in] i_target: SIO target
+ * @param[in] i_reg: Register to write
+ * @param[in] i_data: Data to write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t _writeSIO(TARGETING::Target* i_target,
+ uint8_t i_reg, uint8_t* i_data);
+
+ /**
+ * @brief Internal read function
+ * assumes mutex is locked
+ * @param[in] i_target: SIO target
+ * @param[in] i_reg: Register to read
+ * @param[in] o_byte: Data that was read
+ *
+ * @return Error from operation
+ */
+ errlHndl_t _readSIO(TARGETING::Target* i_target,
+ uint8_t i_reg, uint8_t* o_byte);
+
+ /**
+ * @brief LPC to AHB address translation
+ * @param[in] i_target: SIO target
+ * @param[in] i_addr: Address for subsequent AHB SIO read/write
+ *
+ * @return Error from operation
+ */
+ errlHndl_t _ahbSioAddrPrep(TARGETING::Target* i_target,
+ uint32_t i_addr);
+
+ /**
+ * @brief Internal write function
+ * assumes mutex is locked
+ * @param[in] i_target: SIO target
+ * @param[in] i_reg: Register to write to
+ * @param[in] i_val: Data that is to be written
+ *
+ * @return Error from operation
+ */
+ errlHndl_t _ahbSioWrite(TARGETING::Target* i_target,
+ uint32_t i_reg, uint32_t* i_val);
+
+ /**
+ * @brief Internal read function
+ * assumes mutex is locked
+ * @param[in] i_target: SIO target
+ * @param[in] i_reg: Register to read from
+ * @param[in] i_val: Data that was read
+ *
+ * @return Error from operation
+ */
+ errlHndl_t _ahbSioRead(TARGETING::Target* i_target,
+ uint32_t i_reg, uint32_t* o_data);
+
+ /**
+ * @brief Unlock SIO password register
+ * @param[in] i_target: SIO target
+ */
+ void unlock_SIO(TARGETING::Target* i_target);
+
+ /**
+ * @brief Previous device accessed by SIO
+ */
+ uint8_t iv_prev_dev;
+
+ /**
+ * @brief Mutex to prevent concurrent accesses to SIO
+ */
+ mutex_t iv_sio_mutex;
+ };
+#endif
diff --git a/src/usr/sio/test/makefile b/src/usr/sio/test/makefile
new file mode 100644
index 000000000..4337c81b1
--- /dev/null
+++ b/src/usr/sio/test/makefile
@@ -0,0 +1,30 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: src/usr/sio/test/makefile $
+#
+# OpenPOWER HostBoot Project
+#
+# Contributors Listed Below - COPYRIGHT 2014,2015
+# [+] 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
+ROOTPATH = ../../../..
+
+MODULE = testsio
+TESTS = *.H
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/sio/test/sioddtest.H b/src/usr/sio/test/sioddtest.H
new file mode 100644
index 000000000..2bd91b291
--- /dev/null
+++ b/src/usr/sio/test/sioddtest.H
@@ -0,0 +1,452 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/sio/test/sioddtest.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2014,2015 */
+/* [+] 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 __SIODDTEST_H
+#define __SIODDTEST_H
+
+/**
+ * @file sioddtest.H
+ *
+ * @brief Test case for SuperIO Driver
+*/
+#include <devicefw/driverif.H>
+#include <cxxtest/TestSuite.H>
+#include <errl/errlmanager.H>
+#include <errl/errlentry.H>
+#include <devicefw/userif.H>
+#include <sys/time.h>
+#include <list>
+#include <targeting/common/attributes.H>
+#include <sio/sio.H>
+#include "../siodd.H"
+
+const uint8_t CTLREG_04 = 0x04;
+const uint32_t SPIC_BASE_ADDR_AHB = 0x1E630000;
+class SioDDTest : public CxxTest::TestSuite
+{
+ public:
+ /**
+ * @brief Test SIO access
+ * Use a SIO scratch register to verify reads and writes
+ */
+ void test_SIO(void)
+ {
+ errlHndl_t l_err = NULL;
+ size_t l_len = sizeof(uint8_t);
+ mutex_t l_lock = Singleton<SioDD>::instance().iv_sio_mutex;
+ mutex_lock(&l_lock);
+ // Read SIO to BMC scratch reg 1,2 and save off values
+ uint8_t scratch1 = 0;
+ l_err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(scratch1),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::SUART1, SIO::SIO_SCRATCH_REG1));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_SIO> read from SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ uint8_t scratch2 = 0;
+ l_err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(scratch2),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::SUART1, SIO::SIO_SCRATCH_REG2));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_SIO> read from SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+
+ // Write test patterns into registers
+ uint8_t testdata = 0xA5;
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(testdata),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::SUART1, SIO::SIO_SCRATCH_REG1));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_SIO> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ testdata = 0x12;
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(testdata),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::SUART1, SIO::SIO_SCRATCH_REG2));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_SIO> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+
+ // Read the data back and compare to expected results
+ l_err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(testdata),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::SUART1, SIO::SIO_SCRATCH_REG1));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_SIO> read from SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ if( testdata != 0xA5 )
+ {
+ TS_FAIL("SioDDTest::test_SIO> Data mismatch on SIO 0x21\
+ : Exp=0xA5, Act=%.2X", testdata);
+ }
+ l_err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(testdata),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::SUART1, SIO::SIO_SCRATCH_REG2));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_SIO> read from SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ if( testdata != 0x12 )
+ {
+ TS_FAIL("SioDDTest::test_SIO> Data mismatch on SIO 0x22 :/\
+ Exp=0x12, Act=%.2X", testdata);
+ }
+
+ // Restore the original data
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(scratch1),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::SUART1, SIO::SIO_SCRATCH_REG1));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_SIO> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(scratch2),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::SUART1, SIO::SIO_SCRATCH_REG2));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_SIO> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ mutex_unlock(&l_lock);
+ }
+
+ /**
+ * @brief Concurrency test for SIO registers using devices Key Board
+ * Controller and MailBox
+ */
+ void test_concurrency()
+ {
+ mutex_t l_lock = Singleton<SioDD>::instance().iv_sio_mutex;
+ mutex_lock(&l_lock);
+ errlHndl_t l_err = NULL;
+ uint8_t l_data;
+ size_t l_len = sizeof(l_data);
+ //Enable additional SIO test devices 5 and E
+ l_data = SIO::ENABLE_DEVICE;
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(l_data),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::KBC, 0x30));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::SIO_concurrency> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(l_data),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::MB, 0x30));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::SIO_concurrency> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+
+ //Read current values from devices
+ //KBC
+ uint8_t kbc_base_add_msb = 0;
+ l_err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(kbc_base_add_msb),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::KBC, 0x60));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::SIO_concurrency> read from SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+
+ //MB
+ uint8_t mb_base_add_msb = 0;
+ l_err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(mb_base_add_msb),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::MB, 0x60));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::SIO_concurrency> read from SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+
+ //Write new values to registers 0x60
+ //KBC
+ uint8_t testdata1 = 0xAA;
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(testdata1),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::KBC, 0x60));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::SIO_concurrency> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+
+ //MB
+ uint8_t testdata2 = 0x05;
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(testdata2),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::MB, 0x60));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::SIO_concurrency> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+
+ //Read and compare
+ uint8_t testdata;
+ l_err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(testdata),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::KBC, 0x60));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::SIO_concurrency> read from SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ if( testdata != 0xAA )
+ {
+ TS_FAIL("SioDDTest::SIO_concurreny> Data mismatch on SIO device KBC\
+ reg 0x60 : Exp=0xAA, Act=%.2X", testdata);
+ }
+
+ l_err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(testdata),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::MB, 0x60));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::SIO_concurrency> read from SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ if( testdata != 0x05 )
+ {
+ TS_FAIL("SioDDTest::SIO_concurreny> Data mismatch on SIO device MB\
+ reg 0x60 : Exp=0x05, Act=%.2X", testdata);
+ }
+
+ //Write original data back
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(kbc_base_add_msb),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::KBC, 0x60));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::SIO_concurrency> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+
+ //MB
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(mb_base_add_msb),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::MB, 0x60));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::SIO_concurrency> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ mutex_unlock(&l_lock);
+ }
+
+ /** @brief test simultaneous accesses to same logical device
+ */
+ void test_same_dev()
+ {
+ uint8_t l_data;
+ errlHndl_t l_err = NULL;
+ size_t l_len = sizeof(l_data);
+ mutex_t l_lock = Singleton<SioDD>::instance().iv_sio_mutex;
+ mutex_lock(&l_lock);
+
+ //enable device Key Board Controller
+ l_data = SIO::ENABLE_DEVICE;
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(l_data),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::KBC, 0x30));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_same_dev> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ //Read value at key board controller, reg 0x60
+ uint8_t current_data = 0;
+ l_err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(current_data),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::KBC, 0x60));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_same_dev> read from SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ //Write new test value to key board controller, reg 0x60
+ uint8_t test_data = 0x10;
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(test_data),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::KBC, 0x60));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_same_dev> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ //Read and compare
+ l_err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(test_data),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::KBC, 0x60));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_same_dev> read from SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ if(test_data != 0x10)
+ {
+ TS_FAIL("SioDDTest::test_same_dev> Data mismatch on SIO KBC, 0x60\
+ : Exp=0x10, Act=%.2X", test_data);
+ }
+ //Write back original data
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(current_data),
+ l_len,
+ DEVICE_SIO_ADDRESS(SIO::KBC, 0x60));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_same_dev> write to SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ mutex_unlock(&l_lock);
+ }
+
+ /**
+ * @brief AHB_SIO access
+ * Read and write data to the SPI Control register
+ */
+ void test_AHB_SIO( void )
+ {
+ errlHndl_t l_err = NULL;
+ uint32_t l_lpc_addr;
+ size_t l_len = sizeof(uint32_t);
+ mutex_t l_lock = Singleton<SioDD>::instance().iv_sio_mutex;
+ mutex_lock(&l_lock);
+
+ uint32_t first = 0;
+ l_lpc_addr = CTLREG_04 | SPIC_BASE_ADDR_AHB;
+ l_err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(first),
+ l_len,
+ DEVICE_AHB_SIO_ADDRESS(l_lpc_addr));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_AHB_SIO> read from AHB_SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ uint32_t data1 = 0x12345678;
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(data1),
+ l_len,
+ DEVICE_AHB_SIO_ADDRESS(l_lpc_addr));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_AHB_SIO> write to AHB_SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ l_err = deviceOp( DeviceFW::READ,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(data1),
+ l_len,
+ DEVICE_AHB_SIO_ADDRESS(l_lpc_addr));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_AHB_SIO> read from AHB_SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ if( data1 != 0x12345678 )
+ {
+ TS_FAIL("SioDDTest::test_SPIC> Unexpected result of %.8X\
+ (exp 0x12345678)",data1);
+ }
+ //put back the original
+ l_err = deviceOp( DeviceFW::WRITE,
+ TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL,
+ &(first),
+ l_len,
+ DEVICE_AHB_SIO_ADDRESS(l_lpc_addr));
+ if( l_err )
+ {
+ TS_FAIL("SioDDTest::test_AHB_SIO> write to AHB_SIO failed");
+ errlCommit(l_err,SIO_COMP_ID);
+ }
+ mutex_unlock(&l_lock);
+ }
+};
+#endif
OpenPOWER on IntegriCloud