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 | |
| parent | dee70f6f25fb4ed099942b1b3b0a340bd643ff06 (diff) | |
| download | talos-hostboot-1fbe5e7bf5042ee9e7353a169d13eec54c270f04.tar.gz talos-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')
| -rw-r--r-- | src/include/usr/devicefw/userif.H | 17 | ||||
| -rw-r--r-- | src/include/usr/hbotcompid.H | 8 | ||||
| -rw-r--r-- | src/include/usr/sio/sio.H | 51 | ||||
| -rw-r--r-- | src/makefile | 2 | ||||
| -rw-r--r-- | src/usr/console/HBconfig | 8 | ||||
| -rw-r--r-- | src/usr/console/ast2400.C | 379 | ||||
| -rw-r--r-- | src/usr/initservice/bootconfig/bootconfig_ast2400.C | 173 | ||||
| -rw-r--r-- | src/usr/initservice/bootconfig/bootconfig_ast2400.H | 33 | ||||
| -rw-r--r-- | src/usr/makefile | 3 | ||||
| -rw-r--r-- | src/usr/pnor/sfc_ast2400.C | 285 | ||||
| -rw-r--r-- | src/usr/pnor/sfc_ast2400.H | 44 | ||||
| -rw-r--r-- | src/usr/pnor/test/sfc_ast2400test.H | 138 | ||||
| -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 |
18 files changed, 1452 insertions, 825 deletions
diff --git a/src/include/usr/devicefw/userif.H b/src/include/usr/devicefw/userif.H index 55751d97d..e30595e40 100644 --- a/src/include/usr/devicefw/userif.H +++ b/src/include/usr/devicefw/userif.H @@ -63,6 +63,8 @@ namespace DeviceFW IPMIBT, // As opposed to other phy's PVPD, TPM, + SIO, + AHB_SIO, LAST_ACCESS_TYPE, }; @@ -214,6 +216,21 @@ namespace DeviceFW DeviceFW::LPC, static_cast<uint64_t>(( i_trans_type )),\ static_cast<uint64_t>(( i_address )) + /** + * Construct the device addressing parameters for the SIO device ops. + * @param[i] i_device - SIO device to operate on + * @param[i] i_address - SIO address to operate on + */ + #define DEVICE_SIO_ADDRESS(i_device, i_address)\ + DeviceFW::SIO, static_cast<uint64_t>((i_device)),\ + static_cast<uint64_t>((i_address)) + + /** + * Construct the device addressing parameters for the AHB_SIO device ops. + * @param[i] i_address - AHB_SIO address to operate on + */ + #define DEVICE_AHB_SIO_ADDRESS(i_address)\ + DeviceFW::AHB_SIO, static_cast<uint64_t>((i_address)) /** * Construct the device addressing parameters for the EEPROM device ops. diff --git a/src/include/usr/hbotcompid.H b/src/include/usr/hbotcompid.H index 88cd49dbd..dc5b79d41 100644 --- a/src/include/usr/hbotcompid.H +++ b/src/include/usr/hbotcompid.H @@ -383,6 +383,14 @@ const compId_t FIPS_ERRL_COMP_ID = 0x3100; const char FIPS_ERRL_COMP_NAME[] = "hb-trace"; //@} +/** @name SIO + * SIO driver + */ +//@{ +const compId_t SIO_COMP_ID = 0x3200; +const char SIO_COMP_NAME[] = "sio"; +//@} + /** @name PRDF * PRDF component * @Note PRDF_COMP_ID=0xE500 matches with what diff --git a/src/include/usr/sio/sio.H b/src/include/usr/sio/sio.H new file mode 100644 index 000000000..52f752da7 --- /dev/null +++ b/src/include/usr/sio/sio.H @@ -0,0 +1,51 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/include/usr/sio/sio.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_SIO_H +#define __SIO_SIO_H + +namespace SIO +{ + /** + * SIO constants + */ + enum{ + SIO_DEVICE_SELECT_REG = 0x07, /**< Regsiter to select SIO device */ + SIO_ADDR_REG_2E = 0x2E, /**< SuperIO address register */ + SIO_DATA_REG_2F = 0x2F, /**< SuperIO data register */ + SIO_PASSWORD_REG = 0xA5, /**< SuperIO password register (to be unlocked to access SIO) */ + SUART1 = 0x02, /**< SIO device */ + iLPC2AHB = 0x0D, /**< SIO device */ + KBC = 0x05, /**< SIO device: Keyboard Controller */ + MB = 0x0E, /**< SIO device: Mailbox */ + DONT_CARE = 0x02, /**< SIO device: Don't care for boot flags version */ + ENABLE_DEVICE = 0x01, /**< Enable SIO device by writing 1 to reg 30 of device */ + DISABLE_DEVICE = 0x00, /**< Disable SIO device by writing 0 to reg 30 of device */ + SIO_iLPC2AHB_LENGTH = 0x02, /**< SIO to iLPC2AHB length */ + SIO_ILPC2AHB_TRIGGER = 0xCF, /**< Read/Write 0xCF to reg FE of iLPC2AHB to trigger read/write for SIO/iLPC2AHB */ + SIO_SCRATCH_REG1 = 0x21, /**< Scratch Reg */ + SIO_SCRATCH_REG2 = 0x22, /**< Scratch Reg */ + }; +} +#endif diff --git a/src/makefile b/src/makefile index 8f986862c..f581ebafb 100644 --- a/src/makefile +++ b/src/makefile @@ -115,6 +115,7 @@ BASE_MODULES += secureboot_base BASE_MODULES += lpc BASE_MODULES += pnor BASE_MODULES += vfs +BASE_MODULES += $(if $(CONFIG_AST2400), sio) EXTENDED_MODULES += targeting EXTENDED_MODULES += ecmddatabuffer @@ -208,6 +209,7 @@ TESTCASE_MODULES += testrtloader TESTCASE_MODULES += testsbe TESTCASE_MODULES += testlpc TESTCASE_MODULES += $(if $(CONFIG_HTMGT),testhtmgt) +TESTCASE_MODULES += $(if $(CONFIG_AST2400), testsio) RUNTIME_OBJECTS += rt_start.o RUNTIME_OBJECTS += rt_main.o diff --git a/src/usr/console/HBconfig b/src/usr/console/HBconfig index e6b1ebda7..664febd86 100644 --- a/src/usr/console/HBconfig +++ b/src/usr/console/HBconfig @@ -1,4 +1,10 @@ config CONSOLE - default y if BMC_AST2400 + default y if (BMC_AST2400 || CONSOLE_DEFAULT_UART) help Enable console support. + +config CONSOLE_DEFAULT_UART + default n + depends on !BMC_AST2400 + help + Enable a default UART driver for the console. diff --git a/src/usr/console/ast2400.C b/src/usr/console/ast2400.C index 243c9bec1..c56bf02c4 100644 --- a/src/usr/console/ast2400.C +++ b/src/usr/console/ast2400.C @@ -22,6 +22,7 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ +#include <sio/sio.H> #include "uart.H" #include <devicefw/userif.H> #include <lpc/lpcif.H> @@ -32,19 +33,21 @@ namespace CONSOLE { - const uint32_t VUART1_BASE = 0x1E787000; - const uint32_t VUART1_GCTRLA = VUART1_BASE + 0x20; - const uint32_t VUART1_GCTRLB = VUART1_BASE + 0x24; - const uint32_t VUART1_ADDRL = VUART1_BASE + 0x28; - const uint32_t VUART1_ADDRH = VUART1_BASE + 0x2c; - - const uint8_t SERIAL_IRQ = 4; - - const uint8_t SIO_ADDR_REG_2E = 0x2E; - const uint8_t SIO_DATA_REG_2F = 0x2F; - - // used to test config flags related to console outup selection - const uint8_t CONFIG_MASK = 0xC0; + const uint32_t VUART1_BASE = 0x1E787000; + const uint32_t VUART1_GCTRLA = VUART1_BASE + 0x20; + const uint32_t VUART1_GCTRLB = VUART1_BASE + 0x24; + const uint32_t VUART1_ADDRL = VUART1_BASE + 0x28; + const uint32_t VUART1_ADDRH = VUART1_BASE + 0x2c; + + const uint8_t SERIAL_IRQ = 4; + + // Host SerlIRQ interrupt type for SUART1 + const uint8_t RESERVED = 0x00; + const uint8_t LOW_LEVEL_TRIG = 0x01; + const uint8_t RISING_EDGE_TRIG = 0x02; + const uint8_t HIGH_LEVEL_TRIG = 0x03; + // used to test config flags related to console output selection + const uint8_t CONFIG_MASK = 0xC0; /** Overload the base class with Ast2400 specifics. * @@ -53,7 +56,6 @@ namespace CONSOLE */ class Ast2400Uart : public Uart { - public: enum consoleConfig_t { @@ -64,205 +66,65 @@ namespace CONSOLE }; private: - // $TODO RTC:115576 remove these sio write functions when SIO dd code - // is completed - // Perform raw LPC writes to SIO region. - errlHndl_t _writeReg(uint8_t i_addr, uint8_t i_byte) - { - size_t len = sizeof(i_byte); - return deviceWrite(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, - &i_byte, - len, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO, i_addr)); - } - - // write i_data to register i_reg - errlHndl_t writeSIOReg( uint8_t i_reg, uint8_t i_data ) - { - errlHndl_t l_err = NULL; - - do{ - - l_err = _writeReg( SIO_ADDR_REG_2E, i_reg ); - - if(l_err) { break; } - - l_err = _writeReg( SIO_DATA_REG_2F, i_data ); - - }while(0); - - return l_err; - } - - // Perform reads from the SIO register region. - errlHndl_t readSIOReg(uint8_t i_reg, uint8_t &o_byte) - { - errlHndl_t l_err = NULL; - - size_t len = sizeof(o_byte); - - do{ - l_err = deviceWrite( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, - &i_reg, - len, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO_ADDR_REG_2E)); - - if(l_err) { break; } - - l_err = deviceRead( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, - &o_byte, - len, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO_DATA_REG_2F)); - }while(0); - - return l_err; - } - - // setup the AHB access - errlHndl_t ahbSioAddressPrep(uint32_t reg) - { - errlHndl_t l_err = NULL; - - do{ - // Select logical device D (LPC2AHB) - l_err = writeSIOReg( 0x07, 0x0D ); - if( l_err ) { break; } - - /* Enable iLPC->AHB */ - l_err = writeSIOReg( 0x30, 0x01 ); - if( l_err ) { break; } - - /* Address */ - l_err = writeSIOReg(0xF0, (reg >> 24) & 0xff); - if( l_err ) {break; } - - l_err = writeSIOReg(0xF1, (reg >> 16) & 0xff); - if( l_err ) {break; } - - l_err = writeSIOReg(0xF2, (reg >> 8) & 0xff); - if( l_err ) {break; } - - l_err = writeSIOReg(0xF3, (reg ) & 0xff); - if( l_err ) {break; } - - /* bytes per cycle type */ - l_err = writeSIOReg(0xF8, 0x02); - if( l_err ) {break; } - - }while(0); - - return l_err; - } - - errlHndl_t ahbSioWrite(uint32_t reg, uint32_t val ) - { - errlHndl_t l_err = NULL; - - do{ - - l_err = ahbSioAddressPrep( reg); - if( l_err ) { break; } - - /* Write data */ - l_err = writeSIOReg(0xF4, val >> 24); - if( l_err ) { break; } - l_err = writeSIOReg(0xF5, val >> 16); - if( l_err ) { break; } - l_err = writeSIOReg(0xF6, val >> 8); - if( l_err ) { break; } - l_err = writeSIOReg(0xF7, val); - if( l_err ) { break; } - - /* Trigger the write with the magic number */ - l_err = writeSIOReg(0xFe, 0xcf); - - }while(0); - - return l_err; - } - - errlHndl_t ahbSioRead( uint32_t reg, uint32_t &o_data ) - { - errlHndl_t l_err = NULL; - uint8_t tmp_data = 0; - o_data = 0; - - do{ - - l_err = ahbSioAddressPrep(reg); - if(l_err){break;} - - /* Trigger the read - ignore the output data */ - l_err = readSIOReg(0xFE, tmp_data); - if(l_err){break;} - - tmp_data = 0; - - /* Read results */ - l_err = readSIOReg(0xF4, tmp_data ); - if(l_err){;break;} - o_data = tmp_data; - - l_err = readSIOReg(0xF5, tmp_data ); - if(l_err){break;} - o_data = (o_data << 8) | tmp_data; - - l_err = readSIOReg(0xF6, tmp_data ); - if(l_err){break;} - o_data = (o_data << 8) | tmp_data; - - l_err = readSIOReg(0xF7, tmp_data ); - if(l_err){break;} - o_data = (o_data << 8) | tmp_data; - - }while(0); - - return l_err; - } - - private: - void initializeSUART() { errlHndl_t l_errl = NULL; - + uint8_t l_data; + size_t l_len = sizeof(uint8_t); do { - // Select logical device 2 (SUART1) in SI) - l_errl = writeSIOReg( 0x07, 0x02); - if (l_errl) { break; } - // Disable SUART1 to change settings - l_errl = writeSIOReg( 0x30, 0x00 ); + l_data = SIO::DISABLE_DEVICE; + l_errl = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::SUART1, 0x30)); if (l_errl) { break; } // Set SUART1 addr to g_uartBase - l_errl = writeSIOReg( 0x60, (g_uartBase >> 8) & 0xFF ); + l_data =(g_uartBase >> 8) & 0xFF; + l_errl = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::SUART1, 0x60)); if (l_errl) { break; } - l_errl = writeSIOReg( 0x61, (g_uartBase & 0xFF) ); + l_data = g_uartBase & 0xFF; + l_errl = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::SUART1, 0x61)); if (l_errl) { break; } // Set the SerIRQ - l_errl = writeSIOReg( 0x70, SERIAL_IRQ ); + l_data = SERIAL_IRQ; + l_errl = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::SUART1, 0x70)); if (l_errl) { break; } - l_errl = writeSIOReg( 0x71, 0x01 ); + l_data = LOW_LEVEL_TRIG; + l_errl = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::SUART1, 0x71)); if (l_errl) { break; } - // Enable SUART1 - l_errl = writeSIOReg( 0x30, 0x01 ); // select SIO base enable + l_data = SIO::ENABLE_DEVICE; + l_errl = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::SUART1, 0x30)); if (l_errl) { break; } - //@fixme-RTC:115576 - Leaving SIO unlocked for now to allow - // PNOR write/erase to work - // Lock the SIO registers - //l_errl = _writeReg( 0x2e, 0xAA ); - //if (l_errl) { break; } - } while(0); if (l_errl) @@ -279,29 +141,66 @@ namespace CONSOLE { errlHndl_t l_err = NULL; - do{ + do + { uint32_t v; - + size_t l_len = sizeof(v); + /* Enable device 0x0D*/ + uint8_t l_data = SIO::ENABLE_DEVICE; + l_err = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + (&l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::iLPC2AHB,0x30)); + if(l_err) { break; } /* configure IRQ level as low */ - l_err = ahbSioRead(VUART1_GCTRLA, v); + l_err = deviceOp( DeviceFW::READ, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(v), + l_len, + DEVICE_AHB_SIO_ADDRESS(VUART1_GCTRLA)); if(l_err){break;} v = v & ~2u; - l_err = ahbSioWrite(VUART1_GCTRLA, v); + l_err = deviceOp(DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(v), + l_len, + DEVICE_AHB_SIO_ADDRESS(VUART1_GCTRLA)); + if(l_err){break;} /* configure the IRQ number */ - l_err = ahbSioRead(VUART1_GCTRLB, v); + l_err = deviceOp( DeviceFW::READ, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(v), + l_len, + DEVICE_AHB_SIO_ADDRESS(VUART1_GCTRLB)); if(l_err){break;} v = (v & ~0xf0u) | ((SERIAL_IRQ << 4)); - l_err = ahbSioWrite(VUART1_GCTRLB,v); + l_err = deviceOp(DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(v), + l_len, + DEVICE_AHB_SIO_ADDRESS(VUART1_GCTRLB)); if(l_err){break;} /* configure the address */ - l_err = ahbSioWrite(VUART1_ADDRL, g_uartBase & 0xff); + v = g_uartBase & 0xff; + l_err = deviceOp(DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(v), + l_len, + DEVICE_AHB_SIO_ADDRESS(VUART1_ADDRL)); if(l_err){break;} - l_err = ahbSioWrite(VUART1_ADDRH, g_uartBase >> 8); + v = g_uartBase >> 8; + l_err = deviceOp(DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(v), + l_len, + DEVICE_AHB_SIO_ADDRESS(VUART1_ADDRH)); + if(l_err){break;} }while(0); @@ -323,21 +222,29 @@ namespace CONSOLE { errlHndl_t l_err = NULL; - do{ + do + { // read the control reg, mask off the enabled bit // and write it back uint32_t reg_value = 0; + size_t l_len = sizeof(reg_value); + l_err = deviceOp(DeviceFW::READ, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(reg_value), + l_len, + DEVICE_AHB_SIO_ADDRESS(VUART1_GCTRLA)); - l_err = ahbSioRead(VUART1_GCTRLA, reg_value ); if(l_err){break;} // mask off the low order bit to mark the vuart as disabled reg_value &= 0xFE; - l_err = ahbSioWrite(VUART1_GCTRLA, reg_value ); + l_err = deviceOp(DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(reg_value), + l_len, + DEVICE_AHB_SIO_ADDRESS(VUART1_GCTRLA)); if(l_err){break;} - - }while(0); if (l_err) @@ -350,14 +257,16 @@ namespace CONSOLE { errlHndl_t l_err = NULL; - do{ - - // select device 2 - UART1 - l_err = writeSIOReg(0x07, 0x02); - if(l_err){break;} - + do + { // clear the uart enable from base ctl reg - l_err = writeSIOReg(0x30, 0); + uint8_t l_data = SIO::DISABLE_DEVICE; + size_t l_len = sizeof(uint8_t); + l_err = deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::SUART1, 0x30)); }while(0); @@ -367,54 +276,36 @@ namespace CONSOLE } }; - virtual void unlockSIO() - { - errlHndl_t l_err = NULL; - do{ - // Unlock the SIO registers - // (write 0xA5 password to offset 0x2E two times) - l_err = _writeReg( SIO_ADDR_REG_2E, 0xA5 ); - if (l_err) { break; } - - l_err = _writeReg( SIO_ADDR_REG_2E, 0xA5 ); - - }while(0); - - if (l_err) - { - errlCommit(l_err, CONSOLE_COMP_ID); - } - - } - - public: + public: virtual void initialize() { // read the SIO register set by the BMC to determine uart config const uint8_t expected_version = INITSERVICE::BOOTCONFIG::BOOT_FLAGS_VERSION_1; - uint8_t this_version = 0x00; errlHndl_t l_err = NULL; - + size_t l_len = sizeof(uint8_t); uint8_t uart_config = 0x00; - do{ - // allow access to the registers - unlockSIO(); - + do + { // verify the boot flags version from register 0x28 - l_err = readSIOReg( 0x28, this_version ); - + l_err = deviceOp( DeviceFW::READ, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(this_version), + l_len, + DEVICE_SIO_ADDRESS(SIO::SUART1, 0x28)); if (l_err) { break; } - // is it the version we expected? if( expected_version == this_version ) { - l_err = readSIOReg(0x2d, uart_config); - + l_err = deviceOp( DeviceFW::READ, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(uart_config), + l_len, + DEVICE_SIO_ADDRESS(SIO::SUART1, 0x2d)); if (l_err) { break; } // determine which config has been selected diff --git a/src/usr/initservice/bootconfig/bootconfig_ast2400.C b/src/usr/initservice/bootconfig/bootconfig_ast2400.C index 56f6c8500..25eba8685 100644 --- a/src/usr/initservice/bootconfig/bootconfig_ast2400.C +++ b/src/usr/initservice/bootconfig/bootconfig_ast2400.C @@ -26,6 +26,7 @@ // Includes /******************************************************************************/ #include "bootconfig_ast2400.H" + #include <lpc/lpcif.H> #include <devicefw/userif.H> #include <errl/errlentry.H> @@ -33,6 +34,8 @@ #include <hwas/common/deconfigGard.H> #include <console/consoleif.H> #include <config.h> +#include <sio/sio.H> +#include <devicefw/driverif.H> namespace INITSERVICE { @@ -181,22 +184,21 @@ errlHndl_t AST2400BootConfig::readAndProcessBootConfig() errlHndl_t l_err = NULL; uint8_t register_data = 0; - - do{ - - l_err = unlockSIORegisters(); - - if(l_err) - { - TRACFCOMP(g_bc_trace, "readAndProcessBootConfig()" - " call to unlock SIO registers failed"); - break; - } - + size_t l_len = sizeof(uint8_t); + do + { // read the register holding the agreed upon magic // number to indicate registers have been configured - l_err = readSIORegister( BOOT_FLAGS_VERSION_REG, register_data ); + // Registers below 0x30 do not belong to any particular SIO device. + // Device field advised to be set to SUART1 or iLPC2AHB as these are the + // only two devices currently in use and will thereby save additional + // SIO before and after this call. + l_err = deviceOp( DeviceFW::READ, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(register_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::DONT_CARE, BOOT_FLAGS_VERSION_REG)); if( l_err ) { TRACFCOMP(g_bc_trace,"Failed reading the boot flags version, skip processing"); @@ -219,8 +221,11 @@ errlHndl_t AST2400BootConfig::readAndProcessBootConfig() } // read the SIO register holding the boot flags - l_err = readSIORegister( BOOT_FLAGS_REG, register_data ); - + l_err = deviceOp( DeviceFW::READ, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(register_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::DONT_CARE, BOOT_FLAGS_REG)); if( l_err ) { TRACFCOMP(g_bc_trace,"Failed reading the boot flags, leave" @@ -233,9 +238,6 @@ errlHndl_t AST2400BootConfig::readAndProcessBootConfig() }while(0); - // leave SIO registers unlocked, pnor code is dependant on - // having access to them - TRACDCOMP(g_bc_trace, EXIT_MRK"readAndProcessBootConfig()"); return l_err; @@ -259,20 +261,31 @@ void AST2400BootConfig::processBootFlagsV1( uint8_t i_flags ) errlHndl_t AST2400BootConfig::readIstepControl( istepControl_t &o_stepInfo ) { errlHndl_t l_err = NULL; - + size_t l_len = sizeof(uint8_t); do { // read istep control from 0x2a - l_err = readSIORegister( ISTEP_CONTROL_REG, o_stepInfo.istepControl ); - - if(l_err) break; + l_err = deviceOp( DeviceFW::READ, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(o_stepInfo.istepControl), + l_len, + DEVICE_SIO_ADDRESS(SIO::DONT_CARE, ISTEP_CONTROL_REG)); + if(l_err) { break; } // read major number from 0x2b - l_err = readSIORegister( ISTEP_MAJOR_REG, o_stepInfo.istepMajorNumber ); - if(l_err) break; + l_err = deviceOp( DeviceFW::READ, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(o_stepInfo.istepMajorNumber), + l_len, + DEVICE_SIO_ADDRESS(SIO::DONT_CARE, ISTEP_MAJOR_REG)); + if(l_err) { break; } // read minor number from 0x2c - l_err = readSIORegister( ISTEP_MINOR_REG, o_stepInfo.istepMinorNumber ); + l_err = deviceOp( DeviceFW::READ, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(o_stepInfo.istepMinorNumber), + l_len, + DEVICE_SIO_ADDRESS(SIO::DONT_CARE, ISTEP_MINOR_REG)); } while(0); @@ -280,115 +293,5 @@ errlHndl_t AST2400BootConfig::readIstepControl( istepControl_t &o_stepInfo ) } -// $TODO RTC:115576 remove these functions -errlHndl_t AST2400BootConfig::readSIORegister( uint8_t i_addr, - uint8_t &o_data ) -{ - - errlHndl_t l_err = NULL; - - o_data = 0; - - size_t length = sizeof(o_data); - - // write the value of the read register - l_err = deviceWrite( TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, - &i_addr, - length, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO_ADDR_REG)); - - if( l_err == NULL ) - { - - // get the register contents. - l_err = deviceRead( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, - (void *)&o_data, - length, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO_DATA_REG)); - } - - return l_err; - -} - -// $TODO RTC:115576 remove these function -errlHndl_t AST2400BootConfig::writeSIORegister( uint8_t i_addr, - uint8_t i_data ) -{ - - size_t length = sizeof(i_data); - - errlHndl_t l_err = NULL; - - l_err = deviceWrite( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, - &i_addr, - length, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO_ADDR_REG )); - - if( l_err == NULL ) - { - l_err = deviceWrite( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, - &i_data, - length, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO, SIO_DATA_REG )); - } - - return l_err; -} - -// $TODO RTC:115576 remove these function -errlHndl_t AST2400BootConfig::unlockSIORegisters() -{ - errlHndl_t l_err = NULL; - uint8_t key = SIO_REG_UNLOCK_KEY; - size_t length = sizeof(key); - - do { - - // Write out the register address - l_err = deviceWrite( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, - &key, - length, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_ADDR_REG) ); - - if(l_err) break; - - // Write out the register address - l_err = deviceWrite( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, - &key, - length, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_ADDR_REG) ); - - }while(0); - - return l_err; -} - -// $TODO RTC:115576 remove these function -void AST2400BootConfig::lockSIORegisters() -{ - // write the data to lock it back up.. - uint8_t key = SIO_REG_LOCK_KEY; - size_t length = sizeof(uint8_t); - - // Write out the register address - errlHndl_t l_err = deviceWrite( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, - &key, - length, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_ADDR_REG) ); - - if(l_err) - { - TRACFCOMP(g_bc_trace, "FAILED locking SIO registers"); - errlCommit(l_err, ISTEP_COMP_ID); - } -} - }; }; diff --git a/src/usr/initservice/bootconfig/bootconfig_ast2400.H b/src/usr/initservice/bootconfig/bootconfig_ast2400.H index 68c46149f..d11ae2c26 100644 --- a/src/usr/initservice/bootconfig/bootconfig_ast2400.H +++ b/src/usr/initservice/bootconfig/bootconfig_ast2400.H @@ -191,39 +191,6 @@ public: */ void processBootFlagsV1( uint8_t i_flags ); - // $TODO RTC:115576 remove these temporary SIO related functions - /** - * @brief read a byte from an SIO register - * - * @param[i] i_addr - address of SIO register to read - * @param[o] o_data - SIO register contents - * - * @return errlHndl_t - */ - errlHndl_t readSIORegister( uint8_t i_addr, uint8_t ®ister_value ); - - /** - * @brief Write a byte to an SIO register - * - * @param[i] i_addr - address of SIO register to write - * @param[i] i_data - SIO register contents - * - * @return errlHndl_t - */ - errlHndl_t writeSIORegister( uint8_t i_addr, uint8_t i_data ); - - /** - * @brief Allow read/write access to the SIO registers - * - * @return errlHndl_t - */ - errlHndl_t unlockSIORegisters(); - - /** - * @brief Lock the SIO registers - */ - void lockSIORegisters(); - }; }; diff --git a/src/usr/makefile b/src/usr/makefile index a56abd3f7..d71b4b73c 100644 --- a/src/usr/makefile +++ b/src/usr/makefile @@ -5,7 +5,7 @@ # # OpenPOWER HostBoot Project # -# Contributors Listed Below - COPYRIGHT 2010,2014 +# Contributors Listed Below - COPYRIGHT 2010,2015 # [+] Google Inc. # [+] International Business Machines Corp. # @@ -29,6 +29,7 @@ ROOTPATH = ../.. HOSTBOOT_PROFILE_NO_INSTRUMENT = 1 OBJS += module_init.o +SUBDIRS += sio.d SUBDIRS += trace.d SUBDIRS += cxxtest.d SUBDIRS += testcore.d diff --git a/src/usr/pnor/sfc_ast2400.C b/src/usr/pnor/sfc_ast2400.C index 8ceb391cc..14d01bfba 100644 --- a/src/usr/pnor/sfc_ast2400.C +++ b/src/usr/pnor/sfc_ast2400.C @@ -26,6 +26,7 @@ /*****************************************************************************/ // I n c l u d e s /*****************************************************************************/ +#include <sio/sio.H> #include <sys/mmio.h> #include <sys/task.h> #include <sys/sync.h> @@ -50,22 +51,16 @@ /*****************************************************************************/ - - /*****************************************************************************/ // G l o b a l s /*****************************************************************************/ // Initialized in pnorrp.C extern trace_desc_t* g_trac_pnor; - /*****************************************************************************/ // M e t h o d s /*****************************************************************************/ - - namespace PNOR { - /** * @brief Wrapper for device driver constructor */ @@ -89,7 +84,6 @@ SfcAST2400::SfcAST2400( errlHndl_t& o_err, { } - /** * @brief Read data from the flash */ @@ -99,8 +93,8 @@ errlHndl_t SfcAST2400::readFlash( uint32_t i_addr, { errlHndl_t l_err = NULL; TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::readFlash> i_addr=0x%.8x, i_size=0x%.8x", i_addr, i_size ); - - do{ + do + { uint32_t* word_ptr = static_cast<uint32_t*>(o_data); uint32_t word_size = (ALIGN_4(i_size))/4; for( uint32_t words_read = 0; @@ -120,8 +114,8 @@ errlHndl_t SfcAST2400::readFlash( uint32_t i_addr, lpc_addr) ); if( l_err ) { break; } } - if( l_err ) { break; } - }while(0); + if( l_err ) { break; } + } while(0); TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::readFlash> err=%.8X", ERRL_GETEID_SAFE(l_err) ); return l_err; @@ -228,6 +222,28 @@ errlHndl_t SfcAST2400::eraseFlash( uint32_t i_addr ) return l_err; } +//function to call SIO dd for ahb sio read +errlHndl_t ahbSioReadWrapper(uint32_t i_ahb_sio_data, uint32_t i_lpc_addr) +{ + size_t l_ahb_sio_len = sizeof(i_ahb_sio_data); + return deviceOp( DeviceFW::READ, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(i_ahb_sio_data), + l_ahb_sio_len, + DEVICE_AHB_SIO_ADDRESS(i_lpc_addr)); +} + +//function to call SIO dd for ahb sio write +errlHndl_t ahbSioWriteWrapper(uint32_t i_ahb_sio_data, uint32_t i_lpc_addr) +{ + size_t l_ahb_sio_len = sizeof(i_ahb_sio_data); + return deviceOp( DeviceFW::WRITE, + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + &(i_ahb_sio_data), + l_ahb_sio_len, + DEVICE_AHB_SIO_ADDRESS(i_lpc_addr)); +} + /** * @brief Initialize and configure the SFC hardware */ @@ -235,55 +251,38 @@ errlHndl_t SfcAST2400::hwInit( ) { TRACFCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::hwInit>" ); errlHndl_t l_err = NULL; - - do { - size_t reg_size = sizeof(uint8_t); - - //** Initialize the LPC2AHB logic - - // Send SuperIO password - send A5 twice - uint8_t data = 0xA5; - l_err = deviceOp( DeviceFW::WRITE, - iv_proc, - &data, - reg_size, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_ADDR_2E) ); - if( l_err ) { break; } - + uint32_t l_lpc_addr; + do + { + /* Enable device 0x0D*/ + uint8_t l_data = SIO::ENABLE_DEVICE; + size_t l_len = sizeof(l_data); l_err = deviceOp( DeviceFW::WRITE, - iv_proc, - &data, - reg_size, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_ADDR_2E) ); - if( l_err ) { break; } - - - // Select logical device D (iLPC2AHB) - l_err = writeRegSIO( 0x07, 0x0D ); - if( l_err ) { break; } - - - // Enable iLPC->AHB - l_err = writeRegSIO( 0x30, 0x01 ); - if( l_err ) { break; } - - + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + (&l_data), + l_len, + DEVICE_SIO_ADDRESS(SIO::iLPC2AHB,0x30)); + if(l_err) { break; } //** Setup the SPI Controller /* Enable writing to the controller */ SpiControlReg04_t ctlreg; - l_err = readRegSPIC( CTLREG_04, ctlreg.data32 ); + l_lpc_addr = CTLREG_04 | SPIC_BASE_ADDR_AHB; + l_err = ahbSioReadWrapper(ctlreg.data32, l_lpc_addr); if( l_err ) { break; } + ctlreg.cmdMode = 0b10; //10:Normal Write (CMD + Address + Write data) - l_err = writeRegSPIC( CTLREG_04, ctlreg.data32 ); + l_err = ahbSioWriteWrapper(ctlreg.data32, l_lpc_addr); if( l_err ) { break; } SpiConfigReg00_t confreg; - l_err = readRegSPIC( CONFREG_00, confreg.data32 ); + l_lpc_addr = CONFREG_00 | SPIC_BASE_ADDR_AHB; + l_err = ahbSioReadWrapper(confreg.data32, l_lpc_addr); if( l_err ) { break; } + confreg.inactiveX2mode = 1; //Enable CE# Inactive pulse width X2 mode confreg.enableWrite = 1; //Enable flash memory write - l_err = writeRegSPIC( CONFREG_00, confreg.data32 ); + l_err = ahbSioWriteWrapper(confreg.data32, l_lpc_addr); if( l_err ) { break; } @@ -305,7 +304,8 @@ errlHndl_t SfcAST2400::hwInit( ) iv_ctlRegDefault = ctlreg; // Default setup is regular read mode // Configure for read - l_err = writeRegSPIC( CTLREG_04, ctlreg.data32 ); + l_lpc_addr = CTLREG_04 | SPIC_BASE_ADDR_AHB; + l_err = ahbSioWriteWrapper(ctlreg.data32, l_lpc_addr); if( l_err ) { break; } // Figure out what flash chip we have @@ -482,6 +482,7 @@ errlHndl_t SfcAST2400::sendSpiCmd( uint8_t i_opCode, errlHndl_t SfcAST2400::commandMode( bool i_enter ) { errlHndl_t l_err = NULL; + uint32_t l_lpc_addr; TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::commandMode(%d)", i_enter ); /* @@ -503,20 +504,21 @@ errlHndl_t SfcAST2400::commandMode( bool i_enter ) // Switch to user mode, CE# dropped ctlreg.stopActiveCtl = 1; ctlreg.cmdMode = 0b11; //User Mode (Read/Write Data) - l_err = writeRegSPIC( CTLREG_04, ctlreg.data32 ); + l_lpc_addr = CTLREG_04 | SPIC_BASE_ADDR_AHB; + l_err = ahbSioWriteWrapper(ctlreg.data32, l_lpc_addr); if( l_err ) { break; } if( i_enter ) //ast_sf_start_cmd { // user mode, CE# active ctlreg.stopActiveCtl = 0; - l_err = writeRegSPIC( CTLREG_04, ctlreg.data32 ); + l_err = ahbSioWriteWrapper(ctlreg.data32, l_lpc_addr); if( l_err ) { break; } } else //ast_sf_end_cmd { // Switch back to read mode - l_err = writeRegSPIC( CTLREG_04, iv_ctlRegDefault.data32 ); + l_err = ahbSioWriteWrapper(iv_ctlRegDefault.data32, l_lpc_addr); if( l_err ) { break; } } } while(0); @@ -587,187 +589,6 @@ errlHndl_t SfcAST2400::enableWriteMode( void ) } /** - * @brief Write a single byte into the SIO - */ -errlHndl_t SfcAST2400::writeRegSIO( uint8_t i_regAddr, - uint8_t i_data ) -{ //lpc_sio_outb - errlHndl_t l_err = NULL; - TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::writeRegSIO> i_regAddr=0x%.2X, i_data=0x%.2X", i_regAddr, i_data ); - - do { - size_t reg_size = sizeof(uint8_t); - - // AST2400 integrates a Super I/O module with - // LPC protocol (I/O cycle 0x2E/0x2F) - - // Write out the register address - l_err = deviceOp( DeviceFW::WRITE, - iv_proc, - &i_regAddr, - reg_size, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_ADDR_2E) ); - if( l_err ) { break; } - - // Write out the register data - l_err = deviceOp( DeviceFW::WRITE, - iv_proc, - &i_data, - reg_size, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_DATA_2F) ); - if( l_err ) { break; } - - } while(0); - - TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::writeRegSIO> err=%.8X", ERRL_GETEID_SAFE(l_err) ); - return l_err; -} - -/** - * @brief Read a single byte from the SIO - */ -errlHndl_t SfcAST2400::readRegSIO( uint8_t i_regAddr, - uint8_t& o_data ) -{ //lpc_sio_inb - errlHndl_t l_err = NULL; - TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::readRegSIO> i_regAddr=0x%.2X", i_regAddr ); - - do { - size_t reg_size = sizeof(uint8_t); - - // AST2400 integrates a Super I/O module with - // LPC protocol (I/O cycle 0x2E/0x2F) - - // Write out the register address - l_err = deviceOp( DeviceFW::WRITE, - iv_proc, - &i_regAddr, - reg_size, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_ADDR_2E) ); - if( l_err ) { break; } - - // Read in the register data - l_err = deviceOp( DeviceFW::READ, - iv_proc, - &o_data, - reg_size, - DEVICE_LPC_ADDRESS(LPC::TRANS_IO,SIO_DATA_2F) ); - if( l_err ) { break; } - - } while(0); - - TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::readRegSIO> o_data=0x%.2X, err-%.8X", o_data, ERRL_GETEID_SAFE(l_err) ); - return l_err; -} - -/** - * @brief Prepare the iLPC2AHB address regs - */ -errlHndl_t SfcAST2400::setupAddrLPC2AHB( uint32_t i_addr ) -{ //lpc_ahb_prep - errlHndl_t l_err = NULL; - TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::setupAddrLPC2AHB> i_addr=0x%X", i_addr ); - - do { - // Select logical device D (iLPC2AHB) - l_err = writeRegSIO( 0x07, 0x0D ); - if( l_err ) { break; } - - // Push 4 address bytes into SIO regs 0xF0-0xF3 - for( size_t i=sizeof(i_addr); i>0; i-- ) - { - l_err = writeRegSIO( 0xF3-(i-1), //F0,F1,F2,F3 - static_cast<uint8_t>(i_addr >> ((i-1)*8)) ); - if( l_err ) { break; } - } - if( l_err ) { break; } - - // Configure 4 byte length - l_err = writeRegSIO( 0xF8, 0x02 ); - if( l_err ) { break; } - - } while(0); - - TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::setupAddrLPC2AHB> err=%.8X", ERRL_GETEID_SAFE(l_err) ); - return l_err; -} - -/** - * @brief Write SPI Controller Register - */ -errlHndl_t SfcAST2400::writeRegSPIC( SpicReg_t i_reg, - uint32_t i_data ) -{ - errlHndl_t l_err = NULL; - TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::writeRegSPIC> i_reg=0x%.2X, i_data=0x%.8X", i_reg, i_data ); - - do { - // Compute the full LPC address - uint32_t lpc_addr = i_reg | SPIC_BASE_ADDR_AHB; - - // Setup the logic for the write - l_err = setupAddrLPC2AHB( lpc_addr ); - if( l_err ) { break; } - - // Push 4 data bytes into SIO regs 0xF4-0xF7 - uint8_t* ptr8 = reinterpret_cast<uint8_t*>(&i_data); - for( size_t i=0; i<sizeof(i_data); i++ ) - { - l_err = writeRegSIO( 0xF4+i, //F4,F5,F6,F7 - ptr8[i] ); - if( l_err ) { break; } - } - if( l_err ) { break; } - - // Trigger the write operation by writing the magic 0xCF value - l_err = writeRegSIO( 0xFE, 0xCF ); - if( l_err ) { break; } - - } while(0); - - TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::writeRegSPIC> err=%.8X", ERRL_GETEID_SAFE(l_err) ); - return l_err; -} - -/** - * @brief Read SPI Controller Register - */ -errlHndl_t SfcAST2400::readRegSPIC( SpicReg_t i_reg, - uint32_t& o_data ) -{ - TRACDCOMP( g_trac_pnor, ENTER_MRK"SfcAST2400::readRegSPIC> i_reg=0x%.2X", i_reg ); - errlHndl_t l_err = NULL; - - do { - // Compute the full LPC address - uint32_t lpc_addr = i_reg | SPIC_BASE_ADDR_AHB; - - // Setup the logic for the write - l_err = setupAddrLPC2AHB( lpc_addr ); - if( l_err ) { break; } - - // Trigger the write operation by reading the magic register - uint8_t ignored = 0; - l_err = readRegSIO( 0xFE, ignored ); - if( l_err ) { break; } - - // Read 4 data bytes into SIO regs 0xF4-0xF7 - uint8_t* ptr8 = reinterpret_cast<uint8_t*>(&o_data); - for( size_t i=0; i<sizeof(o_data); i++ ) - { - l_err = readRegSIO( 0xF4+i, //F4,F5,F6,F7 - ptr8[i] ); - if( l_err ) { break; } - } - if( l_err ) { break; } - - } while(0); - - TRACDCOMP( g_trac_pnor, EXIT_MRK"SfcAST2400::readRegSPIC> o_data=0x%.8X, l_err=%.8X", o_data, ERRL_GETEID_SAFE(l_err) ); - return l_err; -} - -/** * @brief Poll for completion of SPI operation */ errlHndl_t SfcAST2400::pollOpComplete( void ) diff --git a/src/usr/pnor/sfc_ast2400.H b/src/usr/pnor/sfc_ast2400.H index 79d18c1ba..28719425e 100644 --- a/src/usr/pnor/sfc_ast2400.H +++ b/src/usr/pnor/sfc_ast2400.H @@ -138,50 +138,6 @@ class SfcAST2400 : public SfcDD }; /** - * @brief Write a SPI Controller register - * - * @param[in] i_reg: Register to write - * @param[in] i_data: Data to write - * - * @return Error from operation - */ - errlHndl_t writeRegSPIC( SpicReg_t i_reg, - uint32_t i_data ); - - /** - * @brief Write a SPI Controller register - * - * @param[in] i_reg: Register to write - * @param[in] o_data: Data that was read - * - * @return Error from operation - */ - errlHndl_t readRegSPIC( SpicReg_t i_reg, - uint32_t& o_data ); - - /** - * @brief Write a single byte into a SIO register - * - * @param[in] i_reg: Register to write - * @param[in] i_data: Data to write - * - * @return Error from operation - */ - errlHndl_t writeRegSIO( uint8_t i_regAddr, - uint8_t i_data ); - - /** - * @brief Read a single byte from a SIO register - * - * @param[in] i_reg: Register to read - * @param[in] o_data: Data that was read - * - * @return Error from operation - */ - errlHndl_t readRegSIO( uint8_t i_regAddr, - uint8_t& o_data ); - - /** * @brief Enable write mode * * @return Error from operation diff --git a/src/usr/pnor/test/sfc_ast2400test.H b/src/usr/pnor/test/sfc_ast2400test.H index 4dc69e68e..70e0d340b 100644 --- a/src/usr/pnor/test/sfc_ast2400test.H +++ b/src/usr/pnor/test/sfc_ast2400test.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2014 */ +/* Contributors Listed Below - COPYRIGHT 2014,2015 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -42,6 +42,7 @@ #include <targeting/common/attributes.H> #include <lpc/lpcif.H> #include "../sfc_ast2400.H" +#include <sio/sio.H> extern trace_desc_t* g_trac_pnor; @@ -92,8 +93,8 @@ class SfcAST2400Test : public CxxTest::TestSuite section_found = true; }while(0); - return section_found; + } /** @@ -167,139 +168,6 @@ class SfcAST2400Test : public CxxTest::TestSuite } } - /** - * @brief Test SIO access - * Use a SIO scratch register to verify reads and writes - */ - void test_SIO(void) - { - SfcAST2400* sfc = reinterpret_cast<SfcAST2400*>( - Singleton<PnorDD>::instance().iv_sfc ); - errlHndl_t l_err = NULL; - - // Read SIO to BMC scratch reg 1,2 and save off values - uint8_t scratch1 = 0; - l_err = sfc->readRegSIO( 0x21, scratch1 ); - if( l_err ) - { - TS_FAIL("SfcAST2400Test::test_SIO> readRegSIO failed"); - errlCommit(l_err,PNOR_COMP_ID); - } - uint8_t scratch2 = 0; - l_err = sfc->readRegSIO( 0x22, scratch2 ); - if( l_err ) - { - TS_FAIL("SfcAST2400Test::test_SIO> readRegSIO failed"); - errlCommit(l_err,PNOR_COMP_ID); - } - - // Write test patterns into registers - uint8_t testdata = 0xA5; - l_err = sfc->writeRegSIO( 0x21, testdata ); - if( l_err ) - { - TS_FAIL("SfcAST2400Test::test_SIO> writeRegSIO failed"); - errlCommit(l_err,PNOR_COMP_ID); - } - testdata = 0x12; - l_err = sfc->writeRegSIO( 0x22, testdata ); - if( l_err ) - { - TS_FAIL("SfcAST2400Test::test_SIO> writeRegSIO failed"); - errlCommit(l_err,PNOR_COMP_ID); - } - - // Read the data back and compare to expected results - l_err = sfc->readRegSIO( 0x21, testdata ); - if( l_err ) - { - TS_FAIL("SfcAST2400Test::test_SIO> readRegSIO failed"); - errlCommit(l_err,PNOR_COMP_ID); - } - if( testdata != 0xA5 ) - { - TS_FAIL("SfcAST2400Test::test_SIO> Data mismatch on SIO 0x21 : Exp=0xA5, Act=%.2X", testdata); - } - l_err = sfc->readRegSIO( 0x22, testdata ); - if( l_err ) - { - TS_FAIL("SfcAST2400Test::test_SIO> readRegSIO failed"); - errlCommit(l_err,PNOR_COMP_ID); - } - if( testdata != 0x12 ) - { - TS_FAIL("SfcAST2400Test::test_SIO> Data mismatch on SIO 0x22 : Exp=0x12, Act=%.2X", testdata); - } - - // Restore the original data - l_err = sfc->writeRegSIO( 0x21, scratch1 ); - if( l_err ) - { - TS_FAIL("SfcAST2400Test::test_SIO> writeRegSIO failed"); - errlCommit(l_err,PNOR_COMP_ID); - } - l_err = sfc->writeRegSIO( 0x22, scratch2 ); - if( l_err ) - { - TS_FAIL("SfcAST2400Test::test_SIO> writeRegSIO failed"); - errlCommit(l_err,PNOR_COMP_ID); - } - } - - /** - * @brief Test SPIC access - * Read and write data to the SPI Control register - */ - void test_SPIC( void ) - { - SfcAST2400* sfc = reinterpret_cast<SfcAST2400*>( - Singleton<PnorDD>::instance().iv_sfc ); - mutex_t* l_mutex = Singleton<PnorDD>::instance().iv_mutex_ptr; - errlHndl_t l_err = NULL; - - mutex_lock(l_mutex); - - uint32_t first = 0; - l_err = sfc->readRegSPIC( SfcAST2400::CTLREG_04, first ); - if( l_err ) - { - TS_FAIL("SfcAST2400Test::test_SPIC> readRegSIO failed"); - mutex_unlock(l_mutex);//unlock before commit - errlCommit(l_err,PNOR_COMP_ID); - mutex_lock(l_mutex);//lock again for next op - } - uint32_t data1 = 0x12345678; - l_err = sfc->writeRegSPIC( SfcAST2400::CTLREG_04, data1 ); - if( l_err ) - { - TS_FAIL("SfcAST2400Test::test_SPIC> readRegSIO failed"); - mutex_unlock(l_mutex);//unlock before commit - errlCommit(l_err,PNOR_COMP_ID); - mutex_lock(l_mutex);//lock again for next op - } - l_err = sfc->readRegSPIC( SfcAST2400::CTLREG_04, data1 ); - if( l_err ) - { - TS_FAIL("SfcAST2400Test::test_SPIC> readRegSIO failed"); - mutex_unlock(l_mutex);//unlock before commit - errlCommit(l_err,PNOR_COMP_ID); - mutex_lock(l_mutex);//lock again for next op - } - if( data1 != 0x12345678 ) - { - TS_FAIL("SfcAST2400Test::test_SPIC> Unexpected result of %.8X (exp 0x12345678)",data1); - } - //put back the original - l_err = sfc->writeRegSPIC( SfcAST2400::CTLREG_04, first ); - if( l_err ) - { - TS_FAIL("SfcAST2400Test::test_SPIC> readRegSIO failed"); - mutex_unlock(l_mutex);//unlock before commit - errlCommit(l_err,PNOR_COMP_ID); - } - - mutex_unlock(l_mutex); - } }; #endif 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 |

