diff options
| author | Manali Kumar <mkkumar@us.ibm.com> | 2015-09-24 18:52:00 -0500 |
|---|---|---|
| committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2015-12-08 10:24:35 -0600 |
| commit | 1fbe5e7bf5042ee9e7353a169d13eec54c270f04 (patch) | |
| tree | 3cb9fc58e569fa0d22f7f16a6d8b32900e9de2da /src/usr/sio | |
| parent | dee70f6f25fb4ed099942b1b3b0a340bd643ff06 (diff) | |
| download | blackbird-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/HBconfig | 4 | ||||
| -rwxr-xr-x | src/usr/sio/makefile | 33 | ||||
| -rwxr-xr-x | src/usr/sio/siodd.C | 434 | ||||
| -rw-r--r-- | src/usr/sio/siodd.H | 183 | ||||
| -rw-r--r-- | src/usr/sio/test/makefile | 30 | ||||
| -rw-r--r-- | src/usr/sio/test/sioddtest.H | 452 |
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 |

