diff options
author | Mike Baiocchi <mbaiocch@us.ibm.com> | 2019-09-12 11:12:10 -0500 |
---|---|---|
committer | Nicholas E Bofferding <bofferdn@us.ibm.com> | 2019-11-14 08:27:53 -0600 |
commit | eace166aa1ef265712798d84f10782f7bc430be7 (patch) | |
tree | 10678b057c02cfe810662f1af04370c3fb1293cd /src/usr | |
parent | 0247cc5fbda6733f8006e8cda36abb153f0c0227 (diff) | |
download | talos-hostboot-eace166aa1ef265712798d84f10782f7bc430be7.tar.gz talos-hostboot-eace166aa1ef265712798d84f10782f7bc430be7.zip |
Support GPIO Physical Presence Detect Devices
This commit makes the necessary changes to support the GPIO devices
used for physical presence detection:
- New attribute GPIO_INFO_PHYS_PRES
- Enable GPIO Device Driver by default
- GPIO Device Driver updated to support new device type
- Added new GPIO PCA9551 layer to sit on top of GPIO Device Driver
Change-Id: I952007503eb5d9fe873adea2eaaeccff21ae18a6
RTC:211220
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/84655
Reviewed-by: Ilya Smirnov <ismirno@us.ibm.com>
Reviewed-by: Christopher J Engel <cjengel@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Nicholas E Bofferding <bofferdn@us.ibm.com>
Diffstat (limited to 'src/usr')
-rw-r--r-- | src/usr/gpio/HBconfig | 2 | ||||
-rw-r--r-- | src/usr/gpio/gpio_pca9551.C | 343 | ||||
-rw-r--r-- | src/usr/gpio/gpiodd.C | 57 | ||||
-rw-r--r-- | src/usr/gpio/makefile | 4 | ||||
-rwxr-xr-x | src/usr/targeting/common/xmltohb/attribute_types_hb.xml | 72 | ||||
-rw-r--r-- | src/usr/targeting/common/xmltohb/target_types_hb.xml | 3 |
6 files changed, 465 insertions, 16 deletions
diff --git a/src/usr/gpio/HBconfig b/src/usr/gpio/HBconfig index e5f650eb9..20ed72dd0 100644 --- a/src/usr/gpio/HBconfig +++ b/src/usr/gpio/HBconfig @@ -1,4 +1,4 @@ config GPIODD - default n + default y help Enable GPIO device driver support diff --git a/src/usr/gpio/gpio_pca9551.C b/src/usr/gpio/gpio_pca9551.C new file mode 100644 index 000000000..2bc4b955b --- /dev/null +++ b/src/usr/gpio/gpio_pca9551.C @@ -0,0 +1,343 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/gpio/gpio_pca9551.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2019 */ +/* [+] 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 */ +/** + * @file gpio_pca9551.C + * + * @brief Implements Interfaces Specific to the PCA9551 GPIO Devices + * + * @note Reference: https://www.nxp.com/docs/en/data-sheet/PCA9551.pdf + * + */ + + +#include <trace/interface.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <errl/errludtarget.H> +#include <errl/errludstring.H> +#include <targeting/common/targetservice.H> +#include <targeting/common/commontargeting.H> +#include <devicefw/driverif.H> +#include "gpiodd.H" +#include <gpio/gpioddreasoncodes.H> +#include <gpio/gpioif.H> +#include <config.h> + +extern trace_desc_t* g_trac_gpio; + +// Set to TRACFCOMP to enble unit race +#define TRACUCOMP(args...) TRACDCOMP(args) + +using namespace DeviceFW; +using namespace TARGETING; + +namespace GPIO +{ + + +void gpioPca9551SetReigsterHelper(const PCA9551_LEDS_t i_led, + const PCA9551_LED_Output_Settings_t i_setting, + uint8_t & io_led_register_data) +{ + uint8_t l_led = i_led; + uint8_t l_mask = PCA9551_LED_SETTINGS_MASK; // 2-bit mask shifted over to + // match i_led's value + uint8_t l_setting = i_setting; // will be shifted with 2-bit mask before it is applied + + // Adjust values for LEDs 4 to 7 to match calculations below for LEDs 0 to 3 + if (i_led > PCA9551_LED3) + { + l_led = l_led / PCA9551_LED_SETTINGS_DIVISOR; + } + TRACUCOMP(g_trac_gpio, "gpioPca9551SetReigsterHelper: " + "i_led=0x%.2X, l_led=0x%.2X, l_mask=0x%.2X, " + "l_setting=0x%.2X, data0=0x%.2X", + i_led, l_led, l_mask, l_setting,io_led_register_data); + + // Move 2-bit mask and setting to cover the correct values + // Setting register is uint8_t broken into 4 2-bit setting sections: + // [LED3 Setting][LED2 Setting][LED1 Setting][LED0 Setting] + // --OR-- + // [LED7 Setting][LED6 Setting][LED5 Setting][LED4 Setting] + + const uint8_t match = 0x01; // shift values until l_led == match + + // l_led must be >= match or following loop won't work + assert(l_led >= match, "gpioPca9551SetReigsterHelper: l_led %d is < match %d", l_led, match); + + TRACUCOMP(g_trac_gpio,"gpioPca9551SetReigsterHelper: Pre-loop: " + "l_led=0x%.2X, match=0x%.2X", + l_led, match); + while ( match != l_led ) + { + l_led = l_led >> PCA9551_LED_SHIFT_AMOUNT; + l_mask = l_mask << PCA9551_LED_SETTINGS_MASK_SHIFT_AMOUNT; + l_setting = l_setting << PCA9551_LED_SETTINGS_MASK_SHIFT_AMOUNT; + TRACUCOMP(g_trac_gpio,"gpioPca9551SetReigsterHelper: inside-loop: " + "l_led=0x%.2X, l_mask=0x%.2X, l_setting=0x%.2X", + l_led, l_mask, l_setting); + } + TRACUCOMP(g_trac_gpio, "gpioPca9551SetReigsterHelper: Post-loop: " + "l_mask=0x%.2X, l_setting=0x%.2X", + l_mask, l_setting); + + // Apply Mask to Register data and then OR-in setting bits + io_led_register_data = (io_led_register_data & ~l_mask) | l_setting; + TRACUCOMP(g_trac_gpio, "gpioPca9551SetReigsterHelper: " + "io_led_register_data=0x%.2X", + io_led_register_data); + + return; +} + + +errlHndl_t gpioPca9551GetLeds(TARGETING::Target * i_target, + uint8_t & o_led_data) +{ + errlHndl_t err = nullptr; + + TRACUCOMP(g_trac_gpio, ENTER_MRK"gpioPca9551GetLeds: " + "i_target 0x%.08X", + get_huid(i_target)); + + do + { + + // Read PCA9551 INPUT Register to get Pin (aka LED) Values + uint8_t data = 0; + size_t data_len = sizeof(data); + const size_t exp_data_len = data_len; + uint64_t device_type = PCA9551_GPIO_PHYS_PRES; + uint64_t register_addr = PCA9551_REGISTER_INPUT; + + err = DeviceFW::deviceOp + ( DeviceFW::READ, + i_target, + &data, + data_len, + DEVICE_GPIO_ADDRESS(device_type, register_addr) + ); + if(err) + { + TRACFCOMP(g_trac_gpio, ERR_MRK"gpioPca9551GetLeds: " + "Reading INPUT register failed"); + break; + } + else + { + o_led_data = data; + TRACUCOMP(g_trac_gpio, INFO_MRK"gpioPca9551GetLeds: " + "register_addr=0x%X, o_led_data=0x%.2X", + register_addr, o_led_data); + } + assert(data_len==exp_data_len, "gpioPca9551GetLeds: expected %d size of data but got %d", exp_data_len, data_len); + + } while (0); + + if (err) + { + err->collectTrace( GPIO_COMP_NAME ); + } + + return err; +} + +errlHndl_t gpioPca9551SetLed(TARGETING::Target * i_target, + const PCA9551_LEDS_t i_led, + const PCA9551_LED_Output_Settings_t i_setting, + uint8_t & o_led_data) +{ + errlHndl_t err = nullptr; + + TRACUCOMP(g_trac_gpio, ENTER_MRK"gpioPca9551SetLed: " + "i_target 0x%.8X, i_led=0x%.2X, i_setting=0x%.2X", + get_huid(i_target), i_led, i_setting); + + do + { + uint64_t deviceType = PCA9551_GPIO_PHYS_PRES; + + // First Read Select Register - either LS0 (LEDs 0-3) or LS1 (LEDs 4-7) + uint64_t register_addr = PCA9551_REGISTER_LS0; + if (i_led > PCA9551_LED3) + { + register_addr = PCA9551_REGISTER_LS1; + } + uint8_t data = 0; + size_t data_len = sizeof(data); + const size_t exp_data_len = data_len; + + err = DeviceFW::deviceOp + ( DeviceFW::READ, + i_target, + &data, + data_len, + DEVICE_GPIO_ADDRESS(deviceType, register_addr) + ); + if(err) + { + TRACFCOMP(g_trac_gpio, ERR_MRK"gpioPca9551SetLed: " + "Reading LED Select register 0x%X failed", + register_addr); + break; + } + else + { + TRACUCOMP(g_trac_gpio, INFO_MRK"gpioPca9551SetLed: " + "LED Select register_addr=0x%X, data=0x%.2X", + register_addr, data); + } + assert(data_len==exp_data_len, "gpioPca9551SetLed: expected %d size of data but got %d", exp_data_len, data_len); + + + // Create Setting Register to Write Back: + uint8_t write_data = data; + gpioPca9551SetReigsterHelper(i_led, i_setting, write_data); + + // Write LED Select Register + data = write_data; + + err = DeviceFW::deviceOp + ( DeviceFW::WRITE, + i_target, + &data, + data_len, + DEVICE_GPIO_ADDRESS(deviceType, register_addr) + ); + if(err) + { + TRACFCOMP(g_trac_gpio, ERR_MRK"gpioPca9551SetLed: " + "Writing LED Select register 0x%X failed", + register_addr); + break; + } + else + { + TRACUCOMP(g_trac_gpio, INFO_MRK"gpioPca9551SetLed: " + "Writing LED Select register_addr=0x%X, data=0x%.2X", + register_addr, data); + } + assert(data_len==exp_data_len, "gpioPca9551SetLed: expected %d size of data but got %d", exp_data_len, data_len); + + + // Read Back LED Select Register + data = 0; + err = DeviceFW::deviceOp + ( DeviceFW::READ, + i_target, + &data, + data_len, + DEVICE_GPIO_ADDRESS(deviceType, register_addr) + ); + if(err) + { + TRACFCOMP(g_trac_gpio, ERR_MRK"gpioPca9551SetLed: " + "Reading LED Select register 0x%X failed", + register_addr); + break; + } + else + { + TRACUCOMP(g_trac_gpio, INFO_MRK"gpioPca9551SetLed: " + "LED Select register_addr=0x%X, data=0x%.2X", + register_addr, data); + } + assert(data_len==exp_data_len, "gpioPca9551SetLed: expected %d size of data but got %d", exp_data_len, data_len); + + // Compare data written and data read back + if (data != write_data) + { + TRACFCOMP(g_trac_gpio, ERR_MRK"gpioPca9551SetLed: " + "Reading Back LED Select register 0x%X had unexpected data=", + "0x%.2X. Expected 0x%.2X", + register_addr, data, write_data); + + /*@ + * @errortype + * @reasoncode GPIO_PCA9551_DATA_MISMATCH + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid GPIO_PCA9551_SET_LED + * @userdata1[0:31] HUID of Master Processor Target + * @userdata1[32:63] Input LED to Set + * @userdata2[0:31] Expected Data (aka data written) + * @userdata2[32:63] Data Read Back + * @devdesc Setting of LED value did not appear to work + * @custdesc A problem occurred during the IPL + * of the system. + */ + err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + GPIO_PCA9551_SET_LED, + GPIO_PCA9551_DATA_MISMATCH, + TWO_UINT32_TO_UINT64( + get_huid(i_target), + i_led), + TWO_UINT32_TO_UINT64( + write_data, + data), + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + + break; + } + + // Read PCA9551 INPUT Register to get Pin (aka LED) Values + data = 0; + data_len = sizeof(data); + register_addr = PCA9551_REGISTER_INPUT; + + err = DeviceFW::deviceOp + ( DeviceFW::READ, + i_target, + &data, + data_len, + DEVICE_GPIO_ADDRESS(deviceType, register_addr) + ); + if(err) + { + TRACFCOMP(g_trac_gpio, ERR_MRK"gpioPca9551SetLed: " + "Reading INPUT register failed"); + break; + } + else + { + o_led_data = data; + TRACUCOMP(g_trac_gpio, INFO_MRK"gpioPca9551SetLed: " + "INPUT register_addr=0x%X, o_led_data=0x%.2X", + register_addr, o_led_data); + } + assert(data_len==exp_data_len, "gpioPca9551SetLed: expected %d size of data but got %d", exp_data_len, data_len); + + } while (0); + + if (err) + { + err->collectTrace( GPIO_COMP_NAME ); + } + + return err; + +} + +}; // end namespace GPIO + diff --git a/src/usr/gpio/gpiodd.C b/src/usr/gpio/gpiodd.C index 559dab79e..69cde2b70 100644 --- a/src/usr/gpio/gpiodd.C +++ b/src/usr/gpio/gpiodd.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2014,2018 */ +/* Contributors Listed Below - COPYRIGHT 2014,2019 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -34,6 +34,8 @@ #include <devicefw/driverif.H> #include "gpiodd.H" #include <gpio/gpioddreasoncodes.H> +#include <gpio/gpioif.H> +#include <config.h> trace_desc_t * g_trac_gpio = NULL; TRAC_INIT( & g_trac_gpio, GPIO_COMP_NAME, KILOBYTE ); @@ -57,6 +59,11 @@ DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, TARGETING::TYPE_MEMBUF, gpioPerformOp); +DEVICE_REGISTER_ROUTE( DeviceFW::WILDCARD, + DeviceFW::GPIO, + TARGETING::TYPE_PROC, + gpioPerformOp); + errlHndl_t gpioPerformOp(DeviceFW::OperationType i_opType, TARGETING::Target * i_target, void * io_buffer, @@ -70,7 +77,8 @@ errlHndl_t gpioPerformOp(DeviceFW::OperationType i_opType, gpioInfo.deviceType = va_arg( i_args, uint64_t ); gpioInfo.portAddr = va_arg( i_args, uint64_t ); - TRACDCOMP(g_trac_gpio, ENTER_MRK"gpioPerformOp(): " +//MAB make TRACD + TRACFCOMP(g_trac_gpio, ENTER_MRK"gpioPerformOp(): " "optype %d deviceType %d portAddr %d", i_opType, gpioInfo.deviceType, gpioInfo.portAddr); @@ -237,20 +245,51 @@ errlHndl_t gpioReadAttributes ( TARGETING::Target * i_target, { errlHndl_t err = NULL; - TARGETING::GpioInfo gpioData; - bool attrReadErr = false; +#ifndef CONFIG_FSP_BUILD + TARGETING::GpioInfo gpioData; +#endif + TARGETING::GpioInfoPhysPres gpioDataPhysPres; switch(io_gpioInfo.deviceType) { +#ifndef CONFIG_FSP_BUILD case PCA95X_GPIO: if( !( i_target-> tryGetAttr<TARGETING::ATTR_GPIO_INFO>( gpioData ) ) ) { attrReadErr = true; } + else + { + io_gpioInfo.i2cMasterPath = gpioData.i2cMasterPath; + io_gpioInfo.engine = gpioData.engine; + io_gpioInfo.i2cPort = gpioData.port; + io_gpioInfo.i2cDeviceAddr = gpioData.devAddr; + io_gpioInfo.i2cMuxBusSelector = gpioData.i2cMuxBusSelector; + io_gpioInfo.i2cMuxPath = gpioData.i2cMuxPath; + } break; +#endif + case PCA9551_GPIO_PHYS_PRES: + + if( !( i_target-> + tryGetAttr<TARGETING::ATTR_GPIO_INFO_PHYS_PRES>(gpioDataPhysPres))) + { + attrReadErr = true; + } + else + { + io_gpioInfo.i2cMasterPath = gpioDataPhysPres.i2cMasterPath; + io_gpioInfo.engine = gpioDataPhysPres.engine; + io_gpioInfo.i2cPort = gpioDataPhysPres.port; + io_gpioInfo.i2cDeviceAddr = gpioDataPhysPres.devAddr; + io_gpioInfo.i2cMuxBusSelector = gpioDataPhysPres.i2cMuxBusSelector; + io_gpioInfo.i2cMuxPath = gpioDataPhysPres.i2cMuxPath; + } + break; + default: TRACFCOMP( g_trac_gpio,ERR_MRK"gpioReadAttributes() - " @@ -309,16 +348,6 @@ errlHndl_t gpioReadAttributes ( TARGETING::Target * i_target, err->collectTrace( GPIO_COMP_NAME ); } - if( !err ) - { - io_gpioInfo.i2cMasterPath = gpioData.i2cMasterPath; - io_gpioInfo.engine = gpioData.engine; - io_gpioInfo.i2cPort = gpioData.port; - io_gpioInfo.i2cDeviceAddr = gpioData.devAddr; - io_gpioInfo.i2cMuxBusSelector = gpioData.i2cMuxBusSelector; - io_gpioInfo.i2cMuxPath = gpioData.i2cMuxPath; - } - return err; } diff --git a/src/usr/gpio/makefile b/src/usr/gpio/makefile index d40eaa130..fd42e2d1d 100644 --- a/src/usr/gpio/makefile +++ b/src/usr/gpio/makefile @@ -5,7 +5,7 @@ # # OpenPOWER HostBoot Project # -# Contributors Listed Below - COPYRIGHT 2014 +# Contributors Listed Below - COPYRIGHT 2014,2019 # [+] Google Inc. # [+] International Business Machines Corp. # @@ -27,6 +27,8 @@ ROOTPATH = ../../.. MODULE = gpio OBJS += $(if $(CONFIG_GPIODD),gpiodd.o,) +OBJS += $(if $(CONFIG_GPIODD),gpio_pca9551.o,) + # no way to test this at the moment TODO RTC 111415 #SUBDIRS = test.d diff --git a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml index 3e651b498..8be123d99 100755 --- a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml +++ b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml @@ -325,6 +325,78 @@ <hbOnly/> </attribute> + <attribute> + <id>GPIO_INFO_PHYS_PRES</id> + <description>Information needed to address GPIO device that corresponds + to the Physical Presence Detect circuit</description> + <complexType> + <description>Structure to define the addessing for an I2C + slave device.</description> + <field> + <name>i2cMasterPath</name> + <description>Entity path to the chip that contains the I2C + master</description> + <type>EntityPath</type> + <default>physical:sys-0/node-0/proc-0</default> + </field> + <field> + <name>port</name> + <description>Port from the I2C Master device. This is a 6-bit + value.</description> + <type>uint8_t</type> + <default>0</default> + </field> + <field> + <name>devAddr</name> + <description>Device address on the I2C bus. This is a 7-bit value, + but then shifted 1 bit left.</description> + <type>uint8_t</type> + <default>0xC0</default> + </field> + <field> + <name>engine</name> + <description>I2C master engine. This is a 2-bit + value.</description> + <type>uint8_t</type> + <default>2</default> + </field> + <field> + <name>windowOpenPin</name> + <description>Logical GPIO pin number used to open or close the physcial + presence window</description> + <type>uint8_t</type> + <default>0</default> + </field> + <field> + <name>physicalPresencePin</name> + <description>Logical GPIO pin number used to determine if physical + presence was asserted</description> + <type>uint8_t</type> + <default>1</default> + </field> + <!-- i2c Mux Bus Selector Definition --> + <field> + <default>0xFF</default> + <description>Determines which of the N selectable buses the mux + will connect to. OxFF indicates no mux present + or N/A.</description> + <name>i2cMuxBusSelector</name> + <type>uint8_t</type> + </field> + <!-- i2c Mux Path Definition --> + <field> + <!-- NOTE: physical:sys-0 implies that there is no mux in + the bus path for this part. --> + <default>physical:sys-0</default> + <description>Entity path to the I2C mux for this device.</description> + <name>i2cMuxPath</name> + <type>EntityPath</type> + </field> + </complexType> + <persistency>non-volatile</persistency> + <readable/> + </attribute> + <!-- TODO RTC 122856 When support for HB only volatile attributes with non-zero default is implemented, update default value to match the description, Until that happens, code must set the appropriate default if needed. --> diff --git a/src/usr/targeting/common/xmltohb/target_types_hb.xml b/src/usr/targeting/common/xmltohb/target_types_hb.xml index 26cf81f6f..080fbecae 100644 --- a/src/usr/targeting/common/xmltohb/target_types_hb.xml +++ b/src/usr/targeting/common/xmltohb/target_types_hb.xml @@ -116,6 +116,9 @@ <id>FSI_SCOM_MUTEX</id> </attribute> <attribute> + <id>GPIO_INFO_PHYS_PRES</id> + </attribute> + <attribute> <id>HBRT_HYP_ID</id> </attribute> <attribute> |