summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods')
-rw-r--r--meta-openbmc-mods/COPYING.MIT17
-rw-r--r--meta-openbmc-mods/COPYING.apache-2.0175
-rw-r--r--meta-openbmc-mods/README64
-rw-r--r--meta-openbmc-mods/conf/layer.conf22
-rw-r--r--meta-openbmc-mods/conf/machine/include/intel.inc23
-rw-r--r--meta-openbmc-mods/files/group12
-rw-r--r--meta-openbmc-mods/files/passwd10
-rw-r--r--meta-openbmc-mods/meta-common-small/conf/layer.conf11
-rw-r--r--meta-openbmc-mods/meta-common-small/recipes-core/systemd/systemd_%.bbappend14
-rw-r--r--meta-openbmc-mods/meta-common/COPYING.MIT17
-rw-r--r--meta-openbmc-mods/meta-common/README64
-rw-r--r--meta-openbmc-mods/meta-common/classes/image_types_phosphor_auto.bbclass75
-rw-r--r--meta-openbmc-mods/meta-common/classes/obmc-phosphor-full-fitimage.bbclass555
-rw-r--r--meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass38
-rw-r--r--meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-dev.bbclass7
-rw-r--r--meta-openbmc-mods/meta-common/conf/layer.conf11
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-flash-use-readX-writeX-not-udelay.patch424
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0002-intel-layout-environment-addr.patch42
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch75
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch56
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0006-Add-Aspeed-g5-interrupt-support.patch389
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch330
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0008-add-sgio-support-for-port80-snoop-post-LEDs.patch160
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0009-Add-basic-GPIO-support.patch414
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch98
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch160
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0012-Add-status-and-ID-LED-support.patch144
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0013-aspeed-Add-Pwm-Driver.patch132
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0014-Keep-interrupts-enabled-until-last-second.patch91
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0015-Rewrite-memmove-to-optimize-on-word-transfers.patch114
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0017-Enable-Macronix-and-Micron-SPI-support.patch54
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch65
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0019-u-boot-full-platform-reset-espi-oob-ready.patch48
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Add-system-reset-status-support.patch206
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Enable-PCIe-L1-support.patch38
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-Config-host-uart-clock-source-using-environment-vari.patch108
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/cpu-log-util/cpu-log-util_git.bb27
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/cpu-log-util/files/com.intel.CpuDebugLog.service10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh104
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl136
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb22
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/ipmi/ipmi-providers.bb37
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/microsoft-gsl/microsoft-gsl.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend85
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/packagegroups/packagegroup-core-standalone-sdk-target.bbappend1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/peci-pcie/peci-pcie_git.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/readline/readline/inputrc61
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/readline/readline_%.bbappend2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/rest-dbus/rest-dbus-static.bb23
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/obmc-targets.bbappend9
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf.bbappend12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf42
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/000-ro-rootfs-tmpfile-defaults.patch51
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/systemd_%.bbappend11
-rw-r--r--meta-openbmc-mods/meta-common/recipes-devtools/dtoverlay/dtoverlay.bb31
-rw-r--r--meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb20
-rw-r--r--meta-openbmc-mods/meta-common/recipes-devtools/template-recipe/template-recipe.bb18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend21
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/start-ipkvm.service11
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_git.bb18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control.bb201
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/intel-power-start@.service16
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/intel-power-stop@.service20
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/intel-power-warm-reset@.service14
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-hard-poweroff@.target12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-poweroff@.target10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-poweron@.target10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-powerreset@.target7
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-reboot@.target10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-soft-reboot@.target10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-start@.target10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-startmin@.target6
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-stop@.target10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-warm-reset@.target10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-host-starting@.service13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-host-stopping@.service13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-post-host-start@.service13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-post-host-stop@.service13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-pre-host-start@.service13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-pre-host-stop@.service14
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/op-reset-chassis-on@.service15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/op-reset-chassis-running@.service15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/xyz.openbmc_project.Chassis.Buttons@.service14
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/xyz.openbmc_project.Chassis.Control.Chassis@.service15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/xyz.openbmc_project.Chassis.Control.Power@.service15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/images/intel-platforms.bb13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend6
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1.bb33
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1/smbios-mdrv1.service13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb33
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2/smbios-mdrv2.service12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-arm-dts-aspeed-g5-add-espi.patch56
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-New-flash-map-for-intel.patch125
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch474
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch240
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch4392
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0019-Add-I2C-IPMB-support.patch426
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch623
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch597
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch387
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch1138
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0029-i2c-aspeed-Improve-driver-to-support-multi-master-us.patch291
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch151
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch132
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch556
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-adpeed-Swap-the-mac-nodes-numbering.patch85
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch249
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0036-net-ncsi-backport-ncsi-patches.patch1425
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0038-media-aspeed-backport-ikvm-patches.patch1995
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch702
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch492
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0041-Enable-passthrough-based-gpio-character-device.patch287
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch105
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch140
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch125
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch235
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0046-misc-Add-clock-control-logic-into-Aspeed-LPC-MBOX-dr.patch166
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch43
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0048-ARM-dts-aspeed-Set-default-status-of-LPC-BT-as-disab.patch40
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend38
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-libc-headers/0001-Enable-passthrough-based-gpio-character-device.patch26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-libc-headers_%.bbappend5
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/network/0001-Patch-to-keep-consistent-MAC-and-IP-address-inbetwee.patch456
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/network/0002-IPv6-Network-changes-to-configuration-file.patch210
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-network/network/network/0003-Adding-channel-specific-privilege-to-network.patch800
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/network_%.bbappend9
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/xyz.openbmc_project.CloseMuxes.service10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0002-Modify-Dbus-for-IPv6.patch55
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0003-Chassis-Power-Control-are-implemented.patch257
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch120
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0006-dbus-interface-add-boot-option-support-for-floppy-an.patch77
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch32
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0009-Add-host-restart-cause-property.patch98
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch34
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch34
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch86
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0014-Add-multiple-state-signal-for-host-start-and-stop.patch63
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch227
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0017-Add-shutdown-policy-interface-for-get-set-shutdown-p.patch42
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0018-Define-post-code-interfaces-for-post-code-manager.patch64
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0019-Creating-the-Session-interface-for-Host-and-LAN.patch126
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch76
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend20
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service20
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend11
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/gpiodaemon/gpiodaemon.bb18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend6
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket9
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend17
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend21
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json23
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json178
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json49
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml31
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Modify-dbus-interface-for-power-control.patch31
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0003-Modify-dbus-interface-for-chassis-control.patch33
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch909
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch56
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0012-ipmi-set-get-boot-options.patch64
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch25
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0014-Enable-get-device-guid-ipmi-command.patch45
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0016-add-better-sdbusplus-exception-handling.patch153
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0018-Catch-sdbusplus-exceptions-in-IPMI-net.patch49
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0021-Implement-IPMI-Commmand-Get-Host-Restart-Cause.patch143
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch25
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch322
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0049-Fix-Unspecified-error-on-ipmi-restart-cause-command.patch71
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0051-Fix-Set-LAN-Config-to-work-without-SetInProgress.patch142
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch80
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch37
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0055-Implement-set-front-panel-button-enables-command.patch185
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch102
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch195
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend37
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.SMM.service13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.service13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend9
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch39
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0007-Adding-support-for-GetSessionInfo-command.patch421
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0008-Sync-GetSession-Info-cmd-based-on-Upstream-review.patch318
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch311
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml0
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb21
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/logging/phosphor-logging_%.bbappend2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend3
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init180
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend6
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb38
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native.bbappend4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native/defaults.yaml181
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager/0001-settings-initialize-data-file-with-default-setting.patch37
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager_%.bbappend4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0001-Modify-dbus-interface-for-power-control.patch38
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0002-Capture-host-restart-cause.patch234
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0003-Use-warm-reboot-for-the-Reboot-host-state-transition.patch71
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reboot-host@.service18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-check@.service19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-reboot-attempts@.service14
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend9
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager/0001-Implement-post-code-manager.patch499
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb34
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch1648
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend9
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb35
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format98
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt52
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp258
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Add-expiredTimerUse-property-support.patch28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/obmc-enable-host-watchdog@.service14
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog@.service12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend6
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf3
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service11
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0001-Implement-KVM-in-webui.patch238
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0007-Fix-some-page-keeps-loading-on-IE11.patch68
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf16
-rw-r--r--meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-support/boost/boost/0001-Close-the-read-pipe-after-_read_error-completes.patch45
-rw-r--r--meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend3
-rw-r--r--meta-openbmc-mods/meta-common/recipes-support/libgpiod/libgpiod/0001-Add-pass-through-setting-in-gpioset.patch265
-rw-r--r--meta-openbmc-mods/meta-common/recipes-support/libgpiod/libgpiod_%.bbappend5
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/beeper-test.bb17
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format99
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt7
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp81
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb17
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt7
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp143
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini277
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt7
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c665
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb17
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt7
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c479
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h78
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb16
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py144
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb20
-rw-r--r--meta-openbmc-mods/meta-wolfpass/conf/bblayers.conf.sample24
-rw-r--r--meta-openbmc-mods/meta-wolfpass/conf/conf-notes.txt5
-rw-r--r--meta-openbmc-mods/meta-wolfpass/conf/layer.conf12
-rw-r--r--meta-openbmc-mods/meta-wolfpass/conf/local.conf.sample25
-rw-r--r--meta-openbmc-mods/meta-wolfpass/conf/machine/include/obmc-bsp-si-common.inc31
-rw-r--r--meta-openbmc-mods/meta-wolfpass/conf/machine/wolfpass.conf19
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-intel/temporary/set-passthrough.bb13
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-intel/temporary/set-passthrough/set-passthrough.sh38
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0001-Create-intel-purley-dts.patch389
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0002-Define-the-gpio-line-names-property-for-purley-platform.patch63
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0003-Leave-GPIOE-in-passthrough-after-boot.patch46
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0004-Test-code-for-LPC-MBOX.patch112
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch31
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/wolfpass.cfg69
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed_%.bbappend8
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/FCXXPDBASSMBL_PDB.json85
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/OPB2RH-Chassis.json18
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/TNP-baseboard.json1945
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json1736
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/WP-Baseboard.json1734
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager_%.bbappend13
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console/obmc-console.conf3
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console/obmc-console@.service21
-rwxr-xr-xmeta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console/sol-option-check.sh25
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console_%.bbappend8
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fans/fan-default-speed.bb20
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fans/fan-default-speed/fan-default-speed.service10
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fans/fan-default-speed/set_fan_speeds.py23
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru.bb27
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/LICENCE13
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600CYP.fru.binbin0 -> 513 bytes
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600TNP.fru.binbin0 -> 512 bytes
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600WC.fru.binbin0 -> 511 bytes
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600WFT.fru.binbin0 -> 512 bytes
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600WP.fru.binbin0 -> 512 bytes
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/SetBaseboardFru.service9
-rwxr-xr-xmeta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/checkFru.sh38
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/workbook/wolfpass-config.bb10
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes.txt2
315 files changed, 41986 insertions, 0 deletions
diff --git a/meta-openbmc-mods/COPYING.MIT b/meta-openbmc-mods/COPYING.MIT
new file mode 100644
index 000000000..89de35479
--- /dev/null
+++ b/meta-openbmc-mods/COPYING.MIT
@@ -0,0 +1,17 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/meta-openbmc-mods/COPYING.apache-2.0 b/meta-openbmc-mods/COPYING.apache-2.0
new file mode 100644
index 000000000..67db85882
--- /dev/null
+++ b/meta-openbmc-mods/COPYING.apache-2.0
@@ -0,0 +1,175 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
diff --git a/meta-openbmc-mods/README b/meta-openbmc-mods/README
new file mode 100644
index 000000000..3d883acb2
--- /dev/null
+++ b/meta-openbmc-mods/README
@@ -0,0 +1,64 @@
+This README file contains information on the contents of the
+intel layer.
+
+Please see the corresponding sections below for details.
+
+
+Dependencies
+============
+
+This layer depends on:
+
+ URI: git://git.openembedded.org/bitbake
+ branch: master
+
+ URI: git://git.openembedded.org/openembedded-core
+ layers: meta
+ branch: master
+
+ URI: git://git.yoctoproject.org/xxxx
+ layers: xxxx
+ branch: master
+
+
+Patches
+=======
+
+Please submit any patches against the intel layer to the
+xxxx mailing list (xxxx@zzzz.org) and cc: the maintainer:
+
+Maintainer: XXX YYYYYY <xxx.yyyyyy@zzzzz.com>
+
+
+Table of Contents
+=================
+
+ I. Adding the intel layer to your build
+ II. Misc
+
+
+I. Adding the intel layer to your build
+=================================================
+
+--- replace with specific instructions for the intel layer ---
+
+In order to use this layer, you need to make the build system aware of
+it.
+
+Assuming the intel layer exists at the top-level of your
+yocto build tree, you can add it to the build system by adding the
+location of the intel layer to bblayers.conf, along with any
+other layers needed. e.g.:
+
+ BBLAYERS ?= " \
+ /path/to/yocto/meta \
+ /path/to/yocto/meta-poky \
+ /path/to/yocto/meta-yocto-bsp \
+ /path/to/yocto/meta-intel \
+ "
+
+
+II. Misc
+========
+
+--- replace with specific information about the intel layer ---
diff --git a/meta-openbmc-mods/conf/layer.conf b/meta-openbmc-mods/conf/layer.conf
new file mode 100644
index 000000000..9cc62fc6a
--- /dev/null
+++ b/meta-openbmc-mods/conf/layer.conf
@@ -0,0 +1,22 @@
+# We have a conf and classes directory, add to BBPATH
+BBPATH .= ":${LAYERDIR}"
+
+# We have recipes-* directories, add to BBFILES
+BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
+ ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "intel"
+BBFILE_PATTERN_intel = "^${LAYERDIR}/"
+BBFILE_PRIORITY_intel = "5"
+LAYERSERIES_COMPAT_intel = "thud"
+
+IMAGE_FEATURES[validitems] += "tools-sdk tools-debug"
+
+# static userid assignments
+USERADDEXTENSION = "useradd-staticids"
+USERADD_UID_TABLES = "files/passwd"
+USERADD_GID_TABLES = "files/group"
+
+LAYER_CONF_VERSION = "10"
+
+INTELBASE = '${@os.path.normpath("${LAYERDIR}/")}'
diff --git a/meta-openbmc-mods/conf/machine/include/intel.inc b/meta-openbmc-mods/conf/machine/include/intel.inc
new file mode 100644
index 000000000..20ca34a66
--- /dev/null
+++ b/meta-openbmc-mods/conf/machine/include/intel.inc
@@ -0,0 +1,23 @@
+OBMC_MACHINE_FEATURES += "\
+ obmc-phosphor-fan-mgmt \
+ obmc-phosphor-chassis-mgmt \
+ obmc-phosphor-flash-mgmt \
+ obmc-host-ipmi \
+ obmc-host-state-mgmt \
+ obmc-chassis-state-mgmt \
+ obmc-bmc-state-mgmt \
+ "
+
+VIRTUAL-RUNTIME_skeleton_workbook = "${MACHINE}-config"
+
+VIRTUAL-RUNTIME_obmc-led-monitor = ""
+
+PREFERRED_PROVIDER_virtual/obmc-host-ipmi-hw = "phosphor-ipmi-kcs"
+PREFERRED_PROVIDER_virtual/obmc-chassis-mgmt = "packagegroup-intel-apps"
+PREFERRED_PROVIDER_virtual/obmc-fan-mgmt = "packagegroup-intel-apps"
+PREFERRED_PROVIDER_virtual/obmc-flash-mgmt = "packagegroup-intel-apps"
+PREFERRED_PROVIDER_virtual/obmc-system-mgmt = "packagegroup-intel-apps"
+PREFERRED_PROVIDER_virtual/obmc-host-ctl ?= "obmc-op-control-host"
+PREFERRED_PROVIDER_virtual/obmc-inventory-data ?= "${VIRTUAL-RUNTIME_skeleton_workbook}"
+PREFERRED_PROVIDER_virtual/phosphor-led-manager-config-native ?= "intel-led-manager-config-native"
+#PREFERRED_PROVIDER_virtual/obmc-gpio-monitor ?= "phosphor-gpio-monitor"
diff --git a/meta-openbmc-mods/files/group b/meta-openbmc-mods/files/group
new file mode 100644
index 000000000..8f8c8e325
--- /dev/null
+++ b/meta-openbmc-mods/files/group
@@ -0,0 +1,12 @@
+bmcweb:x:443:
+ipmid:x:197:
+lock:x:198:
+netdev:x:208:
+avahi:x:200:
+messagebus:x:201
+systemd-journal:x:202:
+systemd-network:x:203:
+systemd-timesync:x:204:
+systemd-coredump:x:205:
+systemd-bus-proxy:x:206:
+systemd-resolve:!:207:
diff --git a/meta-openbmc-mods/files/passwd b/meta-openbmc-mods/files/passwd
new file mode 100644
index 000000000..ae48cfb46
--- /dev/null
+++ b/meta-openbmc-mods/files/passwd
@@ -0,0 +1,10 @@
+bmcweb:x:443:443::/home/bmcweb:/bin/false
+hostipmid:x:196:197::/:/bin/false
+netipmid:x:197:197::/:/bin/false
+avahi:x:200:200::/var/run/avahi-daemon:/bin/false
+messagebus:x:201:201::/var/lib/dbus:/bin/false
+systemd-network:x:203:203::/:/bin/false
+systemd-timesync:x:204:204::/:/bin/false
+systemd-coredump:x:205:205::/:/bin/false
+systemd-bus-proxy:x:206:206::/:/bin/false
+systemd-resolve:!:207:207::/:/bin/nologin
diff --git a/meta-openbmc-mods/meta-common-small/conf/layer.conf b/meta-openbmc-mods/meta-common-small/conf/layer.conf
new file mode 100644
index 000000000..73c015192
--- /dev/null
+++ b/meta-openbmc-mods/meta-common-small/conf/layer.conf
@@ -0,0 +1,11 @@
+# We have a conf and classes directory, add to BBPATH
+BBPATH .= ":${LAYERDIR}"
+
+# We have recipes-* directories, add to BBFILES
+BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
+ ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "common-small"
+BBFILE_PATTERN_common-small = "^${LAYERDIR}/"
+BBFILE_PRIORITY_common-small = "10"
+LAYERSERIES_COMPAT_common-small = "thud"
diff --git a/meta-openbmc-mods/meta-common-small/recipes-core/systemd/systemd_%.bbappend b/meta-openbmc-mods/meta-common-small/recipes-core/systemd/systemd_%.bbappend
new file mode 100644
index 000000000..12cb9fd48
--- /dev/null
+++ b/meta-openbmc-mods/meta-common-small/recipes-core/systemd/systemd_%.bbappend
@@ -0,0 +1,14 @@
+# add some configuration overrides for systemd default /usr/lib/tmpfiles.d/
+
+LICENSE = "GPL-2.0"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+# Disable udev hwdb
+RRECOMMENDS_${PN}_remove += "udev-hwdb"
+PACKAGES_remove += "udev-hwdb"
+
+do_install_append() {
+ rm -rf ${D}${rootlibexecdir}/udev/hwdb.d
+ rm -f ${D}${sysconfdir}/udev/hwdb.bin
+}
diff --git a/meta-openbmc-mods/meta-common/COPYING.MIT b/meta-openbmc-mods/meta-common/COPYING.MIT
new file mode 100644
index 000000000..89de35479
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/COPYING.MIT
@@ -0,0 +1,17 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/meta-openbmc-mods/meta-common/README b/meta-openbmc-mods/meta-common/README
new file mode 100644
index 000000000..9d4a8a1e6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/README
@@ -0,0 +1,64 @@
+This README file contains information on the contents of the
+common layer.
+
+Please see the corresponding sections below for details.
+
+
+Dependencies
+============
+
+This layer depends on:
+
+ URI: git://git.openembedded.org/bitbake
+ branch: master
+
+ URI: git://git.openembedded.org/openembedded-core
+ layers: meta
+ branch: master
+
+ URI: git://git.yoctoproject.org/xxxx
+ layers: xxxx
+ branch: master
+
+
+Patches
+=======
+
+Please submit any patches against the common layer to the
+xxxx mailing list (xxxx@zzzz.org) and cc: the maintainer:
+
+Maintainer: XXX YYYYYY <xxx.yyyyyy@zzzzz.com>
+
+
+Table of Contents
+=================
+
+ I. Adding the common layer to your build
+ II. Misc
+
+
+I. Adding the common layer to your build
+=================================================
+
+--- replace with specific instructions for the common layer ---
+
+In order to use this layer, you need to make the build system aware of
+it.
+
+Assuming the common layer exists at the top-level of your
+yocto build tree, you can add it to the build system by adding the
+location of the common layer to bblayers.conf, along with any
+other layers needed. e.g.:
+
+ BBLAYERS ?= " \
+ /path/to/yocto/meta \
+ /path/to/yocto/meta-poky \
+ /path/to/yocto/meta-yocto-bsp \
+ /path/to/yocto/meta-common \
+ "
+
+
+II. Misc
+========
+
+--- replace with specific information about the common layer ---
diff --git a/meta-openbmc-mods/meta-common/classes/image_types_phosphor_auto.bbclass b/meta-openbmc-mods/meta-common/classes/image_types_phosphor_auto.bbclass
new file mode 100644
index 000000000..91e699979
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/classes/image_types_phosphor_auto.bbclass
@@ -0,0 +1,75 @@
+# Base image class extension, inlined into every image.
+
+# Phosphor image types
+#
+# New image types based on DTS partition information
+#
+inherit logging
+
+# Image composition
+FLASH_FULL_IMAGE ?= "fitImage-rootfs-${MACHINE}.bin"
+
+IMAGE_BASETYPE ?= "squashfs-xz"
+OVERLAY_BASETYPE ?= "jffs2"
+
+IMAGE_TYPES += "mtd-auto"
+
+IMAGE_TYPEDEP_mtd-auto = "${IMAGE_BASETYPE}"
+IMAGE_TYPES_MASKED += "mtd-auto"
+
+# Flash characteristics in KB unless otherwise noted
+python() {
+ # TODO: find partition list in DTS
+ DTB_FULL_FIT_IMAGE_OFFSETS = [0x80000, 0x2480000]
+ d.setVar('FLASH_UBOOT_OFFSET', str(0))
+ if d.getVar('IMAGE_TYPE', True) == 'pfr':
+ d.setVar('FLASH_SIZE', str(128*1024))
+ else:
+ d.setVar('FLASH_SIZE', str(64*1024))
+ d.setVar('FLASH_RUNTIME_OFFSETS', ' '.join(
+ [str(int(x/1024)) for x in DTB_FULL_FIT_IMAGE_OFFSETS]
+ )
+ )
+}
+
+mk_nor_image() {
+ image_dst="$1"
+ image_size_kb=$2
+ dd if=/dev/zero bs=1k count=$image_size_kb \
+ | tr '\000' '\377' > $image_dst
+}
+
+do_generate_auto() {
+ bbdebug 1 "do_generate_auto IMAGE_TYPE=${IMAGE_TYPE} size=${FLASH_SIZE}KB (${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.auto.mtd)"
+ # Assemble the flash image
+ mk_nor_image ${IMGDEPLOYDIR}/${IMAGE_NAME}.auto.mtd ${FLASH_SIZE}
+ dd bs=1k conv=notrunc seek=${FLASH_UBOOT_OFFSET} \
+ if=${DEPLOY_DIR_IMAGE}/u-boot.${UBOOT_SUFFIX} \
+ of=${IMGDEPLOYDIR}/${IMAGE_NAME}.auto.mtd
+
+ for OFFSET in ${FLASH_RUNTIME_OFFSETS}; do
+ dd bs=1k conv=notrunc seek=${OFFSET} \
+ if=${DEPLOY_DIR_IMAGE}/${FLASH_FULL_IMAGE} \
+ of=${IMGDEPLOYDIR}/${IMAGE_NAME}.auto.mtd
+ done
+
+ ln ${IMGDEPLOYDIR}/${IMAGE_NAME}.auto.mtd \
+ ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.auto.mtd
+ ln -sf ${IMAGE_NAME}.auto.mtd ${DEPLOY_DIR_IMAGE}/image-mtd
+}
+do_generate_auto[dirs] = "${S}/auto"
+do_generate_auto[depends] += " \
+ ${PN}:do_image_${@d.getVar('IMAGE_BASETYPE', True).replace('-', '_')} \
+ virtual/kernel:do_deploy \
+ u-boot:do_populate_sysroot \
+ "
+
+python() {
+ types = d.getVar('IMAGE_FSTYPES', True).split()
+
+ if 'mtd-auto' in types:
+ bb.build.addtask(# task, depends_on_task, task_depends_on, d )
+ 'do_generate_auto',
+ 'do_build',
+ 'do_image_complete', d)
+}
diff --git a/meta-openbmc-mods/meta-common/classes/obmc-phosphor-full-fitimage.bbclass b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-full-fitimage.bbclass
new file mode 100644
index 000000000..fefa65569
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-full-fitimage.bbclass
@@ -0,0 +1,555 @@
+inherit uboot-sign logging
+
+DEPENDS += "u-boot-mkimage-native"
+
+SIGNING_KEY ?= "${STAGING_DIR_NATIVE}${datadir}/OpenBMC.priv"
+INSECURE_KEY = "${@'${SIGNING_KEY}' == '${STAGING_DIR_NATIVE}${datadir}/OpenBMC.priv'}"
+SIGNING_KEY_DEPENDS = "${@oe.utils.conditional('INSECURE_KEY', 'True', 'phosphor-insecure-signing-key-native:do_populate_sysroot', '', d)}"
+
+DEPS = " ${PN}:do_image_${@d.getVar('IMAGE_BASETYPE', True).replace('-', '_')} \
+ virtual/kernel:do_deploy \
+ u-boot:do_populate_sysroot "
+
+python() {
+ if d.getVar('IMAGE_TYPE', True) == 'pfr':
+ d.appendVar('DEPS', ' openssl-native:do_populate_sysroot \
+ ${SIGNING_KEY_DEPENDS} \
+ ${PN}:do_copy_signing_pubkey')
+}
+
+
+# Options for the device tree compiler passed to mkimage '-D' feature:
+UBOOT_MKIMAGE_DTCOPTS ??= ""
+
+#
+# Emit the fitImage ITS header
+#
+# $1 ... .its filename
+fitimage_emit_fit_header() {
+ cat << EOF >> ${1}
+/dts-v1/;
+
+/ {
+ description = "U-Boot fitImage for ${DISTRO_NAME}/${PV}/${MACHINE}";
+ #address-cells = <1>;
+EOF
+}
+
+#
+# Emit the fitImage section bits
+#
+# $1 ... .its filename
+# $2 ... Section bit type: imagestart - image section start
+# confstart - configuration section start
+# sectend - section end
+# fitend - fitimage end
+#
+fitimage_emit_section_maint() {
+ case $2 in
+ imagestart)
+ cat << EOF >> ${1}
+
+ images {
+EOF
+ ;;
+ confstart)
+ cat << EOF >> ${1}
+
+ configurations {
+EOF
+ ;;
+ sectend)
+ cat << EOF >> ${1}
+ };
+EOF
+ ;;
+ fitend)
+ cat << EOF >> ${1}
+};
+EOF
+ ;;
+ esac
+}
+
+#
+# Emit the fitImage ITS kernel section
+#
+# $1 ... .its filename
+# $2 ... Image counter
+# $3 ... Path to kernel image
+# $4 ... Compression type
+# $5 ... Hash type
+fitimage_emit_section_kernel() {
+
+ kernel_csum="${5}"
+
+ if [ -n "${kernel_csum}" ]; then
+ hash_blk=$(cat << EOF
+ hash@1 {
+ algo = "${kernel_csum}";
+ };
+EOF
+ )
+ fi
+
+ ENTRYPOINT=${UBOOT_ENTRYPOINT}
+ if [ -n "${UBOOT_ENTRYSYMBOL}" ]; then
+ ENTRYPOINT=`${HOST_PREFIX}nm vmlinux | \
+ awk '$3=="${UBOOT_ENTRYSYMBOL}" {print "0x"$1;exit}'`
+ fi
+
+ cat << EOF >> ${1}
+ kernel@${2} {
+ description = "Linux kernel";
+ data = /incbin/("${3}");
+ type = "kernel";
+ arch = "${UBOOT_ARCH}";
+ os = "linux";
+ compression = "${4}";
+ load = <${UBOOT_LOADADDRESS}>;
+ entry = <${ENTRYPOINT}>;
+ ${hash_blk}
+ };
+EOF
+}
+
+#
+# Emit the fitImage ITS DTB section
+#
+# $1 ... .its filename
+# $2 ... Image counter
+# $3 ... Path to DTB image
+# $4 ... Hash type
+fitimage_emit_section_dtb() {
+
+ dtb_csum="${4}"
+ if [ -n "${dtb_csum}" ]; then
+ hash_blk=$(cat << EOF
+ hash@1 {
+ algo = "${dtb_csum}";
+ };
+EOF
+ )
+ fi
+
+ cat << EOF >> ${1}
+ fdt@${2} {
+ description = "Flattened Device Tree blob";
+ data = /incbin/("${3}");
+ type = "flat_dt";
+ arch = "${UBOOT_ARCH}";
+ compression = "none";
+ ${hash_blk}
+ };
+EOF
+}
+
+#
+# Emit the fitImage ITS setup section
+#
+# $1 ... .its filename
+# $2 ... Image counter
+# $3 ... Path to setup image
+# $4 ... Hash type
+fitimage_emit_section_setup() {
+
+ setup_csum="${4}"
+ if [ -n "${setup_csum}" ]; then
+ hash_blk=$(cat << EOF
+ hash@1 {
+ algo = "${setup_csum}";
+ };
+EOF
+ )
+ fi
+
+ cat << EOF >> ${1}
+ setup@${2} {
+ description = "Linux setup.bin";
+ data = /incbin/("${3}");
+ type = "x86_setup";
+ arch = "${UBOOT_ARCH}";
+ os = "linux";
+ compression = "none";
+ load = <0x00090000>;
+ entry = <0x00090000>;
+ ${hash_blk}
+ };
+EOF
+}
+
+#
+# Emit the fitImage ITS ramdisk section
+#
+# $1 ... .its filename
+# $2 ... Image counter
+# $3 ... Path to ramdisk image
+# $4 ... Hash type
+fitimage_emit_section_ramdisk() {
+
+ ramdisk_csum="${4}"
+ if [ -n "${ramdisk_csum}" ]; then
+ hash_blk=$(cat << EOF
+ hash@1 {
+ algo = "${ramdisk_csum}";
+ };
+EOF
+ )
+ fi
+ ramdisk_ctype="none"
+ ramdisk_loadline=""
+ ramdisk_entryline=""
+
+ if [ -n "${UBOOT_RD_LOADADDRESS}" ]; then
+ ramdisk_loadline="load = <${UBOOT_RD_LOADADDRESS}>;"
+ fi
+ if [ -n "${UBOOT_RD_ENTRYPOINT}" ]; then
+ ramdisk_entryline="entry = <${UBOOT_RD_ENTRYPOINT}>;"
+ fi
+
+ case $3 in
+ *.gz)
+ ramdisk_ctype="gzip"
+ ;;
+ *.bz2)
+ ramdisk_ctype="bzip2"
+ ;;
+ *.lzma)
+ ramdisk_ctype="lzma"
+ ;;
+ *.lzo)
+ ramdisk_ctype="lzo"
+ ;;
+ *.lz4)
+ ramdisk_ctype="lz4"
+ ;;
+ esac
+
+ cat << EOF >> ${1}
+ ramdisk@${2} {
+ description = "${INITRAMFS_IMAGE}";
+ data = /incbin/("${3}");
+ type = "ramdisk";
+ arch = "${UBOOT_ARCH}";
+ os = "linux";
+ compression = "${ramdisk_ctype}";
+ ${ramdisk_loadline}
+ ${ramdisk_entryline}
+ ${hash_blk}
+ };
+EOF
+}
+
+#
+# Emit the fitImage ITS configuration section
+#
+# $1 ... .its filename
+# $2 ... Linux kernel ID
+# $3 ... DTB image name
+# $4 ... ramdisk ID
+# $5 ... config ID
+# $6 ... default flag
+# $7 ... Hash type
+fitimage_emit_section_config() {
+
+ conf_csum="${7}"
+ if [ -n "${conf_csum}" ]; then
+ hash_blk=$(cat << EOF
+ hash@1 {
+ algo = "${conf_csum}";
+ };
+EOF
+ )
+ fi
+ if [ -n "${UBOOT_SIGN_ENABLE}" ] ; then
+ conf_sign_keyname="${UBOOT_SIGN_KEYNAME}"
+ fi
+
+ # Test if we have any DTBs at all
+ conf_desc="Linux kernel"
+ kernel_line="kernel = \"kernel@${2}\";"
+ fdt_line=""
+ ramdisk_line=""
+ setup_line=""
+ default_line=""
+
+ if [ -n "${3}" ]; then
+ conf_desc="${conf_desc}, FDT blob"
+ fdt_line="fdt = \"fdt@${3}\";"
+ fi
+
+ if [ -n "${4}" ]; then
+ conf_desc="${conf_desc}, ramdisk"
+ ramdisk_line="ramdisk = \"ramdisk@${4}\";"
+ fi
+
+ if [ -n "${5}" ]; then
+ conf_desc="${conf_desc}, setup"
+ setup_line="setup = \"setup@${5}\";"
+ fi
+
+ if [ "${6}" = "1" ]; then
+ default_line="default = \"conf@${3}\";"
+ fi
+
+ cat << EOF >> ${1}
+ ${default_line}
+ conf@${3} {
+ description = "${6} ${conf_desc}";
+ ${kernel_line}
+ ${fdt_line}
+ ${ramdisk_line}
+ ${setup_line}
+ ${hash_blk}
+EOF
+
+ if [ ! -z "${conf_sign_keyname}" ] ; then
+
+ sign_line="sign-images = \"kernel\""
+
+ if [ -n "${3}" ]; then
+ sign_line="${sign_line}, \"fdt\""
+ fi
+
+ if [ -n "${4}" ]; then
+ sign_line="${sign_line}, \"ramdisk\""
+ fi
+
+ if [ -n "${5}" ]; then
+ sign_line="${sign_line}, \"setup\""
+ fi
+
+ sign_line="${sign_line};"
+
+ cat << EOF >> ${1}
+ signature@1 {
+ algo = "${conf_csum},rsa2048";
+ key-name-hint = "${conf_sign_keyname}";
+ ${sign_line}
+ };
+EOF
+ fi
+
+ cat << EOF >> ${1}
+ };
+EOF
+}
+
+#
+# Assemble fitImage
+#
+# $1 ... .its filename
+# $2 ... fitImage name
+# $3 ... include rootfs
+fitimage_assemble() {
+ kernelcount=1
+ dtbcount=""
+ DTBS=""
+ ramdiskcount=${3}
+ setupcount=""
+ #hash_type="sha256"
+ hash_type=""
+ rm -f ${1} ${2}
+
+ #
+ # Step 0: find the kernel image in the deploy/images/$machine dir
+ #
+ KIMG=""
+ for KTYPE in zImage bzImage vmlinuz; do
+ if [ -e "${DEPLOY_DIR_IMAGE}/${ktype}" ]; then
+ KIMG="${DEPLOY_DIR_IMAGE}/${KTYPE}"
+ break
+ fi
+ done
+ if [ -z "${KIMG}" ]; then
+ bbdebug 1 "Failed to find kernel image to pack into full fitimage"
+ return 1
+ fi
+
+ fitimage_emit_fit_header ${1}
+
+ #
+ # Step 1: Prepare a kernel image section.
+ #
+ fitimage_emit_section_maint ${1} imagestart
+
+ fitimage_emit_section_kernel ${1} "${kernelcount}" "${KIMG}" "none" "${hash_type}"
+
+ #
+ # Step 2: Prepare a DTB image section
+ #
+ if [ -n "${KERNEL_DEVICETREE}" ]; then
+ dtbcount=1
+ for DTB in ${KERNEL_DEVICETREE}; do
+ if echo ${DTB} | grep -q '/dts/'; then
+ bberror "${DTB} contains the full path to the the dts file, but only the dtb name should be used."
+ DTB=`basename ${DTB} | sed 's,\.dts$,.dtb,g'`
+ fi
+ DTB_PATH="${DEPLOY_DIR_IMAGE}/${DTB}"
+ if [ ! -e "${DTB_PATH}" ]; then
+ bbwarn "${DTB_PATH} does not exist"
+ continue
+ fi
+
+ DTB=$(echo "${DTB}" | tr '/' '_')
+ DTBS="${DTBS} ${DTB}"
+ fitimage_emit_section_dtb ${1} ${DTB} ${DTB_PATH} "${hash_type}"
+ done
+ fi
+
+ #
+ # Step 3: Prepare a setup section. (For x86)
+ #
+ if [ -e arch/${ARCH}/boot/setup.bin ]; then
+ setupcount=1
+ fitimage_emit_section_setup ${1} "${setupcount}" arch/${ARCH}/boot/setup.bin "${hash_type}"
+ fi
+
+ #
+ # Step 4: Prepare a ramdisk section.
+ #
+ if [ "x${ramdiskcount}" = "x1" ] ; then
+ bbdebug 1 "searching for requested rootfs"
+ # Find and use the first initramfs image archive type we find
+ for img in squashfs-lz4 squashfs-xz squashfs cpio.lz4 cpio.lzo cpio.lzma cpio.xz cpio.gz cpio; do
+ initramfs_path="${DEPLOY_DIR_IMAGE}/${IMAGE_BASENAME}-${MACHINE}.${img}"
+ bbdebug 1 "looking for ${initramfs_path}"
+ if [ -e "${initramfs_path}" ]; then
+ bbdebug 1 "Found ${initramfs_path}"
+ fitimage_emit_section_ramdisk ${1} "${ramdiskcount}" "${initramfs_path}" "${hash_type}"
+ break
+ fi
+ done
+ fi
+
+ fitimage_emit_section_maint ${1} sectend
+
+ # Force the first Kernel and DTB in the default config
+ kernelcount=1
+ if [ -n "${dtbcount}" ]; then
+ dtbcount=1
+ fi
+
+ #
+ # Step 5: Prepare a configurations section
+ #
+ fitimage_emit_section_maint ${1} confstart
+
+ if [ -n "${DTBS}" ]; then
+ i=1
+ for DTB in ${DTBS}; do
+ fitimage_emit_section_config ${1} "${kernelcount}" "${DTB}" "${ramdiskcount}" "${setupcount}" "`expr ${i} = ${dtbcount}`" "${hash_type}"
+ i=`expr ${i} + 1`
+ done
+ fi
+
+ fitimage_emit_section_maint ${1} sectend
+
+ fitimage_emit_section_maint ${1} fitend
+
+ #
+ # Step 6: Assemble the image
+ #
+ uboot-mkimage \
+ ${@'-D "${UBOOT_MKIMAGE_DTCOPTS}"' if len('${UBOOT_MKIMAGE_DTCOPTS}') else ''} \
+ -f ${1} ${2}
+
+ #
+ # Step 7: Sign the image and add public key to U-Boot dtb
+ #
+ if [ "x${UBOOT_SIGN_ENABLE}" = "x1" ] ; then
+ uboot-mkimage \
+ ${@'-D "${UBOOT_MKIMAGE_DTCOPTS}"' if len('${UBOOT_MKIMAGE_DTCOPTS}') else ''} \
+ -F -k "${UBOOT_SIGN_KEYDIR}" \
+ -K "${DEPLOY_DIR_IMAGE}/${UBOOT_DTB_BINARY}" \
+ -r ${2}
+ fi
+}
+
+python do_generate_phosphor_manifest() {
+ import os.path
+ b = d.getVar('B', True)
+ manifest_filename = os.path.join(b, "MANIFEST")
+ version = do_get_version(d)
+ with open(manifest_filename, 'w') as fd:
+ fd.write('purpose=xyz.openbmc_project.Software.Version.VersionPurpose.BMC\n')
+ fd.write('version={}\n'.format(version.strip('"')))
+ fd.write('KeyType={}\n'.format("OpenBMC"))
+ fd.write('HashType=RSA-SHA256\n')
+}
+
+make_signatures() {
+ signature_files=""
+ for file in "$@"; do
+ openssl dgst -sha256 -sign ${SIGNING_KEY} -out "${file}.sig" $file
+ signature_files="${signature_files} ${file}.sig"
+ done
+}
+
+def get_pubkey_type(d):
+ return os.listdir(get_pubkey_basedir(d))[0]
+
+def get_pubkey_path(d):
+ return os.path.join(
+ get_pubkey_basedir(d),
+ get_pubkey_type(d),
+ 'publickey')
+python do_copy_signing_pubkey() {
+ with open(get_pubkey_path(d), 'r') as read_fd:
+ with open('publickey', 'w') as write_fd:
+ write_fd.write(read_fd.read())
+}
+
+do_copy_signing_pubkey[dirs] = "${S}"
+do_copy_signing_pubkey[depends] += " \
+ phosphor-image-signing:do_populate_sysroot \
+ "
+
+do_image_fitimage_rootfs() {
+ bbdebug 1 "check for rootfs phosphor fitimage"
+ cd ${B}
+ bbdebug 1 "building rootfs phosphor fitimage"
+ fitimage_assemble fitImage-rootfs-${MACHINE}-${DATETIME}.its \
+ fitImage-rootfs-${MACHINE}-${DATETIME}.bin 1
+
+ for SFX in its bin; do
+ SRC="fitImage-rootfs-${MACHINE}-${DATETIME}.${SFX}"
+ SYM="fitImage-rootfs-${MACHINE}.${SFX}"
+ if [ -e "${B}/${SRC}" ]; then
+ install -m 0644 "${B}/${SRC}" "${DEPLOY_DIR_IMAGE}/${SRC}"
+ ln -sf "${SRC}" "${DEPLOY_DIR_IMAGE}/${SYM}"
+ fi
+ done
+ ln -sf "${DEPLOY_DIR_IMAGE}/fitImage-rootfs-${MACHINE}.bin" "image-runtime"
+ # build a tarball with the right parts: MANIFEST, signatures, etc.
+ # create a directory for the tarball
+ mkdir -p "${B}/img"
+ cd "${B}/img"
+ # add symlinks for the contents
+ ln -sf "${DEPLOY_DIR_IMAGE}/u-boot.${UBOOT_SUFFIX}" "image-u-boot"
+ ln -sf "${DEPLOY_DIR_IMAGE}/fitImage-rootfs-${MACHINE}.bin" "image-runtime"
+ # add the manifest
+ bbdebug 1 "Manifest file: ${B}/MANIFEST"
+ ln -sf ${B}/MANIFEST .
+ # touch the required files to minimize change
+ touch image-kernel image-rofs image-rwfs
+
+ if [ "${IMAGE_TYPE}" = "pfr" ]; then
+ ln -sf ${S}/publickey publickey
+ make_signatures image-u-boot image-kernel image-rofs image-rwfs image-runtime MANIFEST publickey
+ # tar up the update package
+ tar -h -cvf "${DEPLOY_DIR_IMAGE}/${PN}-image-update-${MACHINE}-${DATETIME}.tar" image-u-boot image-runtime image-kernel image-rofs image-rwfs MANIFEST publickey ${signature_files}
+ else
+ tar -h -cvf "${DEPLOY_DIR_IMAGE}/${PN}-image-update-${MACHINE}-${DATETIME}.tar" MANIFEST image-u-boot image-runtime image-kernel image-rofs image-rwfs
+ fi
+ # make a symlink
+ ln -sf "${PN}-image-update-${MACHINE}-${DATETIME}.tar" "${DEPLOY_DIR_IMAGE}/image-update-${MACHINE}"
+ ln -sf "image-update-${MACHINE}" "${DEPLOY_DIR_IMAGE}/image-update"
+}
+
+do_image_fitimage_rootfs[vardepsexclude] = "DATETIME"
+do_image_fitimage_rootfs[depends] += " ${DEPS}"
+
+
+addtask do_image_fitimage_rootfs before do_generate_auto after do_image_complete
+addtask do_generate_phosphor_manifest before do_image_fitimage_rootfs after do_image_complete
diff --git a/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass
new file mode 100644
index 000000000..f10b2389f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass
@@ -0,0 +1,38 @@
+inherit obmc-phosphor-image
+
+IMAGE_INSTALL_append = " \
+ fan-default-speed \
+ bmcweb \
+ dbus-broker \
+ dtc \
+ dtoverlay \
+ entity-manager \
+ ipmitool \
+ ipmi-providers \
+ intel-ipmi-oem \
+ phosphor-ipmi-ipmb \
+ phosphor-node-manager-proxy \
+ dbus-sensors \
+ phosphor-webui \
+ rest-dbus-static \
+ phosphor-pid-control \
+ phosphor-host-postd \
+ smbios-mdrv1 \
+ phosphor-certificate-manager \
+ set-passthrough \
+ phosphor-sel-logger \
+ gpiodaemon \
+ smbios-mdrv2 \
+ obmc-ikvm \
+ system-watchdog \
+ frb2-watchdog \
+ srvcfg-manager \
+ callback-manager \
+ post-code-manager \
+ preinit-mounts \
+ mtd-utils-ubifs \
+ "
+
+# this package was flagged as a security risk
+IMAGE_INSTALL_remove += " lrzsz"
+
diff --git a/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-dev.bbclass b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-dev.bbclass
new file mode 100644
index 000000000..6a1ac3f14
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-dev.bbclass
@@ -0,0 +1,7 @@
+IMAGE_INSTALL_append = " \
+ mtd-util \
+ io-app \
+ intel-fw-update \
+ lpc-cmds \
+ beeper-test \
+ "
diff --git a/meta-openbmc-mods/meta-common/conf/layer.conf b/meta-openbmc-mods/meta-common/conf/layer.conf
new file mode 100644
index 000000000..7e61bfd50
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/conf/layer.conf
@@ -0,0 +1,11 @@
+# We have a conf and classes directory, add to BBPATH
+BBPATH .= ":${LAYERDIR}"
+
+# We have recipes-* directories, add to BBFILES
+BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
+ ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "common"
+BBFILE_PATTERN_common = "^${LAYERDIR}/"
+BBFILE_PRIORITY_common = "10"
+LAYERSERIES_COMPAT_common = "thud"
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-flash-use-readX-writeX-not-udelay.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-flash-use-readX-writeX-not-udelay.patch
new file mode 100644
index 000000000..73ab78a65
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0001-flash-use-readX-writeX-not-udelay.patch
@@ -0,0 +1,424 @@
+Index: u-boot/arch/arm/mach-aspeed/flash.c
+===================================================================
+--- u-boot.orig/arch/arm/mach-aspeed/flash.c
++++ u-boot/arch/arm/mach-aspeed/flash.c
+@@ -28,6 +28,7 @@
+ #include <common.h>
+ #include <asm/processor.h>
+ #include <asm/byteorder.h>
++#include <asm/io.h>
+ #include <environment.h>
+
+ #include <asm/arch/ast_scu.h>
+@@ -199,7 +200,7 @@ static void reset_flash (flash_info_t *
+ if (info->dualport)
+ ulCtrlData |= 0x08;
+ #endif
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+
+ }
+
+@@ -228,28 +229,22 @@ static void enable_write (flash_info_t *
+
+ ulCtrlData = (info->tCK_Write << 8);
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0x06);
+- udelay(10);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0x06, base);
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0x05);
+- udelay(10);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0x05, base);
+ do {
+- jReg = *(volatile uchar *) (base);
++ jReg = readb(base);
+ } while (!(jReg & 0x02));
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+
+ }
+
+@@ -280,30 +275,23 @@ static void write_status_register (flash
+
+ ulCtrlData = (info->tCK_Write << 8);
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0x01);
+- udelay(10);
+- *(uchar *) (base) = (uchar) (data);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0x01, base);
++ writeb(data, base);
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0x05);
+- udelay(10);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0x05, base);
+ do {
+- jReg = *(volatile uchar *) (base);
++ jReg = readb(base);
+ } while (jReg & 0x01);
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+-
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+ }
+
+ static void enable4b (flash_info_t * info)
+@@ -330,13 +318,11 @@ static void enable4b (flash_info_t * inf
+
+ ulCtrlData = (info->tCK_Write << 8);
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0xb7);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0xb7, base);
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+
+ } /* enable4b */
+
+@@ -366,29 +352,23 @@ static void enable4b_spansion (flash_inf
+ /* Enable 4B: BAR0 D[7] = 1 */
+ ulCtrlData = (info->tCK_Write << 8);
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0x17);
+- udelay(10);
+- *(uchar *) (base) = (uchar) (0x80);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0x17, base);
++ writeb(0x80, base);
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0x16);
+- udelay(10);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0x16, base);
+ do {
+- jReg = *(volatile uchar *) (base);
++ jReg = readb(base);
+ } while (!(jReg & 0x80));
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+
+ } /* enable4b_spansion */
+
+@@ -420,14 +400,11 @@ static void enable4b_numonyx (flash_info
+ /* Enable 4B: CMD:0xB7 */
+ ulCtrlData = (info->tCK_Write << 8);
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0xB7);
+- udelay(10);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0xB7, base);
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+
+ } /* enable4b_numonyx */
+
+@@ -463,63 +440,49 @@ static void flash_write_buffer (flash_in
+
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0x02);
+- udelay(10);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0x02, base);
+ if (info->address32)
+ {
+- *(uchar *) (base) = (uchar) ((offset & 0xff000000) >> 24);
+- udelay(10);
++ writeb((uchar) ((offset & 0xff000000) >> 24), base);
+ }
+- *(uchar *) (base) = (uchar) ((offset & 0xff0000) >> 16);
+- udelay(10);
+- *(uchar *) (base) = (uchar) ((offset & 0x00ff00) >> 8);
+- udelay(10);
+- *(uchar *) (base) = (uchar) ((offset & 0x0000ff));
+- udelay(10);
++ writeb((uchar) ((offset & 0xff0000) >> 16), base);
++ writeb((uchar) ((offset & 0x00ff00) >> 8), base);
++ writeb((uchar) ((offset & 0x0000ff)), base);
+
+ for (j=0; j<len; j++)
+ {
+- *(uchar *) (base) = *(uchar *) (src++);
+- udelay(10);
++ writeb(*src++, base);
+ }
+
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0x05);
+- udelay(10);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0x05, base);
+ do {
+- jReg = *(volatile uchar *) (base);
++ jReg = readb(base);
+ } while ((jReg & 0x01));
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+
+ /* RFSR */
+ if (info->specificspi == SpecificSPI_N25Q512)
+ {
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0x70);
+- udelay(10);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0x70, base);
+ do {
+- jReg = *(volatile uchar *) (base);
++ jReg = readb(base);
+ } while (!(jReg & 0x80));
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+ }
+ }
+
+@@ -603,57 +566,44 @@ int flash_erase (flash_info_t * info, in
+
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0xd8);
+- udelay(10);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0xd8, base);
+ if (info->address32)
+ {
+- *(uchar *) (base) = (uchar) ((offset & 0xff000000) >> 24);
+- udelay(10);
++ writeb((uchar) ((offset & 0xff000000) >> 24), base);
+ }
+- *(uchar *) (base) = (uchar) ((offset & 0xff0000) >> 16);
+- udelay(10);
+- *(uchar *) (base) = (uchar) ((offset & 0x00ff00) >> 8);
+- udelay(10);
+- *(uchar *) (base) = (uchar) ((offset & 0x0000ff));
+- udelay(10);
++ writeb((uchar) ((offset & 0xff0000) >> 16), base);
++ writeb((uchar) ((offset & 0x00ff00) >> 8), base);
++ writeb((uchar) ((offset & 0x0000ff)), base);
+
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0x05);
+- udelay(10);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0x05, base);
+ do {
+- jReg = *(volatile uchar *) (base);
++ jReg = readb(base);
+ } while ((jReg & 0x01));
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+
+ /* RFSR */
+ if (info->specificspi == SpecificSPI_N25Q512)
+ {
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (base) = (uchar) (0x70);
+- udelay(10);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0x70, base);
+ do {
+- jReg = *(volatile uchar *) (base);
++ jReg = readb(base);
+ } while (!(jReg & 0x80));
+ ulCtrlData &= CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+ }
+
+ putc ('.');
+@@ -764,22 +714,16 @@ static ulong flash_get_size (ulong base,
+ }
+
+ /* Get Flash ID */
+- ulCtrlData = *(ulong *) (info->reg_base + CtrlOffset) & CMD_MASK;
++ ulCtrlData = readl(info->reg_base + CtrlOffset) & CMD_MASK;
+ ulCtrlData |= CE_LOW | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
+- *(uchar *) (vbase) = (uchar) (0x9F);
+- udelay(10);
+- ch[0] = *(volatile uchar *)(vbase);
+- udelay(10);
+- ch[1] = *(volatile uchar *)(vbase);
+- udelay(10);
+- ch[2] = *(volatile uchar *)(vbase);
+- udelay(10);
+- ulCtrlData = *(ulong *) (info->reg_base + CtrlOffset) & CMD_MASK;
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
++ writeb(0x9F, vbase);
++ ch[0] = readb(vbase);
++ ch[1] = readb(vbase);
++ ch[2] = readb(vbase);
++ ulCtrlData = readl(info->reg_base + CtrlOffset) & CMD_MASK;
+ ulCtrlData |= CE_HIGH | USERMODE;
+- *(ulong *) (info->reg_base + CtrlOffset) = ulCtrlData;
+- udelay(200);
++ writel(ulCtrlData, info->reg_base + CtrlOffset);
+ ulID = ((ulong)ch[0]) | ((ulong)ch[1] << 8) | ((ulong)ch[2] << 16) ;
+ info->flash_id = ulID;
+
+@@ -1294,13 +1238,13 @@ static ulong flash_get_size (ulong base,
+
+ if (info->address32) {
+ #ifndef AST_SOC_G5
+- reg = *((volatile ulong*) 0x1e6e2070); /* set H/W Trappings */
++ reg = readl(0x1e6e2070); /* set H/W Trappings */
+ reg |= 0x10;
+- *((volatile ulong*) 0x1e6e2070) = reg;
++ writel(reg, 0x1e6e2070);
+ #endif
+- reg = *((volatile ulong*) (info->reg_base + 0x4)); /* enable 32b control bit*/
++ reg = readl(info->reg_base + 0x4); /* enable 32b control bit*/
+ reg |= (0x01 << info->CE);
+- *((volatile ulong*) (info->reg_base + 0x4)) = reg;
++ writel(reg, info->reg_base + 0x4);
+
+ /* set flash chips to 32bits addressing mode */
+ if ((info->flash_id & 0xFF) == 0x01) /* Spansion */
+@@ -1322,7 +1266,7 @@ unsigned long flash_init (void)
+ unsigned long size = 0;
+ int i;
+
+- *((volatile ulong*) AST_FMC_BASE) |= 0x800f0000; /* enable Flash Write */
++ writel(readl(AST_FMC_BASE) | 0x800f0000, AST_FMC_BASE); /* enable Flash Write */
+
+ /* Init: FMC */
+ /* BANK 0 : FMC CS0 , 1: FMC CS1, */
+@@ -1352,7 +1296,7 @@ unsigned long flash_init (void)
+ #ifdef CONFIG_SPI0_CS
+ //pin switch by trap[13:12] -- [0:1] Enable SPI Master
+ ast_scu_spi_master(1); /* enable SPI master */
+- *((volatile ulong*) AST_FMC_SPI0_BASE) |= 0x10000; /* enable Flash Write */
++ writel(readl(AST_FMC_SPI0_BASE) | 0x10000, AST_FMC_SPI0_BASE); /* enable Flash Write */
+ flash_info[CONFIG_FMC_CS].sysspi = 1;
+ flash_info[CONFIG_FMC_CS].reg_base = AST_FMC_SPI0_BASE;
+ flash_info[CONFIG_FMC_CS].flash_id = FLASH_UNKNOWN;
+@@ -1403,21 +1347,24 @@ void memmove_dma(void * dest,const void
+ poll_time = 100; /* set 100 us as default */
+
+ /* force end of burst read */
+- *(volatile ulong *) (AST_FMC_BASE + CS0_CTRL) |= CE_HIGH;
+- *(volatile ulong *) (AST_FMC_BASE + CS0_CTRL) &= ~CE_HIGH;
+-
+- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_CONTROL) = (ulong) (~FLASH_DMA_ENABLE);
+- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_FLASH_BASE) = (ulong) (src);
+- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_DRAM_BASE) = (ulong) (dest);
+- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_LENGTH) = (ulong) (count_align);
+- *(ulong *) (AST_FMC_BASE + REG_FLASH_DMA_CONTROL) = (ulong) (FLASH_DMA_ENABLE);
++ data = readl(AST_FMC_BASE + CS0_CTRL);
++ writel(data | CE_HIGH, AST_FMC_BASE + CS0_CTRL);
++ writel(data & ~CE_HIGH, AST_FMC_BASE + CS0_CTRL);
++
++ writel(~FLASH_DMA_ENABLE, AST_FMC_BASE + REG_FLASH_DMA_CONTROL);
++ writel((ulong)src, AST_FMC_BASE + REG_FLASH_DMA_FLASH_BASE);
++ writel((ulong)dest, AST_FMC_BASE + REG_FLASH_DMA_DRAM_BASE);
++ writel(count_align, AST_FMC_BASE + REG_FLASH_DMA_LENGTH);
++ writel(FLASH_DMA_ENABLE, AST_FMC_BASE + REG_FLASH_DMA_CONTROL);
+
+ /* wait poll */
+ do {
+ udelay(poll_time);
+- data = *(ulong *) (AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS);
++ data = readl(AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS);
+ } while (!(data & FLASH_STATUS_DMA_READY));
+
+ /* clear status */
+- *(ulong *) (AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS) |= FLASH_STATUS_DMA_CLEAR;
++ data = readl(AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS);
++ writel(data | FLASH_STATUS_DMA_CLEAR,
++ AST_FMC_BASE + REG_FLASH_INTERRUPT_STATUS);
+ }
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0002-intel-layout-environment-addr.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0002-intel-layout-environment-addr.patch
new file mode 100644
index 000000000..86fa5b7d5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0002-intel-layout-environment-addr.patch
@@ -0,0 +1,42 @@
+Index: u-boot/include/configs/ast-common.h
+===================================================================
+--- u-boot.orig/include/configs/ast-common.h
++++ u-boot/include/configs/ast-common.h
+@@ -103,10 +103,13 @@
+ #define CONFIG_SYS_MAX_FLASH_BANKS (CONFIG_FMC_CS)
+ #define CONFIG_SYS_MAX_FLASH_SECT (8192) /* max number of sectors on one chip */
+ #define CONFIG_ENV_IS_IN_FLASH 1
+-#define CONFIG_ENV_ADDR (AST_FMC_CS0_BASE + 0x60000)
++#define CONFIG_ENV_OFFSET 0x2400000 /* environment starts here */
++#define CONFIG_ENV_ADDR (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET)
++#define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */
+
+-#define CONFIG_ENV_OFFSET 0x60000 /* environment starts here */
+-#define CONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */
++#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE)
++#define CONFIG_ENV_ADDR_REDUND (AST_FMC_CS0_BASE + CONFIG_ENV_OFFSET_REDUND)
++#define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE
+
+ #define CONFIG_BOOTCOMMAND "bootm 20080000"
+ #define CONFIG_ENV_OVERWRITE
+Index: u-boot/common/board_r.c
+===================================================================
+--- u-boot.orig/common/board_r.c
++++ u-boot/common/board_r.c
+@@ -494,10 +494,14 @@ static int should_load_env(void)
+ static int initr_env(void)
+ {
+ /* initialize environment */
+- if (should_load_env())
++ if (should_load_env()) {
++ /* try again, in case the environment failed to load the first time */
++ if (!gd->env_valid)
++ env_init();
+ env_relocate();
+- else
++ } else {
+ set_default_env(NULL);
++ }
+ #ifdef CONFIG_OF_CONTROL
+ setenv_addr("fdtcontroladdr", gd->fdt_blob);
+ #endif
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch
new file mode 100644
index 000000000..8bc0a3ed3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch
@@ -0,0 +1,75 @@
+From 2f0e14630abec2c9679d21901072648c7802f2c4 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Tue, 11 Sep 2018 16:24:06 +0800
+Subject: [PATCH] Make sure debug uart is using 24MHz clock source
+
+u-boot defines the uart5(debug console) as 24MHz,
+set the SCU14[28] to 0, to make sure the clock source is 24M
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ arch/arm/include/asm/arch-aspeed/ast_scu.h | 2 ++
+ arch/arm/include/asm/arch-aspeed/platform.h | 1 +
+ arch/arm/mach-aspeed/ast-scu.c | 6 ++++++
+ board/aspeed/ast-g5/ast-g5.c | 8 ++++++++
+ 4 files changed, 17 insertions(+)
+
+diff --git a/arch/arm/include/asm/arch-aspeed/ast_scu.h b/arch/arm/include/asm/arch-aspeed/ast_scu.h
+index d248416..98e6335 100644
+--- a/arch/arm/include/asm/arch-aspeed/ast_scu.h
++++ b/arch/arm/include/asm/arch-aspeed/ast_scu.h
+@@ -45,4 +45,6 @@ extern void ast_scu_init_eth(u8 num);
+ extern void ast_scu_multi_func_eth(u8 num);
+ extern void ast_scu_multi_func_romcs(u8 num);
+
++void ast_config_uart5_clk(void);
++
+ #endif
+diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h
+index c9c7a81..a423052 100644
+--- a/arch/arm/include/asm/arch-aspeed/platform.h
++++ b/arch/arm/include/asm/arch-aspeed/platform.h
+@@ -27,6 +27,7 @@
+ #include <asm/arch/ast2400_platform.h>
+ #elif defined(AST_SOC_G5)
+ #include <asm/arch/ast_g5_platform.h>
++#define CONFIG_BOARD_EARLY_INIT_F 1 /* Call board_early_init_f */
+ #else
+ #err "No define for platform.h"
+ #endif
+diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c
+index 0cc0d67..902263b 100644
+--- a/arch/arm/mach-aspeed/ast-scu.c
++++ b/arch/arm/mach-aspeed/ast-scu.c
+@@ -496,3 +496,9 @@ void ast_scu_get_who_init_dram(void)
+ break;
+ }
+ }
++
++void ast_config_uart5_clk(void)
++{
++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) &
++ ~(1 << 28), AST_SCU_MISC2_CTRL);
++}
+diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c
+index e67a4bf..5a1fade 100644
+--- a/board/aspeed/ast-g5/ast-g5.c
++++ b/board/aspeed/ast-g5/ast-g5.c
+@@ -16,6 +16,14 @@
+
+ DECLARE_GLOBAL_DATA_PTR;
+
++int board_early_init_f(void)
++{
++ /* make sure uart5 is using 24MHz clock */
++ ast_config_uart5_clk();
++
++ return 0;
++}
++
+ int board_init(void)
+ {
+ gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch
new file mode 100644
index 000000000..0385a5e31
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0005-enable-passthrough-in-uboot.patch
@@ -0,0 +1,56 @@
+From b344cf4462acb1f043ed903ccee713e24ce7226d Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Wed, 7 Nov 2018 13:57:57 +0800
+Subject: [PATCH 1/1] enable passthrough in uboot
+
+---
+ arch/arm/mach-aspeed/ast-scu.c | 22 ++++++++++++++++++++++
+ board/aspeed/ast-g5/ast-g5.c | 2 ++
+ 2 files changed, 24 insertions(+)
+
+diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c
+index 902263b28b..c83931ed54 100644
+--- a/arch/arm/mach-aspeed/ast-scu.c
++++ b/arch/arm/mach-aspeed/ast-scu.c
+@@ -502,3 +502,25 @@ void ast_config_uart5_clk(void)
+ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) &
+ ~(1 << 28), AST_SCU_MISC2_CTRL);
+ }
++
++
++void ast_enable_pass_through(void)
++{
++ //Enable GPIOE pin mode, SCU80[16:23] = 00 */
++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL1) & (~0x00FF0000),
++ AST_SCU_FUN_PIN_CTRL1);
++
++ //Enable all pass through pins by setting SCU8C[15:12] = 0x3.
++ //Pass-through pins set:
++ //GPIOE0 -> GPIOE1
++ //GPIOE2 -> GPIOE3
++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL4) | (0x3000),
++ AST_SCU_FUN_PIN_CTRL4);
++
++ //Disable HWStrap for GPIOE pass-through mode
++ //The write operation to SCU70(0x1e6e2070) only can set to '1'.
++ //To clear to '0', it must write '1' to 0x1e6e207c
++ if (ast_scu_read(AST_SCU_HW_STRAP1) & (0x1 << 22)){
++ ast_scu_write((0x1 << 22), AST_SCU_REVISION_ID);
++ }
++}
+diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c
+index 5a1fadeedd..b492003f51 100644
+--- a/board/aspeed/ast-g5/ast-g5.c
++++ b/board/aspeed/ast-g5/ast-g5.c
+@@ -20,6 +20,8 @@ int board_early_init_f(void)
+ {
+ /* make sure uart5 is using 24MHz clock */
+ ast_config_uart5_clk();
++ /*enable pass through*/
++ ast_enable_pass_through();
+
+ return 0;
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0006-Add-Aspeed-g5-interrupt-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0006-Add-Aspeed-g5-interrupt-support.patch
new file mode 100644
index 000000000..dbaf7b362
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0006-Add-Aspeed-g5-interrupt-support.patch
@@ -0,0 +1,389 @@
+From f33755167ddcdebbf56bc875e4091990273c6997 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Wed, 14 Nov 2018 10:21:40 -0800
+Subject: [PATCH 1/7] Add Aspeed g5 interrupt support
+
+This adds a few new files to the board g5 directory. Several Intel
+features require interrupts running in U-Boot, so this adds basic
+interrupt registration and handling support.
+
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+Change-Id: Id7072f1408dcf364968b1b74f2192e50a22a82f0
+---
+ Kconfig | 13 ++
+ arch/arm/lib/interrupts.c | 11 ++
+ board/aspeed/ast-g5/Makefile | 4 +-
+ board/aspeed/ast-g5/ast-g5-irq.c | 176 ++++++++++++++++++++++++++++
+ board/aspeed/ast-g5/ast-g5-irq.h | 39 ++++++
+ board/aspeed/ast-g5/ast-g5.c | 3 +
+ board/aspeed/ast-g5/ast-g5.h | 7 ++
+ cmd/Kconfig | 5 +
+ configs/ast_g5_ncsi_2boot_defconfig | 1 +
+ configs/ast_g5_ncsi_defconfig | 1 +
+ configs/ast_g5_phy_defconfig | 1 +
+ 11 files changed, 260 insertions(+), 1 deletion(-)
+ create mode 100644 board/aspeed/ast-g5/ast-g5-irq.c
+ create mode 100644 board/aspeed/ast-g5/ast-g5-irq.h
+ create mode 100644 board/aspeed/ast-g5/ast-g5.h
+
+diff --git a/Kconfig b/Kconfig
+index 3ceff25032..d6439d01ca 100644
+--- a/Kconfig
++++ b/Kconfig
+@@ -115,6 +115,19 @@ if EXPERT
+ When disabling this, please check if malloc calls, maybe
+ should be replaced by calloc - if one expects zeroed memory.
+ endif
++
++config USE_IRQ
++ bool "Use interrupts"
++ default n
++
++config STACKSIZE_IRQ
++ int "Size for IRQ stack (only if USE_IRQ enabled)"
++ default 16384
++
++config STACKSIZE_FIQ
++ int "Size for FIQ stack (only if USE_IRQ enabled)"
++ default 16384
++
+ endmenu # General setup
+
+ menu "Boot images"
+diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c
+index ed83043abb..a96b3aa070 100644
+--- a/arch/arm/lib/interrupts.c
++++ b/arch/arm/lib/interrupts.c
+@@ -94,6 +94,17 @@ int disable_interrupts (void)
+ : "memory");
+ return (old & 0x80) == 0;
+ }
++
++int global_interrupts_enabled(void)
++{
++ unsigned long old;
++ __asm__ __volatile__("mrs %0, cpsr\n"
++ : "=r" (old)
++ :
++ : "memory");
++ return (old & 0x80) == 0;
++}
++
+ #else
+ int interrupt_init (void)
+ {
+diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile
+index d1d7f8525e..d41b11589f 100644
+--- a/board/aspeed/ast-g5/Makefile
++++ b/board/aspeed/ast-g5/Makefile
+@@ -1 +1,2 @@
+-obj-y = ast-g5.o
++obj-y += ast-g5.o
++obj-y += ast-g5-irq.o
+diff --git a/board/aspeed/ast-g5/ast-g5-irq.c b/board/aspeed/ast-g5/ast-g5-irq.c
+new file mode 100644
+index 0000000000..860f16cf05
+--- /dev/null
++++ b/board/aspeed/ast-g5/ast-g5-irq.c
+@@ -0,0 +1,176 @@
++/*
++ * Copyright 2018 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include <common.h>
++#include <netdev.h>
++
++#include <asm/arch/ast_scu.h>
++#include <asm/arch/ast-sdmc.h>
++#include <asm/io.h>
++
++#include "ast-g5.h"
++#include "ast-g5-irq.h"
++
++DECLARE_GLOBAL_DATA_PTR;
++
++#ifdef CONFIG_USE_IRQ
++
++#define VIC_STATUS_L 0x80
++#define VIC_STATUS_H 0x84
++#define VIC_IRQ_SELECTION_L 0x98
++#define VIC_IRQ_SELECTION_H 0x9C
++#define VIC_ENABLE_L 0xA0
++#define VIC_ENABLE_H 0xA4
++#define VIC_ENABLE_CLEAR_L 0xA8
++#define VIC_ENABLE_CLEAR_H 0xAC
++#define VIC_INTERRUPT_CLEAR_L 0xD8
++#define VIC_INTERRUPT_CLEAR_H 0xDC
++
++#define VIC_CLEAR_ALL (~0)
++
++int arch_interrupt_init_early(void)
++{
++ writel(VIC_CLEAR_ALL, AST_VIC_BASE + VIC_ENABLE_CLEAR_L);
++ writel(VIC_CLEAR_ALL, AST_VIC_BASE + VIC_ENABLE_CLEAR_H);
++ return 0;
++}
++int arch_interrupt_init(void)
++{
++ return 0;
++}
++
++#define AST_IRQ_START_L 0
++#define AST_IRQ_END_L 31
++#define AST_IRQ_START_H 32
++#define AST_IRQ_END_H 63
++#define AST_IRQ_COUNT 64
++static interrupt_handler_t *handlers[AST_IRQ_COUNT] = {NULL};
++static unsigned long irq_total = 0;
++static unsigned long irq_counts[AST_IRQ_COUNT] = {0};
++
++int request_irq(int irq, interrupt_handler_t *handler)
++{
++ if (irq < AST_IRQ_START_L || irq > AST_IRQ_END_H) {
++ printf("irq %d out of range\n", irq);
++ return -1;
++ }
++ if (handlers[irq]) {
++ printf("irq %d already in use (%p)\n", irq, handlers[irq]);
++ return -1;
++ }
++ handlers[irq] = handler;
++ if (irq < AST_IRQ_START_H) {
++ writel((1 << irq), AST_VIC_BASE + VIC_ENABLE_L);
++ } else {
++ writel((1 << (irq - AST_IRQ_START_H)),
++ AST_VIC_BASE + VIC_ENABLE_H);
++ }
++ return 0;
++}
++
++int release_irq(int irq)
++{
++ if (irq < AST_IRQ_START_L || irq > AST_IRQ_END_H) {
++ return -1;
++ }
++ if (handlers[irq]) {
++ handlers[irq] = NULL;
++ if (irq < AST_IRQ_START_H) {
++ writel((1 << irq), AST_VIC_BASE + VIC_ENABLE_CLEAR_L);
++ } else {
++ writel((1 << (irq - AST_IRQ_START_H)),
++ AST_VIC_BASE + VIC_ENABLE_CLEAR_H);
++ }
++ }
++ return 0;
++}
++
++extern int global_interrupts_enabled(void);
++int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
++{
++ int i;
++ int enabled = global_interrupts_enabled();
++ unsigned long long irqs_enabled =
++ ((unsigned long long)readl(AST_VIC_BASE + VIC_ENABLE_H))
++ << AST_IRQ_START_H
++ | readl(AST_VIC_BASE + VIC_ENABLE_L);
++ printf("interrupts %sabled\n", (enabled ? "en" : "dis"));
++ for (i = AST_IRQ_START_L; i < AST_IRQ_COUNT; i++) {
++ printf("% 2i (% 3s): %lu\n", i,
++ ((irqs_enabled & 1) ? "on" : "off"), irq_counts[i]);
++ irqs_enabled >>= 1;
++ }
++ printf("total: %lu\n", irq_total);
++ return 0;
++}
++
++void do_irq(struct pt_regs *pt_regs)
++{
++ uint32_t irq = readl(AST_VIC_BASE + VIC_STATUS_L);
++ int i;
++ irq_total++;
++ if (irq) {
++ // handler irq0-31
++ for (i = AST_IRQ_START_L; i <= AST_IRQ_END_L; i++) {
++ if (irq & (1 << i)) {
++ irq_counts[i]++;
++ /* mask */
++ writel((1 << i),
++ AST_VIC_BASE + VIC_ENABLE_CLEAR_L);
++ if (handlers[i]) {
++ handlers[i](pt_regs);
++ /* clear */
++ writel((1 << i),
++ AST_VIC_BASE
++ + VIC_INTERRUPT_CLEAR_L);
++ /* unmask */
++ writel((1 << i),
++ AST_VIC_BASE + VIC_ENABLE_L);
++ } else {
++ printf("unexpected interrupt %i; masking\n",
++ i);
++ /* clear; do not unmask */
++ writel((1 << i),
++ AST_VIC_BASE
++ + VIC_INTERRUPT_CLEAR_L);
++ }
++ }
++ }
++ }
++ irq = readl(AST_VIC_BASE + VIC_STATUS_H);
++ if (irq) {
++ // handler irq32-63
++ for (i = AST_IRQ_START_H; i <= AST_IRQ_END_H; i++) {
++ if (irq & (1 << (i - AST_IRQ_START_H))) {
++ irq_counts[i]++;
++ /* mask */
++ writel((1 << (i - AST_IRQ_START_H)),
++ AST_VIC_BASE + VIC_ENABLE_CLEAR_H);
++ if (handlers[i]) {
++ handlers[i](pt_regs);
++ /* clear */
++ writel((1 << (i - AST_IRQ_START_H)),
++ AST_VIC_BASE
++ + VIC_INTERRUPT_CLEAR_H);
++ /* unmask */
++ writel((1 << (i - AST_IRQ_START_H)),
++ AST_VIC_BASE + VIC_ENABLE_H);
++ } else {
++ printf("unexpected interrupt %i; masking\n",
++ i);
++ /* clear; do not unmask */
++ writel((1 << (i - AST_IRQ_START_H)),
++ AST_VIC_BASE
++ + VIC_INTERRUPT_CLEAR_H);
++ }
++ }
++ }
++ }
++}
++#endif
+diff --git a/board/aspeed/ast-g5/ast-g5-irq.h b/board/aspeed/ast-g5/ast-g5-irq.h
+new file mode 100644
+index 0000000000..703eeabf13
+--- /dev/null
++++ b/board/aspeed/ast-g5/ast-g5-irq.h
+@@ -0,0 +1,39 @@
++/*
++ * Copyright 2018 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#ifndef __AST_G5_IRQ_H__
++#define __AST_G5_IRQ_H__
++
++#include <common.h>
++
++#ifdef CONFIG_USE_IRQ
++
++int arch_interrupt_init_early(void);
++
++int request_irq(int irq, interrupt_handler_t *handler);
++
++int release_irq(int irq);
++
++#else /* CONFIG_USE_IRQ */
++
++int arch_interrupt_init_early(void) {
++ return 0;
++}
++
++int request_irq(int irq, interrupt_handler_t *handler) {
++ return -1;
++}
++
++int release_irq(int irq) {
++ return -1;
++}
++
++#endif /* CONFIG_USE_IRQ */
++
++#endif /* __AST_G5_IRQ_H__ */
+diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c
+index b492003f51..2472aa3603 100644
+--- a/board/aspeed/ast-g5/ast-g5.c
++++ b/board/aspeed/ast-g5/ast-g5.c
+@@ -14,6 +14,8 @@
+ #include <asm/arch/ast-sdmc.h>
+ #include <asm/io.h>
+
++#include "ast-g5.h"
++
+ DECLARE_GLOBAL_DATA_PTR;
+
+ int board_early_init_f(void)
+@@ -22,6 +24,7 @@ int board_early_init_f(void)
+ ast_config_uart5_clk();
+ /*enable pass through*/
+ ast_enable_pass_through();
++ arch_interrupt_init_early();
+
+ return 0;
+ }
+diff --git a/board/aspeed/ast-g5/ast-g5.h b/board/aspeed/ast-g5/ast-g5.h
+new file mode 100644
+index 0000000000..9fd10eccb3
+--- /dev/null
++++ b/board/aspeed/ast-g5/ast-g5.h
+@@ -0,0 +1,7 @@
++#ifndef _AST_G5_H_
++#define _AST_G5_H_
++
++#include <common.h>
++#include "ast-g5-irq.h"
++
++#endif /* _AST_G5_H_ */
+diff --git a/cmd/Kconfig b/cmd/Kconfig
+index d69b817c82..33be2407d2 100644
+--- a/cmd/Kconfig
++++ b/cmd/Kconfig
+@@ -313,6 +313,11 @@ endmenu
+
+ menu "Device access commands"
+
++config CMD_IRQ
++ bool "interrupts - enable/disable interrupts"
++ depends on USE_IRQ
++ default y
++
+ config CMD_DM
+ bool "dm - Access to driver model information"
+ depends on DM
+diff --git a/configs/ast_g5_ncsi_2boot_defconfig b/configs/ast_g5_ncsi_2boot_defconfig
+index 2d28c86966..d5b7894a9e 100644
+--- a/configs/ast_g5_ncsi_2boot_defconfig
++++ b/configs/ast_g5_ncsi_2boot_defconfig
+@@ -33,3 +33,4 @@ CONFIG_CMD_CRC32=y
+ CONFIG_LOOPW=y
+ CONFIG_CMD_MEMTEST=y
+ CONFIG_CMD_MX_CYCLIC=y
++CONFIG_USE_IRQ=y
+diff --git a/configs/ast_g5_ncsi_defconfig b/configs/ast_g5_ncsi_defconfig
+index 74029ed514..9481e5fb6e 100644
+--- a/configs/ast_g5_ncsi_defconfig
++++ b/configs/ast_g5_ncsi_defconfig
+@@ -11,3 +11,4 @@ CONFIG_HUSH_PARSER=y
+ CONFIG_OF_LIBFDT=y
+ CONFIG_SPI_FLASH=y
+ CONFIG_SYS_NS16550=y
++CONFIG_USE_IRQ=y
+diff --git a/configs/ast_g5_phy_defconfig b/configs/ast_g5_phy_defconfig
+index 767f3af605..4aefcf49e8 100644
+--- a/configs/ast_g5_phy_defconfig
++++ b/configs/ast_g5_phy_defconfig
+@@ -12,3 +12,4 @@ CONFIG_HUSH_PARSER=y
+ CONFIG_OF_LIBFDT=y
+ CONFIG_SPI_FLASH=y
+ CONFIG_SYS_NS16550=y
++CONFIG_USE_IRQ=y
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch
new file mode 100644
index 000000000..18cc2f9c8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0007-Add-espi-support.patch
@@ -0,0 +1,330 @@
+From 7ad0ea13337550f35c1e726f21d4751bf74078d6 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Wed, 14 Nov 2018 10:21:40 -0800
+Subject: [PATCH 2/7] Add espi support
+
+This adds basic eSPI support for U-Boot. The eSPI driver works best with
+interrupts because the timing of the initialization with the PCH is not
+trivial.
+
+The espi driver is currently just a bare-minimum driver allowing the
+host to boot. In the future it may be expanded to have further
+functions.
+
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+Change-Id: Id7072f1408dcf364968b1b74f2192e50a22a82f0
+---
+ arch/arm/include/asm/arch-aspeed/regs-scu.h | 2 +
+ board/aspeed/ast-g5/Makefile | 1 +
+ board/aspeed/ast-g5/ast-g5-espi.c | 231 ++++++++++++++++++++
+ board/aspeed/ast-g5/ast-g5-intel.c | 16 ++
+ board/aspeed/ast-g5/ast-g5.c | 3 +
+ 5 files changed, 253 insertions(+)
+ create mode 100644 board/aspeed/ast-g5/ast-g5-espi.c
+ create mode 100644 board/aspeed/ast-g5/ast-g5-intel.c
+
+diff --git a/arch/arm/include/asm/arch-aspeed/regs-scu.h b/arch/arm/include/asm/arch-aspeed/regs-scu.h
+index b714fa9234..10b983a966 100644
+--- a/arch/arm/include/asm/arch-aspeed/regs-scu.h
++++ b/arch/arm/include/asm/arch-aspeed/regs-scu.h
+@@ -552,6 +552,8 @@
+
+ #define CLK_25M_IN (0x1 << 23)
+
++#define SCU_HW_STRAP_FAST_RESET (1 << 27)
++#define SCU_HW_STRAP_ESPI_ENABLED (1 << 25)
+ #define SCU_HW_STRAP_2ND_BOOT_WDT (0x1 << 17)
+ #define SCU_HW_STRAP_SUPER_IO_CONFIG (0x1 << 16)
+ #define SCU_HW_STRAP_VGA_CLASS_CODE (0x1 << 15)
+diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile
+index d41b11589f..58e0c648f4 100644
+--- a/board/aspeed/ast-g5/Makefile
++++ b/board/aspeed/ast-g5/Makefile
+@@ -1,2 +1,4 @@
+ obj-y += ast-g5.o
++obj-y += ast-g5-intel.o
++obj-y += ast-g5-espi.o
+ obj-y += ast-g5-irq.o
+diff --git a/board/aspeed/ast-g5/ast-g5-espi.c b/board/aspeed/ast-g5/ast-g5-espi.c
+new file mode 100644
+index 0000000000..79ef253b86
+--- /dev/null
++++ b/board/aspeed/ast-g5/ast-g5-espi.c
+@@ -0,0 +1,231 @@
++/*
++ * Copyright 2018 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include <common.h>
++#include <asm/io.h>
++#include <asm/arch/regs-scu.h>
++#include <asm/arch/ast_scu.h>
++#include <asm/arch/aspeed.h>
++
++#include "ast-g5.h"
++
++#define DEBUG_ESPI_ENABLED 1
++#ifdef DEBUG_ESPI_ENABLED
++#define DBG_ESPI debug
++#else
++#define DBG_ESPI(...)
++#endif
++/* eSPI controller registers */
++#define ESPI000 0x000 /* Engine Control. */
++#define ESPI004 0x004 /* Engine Status. */
++#define ESPI008 0x008 /* Interrupt Status. */
++#define ESPI00C 0x00C /* Interrupt Enable. */
++#define ESPI010 0x010 /* DMA Addr of Peripheral Channel Posted Rx pkt */
++#define ESPI014 0x014 /* Control of Peripheral Channel Posted Rx pkt. */
++#define ESPI018 0x018 /* Data port of Peripheral Channel Posted Rx pkt. */
++#define ESPI020 0x020 /* DMA Addr of Peripheral Channel Posted Tx pkt. */
++#define ESPI024 0x024 /* Control of Peripheral Channel Posted Tx pkt. */
++#define ESPI028 0x028 /* Data port of Peripheral Channel Posted Tx pkt. */
++#define ESPI030 0x030 /* DMA Addr of Peripheral Channel Non-Posted Tx pkt. */
++#define ESPI034 0x034 /* Control of Peripheral Channel Non-Posted Tx pkt. */
++#define ESPI038 0x038 /* Data port of Peripheral Channel Non-Posted Tx pkt. */
++#define ESPI040 0x040 /* DMA Addr of OOB Channel Rx pkt. */
++#define ESPI044 0x044 /* Control of OOB Channel Rx pkt. */
++#define ESPI048 0x048 /* Data port of OOB Channel Rx pkt. */
++#define ESPI050 0x050 /* DMA Addr of OOB Channel Tx pkt. */
++#define ESPI054 0x054 /* Control of OOB Channel Tx pkt. */
++#define ESPI058 0x058 /* Data port of OOB Channel Tx pkt. */
++#define ESPI060 0x060 /* DMA Addr of Flash Channel Rx pkt. */
++#define ESPI064 0x064 /* Control of Flash Channel Rx pkt. */
++#define ESPI068 0x068 /* Data port of Flash Channel Rx pkt. */
++#define ESPI070 0x070 /* DMA Addr of Flash Channel Tx pkt. */
++#define ESPI074 0x074 /* Control of Flash Channel Tx pkt. */
++#define ESPI078 0x078 /* Data port of Flash Channel Tx pkt. */
++#define ESPI084 0x084 /* Mapping Src Addr of Peripheral Channel Rx pkt. */
++#define ESPI088 0x088 /* Mapping Tgt Addr of Peripheral Channel Rx pkt. */
++#define ESPI08C 0x08C /* Mapping Addr Mask of Peripheral Channel Rx pkt. */
++#define ESPI090 0x090 /* Mapping Target Addr and Mask of Flash Channel. */
++#define ESPI094 0x094 /* Interrupt enable of System Event from Master. */
++#define ESPI098 0x098 /* System Event from and to Master. */
++#define ESPI09C 0x09C /* GPIO through Virtual Wire Channel. */
++#define ESPI0A0 0x0A0 /* General Capabilities and Configurations. */
++#define ESPI0A4 0x0A4 /* Channel 0 Capabilities and Configurations. */
++#define ESPI0A8 0x0A8 /* Channel 1 Capabilities and Configurations. */
++#define ESPI0AC 0x0AC /* Channel 2 Capabilities and Configurations. */
++#define ESPI0B0 0x0B0 /* Channel 3 Capabilities and Configurations. */
++#define ESPI0B4 0x0B4 /* GPIO Direction of Virtual Wire Channel. */
++#define ESPI0B8 0x0B8 /* GPIO Selection of Virtual Wire Channel. */
++#define ESPI0BC 0x0BC /* GPIO Reset Selection of Virtual Wire Channel. */
++#define ESPI100 0x100 /* Interrupt enable of System Event 1 from Master. */
++#define ESPI104 0x104 /* System Event 1 from and to Master. */
++#define ESPI110 0x110 /* Interrupt type 0 of System Event from Master. */
++#define ESPI114 0x114 /* Interrupt type 1 of System Event from Master. */
++#define ESPI118 0x118 /* Interrupt type 2 of System Event from Master. */
++#define ESPI11C 0x11C /* Interrupt status of System Event from Master. */
++#define ESPI120 0x120 /* Interrupt type 0 of System Event 1 from Master. */
++#define ESPI124 0x124 /* Interrupt type 1 of System Event 1 from Master. */
++#define ESPI128 0x128 /* Interrupt type 2 of System Event 1 from Master. */
++#define ESPI12C 0x12C /* Interrupt status of System Event 1 from Master. */
++#define ESPICFG004 0x004 /* Device Identification. */
++#define ESPICFG008 0x008 /* General Capabilities and Configurations. */
++#define ESPICFG010 0x010 /* Channel 0 Capabilities and Configurations. */
++#define ESPICFG020 0x020 /* Channel 1 Capabilities and Configurations. */
++#define ESPICFG030 0x030 /* Channel 2 Capabilities and Configurations. */
++#define ESPICFG040 0x040 /* Channel 3 Capabilities and Configurations. */
++#define ESPICFG044 0x044 /* Channel 3 Capabilities and Configurations 2. */
++#define ESPICFG800 0x800 /* GPIO Direction of Virtual Wire Channel. */
++#define ESPICFG804 0x804 /* GPIO Selection of Virtual Wire Channel. */
++#define ESPICFG808 0x808 /* GPIO Reset Selection of Virtual Wire Channel. */
++#define ESPICFG810 0x810 /* Mapping Src Addr of Peripheral Channel Rx pkt */
++#define ESPICFG814 0x814 /* Mapping Tgt Addr of Peripheral Channel Rx pkt */
++#define ESPICFG818 0x818 /* Mapping Addr Mask of Peripheral Channel Rx pkt */
++
++/* ESPI000 bits */
++#define AST_ESPI_OOB_CHRDY (1 << 4)
++#define AST_ESPI_FLASH_SW_CHRDY (0x1 << 7)
++#define AST_ESPI_FLASH_SW_READ (0x1 << 10)
++
++/* ESPI00C bits (Interrupt Enable) */
++#define AST_ESPI_IEN_SYS_EV (1 << 8)
++#define AST_ESPI_IEN_GPIO_EV (1 << 9)
++
++/* ESPI008 bits ISR */
++#define AST_ESPI_VW_SYS_EVT (1 << 8)
++#define AST_ESPI_VW_SYS_EV1 (1 << 22)
++
++/* ESPI098 and ESPI11C bits */
++#define AST_ESPI_OOB_RST_WARN (1 << 6)
++#define AST_ESPI_HOST_RST_WARN (1 << 8)
++#define AST_ESPI_OOB_RST_ACK (1 << 16)
++#define AST_ESPI_SL_BT_DONE (1 << 20)
++#define AST_ESPI_SL_BT_STATUS (1 << 23)
++#define AST_ESPI_HOST_RST_ACK (1 << 27)
++
++/* ESPI104 bits */
++#define AST_ESPI_SUS_WARN (1 << 0)
++#define AST_ESPI_SUS_ACK (1 << 20)
++
++/* LPC chip ID */
++#define SCR0SIO 0x170
++#define IRQ_SRC_ESPI 23 /* IRQ 23 */
++
++static int espi_irq_handler(struct pt_regs *regs)
++{
++ uint32_t irq_status = readl(AST_ESPI_BASE + ESPI008);
++
++ DBG_ESPI("ISR irq_status : 0x%08X\n", irq_status);
++
++ if (irq_status & AST_ESPI_VW_SYS_EVT) {
++ uint32_t sys_status = readl(AST_ESPI_BASE + ESPI11C);
++ uint32_t sys_event = readl(AST_ESPI_BASE + ESPI098);
++
++ DBG_ESPI("sys_status : 0x%08X\n", sys_status);
++ if (sys_status & AST_ESPI_HOST_RST_WARN) {
++ DBG_ESPI("HOST_RST_WARN ev: %08X\n", sys_event);
++ if (sys_event & AST_ESPI_HOST_RST_WARN) {
++ uint32_t v = readl(AST_ESPI_BASE + ESPI098)
++ | AST_ESPI_HOST_RST_ACK;
++ writel(v, AST_ESPI_BASE + ESPI098);
++ }
++ }
++ if (sys_status & AST_ESPI_OOB_RST_WARN) {
++ DBG_ESPI("OOB_RST_WARN ev: %08X\n", sys_event);
++ if (sys_event & AST_ESPI_OOB_RST_WARN) {
++ uint32_t v = readl(AST_ESPI_BASE + ESPI098)
++ | AST_ESPI_OOB_RST_ACK;
++ writel(v, AST_ESPI_BASE + ESPI098);
++ }
++ }
++ writel(sys_status, AST_ESPI_BASE + ESPI11C); // clear status
++ }
++
++ if (irq_status & AST_ESPI_VW_SYS_EV1) {
++ uint32_t sys1_status = readl(AST_ESPI_BASE + ESPI12C);
++ uint32_t sys1_event = readl(AST_ESPI_BASE + ESPI104);
++
++ DBG_ESPI("sys1_status : 0x%08X\n", sys1_status);
++ if (sys1_status & AST_ESPI_SUS_WARN) {
++ DBG_ESPI("SUS WARN ev: %08X\n", sys1_event);
++ if (sys1_event & AST_ESPI_SUS_WARN) {
++ uint32_t v = readl(AST_ESPI_BASE + ESPI104)
++ | AST_ESPI_SUS_ACK;
++ writel(v, AST_ESPI_BASE + ESPI104);
++ }
++ }
++ writel(sys1_status, AST_ESPI_BASE + ESPI12C); // clear status
++ }
++ writel(irq_status, AST_ESPI_BASE + ESPI008); // clear irq_status
++ return 0;
++}
++
++static void espi_handshake_ack(void)
++{
++ // IRQ only serviced if strapped, so no strap check
++ if (!(readl(AST_ESPI_BASE + ESPI098) & AST_ESPI_SL_BT_STATUS)) {
++ DBG_ESPI("Setting espi slave boot done\n");
++ uint32_t v = readl(AST_ESPI_BASE + ESPI098)
++ | AST_ESPI_SL_BT_STATUS | AST_ESPI_SL_BT_DONE;
++ writel(v, AST_ESPI_BASE + ESPI098);
++ }
++
++ if (readl(AST_ESPI_BASE + ESPI104) & AST_ESPI_SUS_WARN) {
++ DBG_ESPI("Boot SUS WARN set %08x\n",
++ readl(AST_ESPI_BASE + ESPI104));
++ uint32_t v = readl(AST_ESPI_BASE + ESPI104) | AST_ESPI_SUS_ACK;
++ writel(v, AST_ESPI_BASE + ESPI104);
++ }
++}
++
++void espi_init(void)
++{
++ if (readl(AST_SCU_BASE + AST_SCU_HW_STRAP1)
++ & SCU_HW_STRAP_ESPI_ENABLED) {
++ uint32_t v;
++ DBG_ESPI("espi_init\n");
++
++ /* Block flash access from Host */
++ v = readl(AST_ESPI_BASE + ESPI000) & ~AST_ESPI_FLASH_SW_CHRDY;
++ v |= AST_ESPI_FLASH_SW_READ | AST_ESPI_OOB_CHRDY;
++ writel(v, AST_ESPI_BASE + ESPI000);
++
++ /* Set SIO register 0x28 to 0xa8 as a faked ASPEED ChipID for
++ * BIOS using in eSPI mode */
++ v = readl(AST_LPC_BASE + SCR0SIO) & ~0x000000ff;
++ writel(v, AST_LPC_BASE + SCR0SIO);
++ v = readl(AST_LPC_BASE + SCR0SIO) | 0xa8;
++ writel(v, AST_LPC_BASE + SCR0SIO);
++
++ v = readl(AST_ESPI_BASE + ESPI000) | AST_ESPI_OOB_CHRDY;
++ writel(v, AST_ESPI_BASE + ESPI000);
++
++ writel(0, AST_ESPI_BASE + ESPI110);
++ writel(0, AST_ESPI_BASE + ESPI114);
++ writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN,
++ AST_ESPI_BASE + ESPI118);
++ writel(AST_ESPI_HOST_RST_WARN | AST_ESPI_OOB_RST_WARN,
++ AST_ESPI_BASE + ESPI094);
++
++ writel(AST_ESPI_SUS_WARN,
++ AST_ESPI_BASE + ESPI120); // int type 0 susp warn
++ writel(0, AST_ESPI_BASE + ESPI124);
++ writel(0, AST_ESPI_BASE + ESPI128);
++ writel(AST_ESPI_SUS_WARN,
++ AST_ESPI_BASE
++ + ESPI100); // Enable sysev1 ints for susp warn
++
++ writel(AST_ESPI_IEN_SYS_EV,
++ AST_ESPI_BASE + ESPI00C); // Enable only sys events
++
++ espi_handshake_ack();
++
++ request_irq(IRQ_SRC_ESPI, espi_irq_handler);
++ } else {
++ DBG_ESPI("No espi strap\n");
++ }
++}
+diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c
+new file mode 100644
+index 0000000000..e79235c8d0
+--- /dev/null
++++ b/board/aspeed/ast-g5/ast-g5-intel.c
+@@ -0,0 +1,16 @@
++/*
++ * Copyright 2018 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include <common.h>
++
++extern void espi_init(void);
++void ast_g5_intel(void)
++{
++ espi_init();
++}
+diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c
+index 2472aa3603..d41ef9cbd3 100644
+--- a/board/aspeed/ast-g5/ast-g5.c
++++ b/board/aspeed/ast-g5/ast-g5.c
+@@ -18,6 +18,8 @@
+
+ DECLARE_GLOBAL_DATA_PTR;
+
++extern void ast_g5_intel(void);
++
+ int board_early_init_f(void)
+ {
+ /* make sure uart5 is using 24MHz clock */
+@@ -34,6 +36,7 @@ int board_init(void)
+ gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+ gd->flags = 0;
+
++ ast_g5_intel();
+ return 0;
+ }
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0008-add-sgio-support-for-port80-snoop-post-LEDs.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0008-add-sgio-support-for-port80-snoop-post-LEDs.patch
new file mode 100644
index 000000000..cb61bd545
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0008-add-sgio-support-for-port80-snoop-post-LEDs.patch
@@ -0,0 +1,160 @@
+From cf43453a75880cf53ea7bbf5859706f2a7cae292 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Wed, 14 Nov 2018 12:09:52 -0800
+Subject: [PATCH 3/7] add sgio support for port80 snoop post LEDs
+
+This ties together the port 80 snooping to the SGPIO output that
+ultimately drives the POST code LEDs.
+
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+Change-Id: Iaa1b91cd40f4b6323dba0598da373cb631459e66
+---
+ arch/arm/include/asm/arch-aspeed/ast_scu.h | 1 +
+ arch/arm/mach-aspeed/ast-scu.c | 8 ++
+ board/aspeed/ast-g5/ast-g5-intel.c | 96 ++++++++++++++++++++++
+ 3 files changed, 105 insertions(+)
+
+diff --git a/arch/arm/include/asm/arch-aspeed/ast_scu.h b/arch/arm/include/asm/arch-aspeed/ast_scu.h
+index 98e63351f1..c10e6a9d4b 100644
+--- a/arch/arm/include/asm/arch-aspeed/ast_scu.h
++++ b/arch/arm/include/asm/arch-aspeed/ast_scu.h
+@@ -44,6 +44,7 @@ extern u32 ast_scu_get_vga_memsize(void);
+ extern void ast_scu_init_eth(u8 num);
+ extern void ast_scu_multi_func_eth(u8 num);
+ extern void ast_scu_multi_func_romcs(u8 num);
++extern void ast_scu_multi_func_sgpio(void);
+
+ void ast_config_uart5_clk(void);
+
+diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c
+index c83931ed54..63e9c7c167 100644
+--- a/arch/arm/mach-aspeed/ast-scu.c
++++ b/arch/arm/mach-aspeed/ast-scu.c
+@@ -407,6 +407,14 @@ void ast_scu_multi_func_romcs(u8 num)
+ SCU_FUN_PIN_ROMCS(num), AST_SCU_FUN_PIN_CTRL3);
+ }
+
++void ast_scu_multi_func_sgpio(void)
++{
++ ast_scu_write(ast_scu_read(AST_SCU_FUN_PIN_CTRL2) |
++ SCU_FUN_PIN_SGPMI | SCU_FUN_PIN_SGPMO |
++ SCU_FUN_PIN_SGPMLD | SCU_FUN_PIN_SGPMCK,
++ AST_SCU_FUN_PIN_CTRL2);
++}
++
+ u32 ast_scu_revision_id(void)
+ {
+ int i;
+diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c
+index e79235c8d0..fca4d91115 100644
+--- a/board/aspeed/ast-g5/ast-g5-intel.c
++++ b/board/aspeed/ast-g5/ast-g5-intel.c
+@@ -8,9 +8,105 @@
+ */
+
+ #include <common.h>
++#include <asm/io.h>
++#include <asm/arch/regs-scu.h>
++#include <asm/arch/ast_scu.h>
++#include <asm/arch/aspeed.h>
++
++#include "ast-g5.h"
++
++#define LPC_SNOOP_ADDR 0x80
++#define HICR5 0x080 /* Host Interface Control Register 5 */
++#define HICR6 0x084 /* Host Interface Control Register 6 */
++#define HICR7 0x088 /* Host Interface Control Register 7 */
++#define HICR8 0x08c /* Host Interface Control Register 8 */
++#define SNPWADR 0x090 /* LPC Snoop Address Register */
++#define SNPWDR 0x094 /* LPC Snoop Data Register */
++#define HICR9 0x098 /* Host Interface Control Register 9 */
++#define HICRA 0x09c /* Host Interface Control Register A */
++#define LHCR0 0x0a0 /* LPC Host Control Register 0 */
++#define LHCR1 0x0a4 /* LPC Host Control Register 1 */
++#define LHCR2 0x0a8 /* LPC Host Control Register 2 */
++#define LHCR3 0x0ac /* LPC Host Control Register 3 */
++#define LHCR4 0x0b0 /* LPC Host Control Register 4 */
++#define LHCR5 0x0b4 /* LPC Host Control Register 5 */
++#define LHCR6 0x0b8 /* LPC Host Control Register 6 */
++#define LHCR7 0x0bc /* LPC Host Control Register 7 */
++#define LHCR8 0x0c0 /* LPC Host Control Register 8 */
++#define PCCR6 0x0c4 /* Post Code Control Register 6 */
++#define LHCRA 0x0c8 /* LPC Host Control Register A */
++#define LHCRB 0x0cc /* LPC Host Control Register B */
++#define PCCR4 0x0d0 /* Post Code Control Register 4 */
++#define PCCR5 0x0d4 /* Post Code Control Register 5 */
++#define HICRB 0x100 /* Host Interface Control Register B */
++#define HICRC 0x104 /* Host Interface Control Register C */
++/* HICR5 Bits */
++#define HICR5_EN_SIOGIO (1 << 31) /* Enable SIOGIO */
++#define HICR5_EN80HGIO (1 << 30) /* Enable 80hGIO */
++#define HICR5_SEL80HGIO (0x1f << 24) /* Select 80hGIO */
++#define SET_SEL80HGIO(x) ((x & 0x1f) << 24) /* Select 80hGIO Offset */
++#define HICR5_UNKVAL_MASK 0x1FFF0000 /* Bits with unknown values on reset */
++#define HICR5_ENINT_SNP0W (1 << 1) /* Enable Snooping address 0 */
++#define HICR5_EN_SNP0W (1 << 0) /* Enable Snooping address 0 */
++
++/* HRCR6 Bits */
++#define HICR6_STR_SNP0W (1 << 0) /* Interrupt Status Snoop address 0 */
++#define HICR6_STR_SNP1W (1 << 1) /* Interrupt Status Snoop address 1 */
++
++/* HICRB Bits */
++#define HICRB_EN80HSGIO (1 << 13) /* Enable 80hSGIO */
++
++#define SGPIO_CLK_DIV(N) ((N) << 16)
++#define SGPIO_BYTES(N) ((N) << 6)
++#define SGPIO_ENABLE 1
++#define GPIO254 0x254
++
++static void sgpio_init(void)
++{
++ uint32_t value;
++ /*
++ 33.4.2
++ LPC port80h direct to SGPIO
++ In AST2500 SGPIO, it supports output data from 80h. It always uses SGPIOA.
++ 1. Configure LPC snoop function.
++ (a) Set SNPWADR(0x1e789090)[15:0] to 0x80.
++ (b) Set HICR5(0x1e789080)[0] to 1 to enable snoop.
++ 2. Configure SGPIO
++ (a) Set GPIO254[9:6] to larger than or equal to 0x1.
++ (b) Set GPIO254[0] to 1 to enable SGPIO.
++ 3. Set SuperIO
++ (a) Set SIOR7 30h to 0x40.
++ */
++ /* make sure multi-pin stuff goes in our favor */
++ ast_scu_multi_func_sgpio();
++
++ /* set lpc snoop #0 to port 0x80 */
++ value = readl(AST_LPC_BASE + SNPWADR) & 0xffff0000;
++ writel(value | LPC_SNOOP_ADDR, AST_LPC_BASE + SNPWADR);
++
++ /* clear interrupt status */
++ value = readl(AST_LPC_BASE + HICR6);
++ value |= HICR6_STR_SNP0W | HICR6_STR_SNP1W;
++ writel(value, AST_LPC_BASE + HICR6);
++
++ /* enable lpc snoop #0 and SIOGIO */
++ value = readl(AST_LPC_BASE + HICR5) & ~(HICR5_UNKVAL_MASK);
++ value |= HICR5_EN_SIOGIO | HICR5_EN_SNP0W | HICR5_ENINT_SNP0W;
++ writel(value, AST_LPC_BASE + HICR5);
++
++
++ /* enable port80h snoop on SGPIO */
++ value = readl(AST_LPC_BASE + HICRB) | HICRB_EN80HSGIO;
++ writel(value, AST_LPC_BASE + HICRB);
++
++ /* set the gpio clock to pclk/(2*(5+1)) or ~2 MHz */
++ value = SGPIO_CLK_DIV(256) | SGPIO_BYTES(10) | SGPIO_ENABLE;
++ writel(value, AST_GPIO_BASE + GPIO254);
++}
+
+ extern void espi_init(void);
+ void ast_g5_intel(void)
+ {
+ espi_init();
++ sgpio_init();
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0009-Add-basic-GPIO-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0009-Add-basic-GPIO-support.patch
new file mode 100644
index 000000000..a49f196ac
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0009-Add-basic-GPIO-support.patch
@@ -0,0 +1,414 @@
+From 89728d8c255204c8d9ec46a1dc0d412b04708f22 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Fri, 16 Nov 2018 09:58:01 -0800
+Subject: [PATCH 4/7] Add basic GPIO support
+
+Add a table of well-known gpios (such as FP LEDs and FF UPD jumper) and
+initialize them at boot.
+
+Add a mechanism to get/set well known gpios from command line.
+
+Change-Id: I4136a5ccb048b3604f13b17ea0c18a4bc596c249
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ board/aspeed/ast-g5/Makefile | 1 +
+ board/aspeed/ast-g5/ast-g5-gpio.c | 195 +++++++++++++++++++++++++++++
+ board/aspeed/ast-g5/ast-g5-gpio.h | 102 +++++++++++++++
+ board/aspeed/ast-g5/ast-g5-intel.c | 42 +++++++
+ board/aspeed/ast-g5/ast-g5.h | 1 +
+ 5 files changed, 341 insertions(+)
+ create mode 100644 board/aspeed/ast-g5/ast-g5-gpio.c
+ create mode 100644 board/aspeed/ast-g5/ast-g5-gpio.h
+
+diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile
+index 58e0c648f4..2970ae5741 100644
+--- a/board/aspeed/ast-g5/Makefile
++++ b/board/aspeed/ast-g5/Makefile
+@@ -2,3 +2,4 @@ obj-y += ast-g5.o
+ obj-y += ast-g5-intel.o
+ obj-y += ast-g5-espi.o
+ obj-y += ast-g5-irq.o
++obj-y += ast-g5-gpio.o
+diff --git a/board/aspeed/ast-g5/ast-g5-gpio.c b/board/aspeed/ast-g5/ast-g5-gpio.c
+new file mode 100644
+index 0000000000..d596c15914
+--- /dev/null
++++ b/board/aspeed/ast-g5/ast-g5-gpio.c
+@@ -0,0 +1,195 @@
++/*
++ * Copyright 2018 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include <common.h>
++#include <asm/io.h>
++#include <asm/arch/regs-scu.h>
++#include <asm/arch/ast_scu.h>
++#include <asm/arch/aspeed.h>
++
++#include "ast-g5.h"
++#include "ast-g5-gpio.h"
++
++typedef struct _gpio_bases {
++ uint32_t u32ddr; /* data and direction registers */
++ uint32_t u32intcfg; /* interrupt config */
++ uint32_t u32debounce; /* debounce config */
++ uint32_t u32cmdsrc; /* command source config */
++} sGPIO_BASES;
++
++static const sGPIO_BASES GPIO_BASES[] = {
++ /* ABCD */
++ {AST_GPIO_BASE + 0x0000, AST_GPIO_BASE + 0x0008,
++ AST_GPIO_BASE + 0x0040, AST_GPIO_BASE + 0x0060},
++ /* EFGH */
++ {AST_GPIO_BASE + 0x0020, AST_GPIO_BASE + 0x0028,
++ AST_GPIO_BASE + 0x0048, AST_GPIO_BASE + 0x0068},
++ /* IJKL */
++ {AST_GPIO_BASE + 0x0070, AST_GPIO_BASE + 0x0098,
++ AST_GPIO_BASE + 0x00b0, AST_GPIO_BASE + 0x0090},
++ /* MNOP */
++ {AST_GPIO_BASE + 0x0078, AST_GPIO_BASE + 0x00e8,
++ AST_GPIO_BASE + 0x0100, AST_GPIO_BASE + 0x00e0},
++ /* QRST */
++ {AST_GPIO_BASE + 0x0080, AST_GPIO_BASE + 0x0118,
++ AST_GPIO_BASE + 0x0130, AST_GPIO_BASE + 0x0110},
++ /* UVWX */
++ {AST_GPIO_BASE + 0x0088, AST_GPIO_BASE + 0x0148,
++ AST_GPIO_BASE + 0x0160, AST_GPIO_BASE + 0x0140},
++ /* YZAB */
++ {AST_GPIO_BASE + 0x01e0, AST_GPIO_BASE + 0x0178,
++ AST_GPIO_BASE + 0x0190, AST_GPIO_BASE + 0x0170},
++ /* AC__ */
++ {AST_GPIO_BASE + 0x01e8, AST_GPIO_BASE + 0x01a8,
++ AST_GPIO_BASE + 0x01c0, AST_GPIO_BASE + 0x01a0},
++};
++
++static size_t gpio_max = 0;
++static const GPIOValue * gpio_table = NULL;
++
++void gpio_set_value(int n, int asserted)
++{
++ uint8_t port;
++ uint8_t pin;
++ uint32_t base;
++ uint8_t shift;
++ uint8_t assert;
++ uint32_t gpio_value;
++
++ if (n >= gpio_max || !gpio_table) {
++ return;
++ }
++ port = GPIO_PORT(gpio_table[n].u8PortPin);
++ assert = GPIO_PORT(gpio_table[n].u8Value);
++ pin = GPIO_PIN(gpio_table[n].u8PortPin);
++ base = GPIO_BASES[GPIO_GROUP(port)].u32ddr;
++ shift = GPIO_SHIFT(port, pin);
++
++ gpio_value = readl(base + GPIO_DATA_VALUE);
++ if ((assert &&asserted) || !(assert || asserted)) {
++ // set the bit
++ gpio_value |= (1 << shift);
++ } else {
++ // clear the bit
++ gpio_value &= ~(1 << shift);
++ }
++ writel(gpio_value, base + GPIO_DATA_VALUE);
++}
++
++int gpio_get_value(int n)
++{
++ uint8_t port;
++ uint8_t pin;
++ uint32_t base;
++ uint8_t shift;
++ uint8_t assert;
++ uint32_t gpio_value;
++
++ if (n >= gpio_max || !gpio_table) {
++ return -1;
++ }
++ port = GPIO_PORT(gpio_table[n].u8PortPin);
++ assert = GPIO_PORT(gpio_table[n].u8Value);
++ pin = GPIO_PIN(gpio_table[n].u8PortPin);
++ base = GPIO_BASES[GPIO_GROUP(port)].u32ddr;
++ shift = GPIO_SHIFT(port, pin);
++
++ gpio_value = readl(base + GPIO_DATA_VALUE);
++ gpio_value >>= shift;
++ gpio_value &= 1;
++ gpio_value ^= assert;
++ return !gpio_value;
++}
++
++void gpio_init(const GPIOValue* table, size_t count)
++{
++ uint32_t pclk, value;
++ int i;
++
++ gpio_table = table;
++ gpio_max = count;
++ /* set up the debounce timers (in units of PCLK cycles) */
++ pclk = ast_get_ahbclk();
++ /* GPIO_DEBOUNCE_120us */
++ writel((pclk / 1000000) * 120, AST_GPIO_BASE + GPIO_DEBOUNCE_TIMER_0);
++ /* GPIO_DEBOUNCE_8ms */
++ writel((pclk / 1000000) * 8000, AST_GPIO_BASE + GPIO_DEBOUNCE_TIMER_1);
++ /* GPIO_DEBOUNCE_16ms */
++ writel((pclk / 1000000) * 16000, AST_GPIO_BASE + GPIO_DEBOUNCE_TIMER_2);
++
++ for (i = 0; i < gpio_max; i++) {
++ uint8_t port;
++ uint8_t pin;
++ uint32_t base;
++ uint8_t shift;
++
++ port = GPIO_PORT(gpio_table[i].u8PortPin);
++ pin = GPIO_PIN(gpio_table[i].u8PortPin);
++ base = GPIO_BASES[GPIO_GROUP(port)].u32ddr;
++ shift = GPIO_SHIFT(port, pin);
++
++ /* set direction */
++ value = readl(base + GPIO_DIRECTION);
++ if (gpio_table[i].u8PinCFG & GPCFG_OUTPUT_EN)
++ value |= (1 << shift);
++ else
++ value &= ~(1 << shift);
++ writel(value, base + GPIO_DIRECTION);
++
++ /* set data value */
++ value = readl(base + GPIO_DATA_VALUE);
++ if (gpio_table[i].u8Value)
++ value |= (1 << shift);
++ else
++ value &= ~(1 << shift);
++ writel(value, base + GPIO_DATA_VALUE);
++
++ /* set debounce */
++ base = GPIO_BASES[GPIO_GROUP(port)].u32debounce;
++ value = readl(base + GPIO_DEBOUNCE_SEL_0);
++ if (gpio_table[i].u8Debounce & 0x01)
++ value |= (1 << shift);
++ else
++ value &= ~(1 << shift);
++ writel(value, base + GPIO_DEBOUNCE_SEL_0);
++ value = readl(base + GPIO_DEBOUNCE_SEL_1);
++ if (gpio_table[i].u8Debounce & 0x02)
++ value |= (1 << shift);
++ else
++ value &= ~(1 << shift);
++ writel(value, base + GPIO_DEBOUNCE_SEL_1);
++ }
++}
++
++int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
++{
++ int n;
++ if (argc < 3) {
++ return 1;
++ }
++ n = simple_strtoul(argv[2], NULL, 16);
++ if (argv[1][0] == 'g') {
++ printf("%d\n", gpio_get_value(n));
++ return 0;
++ }
++ if (argc < 4) {
++ return 1;
++ }
++ if (argv[1][0] == 's') {
++ int value;
++ value = simple_strtoul(argv[3], NULL, 16);
++ gpio_set_value(n, value);
++ return 0;
++ }
++
++ return 1;
++}
++U_BOOT_CMD(gpio, 4, 0, do_gpio,
++ "do stuff with gpios <set|get> [n] [value]",
++ "");
+diff --git a/board/aspeed/ast-g5/ast-g5-gpio.h b/board/aspeed/ast-g5/ast-g5-gpio.h
+new file mode 100644
+index 0000000000..a820c0fcad
+--- /dev/null
++++ b/board/aspeed/ast-g5/ast-g5-gpio.h
+@@ -0,0 +1,102 @@
++#ifndef __HW_GPIO_H__
++#define __HW_GPIO_H__
++
++#define GPIO_PORT_A 0
++#define GPIO_PORT_B 1
++#define GPIO_PORT_C 2
++#define GPIO_PORT_D 3
++#define GPIO_PORT_E 4
++#define GPIO_PORT_F 5
++#define GPIO_PORT_G 6
++#define GPIO_PORT_H 7
++#define GPIO_PORT_I 8
++#define GPIO_PORT_J 9
++#define GPIO_PORT_K 10
++#define GPIO_PORT_L 11
++#define GPIO_PORT_M 12
++#define GPIO_PORT_N 13
++#define GPIO_PORT_O 14
++#define GPIO_PORT_P 15
++#define GPIO_PORT_Q 16
++#define GPIO_PORT_R 17
++#define GPIO_PORT_S 18
++#define GPIO_PORT_T 19
++#define GPIO_PORT_U 20
++#define GPIO_PORT_V 21
++#define GPIO_PORT_W 22
++#define GPIO_PORT_X 23
++#define GPIO_PORT_Y 24
++#define GPIO_PORT_Z 25
++#define GPIO_PORT_AA 26
++#define GPIO_PORT_AB 27
++#define GPIO_PORT_AC 28
++
++#define GPIO_PIN_0 0
++#define GPIO_PIN_1 1
++#define GPIO_PIN_2 2
++#define GPIO_PIN_3 3
++#define GPIO_PIN_4 4
++#define GPIO_PIN_5 5
++#define GPIO_PIN_6 6
++#define GPIO_PIN_7 7
++
++#define GPIO_DEBOUNCE_TIMER_0 0x50
++#define GPIO_DEBOUNCE_TIMER_1 0x54
++#define GPIO_DEBOUNCE_TIMER_2 0x58
++
++/* relative to u32ddr base */
++#define GPIO_DATA_VALUE 0x00
++#define GPIO_DIRECTION 0x04
++/* relative to u32intcfg base */
++#define GPIO_INT_ENABLE 0x00
++#define GPIO_INT_SENSE0 0x04
++#define GPIO_INT_SENSE1 0x18
++#define GPIO_INT_SENSE2 0x1c
++#define GPIO_INT_STATUS 0x20
++#define GPIO_RESET_TOL 0x24
++/* relative to u32debounce base */
++#define GPIO_DEBOUNCE_SEL_0 0
++#define GPIO_DEBOUNCE_SEL_1 4
++/* relative to u32cmdsrc base */
++#define GPIO_CMD_SRC_0 0
++#define GPIO_CMD_SRC_1 4
++
++#define PORT_PIN(PORT, PIN) (((PORT) << 3) | ((PIN)&0x07))
++#define GPIO_PIN(N) (N & 0x07)
++#define GPIO_PORT(N) (N >> 3)
++#define GPIO_SHIFT(PORT, PIN) ((PIN) + (((PORT) % 4) * 8))
++#define GPIO_GROUP(PORT) ((PORT) / 4)
++
++#define ID_LED_PORT_PIN PORT_PIN(GPIO_PORT_S, GPIO_PIN_6)
++#define GRN_LED_PORT_PIN PORT_PIN(GPIO_PORT_S, GPIO_PIN_4)
++#define AMB_LED_PORT_PIN PORT_PIN(GPIO_PORT_S, GPIO_PIN_5)
++#define FORCE_BMC_UPDATE_PORT_PIN PORT_PIN(GPIO_PORT_D, GPIO_PIN_0)
++#define TPM_EN_PULSE_PORT_PIN PORT_PIN(GPIO_PORT_D, GPIO_PIN_6)
++
++
++// GPIO Configuration Register bits
++#define GPCFG_EVENT_TO_SMI (1 << 7) // 1 == enabled
++#define GPCFG_EVENT_TO_IRQ (1 << 6) // 1 == enabled
++#define GPCFG_DEBOUNCE_EN (1 << 5) // 1 == input debounce, 0 == pulse output
++#define GPCFG_ACTIVE_HIGH (1 << 4) // 1 == Active high
++#define GPCFG_LEVEL_TRIG (1 << 3) // 1 == level (default), 0 == edge
++#define GPCFG_OUTPUT_EN (1 << 0) // 1 == Output enabled
++
++// GPIO Debounce and Blink Configuration Register bits
++#define GPIO_DEBOUNCE_NONE 0x00
++#define GPIO_DEBOUNCE_60US 0x01
++#define GPIO_DEBOUNCE_8MS 0x02
++#define GPIO_DEBOUNCE_16MS 0x03
++
++typedef struct {
++ uint8_t u8PortPin;
++ uint8_t u8PinCFG;
++ uint8_t u8Value;
++ uint8_t u8Debounce;
++} GPIOValue;
++
++void gpio_init(const GPIOValue* table, size_t count);
++void gpio_set_value(int n, int asserted);
++int gpio_get_value(int n);
++
++#endif /* __HW_GPIO_H__ */
+diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c
+index fca4d91115..252a05dd73 100644
+--- a/board/aspeed/ast-g5/ast-g5-intel.c
++++ b/board/aspeed/ast-g5/ast-g5-intel.c
+@@ -14,6 +14,47 @@
+ #include <asm/arch/aspeed.h>
+
+ #include "ast-g5.h"
++#include "ast-g5-gpio.h"
++
++/* Names to match the GPIOs */
++enum gpio_names {
++ GPIO_ID_LED = 0,
++ GPIO_GREEN_LED,
++ GPIO_AMBER_LED,
++ GPIO_FF_UPD_JUMPER,
++ GPIO_ENABLE_TPM_PULSE,
++};
++
++#define GPIO_CFG_DEFAULT (GPCFG_ACTIVE_HIGH | GPCFG_LEVEL_TRIG)
++// Active High, Level, Output Disabled
++
++#define GPIO_CFG_FP_LED (GPCFG_OUTPUT_EN)
++// Active High, Pull-up, Level, Output Disabled
++
++// Format is:
++// GPIO PORT, GPIO PIN Number, GPIO PIN Configuration, GPIO PIN Value, GPIO
++// Debounce/Blink Setting
++static const GPIOValue gpio_table[] = {
++ /* ID LED pin S6 - low asserted, 0=on */
++ [GPIO_ID_LED] = {ID_LED_PORT_PIN, GPIO_CFG_FP_LED, 0,
++ GPIO_DEBOUNCE_NONE},
++
++ /* Green LED pin S4 - high asserted, 0=off */
++ [GPIO_GREEN_LED] = {GRN_LED_PORT_PIN, GPIO_CFG_FP_LED, 1,
++ GPIO_DEBOUNCE_NONE},
++
++ /* Amber LED pin S5 - high asserted, 0=off */
++ [GPIO_AMBER_LED] = {AMB_LED_PORT_PIN, GPIO_CFG_FP_LED, 1,
++ GPIO_DEBOUNCE_NONE},
++
++ /* Force Update Jumper -- pin D0 */
++ [GPIO_FF_UPD_JUMPER] = {FORCE_BMC_UPDATE_PORT_PIN, GPIO_CFG_DEFAULT, 0,
++ GPIO_DEBOUNCE_8MS},
++
++ /* Enable Pulse -- pin D6 */
++ [GPIO_ENABLE_TPM_PULSE] = {PORT_PIN(GPIO_PORT_D, GPIO_PIN_6),
++ GPIO_CFG_DEFAULT, 0, GPIO_DEBOUNCE_8MS},
++};
+
+ #define LPC_SNOOP_ADDR 0x80
+ #define HICR5 0x080 /* Host Interface Control Register 5 */
+@@ -107,6 +148,7 @@ static void sgpio_init(void)
+ extern void espi_init(void);
+ void ast_g5_intel(void)
+ {
++ gpio_init(gpio_table, ARRAY_SIZE(gpio_table));
+ espi_init();
+ sgpio_init();
+ }
+diff --git a/board/aspeed/ast-g5/ast-g5.h b/board/aspeed/ast-g5/ast-g5.h
+index 9fd10eccb3..908db1477b 100644
+--- a/board/aspeed/ast-g5/ast-g5.h
++++ b/board/aspeed/ast-g5/ast-g5.h
+@@ -3,5 +3,6 @@
+
+ #include <common.h>
+ #include "ast-g5-irq.h"
++#include "ast-g5-gpio.h"
+
+ #endif /* _AST_G5_H_ */
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch
new file mode 100644
index 000000000..c97e6d74f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch
@@ -0,0 +1,98 @@
+From 1f710737f2fe8dea4bc5ebef1e6011de294764b4 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Fri, 16 Nov 2018 14:59:04 -0800
+Subject: [PATCH] Update Force Firmware Update Jumper to use new gpio API
+
+Add a function that allows easy reading of the FFUJ from other
+functions, such as autoboot.
+
+Change-Id: I8ead931e9dd828522095a0ef386875be652ec885
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ .../include/asm/arch-aspeed/ast-g5-intel.h | 19 +++++++++++++++++++
+ arch/arm/include/asm/arch-aspeed/platform.h | 1 +
+ board/aspeed/ast-g5/ast-g5-intel.c | 5 +++++
+ common/autoboot.c | 6 ++++++
+ 4 files changed, 31 insertions(+)
+ create mode 100644 arch/arm/include/asm/arch-aspeed/ast-g5-intel.h
+
+diff --git a/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h
+new file mode 100644
+index 0000000000..cd9a0994fa
+--- /dev/null
++++ b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h
+@@ -0,0 +1,19 @@
++/*
++ * Copyright 2018 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#ifndef __AST_INTEL_G5_H__
++#define __AST_INTEL_G5_H__
++
++#define AST_G5_INTEL 1
++
++#ifndef __ASSEMBLY__
++int intel_force_firmware_jumper_enabled(void);
++#endif
++
++#endif /* __AST_INTEL_G5_H__ */
+diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h
+index 9f339e913a..3ea1c99089 100644
+--- a/arch/arm/include/asm/arch-aspeed/platform.h
++++ b/arch/arm/include/asm/arch-aspeed/platform.h
+@@ -27,6 +27,7 @@
+ #include <asm/arch/ast2400_platform.h>
+ #elif defined(AST_SOC_G5)
+ #include <asm/arch/ast_g5_platform.h>
++#include <asm/arch/ast-g5-intel.h>
+ #define CONFIG_BOARD_EARLY_INIT_F 1 /* Call board_early_init_f */
+ #else
+ #err "No define for platform.h"
+diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c
+index 252a05dd73..58ad6a55b8 100644
+--- a/board/aspeed/ast-g5/ast-g5-intel.c
++++ b/board/aspeed/ast-g5/ast-g5-intel.c
+@@ -145,6 +145,11 @@ static void sgpio_init(void)
+ writel(value, AST_GPIO_BASE + GPIO254);
+ }
+
++int intel_force_firmware_jumper_enabled(void)
++{
++ return gpio_get_value(GPIO_FF_UPD_JUMPER);
++}
++
+ extern void espi_init(void);
+ void ast_g5_intel(void)
+ {
+diff --git a/common/autoboot.c b/common/autoboot.c
+index c52bad84a4..d66c0fa63a 100644
+--- a/common/autoboot.c
++++ b/common/autoboot.c
+@@ -14,6 +14,7 @@
+ #include <menu.h>
+ #include <post.h>
+ #include <u-boot/sha256.h>
++#include <asm/arch/platform.h>
+
+ DECLARE_GLOBAL_DATA_PTR;
+
+@@ -259,6 +260,11 @@ static int abortboot(int bootdelay)
+ {
+ int abort = 0;
+
++# ifdef AST_G5_INTEL
++ if (intel_force_firmware_jumper_enabled())
++ return 1;
++# endif
++
+ if (bootdelay >= 0)
+ abort = __abortboot(bootdelay);
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch
new file mode 100644
index 000000000..11a474b96
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch
@@ -0,0 +1,160 @@
+From 83d67b5b3cbffcefda5efdc0060b9e30f44c9aca Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Fri, 16 Nov 2018 14:44:49 -0800
+Subject: [PATCH 6/7] Add basic timer support for Aspeed g5 in U-Boot
+
+Timers will be used for timing events and making blinky LEDs. This just
+adds the API and infrastructure.
+
+Change-Id: I8ff03b26070b43a47fb970ddf6124d6c3f29b058
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ board/aspeed/ast-g5/Makefile | 1 +
+ board/aspeed/ast-g5/ast-g5-intel.c | 1 +
+ board/aspeed/ast-g5/ast-g5-timer.c | 66 ++++++++++++++++++++++++++++++
+ board/aspeed/ast-g5/ast-g5-timer.h | 27 ++++++++++++
+ board/aspeed/ast-g5/ast-g5.h | 1 +
+ 5 files changed, 96 insertions(+)
+ create mode 100644 board/aspeed/ast-g5/ast-g5-timer.c
+ create mode 100644 board/aspeed/ast-g5/ast-g5-timer.h
+
+diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile
+index 2970ae5741..90224333c4 100644
+--- a/board/aspeed/ast-g5/Makefile
++++ b/board/aspeed/ast-g5/Makefile
+@@ -3,3 +3,4 @@ obj-y += ast-g5-intel.o
+ obj-y += ast-g5-espi.o
+ obj-y += ast-g5-irq.o
+ obj-y += ast-g5-gpio.o
++obj-y += ast-g5-timer.o
+diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c
+index 58ad6a55b8..23bf4e4352 100644
+--- a/board/aspeed/ast-g5/ast-g5-intel.c
++++ b/board/aspeed/ast-g5/ast-g5-intel.c
+@@ -15,6 +15,7 @@
+
+ #include "ast-g5.h"
+ #include "ast-g5-gpio.h"
++#include "ast-g5-timer.h"
+
+ /* Names to match the GPIOs */
+ enum gpio_names {
+diff --git a/board/aspeed/ast-g5/ast-g5-timer.c b/board/aspeed/ast-g5/ast-g5-timer.c
+new file mode 100644
+index 0000000000..56157222d9
+--- /dev/null
++++ b/board/aspeed/ast-g5/ast-g5-timer.c
+@@ -0,0 +1,66 @@
++/*
++ * Copyright 2018 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include <common.h>
++#include <asm/io.h>
++#include <asm/arch/regs-scu.h>
++#include <asm/arch/ast_scu.h>
++#include <asm/arch/aspeed.h>
++
++#include "ast-g5.h"
++#include "ast-g5-timer.h"
++#include "ast-g5-irq.h"
++
++static const int timer_irqs[] = {16, 17, 18, 35, 37, 37, 38, 39};
++/* offsets from AST_TIMER_BASE for each timer */
++static const uint32_t timer_bases[] = {0, 0x10, 0x20, 0x40,
++ 0x50, 0x60, 0x70, 0x80};
++#define TIMER_1MHZ_CLK_COUNT 1000000u
++#define TIMER_ENABLE 1
++#define TIMER_1MHZ_CLK_SEL 2
++#define TIMER_ENABLE_IRQ 4
++#define TIMER_ENABLE_PULSE 8
++#define TIMER_CONTROL 0x30
++#define TIMER_RELOAD 0x04
++
++void timer_enable(int n, uint32_t freq, interrupt_handler_t *handler)
++{
++ if (n < 0 || n > 7) {
++ return;
++ }
++ uint32_t tctrl = readl(AST_TIMER_BASE + TIMER_CONTROL);
++ writel(tctrl & ~(0x0f << (n * 4)), AST_TIMER_BASE + TIMER_CONTROL);
++
++ // figure out best base for requested frequency
++ // (this will give 1MHz clock preference if period is within 1ms of
++ // requested)
++ uint32_t v = TIMER_1MHZ_CLK_COUNT / freq;
++ if (v > 1000 || v * freq == TIMER_1MHZ_CLK_COUNT) {
++ tctrl |= (TIMER_1MHZ_CLK_SEL << (n * 4));
++ } else {
++ uint32_t pclk = ast_get_ahbclk();
++ v = pclk / freq;
++ }
++ writel(v, AST_TIMER_BASE + timer_bases[n] + TIMER_RELOAD);
++ if (handler) {
++ request_irq(timer_irqs[n], handler);
++ tctrl |= (TIMER_ENABLE_IRQ << (n * 4));
++ }
++ tctrl |= (TIMER_ENABLE << (n * 4));
++ writel(tctrl, AST_TIMER_BASE + TIMER_CONTROL);
++}
++
++void timer_disable(int n)
++{
++ if (n < 0 || n > 7) {
++ return;
++ }
++ uint32_t tctrl = readl(AST_TIMER_BASE + TIMER_CONTROL);
++ writel(tctrl & ~(0x0f << (n * 4)), AST_TIMER_BASE + TIMER_CONTROL);
++}
+diff --git a/board/aspeed/ast-g5/ast-g5-timer.h b/board/aspeed/ast-g5/ast-g5-timer.h
+new file mode 100644
+index 0000000000..4b1ac28a9f
+--- /dev/null
++++ b/board/aspeed/ast-g5/ast-g5-timer.h
+@@ -0,0 +1,27 @@
++/*
++ * Copyright 2018 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#ifndef __AST_G5_TIMER_H__
++#define __AST_G5_TIMER_H__
++
++#include <common.h>
++
++#define TIMER_1 0
++#define TIMER_2 1
++#define TIMER_3 2
++#define TIMER_4 3
++#define TIMER_5 4
++#define TIMER_6 5
++#define TIMER_7 6
++#define TIMER_8 7
++
++void timer_enable(int n, uint32_t freq, interrupt_handler_t handler);
++void timer_disable(int n);
++
++#endif /* __AST_G5_TIMER_H__ */
+diff --git a/board/aspeed/ast-g5/ast-g5.h b/board/aspeed/ast-g5/ast-g5.h
+index 908db1477b..28fe5eafcb 100644
+--- a/board/aspeed/ast-g5/ast-g5.h
++++ b/board/aspeed/ast-g5/ast-g5.h
+@@ -4,5 +4,6 @@
+ #include <common.h>
+ #include "ast-g5-irq.h"
+ #include "ast-g5-gpio.h"
++#include "ast-g5-timer.h"
+
+ #endif /* _AST_G5_H_ */
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0012-Add-status-and-ID-LED-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0012-Add-status-and-ID-LED-support.patch
new file mode 100644
index 000000000..5a2c2206f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0012-Add-status-and-ID-LED-support.patch
@@ -0,0 +1,144 @@
+From f0e3631ea3005640f988727f051106d83b5dfdaf Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Wed, 14 Nov 2018 12:16:53 -0800
+Subject: [PATCH 7/7] Add status and ID LED support
+
+Add status (amber and green) and ID (blue) LED support. In the
+bootloader phase, the LEDs should be blinking. When booting linux, they
+should turn to a fixed state.
+
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+Change-Id: Ic9595621b21000ef465ff57ed2047855296e2714
+---
+ board/aspeed/ast-g5/ast-g5-intel.c | 118 +++++++++++++++++++++++++++++
+ 1 file changed, 118 insertions(+)
+
+diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c
+index 23bf4e4352..5ff2cbd0e2 100644
+--- a/board/aspeed/ast-g5/ast-g5-intel.c
++++ b/board/aspeed/ast-g5/ast-g5-intel.c
+@@ -146,6 +146,110 @@ static void sgpio_init(void)
+ writel(value, AST_GPIO_BASE + GPIO254);
+ }
+
++/* running the timer at 48 hertz will easily give a 24Hz blink */
++#define TICK_HZ 48
++#define BLINK_DELAY(HZ) ((int)((TICK_HZ / (HZ)) / 2) - 1)
++typedef enum {
++ /*
++ * Identifies the control request for the ID LED.
++ */
++ EIDLED_Initialize = 0,
++ EIDLED_Tick,
++ EIDLED_Toggle,
++ EIDLED_Off,
++ EIDLED_On,
++ EIDLED_Blink,
++ EIDLED_Blink_24HZ = EIDLED_Blink + BLINK_DELAY(24),
++ EIDLED_Blink_12HZ = EIDLED_Blink + BLINK_DELAY(12),
++ EIDLED_Blink_6HZ = EIDLED_Blink + BLINK_DELAY(6),
++ EIDLED_Blink_3HZ = EIDLED_Blink + BLINK_DELAY(3),
++ EIDLED_Blink_1HZ = EIDLED_Blink + BLINK_DELAY(1),
++ EIDLED_Blink_0_5HZ = EIDLED_Blink + BLINK_DELAY(0.5),
++} EIDLEDControl;
++
++struct led_info {
++ int gpio;
++ EIDLEDControl mode;
++ int count;
++ int state;
++};
++
++static struct led_info s_led_info[] = {
++ [GPIO_ID_LED] = {GPIO_ID_LED, EIDLED_Blink_3HZ, 1, 0},
++ [GPIO_GREEN_LED] = {GPIO_GREEN_LED, EIDLED_Off, 0, 0},
++ [GPIO_AMBER_LED] = {GPIO_AMBER_LED, EIDLED_Off, 0, 0},
++};
++
++extern void gpio_set_value(int n, int asserted);
++void id_led_control(int id, int action)
++{
++ if (id >= ARRAY_SIZE(s_led_info)) {
++ return;
++ }
++ /* don't bother with LEDs that are not initialized */
++ if (EIDLED_Initialize == s_led_info[id].mode) {
++ return;
++ }
++
++ /* check for a blinker action */
++ if (EIDLED_Tick == action) {
++ if (s_led_info[id].mode < EIDLED_Blink) {
++ return;
++ }
++ /* check countdown for blink */
++ if (s_led_info[id].count == 0) {
++ s_led_info[id].count =
++ s_led_info[id].mode - EIDLED_Blink;
++ s_led_info[id].state = !s_led_info[id].state;
++ } else {
++ s_led_info[id].count--;
++ return;
++ }
++ } else if (EIDLED_Toggle == action) {
++ s_led_info[id].state = !s_led_info[id].state;
++ s_led_info[id].mode =
++ s_led_info[id].state ? EIDLED_On : EIDLED_Off;
++ } else if (action > EIDLED_Toggle) {
++ s_led_info[id].mode = action;
++ if (EIDLED_Off == action) {
++ s_led_info[id].state = 0;
++ } else if (EIDLED_On == action) {
++ s_led_info[id].state = 1;
++ } else if (action >= EIDLED_Blink) {
++ s_led_info[id].count = action - EIDLED_Blink;
++ /* wait for the next tick */
++ return;
++ }
++ } else if (EIDLED_Initialize == action) {
++ if (s_led_info[id].mode >= EIDLED_Blink) {
++ s_led_info[id].count =
++ s_led_info[id].mode - EIDLED_Blink;
++ }
++ }
++ gpio_set_value(s_led_info[id].gpio, s_led_info[id].state);
++}
++
++static void timer8_irq_handler(void *regs)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(s_led_info); i++) {
++ id_led_control(i, EIDLED_Tick);
++ }
++}
++
++void timer8_init(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(s_led_info); i++) {
++ id_led_control(i, EIDLED_Initialize);
++ }
++
++ /* set up the timer to fire at TICK_HZ HZ */
++ timer_enable(TIMER_8, TICK_HZ, timer8_irq_handler);
++}
++
+ int intel_force_firmware_jumper_enabled(void)
+ {
+ return gpio_get_value(GPIO_FF_UPD_JUMPER);
+@@ -157,4 +269,10 @@ void ast_g5_intel(void)
+ gpio_init(gpio_table, ARRAY_SIZE(gpio_table));
+ espi_init();
+ sgpio_init();
++ timer8_init();
++ if (intel_force_firmware_jumper_enabled()) {
++ id_led_control(GPIO_AMBER_LED, EIDLED_On);
++ } else {
++ id_led_control(GPIO_GREEN_LED, EIDLED_On);
++ }
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0013-aspeed-Add-Pwm-Driver.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0013-aspeed-Add-Pwm-Driver.patch
new file mode 100644
index 000000000..d235aea62
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0013-aspeed-Add-Pwm-Driver.patch
@@ -0,0 +1,132 @@
+From 3134584998f624bb6c4ee11102b0bd9b7bb1cbba Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Fri, 16 Nov 2018 15:57:57 -0800
+Subject: [PATCH 1/1] aspeed: add Pwm Driver
+
+Change-Id: Ia8b80212f7c70aafcc6a71782936ec95cf9b7f38
+---
+ board/aspeed/ast-g5/ast-g5-intel.c | 105 +++++++++++++++++++++++++++++
+ 1 file changed, 105 insertions(+)
+
+diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c
+index 5ff2cbd0e2..f810ded4e7 100644
+--- a/board/aspeed/ast-g5/ast-g5-intel.c
++++ b/board/aspeed/ast-g5/ast-g5-intel.c
+@@ -263,9 +263,114 @@ int intel_force_firmware_jumper_enabled(void)
+ return gpio_get_value(GPIO_FF_UPD_JUMPER);
+ }
+
++/* PWM offsets */
++
++#define PWM_BASE_ADDR 0x1E786000
++#define PWM_CONTROL 0x00
++#define PWM_CLOCK_SELECTION 0x04
++#define PWM_DUTY_CYCLE 0x08
++#define PWM_M0 0x10
++#define PWM_M1 0x14
++#define PWM_N0 0x18
++#define PWM_N1 0x1c
++#define PWM_CONTROL_EXT 0x40
++#define PWM_CLOCK_SEL_EXT 0x44
++#define PWM_O0 0x50
++#define PWM_O1 0x54
++#define PWM_CHANNEL_COUNT 8
++
++#define PWM_CLK_ENABLE BIT(0)
++#define PWM_DUTY(PCT) (((PCT) * 128) / 100)
++#define PWM_DUTY_VALUE PWM_DUTY(57)
++
++
++static inline uint32_t ast_scu_read(uint32_t reg)
++{
++ uint32_t val = readl(AST_SCU_BASE + reg);
++
++ debug("ast_scu_read : reg = 0x%08x, val = 0x%08x\n", reg, val);
++ return val;
++}
++
++static inline void ast_scu_write(uint32_t val, uint32_t reg)
++{
++ debug("ast_scu_write : reg = 0x%08x, val = 0x%08x\n", reg, val);
++
++ writel(SCU_PROTECT_UNLOCK, AST_SCU_BASE);
++ writel(val, AST_SCU_BASE + reg);
++#ifdef CONFIG_AST_SCU_LOCK
++ writel(0xaa, AST_SCU_BASE);
++#endif
++}
++
++static void pwm_init(void)
++{
++ uint32_t val;
++ uint32_t chan;
++
++ /* select pwm 0-7 */
++ val = ast_scu_read(AST_SCU_FUN_PIN_CTRL3);
++ val |= (SCU_FUN_PIN_VPIG7 | SCU_FUN_PIN_VPIG6 | SCU_FUN_PIN_VPIG5
++ | SCU_FUN_PIN_VPIG4 | SCU_FUN_PIN_VPIG3 | SCU_FUN_PIN_VPIG2
++ | SCU_FUN_PIN_VPIG1 | SCU_FUN_PIN_VPIG0);
++ ast_scu_write(val, AST_SCU_FUN_PIN_CTRL3);
++
++ /* disable video output mux */
++ val = ast_scu_read(AST_SCU_FUN_PIN_CTRL5);
++ val &= 0xffffffcf;
++ ast_scu_write(val, AST_SCU_FUN_PIN_CTRL5);
++ val = readl(AST_SCU_FUN_PIN_CTRL6);
++ val &= 0xfffffffc;
++ ast_scu_write(val, AST_SCU_FUN_PIN_CTRL6);
++
++ /* SCU reset of PWM module */
++ val = ast_scu_read(AST_SCU_RESET);
++ val |= SCU_RESET_PWM;
++ ast_scu_write(val, AST_SCU_RESET);
++ val &= ~SCU_RESET_PWM;
++ ast_scu_write(val, AST_SCU_RESET);
++
++ /* set M, N, and 0 clock regs to 0 */
++ writel(0, PWM_BASE_ADDR + PWM_M0);
++ writel(0, PWM_BASE_ADDR + PWM_N0);
++ writel(0, PWM_BASE_ADDR + PWM_O0);
++
++ /* disable fans and tachos, set M type control */
++ writel(0x1, PWM_BASE_ADDR + PWM_CONTROL);
++ writel(0x1, PWM_BASE_ADDR + PWM_CONTROL_EXT);
++
++ /* enable pwm channels */
++ for (chan = 0; chan < PWM_CHANNEL_COUNT; chan++) {
++ uint32_t base = chan < 4 ? PWM_BASE_ADDR : PWM_BASE_ADDR + 0x40;
++ uint8_t ch_duty_shift = 16 * (chan & 0x1);
++ uint8_t ch_pair = (chan & 0x3) / 2;
++
++ /* enable pwm for the channel */
++ val = readl(base);
++ val |= ((1 << (chan & 0x3)) << 8);
++ writel(val, base);
++
++ /* set duty cycle */
++ val = readl(base + PWM_DUTY_CYCLE + ch_pair * 4);
++ val &= ~(0xffff << ch_duty_shift);
++ val |= (((uint32_t)PWM_DUTY_VALUE) << 8) << ch_duty_shift;
++ writel(val, base + PWM_DUTY_CYCLE + ch_pair * 4);
++ }
++
++ /* set up clock type M: period = 127 units at 24MHz/8 (resulting ~23kHz period) */
++ writel(0x7f30, PWM_BASE_ADDR + PWM_CLOCK_SELECTION);
++
++ /* enable pwm-tacho */
++
++ val = readl(PWM_BASE_ADDR + PWM_CONTROL);
++ val |= PWM_CLK_ENABLE;
++ writel(val, PWM_BASE_ADDR + PWM_CONTROL);
++}
++
+ extern void espi_init(void);
+ void ast_g5_intel(void)
+ {
++ pwm_init();
+ gpio_init(gpio_table, ARRAY_SIZE(gpio_table));
+ espi_init();
+ sgpio_init();
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0014-Keep-interrupts-enabled-until-last-second.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0014-Keep-interrupts-enabled-until-last-second.patch
new file mode 100644
index 000000000..91665e064
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0014-Keep-interrupts-enabled-until-last-second.patch
@@ -0,0 +1,91 @@
+From 2078771e0ff84be710250b2e9b2e887f7238f9cc Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Sat, 17 Nov 2018 14:17:27 -0800
+Subject: [PATCH 2/3] Keep interrupts enabled until last second
+
+The U-Boot bootm command disabled interrupts almost first thing. This
+would prevent a person hitting the power button on the host immediatly
+after AC on because the BMC would fail to respond to the espi interrupts
+and the host would power off.
+
+Change-Id: I6c0fb5cca1be6c326da4c9a3d3dfbab89dac9928
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ board/aspeed/ast-g5/ast-g5-intel.c | 8 ++++++++
+ common/bootm.c | 7 -------
+ common/bootm_os.c | 1 +
+ 3 files changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c
+index f810ded4e7..4d399be392 100644
+--- a/board/aspeed/ast-g5/ast-g5-intel.c
++++ b/board/aspeed/ast-g5/ast-g5-intel.c
+@@ -263,6 +263,14 @@ int intel_force_firmware_jumper_enabled(void)
+ return gpio_get_value(GPIO_FF_UPD_JUMPER);
+ }
+
++void arch_preboot_os(void)
++{
++ // last second before booting... set the LEDs
++ id_led_control(GPIO_ID_LED, EIDLED_On);
++ id_led_control(GPIO_GREEN_LED, EIDLED_On);
++ id_led_control(GPIO_AMBER_LED, EIDLED_Off);
++}
++
+ /* PWM offsets */
+
+ #define PWM_BASE_ADDR 0x1E786000
+diff --git a/common/bootm.c b/common/bootm.c
+index 2431019b3f..46909ecdbb 100644
+--- a/common/bootm.c
++++ b/common/bootm.c
+@@ -602,7 +602,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+ int states, bootm_headers_t *images, int boot_progress)
+ {
+ boot_os_fn *boot_fn;
+- ulong iflag = 0;
+ int ret = 0, need_boot_fn;
+
+ images->state |= states;
+@@ -626,7 +625,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+ if (!ret && (states & BOOTM_STATE_LOADOS)) {
+ ulong load_end;
+
+- iflag = bootm_disable_interrupts();
+ ret = bootm_load_os(images, &load_end, 0);
+ if (ret == 0)
+ lmb_reserve(&images->lmb, images->os.load,
+@@ -670,8 +668,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+ BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |
+ BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);
+ if (boot_fn == NULL && need_boot_fn) {
+- if (iflag)
+- enable_interrupts();
+ printf("ERROR: booting os '%s' (%d) is not supported\n",
+ genimg_get_os_name(images->os.os), images->os.os);
+ bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);
+@@ -711,9 +707,6 @@ int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+
+ /* Deal with any fallout */
+ err:
+- if (iflag)
+- enable_interrupts();
+-
+ if (ret == BOOTM_ERR_UNIMPLEMENTED)
+ bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
+ else if (ret == BOOTM_ERR_RESET)
+diff --git a/common/bootm_os.c b/common/bootm_os.c
+index 9ec84bd0db..b56eb39780 100644
+--- a/common/bootm_os.c
++++ b/common/bootm_os.c
+@@ -476,6 +476,7 @@ __weak void arch_preboot_os(void)
+ int boot_selected_os(int argc, char * const argv[], int state,
+ bootm_headers_t *images, boot_os_fn *boot_fn)
+ {
++ disable_interrupts();
+ arch_preboot_os();
+ boot_fn(state, argc, argv, images);
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0015-Rewrite-memmove-to-optimize-on-word-transfers.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0015-Rewrite-memmove-to-optimize-on-word-transfers.patch
new file mode 100644
index 000000000..475b8c3ff
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0015-Rewrite-memmove-to-optimize-on-word-transfers.patch
@@ -0,0 +1,114 @@
+From a71794fc928429e199c5ea48181e5edfbb0c4f39 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Mon, 19 Nov 2018 11:04:02 -0800
+Subject: [PATCH] Rewrite memmove to optimize on word transfers
+
+Reading from the flash at boot time was using byte-sized transfers,
+which ultimately turns into four word transfers over spi for every real
+word read. This change breaks memmove down into a header, body, and
+trailer, where the body is all done with word-sized transfers.
+
+Change-Id: Ie0a1f3261e507fb34a908571883d9bf04a1059ee
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ lib/string.c | 77 +++++++++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 64 insertions(+), 13 deletions(-)
+
+diff --git a/lib/string.c b/lib/string.c
+index 67d5f6a421..0bf472f1f6 100644
+--- a/lib/string.c
++++ b/lib/string.c
+@@ -505,26 +505,77 @@ void * memcpy(void *dest, const void *src, size_t count)
+ *
+ * Unlike memcpy(), memmove() copes with overlapping areas.
+ */
+-void * memmove(void * dest,const void *src,size_t count)
++void *memmove(void *dest, const void *src, size_t count)
+ {
+- char *tmp, *s;
+-
+- if (src == dest)
++ unsigned char *bdst = (unsigned char *)dest;
++ const unsigned char *bsrc = (const unsigned char *)src;
++ unsigned long *ldst;
++ const unsigned long *lsrc;
++ size_t unaligned_header = 0, unaligned_trailer = 0;
++ size_t unaligned_src =
++ (sizeof(*ldst) - (size_t)src) & (sizeof(*ldst) - 1);
++ size_t unaligned_dst =
++ (sizeof(*ldst) - (size_t)dest) & (sizeof(*ldst) - 1);
++
++ if (src == dest || !count)
+ return dest;
+
++ if (unaligned_src || unaligned_dst) {
++ if (unaligned_dst != unaligned_src) {
++ unaligned_header = count;
++ } else {
++ unaligned_header = unaligned_src;
++ if (unaligned_header > count) {
++ unaligned_header = count;
++ }
++ }
++ count -= unaligned_header;
++ }
++ if (count & (sizeof(*ldst) - 1)) {
++ unaligned_trailer = count & (sizeof(*ldst) - 1);
++ count -= unaligned_trailer;
++ }
++
+ if (dest <= src) {
+- tmp = (char *) dest;
+- s = (char *) src;
+- while (count--)
+- *tmp++ = *s++;
++ /* possible un-aligned bytes */
++ while (unaligned_header--)
++ *bdst++ = *bsrc++;
++
++ /* aligned words */
++ ldst = (unsigned long *)bdst;
++ lsrc = (const unsigned long *)bsrc;
++ while (count >= sizeof(*ldst)) {
++ count -= sizeof(*ldst);
++ *ldst++ = *lsrc++;
+ }
+- else {
+- tmp = (char *) dest + count;
+- s = (char *) src + count;
+- while (count--)
+- *--tmp = *--s;
++
++ /* possibly un-aligned bytes */
++ bdst = (unsigned char *)ldst;
++ bsrc = (const unsigned char *)lsrc;
++ while (unaligned_trailer--)
++ *bdst++ = *bsrc++;
++ } else {
++ bdst += unaligned_header + count + unaligned_trailer;
++ bsrc += unaligned_header + count + unaligned_trailer;
++
++ /* possibly un-aligned bytes */
++ while (unaligned_trailer--)
++ *--bdst = *--bsrc;
++
++ /* aligned words */
++ ldst = (unsigned long *)bdst;
++ lsrc = (unsigned long *)bsrc;
++ while (count >= sizeof(*ldst)) {
++ count -= sizeof(*ldst);
++ *--ldst = *--lsrc;
+ }
+
++ /* possibly un-aligned bytes */
++ bdst = (unsigned char *)ldst;
++ bsrc = (const unsigned char *)lsrc;
++ while (unaligned_header--)
++ *--bdst = *--bsrc;
++ }
+ return dest;
+ }
+ #endif
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch
new file mode 100644
index 000000000..cc1e56fdb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch
@@ -0,0 +1,28 @@
+From 8992df8f3a0f5fc16ec41ad6dd7a5a13e6f94d32 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Wed, 5 Dec 2018 16:13:15 -0800
+Subject: [PATCH] Add support for 128MB Macronix spi flash MX66L1G45G
+
+This will enable u-boot support for the Macronix MX66L1G45G part.
+
+Change-Id: I5edc69357a8b1607c5c44e53bed3eddf38fdc0be
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ drivers/mtd/spi/sf_params.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c
+index c577d9ed6c..d2a96efe48 100644
+--- a/drivers/mtd/spi/sf_params.c
++++ b/drivers/mtd/spi/sf_params.c
+@@ -50,6 +50,7 @@ const struct spi_flash_params spi_flash_params_table[] = {
+ {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
+ {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP},
+ {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP},
++ {"MX66L1G45G", 0xc2201b, 0x0, 64 * 1024, 2048, RD_FULL, SECT_4K|WR_QPP},
+ {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP},
+ #endif
+ #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0017-Enable-Macronix-and-Micron-SPI-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0017-Enable-Macronix-and-Micron-SPI-support.patch
new file mode 100644
index 000000000..b26803c95
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0017-Enable-Macronix-and-Micron-SPI-support.patch
@@ -0,0 +1,54 @@
+From 8415002a2e77a41831b3064dae264f60996ac88a Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 6 Dec 2018 15:07:09 -0800
+Subject: [PATCH] Enable Macronix and Micron SPI support
+
+This commit enables Macronix and Micron SPI support.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ configs/ast_g5_ncsi_2boot_defconfig | 2 ++
+ configs/ast_g5_ncsi_defconfig | 2 ++
+ configs/ast_g5_phy_defconfig | 2 ++
+ 3 files changed, 6 insertions(+)
+
+diff --git a/configs/ast_g5_ncsi_2boot_defconfig b/configs/ast_g5_ncsi_2boot_defconfig
+index d5b7894a9e00..abceed817615 100644
+--- a/configs/ast_g5_ncsi_2boot_defconfig
++++ b/configs/ast_g5_ncsi_2boot_defconfig
+@@ -10,6 +10,8 @@ CONFIG_FIT_VERBOSE=y
+ CONFIG_HUSH_PARSER=y
+ CONFIG_OF_LIBFDT=y
+ CONFIG_SPI_FLASH=y
++CONFIG_SPI_FLASH_MACRONIX=y
++CONFIG_SPI_FLASH_STMICRO=y
+ CONFIG_SYS_NS16550=y
+ CONFIG_FIRMWARE_2ND_BOOT=y
+ CONFIG_AUTOBOOT=y
+diff --git a/configs/ast_g5_ncsi_defconfig b/configs/ast_g5_ncsi_defconfig
+index 9481e5fb6e9d..3f504a325649 100644
+--- a/configs/ast_g5_ncsi_defconfig
++++ b/configs/ast_g5_ncsi_defconfig
+@@ -10,5 +10,7 @@ CONFIG_FIT_VERBOSE=y
+ CONFIG_HUSH_PARSER=y
+ CONFIG_OF_LIBFDT=y
+ CONFIG_SPI_FLASH=y
++CONFIG_SPI_FLASH_MACRONIX=y
++CONFIG_SPI_FLASH_STMICRO=y
+ CONFIG_SYS_NS16550=y
+ CONFIG_USE_IRQ=y
+diff --git a/configs/ast_g5_phy_defconfig b/configs/ast_g5_phy_defconfig
+index 4aefcf49e880..8f0919043376 100644
+--- a/configs/ast_g5_phy_defconfig
++++ b/configs/ast_g5_phy_defconfig
+@@ -11,5 +11,7 @@ CONFIG_FIT_VERBOSE=y
+ CONFIG_HUSH_PARSER=y
+ CONFIG_OF_LIBFDT=y
+ CONFIG_SPI_FLASH=y
++CONFIG_SPI_FLASH_MACRONIX=y
++CONFIG_SPI_FLASH_STMICRO=y
+ CONFIG_SYS_NS16550=y
+ CONFIG_USE_IRQ=y
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch
new file mode 100644
index 000000000..b96211118
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch
@@ -0,0 +1,65 @@
+From 5f2a7c03c877454eb78a406934abf6b7d05e40a6 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 6 Dec 2018 18:49:04 -0800
+Subject: [PATCH] Add support for Macronix and Micron 1Gbits SPI flash
+
+Quick fix to support Macronix and Micron 1Gbits SPI.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/mach-aspeed/flash.c | 32 ++++++++++++++++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+
+diff --git a/arch/arm/mach-aspeed/flash.c b/arch/arm/mach-aspeed/flash.c
+index f9f1345523d4..abc0420176a6 100644
+--- a/arch/arm/mach-aspeed/flash.c
++++ b/arch/arm/mach-aspeed/flash.c
+@@ -79,6 +79,8 @@ flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* FLASH chips info */
+ #define MX25L12805D 0x1820C2
+ #define MX25L25635E 0x1920C2
+ #define MX66L51235F 0x1A20C2
++#define MX66L1G45G 0x1B20C2
++#define MT25QL01GB 0x21BA20
+ #define SST25VF016B 0x4125bf
+ #define SST25VF064C 0x4b25bf
+ #define SST25VF040B 0x8d25bf
+@@ -977,6 +979,36 @@ static ulong flash_get_size (ulong base, flash_info_t *info)
+ #endif
+ break;
+
++ case MT25QL01GB:
++ case MX66L1G45G:
++ erase_region_size = 0x10000;
++ info->readcmd = 0x0b;
++ info->dualport = 0;
++ info->dummybyte = 1;
++ info->buffersize = 256;
++ WriteClk = 50;
++ EraseClk = 20;
++ ReadClk = 50;
++#if 1
++ info->sector_count = 2048;
++ info->size = 0x4000000;
++ info->address32 = 1;
++#if defined(CONFIG_FLASH_SPIx2_Dummy)
++ info->readcmd = 0xbb;
++ info->dummybyte = 1;
++ info->dualport = 1;
++ info->iomode = IOMODEx2_dummy;
++#elif defined(CONFIG_FLASH_SPIx4_Dummy)
++ info->readcmd = 0xeb;
++ info->dummybyte = 3;
++ info->dualport = 0;
++ info->iomode = IOMODEx4_dummy;
++ info->quadport = 1;
++ info->dummydata = 0xaa;
++#endif
++#endif
++ break;
++
+ case MX25L12805D:
+ info->sector_count = 256;
+ info->size = 0x1000000;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0019-u-boot-full-platform-reset-espi-oob-ready.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0019-u-boot-full-platform-reset-espi-oob-ready.patch
new file mode 100644
index 000000000..1d2b02954
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0019-u-boot-full-platform-reset-espi-oob-ready.patch
@@ -0,0 +1,48 @@
+From bb490aa226dcf261d3d6865be37130765ecbe9f4 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@intel.com>
+Date: Mon, 17 Dec 2018 20:37:23 -0800
+Subject: [PATCH] u-boot: full platform reset + espi oob-ready
+
+If the platform is strapped for fast reset, have platform-g5.S do a full
+reset and then immediately set oob-ready so the espi master controller
+can initiate communication.
+
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ arch/arm/mach-aspeed/platform_g5.S | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-aspeed/platform_g5.S b/arch/arm/mach-aspeed/platform_g5.S
+index 2ac1ca4721..66427b6f33 100644
+--- a/arch/arm/mach-aspeed/platform_g5.S
++++ b/arch/arm/mach-aspeed/platform_g5.S
+@@ -139,7 +139,7 @@
+ But if FW has other initial code executed before platform.S, then it should use WDT_SOC mode.
+ Use WDT_Full may clear the initial result of prior initial code.
+ ******************************************************************************/
+-//#define ASTMMC_INIT_RESET_MODE_FULL
++#define ASTMMC_INIT_RESET_MODE_FULL
+
+ /******************************************************************************
+ There is a compatibility issue for Hynix DDR4 SDRAM.
+@@ -563,6 +563,17 @@ wait_first_reset:
+ *******************************************/
+
+ bypass_first_reset:
++ /* Timing from ESPI master requires OOB channel ready bit be set early */
++ ldr r0, =0x1e6e2070 @ check strapping for eSPI mode
++ tst r0, #0x02000000 @ Test for bit 25 - eSPI Mode
++ beq espi_early_init_done @ if bit 25 clear, dont set OOB ready
++
++ ldr r0, =0x1e6ee000
++ ldr r1, [r0] @ ESPI000: ESPI Engine Control Reg
++ orr r1, r1, #0x00000010 @ Set OOB Channel Ready bit
++ str r1, [r0]
++espi_early_init_done:
++
+ /* Enable Timer separate clear mode */
+ ldr r0, =0x1e782038
+ mov r1, #0xAE
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Add-system-reset-status-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Add-system-reset-status-support.patch
new file mode 100644
index 000000000..814a7dc2a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Add-system-reset-status-support.patch
@@ -0,0 +1,206 @@
+From d0338f68edb7f818b45ee43765cf124c14ccae03 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Tue, 22 Jan 2019 16:15:36 +0800
+Subject: [PATCH] Add system reset status support
+
+Will display the reset reasons and other CPU information in u-boot,
+and save the reset reasons into kernel command line,
+for applications to query.
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ arch/arm/include/asm/arch-aspeed/ast_scu.h | 1 +
+ arch/arm/include/asm/arch-aspeed/platform.h | 2 ++
+ arch/arm/mach-aspeed/ast-scu.c | 55 +++++++++++++++++++++++++++++
+ board/aspeed/ast-g5/ast-g5-intel.c | 30 ++++++++++++++++
+ board/aspeed/ast-g5/ast-g5.c | 7 ++++
+ 5 files changed, 95 insertions(+)
+
+diff --git a/arch/arm/include/asm/arch-aspeed/ast_scu.h b/arch/arm/include/asm/arch-aspeed/ast_scu.h
+index c10e6a9..369c4e3 100644
+--- a/arch/arm/include/asm/arch-aspeed/ast_scu.h
++++ b/arch/arm/include/asm/arch-aspeed/ast_scu.h
+@@ -37,6 +37,7 @@ extern void ast_scu_get_who_init_dram(void);
+
+ extern u32 ast_get_clk_source(void);
+ extern u32 ast_get_h_pll_clk(void);
++extern u32 ast_get_m_pll_clk(void);
+ extern u32 ast_get_ahbclk(void);
+
+ extern u32 ast_scu_get_vga_memsize(void);
+diff --git a/arch/arm/include/asm/arch-aspeed/platform.h b/arch/arm/include/asm/arch-aspeed/platform.h
+index 3b06e52..4e4140d 100644
+--- a/arch/arm/include/asm/arch-aspeed/platform.h
++++ b/arch/arm/include/asm/arch-aspeed/platform.h
+@@ -29,6 +29,8 @@
+ #include <asm/arch/ast_g5_platform.h>
+ #include <asm/arch/ast-g5-intel.h>
+ #define CONFIG_BOARD_EARLY_INIT_F 1 /* Call board_early_init_f */
++#define CONFIG_BOARD_LATE_INIT 1 /* Call board_late_init */
++#define CONFIG_DISPLAY_CPUINFO 1
+ #else
+ #err "No define for platform.h"
+ #endif
+diff --git a/arch/arm/mach-aspeed/ast-scu.c b/arch/arm/mach-aspeed/ast-scu.c
+index 63e9c7c..f4268f3 100644
+--- a/arch/arm/mach-aspeed/ast-scu.c
++++ b/arch/arm/mach-aspeed/ast-scu.c
+@@ -100,6 +100,7 @@ static struct soc_id soc_map_table[] = {
+ SOC_ID("AST2510-A1", 0x04010103),
+ SOC_ID("AST2520-A1", 0x04010203),
+ SOC_ID("AST2530-A1", 0x04010403),
++ SOC_ID("AST2500-A2", 0x04030303),
+ };
+
+ void ast_scu_init_eth(u8 num)
+@@ -235,6 +236,29 @@ u32 ast_get_h_pll_clk(void)
+ return clk;
+ }
+
++u32 ast_get_m_pll_clk(void)
++{
++ u32 clk=0;
++ u32 m_pll_set = ast_scu_read(AST_SCU_M_PLL);
++
++ if(m_pll_set & SCU_M_PLL_OFF)
++ return 0;
++
++ // Programming
++ clk = ast_get_clk_source();
++ if(m_pll_set & SCU_M_PLL_BYPASS) {
++ return clk;
++ } else {
++ //PD == SCU20[13:18]
++ //M == SCU20[5:12]
++ //N == SCU20[0:4]
++ //mpll = 24MHz * [(M+1) /(N+1)] / (P+1)
++ clk = ((clk * (SCU_M_PLL_GET_MNUM(m_pll_set) + 1)) / (SCU_M_PLL_GET_NNUM(m_pll_set) + 1))/(SCU_M_PLL_GET_PDNUM(m_pll_set) + 1);
++ }
++ debug("m_pll = %d\n",clk);
++ return clk;
++}
++
+ u32 ast_get_ahbclk(void)
+ {
+ unsigned int axi_div, ahb_div, hpll;
+@@ -304,6 +328,33 @@ u32 ast_get_h_pll_clk(void)
+ return clk;
+ }
+
++u32 ast_get_m_pll_clk(void)
++{
++ u32 clk=0;
++ u32 m_pll_set = ast_scu_read(AST_SCU_M_PLL);
++
++ if(m_pll_set & SCU_M_PLL_OFF)
++ return 0;
++
++ // Programming
++ clk = ast_get_clk_source();
++ if(m_pll_set & SCU_M_PLL_BYPASS) {
++ return clk;
++ } else {
++ //OD == SCU24[4]
++ //OD = SCU_M_PLL_GET_DIV(h_pll_set);
++ //Numerator == SCU24[10:5]
++ //num = SCU_M_PLL_GET_NUM(h_pll_set);
++ //Denumerator == SCU24[3:0]
++ //denum = SCU_M_PLL_GET_DENUM(h_pll_set);
++
++ //hpll = 24MHz * (2-OD) * ((Numerator+2)/(Denumerator+1))
++ clk = (clk * (2-SCU_M_PLL_GET_DIV(m_pll_set)) * ((SCU_M_PLL_GET_NUM(m_pll_set)+2)/(SCU_M_PLL_GET_DENUM(m_pll_set)+1)));
++ }
++ debug("m_pll = %d\n",clk);
++ return clk;
++}
++
+ u32 ast_get_ahbclk(void)
+ {
+ unsigned int div, hpll;
+@@ -452,6 +503,9 @@ void ast_scu_sys_rest_info(void)
+ {
+ u32 rest = ast_scu_read(AST_SCU_SYS_CTRL);
+
++#ifdef AST_SOC_G5
++ printf("RST : 0x%02x\n", rest);
++#else
+ if (rest & SCU_SYS_EXT_RESET_FLAG) {
+ printf("RST : External\n");
+ ast_scu_write(SCU_SYS_EXT_RESET_FLAG, AST_SCU_SYS_CTRL);
+@@ -464,6 +518,7 @@ void ast_scu_sys_rest_info(void)
+ } else {
+ printf("RST : CLK en\n");
+ }
++#endif
+ }
+
+ u32 ast_scu_get_vga_memsize(void)
+diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c
+index bcaf81e..1e8708a 100644
+--- a/board/aspeed/ast-g5/ast-g5-intel.c
++++ b/board/aspeed/ast-g5/ast-g5-intel.c
+@@ -303,6 +303,36 @@ static inline void ast_scu_write(uint32_t val, uint32_t reg)
+ #endif
+ }
+
++void ast_g5_intel_late_init(void)
++{
++ char *cmdline = NULL;
++ char *cmdline_new = NULL;
++ char buf[32];
++ u32 rest = 0;
++
++ /* save and clear reset status */
++ rest = ast_scu_read(AST_SCU_SYS_CTRL);
++ snprintf(buf, sizeof(buf), " resetreason=0x%x", rest);
++ ast_scu_write(0, AST_SCU_SYS_CTRL);
++
++ cmdline = getenv("bootargs");
++ if (!cmdline) {
++ printf("Get bootargs fail!\n");
++ return;
++ }
++
++ cmdline_new = malloc(strlen(cmdline) + strlen(buf) + 1);
++ if (!cmdline_new) {
++ printf("Cannot malloc memory!\n");
++ return;
++ }
++
++ /* append the reset status into kernel command line */
++ snprintf(cmdline_new, strlen(cmdline) + strlen(buf) + 1, "%s%s", cmdline, buf);
++ setenv("bootargs", cmdline_new);
++ free(cmdline_new);
++}
++
+ static void pwm_init(void)
+ {
+ uint32_t val;
+diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c
+index d41ef9c..0953677 100644
+--- a/board/aspeed/ast-g5/ast-g5.c
++++ b/board/aspeed/ast-g5/ast-g5.c
+@@ -19,6 +19,7 @@
+ DECLARE_GLOBAL_DATA_PTR;
+
+ extern void ast_g5_intel(void);
++extern void ast_g5_intel_late_init(void);
+
+ int board_early_init_f(void)
+ {
+@@ -40,6 +41,12 @@ int board_init(void)
+ return 0;
+ }
+
++int board_late_init(void)
++{
++ ast_g5_intel_late_init();
++ return 0;
++}
++
+ int dram_init(void)
+ {
+ u32 vga = ast_scu_get_vga_memsize();
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Enable-PCIe-L1-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Enable-PCIe-L1-support.patch
new file mode 100644
index 000000000..bdf3d2ddd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0020-Enable-PCIe-L1-support.patch
@@ -0,0 +1,38 @@
+From 22c61ba094d8ebdbdcb44f848eef1f5d87a4be87 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 8 Jan 2019 13:33:15 -0800
+Subject: [PATCH] Enable PCIe L1 support
+
+This commit enables PCIe L1 support using magic registers.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/mach-aspeed/platform_g5.S | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/arch/arm/mach-aspeed/platform_g5.S b/arch/arm/mach-aspeed/platform_g5.S
+index 66427b6f33e7..b4043534b083 100644
+--- a/arch/arm/mach-aspeed/platform_g5.S
++++ b/arch/arm/mach-aspeed/platform_g5.S
+@@ -2432,6 +2432,18 @@ spi_cbr_end:
+ bic r1, r1, #0x00400000
+ str r1, [r0]
+
++ ldr r0, =0x1e6ed07c @ Enable PCIe L1 support
++ ldr r1, =0xa8
++ str r1, [r0]
++
++ ldr r0, =0x1e6ed068
++ ldr r1, =0xc81f0a
++ str r1, [r0]
++
++ ldr r0, =0x1e6ed07c
++ mov r1, #0
++ str r1, [r0]
++
+ /******************************************************************************
+ Configure MAC timing
+ ******************************************************************************/
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-Config-host-uart-clock-source-using-environment-vari.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-Config-host-uart-clock-source-using-environment-vari.patch
new file mode 100755
index 000000000..310d9359b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0021-Config-host-uart-clock-source-using-environment-vari.patch
@@ -0,0 +1,108 @@
+From c82ba33ea40e0007945cbc93da58f296fdeedeaf Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Mon, 11 Feb 2019 15:19:56 +0800
+Subject: [PATCH] Config host uart clock source using environment variable
+
+In order to support high speed uart for host uarts,
+the uart clock needs to be switched between 24M and 192M.
+Config SCU4C based on environment variable hostserialcfg,
+this variable is set by IPMI OEM commands.
+
+Tested:
+Change the hostserialcfg variable to 0/1/2/3,
+using the below commands:
+
+ipmitool raw 0x32 0x90 1 0; reboot
+cat /sys/class/tty/ttyS*/uartclk, all should be 24MHz
+
+ipmitool raw 0x32 0x90 1 1; reboot
+cat /sys/class/tty/ttyS*/uartclk, ttyS0/2/3 should be 192MHz
+
+ipmitool raw 0x32 0x90 1 2; reboot
+cat /sys/class/tty/ttyS*/uartclk, ttyS1 should be 192MHz
+
+ipmitool raw 0x32 0x90 1 3; reboot
+cat /sys/class/tty/ttyS*/uartclk, ttyS0/12/3 should be 192MHz
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ arch/arm/include/asm/arch-aspeed/regs-scu.h | 5 ++++
+ board/aspeed/ast-g5/ast-g5-intel.c | 39 +++++++++++++++++++++++++++++
+ 2 files changed, 44 insertions(+)
+
+diff --git a/arch/arm/include/asm/arch-aspeed/regs-scu.h b/arch/arm/include/asm/arch-aspeed/regs-scu.h
+index 10b983a..8a596ce 100644
+--- a/arch/arm/include/asm/arch-aspeed/regs-scu.h
++++ b/arch/arm/include/asm/arch-aspeed/regs-scu.h
+@@ -529,6 +529,11 @@
+ /* AST_SCU_MAC_CLK 0x48 - MAC interface clock delay setting register */
+
+ /* AST_SCU_MISC2_CTRL 0x4C - Misc. 2 Control register */
++#define SCU_UART5_HS_CLOCK (1 << 28)
++#define SCU_UART4_HS_CLOCK (1 << 27)
++#define SCU_UART3_HS_CLOCK (1 << 26)
++#define SCU_UART2_HS_CLOCK (1 << 25)
++#define SCU_UART1_HS_CLOCK (1 << 24)
+ #ifdef AST_SOC_G5
+ #define SCU_PCIE_MAPPING_HIGH (1 << 15)
+ #define SCU_MALI_DTY_MODE (1 << 8)
+diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c
+index 1e8708a..f810a40 100644
+--- a/board/aspeed/ast-g5/ast-g5-intel.c
++++ b/board/aspeed/ast-g5/ast-g5-intel.c
+@@ -103,6 +103,9 @@ static const GPIOValue gpio_table[] = {
+ #define SGPIO_ENABLE 1
+ #define GPIO254 0x254
+
++#define HOST_SERIAL_A_HIGH_SPEED (1 << 0)
++#define HOST_SERIAL_B_HIGH_SPEED (1 << 1)
++
+ static void sgpio_init(void)
+ {
+ uint32_t value;
+@@ -310,6 +313,42 @@ void ast_g5_intel_late_init(void)
+ char buf[32];
+ u32 rest = 0;
+
++ /* By default host serail A and B use normal speed */
++ uint32_t host_serial_cfg = 0;
++ char *host_serial_cfg_txt = NULL;
++
++ /* Config the uart clock source based on environment configuration */
++ host_serial_cfg_txt = getenv("hostserialcfg");
++
++ if (host_serial_cfg_txt != NULL)
++ host_serial_cfg = simple_strtoul(host_serial_cfg_txt, NULL, 16);
++
++ if (host_serial_cfg > (HOST_SERIAL_A_HIGH_SPEED | HOST_SERIAL_B_HIGH_SPEED)) {
++ printf("Invalided hostserialcfg %x, use default!\n", host_serial_cfg);
++ host_serial_cfg = 0;
++ }
++
++ /* SOL implementation requires uart1/uart3/uart4 have the same clock
++ * source for data forwarding, config uart3 and uart4
++ */
++ if (host_serial_cfg & HOST_SERIAL_A_HIGH_SPEED) {
++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) |
++ SCU_UART1_HS_CLOCK | SCU_UART3_HS_CLOCK |
++ SCU_UART4_HS_CLOCK, AST_SCU_MISC2_CTRL);
++ } else {
++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) &
++ ~SCU_UART1_HS_CLOCK & ~SCU_UART3_HS_CLOCK &
++ ~SCU_UART4_HS_CLOCK, AST_SCU_MISC2_CTRL);
++ }
++
++ if (host_serial_cfg & HOST_SERIAL_B_HIGH_SPEED) {
++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) |
++ SCU_UART2_HS_CLOCK, AST_SCU_MISC2_CTRL);
++ } else {
++ ast_scu_write(ast_scu_read(AST_SCU_MISC2_CTRL) &
++ ~SCU_UART2_HS_CLOCK, AST_SCU_MISC2_CTRL);
++ }
++
+ /* save and clear reset status */
+ rest = ast_scu_read(AST_SCU_SYS_CTRL);
+ snprintf(buf, sizeof(buf), " resetreason=0x%x", rest);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend
new file mode 100644
index 000000000..9494c823e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-aspeed_%.bbappend
@@ -0,0 +1,28 @@
+FILESEXTRAPATHS_append_wolfpass:= "${THISDIR}/files:"
+
+# the meta-phosphor layer adds this patch, which conflicts
+# with the intel layout for environment
+SRC_URI_remove_wolfpass = " file://0001-configs-ast-Add-redundnant-env.patch"
+
+SRC_URI_append_wolfpass = " file://0001-flash-use-readX-writeX-not-udelay.patch \
+ file://0002-intel-layout-environment-addr.patch \
+ file://0004-Make-sure-debug-uart-is-using-24MHz-clock-source.patch \
+ file://0005-enable-passthrough-in-uboot.patch \
+ file://0006-Add-Aspeed-g5-interrupt-support.patch \
+ file://0007-Add-espi-support.patch \
+ file://0008-add-sgio-support-for-port80-snoop-post-LEDs.patch \
+ file://0009-Add-basic-GPIO-support.patch \
+ file://0010-Update-Force-Firmware-Update-Jumper-to-use-new-gpio.patch \
+ file://0011-Add-basic-timer-support-for-Aspeed-g5-in-U-Boot.patch \
+ file://0012-Add-status-and-ID-LED-support.patch \
+ file://0013-aspeed-Add-Pwm-Driver.patch \
+ file://0014-Keep-interrupts-enabled-until-last-second.patch \
+ file://0015-Rewrite-memmove-to-optimize-on-word-transfers.patch \
+ file://0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch \
+ file://0017-Enable-Macronix-and-Micron-SPI-support.patch \
+ file://0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch \
+ file://0019-u-boot-full-platform-reset-espi-oob-ready.patch \
+ file://0020-Enable-PCIe-L1-support.patch \
+ file://0020-Add-system-reset-status-support.patch \
+ file://0021-Config-host-uart-clock-source-using-environment-vari.patch \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug.bb b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug.bb
new file mode 100644
index 000000000..0cf8ed0f0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug.bb
@@ -0,0 +1,24 @@
+inherit obmc-phosphor-systemd
+
+SUMMARY = "At Scale Debug Service"
+DESCRIPTION = "At Scale Debug Service exposes remote JTAG target debug capabilities"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=40c94c59cbbc218afdd64eec899ad2f6"
+
+inherit cmake
+DEPENDS = "sdbusplus openssl libpam"
+
+do_configure[depends] += "virtual/kernel:do_shared_workdir"
+
+SRC_URI = "git://git@github.com/Intel-BMC/at-scale-debug;protocol=ssh"
+
+SRCREV = "e3ef64c6427f7be7c9cd6aa4cd696dd5c33f5085"
+S = "${WORKDIR}/git"
+
+SYSTEMD_SERVICE_${PN} += "com.intel.AtScaleDebug.service"
+
+# Specify any options you want to pass to cmake using EXTRA_OECMAKE:
+EXTRA_OECMAKE = "-DBUILD_UT=OFF"
+
+CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service
new file mode 100644
index 000000000..65d83b4c4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Intel BMC At Scale Debug
+Requires=com.intel.AtScaleDebugJtagTest.service network-online.target
+
+[Service]
+Restart=always
+RestartSec=30
+ExecStart={bindir}/asd -k /home/root/server.pem
+Type=simple
+SyslogIdentifier=asd
+
+[Install]
+WantedBy=obmc-host-start@0.target
diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service
new file mode 100644
index 000000000..281d1a993
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Intel BMC At Scale Debug JTAG test to check if remote debug setting is enabled
+
+[Service]
+Type=oneshot
+ExecStartPre=/bin/sleep 10
+ExecStart={bindir}/jtag_test
+SyslogIdentifier=jtag_test
+RemainAfterExit=true
+
+[Install]
+WantedBy=obmc-host-start@0.target
diff --git a/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab
new file mode 100644
index 000000000..0b53093ae
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab
@@ -0,0 +1,10 @@
+/dev/root / auto defaults 1 1
+proc /proc proc defaults 0 0
+devpts /dev/pts devpts mode=0620,gid=5 0 0
+tmpfs /run tmpfs mode=0755,nodev,nosuid,strictatime 0 0
+tmpfs /var/lib/systemd/coredump tmpfs rw,nosuid,nodev,size=67108864 0 0
+tmpfs /media tmpfs rw 0 0
+
+# uncomment this if your device has a SD/MMC/Transflash slot
+#/dev/mmcblk0p1 /media/card auto defaults,sync,noauto 0 0
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend
new file mode 100644
index 000000000..79e529179
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend
@@ -0,0 +1,2 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+SRC_URI_append = " file://fstab"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/cpu-log-util/cpu-log-util_git.bb b/meta-openbmc-mods/meta-common/recipes-core/cpu-log-util/cpu-log-util_git.bb
new file mode 100644
index 000000000..170412e0c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/cpu-log-util/cpu-log-util_git.bb
@@ -0,0 +1,27 @@
+inherit obmc-phosphor-dbus-service
+inherit obmc-phosphor-systemd
+
+SUMMARY = "CPU Log Utils"
+DESCRIPTION = "CPU utilities for dumping CPU registers over PECI"
+
+DEPENDS = "boost cjson sdbusplus "
+inherit cmake
+
+LICENSE = "CLOSED"
+LIC_FILES_CHKSUM = ""
+
+SRC_URI = "git://git@github.com/Intel-BMC/at-scale-debug;protocol=ssh"
+SRCREV = "e3ef64c6427f7be7c9cd6aa4cd696dd5c33f5085"
+
+S = "${WORKDIR}/git/cpu-log-util"
+PACKAGES += "libpeci"
+
+SYSTEMD_SERVICE_${PN} += "com.intel.CpuDebugLog.service"
+DBUS_SERVICE_${PN} += "com.intel.CpuDebugLog.service"
+
+# linux-libc-headers guides this way to include custom uapi headers
+CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi"
+CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include"
+CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi"
+CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include"
+do_configure[depends] += "virtual/kernel:do_shared_workdir"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/cpu-log-util/files/com.intel.CpuDebugLog.service b/meta-openbmc-mods/meta-common/recipes-core/cpu-log-util/files/com.intel.CpuDebugLog.service
new file mode 100644
index 000000000..13d2c860e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/cpu-log-util/files/com.intel.CpuDebugLog.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Intel BMC CPU Debug Log
+
+[Service]
+Restart=always
+ExecStart={bindir}/cpu_log
+Type=simple
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh
new file mode 100644
index 000000000..5a2637ba3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+SSH_ID=$HOME/.ssh/id_rsa.db
+[ -e $HOME/.fwupd.defaults ] && source $HOME/.fwupd.defaults
+
+usage() {
+ echo "usage: $(basename $0) uri"
+ echo " uri is something like: file:///path/to/fw"
+ echo " tftp://tftp.server.ip.addr/path/to/fw"
+ echo " scp://[user@]scp.server.ip.addr:/path/to/fw"
+ echo " http[s]://web.server.ip.addr/path/to/fw"
+ echo " ftp://[user@]ftp.server.ip.addr/path/to/fw"
+ exit 1
+}
+
+if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then usage; fi
+if [ $# -eq 0 ]; then
+ # set DEFURI in $HOME/.fwupd.defaults
+ URI="$DEFURI"
+else
+ URI="$1"
+fi
+
+PROTO=$(echo "$URI" | sed 's,\([a-z]*\)://.*$,\1,')
+REMOTE=$(echo "$URI" | sed 's,.*://\(.*\)$,\1,')
+REMOTE_HOST=$(echo "$REMOTE" | sed 's,\([^/]*\)/.*$,\1,')
+if [ "$PROTO" = 'scp' ]; then
+ REMOTE_PATH=$(echo "$REMOTE" | cut -d':' -f2)
+else
+ REMOTE_PATH=$(echo "$REMOTE" | sed 's,[^/]*/\(.*\)$,\1,')
+fi
+LOCAL_PATH="/tmp/$(basename $REMOTE_PATH)"
+echo "PROTO=$PROTO"
+echo "REMOTE=$REMOTE"
+echo "REMOTE_HOST=$REMOTE_HOST"
+echo "REMOTE_PATH=$REMOTE_PATH"
+if [ ! -e $LOCAL_PATH ] || [ $(stat -c %s $LOCAL_PATH) -eq 0 ]; then
+ echo "Download '$REMOTE_PATH' from $PROTO $REMOTE_HOST $REMOTE_PATH"
+ case "$PROTO" in
+ scp)
+ mkdir -p $HOME/.ssh
+ if [ -e "$SSH_ID" ]; then
+ ARG_ID="-i $SSH_ID"
+ fi
+ scp $ARG_ID $REMOTE_HOST$REMOTE_PATH $LOCAL_PATH
+ if [ $? -ne 0 ]; then
+ echo "scp $REMOTE $LOCAL_PATH failed!"
+ exit 255
+ fi
+ ;;
+ tftp)
+ cd /tmp
+ tftp -g -r "$REMOTE_PATH" "$REMOTE_HOST"
+ if [ $? -ne 0 ]; then
+ echo "tftp -g -r \"$REMOTE_PATH\" \"$REMOTE_HOST\" failed!"
+ exit 255
+ fi
+ ;;
+ http|https|ftp)
+ wget --no-check-certificate "$URI" -O "$LOCAL_PATH"
+ if [ $? -ne 0 ]; then
+ echo "wget $URI failed!"
+ exit 255
+ fi
+ ;;
+ file)
+ cp "$REMOTE_PATH" "$LOCAL_PATH"
+ ;;
+ *)
+ echo "Invalid URI $URI"
+ exit 1;
+ ;;
+ esac
+fi
+
+# do a quick sanity check on the image
+if [ $(stat -c "%s" "$LOCAL_PATH") -lt 10000000 ]; then
+ echo "Update file "$LOCAL_PATH" seems to be too small"
+ exit 1
+fi
+dtc -I dtb -O dtb "$LOCAL_PATH" > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo "Update file $LOCAL_PATH doesn't seem to be in the proper format"
+ exit 1
+fi
+
+# guess based on fw_env which partition we booted from
+BOOTADDR=$(fw_printenv bootcmd | awk '{print $2}')
+
+TGT="/dev/mtd/image-a"
+case "$BOOTADDR" in
+ 20080000) TGT="/dev/mtd/image-b"; BOOTADDR="22480000" ;;
+ 22480000) TGT="/dev/mtd/image-a"; BOOTADDR="20080000" ;;
+ *) TGT="/dev/mtd/image-a"; BOOTADDR="20080000" ;;
+esac
+echo "Updating $(basename $TGT) (use bootm $BOOTADDR)"
+flash_erase $TGT 0 0
+echo "Writing $(stat -c "%s" "$LOCAL_PATH") bytes"
+cat "$LOCAL_PATH" > "$TGT"
+fw_setenv "bootcmd" "bootm ${BOOTADDR}"
+
+# reboot
+reboot
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl
new file mode 100644
index 000000000..ae9f54263
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl
@@ -0,0 +1,136 @@
+#!/bin/sh
+
+setup_image()
+{
+ set -x
+ local storage="$1"
+ local sz_mb="$2"
+ # create the backing store
+ dd if=/dev/zero of=$storage bs=1M seek=$sz_mb count=0 2>/dev/null
+ # this shows up as 23FC-F676 in /dev/disk/by-uuid
+ local diskid=0x23FCF676
+ mkdosfs -n 'OPENBMC-FW' -i $diskid -I $storage >/dev/null 2>&1
+}
+
+mount_image()
+{
+ set -x
+ local storage="$1"
+ local stormnt="$2"
+ mkdir -p $stormnt || exit 1
+ mount -o loop -t vfat $storage $stormnt
+}
+
+cleanup_image()
+{
+ set -x
+ local storage="$1"
+ local stormnt="$2"
+ umount -f "$stormnt"
+ rm -f "$storage"
+ rmdir "$stormnt"
+}
+
+GADGET_BASE=/sys/kernel/config/usb_gadget
+
+which_dev()
+{
+ local in_use=$(cat $GADGET_BASE/*/UDC)
+ cd /sys/class/udc
+ for D in *; do
+ case "$in_use" in
+ *"$D"*) ;;
+ *) echo "$D"; return 0;;
+ esac
+ done
+ return 1
+}
+
+usb_ms_insert()
+{
+ local name="$1"
+ local storage="$2"
+
+ if [ -d $GADGET_BASE/$name ]; then
+ echo "device $name already exists" >&2
+ return 1
+ fi
+ mkdir $GADGET_BASE/$name
+ cd $GADGET_BASE/$name
+
+ echo 0x1d6b > idVendor # Linux Foundation
+ echo 0x0105 > idProduct # FunctionFS Gadget
+ mkdir strings/0x409
+ local machineid=$(cat /etc/machine-id)
+ local data="OpenBMC USB mass storage gadget device serial number"
+ local serial=$( echo -n "${machineid}${data}${machineid}" | \
+ sha256sum | cut -b 0-12 )
+ echo $serial > strings/0x409/serialnumber
+ echo OpenBMC > strings/0x409/manufacturer
+ echo "OpenBMC Mass Storage" > strings/0x409/product
+
+ mkdir configs/c.1
+ mkdir functions/mass_storage.$name
+ echo $storage > functions/mass_storage.$name/lun.0/file
+ echo 0 > functions/mass_storage.$name/lun.0/removable
+ mkdir configs/c.1/strings/0x409
+
+ echo "Conf 1" > configs/c.1/strings/0x409/configuration
+ echo 120 > configs/c.1/MaxPower
+ ln -s functions/mass_storage.$name configs/c.1
+ local dev=$(which_dev)
+ echo $dev > UDC
+}
+
+usb_ms_eject()
+{
+ local name="$1"
+
+ echo '' > $GADGET_BASE/$name/UDC
+
+ rm -f $GADGET_BASE/$name/configs/c.1/mass_storage.$name
+ rmdir $GADGET_BASE/$name/configs/c.1/strings/0x409
+ rmdir $GADGET_BASE/$name/configs/c.1
+ rmdir $GADGET_BASE/$name/functions/mass_storage.$name
+ rmdir $GADGET_BASE/$name/strings/0x409
+ rmdir $GADGET_BASE/$name
+}
+
+usage()
+{
+ echo "Usage: $0 <action> ..."
+ echo " $0 setup <file> <sizeMB>"
+ echo " $0 insert <name> <file>"
+ echo " $0 eject <name>"
+ echo " $0 mount <file> <mnt>"
+ echo " $0 cleanup <file> <mnt>"
+ exit 1
+}
+
+echo "$#: $0 $@"
+case "$1" in
+ insert)
+ shift
+ usb_ms_insert "$@"
+ ;;
+ eject)
+ shift
+ usb_ms_eject "$@"
+ ;;
+ setup)
+ shift
+ setup_image "$@"
+ ;;
+ mount)
+ shift
+ mount_image "$@"
+ ;;
+ cleanup)
+ shift
+ cleanup_image "$@"
+ ;;
+ *)
+ usage
+ ;;
+esac
+exit $?
diff --git a/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb b/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb
new file mode 100644
index 000000000..ac8e58c03
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb
@@ -0,0 +1,22 @@
+SUMMARY = "Temporary intel-fw-update script"
+DESCRIPTION = "At runtime, perform a firmware update and reboot"
+PR = "r1"
+
+# flash_eraseall
+RDEPENDS_intel-fw-update += "mtd-utils"
+# wget tftp scp
+RDEPENDS_intel-fw-update += "busybox dropbear"
+# mkfs.vfat, parted
+RDEPENDS_intel-fw-update += "dosfstools parted"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SRC_URI += "file://fwupd.sh"
+SRC_URI += "file://usb-ctrl"
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 ${WORKDIR}/fwupd.sh ${D}${bindir}
+ install -m 0755 ${WORKDIR}/usb-ctrl ${D}${bindir}
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend
new file mode 100644
index 000000000..e0f4d5d2b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend
@@ -0,0 +1,2 @@
+SRC_URI = "git://github.com/openbmc/intel-ipmi-oem.git"
+SRCREV = "7944c3072287a3833a29283aafa8650a31cd4ce7"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/ipmi/ipmi-providers.bb b/meta-openbmc-mods/meta-common/recipes-core/ipmi/ipmi-providers.bb
new file mode 100644
index 000000000..c23da6df2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/ipmi-providers.bb
@@ -0,0 +1,37 @@
+SUMMARY = "Intel IPMI Providers"
+DESCRIPTION = "IPMI Provider Libraries"
+
+SRC_URI = "git://git@github.com/Intel-BMC/intel-ipmi-providers;protocol=ssh"
+SRCREV = "bbb45687fc2993980ac95117d8503ee6c2358965"
+
+S = "${WORKDIR}/git"
+PV = "0.1+git${SRCPV}"
+
+DEPENDS = "boost phosphor-ipmi-host intel-ipmi-oem systemd microsoft-gsl"
+
+inherit cmake obmc-phosphor-ipmiprovider-symlink
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=2ee41112a44fe7014dce33e26468ba93"
+
+EXTRA_OECMAKE="-DENABLE_TEST=0 -DYOCTO=1"
+
+LIBRARY_NAMES += "libmtmcmds.so"
+LIBRARY_NAMES += "libsmbioshandler.so"
+LIBRARY_NAMES += "libzbridgecmd.so"
+LIBRARY_NAMES += "libsmbiosmdrv2.so"
+LIBRARY_NAMES += "libfwupdcmds.so"
+
+HOSTIPMI_PROVIDER_LIBRARY += "${LIBRARY_NAMES}"
+NETIPMI_PROVIDER_LIBRARY += "${LIBRARY_NAMES}"
+
+FILES_${PN}_append = " ${libdir}/ipmid-providers/lib*${SOLIBS}"
+FILES_${PN}_append = " ${libdir}/host-ipmid/lib*${SOLIBS}"
+FILES_${PN}_append = " ${libdir}/net-ipmid/lib*${SOLIBS}"
+FILES_${PN}-dev_append = " ${libdir}/ipmid-providers/lib*${SOLIBSDEV}"
+
+do_configure_prepend() {
+ cp -r ${WORKDIR}/recipe-sysroot${libdir}/phosphor-ipmi-host ${S}
+ cp -r ${WORKDIR}/recipe-sysroot${includedir}/phosphor-ipmi-host ${S}
+ cp -r ${WORKDIR}/recipe-sysroot${includedir}/intel-ipmi-oem ${S}
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-core/microsoft-gsl/microsoft-gsl.bb b/meta-openbmc-mods/meta-common/recipes-core/microsoft-gsl/microsoft-gsl.bb
new file mode 100644
index 000000000..8cb593bce
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/microsoft-gsl/microsoft-gsl.bb
@@ -0,0 +1,24 @@
+# Add GSL: Guideline Support Library for c++
+# https://github.com/Microsoft/GSL
+
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=363055e71e77071107ba2bb9a54bd9a7"
+
+SRC_URI = "git://github.com/Microsoft/GSL.git;protocol=https"
+
+# Modify these as desired
+PV = "1.0+git${SRCPV}"
+#SRCREV = "${AUTOREV}"
+SRCREV = "be43c79742dc36ee55b21c5d531a5ff301d0ef8d"
+
+S = "${WORKDIR}/git"
+
+do_install () {
+ install -d ${D}/usr/include
+ install -d ${D}/usr/include/gsl
+ for F in ${S}/include/gsl/*; do
+ install -m 0644 ${F} ${D}/usr/include/gsl
+ done
+}
+
+ALLOW_EMPTY_${PN} = "1"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend b/meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend
new file mode 100644
index 000000000..584d3b645
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend
@@ -0,0 +1,85 @@
+# WARNING!
+#
+# These modifications to os-release disable the bitbake parse
+# cache (for the os-release recipe only). Before copying
+# and pasting into another recipe ensure it is understood
+# what that means!
+
+def irun_git(d, oeroot, git_cmd, **kwargs):
+ err = None
+ try:
+ cmd = 'git --work-tree {} --git-dir {}/.git {}'.format(oeroot, oeroot, git_cmd)
+ ret, err = bb.process.run(cmd, **kwargs)
+ if err is not None:
+ ret += err
+ except bb.process.ExecutionError as e:
+ ret = ''
+ if e.stdout is not None:
+ ret += e.stdout
+ if e.stderr is not None:
+ ret += e.stderr
+ except Exception as e:
+ ret = str(e)
+ return ret.strip('\n')
+
+def repo_status(d, f, repo, tagargs):
+ import subprocess
+
+ cmd_list = [['HEAD', 'rev-parse HEAD'],
+ ['TAG', 'describe {} --dirty --long'.format(tagargs)],
+ ['STATUS', 'status -sb']]
+
+ f.write(('\n# REPOSITORY: {} '.format(os.path.basename(repo))).ljust(80, '+') + '\n')
+ for item in cmd_list:
+ f.write('# {}: '.format(item[0]))
+ sb = irun_git(d, repo, item[1])
+ if sb:
+ sb_lines = sb.split('\n')
+ if len(sb_lines) == 1:
+ f.write(sb_lines[0])
+ else:
+ f.write('\n# ' + '\n# '.join(sb_lines))
+ f.write('\n')
+
+python() {
+ corebase = d.getVar('COREBASE', True)
+ mibase = os.path.join(corebase, 'meta-openbmc-mods')
+ obmc_vers = irun_git(d, corebase, 'describe --dirty --long')
+ meta_vers = irun_git(d, mibase, 'rev-parse HEAD')[0:7]
+ version_id = '{}-{}'.format(obmc_vers, meta_vers)
+ if version_id:
+ d.setVar('VERSION_ID', version_id)
+ versionList = version_id.split('-')
+ version = '{}-{}'.format(versionList[0], versionList[1])
+ d.setVar('VERSION', version)
+
+ build_id = irun_git(d, corebase, 'describe --abbrev=0')
+ if build_id:
+ d.setVar('BUILD_ID', build_id)
+}
+
+OS_RELEASE_FIELDS_append = " BUILD_ID"
+
+python do_compile_append () {
+ import glob
+ with open(d.expand('${B}/os-release'), 'a') as f:
+ corebase = d.getVar('COREBASE', True)
+ f.write('\n# Build Configuration Details\n')
+ repo_status(d, f, corebase, '')
+ repo_status(d, f, os.path.join(corebase, 'meta-openbmc-mods'), '--tags')
+ appends_dir = os.path.join(d.getVar('TOPDIR', True), 'workspace', 'appends')
+
+ for fn in glob.glob(os.path.join(appends_dir, '*.bbappend')):
+ with open(fn, 'r') as bb_f:
+ for line in bb_f:
+ if line.startswith('# srctreebase: '):
+ srctreebase = line.split(':', 1)[1].strip()
+ repo_status(d, f, srctreebase, '--tags')
+}
+
+
+# Ensure the git commands run every time bitbake is invoked.
+BB_DONT_CACHE = "1"
+
+# Make os-release available to other recipes.
+SYSROOT_DIRS_append = " ${sysconfdir}"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/packagegroups/packagegroup-core-standalone-sdk-target.bbappend b/meta-openbmc-mods/meta-common/recipes-core/packagegroups/packagegroup-core-standalone-sdk-target.bbappend
new file mode 100644
index 000000000..87a4c8503
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/packagegroups/packagegroup-core-standalone-sdk-target.bbappend
@@ -0,0 +1 @@
+RRECOMMENDS_${PN}_append = " vim cmake sdbusplus"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/peci-pcie/peci-pcie_git.bb b/meta-openbmc-mods/meta-common/recipes-core/peci-pcie/peci-pcie_git.bb
new file mode 100644
index 000000000..dec71e0d6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/peci-pcie/peci-pcie_git.bb
@@ -0,0 +1,24 @@
+# NOTE: LICENSE is being set to "CLOSED" for now. The PCIe reads over PECI expose
+# more information than is accessible from the BIOS or OS, so we need to keep this
+# internal to Intel until it's resolved.
+LICENSE = "CLOSED"
+LIC_FILES_CHKSUM = ""
+inherit cmake systemd
+
+SRC_URI = "git://git@github.com/Intel-BMC/provingground;protocol=ssh"
+
+DEPENDS = "boost sdbusplus cpu-log-util"
+
+PV = "0.1+git${SRCPV}"
+SRCREV = "f4d4bfc3296cb27feb17aa5d1d93b3061b56ce10"
+
+S = "${WORKDIR}/git/peci_pcie"
+
+SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.PCIe.service"
+
+# linux-libc-headers guides this way to include custom uapi headers
+CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi"
+CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include"
+CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi"
+CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include"
+do_configure[depends] += "virtual/kernel:do_shared_workdir"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/readline/readline/inputrc b/meta-openbmc-mods/meta-common/recipes-core/readline/readline/inputrc
new file mode 100644
index 000000000..7b84c9916
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/readline/readline/inputrc
@@ -0,0 +1,61 @@
+# /etc/inputrc - global inputrc for libreadline
+# See readline(3readline) and `info rluserman' for more information.
+
+# Be 8 bit clean.
+set input-meta on
+set output-meta on
+
+# To allow the use of 8bit-characters like the german umlauts, comment out
+# the line below. However this makes the meta key not work as a meta key,
+# which is annoying to those which don't need to type in 8-bit characters.
+
+# set convert-meta off
+
+# try to enable the application keypad when it is called. Some systems
+# need this to enable the arrow keys.
+# set enable-keypad on
+
+# see /usr/share/doc/bash/inputrc.arrows for other codes of arrow keys
+
+# do not bell on tab-completion
+# set bell-style none
+
+# some defaults / modifications for the emacs mode
+$if mode=emacs
+
+# allow the use of the Home/End keys
+ "\e[1~": beginning-of-line
+ "\e[4~": end-of-line
+
+# allow the use of the Delete/Insert keys
+ "\e[3~": delete-char
+# "\e[2~": quoted-insert
+
+# mappings for "page up" and "page down" to step to the beginning/end
+# of the history
+# "\e[5~": beginning-of-history
+# "\e[6~": end-of-history
+
+# alternate mappings for "page up" and "page down" to search the history
+# "\e[5~": history-search-backward
+# "\e[6~": history-search-forward
+
+# # mappings for Ctrl-left-arrow and Ctrl-right-arrow for word moving
+# "\e[5C": forward-word
+# "\e[5D": backward-word
+# "\e\e[C": forward-word
+# "\e\e[D": backward-word
+
+# $if term=rxvt
+# "\e[8~": end-of-line
+# $endif
+
+# for non RH/Debian xterm, can't hurt for RH/DEbian xterm
+# "\eOH": beginning-of-line
+# "\eOF": end-of-line
+
+# for freebsd console
+# "\e[H": beginning-of-line
+# "\e[F": end-of-line
+
+$endif
diff --git a/meta-openbmc-mods/meta-common/recipes-core/readline/readline_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/readline/readline_%.bbappend
new file mode 100644
index 000000000..c63a45dd4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/readline/readline_%.bbappend
@@ -0,0 +1,2 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+SRC_URI_append = " file://inputrc"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/rest-dbus/rest-dbus-static.bb b/meta-openbmc-mods/meta-common/recipes-core/rest-dbus/rest-dbus-static.bb
new file mode 100644
index 000000000..429d5b4b4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/rest-dbus/rest-dbus-static.bb
@@ -0,0 +1,23 @@
+SUMMARY = "Phosphor OpenBMC REST framework"
+DESCRIPTION = "Phosphor OpenBMC REST to DBUS daemon."
+HOMEPAGE = "http://github.com/openbmc/rest-dbus"
+PR = "r1"
+
+inherit allarch
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SRC_URI += "git://github.com/openbmc/rest-dbus.git"
+
+SRCREV = "9273a302e8f2b3c3e939dff77758e90f163bf6a1"
+
+S = "${WORKDIR}/git"
+
+FILES_${PN} += "${datadir}/www/rest-dbus/*"
+
+do_install () {
+ install -d ${D}${datadir}/www/rest-dbus/res
+ install -m 644 ${S}/resources/** ${D}${datadir}/www/rest-dbus/res
+ install -m 644 ${S}/resources/index.html ${D}${datadir}/www/rest-dbus/index.html
+}
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/obmc-targets.bbappend b/meta-openbmc-mods/meta-common/recipes-core/systemd/obmc-targets.bbappend
new file mode 100644
index 000000000..3fe1c3f38
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/obmc-targets.bbappend
@@ -0,0 +1,9 @@
+# Remove these files since they are provided by obmc-intel-targets
+SYSTEMD_SERVICE_${PN}_remove += " obmc-host-start@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-host-stop@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-host-reboot@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-host-startmin@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-poweron@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-poweroff@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-hard-poweroff@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-powerreset@.target"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf.bbappend b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf.bbappend
new file mode 100644
index 000000000..8f26d784b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf.bbappend
@@ -0,0 +1,12 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://journald.conf \
+ file://systemd-timesyncd-save-time.conf \
+ "
+
+FILES_${PN} += " ${systemd_system_unitdir}/systemd-timesyncd.service.d/systemd-timesyncd-save-time.conf"
+
+do_install_append() {
+ install -m 644 -D ${WORKDIR}/journald.conf ${D}${sysconfdir}/systemd/journald.conf
+ install -m 644 -D ${WORKDIR}/systemd-timesyncd-save-time.conf ${D}${systemd_system_unitdir}/systemd-timesyncd.service.d/systemd-timesyncd-save-time.conf
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf
new file mode 100644
index 000000000..5d4134cbd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf
@@ -0,0 +1,42 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
+#
+# See journald.conf(5) for details.
+
+[Journal]
+Storage=persistent
+#Compress=yes
+#Seal=yes
+#SplitMode=uid
+#SyncIntervalSec=5m
+#RateLimitIntervalSec=30s
+#RateLimitBurst=10000
+SystemMaxUse=6M
+#SystemKeepFree=
+SystemMaxFileSize=512K
+# SystemMaxFiles=32
+#RuntimeMaxUse=32M
+#RuntimeKeepFree=
+#RuntimeMaxFileSize=
+#RuntimeMaxFiles=4
+#MaxRetentionSec=
+#MaxFileSec=1month
+#ForwardToSyslog=no
+#ForwardToKMsg=no
+#ForwardToConsole=no
+#ForwardToWall=yes
+#TTYPath=/dev/console
+MaxLevelStore=notice
+#MaxLevelSyslog=debug
+#MaxLevelKMsg=notice
+#MaxLevelConsole=info
+#MaxLevelWall=emerg
+#LineMax=48K
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf
new file mode 100644
index 000000000..aa455cbcb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf
@@ -0,0 +1,2 @@
+[Service]
+ExecStop=touch /var/lib/systemd/timesync/clock \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/000-ro-rootfs-tmpfile-defaults.patch b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/000-ro-rootfs-tmpfile-defaults.patch
new file mode 100644
index 000000000..d16f3a2dc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/000-ro-rootfs-tmpfile-defaults.patch
@@ -0,0 +1,51 @@
+From 05e1b853abfd54d117dad25185c602d1791d83f6 Mon Sep 17 00:00:00 2001
+From: David Cobbley <david.j.cobbley@linux.intel.com>
+Date: Tue, 26 Jun 2018 16:10:14 -0700
+Subject: [PATCH] ro-rootfs-tmpfile-defaults
+
+---
+ tmpfiles.d/home.conf | 1 -
+ tmpfiles.d/tmp.conf | 1 -
+ tmpfiles.d/var.conf.m4 | 5 ++++-
+ 3 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/tmpfiles.d/home.conf b/tmpfiles.d/home.conf
+index 9f25b83..5c7513a 100644
+--- a/tmpfiles.d/home.conf
++++ b/tmpfiles.d/home.conf
+@@ -8,4 +8,3 @@
+ # See tmpfiles.d(5) for details
+
+ Q /home 0755 - - -
+-q /srv 0755 - - -
+diff --git a/tmpfiles.d/tmp.conf b/tmpfiles.d/tmp.conf
+index 22555a0..aad1b98 100644
+--- a/tmpfiles.d/tmp.conf
++++ b/tmpfiles.d/tmp.conf
+@@ -9,7 +9,6 @@
+
+ # Clear tmp directories separately, to make them easier to override
+ q /tmp 1777 root root 10d
+-q /var/tmp 1777 root root 30d
+
+ # Exclude namespace mountpoints created with PrivateTmp=yes
+ x /tmp/systemd-private-%b-*
+diff --git a/tmpfiles.d/var.conf.m4 b/tmpfiles.d/var.conf.m4
+index 0e2c509..fa288b8 100644
+--- a/tmpfiles.d/var.conf.m4
++++ b/tmpfiles.d/var.conf.m4
+@@ -11,7 +11,10 @@ q /var 0755 - - -
+
+ L /var/run - - - - ../run
+
+-d /var/log 0755 - - -
++# now /var/log and /var/tmp really live in volatile
++L /var/log - - - - volatile/log
++L /var/tmp - - - - volatile/tmp
++
+ m4_ifdef(`ENABLE_UTMP',
+ f /var/log/wtmp 0664 root utmp -
+ f /var/log/btmp 0660 root utmp -
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch
new file mode 100644
index 000000000..f72052e0c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch
@@ -0,0 +1,28 @@
+From 3016898f4300fdd8db74f821cd6ea54dbf39fdc8 Mon Sep 17 00:00:00 2001
+From: James Feist <james.feist@linux.intel.com>
+Date: Tue, 6 Mar 2018 16:06:33 -0800
+Subject: [PATCH 1/1] Modfiy system.conf DefaultTimeoutStopSec
+
+Current time is 5 minutes, change it to 10 seconds.
+
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+---
+ src/core/system.conf | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/core/system.conf.in b/src/core/system.conf.in
+index 746572b..ba2a265 100644
+--- a/src/core/system.conf.in
++++ b/src/core/system.conf.in
+@@ -33,7 +33,7 @@
+ #DefaultStandardOutput=journal
+ #DefaultStandardError=inherit
+ #DefaultTimeoutStartSec=90s
+-#DefaultTimeoutStopSec=90s
++DefaultTimeoutStopSec=10s
+ #DefaultRestartSec=100ms
+ #DefaultStartLimitIntervalSec=10s
+ #DefaultStartLimitBurst=5
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd_%.bbappend
new file mode 100644
index 000000000..ef7ac20e2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd_%.bbappend
@@ -0,0 +1,11 @@
+# add some configuration overrides for systemd default /usr/lib/tmpfiles.d/
+
+LICENSE = "GPL-2.0"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://000-ro-rootfs-tmpfile-defaults.patch \
+ file://0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch \
+ "
+
+USERADD_PACKAGES_remove = "${PN}-journal-gateway ${PN}-journal-upload ${PN}-journal-remote"
diff --git a/meta-openbmc-mods/meta-common/recipes-devtools/dtoverlay/dtoverlay.bb b/meta-openbmc-mods/meta-common/recipes-devtools/dtoverlay/dtoverlay.bb
new file mode 100644
index 000000000..66107d81b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-devtools/dtoverlay/dtoverlay.bb
@@ -0,0 +1,31 @@
+SUMMARY = "dtoverlay"
+DESCRIPTION = "device tree overlay application"
+
+SRC_URI = "git://github.com/raspberrypi/userland.git"
+LICENSE = "BSD"
+LIC_FILES_CHKSUM = "file://LICENCE;md5=0448d6488ef8cc380632b1569ee6d196"
+
+SRCREV = "11389772c79685442e0ab8aa9be8ad0e32703f68"
+requires = "chrpath-native"
+
+S = "${WORKDIR}/git"
+
+PV = "1"
+
+inherit cmake
+
+FILES_${PN} += "${libdir} ${libdir}libdtovl.so.${PV}"
+
+do_compile_append(){
+ chrpath -d ${S}/build/bin/dtoverlay
+}
+
+do_install() {
+ install -d ${D}${libdir}
+ install -m 0644 ${S}/build/lib/libdtovl.so ${D}${libdir}/libdtovl.so.${PV}
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/build/bin/dtoverlay ${D}${bindir}/dtoverlay
+
+ ln -sf libdtovl.so.${PV} ${D}{libdir}libdtovl.so
+}
+
diff --git a/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb b/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb
new file mode 100644
index 000000000..f973acac6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb
@@ -0,0 +1,20 @@
+DESCRIPTION = "OpenBMC mtd-util"
+
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://COPYING;md5=b77c43ae4eaf67bd73fb6452b2f113a3"
+
+SRC_URI = "git://git@github.com/Intel-BMC/mtd-util;protocol=ssh"
+
+PV = "1.0+git${SRCPV}"
+SRCREV = "22a0216b5e197bb8c7264fd0be0a4bb2d5d25b90"
+
+
+S = "${WORKDIR}/git"
+
+DEPENDS += "dbus openssl zlib boost microsoft-gsl"
+
+inherit cmake pkgconfig
+
+# Specify any options you want to pass to cmake using EXTRA_OECMAKE:
+EXTRA_OECMAKE = ""
+
diff --git a/meta-openbmc-mods/meta-common/recipes-devtools/template-recipe/template-recipe.bb b/meta-openbmc-mods/meta-common/recipes-devtools/template-recipe/template-recipe.bb
new file mode 100644
index 000000000..5d13a8c44
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-devtools/template-recipe/template-recipe.bb
@@ -0,0 +1,18 @@
+SUMMARY = "HelloWorld app with phosphor-logging usage example."
+DESCRIPTION = "NOTE: Phosphor-logging has dependencies on systemd and sdbusplus."
+
+SRC_URI = "git://git-amr-2.devtools.intel.com:29418/openbmc_template-recipe;protocol=ssh"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+# Modify these as desired
+PV = "1.0+git${SRCPV}"
+SRCREV = "2d5d731254319de8b42d6438b0ce3908dd5b0dec"
+
+S = "${WORKDIR}/git"
+
+inherit cmake
+
+DEPENDS = "systemd sdbusplus phosphor-logging"
+RDEPENDS_${PN} = "libsystemd sdbusplus phosphor-logging"
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend b/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend
new file mode 100644
index 000000000..a7d8d8a95
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend
@@ -0,0 +1,21 @@
+PACKAGECONFIG_remove = "gcrypt gnutls png sdl zlib"
+
+TARGET_CXXFLAGS += " -Dflto"
+
+do_install_append() {
+ rm -rf ${D}${libdir}/libvncclient*
+}
+
+inherit cmake
+
+# Use the latest to support obmc-ikvm
+DEPENDS += "openssl lzo"
+SRC_URI = "git://github.com/LibVNC/libvncserver"
+SRCREV = "3348a7e42e86dfb98dd7458ad29def476cf6096f"
+S = "${WORKDIR}/git"
+
+# Remove x11 and gtk+ that cause big image size
+# Actually, these aren't needed to support obmc-ikvm
+REQUIRED_DISTRO_FEATURES_remove = "x11"
+DEPENDS_remove = "gtk+"
+RDEPENDS_${PN}_remove = "gtk+"
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/start-ipkvm.service b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/start-ipkvm.service
new file mode 100644
index 000000000..61d6cf213
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/start-ipkvm.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=OpenBMC ipKVM daemon
+StopWhenUnneeded=false
+
+[Service]
+Restart=always
+ExecStartPre=/usr/bin/create_usbhid.sh
+ExecStart=/usr/bin/env obmc-ikvm -v /dev/video0 -f 10 -k /dev/hidg0 -p /dev/hidg1
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_git.bb b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_git.bb
new file mode 100644
index 000000000..f69382440
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_git.bb
@@ -0,0 +1,18 @@
+SUMMARY = "OpenBMC VNC server and ipKVM daemon"
+DESCRIPTION = "obmc-ikvm is a vncserver for JPEG-serving V4L2 devices to allow ipKVM"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=75859989545e37968a99b631ef42722e"
+
+DEPENDS = " libvncserver sdbusplus sdbusplus-native phosphor-logging phosphor-dbus-interfaces autoconf-archive-native"
+
+SRC_URI = "git://github.com/openbmc/obmc-ikvm"
+SRCREV = "f6ed0e75b05b573345e4f3eb9d80e677f98992ac"
+
+PR = "r1"
+PR_append = "+gitr${SRCPV}"
+
+SYSTEMD_SERVICE_${PN} += "start-ipkvm.service"
+
+S = "${WORKDIR}/git"
+
+inherit autotools pkgconfig obmc-phosphor-systemd
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control.bb b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control.bb
new file mode 100644
index 000000000..1635b41a1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control.bb
@@ -0,0 +1,201 @@
+SUMMARY = "Chassis Power Control service for Intel based platform"
+DESCRIPTION = "Chassis Power Control service for Intel based platfrom"
+
+SRC_URI = "git://git@github.com/Intel-BMC/intel-chassis-control.git;protocol=ssh"
+SRCREV = "d49efd0b5e1c81fd530dbd9fa0a7545f071bc823"
+
+S = "${WORKDIR}/git/services/chassis/"
+
+PV = "1.0+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+inherit cmake pkgconfig pythonnative
+inherit obmc-phosphor-dbus-service
+
+DBUS_SERVICE_${PN} += "xyz.openbmc_project.Chassis.Control.Power@.service"
+DBUS_SERVICE_${PN} += "xyz.openbmc_project.Chassis.Control.Chassis@.service"
+DBUS_SERVICE_${PN} += "xyz.openbmc_project.Chassis.Buttons@.service"
+
+# Force the standby target to run these services
+SYSD_TGT = "${SYSTEMD_DEFAULT_TARGET}"
+
+POWER_TMPL_CTRL = "xyz.openbmc_project.Chassis.Control.Power@.service"
+#SYSD_TGT = "${SYSTEMD_DEFAULT_TARGET}"
+POWER_INSTFMT_CTRL = "xyz.openbmc_project.Chassis.Control.Power@{0}.service"
+POWER_FMT_CTRL = "../${POWER_TMPL_CTRL}:${SYSD_TGT}.wants/${POWER_INSTFMT_CTRL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'POWER_FMT_CTRL', 'OBMC_HOST_INSTANCES')}"
+
+CHASSIS_TMPL_CTRL = "xyz.openbmc_project.Chassis.Control.Chassis@.service"
+#SYSD_TGT = "${SYSTEMD_DEFAULT_TARGET}"
+CHASSIS_INSTFMT_CTRL = "xyz.openbmc_project.Chassis.Control.Chassis@{0}.service"
+CHASSIS_FMT_CTRL = "../${CHASSIS_TMPL_CTRL}:${SYSD_TGT}.wants/${CHASSIS_INSTFMT_CTRL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'CHASSIS_FMT_CTRL', 'OBMC_HOST_INSTANCES')}"
+
+BUTTONS_TMPL_CTRL = "xyz.openbmc_project.Chassis.Buttons@.service"
+#SYSD_TGT = "${SYSTEMD_DEFAULT_TARGET}"
+BUTTONS_INSTFMT_CTRL = "xyz.openbmc_project.Chassis.Buttons@{0}.service"
+BUTTONS_FMT_CTRL = "../${BUTTONS_TMPL_CTRL}:${SYSD_TGT}.wants/${BUTTONS_INSTFMT_CTRL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'BUTTONS_FMT_CTRL', 'OBMC_HOST_INSTANCES')}"
+
+SYSTEMD_SERVICE_${PN} += " \
+ obmc-host-start@.target \
+ obmc-host-startmin@.target \
+ obmc-host-stop@.target \
+ obmc-host-reboot@.target \
+ obmc-chassis-poweroff@.target \
+ obmc-chassis-poweron@.target \
+ obmc-chassis-hard-poweroff@.target \
+ obmc-host-soft-reboot@.target \
+ obmc-host-warm-reset@.target \
+ obmc-chassis-powerreset@.target \
+ "
+
+RESET_TGTFMT = "obmc-chassis-powerreset@{0}.target"
+
+RESET_ON_TMPL = "op-reset-chassis-running@.service"
+RESET_ON_INSTFMT = "op-reset-chassis-running@{0}.service"
+RESET_ON_FMT = "../${RESET_ON_TMPL}:${RESET_TGTFMT}.requires/${RESET_ON_INSTFMT}"
+SYSTEMD_SERVICE_${PN} += "${RESET_ON_TMPL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'RESET_ON_FMT', 'OBMC_CHASSIS_INSTANCES')}"
+
+RESET_ON_CHASSIS_TMPL = "op-reset-chassis-on@.service"
+RESET_ON_CHASSIS_INSTFMT = "op-reset-chassis-on@{0}.service"
+RESET_ON_CHASSIS_FMT = "../${RESET_ON_CHASSIS_TMPL}:${RESET_TGTFMT}.requires/${RESET_ON_CHASSIS_INSTFMT}"
+SYSTEMD_SERVICE_${PN} += "${RESET_ON_CHASSIS_TMPL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'RESET_ON_CHASSIS_FMT', 'OBMC_CHASSIS_INSTANCES')}"
+
+# Force the standby target to run the chassis reset check target
+RESET_TMPL_CTRL = "obmc-chassis-powerreset@.target"
+SYSD_TGT = "${SYSTEMD_DEFAULT_TARGET}"
+RESET_INSTFMT_CTRL = "obmc-chassis-powerreset@{0}.target"
+RESET_FMT_CTRL = "../${RESET_TMPL_CTRL}:${SYSD_TGT}.wants/${RESET_INSTFMT_CTRL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'RESET_FMT_CTRL', 'OBMC_CHASSIS_INSTANCES')}"
+
+START_TMPL = "intel-power-start@.service"
+START_TGTFMT = "obmc-chassis-poweron@{0}.target"
+START_INSTFMT = "intel-power-start@{0}.service"
+START_FMT = "../${START_TMPL}:${START_TGTFMT}.requires/${START_INSTFMT}"
+SYSTEMD_SERVICE_${PN} += "${START_TMPL}"
+
+STOP_TMPL = "intel-power-stop@.service"
+STOP_TGTFMT = "obmc-chassis-poweroff@{0}.target"
+STOP_INSTFMT = "intel-power-stop@{0}.service"
+STOP_FMT = "../${STOP_TMPL}:${STOP_TGTFMT}.requires/${STOP_INSTFMT}"
+SYSTEMD_SERVICE_${PN} += "${STOP_TMPL}"
+
+WARM_RESET_TMPL = "intel-power-warm-reset@.service"
+WARM_RESET_TGTFMT = "obmc-host-warm-reset@{0}.target"
+WARM_RESET_INSTFMT = "intel-power-warm-reset@{0}.service"
+WARM_RESET_FMT = "../${WARM_RESET_TMPL}:${WARM_RESET_TGTFMT}.requires/${WARM_RESET_INSTFMT}"
+WARM_RESET_LINK_FMT = "obmc-host-warm-reset@.target:${WARM_RESET_TGTFMT}"
+SYSTEMD_SERVICE_${PN} += "${WARM_RESET_TMPL}"
+
+# Build up requires relationship for START_TGTFMT and STOP_TGTFMT
+SYSTEMD_LINK_${PN} += "${@compose_list(d, 'START_FMT', 'OBMC_CHASSIS_INSTANCES')}"
+SYSTEMD_LINK_${PN} += "${@compose_list(d, 'STOP_FMT', 'OBMC_CHASSIS_INSTANCES')}"
+SYSTEMD_LINK_${PN} += "${@compose_list(d, 'WARM_RESET_FMT', 'OBMC_CHASSIS_INSTANCES')}"
+SYSTEMD_LINK_${PN} += "${@compose_list(d, 'WARM_RESET_LINK_FMT', 'OBMC_CHASSIS_INSTANCES')}"
+
+#The main control target requires these power targets
+START_TMPL_CTRL = "obmc-chassis-poweron@.target"
+START_TGTFMT_CTRL = "obmc-host-startmin@{0}.target"
+START_INSTFMT_CTRL = "obmc-chassis-poweron@{0}.target"
+START_FMT_CTRL = "../${START_TMPL_CTRL}:${START_TGTFMT_CTRL}.requires/${START_INSTFMT_CTRL}"
+SYSTEMD_LINK_${PN} += "${@compose_list(d, 'START_FMT_CTRL', 'OBMC_CHASSIS_INSTANCES')}"
+
+# Chassis off requires host off
+STOP_TMPL_CTRL = "obmc-host-stop@.target"
+STOP_TGTFMT_CTRL = "obmc-chassis-poweroff@{0}.target"
+STOP_INSTFMT_CTRL = "obmc-host-stop@{0}.target"
+STOP_FMT_CTRL = "../${STOP_TMPL_CTRL}:${STOP_TGTFMT_CTRL}.requires/${STOP_INSTFMT_CTRL}"
+SYSTEMD_LINK_${PN} += "${@compose_list(d, 'STOP_FMT_CTRL', 'OBMC_CHASSIS_INSTANCES')}"
+
+# Hard power off requires chassis off
+HARD_OFF_TMPL_CTRL = "obmc-chassis-poweroff@.target"
+HARD_OFF_TGTFMT_CTRL = "obmc-chassis-hard-poweroff@{0}.target"
+HARD_OFF_INSTFMT_CTRL = "obmc-chassis-poweroff@{0}.target"
+HARD_OFF_FMT_CTRL = "../${HARD_OFF_TMPL_CTRL}:${HARD_OFF_TGTFMT_CTRL}.requires/${HARD_OFF_INSTFMT_CTRL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'HARD_OFF_FMT_CTRL', 'OBMC_CHASSIS_INSTANCES')}"
+
+# Host soft reboot to run the shutdown target
+HOST_SHUTDOWN_TMPL = "obmc-host-shutdown@.target"
+HOST_SOFT_REBOOT_TMPL = "obmc-host-soft-reboot@.target"
+HOST_SOFT_REBOOT_TGTFMT = "obmc-host-soft-reboot@{0}.target"
+HOST_SHUTDOWN_INSTFMT = "obmc-host-shutdown@{0}.target"
+HOST_SOFT_REBOOT_FMT = "../${HOST_SHUTDOWN_TMPL}:${HOST_SOFT_REBOOT_TGTFMT}.requires/${HOST_SHUTDOWN_INSTFMT}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'HOST_SOFT_REBOOT_FMT', 'OBMC_HOST_INSTANCES')}"
+# And also to call the host startmin service
+HOST_SOFT_REBOOT_SVC = "phosphor-reboot-host@.service"
+HOST_SOFT_REBOOT_SVC_INST = "phosphor-reboot-host@{0}.service"
+HOST_SOFT_REBOOT_SVC_FMT = "../${HOST_SOFT_REBOOT_SVC}:${HOST_SOFT_REBOOT_TGTFMT}.requires/${HOST_SOFT_REBOOT_SVC_INST}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'HOST_SOFT_REBOOT_SVC_FMT', 'OBMC_HOST_INSTANCES')}"
+
+#Broadcast Host state
+PRE_HOST_START_TMPL = "obmc-send-signal-pre-host-start@.service"
+PRE_HOST_START_TGTFMT = "obmc-host-start-pre@{0}.target"
+PRE_HOST_START_INSTFMT = "obmc-send-signal-pre-host-start@{0}.service"
+PRE_HOST_START_FMT = "../${PRE_HOST_START_TMPL}:${PRE_HOST_START_TGTFMT}.requires/${PRE_HOST_START_INSTFMT}"
+SYSTEMD_SERVICE_${PN} += "${PRE_HOST_START_TMPL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'PRE_HOST_START_FMT', 'OBMC_HOST_INSTANCES')}"
+
+POST_HOST_START_TMPL = "obmc-send-signal-post-host-start@.service"
+POST_HOST_START_TGTFMT = "obmc-host-started@{0}.target"
+POST_HOST_START_INSTFMT = "obmc-send-signal-post-host-start@{0}.service"
+POST_HOST_START_FMT = "../${POST_HOST_START_TMPL}:${POST_HOST_START_TGTFMT}.requires/${POST_HOST_START_INSTFMT}"
+SYSTEMD_SERVICE_${PN} += "${POST_HOST_START_TMPL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'POST_HOST_START_FMT', 'OBMC_HOST_INSTANCES')}"
+
+HOST_STARTING_TMPL = "obmc-send-signal-host-starting@.service"
+HOST_STARTING_TGTFMT = "obmc-host-starting@{0}.target"
+HOST_STARTING_INSTFMT = "obmc-send-signal-host-starting@{0}.service"
+HOST_STARTING_FMT = "../${HOST_STARTING_TMPL}:${HOST_STARTING_TGTFMT}.requires/${HOST_STARTING_INSTFMT}"
+SYSTEMD_SERVICE_${PN} += "${HOST_STARTING_TMPL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'HOST_STARTING_FMT', 'OBMC_HOST_INSTANCES')}"
+
+PRE_HOST_STOP_TMPL = "obmc-send-signal-pre-host-stop@.service"
+PRE_HOST_STOP_TGTFMT = "obmc-host-stop-pre@{0}.target"
+PRE_HOST_STOP_INSTFMT = "obmc-send-signal-pre-host-stop@{0}.service"
+PRE_HOST_STOP_FMT = "../${PRE_HOST_STOP_TMPL}:${PRE_HOST_STOP_TGTFMT}.requires/${PRE_HOST_STOP_INSTFMT}"
+SYSTEMD_SERVICE_${PN} += "${PRE_HOST_STOP_TMPL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'PRE_HOST_STOP_FMT', 'OBMC_HOST_INSTANCES')}"
+
+POST_HOST_STOP_TMPL = "obmc-send-signal-post-host-stop@.service"
+POST_HOST_STOP_TGTFMT = "obmc-host-stopped@{0}.target"
+POST_HOST_STOP_INSTFMT = "obmc-send-signal-post-host-stop@{0}.service"
+POST_HOST_STOP_FMT = "../${POST_HOST_STOP_TMPL}:${POST_HOST_STOP_TGTFMT}.requires/${POST_HOST_STOP_INSTFMT}"
+SYSTEMD_SERVICE_${PN} += "${POST_HOST_STOP_TMPL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'POST_HOST_STOP_FMT', 'OBMC_HOST_INSTANCES')}"
+
+HOST_STOPPING_TMPL = "obmc-send-signal-host-stopping@.service"
+HOST_STOPPING_TGTFMT = "obmc-host-stopping@{0}.target"
+HOST_STOPPING_INSTFMT = "obmc-send-signal-host-stopping@{0}.service"
+HOST_STOPPING_FMT = "../${HOST_STOPPING_TMPL}:${HOST_STOPPING_TGTFMT}.requires/${HOST_STOPPING_INSTFMT}"
+SYSTEMD_SERVICE_${PN} += "${HOST_STOPPING_TMPL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'HOST_STOPPING_FMT', 'OBMC_HOST_INSTANCES')}"
+
+DEPENDS += " \
+ autoconf-archive-native \
+ boost \
+ i2c-tools \
+ systemd \
+ sdbusplus \
+ sdbusplus-native \
+ phosphor-dbus-interfaces \
+ phosphor-dbus-interfaces-native \
+ phosphor-logging \
+ "
+RDEPENDS_${PN} += " \
+ libsystemd \
+ sdbusplus \
+ phosphor-dbus-interfaces \
+ phosphor-logging \
+ "
+
+EXTRA_OECMAKE = " -DENABLE_GTEST=OFF -DCMAKE_SKIP_RPATH=ON"
+
+# linux-libc-headers guides this way to include custom uapi headers
+CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi"
+CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include"
+do_configure[depends] += "virtual/kernel:do_shared_workdir"
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/intel-power-start@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/intel-power-start@.service
new file mode 100644
index 000000000..763c11546
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/intel-power-start@.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=Start Power%i on
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Power%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Power%i.service
+Conflicts=obmc-chassis-poweroff@%i.target
+ConditionPathExists=!/run/openbmc/chassis@%i-on
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -c "busctl call `mapper get-service /xyz/openbmc_project/Chassis/Control/Power%i` \
+ /xyz/openbmc_project/Chassis/Control/Power%i xyz.openbmc_project.Chassis.Control.Power setPowerState i 1"
+SyslogIdentifier=intel-power-start
+StartLimitInterval=0
+
+[Install]
+WantedBy=obmc-host-start@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/intel-power-stop@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/intel-power-stop@.service
new file mode 100644
index 000000000..5d0e46f82
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/intel-power-stop@.service
@@ -0,0 +1,20 @@
+[Unit]
+Description=Stop Power%i
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Power%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Power%i.service
+Conflicts=obmc-chassis-poweron@%i.target
+Conflicts=obmc-host-start@%i.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -c "busctl call `mapper get-service /xyz/openbmc_project/Chassis/Control/Power%i` \
+ /xyz/openbmc_project/Chassis/Control/Power%i xyz.openbmc_project.Chassis.Control.Power setPowerState i 0"
+SyslogIdentifier=intel-power-stop
+StartLimitInterval=0
+
+ExecStart=/bin/rm -f /run/openbmc/chassis@%i-on
+ExecStart=/bin/rm -f /run/openbmc/host@%i-on
+ExecStart=/bin/rm -f /run/openbmc/host@%i-request
+
+[Install]
+WantedBy=obmc-chassis-poweroff@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/intel-power-warm-reset@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/intel-power-warm-reset@.service
new file mode 100644
index 000000000..8d4897a25
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/intel-power-warm-reset@.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Power%i warm reset
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Power%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Power%i.service
+Conflicts=obmc-chassis-poweroff@%i.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -c "busctl call `mapper get-service /xyz/openbmc_project/Chassis/Control/Power%i` \
+ /xyz/openbmc_project/Chassis/Control/Power%i xyz.openbmc_project.Chassis.Control.Power setPowerState i 2"
+SyslogIdentifier=intel-power-warm-reset
+
+[Install]
+WantedBy=obmc-host-warm-reset@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-hard-poweroff@.target b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-hard-poweroff@.target
new file mode 100644
index 000000000..9a9902f7c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-hard-poweroff@.target
@@ -0,0 +1,12 @@
+[Unit]
+Description=Chassis%i (Hard Power Off)
+Wants={SYSTEMD_DEFAULT_TARGET}
+After={SYSTEMD_DEFAULT_TARGET}
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+Conflicts=obmc-chassis-poweron@%i.target
+Conflicts=obmc-chassis-reset@%i.target
+Conflicts=obmc-host-shutdown@%i.target
+Conflicts=xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service
+RefuseManualStop=yes
+
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-poweroff@.target b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-poweroff@.target
new file mode 100644
index 000000000..34580a21f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-poweroff@.target
@@ -0,0 +1,10 @@
+[Unit]
+Description=Chassis%i (Power Off)
+Wants={SYSTEMD_DEFAULT_TARGET}
+After={SYSTEMD_DEFAULT_TARGET}
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+Conflicts=obmc-chassis-poweron@%i.target
+Conflicts=obmc-chassis-reset@%i.target
+RefuseManualStop=yes
+
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-poweron@.target b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-poweron@.target
new file mode 100644
index 000000000..f8fecf2a6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-poweron@.target
@@ -0,0 +1,10 @@
+[Unit]
+Description=Chassis%i (Power On)
+Wants={SYSTEMD_DEFAULT_TARGET}
+After={SYSTEMD_DEFAULT_TARGET}
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+Conflicts=obmc-chassis-poweroff@%i.target
+RefuseManualStop=yes
+OnFailure=obmc-chassis-poweroff@%i.target
+OnFailureJobMode=flush
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-powerreset@.target b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-powerreset@.target
new file mode 100644
index 000000000..8d7c47e6b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-chassis-powerreset@.target
@@ -0,0 +1,7 @@
+[Unit]
+Description=Chassis%i (Reset Check)
+Conflicts=obmc-chassis-poweroff@%i.target
+RefuseManualStop=yes
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-reboot@.target b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-reboot@.target
new file mode 100644
index 000000000..c860889e3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-reboot@.target
@@ -0,0 +1,10 @@
+[Unit]
+Description=Reboot Host%i
+Wants={SYSTEMD_DEFAULT_TARGET}
+After={SYSTEMD_DEFAULT_TARGET}
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+Conflicts=obmc-host-startmin@%i.target
+RefuseManualStop=yes
+OnFailure=obmc-chassis-poweroff@%i.target
+OnFailureJobMode=flush
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-soft-reboot@.target b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-soft-reboot@.target
new file mode 100644
index 000000000..c35c3e1ae
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-soft-reboot@.target
@@ -0,0 +1,10 @@
+[Unit]
+Description=Soft Reboot Host%i
+Wants={SYSTEMD_DEFAULT_TARGET}
+After={SYSTEMD_DEFAULT_TARGET}
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+Conflicts=obmc-host-startmin@%i.target
+RefuseManualStop=yes
+OnFailure=obmc-chassis-poweroff@%i.target
+OnFailureJobMode=flush
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-start@.target b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-start@.target
new file mode 100644
index 000000000..425953d4d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-start@.target
@@ -0,0 +1,10 @@
+[Unit]
+Description=Start Host%i
+Wants={SYSTEMD_DEFAULT_TARGET}
+After={SYSTEMD_DEFAULT_TARGET}
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+Conflicts=obmc-host-stop@%i.target
+RefuseManualStop=yes
+OnFailure=obmc-host-quiesce@%i.target
+OnFailureJobMode=flush \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-startmin@.target b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-startmin@.target
new file mode 100644
index 000000000..69056254a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-startmin@.target
@@ -0,0 +1,6 @@
+[Unit]
+Description=Start Host%i Minimum
+Wants={SYSTEMD_DEFAULT_TARGET}
+After={SYSTEMD_DEFAULT_TARGET}
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-stop@.target b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-stop@.target
new file mode 100644
index 000000000..0693db6e5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-stop@.target
@@ -0,0 +1,10 @@
+[Unit]
+Description=Stop Host%i
+Wants={SYSTEMD_DEFAULT_TARGET}
+After={SYSTEMD_DEFAULT_TARGET}
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+Conflicts=obmc-host-startmin@%i.target
+RefuseManualStop=yes
+OnFailure=obmc-chassis-poweroff@%i.target
+OnFailureJobMode=flush \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-warm-reset@.target b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-warm-reset@.target
new file mode 100644
index 000000000..8aed937e7
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-host-warm-reset@.target
@@ -0,0 +1,10 @@
+[Unit]
+Description=Warm reset Host%i
+Wants={SYSTEMD_DEFAULT_TARGET}
+After={SYSTEMD_DEFAULT_TARGET}
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Chassis%i.service
+Conflicts=obmc-host-stop@%i.target
+RefuseManualStop=yes
+OnFailure=obmc-host-quiesce@%i.target
+OnFailureJobMode=flush
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-host-starting@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-host-starting@.service
new file mode 100644
index 000000000..4e84c8783
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-host-starting@.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Broadcast host starting signal to dbus
+Wants=mapper-wait@-xyz-openbmc_project-state-host%i.service
+After=mapper-wait@-xyz-openbmc_project-state-host%i.service
+
+[Service]
+Restart=no
+Type=oneshot
+ExecStart=/bin/sh -c "dbus-send --system --type=signal /xyz/openbmc_project/state/host0 xyz.openbmc_project.State.Host.HostStarting"
+SyslogIdentifier=hoststartingsignal
+
+[Install]
+WantedBy=obmc-host-starting@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-host-stopping@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-host-stopping@.service
new file mode 100644
index 000000000..0f89f94a8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-host-stopping@.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Broadcast host stopping signal to dbus
+Wants=mapper-wait@-xyz-openbmc_project-state-host%i.service
+After=mapper-wait@-xyz-openbmc_project-state-host%i.service
+
+[Service]
+Restart=no
+Type=oneshot
+ExecStart=/bin/sh -c "dbus-send --system --type=signal /xyz/openbmc_project/state/host0 xyz.openbmc_project.State.Host.HostStoping"
+SyslogIdentifier=hoststoppingsignal
+
+[Install]
+WantedBy=obmc-host-stopping@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-post-host-start@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-post-host-start@.service
new file mode 100644
index 000000000..f7e0a3bde
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-post-host-start@.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Broadcast post host start signal to dbus
+Wants=mapper-wait@-xyz-openbmc_project-state-host%i.service
+After=mapper-wait@-xyz-openbmc_project-state-host%i.service
+
+[Service]
+Restart=no
+Type=oneshot
+ExecStart=/bin/sh -c "dbus-send --system --type=signal /xyz/openbmc_project/state/host0 xyz.openbmc_project.State.Host.PostHostStart"
+SyslogIdentifier=posthoststartsignal
+
+[Install]
+WantedBy=obmc-host-started@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-post-host-stop@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-post-host-stop@.service
new file mode 100644
index 000000000..90007dbf2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-post-host-stop@.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Broadcast post host stop signal to dbus
+Wants=mapper-wait@-xyz-openbmc_project-state-host%i.service
+After=mapper-wait@-xyz-openbmc_project-state-host%i.service
+
+[Service]
+Restart=no
+Type=oneshot
+ExecStart=/bin/sh -c "dbus-send --system --type=signal /xyz/openbmc_project/state/host0 xyz.openbmc_project.State.Host.PostHostStop"
+SyslogIdentifier=posthoststopsignal
+
+[Install]
+WantedBy=obmc-host-stopped@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-pre-host-start@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-pre-host-start@.service
new file mode 100644
index 000000000..a57423e2c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-pre-host-start@.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Broadcast pre host start signal to dbus
+Wants=mapper-wait@-xyz-openbmc_project-state-host%i.service
+After=mapper-wait@-xyz-openbmc_project-state-host%i.service
+
+[Service]
+Restart=no
+Type=oneshot
+ExecStart=/bin/sh -c "dbus-send --system --type=signal /xyz/openbmc_project/state/host0 xyz.openbmc_project.State.Host.PreHostStart"
+SyslogIdentifier=prehoststartsignal
+
+[Install]
+WantedBy=obmc-host-start-pre@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-pre-host-stop@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-pre-host-stop@.service
new file mode 100644
index 000000000..ec6f453cd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/obmc-send-signal-pre-host-stop@.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Broadcast pre host stop signal to dbus
+Wants=mapper-wait@-xyz-openbmc_project-state-host%i.service
+After=mapper-wait@-xyz-openbmc_project-state-host%i.service
+
+[Service]
+Restart=no
+Type=oneshot
+ExecStart=/bin/sh -c "dbus-send --system --type=signal /xyz/openbmc_project/state/host0 xyz.openbmc_project.State.Host.PreHostStop"
+SyslogIdentifier=prehoststopsignal
+
+[Install]
+WantedBy=obmc-host-stop-pre@%i.target
+
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/op-reset-chassis-on@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/op-reset-chassis-on@.service
new file mode 100644
index 000000000..d3ea71639
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/op-reset-chassis-on@.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Start chassis%i on after BMC reset
+Requires=op-reset-chassis-running@%i.service
+After=op-reset-chassis-running@%i.service
+After=obmc-power-reset-on@%i.target
+Requires=obmc-power-reset-on@%i.target
+ConditionPathExists=/run/openbmc/chassis@%i-on
+
+[Service]
+RemainAfterExit=no
+ExecStart=/bin/systemctl start obmc-host-start@%i.target
+
+
+[Install]
+WantedBy=obmc-chassis-powerreset@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/op-reset-chassis-running@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/op-reset-chassis-running@.service
new file mode 100644
index 000000000..3280d0a40
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/op-reset-chassis-running@.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Check Chassis%i pgood and create a file to indicate it
+Wants=mapper-wait@-xyz-openbmc_project-Chassis-Control-Power%i.service
+After=mapper-wait@-xyz-openbmc_project-Chassis-Control-Power%i.service
+Wants=obmc-power-reset-on@%i.target
+Before=obmc-power-reset-on@%i.target
+Conflicts=obmc-chassis-poweroff@%i.target
+
+[Service]
+RemainAfterExit=no
+Type=oneshot
+ExecStart=/bin/sh -c "if [ $(busctl get-property `mapper get-service /xyz/openbmc_project/Chassis/Control/Power%i` /xyz/openbmc_project/Chassis/Control/Power%i xyz.openbmc_project.Chassis.Control.Power pgood | sed 's/i\s*[1]/on/' | grep on | wc -l) != 0 ]; then mkdir -p /run/openbmc/ && touch /run/openbmc/chassis@%i-on; fi"
+
+[Install]
+WantedBy=obmc-chassis-powerreset@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/xyz.openbmc_project.Chassis.Buttons@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/xyz.openbmc_project.Chassis.Buttons@.service
new file mode 100644
index 000000000..e1e3baedf
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/xyz.openbmc_project.Chassis.Buttons@.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Intel Buttons%i
+
+[Service]
+Restart=always
+RestartSec=3
+ExecStart=/usr/bin/env buttons
+SyslogIdentifier=buttons
+Type=dbus
+BusName={BUSNAME}
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
+
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/xyz.openbmc_project.Chassis.Control.Chassis@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/xyz.openbmc_project.Chassis.Control.Chassis@.service
new file mode 100644
index 000000000..521cb17b4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/xyz.openbmc_project.Chassis.Control.Chassis@.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Intel Chassis%i Control
+
+[Service]
+Restart=always
+ExecStart=/usr/bin/env chassis-control
+SyslogIdentifier=chassis-control
+Type=dbus
+BusName={BUSNAME}
+Nice=19
+TimeoutStartSec=180s
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
+
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/xyz.openbmc_project.Chassis.Control.Power@.service b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/xyz.openbmc_project.Chassis.Control.Power@.service
new file mode 100644
index 000000000..985479401
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/chassis/intel-chassis-control/xyz.openbmc_project.Chassis.Control.Power@.service
@@ -0,0 +1,15 @@
+
+[Unit]
+Description=Intel Power Control%i
+
+[Service]
+Restart=always
+RestartSec=3
+ExecStart=/usr/bin/env power-control
+SyslogIdentifier=power-control
+Type=dbus
+BusName={BUSNAME}
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
+
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/images/intel-platforms.bb b/meta-openbmc-mods/meta-common/recipes-intel/images/intel-platforms.bb
new file mode 100644
index 000000000..276e549b9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/images/intel-platforms.bb
@@ -0,0 +1,13 @@
+DESCRIPTION = "Image with Intel content based upon Phosphor, an OpenBMC framework."
+
+inherit obmc-phosphor-full-fitimage
+inherit obmc-phosphor-image-common
+inherit obmc-phosphor-image-dev
+
+FEATURE_PACKAGES_obmc-sensors = ""
+
+fix_shadow_perms() {
+ chgrp shadow ${IMAGE_ROOTFS}${sysconfdir}/shadow
+ chmod u=rw,g+r ${IMAGE_ROOTFS}${sysconfdir}/shadow
+}
+ROOTFS_POSTPROCESS_COMMAND += "fix_shadow_perms ; "
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb
new file mode 100644
index 000000000..fdaf60b41
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb
@@ -0,0 +1,44 @@
+SUMMARY = "OpenBMC for Intel - Applications"
+PR = "r1"
+
+inherit packagegroup
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+PROVIDES = "${PACKAGES}"
+PACKAGES = " \
+ ${PN}-chassis \
+ ${PN}-fans \
+ ${PN}-flash \
+ ${PN}-system \
+ "
+
+PROVIDES += "virtual/obmc-chassis-mgmt"
+PROVIDES += "virtual/obmc-fan-mgmt"
+PROVIDES += "virtual/obmc-flash-mgmt"
+PROVIDES += "virtual/obmc-system-mgmt"
+
+RPROVIDES_${PN}-chassis += "virtual-obmc-chassis-mgmt"
+RPROVIDES_${PN}-fans += "virtual-obmc-fan-mgmt"
+RPROVIDES_${PN}-flash += "virtual-obmc-flash-mgmt"
+RPROVIDES_${PN}-system += "virtual-obmc-system-mgmt"
+
+SUMMARY_${PN}-chassis = "Intel Chassis"
+RDEPENDS_${PN}-chassis = " \
+ intel-chassis-control \
+ libgpiod \
+ obmc-host-failure-reboots \
+ "
+
+SUMMARY_${PN}-fans = "Intel Fans"
+RDEPENDS_${PN}-fans = " \
+ phosphor-pid-control \
+ "
+
+SUMMARY_${PN}-flash = "Intel Flash"
+RDEPENDS_${PN}-flash = " \
+ obmc-flash-bmc \
+ obmc-mgr-download \
+ obmc-control-bmc \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend
new file mode 100644
index 000000000..db0ec4688
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend
@@ -0,0 +1,6 @@
+# this is here to keep obmc-mgr-system happy,
+# power control should stop relying on the deprcated
+# package then we can remove it obmc-mgr-inventory
+RDEPENDS_${PN}-inventory += "obmc-mgr-inventory"
+# this is for image signing and signature verification
+RDEPENDS_${PN}-extras += "${@bb.utils.contains('IMAGE_TYPE', 'pfr', ' phosphor-image-signing', '', d)}" \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1.bb b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1.bb
new file mode 100644
index 000000000..323b2f18c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1.bb
@@ -0,0 +1,33 @@
+SUMMARY = "SMBIOS MDR version 1 service for Intel based platform"
+DESCRIPTION = "SMBIOS MDR version 1 service for Intel based platfrom"
+
+SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh"
+SRCREV = "f4d4bfc3296cb27feb17aa5d1d93b3061b56ce10"
+
+S = "${WORKDIR}/git/services/smbios/"
+
+PV = "1.0+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+inherit cmake pkgconfig pythonnative
+inherit obmc-phosphor-systemd
+
+SYSTEMD_SERVICE_${PN} += "smbios-mdrv1.service"
+
+DEPENDS += " \
+ autoconf-archive-native \
+ systemd \
+ sdbusplus \
+ sdbusplus-native \
+ phosphor-dbus-interfaces \
+ phosphor-dbus-interfaces-native \
+ phosphor-logging \
+ "
+RDEPENDS_${PN} += " \
+ libsystemd \
+ sdbusplus \
+ phosphor-dbus-interfaces \
+ phosphor-logging \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1/smbios-mdrv1.service b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1/smbios-mdrv1.service
new file mode 100644
index 000000000..edfd3bf70
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv1/smbios-mdrv1.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Intel BMC SMBIOS MDR V1
+
+[Service]
+Restart=always
+RestartSec=5
+StartLimitBurst=10
+ExecStartPre=/bin/mkdir -p /etc/smbios
+ExecStart=/usr/bin/env smbiosapp
+SyslogIdentifier=smbiosapp
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb
new file mode 100644
index 000000000..0cf0a7c32
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb
@@ -0,0 +1,33 @@
+SUMMARY = "SMBIOS MDR version 2 service for Intel based platform"
+DESCRIPTION = "SMBIOS MDR version 2 service for Intel based platfrom"
+
+SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh"
+SRCREV = "f4d4bfc3296cb27feb17aa5d1d93b3061b56ce10"
+
+S = "${WORKDIR}/git/services/smbios-mdrv2/"
+
+PV = "1.0+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+inherit cmake pkgconfig pythonnative
+inherit obmc-phosphor-systemd
+
+SYSTEMD_SERVICE_${PN} += "smbios-mdrv2.service"
+
+DEPENDS += " \
+ autoconf-archive-native \
+ systemd \
+ sdbusplus \
+ sdbusplus-native \
+ phosphor-dbus-interfaces \
+ phosphor-dbus-interfaces-native \
+ phosphor-logging \
+ "
+RDEPENDS_${PN} += " \
+ libsystemd \
+ sdbusplus \
+ phosphor-dbus-interfaces \
+ phosphor-logging \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2/smbios-mdrv2.service b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2/smbios-mdrv2.service
new file mode 100644
index 000000000..b72873406
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2/smbios-mdrv2.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Intel BMC SMBIOS MDR V2
+
+[Service]
+Restart=always
+RestartSec=5
+StartLimitBurst=10
+ExecStart=/usr/bin/env smbiosmdrv2app
+SyslogIdentifier=smbiosmdrv2app
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-arm-dts-aspeed-g5-add-espi.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-arm-dts-aspeed-g5-add-espi.patch
new file mode 100644
index 000000000..2a94453b3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-arm-dts-aspeed-g5-add-espi.patch
@@ -0,0 +1,56 @@
+From 2affc8ab570c9d1e6d6e5ecbdbeddbc5e3b15cc5 Mon Sep 17 00:00:00 2001
+From: Juston Li <juston.li@intel.com>
+Date: Mon, 27 Mar 2017 11:16:00 -0700
+Subject: [PATCH] arm: dts: aspeed-g5: add espi
+
+Change-Id: I0b607657883619a3acefdbf344d39bf01790c4b1
+Signed-off-by: Juston Li <juston.li@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g5.dtsi | 18 +++++++++++++++++-
+ 1 file changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index e4c5de3208e0..a3c456ba3f34 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -260,13 +260,22 @@
+ gpio-controller;
+ compatible = "aspeed,ast2500-gpio";
+- reg = <0x1e780000 0x1000>;
++ reg = <0x1e780000 0x0200>;
+ interrupts = <20>;
+ gpio-ranges = <&pinctrl 0 0 220>;
+ clocks = <&syscon ASPEED_CLK_APB>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
++ sgpio: sgpio@1e780200 {
++ #gpio-cells = <2>;
++ gpio-controller;
++ compatible = "aspeed,ast2500-sgpio";
++ reg = <0x1e780200 0x0100>;
++ interrupts = <40>;
++ interrupt-controller;
++ };
++
+ rtc: rtc@1e781000 {
+ compatible = "aspeed,ast2500-rtc";
+ reg = <0x1e781000 0x18>;
+@@ -342,6 +351,13 @@
+ status = "disabled";
+ };
+
++ espi: espi@1e6ee000 {
++ compatible = "aspeed,ast2500-espi-slave";
++ reg = <0x1e6ee000 0x100>;
++ interrupts = <23>;
++ status = "disabled";
++ };
++
+ lpc: lpc@1e789000 {
+ compatible = "aspeed,ast2500-lpc", "simple-mfd";
+ reg = <0x1e789000 0x1000>;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-New-flash-map-for-intel.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-New-flash-map-for-intel.patch
new file mode 100644
index 000000000..2ac429a22
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-New-flash-map-for-intel.patch
@@ -0,0 +1,125 @@
+From 074f1c74fde88aac3a10059e4928919782cd40d6 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@intel.com>
+Date: Mon, 4 Jun 2018 13:45:42 -0700
+Subject: [PATCH] New flash map for Intel
+ ===================================================================
+
+---
+ .../boot/dts/openbmc-flash-layout-intel-128MB.dtsi | 58 ++++++++++++++++++++++
+ .../boot/dts/openbmc-flash-layout-intel-64MB.dtsi | 39 +++++++++++++++
+ 2 files changed, 97 insertions(+)
+ create mode 100644 arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi
+ create mode 100644 arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi
+
+diff --git a/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi b/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi
+new file mode 100644
+index 0000000..23426ac
+--- /dev/null
++++ b/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi
+@@ -0,0 +1,58 @@
++// SPDX-License-Identifier: GPL-2.0+
++// 128MB flash layout: PFR (active + tmp1/tmp2 + extra)
++// image with common RW partition
++
++partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ u-boot@0 {
++ reg = <0x0 0x80000>;
++ label = "u-boot";
++ };
++
++ fit-image-a@80000 {
++ reg = <0x80000 0x1b80000>;
++ label = "image-a";
++ };
++
++ sofs@1c00000 {
++ reg = <0x1c00000 0x200000>;
++ label = "sofs";
++ };
++
++ rwfs@1e00000 {
++ reg = <0x1e00000 0x600000>;
++ label = "rwfs";
++ };
++
++ u-boot-env@2400000 {
++ reg = <0x2400000 0x20000>;
++ label = "u-boot-env";
++ };
++
++ /*
++ pfr-resvd@1260000 {
++ reg = <0x2460000 0x20000>;
++ label = "pfr-resvd";
++ };
++ */
++
++ rc1@2480000 {
++ reg = <0x2480000 0x1b80000>;
++ label = "rc1";
++ };
++
++ rc2@4000000 {
++ reg = <0x4000000 0x1b80000>;
++ label = "rc2";
++ };
++
++ bios-staging@6000000 {
++ reg = <0x6000000 0x2000000>;
++ label = "bios-staging";
++ };
++};
++
++
+diff --git a/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi b/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi
+new file mode 100644
+index 0000000..6ae8e57
+--- /dev/null
++++ b/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi
+@@ -0,0 +1,39 @@
++// SPDX-License-Identifier: GPL-2.0+
++// 64MB flash layout: redundant image with common RW partition
++
++partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ u-boot@0 {
++ reg = <0x0 0x80000>;
++ label = "u-boot";
++ };
++
++ fit-image-a@80000 {
++ reg = <0x80000 0x1b80000>;
++ label = "image-a";
++ };
++
++ sofs@1c00000 {
++ reg = <0x1c00000 0x200000>;
++ label = "sofs";
++ };
++
++ rwfs@1e00000 {
++ reg = <0x1e00000 0x600000>;
++ label = "rwfs";
++ };
++
++ u-boot-env@2400000 {
++ reg = <0x2400000 0x20000>;
++ label = "u-boot-env";
++ };
++
++ fit-image-b@2480000 {
++ reg = <0x2480000 0x1b80000>;
++ label = "image-b";
++ };
++};
++
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch
new file mode 100644
index 000000000..78824dde7
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch
@@ -0,0 +1,474 @@
+From 42505ffb3c24b3e7f8182af520ab1c10a3b3f3c4 Mon Sep 17 00:00:00 2001
+From: "Feist, James" <james.feist@intel.com>
+Date: Mon, 5 Jun 2017 11:13:52 -0700
+Subject: [PATCH] Add ASPEED SGPIO driver.
+
+Port aspeed sgpio driver to OBMC Kernel and
+enable it on Purley config. Based off AST sdk 4.0.
+
+Change-Id: I8529c3fb001ea6f93e63b269cdcdde3887a84e40
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/gpio/Kconfig | 8 +
+ drivers/gpio/Makefile | 1 +
+ drivers/gpio/sgpio-aspeed.c | 416 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 425 insertions(+)
+ create mode 100644 drivers/gpio/sgpio-aspeed.c
+
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index 71c0ab46f216..a0485be99db7 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -124,6 +124,14 @@ config GPIO_ASPEED
+ help
+ Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers.
+
++config SGPIO_ASPEED
++ bool "ASPEED SGPIO support"
++ depends on ARCH_ASPEED
++ select GPIO_GENERIC
++ select GPIOLIB_IRQCHIP
++ help
++ Say Y here to support ASPEED SGPIO functionality.
++
+ config GPIO_ATH79
+ tristate "Atheros AR71XX/AR724X/AR913X GPIO support"
+ default y if ATH79
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index 1324c8f966a7..23b8d29bef70 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -32,6 +32,7 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
+ obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
+ obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
+ obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
++obj-$(CONFIG_SGPIO_ASPEED) += sgpio-aspeed.o
+ obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
+ obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
+ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
+diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c
+new file mode 100644
+index 000000000000..9c4add74602a
+--- /dev/null
++++ b/drivers/gpio/sgpio-aspeed.c
+@@ -0,0 +1,416 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (C) 2012-2017 ASPEED Technology Inc.
++// Copyright (c) 2018 Intel Corporation
++
++#include <asm/mach/irq.h>
++#include <linux/bitfield.h>
++#include <linux/gpio/driver.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_gpio.h>
++#include <linux/platform_device.h>
++
++#ifdef ARCH_NR_GPIOS
++#undef ARCH_NR_GPIOS
++#endif
++
++// TODO: move this to aspeed_sgpio_of_table
++#if defined(CONFIG_MACH_ASPEED_G5)
++#define GPIO_PORT_NUM 29
++#elif defined(CONFIG_MACH_ASPEED_G4)
++#define GPIO_PORT_NUM 28
++#endif
++
++// TODO: fix defines
++#define GPIOS_PER_PORT 8
++#define ARCH_NR_GPIOS (GPIOS_PER_PORT * GPIO_PORT_NUM)
++#define ASPEED_SGPIO_CTRL 0x54
++#define SGPIO_CHAIN_CHIP_BASE ARCH_NR_GPIOS
++#define SGPIO_GROUP_NUMS 10
++
++#define ASPEED_VIC_NUMS 64
++#define ASPEED_FIQ_NUMS 64
++#define ARCH_NR_I2C 14
++
++#define IRQ_I2C_CHAIN_START (ASPEED_VIC_NUMS + ASPEED_FIQ_NUMS)
++#define IRQ_GPIO_CHAIN_START (IRQ_I2C_CHAIN_START + ARCH_NR_I2C)
++#define IRQ_SGPIO_CHAIN_START (IRQ_GPIO_CHAIN_START + ARCH_NR_GPIOS)
++
++#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6)
++#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16)
++#define ASPEED_SGPIO_ENABLE BIT(0)
++
++struct aspeed_sgpio {
++ struct device *dev;
++ int mirq; /* master irq */
++ void __iomem *base;
++// TODO: make below members as a struct member
++ uint index;
++ uint data_offset;
++ uint data_read_offset;
++ uint int_en_offset;
++ uint int_type_offset;
++ uint int_sts_offset;
++ uint rst_tol_offset;
++ struct gpio_chip chip;
++};
++
++uint aspeed_sgpio_to_irq(uint gpio)
++{
++ return (gpio + IRQ_SGPIO_CHAIN_START);
++}
++EXPORT_SYMBOL(aspeed_sgpio_to_irq);
++
++uint aspeed_irq_to_sgpio(uint irq)
++{
++ return (irq - IRQ_SGPIO_CHAIN_START);
++}
++EXPORT_SYMBOL(aspeed_irq_to_sgpio);
++
++static int aspeed_sgpio_get(struct gpio_chip *chip, unsigned offset)
++{
++ struct aspeed_sgpio *priv = gpiochip_get_data(chip);
++ uint bit_nr = priv->index * GPIOS_PER_PORT + offset;
++ unsigned long flags;
++ u32 v;
++
++ local_irq_save(flags);
++
++ v = readl(priv->base + priv->data_offset);
++ v &= BIT(bit_nr);
++
++ if (v)
++ v = 1;
++ else
++ v = 0;
++
++ local_irq_restore(flags);
++
++ dev_dbg(priv->dev, "%s, %s[%d]: %d\n", __func__, chip->label,
++ offset, v);
++
++ return v;
++}
++
++static void aspeed_sgpio_set(struct gpio_chip *chip, unsigned offset, int val)
++{
++ struct aspeed_sgpio *priv = gpiochip_get_data(chip);
++ uint bit_nr = priv->index * GPIOS_PER_PORT + offset;
++ unsigned long flags;
++ u32 v;
++
++ local_irq_save(flags);
++
++ v = readl(priv->base + priv->data_read_offset);
++
++ if (val)
++ v |= BIT(bit_nr);
++ else
++ v &= ~BIT(bit_nr);
++
++ writel(v, priv->base + priv->data_offset);
++
++ dev_dbg(priv->dev, "%s, %s[%d]: %d\n", __func__, chip->label,
++ offset, val);
++
++ local_irq_restore(flags);
++}
++
++#define SGPIO_BANK(name, index_no, data, read_data, int_en, int_type, \
++ int_sts, rst_tol, chip_base_idx) { \
++ .index = index_no, \
++ .data_offset = data, \
++ .data_read_offset = read_data, \
++ .int_en_offset = int_en, \
++ .int_type_offset = int_type, \
++ .int_sts_offset = int_sts, \
++ .rst_tol_offset = rst_tol, \
++ .chip = { \
++ .label = name, \
++ .get = aspeed_sgpio_get, \
++ .set = aspeed_sgpio_set, \
++ .base = SGPIO_CHAIN_CHIP_BASE + chip_base_idx * 8, \
++ .ngpio = GPIOS_PER_PORT, \
++ }, \
++}
++
++// TODO: use a single priv after changing it as an array member of the priv
++static struct aspeed_sgpio aspeed_sgpio_gp[] = {
++ SGPIO_BANK("SGPIOA", 0, 0x000, 0x070, 0x004, 0x008, 0x014, 0x018, 0),
++ SGPIO_BANK("SGPIOB", 1, 0x000, 0x070, 0x004, 0x008, 0x014, 0x018, 1),
++ SGPIO_BANK("SGPIOC", 2, 0x000, 0x070, 0x004, 0x008, 0x014, 0x018, 2),
++ SGPIO_BANK("SGPIOD", 3, 0x000, 0x070, 0x004, 0x008, 0x014, 0x018, 3),
++ SGPIO_BANK("SGPIOE", 0, 0x01C, 0x074, 0x020, 0x024, 0x030, 0x034, 4),
++ SGPIO_BANK("SGPIOF", 1, 0x01C, 0x074, 0x020, 0x024, 0x030, 0x034, 5),
++ SGPIO_BANK("SGPIOG", 2, 0x01C, 0x074, 0x020, 0x024, 0x030, 0x034, 6),
++ SGPIO_BANK("SGPIOH", 3, 0x01C, 0x074, 0x020, 0x024, 0x030, 0x034, 7),
++ SGPIO_BANK("SGPIOI", 0, 0x038, 0x078, 0x03C, 0x040, 0x04C, 0x050, 8),
++ SGPIO_BANK("SGPIOJ", 1, 0x038, 0x078, 0x03C, 0x040, 0x04C, 0x050, 9),
++};
++
++/**
++ * We need to unmask the GPIO bank interrupt as soon as possible to avoid
++ * missing GPIO interrupts for other lines in the bank. Then we need to
++ * mask-read-clear-unmask the triggered GPIO lines in the bank to avoid missing
++ * nested interrupts for a GPIO line. If we wait to unmask individual GPIO lines
++ * in the bank after the line's interrupt handler has been run, we may miss some
++ * nested interrupts.
++ */
++static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
++{
++ struct irq_chip *chip = irq_desc_get_chip(desc);
++ struct aspeed_sgpio *priv = irq_desc_get_chip_data(desc);
++ u32 isr;
++ int i;
++
++ chained_irq_enter(chip, desc);
++
++ isr = readl(priv->base + priv->int_sts_offset);
++ isr = (isr >> (GPIOS_PER_PORT * priv->index)) & 0xff;
++
++ dev_dbg(priv->dev, "[%s] isr %x \n", priv->chip.label, isr);
++
++ if (isr != 0) {
++ for (i = 0; i < GPIOS_PER_PORT; i++) {
++ if (BIT(i) & isr)
++ generic_handle_irq(i * GPIOS_PER_PORT +
++ i + IRQ_SGPIO_CHAIN_START);
++ }
++ }
++
++ chained_irq_exit(chip, desc);
++}
++
++static void aspeed_sgpio_ack_irq(struct irq_data *d)
++{
++ struct aspeed_sgpio *priv = irq_get_chip_data(d->irq);
++ uint sgpio_irq = (d->irq - IRQ_SGPIO_CHAIN_START) % GPIOS_PER_PORT;
++ uint bit_nr = priv->index * GPIOS_PER_PORT + sgpio_irq;
++
++ dev_dbg(priv->dev, "irq %d: %s [%s] pin %d\n", d->irq, __func__,
++ priv->chip.label, sgpio_irq);
++
++ writel(BIT(bit_nr), priv->base + priv->int_sts_offset);
++}
++
++static void aspeed_sgpio_mask_irq(struct irq_data *d)
++{
++ struct aspeed_sgpio *priv = irq_get_chip_data(d->irq);
++ uint sgpio_irq = (d->irq - IRQ_SGPIO_CHAIN_START) % GPIOS_PER_PORT;
++ uint bit_nr = priv->index * GPIOS_PER_PORT + sgpio_irq;
++
++ /* Disable IRQ */
++ writel(readl(priv->base + priv->int_en_offset) & ~BIT(bit_nr),
++ priv->base + priv->int_en_offset);
++
++ dev_dbg(priv->dev, "irq %d: %s [%s] pin %d\n ", d->irq, __func__,
++ priv->chip.label, sgpio_irq);
++}
++
++static void aspeed_sgpio_unmask_irq(struct irq_data *d)
++{
++ struct aspeed_sgpio *priv = irq_data_get_irq_chip_data(d);
++ u32 sgpio_irq = (d->irq - IRQ_SGPIO_CHAIN_START) % GPIOS_PER_PORT;
++ uint bit_nr = priv->index * GPIOS_PER_PORT + sgpio_irq;
++
++ /* Enable IRQ */
++ writel(BIT(bit_nr), priv->base + priv->int_sts_offset);
++ writel(readl(priv->base + priv->int_en_offset) | BIT(bit_nr),
++ priv->base + priv->int_en_offset);
++
++ dev_dbg(priv->dev, "irq %d: %s [%s] pin %d\n", d->irq, __func__,
++ priv->chip.label, sgpio_irq);
++}
++
++static int aspeed_sgpio_irq_type(struct irq_data *d, unsigned int type)
++{
++ unsigned int irq = d->irq;
++ struct aspeed_sgpio *priv = irq_get_chip_data(irq);
++ u32 sgpio_irq = (irq - IRQ_SGPIO_CHAIN_START) % GPIOS_PER_PORT;
++ u32 type0, type1, type2;
++
++ dev_dbg(priv->dev, "irq: %d, sgpio_irq: %d , irq_type: 0x%x\n",
++ irq, sgpio_irq, type);
++
++ if (type & ~IRQ_TYPE_SENSE_MASK)
++ return -EINVAL;
++
++ type0 = readl(priv->base + priv->int_type_offset);
++ type1 = readl(priv->base + priv->int_type_offset + 0x04);
++ type2 = readl(priv->base + priv->int_type_offset + 0x08);
++
++ switch (type) {
++ /* Edge rising type */
++ case IRQ_TYPE_EDGE_RISING:
++ type0 |= BIT(sgpio_irq);
++ type1 &= ~BIT(sgpio_irq);
++ type2 &= ~BIT(sgpio_irq);
++ break;
++ /* Edge falling type */
++ case IRQ_TYPE_EDGE_FALLING:
++ type2 |= BIT(sgpio_irq);
++ break;
++ case IRQ_TYPE_EDGE_BOTH:
++ type0 &= ~BIT(sgpio_irq);
++ type1 |= BIT(sgpio_irq);
++ type2 &= ~BIT(sgpio_irq);
++ break;
++ case IRQ_TYPE_LEVEL_HIGH:
++ type0 |= BIT(sgpio_irq);
++ type1 |= BIT(sgpio_irq);
++ type2 &= ~BIT(sgpio_irq);
++ break;
++ case IRQ_TYPE_LEVEL_LOW:
++ type0 &= ~BIT(sgpio_irq);
++ type1 |= BIT(sgpio_irq);
++ type2 &= ~BIT(sgpio_irq);
++ break;
++ default:
++ dev_dbg(priv->dev, "not supported trigger type: %d", type);
++ return -EINVAL;
++ break;
++ }
++
++ writel(type0, priv->base + priv->int_type_offset);
++ writel(type1, priv->base + priv->int_type_offset + 0x04);
++ writel(type2, priv->base + priv->int_type_offset + 0x08);
++
++ return 0;
++}
++
++static struct irq_chip aspeed_sgpio_irq_chip = {
++ .name = "aspeed-sgpio",
++ .irq_ack = aspeed_sgpio_ack_irq,
++ .irq_mask = aspeed_sgpio_mask_irq,
++ .irq_unmask = aspeed_sgpio_unmask_irq,
++ .irq_set_type = aspeed_sgpio_irq_type,
++};
++
++static int aspeed_sgpio_config(struct aspeed_sgpio *priv)
++{
++ /**
++ * There is a limitation that SGPIO clock division has to be larger or
++ * equal to 1. And the value of clock division read back is left shift
++ * 1 bit from actual value.
++ *
++ * GPIO254[31:16] - Serial GPIO clock division
++ * Serial GPIO clock period = period of PCLK * 2 * (GPIO254[31:16] + 1)
++ *
++ * SGPIO master controller updates every data input when SGPMLD is low.
++ * For example, SGPIO clock is 1MHz and number of SGPIO is 80 then each
++ * SGPIO will be updated in every 80us.
++ */
++ writel(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, 10) |
++ FIELD_PREP(ASPEED_SGPIO_PINS_MASK, SGPIO_GROUP_NUMS) |
++ ASPEED_SGPIO_ENABLE,
++ priv->base + ASPEED_SGPIO_CTRL);
++ dev_dbg(priv->dev, "sgpio config reg: 0x%08X\n",
++ readl(priv->base + ASPEED_SGPIO_CTRL));
++
++ return 0;
++}
++
++static int aspeed_sgpio_probe(struct platform_device *pdev)
++{
++ int i, j;
++ uint irq;
++ struct resource *res;
++ struct aspeed_sgpio *priv;
++ void __iomem *base;
++ int mirq;
++
++ // aspeed_scu_multi_func_sgpio(); done via pinctl
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++ base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(base))
++ return PTR_ERR(base);
++
++ mirq = platform_get_irq(pdev, 0);
++ if (!mirq)
++ return -ENODEV;
++
++ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_gp); i++) {
++ // TODO: use heap allocation and use a single priv
++ priv = &aspeed_sgpio_gp[i];
++ priv->dev = &pdev->dev;
++ priv->base = base;
++ priv->mirq = mirq;
++ dev_set_drvdata(&pdev->dev, priv);
++
++ dev_dbg(priv->dev, "add gpio_chip [%s]: %d\n", priv->chip.label,
++ i);
++
++ devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
++
++ /* Disable Interrupt & Clear Status & Set Level-High Trigger */
++ writel(0x00000000, priv->base + priv->int_en_offset);
++ writel(0xffffffff, priv->base + priv->int_sts_offset);
++ writel(0xffffffff, priv->base + priv->int_type_offset);
++ writel(0xffffffff, priv->base + priv->int_type_offset + 0x04);
++ writel(0x00000000, priv->base + priv->int_type_offset + 0x08);
++
++ // TODO: no this many chip registration is needed. fix it.
++ for (j = 0; j < GPIOS_PER_PORT; j++) {
++ irq = i * GPIOS_PER_PORT + j + IRQ_SGPIO_CHAIN_START;
++ dev_dbg(priv->dev, "inst chip data %d\n", irq);
++ irq_set_chip_data(irq, priv);
++ irq_set_chip_and_handler(irq, &aspeed_sgpio_irq_chip,
++ handle_level_irq);
++ irq_clear_status_flags(irq, IRQ_NOREQUEST);
++ }
++ }
++
++ irq_set_chained_handler(priv->mirq, aspeed_sgpio_irq_handler);
++
++ aspeed_sgpio_config(priv);
++
++ dev_info(&pdev->dev, "sgpio controller registered, irq %d\n",
++ priv->mirq);
++
++ return 0;
++}
++
++static int aspeed_sgpio_remove(struct platform_device *pdev)
++{
++ struct aspeed_sgpio *priv =
++ &aspeed_sgpio_gp[ARRAY_SIZE(aspeed_sgpio_gp) - 1];
++
++ irq_set_chained_handler(priv->mirq, NULL);
++
++ return 0;
++}
++
++static const struct of_device_id aspeed_sgpio_of_table[] = {
++ { .compatible = "aspeed,ast2400-sgpio", },
++ { .compatible = "aspeed,ast2500-sgpio", },
++ { },
++};
++MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
++
++static struct platform_driver aspeed_sgpio_driver = {
++ .probe = aspeed_sgpio_probe,
++ .remove = aspeed_sgpio_remove,
++ .driver = {
++ .name = "sgpio-aspeed",
++ .of_match_table = of_match_ptr(aspeed_sgpio_of_table),
++ },
++};
++
++static int __init aspeed_sgpio_init(void)
++{
++ return platform_driver_register(&aspeed_sgpio_driver);
++}
++subsys_initcall(aspeed_sgpio_init);
++
++static void __exit aspeed_sgpio_exit(void)
++{
++ platform_driver_unregister(&aspeed_sgpio_driver);
++}
++module_exit(aspeed_sgpio_exit);
++
++MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
++MODULE_DESCRIPTION("ASPEED SGPIO driver");
++MODULE_LICENSE("GPL v2");
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch
new file mode 100644
index 000000000..346b9e3e3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch
@@ -0,0 +1,240 @@
+From f4b91f5c6723e56e106a609cdbcc8da48c56499e Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@intel.com>
+Date: Wed, 16 May 2018 10:03:14 -0700
+Subject: [PATCH] SGPIO DT and pinctrl fixup
+
+This commit fixes DT and pinctrl for SGPIO use.
+
+Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g4.dtsi | 54 ++++++++++--------------------
+ arch/arm/boot/dts/aspeed-g5.dtsi | 8 +++++
+ drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c | 48 +++++++++++++-------------
+ drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 4 +++
+ 4 files changed, 54 insertions(+), 60 deletions(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index 6af12872ee74..9aed0f696a98 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -201,6 +201,18 @@
+ interrupt-controller;
+ };
+
++ sgpio: sgpio@1e780200 {
++ #gpio-cells = <2>;
++ gpio-controller;
++ compatible = "aspeed,ast2400-sgpio";
++ reg = <0x1e780200 0x0100>;
++ interrupts = <40>;
++ interrupt-controller;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_sgpm_default>;
++ status = "disabled";
++ };
++
+ timer: timer@1e782000 {
+ /* This timer is a Faraday FTTMR010 derivative */
+ compatible = "aspeed,ast2400-timer";
+@@ -1150,44 +1162,14 @@
+ groups = "SD2";
+ };
+
+- pinctrl_sgpmck_default: sgpmck_default {
+- function = "SGPMCK";
+- groups = "SGPMCK";
+- };
+-
+- pinctrl_sgpmi_default: sgpmi_default {
+- function = "SGPMI";
+- groups = "SGPMI";
+- };
+-
+- pinctrl_sgpmld_default: sgpmld_default {
+- function = "SGPMLD";
+- groups = "SGPMLD";
+- };
+-
+- pinctrl_sgpmo_default: sgpmo_default {
+- function = "SGPMO";
+- groups = "SGPMO";
+- };
+-
+- pinctrl_sgpsck_default: sgpsck_default {
+- function = "SGPSCK";
+- groups = "SGPSCK";
+- };
+-
+- pinctrl_sgpsi0_default: sgpsi0_default {
+- function = "SGPSI0";
+- groups = "SGPSI0";
+- };
+-
+- pinctrl_sgpsi1_default: sgpsi1_default {
+- function = "SGPSI1";
+- groups = "SGPSI1";
++ pinctrl_sgpm_default: sgpm_default {
++ function = "SGPM";
++ groups = "SGPM";
+ };
+
+- pinctrl_sgpsld_default: sgpsld_default {
+- function = "SGPSLD";
+- groups = "SGPSLD";
++ pinctrl_sgps_default: sgps_default {
++ function = "SGPS";
++ groups = "SGPS";
+ };
+
+ pinctrl_sioonctrl_default: sioonctrl_default {
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index 01e901031bd4..36d72c91a2ad 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -274,6 +274,9 @@
+ reg = <0x1e780200 0x0100>;
+ interrupts = <40>;
+ interrupt-controller;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_sgpm_default>;
++ status = "disabled";
+ };
+
+ timer: timer@1e782000 {
+@@ -1324,6 +1327,11 @@
+ groups = "SDA2";
+ };
+
++ pinctrl_sgpm_default: sgpm_default {
++ function = "SGPM";
++ groups = "SGPM";
++ };
++
+ pinctrl_sgps1_default: sgps1_default {
+ function = "SGPS1";
+ groups = "SGPS1";
+diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
+index 05b153034517..353af05b8602 100644
+--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
+@@ -401,16 +401,22 @@ SSSF_PIN_DECL(E16, GPIOF6, TXD4, SIG_DESC_SET(SCU80, 30));
+ SSSF_PIN_DECL(C17, GPIOF7, RXD4, SIG_DESC_SET(SCU80, 31));
+
+ #define A14 48
+-SSSF_PIN_DECL(A14, GPIOG0, SGPSCK, SIG_DESC_SET(SCU84, 0));
++SIG_EXPR_LIST_DECL_SINGLE(SGPSCK, SGPS, SIG_DESC_SET(SCU84, 0));
++SS_PIN_DECL(A14, GPIOG0, SGPSCK);
+
+ #define E13 49
+-SSSF_PIN_DECL(E13, GPIOG1, SGPSLD, SIG_DESC_SET(SCU84, 1));
++SIG_EXPR_LIST_DECL_SINGLE(SGPSLD, SGPS, SIG_DESC_SET(SCU84, 1));
++SS_PIN_DECL(E13, GPIOG1, SGPSLD);
+
+ #define D13 50
+-SSSF_PIN_DECL(D13, GPIOG2, SGPSI0, SIG_DESC_SET(SCU84, 2));
++SIG_EXPR_LIST_DECL_SINGLE(SGPSIO, SGPS, SIG_DESC_SET(SCU84, 2));
++SS_PIN_DECL(D13, GPIOG2, SGPSIO);
+
+ #define C13 51
+-SSSF_PIN_DECL(C13, GPIOG3, SGPSI1, SIG_DESC_SET(SCU84, 3));
++SIG_EXPR_LIST_DECL_SINGLE(SGPSI1, SGPS, SIG_DESC_SET(SCU84, 3));
++SS_PIN_DECL(C13, GPIOG3, SGPSI1);
++
++FUNC_GROUP_DECL(SGPS, A14, E13, D13, C13);
+
+ #define B13 52
+ SIG_EXPR_LIST_DECL_SINGLE(OSCCLK, OSCCLK, SIG_DESC_SET(SCU2C, 1));
+@@ -576,16 +582,22 @@ FUNC_GROUP_DECL(SPI1PASSTHRU, C22, G18, D19, C20, B22, G19, C18, E20);
+ FUNC_GROUP_DECL(VGABIOS_ROM, B22, G19, C18, E20);
+
+ #define J5 72
+-SSSF_PIN_DECL(J5, GPIOJ0, SGPMCK, SIG_DESC_SET(SCU84, 8));
++SIG_EXPR_LIST_DECL_SINGLE(SGPMCK, SGPM, SIG_DESC_SET(SCU84, 8));
++SS_PIN_DECL(J5, GPIOJ0, SGPMCK);
+
+ #define J4 73
+-SSSF_PIN_DECL(J4, GPIOJ1, SGPMLD, SIG_DESC_SET(SCU84, 9));
++SIG_EXPR_LIST_DECL_SINGLE(SGPMLD, SGPM, SIG_DESC_SET(SCU84, 9));
++SS_PIN_DECL(J4, GPIOJ1, SGPMLD);
+
+ #define K5 74
+-SSSF_PIN_DECL(K5, GPIOJ2, SGPMO, SIG_DESC_SET(SCU84, 10));
++SIG_EXPR_LIST_DECL_SINGLE(SGPMO, SGPM, SIG_DESC_SET(SCU84, 10));
++SS_PIN_DECL(K5, GPIOJ2, SGPMO);
+
+ #define J3 75
+-SSSF_PIN_DECL(J3, GPIOJ3, SGPMI, SIG_DESC_SET(SCU84, 11));
++SIG_EXPR_LIST_DECL_SINGLE(SGPMI, SGPM, SIG_DESC_SET(SCU84, 11));
++SS_PIN_DECL(J3, GPIOJ3, SGPMI);
++
++FUNC_GROUP_DECL(SGPM, J5, J4, K5, J3);
+
+ #define T4 76
+ SSSF_PIN_DECL(T4, GPIOJ4, VGAHS, SIG_DESC_SET(SCU84, 12));
+@@ -2083,14 +2095,8 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = {
+ ASPEED_PINCTRL_GROUP(SALT4),
+ ASPEED_PINCTRL_GROUP(SD1),
+ ASPEED_PINCTRL_GROUP(SD2),
+- ASPEED_PINCTRL_GROUP(SGPMCK),
+- ASPEED_PINCTRL_GROUP(SGPMI),
+- ASPEED_PINCTRL_GROUP(SGPMLD),
+- ASPEED_PINCTRL_GROUP(SGPMO),
+- ASPEED_PINCTRL_GROUP(SGPSCK),
+- ASPEED_PINCTRL_GROUP(SGPSI0),
+- ASPEED_PINCTRL_GROUP(SGPSI1),
+- ASPEED_PINCTRL_GROUP(SGPSLD),
++ ASPEED_PINCTRL_GROUP(SGPM),
++ ASPEED_PINCTRL_GROUP(SGPS),
+ ASPEED_PINCTRL_GROUP(SIOONCTRL),
+ ASPEED_PINCTRL_GROUP(SIOPBI),
+ ASPEED_PINCTRL_GROUP(SIOPBO),
+@@ -2238,14 +2244,8 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = {
+ ASPEED_PINCTRL_FUNC(SALT4),
+ ASPEED_PINCTRL_FUNC(SD1),
+ ASPEED_PINCTRL_FUNC(SD2),
+- ASPEED_PINCTRL_FUNC(SGPMCK),
+- ASPEED_PINCTRL_FUNC(SGPMI),
+- ASPEED_PINCTRL_FUNC(SGPMLD),
+- ASPEED_PINCTRL_FUNC(SGPMO),
+- ASPEED_PINCTRL_FUNC(SGPSCK),
+- ASPEED_PINCTRL_FUNC(SGPSI0),
+- ASPEED_PINCTRL_FUNC(SGPSI1),
+- ASPEED_PINCTRL_FUNC(SGPSLD),
++ ASPEED_PINCTRL_FUNC(SGPM),
++ ASPEED_PINCTRL_FUNC(SGPS),
+ ASPEED_PINCTRL_FUNC(SIOONCTRL),
+ ASPEED_PINCTRL_FUNC(SIOPBI),
+ ASPEED_PINCTRL_FUNC(SIOPBO),
+diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+index 187abd7693cf..0c89647f166f 100644
+--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+@@ -577,6 +577,8 @@ SS_PIN_DECL(N3, GPIOJ2, SGPMO);
+ SIG_EXPR_LIST_DECL_SINGLE(SGPMI, SGPM, SIG_DESC_SET(SCU84, 11));
+ SS_PIN_DECL(N4, GPIOJ3, SGPMI);
+
++FUNC_GROUP_DECL(SGPM, R2, L2, N3, N4);
++
+ #define N5 76
+ SIG_EXPR_LIST_DECL_SINGLE(VGAHS, VGAHS, SIG_DESC_SET(SCU84, 12));
+ SIG_EXPR_LIST_DECL_SINGLE(DASHN5, DASHN5, SIG_DESC_SET(SCU94, 8));
+@@ -2127,6 +2129,7 @@ static const struct aspeed_pin_group aspeed_g5_groups[] = {
+ ASPEED_PINCTRL_GROUP(SD2),
+ ASPEED_PINCTRL_GROUP(SDA1),
+ ASPEED_PINCTRL_GROUP(SDA2),
++ ASPEED_PINCTRL_GROUP(SGPM),
+ ASPEED_PINCTRL_GROUP(SGPS1),
+ ASPEED_PINCTRL_GROUP(SGPS2),
+ ASPEED_PINCTRL_GROUP(SIOONCTRL),
+@@ -2296,6 +2299,7 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = {
+ ASPEED_PINCTRL_FUNC(SD2),
+ ASPEED_PINCTRL_FUNC(SDA1),
+ ASPEED_PINCTRL_FUNC(SDA2),
++ ASPEED_PINCTRL_FUNC(SGPM),
+ ASPEED_PINCTRL_FUNC(SGPS1),
+ ASPEED_PINCTRL_FUNC(SGPS2),
+ ASPEED_PINCTRL_FUNC(SIOONCTRL),
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch
new file mode 100644
index 000000000..3cd1d9e84
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch
@@ -0,0 +1,4392 @@
+From ce7a88017fb2124100c4e5481a205034f34da23c Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Mon, 7 Jan 2019 09:56:10 -0800
+Subject: [PATCH] Update PECI drivers to sync with linux upstreaming version
+
+Upstreaming is in holding. It's for adding DTS sensor with PECI
+subsystem code update.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ Documentation/hwmon/peci-cputemp | 34 +-
+ drivers/hwmon/Kconfig | 4 +-
+ drivers/hwmon/peci-cputemp.c | 156 ++++--
+ drivers/hwmon/peci-dimmtemp.c | 69 +--
+ drivers/hwmon/peci-hwmon.h | 9 +-
+ drivers/mfd/Kconfig | 5 +-
+ drivers/mfd/intel-peci-client.c | 43 +-
+ drivers/peci/Kconfig | 35 +-
+ drivers/peci/Makefile | 6 +-
+ drivers/peci/busses/Kconfig | 19 +
+ drivers/peci/busses/Makefile | 6 +
+ drivers/peci/busses/peci-aspeed.c | 494 +++++++++++++++++++
+ drivers/peci/peci-aspeed.c | 505 -------------------
+ drivers/peci/peci-core.c | 889 ++++++++++++++++++----------------
+ drivers/peci/peci-dev.c | 340 +++++++++++++
+ include/linux/mfd/intel-peci-client.h | 6 +-
+ include/linux/peci.h | 30 +-
+ include/uapi/linux/peci-ioctl.h | 394 ++++++++-------
+ 18 files changed, 1805 insertions(+), 1239 deletions(-)
+ create mode 100644 drivers/peci/busses/Kconfig
+ create mode 100644 drivers/peci/busses/Makefile
+ create mode 100644 drivers/peci/busses/peci-aspeed.c
+ delete mode 100644 drivers/peci/peci-aspeed.c
+ create mode 100644 drivers/peci/peci-dev.c
+
+diff --git a/Documentation/hwmon/peci-cputemp b/Documentation/hwmon/peci-cputemp
+index 821a9258f2e6..a3a3e465c888 100644
+--- a/Documentation/hwmon/peci-cputemp
++++ b/Documentation/hwmon/peci-cputemp
+@@ -51,28 +51,38 @@ temp1_crit Provides shutdown temperature of the CPU package which
+ temp1_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
+ the CPU package.
+
+-temp2_label "Tcontrol"
+-temp2_input Provides current Tcontrol temperature of the CPU
++temp2_label "DTS"
++temp2_input Provides current DTS temperature of the CPU package.
++temp2_max Provides thermal control temperature of the CPU package
++ which is also known as Tcontrol.
++temp2_crit Provides shutdown temperature of the CPU package which
++ is also known as the maximum processor junction
++ temperature, Tjmax or Tprochot.
++temp2_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
++ the CPU package.
++
++temp3_label "Tcontrol"
++temp3_input Provides current Tcontrol temperature of the CPU
+ package which is also known as Fan Temperature target.
+ Indicates the relative value from thermal monitor trip
+ temperature at which fans should be engaged.
+-temp2_crit Provides Tcontrol critical value of the CPU package
++temp3_crit Provides Tcontrol critical value of the CPU package
+ which is same to Tjmax.
+
+-temp3_label "Tthrottle"
+-temp3_input Provides current Tthrottle temperature of the CPU
++temp4_label "Tthrottle"
++temp4_input Provides current Tthrottle temperature of the CPU
+ package. Used for throttling temperature. If this value
+ is allowed and lower than Tjmax - the throttle will
+ occur and reported at lower than Tjmax.
+
+-temp4_label "Tjmax"
+-temp4_input Provides the maximum junction temperature, Tjmax of the
++temp5_label "Tjmax"
++temp5_input Provides the maximum junction temperature, Tjmax of the
+ CPU package.
+
+-temp[5-*]_label Provides string "Core X", where X is resolved core
++temp[6-*]_label Provides string "Core X", where X is resolved core
+ number.
+-temp[5-*]_input Provides current temperature of each core.
+-temp[5-*]_max Provides thermal control temperature of the core.
+-temp[5-*]_crit Provides shutdown temperature of the core.
+-temp[5-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
++temp[6-*]_input Provides current temperature of each core.
++temp[6-*]_max Provides thermal control temperature of the core.
++temp[6-*]_crit Provides shutdown temperature of the core.
++temp[6-*]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
+ the core.
+diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
+index 9e118d700b48..efe67f7faed3 100644
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -1319,7 +1319,7 @@ config SENSORS_PECI_CPUTEMP
+ the PECI Client Command Suite via the processor PECI client.
+ Check Documentation/hwmon/peci-cputemp for details.
+
+- This driver can also be built as a module. If so, the module
++ This driver can also be built as a module. If so, the module
+ will be called peci-cputemp.
+
+ config SENSORS_PECI_DIMMTEMP
+@@ -1333,7 +1333,7 @@ config SENSORS_PECI_DIMMTEMP
+ Suite via the processor PECI client.
+ Check Documentation/hwmon/peci-dimmtemp for details.
+
+- This driver can also be built as a module. If so, the module
++ This driver can also be built as a module. If so, the module
+ will be called peci-dimmtemp.
+
+ source drivers/hwmon/pmbus/Kconfig
+diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c
+index 11880c86a854..30ba1638e358 100644
+--- a/drivers/hwmon/peci-cputemp.c
++++ b/drivers/hwmon/peci-cputemp.c
+@@ -1,5 +1,5 @@
+ // SPDX-License-Identifier: GPL-2.0
+-// Copyright (c) 2018 Intel Corporation
++// Copyright (c) 2018-2019 Intel Corporation
+
+ #include <linux/hwmon.h>
+ #include <linux/jiffies.h>
+@@ -9,7 +9,7 @@
+ #include <linux/platform_device.h>
+ #include "peci-hwmon.h"
+
+-#define DEFAULT_CHANNEL_NUMS 4
++#define DEFAULT_CHANNEL_NUMS 5
+ #define CORETEMP_CHANNEL_NUMS CORE_NUMS_MAX
+ #define CPUTEMP_CHANNEL_NUMS (DEFAULT_CHANNEL_NUMS + CORETEMP_CHANNEL_NUMS)
+
+@@ -21,6 +21,7 @@
+
+ struct temp_group {
+ struct temp_data die;
++ struct temp_data dts;
+ struct temp_data tcontrol;
+ struct temp_data tthrottle;
+ struct temp_data tjmax;
+@@ -43,6 +44,7 @@ struct peci_cputemp {
+
+ enum cputemp_channels {
+ channel_die,
++ channel_dts,
+ channel_tcontrol,
+ channel_tthrottle,
+ channel_tjmax,
+@@ -54,6 +56,10 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = {
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_CRIT_HYST,
+
++ /* DTS margin */
++ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
++ HWMON_T_CRIT_HYST,
++
+ /* Tcontrol temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT,
+
+@@ -70,6 +76,7 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = {
+
+ static const char *cputemp_label[CPUTEMP_CHANNEL_NUMS] = {
+ "Die",
++ "DTS",
+ "Tcontrol",
+ "Tthrottle",
+ "Tjmax",
+@@ -92,19 +99,20 @@ static int get_temp_targets(struct peci_cputemp *priv)
+ s32 tthrottle_offset;
+ s32 tcontrol_margin;
+ u8 pkg_cfg[4];
+- int rc;
++ int ret;
+
+- /**
++ /*
+ * Just use only the tcontrol marker to determine if target values need
+ * update.
+ */
+ if (!peci_temp_need_update(&priv->temp.tcontrol))
+ return 0;
+
+- rc = peci_client_read_package_config(priv->mgr,
+- MBX_INDEX_TEMP_TARGET, 0, pkg_cfg);
+- if (rc)
+- return rc;
++ ret = peci_client_read_package_config(priv->mgr,
++ PECI_MBX_INDEX_TEMP_TARGET, 0,
++ pkg_cfg);
++ if (ret)
++ return ret;
+
+ priv->temp.tjmax.value = pkg_cfg[2] * 1000;
+
+@@ -123,17 +131,16 @@ static int get_temp_targets(struct peci_cputemp *priv)
+ static int get_die_temp(struct peci_cputemp *priv)
+ {
+ struct peci_get_temp_msg msg;
+- int rc;
++ int ret;
+
+ if (!peci_temp_need_update(&priv->temp.die))
+ return 0;
+
+ msg.addr = priv->mgr->client->addr;
+
+- rc = peci_command(priv->mgr->client->adapter, PECI_CMD_GET_TEMP,
+- &msg);
+- if (rc)
+- return rc;
++ ret = peci_command(priv->mgr->client->adapter, PECI_CMD_GET_TEMP, &msg);
++ if (ret)
++ return ret;
+
+ /* Note that the tjmax should be available before calling it */
+ priv->temp.die.value = priv->temp.tjmax.value +
+@@ -144,24 +151,67 @@ static int get_die_temp(struct peci_cputemp *priv)
+ return 0;
+ }
+
++static int get_dts(struct peci_cputemp *priv)
++{
++ struct peci_rd_pkg_cfg_msg msg;
++ s32 dts_margin;
++ int ret;
++
++ if (!peci_temp_need_update(&priv->temp.dts))
++ return 0;
++
++ msg.addr = priv->mgr->client->addr;
++ msg.index = PECI_MBX_INDEX_DTS_MARGIN;
++ msg.param = 0;
++ msg.rx_len = 4;
++
++ ret = peci_command(priv->mgr->client->adapter, PECI_CMD_RD_PKG_CFG,
++ &msg);
++ if (ret)
++ return ret;
++
++ dts_margin = (msg.pkg_config[1] << 8) | msg.pkg_config[0];
++
++ /**
++ * Processors return a value of DTS reading in 10.6 format
++ * (10 bits signed decimal, 6 bits fractional).
++ * Error codes:
++ * 0x8000: General sensor error
++ * 0x8001: Reserved
++ * 0x8002: Underflow on reading value
++ * 0x8003-0x81ff: Reserved
++ */
++ if (dts_margin >= 0x8000 && dts_margin <= 0x81ff)
++ return -EIO;
++
++ dts_margin = ten_dot_six_to_millidegree(dts_margin);
++
++ /* Note that the tcontrol should be available before calling it */
++ priv->temp.dts.value = priv->temp.tcontrol.value - dts_margin;
++
++ peci_temp_mark_updated(&priv->temp.dts);
++
++ return 0;
++}
++
+ static int get_core_temp(struct peci_cputemp *priv, int core_index)
+ {
+ s32 core_dts_margin;
+ u8 pkg_cfg[4];
+- int rc;
++ int ret;
+
+ if (!peci_temp_need_update(&priv->temp.core[core_index]))
+ return 0;
+
+- rc = peci_client_read_package_config(priv->mgr,
+- MBX_INDEX_PER_CORE_DTS_TEMP,
+- core_index, pkg_cfg);
+- if (rc)
+- return rc;
++ ret = peci_client_read_package_config(priv->mgr,
++ PECI_MBX_INDEX_PER_CORE_DTS_TEMP,
++ core_index, pkg_cfg);
++ if (ret)
++ return ret;
+
+ core_dts_margin = le16_to_cpup((__le16 *)pkg_cfg);
+
+- /**
++ /*
+ * Processors return a value of the core DTS reading in 10.6 format
+ * (10 bits signed decimal, 6 bits fractional).
+ * Error codes:
+@@ -192,6 +242,7 @@ static int cputemp_read_string(struct device *dev,
+ return -EOPNOTSUPP;
+
+ *str = cputemp_label[channel];
++
+ return 0;
+ }
+
+@@ -200,26 +251,33 @@ static int cputemp_read(struct device *dev,
+ u32 attr, int channel, long *val)
+ {
+ struct peci_cputemp *priv = dev_get_drvdata(dev);
+- int rc, core_index;
++ int ret, core_index;
+
+ if (channel >= CPUTEMP_CHANNEL_NUMS ||
+ !(priv->temp_config[channel] & BIT(attr)))
+ return -EOPNOTSUPP;
+
+- rc = get_temp_targets(priv);
+- if (rc)
+- return rc;
++ ret = get_temp_targets(priv);
++ if (ret)
++ return ret;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ switch (channel) {
+ case channel_die:
+- rc = get_die_temp(priv);
+- if (rc)
++ ret = get_die_temp(priv);
++ if (ret)
+ break;
+
+ *val = priv->temp.die.value;
+ break;
++ case channel_dts:
++ ret = get_dts(priv);
++ if (ret)
++ break;
++
++ *val = priv->temp.dts.value;
++ break;
+ case channel_tcontrol:
+ *val = priv->temp.tcontrol.value;
+ break;
+@@ -231,8 +289,8 @@ static int cputemp_read(struct device *dev,
+ break;
+ default:
+ core_index = channel - DEFAULT_CHANNEL_NUMS;
+- rc = get_core_temp(priv, core_index);
+- if (rc)
++ ret = get_core_temp(priv, core_index);
++ if (ret)
+ break;
+
+ *val = priv->temp.core[core_index].value;
+@@ -249,11 +307,11 @@ static int cputemp_read(struct device *dev,
+ *val = priv->temp.tjmax.value - priv->temp.tcontrol.value;
+ break;
+ default:
+- rc = -EOPNOTSUPP;
++ ret = -EOPNOTSUPP;
+ break;
+ }
+
+- return rc;
++ return ret;
+ }
+
+ static umode_t cputemp_is_visible(const void *data,
+@@ -262,11 +320,11 @@ static umode_t cputemp_is_visible(const void *data,
+ {
+ const struct peci_cputemp *priv = data;
+
+- if (priv->temp_config[channel] & BIT(attr))
+- if (channel < DEFAULT_CHANNEL_NUMS ||
+- (channel >= DEFAULT_CHANNEL_NUMS &&
+- (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS))))
+- return 0444;
++ if ((priv->temp_config[channel] & BIT(attr)) &&
++ (channel < DEFAULT_CHANNEL_NUMS ||
++ (channel >= DEFAULT_CHANNEL_NUMS &&
++ (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS)))))
++ return 0444;
+
+ return 0;
+ }
+@@ -280,7 +338,7 @@ static const struct hwmon_ops cputemp_ops = {
+ static int check_resolved_cores(struct peci_cputemp *priv)
+ {
+ struct peci_rd_pci_cfg_local_msg msg;
+- int rc;
++ int ret;
+
+ /* Get the RESOLVED_CORES register value */
+ msg.addr = priv->mgr->client->addr;
+@@ -290,30 +348,31 @@ static int check_resolved_cores(struct peci_cputemp *priv)
+ msg.reg = REG_RESOLVED_CORES_OFFSET;
+ msg.rx_len = 4;
+
+- rc = peci_command(priv->mgr->client->adapter,
+- PECI_CMD_RD_PCI_CFG_LOCAL, &msg);
+- if (rc)
+- return rc;
++ ret = peci_command(priv->mgr->client->adapter,
++ PECI_CMD_RD_PCI_CFG_LOCAL, &msg);
++ if (ret)
++ return ret;
+
+ priv->core_mask = le32_to_cpup((__le32 *)msg.pci_config);
+ if (!priv->core_mask)
+ return -EAGAIN;
+
+ dev_dbg(priv->dev, "Scanned resolved cores: 0x%x\n", priv->core_mask);
++
+ return 0;
+ }
+
+ static int create_core_temp_info(struct peci_cputemp *priv)
+ {
+- int rc, i;
++ int ret, i;
+
+- rc = check_resolved_cores(priv);
+- if (rc)
+- return rc;
++ ret = check_resolved_cores(priv);
++ if (ret)
++ return ret;
+
+ for (i = 0; i < priv->gen_info->core_max; i++)
+ if (priv->core_mask & BIT(i))
+- while (i + DEFAULT_CHANNEL_NUMS >= priv->config_idx)
++ while (priv->config_idx <= i + DEFAULT_CHANNEL_NUMS)
+ priv->temp_config[priv->config_idx++] =
+ config_table[channel_core];
+
+@@ -326,7 +385,7 @@ static int peci_cputemp_probe(struct platform_device *pdev)
+ struct device *dev = &pdev->dev;
+ struct peci_cputemp *priv;
+ struct device *hwmon_dev;
+- int rc;
++ int ret;
+
+ if ((mgr->client->adapter->cmd_mask &
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
+@@ -346,12 +405,13 @@ static int peci_cputemp_probe(struct platform_device *pdev)
+ mgr->client->addr - PECI_BASE_ADDR);
+
+ priv->temp_config[priv->config_idx++] = config_table[channel_die];
++ priv->temp_config[priv->config_idx++] = config_table[channel_dts];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tcontrol];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tthrottle];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tjmax];
+
+- rc = create_core_temp_info(priv);
+- if (rc)
++ ret = create_core_temp_info(priv);
++ if (ret)
+ dev_dbg(dev, "Skipped creating core temp info\n");
+
+ priv->chip.ops = &cputemp_ops;
+diff --git a/drivers/hwmon/peci-dimmtemp.c b/drivers/hwmon/peci-dimmtemp.c
+index 86a45a90805b..e088366fd138 100644
+--- a/drivers/hwmon/peci-dimmtemp.c
++++ b/drivers/hwmon/peci-dimmtemp.c
+@@ -1,5 +1,5 @@
+ // SPDX-License-Identifier: GPL-2.0
+-// Copyright (c) 2018 Intel Corporation
++// Copyright (c) 2018-2019 Intel Corporation
+
+ #include <linux/hwmon.h>
+ #include <linux/jiffies.h>
+@@ -45,16 +45,16 @@ static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no)
+ int dimm_order = dimm_no % priv->gen_info->dimm_idx_max;
+ int chan_rank = dimm_no / priv->gen_info->dimm_idx_max;
+ u8 cfg_data[4];
+- int rc;
++ int ret;
+
+ if (!peci_temp_need_update(&priv->temp[dimm_no]))
+ return 0;
+
+- rc = peci_client_read_package_config(priv->mgr,
+- MBX_INDEX_DDR_DIMM_TEMP,
+- chan_rank, cfg_data);
+- if (rc)
+- return rc;
++ ret = peci_client_read_package_config(priv->mgr,
++ PECI_MBX_INDEX_DDR_DIMM_TEMP,
++ chan_rank, cfg_data);
++ if (ret)
++ return ret;
+
+ priv->temp[dimm_no].value = cfg_data[dimm_order] * 1000;
+
+@@ -77,6 +77,7 @@ static int dimmtemp_read_string(struct device *dev,
+ chan_rank = channel / dimm_idx_max;
+ dimm_idx = channel % dimm_idx_max;
+ *str = dimmtemp_label[chan_rank][dimm_idx];
++
+ return 0;
+ }
+
+@@ -84,16 +85,17 @@ static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+ {
+ struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+- int rc;
++ int ret;
+
+ if (attr != hwmon_temp_input)
+ return -EOPNOTSUPP;
+
+- rc = get_dimm_temp(priv, channel);
+- if (rc)
+- return rc;
++ ret = get_dimm_temp(priv, channel);
++ if (ret)
++ return ret;
+
+ *val = priv->temp[channel].value;
++
+ return 0;
+ }
+
+@@ -120,16 +122,16 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
+ {
+ u32 chan_rank_max = priv->gen_info->chan_rank_max;
+ u32 dimm_idx_max = priv->gen_info->dimm_idx_max;
+- int chan_rank, dimm_idx, rc;
++ int chan_rank, dimm_idx, ret;
+ u8 cfg_data[4];
+
+ for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) {
+- rc = peci_client_read_package_config(priv->mgr,
+- MBX_INDEX_DDR_DIMM_TEMP,
+- chan_rank, cfg_data);
+- if (rc) {
++ ret = peci_client_read_package_config(priv->mgr,
++ PECI_MBX_INDEX_DDR_DIMM_TEMP,
++ chan_rank, cfg_data);
++ if (ret) {
+ priv->dimm_mask = 0;
+- return rc;
++ return ret;
+ }
+
+ for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++)
+@@ -143,17 +145,18 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
+ return -EAGAIN;
+
+ dev_dbg(priv->dev, "Scanned populated DIMMs: 0x%x\n", priv->dimm_mask);
++
+ return 0;
+ }
+
+ static int create_dimm_temp_info(struct peci_dimmtemp *priv)
+ {
+- int rc, i, config_idx, channels;
++ int ret, i, config_idx, channels;
+ struct device *hwmon_dev;
+
+- rc = check_populated_dimms(priv);
+- if (rc) {
+- if (rc == -EAGAIN) {
++ ret = check_populated_dimms(priv);
++ if (ret) {
++ if (ret == -EAGAIN) {
+ if (priv->retry_count < DIMM_MASK_CHECK_RETRY_MAX) {
+ queue_delayed_work(priv->work_queue,
+ &priv->work_handler,
+@@ -164,11 +167,11 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv)
+ } else {
+ dev_err(priv->dev,
+ "Timeout DIMM temp info creation\n");
+- rc = -ETIMEDOUT;
++ ret = -ETIMEDOUT;
+ }
+ }
+
+- return rc;
++ return ret;
+ }
+
+ channels = priv->gen_info->chan_rank_max *
+@@ -192,12 +195,12 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv)
+ priv,
+ &priv->chip,
+ NULL);
+- rc = PTR_ERR_OR_ZERO(hwmon_dev);
+- if (!rc)
++ ret = PTR_ERR_OR_ZERO(hwmon_dev);
++ if (!ret)
+ dev_dbg(priv->dev, "%s: sensor '%s'\n",
+ dev_name(hwmon_dev), priv->name);
+
+- return rc;
++ return ret;
+ }
+
+ static void create_dimm_temp_info_delayed(struct work_struct *work)
+@@ -205,10 +208,10 @@ static void create_dimm_temp_info_delayed(struct work_struct *work)
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct peci_dimmtemp *priv = container_of(dwork, struct peci_dimmtemp,
+ work_handler);
+- int rc;
++ int ret;
+
+- rc = create_dimm_temp_info(priv);
+- if (rc && rc != -EAGAIN)
++ ret = create_dimm_temp_info(priv);
++ if (ret && ret != -EAGAIN)
+ dev_dbg(priv->dev, "Failed to create DIMM temp info\n");
+ }
+
+@@ -217,7 +220,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev)
+ struct peci_client_manager *mgr = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct peci_dimmtemp *priv;
+- int rc;
++ int ret;
+
+ if ((mgr->client->adapter->cmd_mask &
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
+@@ -242,8 +245,8 @@ static int peci_dimmtemp_probe(struct platform_device *pdev)
+
+ INIT_DELAYED_WORK(&priv->work_handler, create_dimm_temp_info_delayed);
+
+- rc = create_dimm_temp_info(priv);
+- if (rc && rc != -EAGAIN) {
++ ret = create_dimm_temp_info(priv);
++ if (ret && ret != -EAGAIN) {
+ dev_err(dev, "Failed to create DIMM temp info\n");
+ goto err_free_wq;
+ }
+@@ -252,7 +255,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev)
+
+ err_free_wq:
+ destroy_workqueue(priv->work_queue);
+- return rc;
++ return ret;
+ }
+
+ static int peci_dimmtemp_remove(struct platform_device *pdev)
+diff --git a/drivers/hwmon/peci-hwmon.h b/drivers/hwmon/peci-hwmon.h
+index 6ca1855a86bb..ce6b470eae63 100644
+--- a/drivers/hwmon/peci-hwmon.h
++++ b/drivers/hwmon/peci-hwmon.h
+@@ -1,5 +1,5 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+-/* Copyright (c) 2018 Intel Corporation */
++/* Copyright (c) 2018-2019 Intel Corporation */
+
+ #ifndef __PECI_HWMON_H
+ #define __PECI_HWMON_H
+@@ -29,11 +29,8 @@ struct temp_data {
+ */
+ static inline bool peci_temp_need_update(struct temp_data *temp)
+ {
+- if (temp->valid &&
+- time_before(jiffies, temp->last_updated + UPDATE_INTERVAL))
+- return false;
+-
+- return true;
++ return !temp->valid ||
++ time_after(jiffies, temp->last_updated + UPDATE_INTERVAL);
+ }
+
+ /**
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 66b71a6122d6..28a83b354ea8 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -596,7 +596,7 @@ config MFD_INTEL_MSIC
+ devices used in Intel Medfield platforms.
+
+ config MFD_INTEL_PECI_CLIENT
+- bool "Intel PECI client"
++ tristate "Intel PECI client"
+ depends on (PECI || COMPILE_TEST)
+ select MFD_CORE
+ help
+@@ -609,6 +609,9 @@ config MFD_INTEL_PECI_CLIENT
+ Additional drivers must be enabled in order to use the functionality
+ of the device.
+
++ This driver can also be built as a module. If so, the module
++ will be called intel-peci-client.
++
+ config MFD_IPAQ_MICRO
+ bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support"
+ depends on SA1100_H3100 || SA1100_H3600
+diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c
+index d53e4f1078ac..d62442438512 100644
+--- a/drivers/mfd/intel-peci-client.c
++++ b/drivers/mfd/intel-peci-client.c
+@@ -1,12 +1,12 @@
+ // SPDX-License-Identifier: GPL-2.0
+-// Copyright (c) 2018 Intel Corporation
++// Copyright (c) 2018-2019 Intel Corporation
+
+ #include <linux/bitfield.h>
+ #include <linux/mfd/core.h>
+ #include <linux/mfd/intel-peci-client.h>
+ #include <linux/module.h>
+-#include <linux/peci.h>
+ #include <linux/of_device.h>
++#include <linux/peci.h>
+
+ #define CPU_ID_MODEL_MASK GENMASK(7, 4)
+ #define CPU_ID_FAMILY_MASK GENMASK(11, 8)
+@@ -18,12 +18,6 @@
+ #define LOWER_BYTE_MASK GENMASK(7, 0)
+ #define UPPER_BYTE_MASK GENMASK(16, 8)
+
+-enum cpu_gens {
+- CPU_GEN_HSX = 0, /* Haswell Xeon */
+- CPU_GEN_BRX, /* Broadwell Xeon */
+- CPU_GEN_SKX, /* Skylake Xeon */
+-};
+-
+ static struct mfd_cell peci_functions[] = {
+ { .name = "peci-cputemp", },
+ { .name = "peci-dimmtemp", },
+@@ -31,19 +25,19 @@ static struct mfd_cell peci_functions[] = {
+ };
+
+ static const struct cpu_gen_info cpu_gen_info_table[] = {
+- [CPU_GEN_HSX] = {
++ { /* Haswell Xeon */
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_HASWELL_X,
+ .core_max = CORE_MAX_ON_HSX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_HSX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_HSX },
+- [CPU_GEN_BRX] = {
++ { /* Broadwell Xeon */
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_BROADWELL_X,
+ .core_max = CORE_MAX_ON_BDX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_BDX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_BDX },
+- [CPU_GEN_SKX] = {
++ { /* Skylake Xeon */
+ .family = 6, /* Family code */
+ .model = INTEL_FAM6_SKYLAKE_X,
+ .core_max = CORE_MAX_ON_SKX,
+@@ -53,16 +47,17 @@ static const struct cpu_gen_info cpu_gen_info_table[] = {
+
+ static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv)
+ {
++ struct device *dev = &priv->client->dev;
+ u32 cpu_id;
+ u16 family;
+ u8 model;
+- int rc;
++ int ret;
+ int i;
+
+- rc = peci_get_cpu_id(priv->client->adapter, priv->client->addr,
+- &cpu_id);
+- if (rc)
+- return rc;
++ ret = peci_get_cpu_id(priv->client->adapter, priv->client->addr,
++ &cpu_id);
++ if (ret)
++ return ret;
+
+ family = FIELD_PREP(LOWER_BYTE_MASK,
+ FIELD_GET(CPU_ID_FAMILY_MASK, cpu_id)) |
+@@ -83,11 +78,11 @@ static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv)
+ }
+
+ if (!priv->gen_info) {
+- dev_err(priv->dev, "Can't support this CPU: 0x%x\n", cpu_id);
+- rc = -ENODEV;
++ dev_err(dev, "Can't support this CPU: 0x%x\n", cpu_id);
++ ret = -ENODEV;
+ }
+
+- return rc;
++ return ret;
+ }
+
+ static int peci_client_probe(struct peci_client *client)
+@@ -103,31 +98,29 @@ static int peci_client_probe(struct peci_client *client)
+
+ dev_set_drvdata(dev, priv);
+ priv->client = client;
+- priv->dev = dev;
+ cpu_no = client->addr - PECI_BASE_ADDR;
+
+ ret = peci_client_get_cpu_gen_info(priv);
+ if (ret)
+ return ret;
+
+- ret = devm_mfd_add_devices(priv->dev, cpu_no, peci_functions,
++ ret = devm_mfd_add_devices(dev, cpu_no, peci_functions,
+ ARRAY_SIZE(peci_functions), NULL, 0, NULL);
+ if (ret < 0) {
+- dev_err(priv->dev, "Failed to register child devices: %d\n",
+- ret);
++ dev_err(dev, "Failed to register child devices: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+ }
+
+-#ifdef CONFIG_OF
++#if IS_ENABLED(CONFIG_OF)
+ static const struct of_device_id peci_client_of_table[] = {
+ { .compatible = "intel,peci-client" },
+ { }
+ };
+ MODULE_DEVICE_TABLE(of, peci_client_of_table);
+-#endif
++#endif /* CONFIG_OF */
+
+ static const struct peci_device_id peci_client_ids[] = {
+ { .name = "peci-client" },
+diff --git a/drivers/peci/Kconfig b/drivers/peci/Kconfig
+index 9e9845ebcff4..9752feee2454 100644
+--- a/drivers/peci/Kconfig
++++ b/drivers/peci/Kconfig
+@@ -2,10 +2,12 @@
+ # Platform Environment Control Interface (PECI) subsystem configuration
+ #
+
++menu "PECI support"
++
+ config PECI
+- bool "PECI support"
+- select RT_MUTEXES
++ tristate "PECI support"
+ select CRC8
++ default n
+ help
+ The Platform Environment Control Interface (PECI) is a one-wire bus
+ interface that provides a communication channel from Intel processors
+@@ -14,26 +16,23 @@ config PECI
+ If you want PECI support, you should say Y here and also to the
+ specific driver for your bus adapter(s) below.
+
+-if PECI
+-
+-#
+-# PECI hardware bus configuration
+-#
++ This support is also available as a module. If so, the module
++ will be called peci-core.
+
+-menu "PECI Hardware Bus support"
++if PECI
+
+-config PECI_ASPEED
+- tristate "ASPEED PECI support"
+- select REGMAP_MMIO
+- depends on OF
+- depends on ARCH_ASPEED || COMPILE_TEST
++config PECI_CHARDEV
++ tristate "PECI device interface"
+ help
+- Say Y here if you want support for the Platform Environment Control
+- Interface (PECI) bus adapter driver on the ASPEED SoCs.
++ Say Y here to use peci-* device files, usually found in the /dev
++ directory on your system. They make it possible to have user-space
++ programs use the PECI bus.
+
+- This support is also available as a module. If so, the module
+- will be called peci-aspeed.
++ This support is also available as a module. If so, the module
++ will be called peci-dev.
+
+-endmenu
++source "drivers/peci/busses/Kconfig"
+
+ endif # PECI
++
++endmenu
+diff --git a/drivers/peci/Makefile b/drivers/peci/Makefile
+index 886285e69765..da8b0a33fa42 100644
+--- a/drivers/peci/Makefile
++++ b/drivers/peci/Makefile
+@@ -1,9 +1,11 @@
++# SPDX-License-Identifier: GPL-2.0
+ #
+-# Makefile for the PECI core and bus drivers.
++# Makefile for the PECI core drivers.
+ #
+
+ # Core functionality
+ obj-$(CONFIG_PECI) += peci-core.o
++obj-$(CONFIG_PECI_CHARDEV) += peci-dev.o
+
+ # Hardware specific bus drivers
+-obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o
++obj-y += busses/
+diff --git a/drivers/peci/busses/Kconfig b/drivers/peci/busses/Kconfig
+new file mode 100644
+index 000000000000..a20d470b4250
+--- /dev/null
++++ b/drivers/peci/busses/Kconfig
+@@ -0,0 +1,19 @@
++#
++# PECI hardware bus configuration
++#
++
++menu "PECI Hardware Bus support"
++
++config PECI_ASPEED
++ tristate "ASPEED PECI support"
++ depends on ARCH_ASPEED || COMPILE_TEST
++ depends on OF
++ depends on PECI
++ help
++ Say Y here if you want support for the Platform Environment Control
++ Interface (PECI) bus adapter driver on the ASPEED SoCs.
++
++ This support is also available as a module. If so, the module
++ will be called peci-aspeed.
++
++endmenu
+diff --git a/drivers/peci/busses/Makefile b/drivers/peci/busses/Makefile
+new file mode 100644
+index 000000000000..69e31dfaca19
+--- /dev/null
++++ b/drivers/peci/busses/Makefile
+@@ -0,0 +1,6 @@
++# SPDX-License-Identifier: GPL-2.0
++#
++# Makefile for the PECI hardware bus drivers.
++#
++
++obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o
+diff --git a/drivers/peci/busses/peci-aspeed.c b/drivers/peci/busses/peci-aspeed.c
+new file mode 100644
+index 000000000000..8a0dd40730cc
+--- /dev/null
++++ b/drivers/peci/busses/peci-aspeed.c
+@@ -0,0 +1,494 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (C) 2012-2017 ASPEED Technology Inc.
++// Copyright (c) 2018-2019 Intel Corporation
++
++#include <linux/bitfield.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/jiffies.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/peci.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++
++/* ASPEED PECI Registers */
++/* Control Register */
++#define ASPEED_PECI_CTRL 0x00
++#define ASPEED_PECI_CTRL_SAMPLING_MASK GENMASK(19, 16)
++#define ASPEED_PECI_CTRL_READ_MODE_MASK GENMASK(13, 12)
++#define ASPEED_PECI_CTRL_READ_MODE_COUNT BIT(12)
++#define ASPEED_PECI_CTRL_READ_MODE_DBG BIT(13)
++#define ASPEED_PECI_CTRL_CLK_SOURCE_MASK BIT(11)
++#define ASPEED_PECI_CTRL_CLK_DIV_MASK GENMASK(10, 8)
++#define ASPEED_PECI_CTRL_INVERT_OUT BIT(7)
++#define ASPEED_PECI_CTRL_INVERT_IN BIT(6)
++#define ASPEED_PECI_CTRL_BUS_CONTENT_EN BIT(5)
++#define ASPEED_PECI_CTRL_PECI_EN BIT(4)
++#define ASPEED_PECI_CTRL_PECI_CLK_EN BIT(0)
++
++/* Timing Negotiation Register */
++#define ASPEED_PECI_TIMING_NEGOTIATION 0x04
++#define ASPEED_PECI_TIMING_MESSAGE_MASK GENMASK(15, 8)
++#define ASPEED_PECI_TIMING_ADDRESS_MASK GENMASK(7, 0)
++
++/* Command Register */
++#define ASPEED_PECI_CMD 0x08
++#define ASPEED_PECI_CMD_PIN_MON BIT(31)
++#define ASPEED_PECI_CMD_STS_MASK GENMASK(27, 24)
++#define ASPEED_PECI_CMD_IDLE_MASK (ASPEED_PECI_CMD_STS_MASK | \
++ ASPEED_PECI_CMD_PIN_MON)
++#define ASPEED_PECI_CMD_FIRE BIT(0)
++
++/* Read/Write Length Register */
++#define ASPEED_PECI_RW_LENGTH 0x0c
++#define ASPEED_PECI_AW_FCS_EN BIT(31)
++#define ASPEED_PECI_READ_LEN_MASK GENMASK(23, 16)
++#define ASPEED_PECI_WRITE_LEN_MASK GENMASK(15, 8)
++#define ASPEED_PECI_TAGET_ADDR_MASK GENMASK(7, 0)
++
++/* Expected FCS Data Register */
++#define ASPEED_PECI_EXP_FCS 0x10
++#define ASPEED_PECI_EXP_READ_FCS_MASK GENMASK(23, 16)
++#define ASPEED_PECI_EXP_AW_FCS_AUTO_MASK GENMASK(15, 8)
++#define ASPEED_PECI_EXP_WRITE_FCS_MASK GENMASK(7, 0)
++
++/* Captured FCS Data Register */
++#define ASPEED_PECI_CAP_FCS 0x14
++#define ASPEED_PECI_CAP_READ_FCS_MASK GENMASK(23, 16)
++#define ASPEED_PECI_CAP_WRITE_FCS_MASK GENMASK(7, 0)
++
++/* Interrupt Register */
++#define ASPEED_PECI_INT_CTRL 0x18
++#define ASPEED_PECI_TIMING_NEGO_SEL_MASK GENMASK(31, 30)
++#define ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO 0
++#define ASPEED_PECI_2ND_BIT_OF_ADDR_NEGO 1
++#define ASPEED_PECI_MESSAGE_NEGO 2
++#define ASPEED_PECI_INT_MASK GENMASK(4, 0)
++#define ASPEED_PECI_INT_BUS_TIMEOUT BIT(4)
++#define ASPEED_PECI_INT_BUS_CONNECT BIT(3)
++#define ASPEED_PECI_INT_W_FCS_BAD BIT(2)
++#define ASPEED_PECI_INT_W_FCS_ABORT BIT(1)
++#define ASPEED_PECI_INT_CMD_DONE BIT(0)
++
++/* Interrupt Status Register */
++#define ASPEED_PECI_INT_STS 0x1c
++#define ASPEED_PECI_INT_TIMING_RESULT_MASK GENMASK(29, 16)
++ /* bits[4..0]: Same bit fields in the 'Interrupt Register' */
++
++/* Rx/Tx Data Buffer Registers */
++#define ASPEED_PECI_W_DATA0 0x20
++#define ASPEED_PECI_W_DATA1 0x24
++#define ASPEED_PECI_W_DATA2 0x28
++#define ASPEED_PECI_W_DATA3 0x2c
++#define ASPEED_PECI_R_DATA0 0x30
++#define ASPEED_PECI_R_DATA1 0x34
++#define ASPEED_PECI_R_DATA2 0x38
++#define ASPEED_PECI_R_DATA3 0x3c
++#define ASPEED_PECI_W_DATA4 0x40
++#define ASPEED_PECI_W_DATA5 0x44
++#define ASPEED_PECI_W_DATA6 0x48
++#define ASPEED_PECI_W_DATA7 0x4c
++#define ASPEED_PECI_R_DATA4 0x50
++#define ASPEED_PECI_R_DATA5 0x54
++#define ASPEED_PECI_R_DATA6 0x58
++#define ASPEED_PECI_R_DATA7 0x5c
++#define ASPEED_PECI_DATA_BUF_SIZE_MAX 32
++
++/* Timing Negotiation */
++#define ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT 8
++#define ASPEED_PECI_RD_SAMPLING_POINT_MAX 15
++#define ASPEED_PECI_CLK_DIV_DEFAULT 0
++#define ASPEED_PECI_CLK_DIV_MAX 7
++#define ASPEED_PECI_MSG_TIMING_DEFAULT 1
++#define ASPEED_PECI_MSG_TIMING_MAX 255
++#define ASPEED_PECI_ADDR_TIMING_DEFAULT 1
++#define ASPEED_PECI_ADDR_TIMING_MAX 255
++
++/* Timeout */
++#define ASPEED_PECI_IDLE_CHECK_TIMEOUT_USEC 50000
++#define ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC 10000
++#define ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT 1000
++#define ASPEED_PECI_CMD_TIMEOUT_MS_MAX 60000
++
++struct aspeed_peci {
++ struct peci_adapter *adapter;
++ struct device *dev;
++ void __iomem *base;
++ struct clk *clk;
++ struct reset_control *rst;
++ int irq;
++ spinlock_t lock; /* to sync completion status handling */
++ struct completion xfer_complete;
++ u32 status;
++ u32 cmd_timeout_ms;
++};
++
++static int aspeed_peci_check_idle(struct aspeed_peci *priv)
++{
++ ulong timeout = jiffies + usecs_to_jiffies(ASPEED_PECI_IDLE_CHECK_TIMEOUT_USEC);
++ u32 cmd_sts;
++
++ for (;;) {
++ cmd_sts = readl(priv->base + ASPEED_PECI_CMD);
++ if (!(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK))
++ break;
++ if (time_after(jiffies, timeout)) {
++ cmd_sts = readl(priv->base + ASPEED_PECI_CMD);
++ break;
++ }
++ usleep_range((ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC >> 2) + 1,
++ ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC);
++ }
++
++ return !(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK) ? 0 : -ETIMEDOUT;
++}
++
++static int aspeed_peci_xfer(struct peci_adapter *adapter,
++ struct peci_xfer_msg *msg)
++{
++ struct aspeed_peci *priv = peci_get_adapdata(adapter);
++ long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms);
++ u32 peci_head, peci_state, rx_data = 0;
++ ulong flags;
++ int i, ret;
++ uint reg;
++
++ if (msg->tx_len > ASPEED_PECI_DATA_BUF_SIZE_MAX ||
++ msg->rx_len > ASPEED_PECI_DATA_BUF_SIZE_MAX)
++ return -EINVAL;
++
++ /* Check command sts and bus idle state */
++ ret = aspeed_peci_check_idle(priv);
++ if (ret)
++ return ret; /* -ETIMEDOUT */
++
++ spin_lock_irqsave(&priv->lock, flags);
++ reinit_completion(&priv->xfer_complete);
++
++ peci_head = FIELD_PREP(ASPEED_PECI_TAGET_ADDR_MASK, msg->addr) |
++ FIELD_PREP(ASPEED_PECI_WRITE_LEN_MASK, msg->tx_len) |
++ FIELD_PREP(ASPEED_PECI_READ_LEN_MASK, msg->rx_len);
++
++ writel(peci_head, priv->base + ASPEED_PECI_RW_LENGTH);
++
++ for (i = 0; i < msg->tx_len; i += 4) {
++ reg = i < 16 ? ASPEED_PECI_W_DATA0 + i % 16 :
++ ASPEED_PECI_W_DATA4 + i % 16;
++ writel(le32_to_cpup((__le32 *)&msg->tx_buf[i]),
++ priv->base + reg);
++ }
++
++ dev_dbg(priv->dev, "HEAD : 0x%08x\n", peci_head);
++ print_hex_dump_debug("TX : ", DUMP_PREFIX_NONE, 16, 1,
++ msg->tx_buf, msg->tx_len, true);
++
++ priv->status = 0;
++ writel(ASPEED_PECI_CMD_FIRE, priv->base + ASPEED_PECI_CMD);
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ err = wait_for_completion_interruptible_timeout(&priv->xfer_complete,
++ timeout);
++
++ spin_lock_irqsave(&priv->lock, flags);
++ dev_dbg(priv->dev, "INT_STS : 0x%08x\n", priv->status);
++ peci_state = readl(priv->base + ASPEED_PECI_CMD);
++ dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n",
++ FIELD_GET(ASPEED_PECI_CMD_STS_MASK, peci_state));
++
++ writel(0, priv->base + ASPEED_PECI_CMD);
++
++ if (err <= 0 || priv->status != ASPEED_PECI_INT_CMD_DONE) {
++ if (err < 0) { /* -ERESTARTSYS */
++ ret = (int)err;
++ goto err_irqrestore;
++ } else if (err == 0) {
++ dev_dbg(priv->dev, "Timeout waiting for a response!\n");
++ ret = -ETIMEDOUT;
++ goto err_irqrestore;
++ }
++
++ dev_dbg(priv->dev, "No valid response!\n");
++ ret = -EIO;
++ goto err_irqrestore;
++ }
++
++ /*
++ * Note that rx_len and rx_buf size can be an odd number.
++ * Byte handling is more efficient.
++ */
++ for (i = 0; i < msg->rx_len; i++) {
++ u8 byte_offset = i % 4;
++
++ if (byte_offset == 0) {
++ reg = i < 16 ? ASPEED_PECI_R_DATA0 + i % 16 :
++ ASPEED_PECI_R_DATA4 + i % 16;
++ rx_data = readl(priv->base + reg);
++ }
++
++ msg->rx_buf[i] = (u8)(rx_data >> (byte_offset << 3));
++ }
++
++ print_hex_dump_debug("RX : ", DUMP_PREFIX_NONE, 16, 1,
++ msg->rx_buf, msg->rx_len, true);
++
++ peci_state = readl(priv->base + ASPEED_PECI_CMD);
++ dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n",
++ FIELD_GET(ASPEED_PECI_CMD_STS_MASK, peci_state));
++ dev_dbg(priv->dev, "------------------------\n");
++
++err_irqrestore:
++ spin_unlock_irqrestore(&priv->lock, flags);
++ return ret;
++}
++
++static irqreturn_t aspeed_peci_irq_handler(int irq, void *arg)
++{
++ struct aspeed_peci *priv = arg;
++ u32 status;
++
++ spin_lock(&priv->lock);
++ status = readl(priv->base + ASPEED_PECI_INT_STS);
++ writel(status, priv->base + ASPEED_PECI_INT_STS);
++ priv->status |= (status & ASPEED_PECI_INT_MASK);
++
++ /*
++ * In most cases, interrupt bits will be set one by one but also note
++ * that multiple interrupt bits could be set at the same time.
++ */
++ if (status & ASPEED_PECI_INT_BUS_TIMEOUT) {
++ dev_dbg(priv->dev, "ASPEED_PECI_INT_BUS_TIMEOUT\n");
++ }
++
++ if (status & ASPEED_PECI_INT_BUS_CONNECT) {
++ dev_dbg(priv->dev, "ASPEED_PECI_INT_BUS_CONNECT\n");
++ }
++
++ if (status & ASPEED_PECI_INT_W_FCS_BAD) {
++ dev_dbg(priv->dev, "ASPEED_PECI_INT_W_FCS_BAD\n");
++ }
++
++ if (status & ASPEED_PECI_INT_W_FCS_ABORT) {
++ dev_dbg(priv->dev, "ASPEED_PECI_INT_W_FCS_ABORT\n");
++ }
++
++ /*
++ * All commands should be ended up with a ASPEED_PECI_INT_CMD_DONE bit
++ * set even in an error case.
++ */
++ if (status & ASPEED_PECI_INT_CMD_DONE) {
++ dev_dbg(priv->dev, "ASPEED_PECI_INT_CMD_DONE\n");
++ complete(&priv->xfer_complete);
++ }
++
++ spin_unlock(&priv->lock);
++ return IRQ_HANDLED;
++}
++
++static int aspeed_peci_init_ctrl(struct aspeed_peci *priv)
++{
++ u32 msg_timing, addr_timing, rd_sampling_point;
++ u32 clk_freq, clk_divisor, clk_div_val = 0;
++ int ret;
++
++ priv->clk = devm_clk_get(priv->dev, NULL);
++ if (IS_ERR(priv->clk)) {
++ dev_err(priv->dev, "Failed to get clk source.\n");
++ return PTR_ERR(priv->clk);
++ }
++
++ ret = clk_prepare_enable(priv->clk);
++ if (ret) {
++ dev_err(priv->dev, "Failed to enable clock.\n");
++ return ret;
++ }
++
++ ret = device_property_read_u32(priv->dev, "clock-frequency", &clk_freq);
++ if (ret) {
++ dev_err(priv->dev,
++ "Could not read clock-frequency property.\n");
++ clk_disable_unprepare(priv->clk);
++ return ret;
++ }
++
++ clk_divisor = clk_get_rate(priv->clk) / clk_freq;
++
++ while ((clk_divisor >> 1) && (clk_div_val < ASPEED_PECI_CLK_DIV_MAX))
++ clk_div_val++;
++
++ ret = device_property_read_u32(priv->dev, "msg-timing", &msg_timing);
++ if (ret || msg_timing > ASPEED_PECI_MSG_TIMING_MAX) {
++ if (!ret)
++ dev_warn(priv->dev,
++ "Invalid msg-timing : %u, Use default : %u\n",
++ msg_timing, ASPEED_PECI_MSG_TIMING_DEFAULT);
++ msg_timing = ASPEED_PECI_MSG_TIMING_DEFAULT;
++ }
++
++ ret = device_property_read_u32(priv->dev, "addr-timing", &addr_timing);
++ if (ret || addr_timing > ASPEED_PECI_ADDR_TIMING_MAX) {
++ if (!ret)
++ dev_warn(priv->dev,
++ "Invalid addr-timing : %u, Use default : %u\n",
++ addr_timing, ASPEED_PECI_ADDR_TIMING_DEFAULT);
++ addr_timing = ASPEED_PECI_ADDR_TIMING_DEFAULT;
++ }
++
++ ret = device_property_read_u32(priv->dev, "rd-sampling-point",
++ &rd_sampling_point);
++ if (ret || rd_sampling_point > ASPEED_PECI_RD_SAMPLING_POINT_MAX) {
++ if (!ret)
++ dev_warn(priv->dev,
++ "Invalid rd-sampling-point : %u. Use default : %u\n",
++ rd_sampling_point,
++ ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT);
++ rd_sampling_point = ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT;
++ }
++
++ ret = device_property_read_u32(priv->dev, "cmd-timeout-ms",
++ &priv->cmd_timeout_ms);
++ if (ret || priv->cmd_timeout_ms > ASPEED_PECI_CMD_TIMEOUT_MS_MAX ||
++ priv->cmd_timeout_ms == 0) {
++ if (!ret)
++ dev_warn(priv->dev,
++ "Invalid cmd-timeout-ms : %u. Use default : %u\n",
++ priv->cmd_timeout_ms,
++ ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT);
++ priv->cmd_timeout_ms = ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT;
++ }
++
++ writel(FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK,
++ ASPEED_PECI_CLK_DIV_DEFAULT) |
++ ASPEED_PECI_CTRL_PECI_CLK_EN, priv->base + ASPEED_PECI_CTRL);
++
++ /*
++ * Timing negotiation period setting.
++ * The unit of the programmed value is 4 times of PECI clock period.
++ */
++ writel(FIELD_PREP(ASPEED_PECI_TIMING_MESSAGE_MASK, msg_timing) |
++ FIELD_PREP(ASPEED_PECI_TIMING_ADDRESS_MASK, addr_timing),
++ priv->base + ASPEED_PECI_TIMING_NEGOTIATION);
++
++ /* Clear interrupts */
++ writel(readl(priv->base + ASPEED_PECI_INT_STS) | ASPEED_PECI_INT_MASK,
++ priv->base + ASPEED_PECI_INT_STS);
++
++ /* Set timing negotiation mode and enable interrupts */
++ writel(FIELD_PREP(ASPEED_PECI_TIMING_NEGO_SEL_MASK,
++ ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO) |
++ ASPEED_PECI_INT_MASK, priv->base + ASPEED_PECI_INT_CTRL);
++
++ /* Read sampling point and clock speed setting */
++ writel(FIELD_PREP(ASPEED_PECI_CTRL_SAMPLING_MASK, rd_sampling_point) |
++ FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, clk_div_val) |
++ ASPEED_PECI_CTRL_PECI_EN | ASPEED_PECI_CTRL_PECI_CLK_EN,
++ priv->base + ASPEED_PECI_CTRL);
++
++ return 0;
++}
++
++static int aspeed_peci_probe(struct platform_device *pdev)
++{
++ struct peci_adapter *adapter;
++ struct aspeed_peci *priv;
++ struct resource *res;
++ int ret;
++
++ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv));
++ if (!adapter)
++ return -ENOMEM;
++
++ priv = peci_get_adapdata(adapter);
++ priv->adapter = adapter;
++ priv->dev = &pdev->dev;
++ dev_set_drvdata(&pdev->dev, priv);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ priv->base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(priv->base)) {
++ ret = PTR_ERR(priv->base);
++ goto err_put_adapter_dev;
++ }
++
++ priv->irq = platform_get_irq(pdev, 0);
++ if (!priv->irq) {
++ ret = -ENODEV;
++ goto err_put_adapter_dev;
++ }
++
++ ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler,
++ 0, "peci-aspeed-irq", priv);
++ if (ret)
++ goto err_put_adapter_dev;
++
++ init_completion(&priv->xfer_complete);
++ spin_lock_init(&priv->lock);
++
++ priv->adapter->owner = THIS_MODULE;
++ priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev));
++ strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name));
++ priv->adapter->xfer = aspeed_peci_xfer;
++ priv->adapter->use_dma = false;
++
++ priv->rst = devm_reset_control_get(&pdev->dev, NULL);
++ if (IS_ERR(priv->rst)) {
++ dev_err(&pdev->dev,
++ "missing or invalid reset controller entry");
++ ret = PTR_ERR(priv->rst);
++ goto err_put_adapter_dev;
++ }
++ reset_control_deassert(priv->rst);
++
++ ret = aspeed_peci_init_ctrl(priv);
++ if (ret)
++ goto err_put_adapter_dev;
++
++ ret = peci_add_adapter(priv->adapter);
++ if (ret)
++ goto err_put_adapter_dev;
++
++ dev_info(&pdev->dev, "peci bus %d registered, irq %d\n",
++ priv->adapter->nr, priv->irq);
++
++ return 0;
++
++err_put_adapter_dev:
++ put_device(&adapter->dev);
++ return ret;
++}
++
++static int aspeed_peci_remove(struct platform_device *pdev)
++{
++ struct aspeed_peci *priv = dev_get_drvdata(&pdev->dev);
++
++ clk_disable_unprepare(priv->clk);
++ reset_control_assert(priv->rst);
++ peci_del_adapter(priv->adapter);
++ of_node_put(priv->adapter->dev.of_node);
++
++ return 0;
++}
++
++static const struct of_device_id aspeed_peci_of_table[] = {
++ { .compatible = "aspeed,ast2400-peci", },
++ { .compatible = "aspeed,ast2500-peci", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, aspeed_peci_of_table);
++
++static struct platform_driver aspeed_peci_driver = {
++ .probe = aspeed_peci_probe,
++ .remove = aspeed_peci_remove,
++ .driver = {
++ .name = "peci-aspeed",
++ .of_match_table = of_match_ptr(aspeed_peci_of_table),
++ },
++};
++module_platform_driver(aspeed_peci_driver);
++
++MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
++MODULE_DESCRIPTION("ASPEED PECI driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/peci/peci-aspeed.c b/drivers/peci/peci-aspeed.c
+deleted file mode 100644
+index 51cb2563ceb6..000000000000
+--- a/drivers/peci/peci-aspeed.c
++++ /dev/null
+@@ -1,505 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-// Copyright (C) 2012-2017 ASPEED Technology Inc.
+-// Copyright (c) 2018 Intel Corporation
+-
+-#include <linux/bitfield.h>
+-#include <linux/clk.h>
+-#include <linux/interrupt.h>
+-#include <linux/jiffies.h>
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/peci.h>
+-#include <linux/platform_device.h>
+-#include <linux/regmap.h>
+-#include <linux/reset.h>
+-
+-/* ASPEED PECI Registers */
+-#define ASPEED_PECI_CTRL 0x00
+-#define ASPEED_PECI_TIMING 0x04
+-#define ASPEED_PECI_CMD 0x08
+-#define ASPEED_PECI_CMD_CTRL 0x0c
+-#define ASPEED_PECI_EXP_FCS 0x10
+-#define ASPEED_PECI_CAP_FCS 0x14
+-#define ASPEED_PECI_INT_CTRL 0x18
+-#define ASPEED_PECI_INT_STS 0x1c
+-#define ASPEED_PECI_W_DATA0 0x20
+-#define ASPEED_PECI_W_DATA1 0x24
+-#define ASPEED_PECI_W_DATA2 0x28
+-#define ASPEED_PECI_W_DATA3 0x2c
+-#define ASPEED_PECI_R_DATA0 0x30
+-#define ASPEED_PECI_R_DATA1 0x34
+-#define ASPEED_PECI_R_DATA2 0x38
+-#define ASPEED_PECI_R_DATA3 0x3c
+-#define ASPEED_PECI_W_DATA4 0x40
+-#define ASPEED_PECI_W_DATA5 0x44
+-#define ASPEED_PECI_W_DATA6 0x48
+-#define ASPEED_PECI_W_DATA7 0x4c
+-#define ASPEED_PECI_R_DATA4 0x50
+-#define ASPEED_PECI_R_DATA5 0x54
+-#define ASPEED_PECI_R_DATA6 0x58
+-#define ASPEED_PECI_R_DATA7 0x5c
+-
+-/* ASPEED_PECI_CTRL - 0x00 : Control Register */
+-#define PECI_CTRL_SAMPLING_MASK GENMASK(19, 16)
+-#define PECI_CTRL_READ_MODE_MASK GENMASK(13, 12)
+-#define PECI_CTRL_READ_MODE_COUNT BIT(12)
+-#define PECI_CTRL_READ_MODE_DBG BIT(13)
+-#define PECI_CTRL_CLK_SOURCE_MASK BIT(11)
+-#define PECI_CTRL_CLK_DIV_MASK GENMASK(10, 8)
+-#define PECI_CTRL_INVERT_OUT BIT(7)
+-#define PECI_CTRL_INVERT_IN BIT(6)
+-#define PECI_CTRL_BUS_CONTENT_EN BIT(5)
+-#define PECI_CTRL_PECI_EN BIT(4)
+-#define PECI_CTRL_PECI_CLK_EN BIT(0)
+-
+-/* ASPEED_PECI_TIMING - 0x04 : Timing Negotiation Register */
+-#define PECI_TIMING_MESSAGE_MASK GENMASK(15, 8)
+-#define PECI_TIMING_ADDRESS_MASK GENMASK(7, 0)
+-
+-/* ASPEED_PECI_CMD - 0x08 : Command Register */
+-#define PECI_CMD_PIN_MON BIT(31)
+-#define PECI_CMD_STS_MASK GENMASK(27, 24)
+-#define PECI_CMD_IDLE_MASK (PECI_CMD_STS_MASK | PECI_CMD_PIN_MON)
+-#define PECI_CMD_FIRE BIT(0)
+-
+-/* ASPEED_PECI_LEN - 0x0C : Read/Write Length Register */
+-#define PECI_AW_FCS_EN BIT(31)
+-#define PECI_READ_LEN_MASK GENMASK(23, 16)
+-#define PECI_WRITE_LEN_MASK GENMASK(15, 8)
+-#define PECI_TAGET_ADDR_MASK GENMASK(7, 0)
+-
+-/* ASPEED_PECI_EXP_FCS - 0x10 : Expected FCS Data Register */
+-#define PECI_EXPECT_READ_FCS_MASK GENMASK(23, 16)
+-#define PECI_EXPECT_AW_FCS_AUTO_MASK GENMASK(15, 8)
+-#define PECI_EXPECT_WRITE_FCS_MASK GENMASK(7, 0)
+-
+-/* ASPEED_PECI_CAP_FCS - 0x14 : Captured FCS Data Register */
+-#define PECI_CAPTURE_READ_FCS_MASK GENMASK(23, 16)
+-#define PECI_CAPTURE_WRITE_FCS_MASK GENMASK(7, 0)
+-
+-/* ASPEED_PECI_INT_CTRL/STS - 0x18/0x1c : Interrupt Register */
+-#define PECI_INT_TIMING_RESULT_MASK GENMASK(31, 30)
+-#define PECI_INT_TIMEOUT BIT(4)
+-#define PECI_INT_CONNECT BIT(3)
+-#define PECI_INT_W_FCS_BAD BIT(2)
+-#define PECI_INT_W_FCS_ABORT BIT(1)
+-#define PECI_INT_CMD_DONE BIT(0)
+-
+-#define PECI_INT_MASK (PECI_INT_TIMEOUT | PECI_INT_CONNECT | \
+- PECI_INT_W_FCS_BAD | PECI_INT_W_FCS_ABORT | \
+- PECI_INT_CMD_DONE)
+-
+-#define PECI_IDLE_CHECK_TIMEOUT_USEC 50000
+-#define PECI_IDLE_CHECK_INTERVAL_USEC 10000
+-
+-#define PECI_RD_SAMPLING_POINT_DEFAULT 8
+-#define PECI_RD_SAMPLING_POINT_MAX 15
+-#define PECI_CLK_DIV_DEFAULT 0
+-#define PECI_CLK_DIV_MAX 7
+-#define PECI_MSG_TIMING_DEFAULT 1
+-#define PECI_MSG_TIMING_MAX 255
+-#define PECI_ADDR_TIMING_DEFAULT 1
+-#define PECI_ADDR_TIMING_MAX 255
+-#define PECI_CMD_TIMEOUT_MS_DEFAULT 1000
+-#define PECI_CMD_TIMEOUT_MS_MAX 60000
+-
+-struct aspeed_peci {
+- struct peci_adapter *adapter;
+- struct device *dev;
+- struct regmap *regmap;
+- struct clk *clk;
+- struct reset_control *rst;
+- int irq;
+- spinlock_t lock; /* to sync completion status handling */
+- struct completion xfer_complete;
+- u32 status;
+- u32 cmd_timeout_ms;
+-};
+-
+-static int aspeed_peci_xfer_native(struct aspeed_peci *priv,
+- struct peci_xfer_msg *msg)
+-{
+- long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms);
+- u32 peci_head, peci_state, rx_data, cmd_sts;
+- unsigned long flags;
+- int i, rc;
+- uint reg;
+-
+- /* Check command sts and bus idle state */
+- rc = regmap_read_poll_timeout(priv->regmap, ASPEED_PECI_CMD, cmd_sts,
+- !(cmd_sts & PECI_CMD_IDLE_MASK),
+- PECI_IDLE_CHECK_INTERVAL_USEC,
+- PECI_IDLE_CHECK_TIMEOUT_USEC);
+- if (rc)
+- return rc; /* -ETIMEDOUT */
+-
+- spin_lock_irqsave(&priv->lock, flags);
+- reinit_completion(&priv->xfer_complete);
+-
+- peci_head = FIELD_PREP(PECI_TAGET_ADDR_MASK, msg->addr) |
+- FIELD_PREP(PECI_WRITE_LEN_MASK, msg->tx_len) |
+- FIELD_PREP(PECI_READ_LEN_MASK, msg->rx_len);
+-
+- regmap_write(priv->regmap, ASPEED_PECI_CMD_CTRL, peci_head);
+-
+- for (i = 0; i < msg->tx_len; i += 4) {
+- reg = i < 16 ? ASPEED_PECI_W_DATA0 + i % 16 :
+- ASPEED_PECI_W_DATA4 + i % 16;
+- regmap_write(priv->regmap, reg,
+- le32_to_cpup((__le32 *)&msg->tx_buf[i]));
+- }
+-
+- dev_dbg(priv->dev, "HEAD : 0x%08x\n", peci_head);
+- print_hex_dump_debug("TX : ", DUMP_PREFIX_NONE, 16, 1,
+- msg->tx_buf, msg->tx_len, true);
+-
+- priv->status = 0;
+- regmap_write(priv->regmap, ASPEED_PECI_CMD, PECI_CMD_FIRE);
+- spin_unlock_irqrestore(&priv->lock, flags);
+-
+- err = wait_for_completion_interruptible_timeout(&priv->xfer_complete,
+- timeout);
+-
+- spin_lock_irqsave(&priv->lock, flags);
+- dev_dbg(priv->dev, "INT_STS : 0x%08x\n", priv->status);
+- regmap_read(priv->regmap, ASPEED_PECI_CMD, &peci_state);
+- dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n",
+- FIELD_GET(PECI_CMD_STS_MASK, peci_state));
+-
+- regmap_write(priv->regmap, ASPEED_PECI_CMD, 0);
+-
+- if (err <= 0 || priv->status != PECI_INT_CMD_DONE) {
+- if (err < 0) { /* -ERESTARTSYS */
+- rc = (int)err;
+- goto err_irqrestore;
+- } else if (err == 0) {
+- dev_dbg(priv->dev, "Timeout waiting for a response!\n");
+- rc = -ETIMEDOUT;
+- goto err_irqrestore;
+- }
+-
+- dev_dbg(priv->dev, "No valid response!\n");
+- rc = -EIO;
+- goto err_irqrestore;
+- }
+-
+- /**
+- * Note that rx_len and rx_buf size can be an odd number.
+- * Byte handling is more efficient.
+- */
+- for (i = 0; i < msg->rx_len; i++) {
+- u8 byte_offset = i % 4;
+-
+- if (byte_offset == 0) {
+- reg = i < 16 ? ASPEED_PECI_R_DATA0 + i % 16 :
+- ASPEED_PECI_R_DATA4 + i % 16;
+- regmap_read(priv->regmap, reg, &rx_data);
+- }
+-
+- msg->rx_buf[i] = (u8)(rx_data >> (byte_offset << 3));
+- }
+-
+- print_hex_dump_debug("RX : ", DUMP_PREFIX_NONE, 16, 1,
+- msg->rx_buf, msg->rx_len, true);
+-
+- regmap_read(priv->regmap, ASPEED_PECI_CMD, &peci_state);
+- dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n",
+- FIELD_GET(PECI_CMD_STS_MASK, peci_state));
+- dev_dbg(priv->dev, "------------------------\n");
+-
+-err_irqrestore:
+- spin_unlock_irqrestore(&priv->lock, flags);
+- return rc;
+-}
+-
+-static irqreturn_t aspeed_peci_irq_handler(int irq, void *arg)
+-{
+- struct aspeed_peci *priv = arg;
+- u32 status_ack = 0;
+- u32 status;
+-
+- spin_lock(&priv->lock);
+- regmap_read(priv->regmap, ASPEED_PECI_INT_STS, &status);
+- priv->status |= (status & PECI_INT_MASK);
+-
+- /**
+- * In most cases, interrupt bits will be set one by one but also note
+- * that multiple interrupt bits could be set at the same time.
+- */
+- if (status & PECI_INT_TIMEOUT) {
+- dev_dbg(priv->dev, "PECI_INT_TIMEOUT\n");
+- status_ack |= PECI_INT_TIMEOUT;
+- }
+-
+- if (status & PECI_INT_CONNECT) {
+- dev_dbg(priv->dev, "PECI_INT_CONNECT\n");
+- status_ack |= PECI_INT_CONNECT;
+- }
+-
+- if (status & PECI_INT_W_FCS_BAD) {
+- dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n");
+- status_ack |= PECI_INT_W_FCS_BAD;
+- }
+-
+- if (status & PECI_INT_W_FCS_ABORT) {
+- dev_dbg(priv->dev, "PECI_INT_W_FCS_ABORT\n");
+- status_ack |= PECI_INT_W_FCS_ABORT;
+- }
+-
+- /**
+- * All commands should be ended up with a PECI_INT_CMD_DONE bit set
+- * even in an error case.
+- */
+- if (status & PECI_INT_CMD_DONE) {
+- dev_dbg(priv->dev, "PECI_INT_CMD_DONE\n");
+- status_ack |= PECI_INT_CMD_DONE;
+- complete(&priv->xfer_complete);
+- }
+-
+- regmap_write(priv->regmap, ASPEED_PECI_INT_STS, status_ack);
+- spin_unlock(&priv->lock);
+- return IRQ_HANDLED;
+-}
+-
+-static int aspeed_peci_init_ctrl(struct aspeed_peci *priv)
+-{
+- u32 msg_timing, addr_timing, rd_sampling_point;
+- u32 clk_freq, clk_divisor, clk_div_val = 0;
+- int ret;
+-
+- priv->clk = devm_clk_get(priv->dev, NULL);
+- if (IS_ERR(priv->clk)) {
+- dev_err(priv->dev, "Failed to get clk source.\n");
+- return PTR_ERR(priv->clk);
+- }
+-
+- ret = clk_prepare_enable(priv->clk);
+- if (ret) {
+- dev_err(priv->dev, "Failed to enable clock.\n");
+- return ret;
+- }
+-
+- ret = of_property_read_u32(priv->dev->of_node, "clock-frequency",
+- &clk_freq);
+- if (ret) {
+- dev_err(priv->dev,
+- "Could not read clock-frequency property.\n");
+- clk_disable_unprepare(priv->clk);
+- return ret;
+- }
+-
+- clk_divisor = clk_get_rate(priv->clk) / clk_freq;
+-
+- while ((clk_divisor >> 1) && (clk_div_val < PECI_CLK_DIV_MAX))
+- clk_div_val++;
+-
+- ret = of_property_read_u32(priv->dev->of_node, "msg-timing",
+- &msg_timing);
+- if (ret || msg_timing > PECI_MSG_TIMING_MAX) {
+- if (!ret)
+- dev_warn(priv->dev,
+- "Invalid msg-timing : %u, Use default : %u\n",
+- msg_timing, PECI_MSG_TIMING_DEFAULT);
+- msg_timing = PECI_MSG_TIMING_DEFAULT;
+- }
+-
+- ret = of_property_read_u32(priv->dev->of_node, "addr-timing",
+- &addr_timing);
+- if (ret || addr_timing > PECI_ADDR_TIMING_MAX) {
+- if (!ret)
+- dev_warn(priv->dev,
+- "Invalid addr-timing : %u, Use default : %u\n",
+- addr_timing, PECI_ADDR_TIMING_DEFAULT);
+- addr_timing = PECI_ADDR_TIMING_DEFAULT;
+- }
+-
+- ret = of_property_read_u32(priv->dev->of_node, "rd-sampling-point",
+- &rd_sampling_point);
+- if (ret || rd_sampling_point > PECI_RD_SAMPLING_POINT_MAX) {
+- if (!ret)
+- dev_warn(priv->dev,
+- "Invalid rd-sampling-point : %u. Use default : %u\n",
+- rd_sampling_point,
+- PECI_RD_SAMPLING_POINT_DEFAULT);
+- rd_sampling_point = PECI_RD_SAMPLING_POINT_DEFAULT;
+- }
+-
+- ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms",
+- &priv->cmd_timeout_ms);
+- if (ret || priv->cmd_timeout_ms > PECI_CMD_TIMEOUT_MS_MAX ||
+- priv->cmd_timeout_ms == 0) {
+- if (!ret)
+- dev_warn(priv->dev,
+- "Invalid cmd-timeout-ms : %u. Use default : %u\n",
+- priv->cmd_timeout_ms,
+- PECI_CMD_TIMEOUT_MS_DEFAULT);
+- priv->cmd_timeout_ms = PECI_CMD_TIMEOUT_MS_DEFAULT;
+- }
+-
+- regmap_write(priv->regmap, ASPEED_PECI_CTRL,
+- FIELD_PREP(PECI_CTRL_CLK_DIV_MASK, PECI_CLK_DIV_DEFAULT) |
+- PECI_CTRL_PECI_CLK_EN);
+-
+- /**
+- * Timing negotiation period setting.
+- * The unit of the programmed value is 4 times of PECI clock period.
+- */
+- regmap_write(priv->regmap, ASPEED_PECI_TIMING,
+- FIELD_PREP(PECI_TIMING_MESSAGE_MASK, msg_timing) |
+- FIELD_PREP(PECI_TIMING_ADDRESS_MASK, addr_timing));
+-
+- /* Clear interrupts */
+- regmap_write(priv->regmap, ASPEED_PECI_INT_STS, PECI_INT_MASK);
+-
+- /* Enable interrupts */
+- regmap_write(priv->regmap, ASPEED_PECI_INT_CTRL, PECI_INT_MASK);
+-
+- /* Read sampling point and clock speed setting */
+- regmap_write(priv->regmap, ASPEED_PECI_CTRL,
+- FIELD_PREP(PECI_CTRL_SAMPLING_MASK, rd_sampling_point) |
+- FIELD_PREP(PECI_CTRL_CLK_DIV_MASK, clk_div_val) |
+- PECI_CTRL_PECI_EN | PECI_CTRL_PECI_CLK_EN);
+-
+- return 0;
+-}
+-
+-static const struct regmap_config aspeed_peci_regmap_config = {
+- .reg_bits = 32,
+- .val_bits = 32,
+- .reg_stride = 4,
+- .max_register = ASPEED_PECI_R_DATA7,
+- .val_format_endian = REGMAP_ENDIAN_LITTLE,
+- .fast_io = true,
+-};
+-
+-static int aspeed_peci_xfer(struct peci_adapter *adapter,
+- struct peci_xfer_msg *msg)
+-{
+- struct aspeed_peci *priv = peci_get_adapdata(adapter);
+-
+- return aspeed_peci_xfer_native(priv, msg);
+-}
+-
+-static int aspeed_peci_probe(struct platform_device *pdev)
+-{
+- struct peci_adapter *adapter;
+- struct aspeed_peci *priv;
+- struct resource *res;
+- void __iomem *base;
+- u32 cmd_sts;
+- int ret;
+-
+- adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv));
+- if (!adapter)
+- return -ENOMEM;
+-
+- priv = peci_get_adapdata(adapter);
+- priv->adapter = adapter;
+- priv->dev = &pdev->dev;
+- dev_set_drvdata(&pdev->dev, priv);
+-
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- base = devm_ioremap_resource(&pdev->dev, res);
+- if (IS_ERR(base)) {
+- ret = PTR_ERR(base);
+- goto err_put_adapter_dev;
+- }
+-
+- priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+- &aspeed_peci_regmap_config);
+- if (IS_ERR(priv->regmap)) {
+- ret = PTR_ERR(priv->regmap);
+- goto err_put_adapter_dev;
+- }
+-
+- /**
+- * We check that the regmap works on this very first access,
+- * but as this is an MMIO-backed regmap, subsequent regmap
+- * access is not going to fail and we skip error checks from
+- * this point.
+- */
+- ret = regmap_read(priv->regmap, ASPEED_PECI_CMD, &cmd_sts);
+- if (ret) {
+- ret = -EIO;
+- goto err_put_adapter_dev;
+- }
+-
+- priv->irq = platform_get_irq(pdev, 0);
+- if (!priv->irq) {
+- ret = -ENODEV;
+- goto err_put_adapter_dev;
+- }
+-
+- ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler,
+- 0, "peci-aspeed-irq", priv);
+- if (ret)
+- goto err_put_adapter_dev;
+-
+- init_completion(&priv->xfer_complete);
+- spin_lock_init(&priv->lock);
+-
+- priv->adapter->owner = THIS_MODULE;
+- priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev));
+- strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name));
+- priv->adapter->xfer = aspeed_peci_xfer;
+-
+- priv->rst = devm_reset_control_get(&pdev->dev, NULL);
+- if (IS_ERR(priv->rst)) {
+- dev_err(&pdev->dev,
+- "missing or invalid reset controller entry");
+- ret = PTR_ERR(priv->rst);
+- goto err_put_adapter_dev;
+- }
+- reset_control_deassert(priv->rst);
+-
+- ret = aspeed_peci_init_ctrl(priv);
+- if (ret)
+- goto err_put_adapter_dev;
+-
+- ret = peci_add_adapter(priv->adapter);
+- if (ret)
+- goto err_put_adapter_dev;
+-
+- dev_info(&pdev->dev, "peci bus %d registered, irq %d\n",
+- priv->adapter->nr, priv->irq);
+-
+- return 0;
+-
+-err_put_adapter_dev:
+- put_device(&adapter->dev);
+- return ret;
+-}
+-
+-static int aspeed_peci_remove(struct platform_device *pdev)
+-{
+- struct aspeed_peci *priv = dev_get_drvdata(&pdev->dev);
+-
+- clk_disable_unprepare(priv->clk);
+- reset_control_assert(priv->rst);
+- peci_del_adapter(priv->adapter);
+- of_node_put(priv->adapter->dev.of_node);
+-
+- return 0;
+-}
+-
+-static const struct of_device_id aspeed_peci_of_table[] = {
+- { .compatible = "aspeed,ast2400-peci", },
+- { .compatible = "aspeed,ast2500-peci", },
+- { }
+-};
+-MODULE_DEVICE_TABLE(of, aspeed_peci_of_table);
+-
+-static struct platform_driver aspeed_peci_driver = {
+- .probe = aspeed_peci_probe,
+- .remove = aspeed_peci_remove,
+- .driver = {
+- .name = "peci-aspeed",
+- .of_match_table = of_match_ptr(aspeed_peci_of_table),
+- },
+-};
+-module_platform_driver(aspeed_peci_driver);
+-
+-MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
+-MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+-MODULE_DESCRIPTION("ASPEED PECI driver");
+-MODULE_LICENSE("GPL v2");
+diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c
+index fac8c72dcda8..e2ef013e5002 100644
+--- a/drivers/peci/peci-core.c
++++ b/drivers/peci/peci-core.c
+@@ -1,38 +1,31 @@
+ // SPDX-License-Identifier: GPL-2.0
+-// Copyright (c) 2018 Intel Corporation
++// Copyright (c) 2018-2019 Intel Corporation
+
+ #include <linux/bitfield.h>
+ #include <linux/crc8.h>
+ #include <linux/delay.h>
+-#include <linux/fs.h>
++#include <linux/mm.h>
+ #include <linux/module.h>
+ #include <linux/of_device.h>
+ #include <linux/peci.h>
+ #include <linux/pm_domain.h>
+ #include <linux/pm_runtime.h>
++#include <linux/sched/task_stack.h>
+ #include <linux/slab.h>
+-#include <linux/uaccess.h>
+
+ /* Mask for getting minor revision number from DIB */
+ #define REVISION_NUM_MASK GENMASK(15, 8)
+
+-/* CRC8 table for Assure Write Frame Check */
++/* CRC8 table for Assured Write Frame Check */
+ #define PECI_CRC8_POLYNOMIAL 0x07
+ DECLARE_CRC8_TABLE(peci_crc8_table);
+
+-static struct device_type peci_adapter_type;
+-static struct device_type peci_client_type;
+-
+-/* Max number of peci cdev */
+-#define PECI_CDEV_MAX 16
+-
+-static dev_t peci_devt;
+ static bool is_registered;
+
+ static DEFINE_MUTEX(core_lock);
+ static DEFINE_IDR(peci_adapter_idr);
+
+-static struct peci_adapter *peci_get_adapter(int nr)
++struct peci_adapter *peci_get_adapter(int nr)
+ {
+ struct peci_adapter *adapter;
+
+@@ -48,10 +41,12 @@ static struct peci_adapter *peci_get_adapter(int nr)
+
+ out_unlock:
+ mutex_unlock(&core_lock);
++
+ return adapter;
+ }
++EXPORT_SYMBOL_GPL(peci_get_adapter);
+
+-static void peci_put_adapter(struct peci_adapter *adapter)
++void peci_put_adapter(struct peci_adapter *adapter)
+ {
+ if (!adapter)
+ return;
+@@ -59,6 +54,7 @@ static void peci_put_adapter(struct peci_adapter *adapter)
+ put_device(&adapter->dev);
+ module_put(adapter->owner);
+ }
++EXPORT_SYMBOL_GPL(peci_put_adapter);
+
+ static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr,
+@@ -84,10 +80,11 @@ static struct attribute *peci_device_attrs[] = {
+ };
+ ATTRIBUTE_GROUPS(peci_device);
+
+-static struct device_type peci_client_type = {
++struct device_type peci_client_type = {
+ .groups = peci_device_groups,
+ .release = peci_client_dev_release,
+ };
++EXPORT_SYMBOL_GPL(peci_client_type);
+
+ /**
+ * peci_verify_client - return parameter as peci_client, or NULL
+@@ -103,19 +100,120 @@ struct peci_client *peci_verify_client(struct device *dev)
+ }
+ EXPORT_SYMBOL_GPL(peci_verify_client);
+
+-static u8 peci_aw_fcs(u8 *data, int len)
++/**
++ * peci_get_xfer_msg() - get a DMA safe peci_xfer_msg for the given tx and rx
++ * length
++ * @tx_len: the length of tx_buf. May be 0 if tx_buf isn't needed.
++ * @rx_len: the length of rx_buf. May be 0 if rx_buf isn't needed.
++ *
++ * Return: NULL if a DMA safe buffer was not obtained.
++ * Or a valid pointer to be used with DMA. After use, release it by
++ * calling peci_put_xfer_msg().
++ *
++ * This function must only be called from process context!
++ */
++struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len)
++{
++ struct peci_xfer_msg *msg;
++ u8 *tx_buf, *rx_buf;
++
++ if (tx_len) {
++ tx_buf = kzalloc(tx_len, GFP_KERNEL);
++ if (!tx_buf)
++ return NULL;
++ } else {
++ tx_buf = NULL;
++ }
++
++ if (rx_len) {
++ rx_buf = kzalloc(rx_len, GFP_KERNEL);
++ if (!rx_buf)
++ goto err_free_tx_buf;
++ } else {
++ rx_buf = NULL;
++ }
++
++ msg = kzalloc(sizeof(struct peci_xfer_msg), GFP_KERNEL);
++ if (!msg)
++ goto err_free_tx_rx_buf;
++
++ msg->tx_len = tx_len;
++ msg->tx_buf = tx_buf;
++ msg->rx_len = rx_len;
++ msg->rx_buf = rx_buf;
++
++ return msg;
++
++err_free_tx_rx_buf:
++ kfree(rx_buf);
++err_free_tx_buf:
++ kfree(tx_buf);
++
++ return NULL;
++}
++EXPORT_SYMBOL_GPL(peci_get_xfer_msg);
++
++/**
++ * peci_put_xfer_msg - release a DMA safe peci_xfer_msg
++ * @msg: the message obtained from peci_get_xfer_msg(). May be NULL.
++ */
++void peci_put_xfer_msg(struct peci_xfer_msg *msg)
++{
++ if (!msg)
++ return;
++
++ kfree(msg->rx_buf);
++ kfree(msg->tx_buf);
++ kfree(msg);
++}
++EXPORT_SYMBOL_GPL(peci_put_xfer_msg);
++
++/* Calculate an Assured Write Frame Check Sequence byte */
++static int peci_aw_fcs(struct peci_xfer_msg *msg, int len, u8 *aw_fcs)
+ {
+- return crc8(peci_crc8_table, data, (size_t)len, 0);
++ u8 *tmp_buf;
++
++ /* Allocate a temporary buffer to use a contiguous byte array */
++ tmp_buf = kmalloc(len, GFP_KERNEL);
++ if (!tmp_buf)
++ return -ENOMEM;
++
++ tmp_buf[0] = msg->addr;
++ tmp_buf[1] = msg->tx_len;
++ tmp_buf[2] = msg->rx_len;
++ memcpy(&tmp_buf[3], msg->tx_buf, len - 3);
++
++ *aw_fcs = crc8(peci_crc8_table, tmp_buf, (size_t)len, 0);
++
++ kfree(tmp_buf);
++
++ return 0;
+ }
+
+ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg,
+ bool do_retry, bool has_aw_fcs)
+ {
+- ktime_t start, end;
+- s64 elapsed_ms;
+- int rc = 0;
++ ulong timeout = jiffies;
++ u8 aw_fcs;
++ int ret;
+
+- /**
++ /*
++ * In case if adapter uses DMA, check at here whether tx and rx buffers
++ * are DMA capable or not.
++ */
++ if (IS_ENABLED(CONFIG_HAS_DMA) && adapter->use_dma) {
++ if (is_vmalloc_addr(msg->tx_buf) ||
++ is_vmalloc_addr(msg->rx_buf)) {
++ WARN_ONCE(1, "xfer msg is not dma capable\n");
++ return -EAGAIN;
++ } else if (object_is_on_stack(msg->tx_buf) ||
++ object_is_on_stack(msg->rx_buf)) {
++ WARN_ONCE(1, "xfer msg is on stack\n");
++ return -EAGAIN;
++ }
++ }
++
++ /*
+ * For some commands, the PECI originator may need to retry a command if
+ * the processor PECI client responds with a 0x8x completion code. In
+ * each instance, the processor PECI client may have started the
+@@ -125,55 +223,56 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg,
+ */
+
+ if (do_retry)
+- start = ktime_get();
++ timeout += msecs_to_jiffies(PECI_DEV_RETRY_TIME_MS);
+
+- do {
+- rc = adapter->xfer(adapter, msg);
++ for (;;) {
++ ret = adapter->xfer(adapter, msg);
+
+- if (!do_retry || rc)
++ if (!do_retry || ret)
+ break;
+
+- if (msg->rx_buf[0] == DEV_PECI_CC_SUCCESS)
++ if (msg->rx_buf[0] == PECI_DEV_CC_SUCCESS)
+ break;
+
+ /* Retry is needed when completion code is 0x8x */
+- if ((msg->rx_buf[0] & DEV_PECI_CC_RETRY_CHECK_MASK) !=
+- DEV_PECI_CC_NEED_RETRY) {
+- rc = -EIO;
++ if ((msg->rx_buf[0] & PECI_DEV_CC_RETRY_CHECK_MASK) !=
++ PECI_DEV_CC_NEED_RETRY) {
++ ret = -EIO;
+ break;
+ }
+
+ /* Set the retry bit to indicate a retry attempt */
+- msg->tx_buf[1] |= DEV_PECI_RETRY_BIT;
++ msg->tx_buf[1] |= PECI_DEV_RETRY_BIT;
+
+ /* Recalculate the AW FCS if it has one */
+- if (has_aw_fcs)
+- msg->tx_buf[msg->tx_len - 1] = 0x80 ^
+- peci_aw_fcs((u8 *)msg,
+- 2 + msg->tx_len);
++ if (has_aw_fcs) {
++ ret = peci_aw_fcs(msg, 2 + msg->tx_len, &aw_fcs);
++ if (ret)
++ break;
+
+- /**
++ msg->tx_buf[msg->tx_len - 1] = 0x80 ^ aw_fcs;
++ }
++
++ /*
+ * Retry for at least 250ms before returning an error.
+ * Retry interval guideline:
+ * No minimum < Retry Interval < No maximum
+ * (recommend 10ms)
+ */
+- end = ktime_get();
+- elapsed_ms = ktime_to_ms(ktime_sub(end, start));
+- if (elapsed_ms >= DEV_PECI_RETRY_TIME_MS) {
++ if (time_after(jiffies, timeout)) {
+ dev_dbg(&adapter->dev, "Timeout retrying xfer!\n");
+- rc = -ETIMEDOUT;
++ ret = -ETIMEDOUT;
+ break;
+ }
+
+- usleep_range((DEV_PECI_RETRY_INTERVAL_USEC >> 2) + 1,
+- DEV_PECI_RETRY_INTERVAL_USEC);
+- } while (true);
++ usleep_range((PECI_DEV_RETRY_INTERVAL_USEC >> 2) + 1,
++ PECI_DEV_RETRY_INTERVAL_USEC);
++ }
+
+- if (rc)
+- dev_dbg(&adapter->dev, "xfer error, rc: %d\n", rc);
++ if (ret)
++ dev_dbg(&adapter->dev, "xfer error: %d\n", ret);
+
+- return rc;
++ return ret;
+ }
+
+ static int peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg)
+@@ -190,34 +289,37 @@ static int peci_xfer_with_retries(struct peci_adapter *adapter,
+
+ static int peci_scan_cmd_mask(struct peci_adapter *adapter)
+ {
+- struct peci_xfer_msg msg;
++ struct peci_xfer_msg *msg;
+ u8 revision;
+- int rc = 0;
++ int ret;
+ u64 dib;
+
+ /* Update command mask just once */
+ if (adapter->cmd_mask & BIT(PECI_CMD_XFER))
+ return 0;
+
+- msg.addr = PECI_BASE_ADDR;
+- msg.tx_len = GET_DIB_WR_LEN;
+- msg.rx_len = GET_DIB_RD_LEN;
+- msg.tx_buf[0] = GET_DIB_PECI_CMD;
++ msg = peci_get_xfer_msg(PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN);
++ if (!msg)
++ return -ENOMEM;
++
++ msg->addr = PECI_BASE_ADDR;
++ msg->tx_buf[0] = PECI_GET_DIB_CMD;
+
+- rc = peci_xfer(adapter, &msg);
+- if (rc)
+- return rc;
++ ret = peci_xfer(adapter, msg);
++ if (ret)
++ return ret;
+
+- dib = le64_to_cpup((__le64 *)msg.rx_buf);
++ dib = le64_to_cpup((__le64 *)msg->rx_buf);
+
+ /* Check special case for Get DIB command */
+ if (dib == 0) {
+ dev_dbg(&adapter->dev, "DIB read as 0\n");
+- return -EIO;
++ ret = -EIO;
++ goto out;
+ }
+
+ /**
+- * Setting up the supporting commands based on minor revision number.
++ * Setting up the supporting commands based on revision number.
+ * See PECI Spec Table 3-1.
+ */
+ revision = FIELD_GET(REVISION_NUM_MASK, dib);
+@@ -243,10 +345,14 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter)
+ adapter->cmd_mask |= BIT(PECI_CMD_GET_DIB);
+ adapter->cmd_mask |= BIT(PECI_CMD_PING);
+
+- return rc;
++out:
++ peci_put_xfer_msg(msg);
++
++ return ret;
+ }
+
+-static int peci_cmd_support(struct peci_adapter *adapter, enum peci_cmd cmd)
++static int peci_check_cmd_support(struct peci_adapter *adapter,
++ enum peci_cmd cmd)
+ {
+ if (!(adapter->cmd_mask & BIT(PECI_CMD_PING)) &&
+ peci_scan_cmd_mask(adapter) < 0) {
+@@ -262,70 +368,87 @@ static int peci_cmd_support(struct peci_adapter *adapter, enum peci_cmd cmd)
+ return 0;
+ }
+
+-static int peci_ioctl_xfer(struct peci_adapter *adapter, void *vmsg)
++static int peci_cmd_xfer(struct peci_adapter *adapter, void *vmsg)
+ {
+ struct peci_xfer_msg *msg = vmsg;
+
+ return peci_xfer(adapter, msg);
+ }
+
+-static int peci_ioctl_ping(struct peci_adapter *adapter, void *vmsg)
++static int peci_cmd_ping(struct peci_adapter *adapter, void *vmsg)
+ {
+ struct peci_ping_msg *umsg = vmsg;
+- struct peci_xfer_msg msg;
++ struct peci_xfer_msg *msg;
++ int ret;
+
+- msg.addr = umsg->addr;
+- msg.tx_len = 0;
+- msg.rx_len = 0;
++ msg = peci_get_xfer_msg(0, 0);
++ if (!msg)
++ return -ENOMEM;
+
+- return peci_xfer(adapter, &msg);
++ msg->addr = umsg->addr;
++
++ ret = peci_xfer(adapter, msg);
++
++ peci_put_xfer_msg(msg);
++
++ return ret;
+ }
+
+-static int peci_ioctl_get_dib(struct peci_adapter *adapter, void *vmsg)
++static int peci_cmd_get_dib(struct peci_adapter *adapter, void *vmsg)
+ {
+ struct peci_get_dib_msg *umsg = vmsg;
+- struct peci_xfer_msg msg;
+- int rc;
++ struct peci_xfer_msg *msg;
++ int ret;
+
+- msg.addr = umsg->addr;
+- msg.tx_len = GET_DIB_WR_LEN;
+- msg.rx_len = GET_DIB_RD_LEN;
+- msg.tx_buf[0] = GET_DIB_PECI_CMD;
++ msg = peci_get_xfer_msg(PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN);
++ if (!msg)
++ return -ENOMEM;
+
+- rc = peci_xfer(adapter, &msg);
+- if (rc)
+- return rc;
++ msg->addr = umsg->addr;
++ msg->tx_buf[0] = PECI_GET_DIB_CMD;
+
+- umsg->dib = le64_to_cpup((__le64 *)msg.rx_buf);
++ ret = peci_xfer(adapter, msg);
++ if (ret)
++ goto out;
+
+- return 0;
++ umsg->dib = le64_to_cpup((__le64 *)msg->rx_buf);
++
++out:
++ peci_put_xfer_msg(msg);
++
++ return ret;
+ }
+
+-static int peci_ioctl_get_temp(struct peci_adapter *adapter, void *vmsg)
++static int peci_cmd_get_temp(struct peci_adapter *adapter, void *vmsg)
+ {
+ struct peci_get_temp_msg *umsg = vmsg;
+- struct peci_xfer_msg msg;
+- int rc;
++ struct peci_xfer_msg *msg;
++ int ret;
+
+- msg.addr = umsg->addr;
+- msg.tx_len = GET_TEMP_WR_LEN;
+- msg.rx_len = GET_TEMP_RD_LEN;
+- msg.tx_buf[0] = GET_TEMP_PECI_CMD;
++ msg = peci_get_xfer_msg(PECI_GET_TEMP_WR_LEN, PECI_GET_TEMP_RD_LEN);
++ if (!msg)
++ return -ENOMEM;
+
+- rc = peci_xfer(adapter, &msg);
+- if (rc)
+- return rc;
++ msg->addr = umsg->addr;
++ msg->tx_buf[0] = PECI_GET_TEMP_CMD;
+
+- umsg->temp_raw = le16_to_cpup((__le16 *)msg.rx_buf);
++ ret = peci_xfer(adapter, msg);
++ if (ret)
++ goto out;
+
+- return 0;
++ umsg->temp_raw = le16_to_cpup((__le16 *)msg->rx_buf);
++
++out:
++ peci_put_xfer_msg(msg);
++
++ return ret;
+ }
+
+-static int peci_ioctl_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg)
++static int peci_cmd_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg)
+ {
+ struct peci_rd_pkg_cfg_msg *umsg = vmsg;
+- struct peci_xfer_msg msg;
+- int rc = 0;
++ struct peci_xfer_msg *msg;
++ int ret;
+
+ /* Per the PECI spec, the read length must be a byte, word, or dword */
+ if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) {
+@@ -334,29 +457,34 @@ static int peci_ioctl_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg)
+ return -EINVAL;
+ }
+
+- msg.addr = umsg->addr;
+- msg.tx_len = RDPKGCFG_WRITE_LEN;
+- /* read lengths of 1 and 2 result in an error, so only use 4 for now */
+- msg.rx_len = RDPKGCFG_READ_LEN_BASE + umsg->rx_len;
+- msg.tx_buf[0] = RDPKGCFG_PECI_CMD;
+- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
+- /* Host ID is 0 for PECI 3.0 */
+- msg.tx_buf[2] = umsg->index; /* RdPkgConfig index */
+- msg.tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */
+- msg.tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */
++ msg = peci_get_xfer_msg(PECI_RDPKGCFG_WRITE_LEN,
++ PECI_RDPKGCFG_READ_LEN_BASE + umsg->rx_len);
++ if (!msg)
++ return -ENOMEM;
++
++ msg->addr = umsg->addr;
++ msg->tx_buf[0] = PECI_RDPKGCFG_CMD;
++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
++ /* Host ID is 0 for PECI 3.0 */
++ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */
++ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */
++ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */
++
++ ret = peci_xfer_with_retries(adapter, msg, false);
++ if (!ret)
++ memcpy(umsg->pkg_config, &msg->rx_buf[1], umsg->rx_len);
+
+- rc = peci_xfer_with_retries(adapter, &msg, false);
+- if (!rc)
+- memcpy(umsg->pkg_config, &msg.rx_buf[1], umsg->rx_len);
++ peci_put_xfer_msg(msg);
+
+- return rc;
++ return ret;
+ }
+
+-static int peci_ioctl_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg)
++static int peci_cmd_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg)
+ {
+ struct peci_wr_pkg_cfg_msg *umsg = vmsg;
+- struct peci_xfer_msg msg;
+- int rc = 0, i;
++ struct peci_xfer_msg *msg;
++ int ret, i;
++ u8 aw_fcs;
+
+ /* Per the PECI spec, the write length must be a dword */
+ if (umsg->tx_len != 4) {
+@@ -365,86 +493,113 @@ static int peci_ioctl_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg)
+ return -EINVAL;
+ }
+
+- msg.addr = umsg->addr;
+- msg.tx_len = WRPKGCFG_WRITE_LEN_BASE + umsg->tx_len;
+- /* read lengths of 1 and 2 result in an error, so only use 4 for now */
+- msg.rx_len = WRPKGCFG_READ_LEN;
+- msg.tx_buf[0] = WRPKGCFG_PECI_CMD;
+- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
++ msg = peci_get_xfer_msg(PECI_WRPKGCFG_WRITE_LEN_BASE + umsg->tx_len,
++ PECI_WRPKGCFG_READ_LEN);
++ if (!msg)
++ return -ENOMEM;
++
++ msg->addr = umsg->addr;
++ msg->tx_buf[0] = PECI_WRPKGCFG_CMD;
++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
+ /* Host ID is 0 for PECI 3.0 */
+- msg.tx_buf[2] = umsg->index; /* RdPkgConfig index */
+- msg.tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */
+- msg.tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */
++ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */
++ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */
++ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */
+ for (i = 0; i < umsg->tx_len; i++)
+- msg.tx_buf[5 + i] = (u8)(umsg->value >> (i << 3));
++ msg->tx_buf[5 + i] = (u8)(umsg->value >> (i << 3));
++
++ /* Add an Assured Write Frame Check Sequence byte */
++ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs);
++ if (ret)
++ goto out;
++
++ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs;
+
+- /* Add an Assure Write Frame Check Sequence byte */
+- msg.tx_buf[5 + i] = 0x80 ^
+- peci_aw_fcs((u8 *)&msg, 8 + umsg->tx_len);
++ ret = peci_xfer_with_retries(adapter, msg, true);
+
+- rc = peci_xfer_with_retries(adapter, &msg, true);
++out:
++ peci_put_xfer_msg(msg);
+
+- return rc;
++ return ret;
+ }
+
+-static int peci_ioctl_rd_ia_msr(struct peci_adapter *adapter, void *vmsg)
++static int peci_cmd_rd_ia_msr(struct peci_adapter *adapter, void *vmsg)
+ {
+ struct peci_rd_ia_msr_msg *umsg = vmsg;
+- struct peci_xfer_msg msg;
+- int rc = 0;
+-
+- msg.addr = umsg->addr;
+- msg.tx_len = RDIAMSR_WRITE_LEN;
+- msg.rx_len = RDIAMSR_READ_LEN;
+- msg.tx_buf[0] = RDIAMSR_PECI_CMD;
+- msg.tx_buf[1] = 0;
+- msg.tx_buf[2] = umsg->thread_id;
+- msg.tx_buf[3] = (u8)umsg->address;
+- msg.tx_buf[4] = (u8)(umsg->address >> 8);
+-
+- rc = peci_xfer_with_retries(adapter, &msg, false);
+- if (!rc)
+- memcpy(&umsg->value, &msg.rx_buf[1], sizeof(uint64_t));
+-
+- return rc;
++ struct peci_xfer_msg *msg;
++ int ret;
++
++ msg = peci_get_xfer_msg(PECI_RDIAMSR_WRITE_LEN, PECI_RDIAMSR_READ_LEN);
++ if (!msg)
++ return -ENOMEM;
++
++ msg->addr = umsg->addr;
++ msg->tx_buf[0] = PECI_RDIAMSR_CMD;
++ msg->tx_buf[1] = 0;
++ msg->tx_buf[2] = umsg->thread_id;
++ msg->tx_buf[3] = (u8)umsg->address;
++ msg->tx_buf[4] = (u8)(umsg->address >> 8);
++
++ ret = peci_xfer_with_retries(adapter, msg, false);
++ if (!ret)
++ memcpy(&umsg->value, &msg->rx_buf[1], sizeof(uint64_t));
++
++ peci_put_xfer_msg(msg);
++
++ return ret;
++}
++
++static int peci_cmd_wr_ia_msr(struct peci_adapter *adapter, void *vmsg)
++{
++ return -ENOSYS; /* Not implemented yet */
+ }
+
+-static int peci_ioctl_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg)
++static int peci_cmd_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg)
+ {
+ struct peci_rd_pci_cfg_msg *umsg = vmsg;
+- struct peci_xfer_msg msg;
++ struct peci_xfer_msg *msg;
+ u32 address;
+- int rc = 0;
++ int ret;
++
++ msg = peci_get_xfer_msg(PECI_RDPCICFG_WRITE_LEN,
++ PECI_RDPCICFG_READ_LEN);
++ if (!msg)
++ return -ENOMEM;
+
+ address = umsg->reg; /* [11:0] - Register */
+ address |= (u32)umsg->function << 12; /* [14:12] - Function */
+ address |= (u32)umsg->device << 15; /* [19:15] - Device */
+ address |= (u32)umsg->bus << 20; /* [27:20] - Bus */
+ /* [31:28] - Reserved */
+- msg.addr = umsg->addr;
+- msg.tx_len = RDPCICFG_WRITE_LEN;
+- msg.rx_len = RDPCICFG_READ_LEN;
+- msg.tx_buf[0] = RDPCICFG_PECI_CMD;
+- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
++ msg->addr = umsg->addr;
++ msg->tx_buf[0] = PECI_RDPCICFG_CMD;
++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
+ /* Host ID is 0 for PECI 3.0 */
+- msg.tx_buf[2] = (u8)address; /* LSB - PCI Config Address */
+- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Config Address */
+- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Config Address */
+- msg.tx_buf[5] = (u8)(address >> 24); /* MSB - PCI Config Address */
++ msg->tx_buf[2] = (u8)address; /* LSB - PCI Config Address */
++ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Config Address */
++ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Config Address */
++ msg->tx_buf[5] = (u8)(address >> 24); /* MSB - PCI Config Address */
++
++ ret = peci_xfer_with_retries(adapter, msg, false);
++ if (!ret)
++ memcpy(umsg->pci_config, &msg->rx_buf[1], 4);
+
+- rc = peci_xfer_with_retries(adapter, &msg, false);
+- if (!rc)
+- memcpy(umsg->pci_config, &msg.rx_buf[1], 4);
++ peci_put_xfer_msg(msg);
+
+- return rc;
++ return ret;
+ }
+
+-static int peci_ioctl_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
++static int peci_cmd_wr_pci_cfg(struct peci_adapter *adapter, void *vmsg)
++{
++ return -ENOSYS; /* Not implemented yet */
++}
++
++static int peci_cmd_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
+ {
+ struct peci_rd_pci_cfg_local_msg *umsg = vmsg;
+- struct peci_xfer_msg msg;
++ struct peci_xfer_msg *msg;
+ u32 address;
+- int rc = 0;
++ int ret;
+
+ /* Per the PECI spec, the read length must be a byte, word, or dword */
+ if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) {
+@@ -453,34 +608,41 @@ static int peci_ioctl_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
+ return -EINVAL;
+ }
+
++ msg = peci_get_xfer_msg(PECI_RDPCICFGLOCAL_WRITE_LEN,
++ PECI_RDPCICFGLOCAL_READ_LEN_BASE +
++ umsg->rx_len);
++ if (!msg)
++ return -ENOMEM;
++
+ address = umsg->reg; /* [11:0] - Register */
+ address |= (u32)umsg->function << 12; /* [14:12] - Function */
+ address |= (u32)umsg->device << 15; /* [19:15] - Device */
+ address |= (u32)umsg->bus << 20; /* [23:20] - Bus */
+
+- msg.addr = umsg->addr;
+- msg.tx_len = RDPCICFGLOCAL_WRITE_LEN;
+- msg.rx_len = RDPCICFGLOCAL_READ_LEN_BASE + umsg->rx_len;
+- msg.tx_buf[0] = RDPCICFGLOCAL_PECI_CMD;
+- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
+- /* Host ID is 0 for PECI 3.0 */
+- msg.tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */
+- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */
+- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */
++ msg->addr = umsg->addr;
++ msg->tx_buf[0] = PECI_RDPCICFGLOCAL_CMD;
++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
++ /* Host ID is 0 for PECI 3.0 */
++ msg->tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */
++ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */
++ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */
++
++ ret = peci_xfer_with_retries(adapter, msg, false);
++ if (!ret)
++ memcpy(umsg->pci_config, &msg->rx_buf[1], umsg->rx_len);
+
+- rc = peci_xfer_with_retries(adapter, &msg, false);
+- if (!rc)
+- memcpy(umsg->pci_config, &msg.rx_buf[1], umsg->rx_len);
++ peci_put_xfer_msg(msg);
+
+- return rc;
++ return ret;
+ }
+
+-static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
++static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
+ {
+ struct peci_wr_pci_cfg_local_msg *umsg = vmsg;
+- struct peci_xfer_msg msg;
+- int rc = 0, i;
++ struct peci_xfer_msg *msg;
+ u32 address;
++ int ret, i;
++ u8 aw_fcs;
+
+ /* Per the PECI spec, the write length must be a byte, word, or dword */
+ if (umsg->tx_len != 1 && umsg->tx_len != 2 && umsg->tx_len != 4) {
+@@ -489,47 +651,56 @@ static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
+ return -EINVAL;
+ }
+
++ msg = peci_get_xfer_msg(PECI_WRPCICFGLOCAL_WRITE_LEN_BASE +
++ umsg->tx_len, PECI_WRPCICFGLOCAL_READ_LEN);
++ if (!msg)
++ return -ENOMEM;
++
+ address = umsg->reg; /* [11:0] - Register */
+ address |= (u32)umsg->function << 12; /* [14:12] - Function */
+ address |= (u32)umsg->device << 15; /* [19:15] - Device */
+ address |= (u32)umsg->bus << 20; /* [23:20] - Bus */
+
+- msg.addr = umsg->addr;
+- msg.tx_len = WRPCICFGLOCAL_WRITE_LEN_BASE + umsg->tx_len;
+- msg.rx_len = WRPCICFGLOCAL_READ_LEN;
+- msg.tx_buf[0] = WRPCICFGLOCAL_PECI_CMD;
+- msg.tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
+- /* Host ID is 0 for PECI 3.0 */
+- msg.tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */
+- msg.tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */
+- msg.tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */
++ msg->addr = umsg->addr;
++ msg->tx_buf[0] = PECI_WRPCICFGLOCAL_CMD;
++ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
++ /* Host ID is 0 for PECI 3.0 */
++ msg->tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */
++ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */
++ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */
+ for (i = 0; i < umsg->tx_len; i++)
+- msg.tx_buf[5 + i] = (u8)(umsg->value >> (i << 3));
++ msg->tx_buf[5 + i] = (u8)(umsg->value >> (i << 3));
++
++ /* Add an Assured Write Frame Check Sequence byte */
++ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs);
++ if (ret)
++ goto out;
++
++ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs;
+
+- /* Add an Assure Write Frame Check Sequence byte */
+- msg.tx_buf[5 + i] = 0x80 ^
+- peci_aw_fcs((u8 *)&msg, 8 + umsg->tx_len);
++ ret = peci_xfer_with_retries(adapter, msg, true);
+
+- rc = peci_xfer_with_retries(adapter, &msg, true);
++out:
++ peci_put_xfer_msg(msg);
+
+- return rc;
++ return ret;
+ }
+
+-typedef int (*peci_ioctl_fn_type)(struct peci_adapter *, void *);
+-
+-static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = {
+- peci_ioctl_xfer,
+- peci_ioctl_ping,
+- peci_ioctl_get_dib,
+- peci_ioctl_get_temp,
+- peci_ioctl_rd_pkg_cfg,
+- peci_ioctl_wr_pkg_cfg,
+- peci_ioctl_rd_ia_msr,
+- NULL, /* Reserved */
+- peci_ioctl_rd_pci_cfg,
+- NULL, /* Reserved */
+- peci_ioctl_rd_pci_cfg_local,
+- peci_ioctl_wr_pci_cfg_local,
++typedef int (*peci_cmd_fn_type)(struct peci_adapter *, void *);
++
++static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = {
++ peci_cmd_xfer,
++ peci_cmd_ping,
++ peci_cmd_get_dib,
++ peci_cmd_get_temp,
++ peci_cmd_rd_pkg_cfg,
++ peci_cmd_wr_pkg_cfg,
++ peci_cmd_rd_ia_msr,
++ peci_cmd_wr_ia_msr,
++ peci_cmd_rd_pci_cfg,
++ peci_cmd_wr_pci_cfg,
++ peci_cmd_rd_pci_cfg_local,
++ peci_cmd_wr_pci_cfg_local,
+ };
+
+ /**
+@@ -545,109 +716,28 @@ static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = {
+ */
+ int peci_command(struct peci_adapter *adapter, enum peci_cmd cmd, void *vmsg)
+ {
+- int rc = 0;
++ int ret;
+
+ if (cmd >= PECI_CMD_MAX || cmd < PECI_CMD_XFER)
+- return -EINVAL;
++ return -ENOTTY;
+
+ dev_dbg(&adapter->dev, "%s, cmd=0x%02x\n", __func__, cmd);
+
+- if (!peci_ioctl_fn[cmd])
++ if (!peci_cmd_fn[cmd])
+ return -EINVAL;
+
+- rt_mutex_lock(&adapter->bus_lock);
++ mutex_lock(&adapter->bus_lock);
+
+- rc = peci_cmd_support(adapter, cmd);
+- if (!rc)
+- rc = peci_ioctl_fn[cmd](adapter, vmsg);
++ ret = peci_check_cmd_support(adapter, cmd);
++ if (!ret)
++ ret = peci_cmd_fn[cmd](adapter, vmsg);
+
+- rt_mutex_unlock(&adapter->bus_lock);
++ mutex_unlock(&adapter->bus_lock);
+
+- return rc;
++ return ret;
+ }
+ EXPORT_SYMBOL_GPL(peci_command);
+
+-static long peci_ioctl(struct file *file, unsigned int iocmd, unsigned long arg)
+-{
+- struct peci_adapter *adapter = file->private_data;
+- void __user *argp = (void __user *)arg;
+- unsigned int msg_len;
+- enum peci_cmd cmd;
+- int rc = 0;
+- u8 *msg;
+-
+- if (!capable(CAP_SYS_ADMIN))
+- return -EPERM;
+-
+- dev_dbg(&adapter->dev, "ioctl, cmd=0x%x, arg=0x%lx\n", iocmd, arg);
+-
+- switch (iocmd) {
+- case PECI_IOC_XFER:
+- case PECI_IOC_PING:
+- case PECI_IOC_GET_DIB:
+- case PECI_IOC_GET_TEMP:
+- case PECI_IOC_RD_PKG_CFG:
+- case PECI_IOC_WR_PKG_CFG:
+- case PECI_IOC_RD_IA_MSR:
+- case PECI_IOC_RD_PCI_CFG:
+- case PECI_IOC_RD_PCI_CFG_LOCAL:
+- case PECI_IOC_WR_PCI_CFG_LOCAL:
+- cmd = _IOC_NR(iocmd);
+- msg_len = _IOC_SIZE(iocmd);
+- break;
+-
+- default:
+- dev_dbg(&adapter->dev, "Invalid ioctl cmd : 0x%x\n", iocmd);
+- return -ENOTTY;
+- }
+-
+- if (!access_ok(VERIFY_WRITE, argp, msg_len))
+- return -EFAULT;
+-
+- msg = memdup_user(argp, msg_len);
+- if (IS_ERR(msg))
+- return PTR_ERR(msg);
+-
+- rc = peci_command(adapter, cmd, msg);
+-
+- if (!rc && copy_to_user(argp, msg, msg_len))
+- rc = -EFAULT;
+-
+- kfree(msg);
+- return (long)rc;
+-}
+-
+-static int peci_open(struct inode *inode, struct file *file)
+-{
+- unsigned int minor = iminor(inode);
+- struct peci_adapter *adapter;
+-
+- adapter = peci_get_adapter(minor);
+- if (!adapter)
+- return -ENODEV;
+-
+- file->private_data = adapter;
+-
+- return 0;
+-}
+-
+-static int peci_release(struct inode *inode, struct file *file)
+-{
+- struct peci_adapter *adapter = file->private_data;
+-
+- peci_put_adapter(adapter);
+- file->private_data = NULL;
+-
+- return 0;
+-}
+-
+-static const struct file_operations peci_fops = {
+- .owner = THIS_MODULE,
+- .unlocked_ioctl = peci_ioctl,
+- .open = peci_open,
+- .release = peci_release,
+-};
+-
+ static int peci_detect(struct peci_adapter *adapter, u8 addr)
+ {
+ struct peci_ping_msg msg;
+@@ -666,9 +756,9 @@ peci_of_match_device(const struct of_device_id *matches,
+ return NULL;
+
+ return of_match_device(matches, &client->dev);
+-#else
++#else /* CONFIG_OF */
+ return NULL;
+-#endif
++#endif /* CONFIG_OF */
+ }
+
+ static const struct peci_device_id *
+@@ -737,6 +827,7 @@ static int peci_device_probe(struct device *dev)
+
+ err_detach_pm_domain:
+ dev_pm_domain_detach(&client->dev, true);
++
+ return status;
+ }
+
+@@ -775,13 +866,14 @@ static void peci_device_shutdown(struct device *dev)
+ driver->shutdown(client);
+ }
+
+-static struct bus_type peci_bus_type = {
++struct bus_type peci_bus_type = {
+ .name = "peci",
+ .match = peci_device_match,
+ .probe = peci_device_probe,
+ .remove = peci_device_remove,
+ .shutdown = peci_device_shutdown,
+ };
++EXPORT_SYMBOL_GPL(peci_bus_type);
+
+ static int peci_check_addr_validity(u8 addr)
+ {
+@@ -814,18 +906,18 @@ static int peci_check_client_busy(struct device *dev, void *client_new_p)
+ int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id)
+ {
+ struct peci_rd_pkg_cfg_msg msg;
+- int rc;
++ int ret;
+
+ msg.addr = addr;
+- msg.index = MBX_INDEX_CPU_ID;
+- msg.param = PKG_ID_CPU_ID;
++ msg.index = PECI_MBX_INDEX_CPU_ID;
++ msg.param = PECI_PKG_ID_CPU_ID;
+ msg.rx_len = 4;
+
+- rc = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg);
+- if (!rc)
++ ret = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg);
++ if (!ret)
+ *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config);
+
+- return rc;
++ return ret;
+ }
+ EXPORT_SYMBOL_GPL(peci_get_cpu_id);
+
+@@ -833,7 +925,7 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter,
+ struct peci_board_info const *info)
+ {
+ struct peci_client *client;
+- int rc;
++ int ret;
+
+ /* Increase reference count for the adapter assigned */
+ if (!peci_get_adapter(adapter->nr))
+@@ -847,46 +939,49 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter,
+ client->addr = info->addr;
+ strlcpy(client->name, info->type, sizeof(client->name));
+
+- rc = peci_check_addr_validity(client->addr);
+- if (rc) {
++ ret = peci_check_addr_validity(client->addr);
++ if (ret) {
+ dev_err(&adapter->dev, "Invalid PECI CPU address 0x%02hx\n",
+ client->addr);
+ goto err_free_client_silent;
+ }
+
+ /* Check online status of client */
+- rc = peci_detect(adapter, client->addr);
+- if (rc)
++ ret = peci_detect(adapter, client->addr);
++ if (ret)
+ goto err_free_client;
+
+- rc = device_for_each_child(&adapter->dev, client,
+- peci_check_client_busy);
+- if (rc)
++ ret = device_for_each_child(&adapter->dev, client,
++ peci_check_client_busy);
++ if (ret)
+ goto err_free_client;
+
+ client->dev.parent = &client->adapter->dev;
+ client->dev.bus = &peci_bus_type;
+ client->dev.type = &peci_client_type;
+- client->dev.of_node = info->of_node;
++ client->dev.of_node = of_node_get(info->of_node);
+ dev_set_name(&client->dev, "%d-%02x", adapter->nr, client->addr);
+
+- rc = device_register(&client->dev);
+- if (rc)
+- goto err_free_client;
++ ret = device_register(&client->dev);
++ if (ret)
++ goto err_put_of_node;
+
+ dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
+ client->name, dev_name(&client->dev));
+
+ return client;
+
++err_put_of_node:
++ of_node_put(info->of_node);
+ err_free_client:
+ dev_err(&adapter->dev,
+ "Failed to register peci client %s at 0x%02x (%d)\n",
+- client->name, client->addr, rc);
++ client->name, client->addr, ret);
+ err_free_client_silent:
+ kfree(client);
+ err_put_adapter:
+ peci_put_adapter(adapter);
++
+ return NULL;
+ }
+
+@@ -895,8 +990,10 @@ static void peci_unregister_device(struct peci_client *client)
+ if (!client)
+ return;
+
+- if (client->dev.of_node)
++ if (client->dev.of_node) {
+ of_node_clear_flag(client->dev.of_node, OF_POPULATED);
++ of_node_put(client->dev.of_node);
++ }
+
+ device_unregister(&client->dev);
+ }
+@@ -916,7 +1013,7 @@ static void peci_adapter_dev_release(struct device *dev)
+
+ dev_dbg(dev, "%s: %s\n", __func__, adapter->name);
+ mutex_destroy(&adapter->userspace_clients_lock);
+- rt_mutex_destroy(&adapter->bus_lock);
++ mutex_destroy(&adapter->bus_lock);
+ kfree(adapter);
+ }
+
+@@ -928,7 +1025,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
+ struct peci_board_info info = {};
+ struct peci_client *client;
+ char *blank, end;
+- int rc;
++ short addr;
++ int ret;
+
+ /* Parse device type */
+ blank = strchr(buf, ' ');
+@@ -943,16 +1041,17 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
+ memcpy(info.type, buf, blank - buf);
+
+ /* Parse remaining parameters, reject extra parameters */
+- rc = sscanf(++blank, "%hi%c", &info.addr, &end);
+- if (rc < 1) {
++ ret = sscanf(++blank, "%hi%c", &addr, &end);
++ if (ret < 1) {
+ dev_err(dev, "%s: Can't parse client address\n", "new_device");
+ return -EINVAL;
+ }
+- if (rc > 1 && end != '\n') {
++ if (ret > 1 && end != '\n') {
+ dev_err(dev, "%s: Extra parameters\n", "new_device");
+ return -EINVAL;
+ }
+
++ info.addr = (u8)addr;
+ client = peci_new_device(adapter, &info);
+ if (!client)
+ return -EINVAL;
+@@ -961,8 +1060,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
+ mutex_lock(&adapter->userspace_clients_lock);
+ list_add_tail(&client->detected, &adapter->userspace_clients);
+ mutex_unlock(&adapter->userspace_clients_lock);
+- dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device",
+- info.type, info.addr);
++ dev_dbg(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device",
++ info.type, info.addr);
+
+ return count;
+ }
+@@ -975,9 +1074,9 @@ static ssize_t peci_sysfs_delete_device(struct device *dev,
+ struct peci_adapter *adapter = to_peci_adapter(dev);
+ struct peci_client *client, *next;
+ struct peci_board_info info = {};
+- struct peci_driver *driver;
+ char *blank, end;
+- int rc;
++ short addr;
++ int ret;
+
+ /* Parse device type */
+ blank = strchr(buf, ' ');
+@@ -992,41 +1091,41 @@ static ssize_t peci_sysfs_delete_device(struct device *dev,
+ memcpy(info.type, buf, blank - buf);
+
+ /* Parse remaining parameters, reject extra parameters */
+- rc = sscanf(++blank, "%hi%c", &info.addr, &end);
+- if (rc < 1) {
++ ret = sscanf(++blank, "%hi%c", &addr, &end);
++ if (ret < 1) {
+ dev_err(dev, "%s: Can't parse client address\n",
+ "delete_device");
+ return -EINVAL;
+ }
+- if (rc > 1 && end != '\n') {
++ if (ret > 1 && end != '\n') {
+ dev_err(dev, "%s: Extra parameters\n", "delete_device");
+ return -EINVAL;
+ }
+
++ info.addr = (u8)addr;
++
+ /* Make sure the device was added through sysfs */
+- rc = -ENOENT;
++ ret = -ENOENT;
+ mutex_lock(&adapter->userspace_clients_lock);
+ list_for_each_entry_safe(client, next, &adapter->userspace_clients,
+ detected) {
+- driver = to_peci_driver(client->dev.driver);
+-
+ if (client->addr == info.addr &&
+ !strncmp(client->name, info.type, PECI_NAME_SIZE)) {
+- dev_info(dev, "%s: Deleting device %s at 0x%02hx\n",
+- "delete_device", client->name, client->addr);
++ dev_dbg(dev, "%s: Deleting device %s at 0x%02hx\n",
++ "delete_device", client->name, client->addr);
+ list_del(&client->detected);
+ peci_unregister_device(client);
+- rc = count;
++ ret = count;
+ break;
+ }
+ }
+ mutex_unlock(&adapter->userspace_clients_lock);
+
+- if (rc < 0)
+- dev_err(dev, "%s: Can't find device in list\n",
++ if (ret < 0)
++ dev_dbg(dev, "%s: Can't find device in list\n",
+ "delete_device");
+
+- return rc;
++ return ret;
+ }
+ static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, 0200, NULL,
+ peci_sysfs_delete_device);
+@@ -1039,10 +1138,11 @@ static struct attribute *peci_adapter_attrs[] = {
+ };
+ ATTRIBUTE_GROUPS(peci_adapter);
+
+-static struct device_type peci_adapter_type = {
++struct device_type peci_adapter_type = {
+ .groups = peci_adapter_groups,
+ .release = peci_adapter_dev_release,
+ };
++EXPORT_SYMBOL_GPL(peci_adapter_type);
+
+ /**
+ * peci_verify_adapter - return parameter as peci_adapter, or NULL
+@@ -1063,32 +1163,26 @@ static struct peci_client *peci_of_register_device(struct peci_adapter *adapter,
+ struct device_node *node)
+ {
+ struct peci_board_info info = {};
+- struct peci_client *result;
+- const __be32 *addr_be;
+- int len;
++ struct peci_client *client;
++ u32 addr;
++ int ret;
+
+ dev_dbg(&adapter->dev, "register %pOF\n", node);
+
+- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
+- dev_err(&adapter->dev, "modalias failure on %pOF\n", node);
+- return ERR_PTR(-EINVAL);
+- }
+-
+- addr_be = of_get_property(node, "reg", &len);
+- if (!addr_be || len < sizeof(*addr_be)) {
++ ret = of_property_read_u32(node, "reg", &addr);
++ if (ret) {
+ dev_err(&adapter->dev, "invalid reg on %pOF\n", node);
+- return ERR_PTR(-EINVAL);
++ return ERR_PTR(ret);
+ }
+
+- info.addr = be32_to_cpup(addr_be);
+- info.of_node = of_node_get(node);
++ info.addr = addr;
++ info.of_node = node;
+
+- result = peci_new_device(adapter, &info);
+- if (!result)
+- result = ERR_PTR(-EINVAL);
++ client = peci_new_device(adapter, &info);
++ if (!client)
++ client = ERR_PTR(-EINVAL);
+
+- of_node_put(node);
+- return result;
++ return client;
+ }
+
+ static void peci_of_register_devices(struct peci_adapter *adapter)
+@@ -1119,7 +1213,7 @@ static void peci_of_register_devices(struct peci_adapter *adapter)
+
+ of_node_put(bus);
+ }
+-#else
++#else /* CONFIG_OF */
+ static void peci_of_register_devices(struct peci_adapter *adapter) { }
+ #endif /* CONFIG_OF */
+
+@@ -1163,9 +1257,7 @@ static struct peci_adapter *peci_of_find_adapter(struct device_node *node)
+ return adapter;
+ }
+
+-static int peci_of_notify(struct notifier_block *nb,
+- unsigned long action,
+- void *arg)
++static int peci_of_notify(struct notifier_block *nb, ulong action, void *arg)
+ {
+ struct of_reconfig_data *rd = arg;
+ struct peci_adapter *adapter;
+@@ -1216,7 +1308,7 @@ static int peci_of_notify(struct notifier_block *nb,
+ static struct notifier_block peci_of_notifier = {
+ .notifier_call = peci_of_notify,
+ };
+-#else
++#else /* CONFIG_OF_DYNAMIC */
+ extern struct notifier_block peci_of_notifier;
+ #endif /* CONFIG_OF_DYNAMIC */
+
+@@ -1240,7 +1332,7 @@ extern struct notifier_block peci_of_notifier;
+ *
+ * Return: the peci_adapter structure on success, else NULL.
+ */
+-struct peci_adapter *peci_alloc_adapter(struct device *dev, unsigned int size)
++struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size)
+ {
+ struct peci_adapter *adapter;
+
+@@ -1263,7 +1355,7 @@ EXPORT_SYMBOL_GPL(peci_alloc_adapter);
+
+ static int peci_register_adapter(struct peci_adapter *adapter)
+ {
+- int rc = -EINVAL;
++ int ret = -EINVAL;
+
+ /* Can't register until after driver model init */
+ if (WARN_ON(!is_registered))
+@@ -1275,27 +1367,17 @@ static int peci_register_adapter(struct peci_adapter *adapter)
+ if (WARN(!adapter->xfer, "peci adapter has no xfer function\n"))
+ goto err_free_idr;
+
+- rt_mutex_init(&adapter->bus_lock);
++ mutex_init(&adapter->bus_lock);
+ mutex_init(&adapter->userspace_clients_lock);
+ INIT_LIST_HEAD(&adapter->userspace_clients);
+
+ dev_set_name(&adapter->dev, "peci-%d", adapter->nr);
+
+- /* cdev */
+- cdev_init(&adapter->cdev, &peci_fops);
+- adapter->cdev.owner = THIS_MODULE;
+- adapter->dev.devt = MKDEV(MAJOR(peci_devt), adapter->nr);
+- rc = cdev_add(&adapter->cdev, adapter->dev.devt, 1);
+- if (rc) {
+- pr_err("adapter '%s': can't add cdev (%d)\n",
+- adapter->name, rc);
+- goto err_free_idr;
+- }
+- rc = device_add(&adapter->dev);
+- if (rc) {
++ ret = device_add(&adapter->dev);
++ if (ret) {
+ pr_err("adapter '%s': can't add device (%d)\n",
+- adapter->name, rc);
+- goto err_del_cdev;
++ adapter->name, ret);
++ goto err_free_idr;
+ }
+
+ dev_dbg(&adapter->dev, "adapter [%s] registered\n", adapter->name);
+@@ -1309,13 +1391,11 @@ static int peci_register_adapter(struct peci_adapter *adapter)
+
+ return 0;
+
+-err_del_cdev:
+- cdev_del(&adapter->cdev);
+ err_free_idr:
+ mutex_lock(&core_lock);
+ idr_remove(&peci_adapter_idr, adapter->nr);
+ mutex_unlock(&core_lock);
+- return rc;
++ return ret;
+ }
+
+ static int peci_add_numbered_adapter(struct peci_adapter *adapter)
+@@ -1411,7 +1491,7 @@ void peci_del_adapter(struct peci_adapter *adapter)
+ }
+ mutex_unlock(&adapter->userspace_clients_lock);
+
+- /**
++ /*
+ * Detach any active clients. This can't fail, thus we do not
+ * check the returned value.
+ */
+@@ -1420,13 +1500,8 @@ void peci_del_adapter(struct peci_adapter *adapter)
+ /* device name is gone after device_unregister */
+ dev_dbg(&adapter->dev, "adapter [%s] unregistered\n", adapter->name);
+
+- /* free cdev */
+- cdev_del(&adapter->cdev);
+-
+ pm_runtime_disable(&adapter->dev);
+-
+ nr = adapter->nr;
+-
+ device_unregister(&adapter->dev);
+
+ /* free bus id */
+@@ -1436,6 +1511,18 @@ void peci_del_adapter(struct peci_adapter *adapter)
+ }
+ EXPORT_SYMBOL_GPL(peci_del_adapter);
+
++int peci_for_each_dev(void *data, int (*fn)(struct device *, void *))
++{
++ int ret;
++
++ mutex_lock(&core_lock);
++ ret = bus_for_each_dev(&peci_bus_type, NULL, data, fn);
++ mutex_unlock(&core_lock);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(peci_for_each_dev);
++
+ /**
+ * peci_register_driver - register a PECI driver
+ * @owner: owner module of the driver being registered
+@@ -1446,7 +1533,7 @@ EXPORT_SYMBOL_GPL(peci_del_adapter);
+ */
+ int peci_register_driver(struct module *owner, struct peci_driver *driver)
+ {
+- int rc;
++ int ret;
+
+ /* Can't register until after driver model init */
+ if (WARN_ON(!is_registered))
+@@ -1456,13 +1543,13 @@ int peci_register_driver(struct module *owner, struct peci_driver *driver)
+ driver->driver.owner = owner;
+ driver->driver.bus = &peci_bus_type;
+
+- /**
++ /*
+ * When registration returns, the driver core
+ * will have called probe() for all matching-but-unbound devices.
+ */
+- rc = driver_register(&driver->driver);
+- if (rc)
+- return rc;
++ ret = driver_register(&driver->driver);
++ if (ret)
++ return ret;
+
+ pr_debug("driver [%s] registered\n", driver->driver.name);
+
+@@ -1492,13 +1579,6 @@ static int __init peci_init(void)
+ return ret;
+ }
+
+- ret = alloc_chrdev_region(&peci_devt, 0, PECI_CDEV_MAX, "peci");
+- if (ret < 0) {
+- pr_err("peci: Failed to allocate chr dev region!\n");
+- bus_unregister(&peci_bus_type);
+- return ret;
+- }
+-
+ crc8_populate_msb(peci_crc8_table, PECI_CRC8_POLYNOMIAL);
+
+ if (IS_ENABLED(CONFIG_OF_DYNAMIC))
+@@ -1514,11 +1594,10 @@ static void __exit peci_exit(void)
+ if (IS_ENABLED(CONFIG_OF_DYNAMIC))
+ WARN_ON(of_reconfig_notifier_unregister(&peci_of_notifier));
+
+- unregister_chrdev_region(peci_devt, PECI_CDEV_MAX);
+ bus_unregister(&peci_bus_type);
+ }
+
+-postcore_initcall(peci_init);
++subsys_initcall(peci_init);
+ module_exit(peci_exit);
+
+ MODULE_AUTHOR("Jason M Biils <jason.m.bills@linux.intel.com>");
+diff --git a/drivers/peci/peci-dev.c b/drivers/peci/peci-dev.c
+new file mode 100644
+index 000000000000..5de0683206bc
+--- /dev/null
++++ b/drivers/peci/peci-dev.c
+@@ -0,0 +1,340 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2018-2019 Intel Corporation
++
++#include <linux/cdev.h>
++#include <linux/fs.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
++#include <linux/peci.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++
++/*
++ * A peci_dev represents an peci_adapter ... an PECI or SMBus master, not a
++ * slave (peci_client) with which messages will be exchanged. It's coupled
++ * with a character special file which is accessed by user mode drivers.
++ *
++ * The list of peci_dev structures is parallel to the peci_adapter lists
++ * maintained by the driver model, and is updated using bus notifications.
++ */
++struct peci_dev {
++ struct list_head list;
++ struct peci_adapter *adapter;
++ struct device *dev;
++ struct cdev cdev;
++};
++
++#define PECI_MINORS MINORMASK
++
++static dev_t peci_devt;
++static LIST_HEAD(peci_dev_list);
++static DEFINE_SPINLOCK(peci_dev_list_lock);
++
++static struct peci_dev *peci_dev_get_by_minor(uint index)
++{
++ struct peci_dev *peci_dev;
++
++ spin_lock(&peci_dev_list_lock);
++ list_for_each_entry(peci_dev, &peci_dev_list, list) {
++ if (peci_dev->adapter->nr == index)
++ goto found;
++ }
++ peci_dev = NULL;
++found:
++ spin_unlock(&peci_dev_list_lock);
++
++ return peci_dev;
++}
++
++static struct peci_dev *peci_dev_alloc(struct peci_adapter *adapter)
++{
++ struct peci_dev *peci_dev;
++
++ if (adapter->nr >= PECI_MINORS) {
++ printk(KERN_ERR "peci-dev: Out of device minors (%d)\n",
++ adapter->nr);
++ return ERR_PTR(-ENODEV);
++ }
++
++ peci_dev = kzalloc(sizeof(*peci_dev), GFP_KERNEL);
++ if (!peci_dev)
++ return ERR_PTR(-ENOMEM);
++ peci_dev->adapter = adapter;
++
++ spin_lock(&peci_dev_list_lock);
++ list_add_tail(&peci_dev->list, &peci_dev_list);
++ spin_unlock(&peci_dev_list_lock);
++
++ return peci_dev;
++}
++
++static void peci_dev_put(struct peci_dev *peci_dev)
++{
++ spin_lock(&peci_dev_list_lock);
++ list_del(&peci_dev->list);
++ spin_unlock(&peci_dev_list_lock);
++ kfree(peci_dev);
++}
++
++static ssize_t name_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct peci_dev *peci_dev = peci_dev_get_by_minor(MINOR(dev->devt));
++
++ if (!peci_dev)
++ return -ENODEV;
++
++ return sprintf(buf, "%s\n", peci_dev->adapter->name);
++}
++static DEVICE_ATTR_RO(name);
++
++static struct attribute *peci_dev_attrs[] = {
++ &dev_attr_name.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(peci_dev);
++
++static long peci_dev_ioctl(struct file *file, uint iocmd, ulong arg)
++{
++ struct peci_dev *peci_dev = file->private_data;
++ struct peci_xfer_msg __user *uxmsg;
++ struct peci_xfer_msg *xmsg = NULL;
++ void __user *umsg;
++ enum peci_cmd cmd;
++ u8 *msg = NULL;
++ uint msg_len;
++ int ret;
++
++ cmd = _IOC_NR(iocmd);
++ msg_len = _IOC_SIZE(iocmd);
++
++ switch (cmd) {
++ case PECI_CMD_XFER:
++ if (msg_len != sizeof(struct peci_xfer_msg)) {
++ ret = -EFAULT;
++ break;
++ }
++
++ uxmsg = (struct peci_xfer_msg __user *)arg;
++ xmsg = peci_get_xfer_msg(uxmsg->tx_len, uxmsg->rx_len);
++ if (IS_ERR(xmsg)) {
++ ret = PTR_ERR(xmsg);
++ break;
++ }
++
++ if (uxmsg->tx_len &&
++ copy_from_user(uxmsg->tx_buf, xmsg->tx_buf,
++ uxmsg->tx_len)) {
++ ret = -EFAULT;
++ break;
++ }
++
++ ret = peci_command(peci_dev->adapter, cmd, xmsg);
++ if (!ret && uxmsg->rx_len &&
++ copy_to_user(xmsg->rx_buf, uxmsg->rx_buf,
++ uxmsg->rx_len))
++ ret = -EFAULT;
++
++ break;
++
++ default:
++ umsg = (void __user *)arg;
++ msg = memdup_user(umsg, msg_len);
++ if (IS_ERR(msg)) {
++ ret = PTR_ERR(msg);
++ break;
++ }
++
++ ret = peci_command(peci_dev->adapter, cmd, msg);
++ if (!ret && copy_to_user(umsg, msg, msg_len))
++ ret = -EFAULT;
++
++ break;
++ }
++
++ peci_put_xfer_msg(xmsg);
++ kfree(msg);
++
++ return (long)ret;
++}
++
++static int peci_dev_open(struct inode *inode, struct file *file)
++{
++ struct peci_adapter *adapter;
++ struct peci_dev *peci_dev;
++
++ peci_dev = peci_dev_get_by_minor(iminor(inode));
++ if (!peci_dev)
++ return -ENODEV;
++
++ adapter = peci_get_adapter(peci_dev->adapter->nr);
++ if (!adapter)
++ return -ENODEV;
++
++ file->private_data = peci_dev;
++
++ return 0;
++}
++
++static int peci_dev_release(struct inode *inode, struct file *file)
++{
++ struct peci_dev *peci_dev = file->private_data;
++
++ peci_put_adapter(peci_dev->adapter);
++ file->private_data = NULL;
++
++ return 0;
++}
++
++static const struct file_operations peci_dev_fops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = peci_dev_ioctl,
++ .open = peci_dev_open,
++ .release = peci_dev_release,
++ .llseek = no_llseek,
++};
++
++static struct class *peci_dev_class;
++
++static int peci_dev_attach_adapter(struct device *dev, void *dummy)
++{
++ struct peci_adapter *adapter;
++ struct peci_dev *peci_dev;
++ dev_t devt;
++ int ret;
++
++ if (dev->type != &peci_adapter_type)
++ return 0;
++
++ adapter = to_peci_adapter(dev);
++ peci_dev = peci_dev_alloc(adapter);
++ if (IS_ERR(peci_dev))
++ return PTR_ERR(peci_dev);
++
++ cdev_init(&peci_dev->cdev, &peci_dev_fops);
++ peci_dev->cdev.owner = THIS_MODULE;
++ devt = MKDEV(MAJOR(peci_devt), adapter->nr);
++
++ ret = cdev_add(&peci_dev->cdev, devt, 1);
++ if (ret)
++ goto err_put_dev;
++
++ /* register this peci device with the driver core */
++ peci_dev->dev = device_create(peci_dev_class, &adapter->dev, devt, NULL,
++ "peci-%d", adapter->nr);
++ if (IS_ERR(peci_dev->dev)) {
++ ret = PTR_ERR(peci_dev->dev);
++ goto err_del_cdev;
++ }
++
++ pr_info("peci-dev: adapter [%s] registered as minor %d\n",
++ adapter->name, adapter->nr);
++
++ return 0;
++
++err_del_cdev:
++ cdev_del(&peci_dev->cdev);
++err_put_dev:
++ peci_dev_put(peci_dev);
++
++ return ret;
++}
++
++static int peci_dev_detach_adapter(struct device *dev, void *dummy)
++{
++ struct peci_adapter *adapter;
++ struct peci_dev *peci_dev;
++ dev_t devt;
++
++ if (dev->type != &peci_adapter_type)
++ return 0;
++
++ adapter = to_peci_adapter(dev);
++ peci_dev = peci_dev_get_by_minor(adapter->nr);
++ if (!peci_dev)
++ return 0;
++
++ cdev_del(&peci_dev->cdev);
++ devt = peci_dev->dev->devt;
++ peci_dev_put(peci_dev);
++ device_destroy(peci_dev_class, devt);
++
++ pr_info("peci-dev: adapter [%s] unregistered\n", adapter->name);
++
++ return 0;
++}
++
++static int peci_dev_notifier_call(struct notifier_block *nb, ulong action,
++ void *data)
++{
++ struct device *dev = data;
++
++ switch (action) {
++ case BUS_NOTIFY_ADD_DEVICE:
++ return peci_dev_attach_adapter(dev, NULL);
++ case BUS_NOTIFY_DEL_DEVICE:
++ return peci_dev_detach_adapter(dev, NULL);
++ }
++
++ return 0;
++}
++
++static struct notifier_block peci_dev_notifier = {
++ .notifier_call = peci_dev_notifier_call,
++};
++
++static int __init peci_dev_init(void)
++{
++ int ret;
++
++ printk(KERN_INFO "peci /dev entries driver\n");
++
++ ret = alloc_chrdev_region(&peci_devt, 0, PECI_MINORS, "peci");
++ if (ret < 0) {
++ pr_err("peci: Failed to allocate chr dev region!\n");
++ bus_unregister(&peci_bus_type);
++ goto err;
++ }
++
++ peci_dev_class = class_create(THIS_MODULE, "peci-dev");
++ if (IS_ERR(peci_dev_class)) {
++ ret = PTR_ERR(peci_dev_class);
++ goto err_unreg_chrdev;
++ }
++ peci_dev_class->dev_groups = peci_dev_groups;
++
++ /* Keep track of adapters which will be added or removed later */
++ ret = bus_register_notifier(&peci_bus_type, &peci_dev_notifier);
++ if (ret)
++ goto err_destroy_class;
++
++ /* Bind to already existing adapters right away */
++ peci_for_each_dev(NULL, peci_dev_attach_adapter);
++
++ return 0;
++
++err_destroy_class:
++ class_destroy(peci_dev_class);
++err_unreg_chrdev:
++ unregister_chrdev_region(peci_devt, PECI_MINORS);
++err:
++ printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
++
++ return ret;
++}
++
++static void __exit peci_dev_exit(void)
++{
++ bus_unregister_notifier(&peci_bus_type, &peci_dev_notifier);
++ peci_for_each_dev(NULL, peci_dev_detach_adapter);
++ class_destroy(peci_dev_class);
++ unregister_chrdev_region(peci_devt, PECI_MINORS);
++}
++
++module_init(peci_dev_init);
++module_exit(peci_dev_exit);
++
++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
++MODULE_DESCRIPTION("PECI /dev entries driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h
+index 8f6d823a59cd..1f1b07a9aeab 100644
+--- a/include/linux/mfd/intel-peci-client.h
++++ b/include/linux/mfd/intel-peci-client.h
+@@ -1,5 +1,5 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+-/* Copyright (c) 2018 Intel Corporation */
++/* Copyright (c) 2018-2019 Intel Corporation */
+
+ #ifndef __LINUX_MFD_INTEL_PECI_CLIENT_H
+ #define __LINUX_MFD_INTEL_PECI_CLIENT_H
+@@ -9,7 +9,7 @@
+ #if IS_ENABLED(CONFIG_X86)
+ #include <asm/intel-family.h>
+ #else
+-/**
++/*
+ * Architectures other than x86 cannot include the header file so define these
+ * at here. These are needed for detecting type of client x86 CPUs behind a PECI
+ * connection.
+@@ -58,7 +58,6 @@ struct cpu_gen_info {
+ /**
+ * struct peci_client_manager - PECI client manager information
+ * @client; pointer to the PECI client
+- * @dev: pointer to the struct device
+ * @name: PECI client manager name
+ * @gen_info: CPU generation info of the detected CPU
+ *
+@@ -67,7 +66,6 @@ struct cpu_gen_info {
+ */
+ struct peci_client_manager {
+ struct peci_client *client;
+- struct device *dev;
+ char name[PECI_NAME_SIZE];
+ const struct cpu_gen_info *gen_info;
+ };
+diff --git a/include/linux/peci.h b/include/linux/peci.h
+index d0e47d45d1d0..6fc424dc2a73 100644
+--- a/include/linux/peci.h
++++ b/include/linux/peci.h
+@@ -1,19 +1,18 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+-/* Copyright (c) 2018 Intel Corporation */
++/* Copyright (c) 2018-2019 Intel Corporation */
+
+ #ifndef __LINUX_PECI_H
+ #define __LINUX_PECI_H
+
+-#include <linux/cdev.h>
+ #include <linux/device.h>
++#include <linux/mutex.h>
+ #include <linux/peci-ioctl.h>
+-#include <linux/rtmutex.h>
+
+ #define PECI_NAME_SIZE 32
+
+ struct peci_board_info {
+ char type[PECI_NAME_SIZE];
+- unsigned short addr; /* CPU client address */
++ u8 addr; /* CPU client address */
+ struct device_node *of_node;
+ };
+
+@@ -22,29 +21,29 @@ struct peci_board_info {
+ * @owner: owner module of the PECI adpater
+ * @bus_lock: mutex for exclusion of multiple callers
+ * @dev: device interface to this driver
+- * @cdev: character device object to create character device
+ * @nr: the bus number to map
+ * @name: name of the adapter
+ * @userspace_clients_lock: mutex for exclusion of clients handling
+ * @userspace_clients: list of registered clients
+ * @xfer: low-level transfer function pointer of the adapter
+ * @cmd_mask: mask for supportable PECI commands
++ * @use_dma: flag for indicating that adapter uses DMA
+ *
+ * Each PECI adapter can communicate with one or more PECI client children.
+ * These make a small bus, sharing a single wired PECI connection.
+ */
+ struct peci_adapter {
+ struct module *owner;
+- struct rt_mutex bus_lock;
++ struct mutex bus_lock;
+ struct device dev;
+- struct cdev cdev;
+ int nr;
+ char name[PECI_NAME_SIZE];
+ struct mutex userspace_clients_lock; /* clients list mutex */
+ struct list_head userspace_clients;
+ int (*xfer)(struct peci_adapter *adapter,
+ struct peci_xfer_msg *msg);
+- uint cmd_mask;
++ u32 cmd_mask;
++ bool use_dma;
+ };
+
+ static inline struct peci_adapter *to_peci_adapter(void *d)
+@@ -87,8 +86,8 @@ static inline struct peci_client *to_peci_client(void *d)
+ }
+
+ struct peci_device_id {
+- char name[PECI_NAME_SIZE];
+- unsigned long driver_data; /* Data private to the driver */
++ char name[PECI_NAME_SIZE];
++ ulong driver_data; /* Data private to the driver */
+ };
+
+ /**
+@@ -129,13 +128,22 @@ static inline struct peci_driver *to_peci_driver(void *d)
+ /* use a define to avoid include chaining to get THIS_MODULE */
+ #define peci_add_driver(driver) peci_register_driver(THIS_MODULE, driver)
+
++extern struct bus_type peci_bus_type;
++extern struct device_type peci_adapter_type;
++extern struct device_type peci_client_type;
++
+ int peci_register_driver(struct module *owner, struct peci_driver *drv);
+ void peci_del_driver(struct peci_driver *driver);
+ struct peci_client *peci_verify_client(struct device *dev);
+-struct peci_adapter *peci_alloc_adapter(struct device *dev, unsigned int size);
++struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size);
++struct peci_adapter *peci_get_adapter(int nr);
++void peci_put_adapter(struct peci_adapter *adapter);
+ int peci_add_adapter(struct peci_adapter *adapter);
+ void peci_del_adapter(struct peci_adapter *adapter);
+ struct peci_adapter *peci_verify_adapter(struct device *dev);
++int peci_for_each_dev(void *data, int (*fn)(struct device *, void *));
++struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len);
++void peci_put_xfer_msg(struct peci_xfer_msg *msg);
+ int peci_command(struct peci_adapter *adpater, enum peci_cmd cmd, void *vmsg);
+ int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id);
+
+diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h
+index a6dae71cbff5..8467b2fbee1f 100644
+--- a/include/uapi/linux/peci-ioctl.h
++++ b/include/uapi/linux/peci-ioctl.h
+@@ -1,5 +1,5 @@
+ /* SPDX-License-Identifier: GPL-2.0 */
+-/* Copyright (c) 2018 Intel Corporation */
++/* Copyright (c) 2018-2019 Intel Corporation */
+
+ #ifndef __PECI_IOCTL_H
+ #define __PECI_IOCTL_H
+@@ -7,136 +7,34 @@
+ #include <linux/ioctl.h>
+ #include <linux/types.h>
+
+-/* Base Address of 48d */
+-#define PECI_BASE_ADDR 0x30 /* The PECI client's default address of 0x30 */
+-#define PECI_OFFSET_MAX 8 /* Max numver of CPU clients */
+-
+-/* PCI Access */
+-#define MAX_PCI_READ_LEN 24 /* Number of bytes of the PCI Space read */
+-
+-#define PCI_BUS0_CPU0 0x00
+-#define PCI_BUS0_CPU1 0x80
+-#define PCI_CPUBUSNO_BUS 0x00
+-#define PCI_CPUBUSNO_DEV 0x08
+-#define PCI_CPUBUSNO_FUNC 0x02
+-#define PCI_CPUBUSNO 0xcc
+-#define PCI_CPUBUSNO_1 0xd0
+-#define PCI_CPUBUSNO_VALID 0xd4
+-
+-/* Package Identifier Read Parameter Value */
+-#define PKG_ID_CPU_ID 0x0000 /* CPUID Info */
+-#define PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */
+-#define PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */
+-#define PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */
+-#define PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */
+-#define PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */
+-
+-/* RdPkgConfig Index */
+-#define MBX_INDEX_CPU_ID 0 /* Package Identifier Read */
+-#define MBX_INDEX_VR_DEBUG 1 /* VR Debug */
+-#define MBX_INDEX_PKG_TEMP_READ 2 /* Package Temperature Read */
+-#define MBX_INDEX_ENERGY_COUNTER 3 /* Energy counter */
+-#define MBX_INDEX_ENERGY_STATUS 4 /* DDR Energy Status */
+-#define MBX_INDEX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */
+-#define MBX_INDEX_EPI 6 /* Efficient Performance Indication */
+-#define MBX_INDEX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */
+-#define MBX_INDEX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */
+-#define MBX_INDEX_DTS_MARGIN 10 /* DTS thermal margin */
+-#define MBX_INDEX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */
+-#define MBX_INDEX_CFG_TDP_CONTROL 12 /* TDP Config Control */
+-#define MBX_INDEX_CFG_TDP_LEVELS 13 /* TDP Config Levels */
+-#define MBX_INDEX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */
+-#define MBX_INDEX_CFG_ICCMAX 15 /* Configurable ICCMAX */
+-#define MBX_INDEX_TEMP_TARGET 16 /* Temperature Target Read */
+-#define MBX_INDEX_CURR_CFG_LIMIT 17 /* Current Config Limit */
+-#define MBX_INDEX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */
+-#define MBX_INDEX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */
+-#define MBX_INDEX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */
+-#define MBX_INDEX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */
+-#define MBX_INDEX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */
+-#define MBX_INDEX_TDP 28 /* Thermal design power minimum */
+-#define MBX_INDEX_TDP_HIGH 29 /* Thermal design power maximum */
+-#define MBX_INDEX_TDP_UNITS 30 /* Units for power/energy registers */
+-#define MBX_INDEX_RUN_TIME 31 /* Accumulated Run Time */
+-#define MBX_INDEX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */
+-#define MBX_INDEX_TURBO_RATIO 33 /* Turbo Activation Ratio */
+-#define MBX_INDEX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */
+-#define MBX_INDEX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */
+-#define MBX_INDEX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */
+-#define MBX_INDEX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */
+-#define MBX_INDEX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */
+-#define MBX_INDEX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */
+-#define MBX_INDEX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */
+-#define MBX_INDEX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */
+-#define MBX_INDEX_DDR_THERM_STATUS 46 /* DDR Thermal Status */
+-#define MBX_INDEX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */
+-#define MBX_INDEX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */
+-#define MBX_INDEX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */
+-#define MBX_INDEX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */
+-#define MBX_INDEX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */
+-#define MBX_INDEX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */
+-#define MBX_INDEX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */
+-#define MBX_INDEX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */
+-#define MBX_INDEX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */
+-#define MBX_INDEX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */
+-
+-/* WrPkgConfig Index */
+-#define MBX_INDEX_DIMM_AMBIENT 19
+-#define MBX_INDEX_DIMM_TEMP 24
++/* The PECI client's default address of 0x30 */
++#define PECI_BASE_ADDR 0x30
++
++/* Max number of CPU clients */
++#define PECI_OFFSET_MAX 8
++
++/* PECI read/write data buffer size max */
++#define PECI_BUFFER_SIZE 255
+
+ /* Device Specific Completion Code (CC) Definition */
+-#define DEV_PECI_CC_SUCCESS 0x40
+-#define DEV_PECI_CC_TIMEOUT 0x80
+-#define DEV_PECI_CC_OUT_OF_RESOURCE 0x81
+-#define DEV_PECI_CC_UNAVAIL_RESOURCE 0x82
+-#define DEV_PECI_CC_INVALID_REQ 0x90
++#define PECI_DEV_CC_SUCCESS 0x40
++#define PECI_DEV_CC_TIMEOUT 0x80
++#define PECI_DEV_CC_OUT_OF_RESOURCE 0x81
++#define PECI_DEV_CC_UNAVAIL_RESOURCE 0x82
++#define PECI_DEV_CC_INVALID_REQ 0x90
+
+ /* Completion Code mask to check retry needs */
+-#define DEV_PECI_CC_RETRY_CHECK_MASK 0xf0
+-#define DEV_PECI_CC_NEED_RETRY 0x80
++#define PECI_DEV_CC_RETRY_CHECK_MASK 0xf0
++#define PECI_DEV_CC_NEED_RETRY 0x80
+
+ /* Skylake EDS says to retry for 250ms */
+-#define DEV_PECI_RETRY_TIME_MS 250
+-#define DEV_PECI_RETRY_INTERVAL_USEC 10000
+-#define DEV_PECI_RETRY_BIT 0x01
+-
+-#define GET_TEMP_WR_LEN 1
+-#define GET_TEMP_RD_LEN 2
+-#define GET_TEMP_PECI_CMD 0x01
+-
+-#define GET_DIB_WR_LEN 1
+-#define GET_DIB_RD_LEN 8
+-#define GET_DIB_PECI_CMD 0xf7
+-
+-#define RDPKGCFG_WRITE_LEN 5
+-#define RDPKGCFG_READ_LEN_BASE 1
+-#define RDPKGCFG_PECI_CMD 0xa1
+-
+-#define WRPKGCFG_WRITE_LEN_BASE 6
+-#define WRPKGCFG_READ_LEN 1
+-#define WRPKGCFG_PECI_CMD 0xa5
+-
+-#define RDIAMSR_WRITE_LEN 5
+-#define RDIAMSR_READ_LEN 9
+-#define RDIAMSR_PECI_CMD 0xb1
+-
+-#define WRIAMSR_PECI_CMD 0xb5
+-
+-#define RDPCICFG_WRITE_LEN 6
+-#define RDPCICFG_READ_LEN 5
+-#define RDPCICFG_PECI_CMD 0x61
++#define PECI_DEV_RETRY_TIME_MS 250
++#define PECI_DEV_RETRY_INTERVAL_USEC 10000
++#define PECI_DEV_RETRY_BIT 0x01
+
+-#define WRPCICFG_PECI_CMD 0x65
++#define PECI_WRIAMSR_CMD 0xb5
+
+-#define RDPCICFGLOCAL_WRITE_LEN 5
+-#define RDPCICFGLOCAL_READ_LEN_BASE 1
+-#define RDPCICFGLOCAL_PECI_CMD 0xe1
+-
+-#define WRPCICFGLOCAL_WRITE_LEN_BASE 6
+-#define WRPCICFGLOCAL_READ_LEN 1
+-#define WRPCICFGLOCAL_PECI_CMD 0xe5
+-
+-#define PECI_BUFFER_SIZE 32
++#define PECI_WRPCICFG_CMD 0x65
+
+ /**
+ * enum peci_cmd - PECI client commands
+@@ -186,11 +84,12 @@ enum peci_cmd {
+ * raw PECI transfer
+ */
+ struct peci_xfer_msg {
+- __u8 addr;
+- __u8 tx_len;
+- __u8 rx_len;
+- __u8 tx_buf[PECI_BUFFER_SIZE];
+- __u8 rx_buf[PECI_BUFFER_SIZE];
++ __u8 addr;
++ __u8 tx_len;
++ __u8 rx_len;
++ __u8 padding;
++ __u8 *tx_buf;
++ __u8 *rx_buf;
+ } __attribute__((__packed__));
+
+ /**
+@@ -202,7 +101,8 @@ struct peci_xfer_msg {
+ * powered-off, etc.
+ */
+ struct peci_ping_msg {
+- __u8 addr;
++ __u8 addr;
++ __u8 padding[3];
+ } __attribute__((__packed__));
+
+ /**
+@@ -216,8 +116,13 @@ struct peci_ping_msg {
+ * command.
+ */
+ struct peci_get_dib_msg {
+- __u8 addr;
+- __u64 dib;
++#define PECI_GET_DIB_WR_LEN 1
++#define PECI_GET_DIB_RD_LEN 8
++#define PECI_GET_DIB_CMD 0xf7
++
++ __u8 addr;
++ __u8 padding[3];
++ __u64 dib;
+ } __attribute__((__packed__));
+
+ /**
+@@ -232,8 +137,14 @@ struct peci_get_dib_msg {
+ * below the maximum processor junction temperature.
+ */
+ struct peci_get_temp_msg {
+- __u8 addr;
+- __s16 temp_raw;
++#define PECI_GET_TEMP_WR_LEN 1
++#define PECI_GET_TEMP_RD_LEN 2
++#define PECI_GET_TEMP_CMD 0x01
++
++ __u8 addr;
++ __u8 padding0[3];
++ __s16 temp_raw;
++ __u8 padding1[2];
+ } __attribute__((__packed__));
+
+ /**
+@@ -251,11 +162,72 @@ struct peci_get_temp_msg {
+ * DIMM temperatures and so on.
+ */
+ struct peci_rd_pkg_cfg_msg {
+- __u8 addr;
+- __u8 index;
+- __u16 param;
+- __u8 rx_len;
+- __u8 pkg_config[4];
++#define PECI_RDPKGCFG_WRITE_LEN 5
++#define PECI_RDPKGCFG_READ_LEN_BASE 1
++#define PECI_RDPKGCFG_CMD 0xa1
++
++ __u8 addr;
++ __u8 index;
++#define PECI_MBX_INDEX_CPU_ID 0 /* Package Identifier Read */
++#define PECI_MBX_INDEX_VR_DEBUG 1 /* VR Debug */
++#define PECI_MBX_INDEX_PKG_TEMP_READ 2 /* Package Temperature Read */
++#define PECI_MBX_INDEX_ENERGY_COUNTER 3 /* Energy counter */
++#define PECI_MBX_INDEX_ENERGY_STATUS 4 /* DDR Energy Status */
++#define PECI_MBX_INDEX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */
++#define PECI_MBX_INDEX_EPI 6 /* Efficient Performance Indication */
++#define PECI_MBX_INDEX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */
++#define PECI_MBX_INDEX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */
++#define PECI_MBX_INDEX_DTS_MARGIN 10 /* DTS thermal margin */
++#define PECI_MBX_INDEX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */
++#define PECI_MBX_INDEX_CFG_TDP_CONTROL 12 /* TDP Config Control */
++#define PECI_MBX_INDEX_CFG_TDP_LEVELS 13 /* TDP Config Levels */
++#define PECI_MBX_INDEX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */
++#define PECI_MBX_INDEX_CFG_ICCMAX 15 /* Configurable ICCMAX */
++#define PECI_MBX_INDEX_TEMP_TARGET 16 /* Temperature Target Read */
++#define PECI_MBX_INDEX_CURR_CFG_LIMIT 17 /* Current Config Limit */
++#define PECI_MBX_INDEX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */
++#define PECI_MBX_INDEX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */
++#define PECI_MBX_INDEX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */
++#define PECI_MBX_INDEX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */
++#define PECI_MBX_INDEX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */
++#define PECI_MBX_INDEX_TDP 28 /* Thermal design power minimum */
++#define PECI_MBX_INDEX_TDP_HIGH 29 /* Thermal design power maximum */
++#define PECI_MBX_INDEX_TDP_UNITS 30 /* Units for power/energy registers */
++#define PECI_MBX_INDEX_RUN_TIME 31 /* Accumulated Run Time */
++#define PECI_MBX_INDEX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */
++#define PECI_MBX_INDEX_TURBO_RATIO 33 /* Turbo Activation Ratio */
++#define PECI_MBX_INDEX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */
++#define PECI_MBX_INDEX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */
++#define PECI_MBX_INDEX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */
++#define PECI_MBX_INDEX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */
++#define PECI_MBX_INDEX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */
++#define PECI_MBX_INDEX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */
++#define PECI_MBX_INDEX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */
++#define PECI_MBX_INDEX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */
++#define PECI_MBX_INDEX_DDR_THERM_STATUS 46 /* DDR Thermal Status */
++#define PECI_MBX_INDEX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */
++#define PECI_MBX_INDEX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */
++#define PECI_MBX_INDEX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */
++#define PECI_MBX_INDEX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */
++#define PECI_MBX_INDEX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */
++#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */
++#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */
++#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */
++#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */
++#define PECI_MBX_INDEX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */
++
++ __u16 param;
++/* When index is PECI_MBX_INDEX_CPU_ID */
++#define PECI_PKG_ID_CPU_ID 0x0000 /* CPUID Info */
++#define PECI_PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */
++#define PECI_PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */
++#define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */
++#define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */
++#define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */
++
++ __u8 rx_len;
++ __u8 padding[3];
++ __u8 pkg_config[4];
+ } __attribute__((__packed__));
+
+ /**
+@@ -272,11 +244,19 @@ struct peci_rd_pkg_cfg_msg {
+ * may include power limiting, thermal averaging constant programming and so on.
+ */
+ struct peci_wr_pkg_cfg_msg {
+- __u8 addr;
+- __u8 index;
+- __u16 param;
+- __u8 tx_len;
+- __u32 value;
++#define PECI_WRPKGCFG_WRITE_LEN_BASE 6
++#define PECI_WRPKGCFG_READ_LEN 1
++#define PECI_WRPKGCFG_CMD 0xa5
++
++ __u8 addr;
++ __u8 index;
++#define PECI_MBX_INDEX_DIMM_AMBIENT 19
++#define PECI_MBX_INDEX_DIMM_TEMP 24
++
++ __u16 param;
++ __u8 tx_len;
++ __u8 padding[3];
++ __u32 value;
+ } __attribute__((__packed__));
+
+ /**
+@@ -290,10 +270,34 @@ struct peci_wr_pkg_cfg_msg {
+ * (MSRs) defined in the processor's Intel Architecture (IA).
+ */
+ struct peci_rd_ia_msr_msg {
+- __u8 addr;
+- __u8 thread_id;
+- __u16 address;
+- __u64 value;
++#define PECI_RDIAMSR_WRITE_LEN 5
++#define PECI_RDIAMSR_READ_LEN 9
++#define PECI_RDIAMSR_CMD 0xb1
++
++ __u8 addr;
++ __u8 thread_id;
++ __u16 address;
++ __u64 value;
++} __attribute__((__packed__));
++
++/**
++ * struct peci_wr_ia_msr_msg - WrIAMSR command
++ * @addr: address of the client
++ * @thread_id: ID of the specific logical processor
++ * @address: address of MSR to write to
++ * @tx_len: number of data to be written in bytes
++ * @value: data to be written
++ *
++ * The WrIAMSR() PECI command provides write access to Model Specific Registers
++ * (MSRs) defined in the processor's Intel Architecture (IA).
++ */
++struct peci_wr_ia_msr_msg {
++ __u8 addr;
++ __u8 thread_id;
++ __u16 address;
++ __u8 tx_len;
++ __u8 padding[3];
++ __u64 value;
+ } __attribute__((__packed__));
+
+ /**
+@@ -310,12 +314,52 @@ struct peci_rd_ia_msr_msg {
+ * processor.
+ */
+ struct peci_rd_pci_cfg_msg {
+- __u8 addr;
+- __u8 bus;
+- __u8 device;
+- __u8 function;
+- __u16 reg;
+- __u8 pci_config[4];
++#define PECI_RDPCICFG_WRITE_LEN 6
++#define PECI_RDPCICFG_READ_LEN 5
++#define PECI_RDPCICFG_READ_LEN_MAX 24
++#define PECI_RDPCICFG_CMD 0x61
++
++ __u8 addr;
++ __u8 bus;
++#define PECI_PCI_BUS0_CPU0 0x00
++#define PECI_PCI_BUS0_CPU1 0x80
++#define PECI_PCI_CPUBUSNO_BUS 0x00
++#define PECI_PCI_CPUBUSNO_DEV 0x08
++#define PECI_PCI_CPUBUSNO_FUNC 0x02
++#define PECI_PCI_CPUBUSNO 0xcc
++#define PECI_PCI_CPUBUSNO_1 0xd0
++#define PECI_PCI_CPUBUSNO_VALID 0xd4
++
++ __u8 device;
++ __u8 function;
++ __u16 reg;
++ __u8 padding[2];
++ __u8 pci_config[4];
++} __attribute__((__packed__));
++
++/**
++ * struct peci_wr_pci_cfg_msg - WrPCIConfig command
++ * @addr: address of the client
++ * @bus: PCI bus number
++ * @device: PCI device number
++ * @function: specific function to write to
++ * @reg: specific register to write to
++ * @tx_len: number of data to be written in bytes
++ * @pci_config: config data to be written
++ *
++ * The RdPCIConfig() command provides sideband write access to the PCI
++ * configuration space maintained in downstream devices external to the
++ * processor.
++ */
++struct peci_wr_pci_cfg_msg {
++ __u8 addr;
++ __u8 bus;
++ __u8 device;
++ __u8 function;
++ __u16 reg;
++ __u8 tx_len;
++ __u8 padding;
++ __u8 pci_config[4];
+ } __attribute__((__packed__));
+
+ /**
+@@ -333,13 +377,18 @@ struct peci_rd_pci_cfg_msg {
+ * processor IIO and uncore registers within the PCI configuration space.
+ */
+ struct peci_rd_pci_cfg_local_msg {
+- __u8 addr;
+- __u8 bus;
+- __u8 device;
+- __u8 function;
+- __u16 reg;
+- __u8 rx_len;
+- __u8 pci_config[4];
++#define PECI_RDPCICFGLOCAL_WRITE_LEN 5
++#define PECI_RDPCICFGLOCAL_READ_LEN_BASE 1
++#define PECI_RDPCICFGLOCAL_CMD 0xe1
++
++ __u8 addr;
++ __u8 bus;
++ __u8 device;
++ __u8 function;
++ __u16 reg;
++ __u8 rx_len;
++ __u8 padding[3];
++ __u8 pci_config[4];
+ } __attribute__((__packed__));
+
+ /**
+@@ -357,13 +406,18 @@ struct peci_rd_pci_cfg_local_msg {
+ * access this space even before BIOS enumeration of the system buses.
+ */
+ struct peci_wr_pci_cfg_local_msg {
+- __u8 addr;
+- __u8 bus;
+- __u8 device;
+- __u8 function;
+- __u16 reg;
+- __u8 tx_len;
+- __u32 value;
++#define PECI_WRPCICFGLOCAL_WRITE_LEN_BASE 6
++#define PECI_WRPCICFGLOCAL_READ_LEN 1
++#define PECI_WRPCICFGLOCAL_CMD 0xe5
++
++ __u8 addr;
++ __u8 bus;
++ __u8 device;
++ __u8 function;
++ __u16 reg;
++ __u8 tx_len;
++ __u8 padding[3];
++ __u32 value;
+ } __attribute__((__packed__));
+
+ #define PECI_IOC_BASE 0xb7
+@@ -389,9 +443,15 @@ struct peci_wr_pci_cfg_local_msg {
+ #define PECI_IOC_RD_IA_MSR \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_RD_IA_MSR, struct peci_rd_ia_msr_msg)
+
++#define PECI_IOC_WR_IA_MSR \
++ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_IA_MSR, struct peci_wr_ia_msr_msg)
++
+ #define PECI_IOC_RD_PCI_CFG \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG, struct peci_rd_pci_cfg_msg)
+
++#define PECI_IOC_WR_PCI_CFG \
++ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG, struct peci_wr_pci_cfg_msg)
++
+ #define PECI_IOC_RD_PCI_CFG_LOCAL \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG_LOCAL, \
+ struct peci_rd_pci_cfg_local_msg)
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0019-Add-I2C-IPMB-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0019-Add-I2C-IPMB-support.patch
new file mode 100644
index 000000000..391d6f816
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0019-Add-I2C-IPMB-support.patch
@@ -0,0 +1,426 @@
+From 59e2471d9bf64fa7d539520ef66cf5f33c0b0e55 Mon Sep 17 00:00:00 2001
+From: Haiyue Wang <haiyue.wang@linux.intel.com>
+Date: Tue, 13 Feb 2018 14:28:12 +0800
+Subject: [PATCH] i2c: slave-mqueue: add mqueue driver to receive ipmi message
+
+Some protocols over I2C are designed for bi-directional transferring
+messages by using I2C Master Write protocol. Like the MCTP (Management
+Component Transport Protocol) and IPMB (Intelligent Platform Management
+Bus), they both require that the userspace can receive messages from
+I2C dirvers under slave mode.
+
+This new slave mqueue backend is used to receive and queue messages, it
+will exposes these messages to userspace by sysfs bin file.
+
+Signed-off-by: Haiyue Wang <haiyue.wang@linux.intel.com>
+---
+ Documentation/i2c/slave-mqueue-backend.rst | 125 +++++++++++++++++
+ drivers/i2c/Kconfig | 23 +++
+ drivers/i2c/Makefile | 1 +
+ drivers/i2c/i2c-slave-mqueue.c | 217 +++++++++++++++++++++++++++++
+ 4 files changed, 366 insertions(+)
+ create mode 100644 Documentation/i2c/slave-mqueue-backend.rst
+ create mode 100644 drivers/i2c/i2c-slave-mqueue.c
+
+diff --git a/Documentation/i2c/slave-mqueue-backend.rst b/Documentation/i2c/slave-mqueue-backend.rst
+new file mode 100644
+index 000000000000..3966cf0ab8da
+--- /dev/null
++++ b/Documentation/i2c/slave-mqueue-backend.rst
+@@ -0,0 +1,125 @@
++.. SPDX-License-Identifier: GPL-2.0
++
++=====================================
++Linux I2C slave message queue backend
++=====================================
++
++:Author: Haiyue Wang <haiyue.wang@linux.intel.com>
++
++Some protocols over I2C/SMBus are designed for bi-directional transferring
++messages by using I2C Master Write protocol. This requires that both sides
++of the communication have slave addresses.
++
++Like MCTP (Management Component Transport Protocol) and IPMB (Intelligent
++Platform Management Bus), they both require that the userspace can receive
++messages from i2c dirvers under slave mode.
++
++This I2C slave mqueue (message queue) backend is used to receive and queue
++messages from the remote i2c intelligent device; and it will add the target
++slave address (with R/W# bit is always 0) into the message at the first byte,
++so that userspace can use this byte to dispatch the messages into different
++handling modules. Also, like IPMB, the address byte is in its message format,
++it needs it to do checksum.
++
++For messages are time related, so this backend will flush the oldest message
++to queue the newest one.
++
++Link
++----
++`Intelligent Platform Management Bus
++Communications Protocol Specification
++<https://www.intel.com/content/dam/www/public/us/en/documents/product-briefs/ipmp-spec-v1.0.pdf>`_
++
++`Management Component Transport Protocol (MCTP)
++SMBus/I2C Transport Binding Specification
++<https://www.dmtf.org/sites/default/files/standards/documents/DSP0237_1.1.0.pdf>`_
++
++How to use
++----------
++For example, the I2C5 bus has slave address 0x10, the below command will create
++the related message queue interface:
++
++ echo slave-mqueue 0x1010 > /sys/bus/i2c/devices/i2c-5/new_device
++
++Then you can dump the messages like this:
++
++ hexdump -C /sys/bus/i2c/devices/5-1010/slave-mqueue
++
++Code Example
++------------
++*Note: call 'lseek' before 'read', this is a requirement from kernfs' design.*
++
++::
++
++ #include <sys/types.h>
++ #include <sys/stat.h>
++ #include <unistd.h>
++ #include <poll.h>
++ #include <time.h>
++ #include <fcntl.h>
++ #include <stdio.h>
++
++ int main(int argc, char *argv[])
++ {
++ int i, r;
++ struct pollfd pfd;
++ struct timespec ts;
++ unsigned char data[256];
++
++ pfd.fd = open(argv[1], O_RDONLY | O_NONBLOCK);
++ if (pfd.fd < 0)
++ return -1;
++
++ pfd.events = POLLPRI;
++
++ while (1) {
++ r = poll(&pfd, 1, 5000);
++
++ if (r < 0)
++ break;
++
++ if (r == 0 || !(pfd.revents & POLLPRI))
++ continue;
++
++ lseek(pfd.fd, 0, SEEK_SET);
++ r = read(pfd.fd, data, sizeof(data));
++ if (r <= 0)
++ continue;
++
++ clock_gettime(CLOCK_MONOTONIC, &ts);
++ printf("[%ld.%.9ld] :", ts.tv_sec, ts.tv_nsec);
++ for (i = 0; i < r; i++)
++ printf(" %02x", data[i]);
++ printf("\n");
++ }
++
++ close(pfd.fd);
++
++ return 0;
++ }
++
++Result
++------
++*./a.out "/sys/bus/i2c/devices/5-1010/slave-mqueue"*
++
++::
++
++ [10183.232500449] : 20 18 c8 2c 78 01 5b
++ [10183.479358348] : 20 18 c8 2c 78 01 5b
++ [10183.726556812] : 20 18 c8 2c 78 01 5b
++ [10183.972605863] : 20 18 c8 2c 78 01 5b
++ [10184.220124772] : 20 18 c8 2c 78 01 5b
++ [10184.467764166] : 20 18 c8 2c 78 01 5b
++ [10193.233421784] : 20 18 c8 2c 7c 01 57
++ [10193.480273460] : 20 18 c8 2c 7c 01 57
++ [10193.726788733] : 20 18 c8 2c 7c 01 57
++ [10193.972781945] : 20 18 c8 2c 7c 01 57
++ [10194.220487360] : 20 18 c8 2c 7c 01 57
++ [10194.468089259] : 20 18 c8 2c 7c 01 57
++ [10203.233433099] : 20 18 c8 2c 80 01 53
++ [10203.481058715] : 20 18 c8 2c 80 01 53
++ [10203.727610472] : 20 18 c8 2c 80 01 53
++ [10203.974044856] : 20 18 c8 2c 80 01 53
++ [10204.220734634] : 20 18 c8 2c 80 01 53
++ [10204.468461664] : 20 18 c8 2c 80 01 53
++
+diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
+index efc3354d60ae..04fb851f2c82 100644
+--- a/drivers/i2c/Kconfig
++++ b/drivers/i2c/Kconfig
+@@ -118,6 +118,29 @@ if I2C_SLAVE
+ config I2C_SLAVE_EEPROM
+ tristate "I2C eeprom slave driver"
+
++config I2C_SLAVE_MQUEUE_MESSAGE_SIZE
++ int "The message size of I2C mqueue slave"
++ default 120
++
++config I2C_SLAVE_MQUEUE_QUEUE_SIZE
++ int "The queue size of I2C mqueue slave"
++ default 32
++ help
++ This number MUST be power of 2.
++
++config I2C_SLAVE_MQUEUE
++ tristate "I2C mqueue (message queue) slave driver"
++ help
++ Some protocols over I2C are designed for bi-directional transferring
++ messages by using I2C Master Write protocol. This driver is used to
++ receive and queue messages from the remote I2C device.
++
++ Userspace can get the messages by reading sysfs file that this driver
++ exposes.
++
++ This support is also available as a module. If so, the module will be
++ called i2c-slave-mqueue.
++
+ endif
+
+ config I2C_DEBUG_CORE
+diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
+index bed6ba63c983..9a31bc75a446 100644
+--- a/drivers/i2c/Makefile
++++ b/drivers/i2c/Makefile
+@@ -16,5 +16,6 @@ obj-$(CONFIG_I2C_MUX) += i2c-mux.o
+ obj-y += algos/ busses/ muxes/
+ obj-$(CONFIG_I2C_STUB) += i2c-stub.o
+ obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o
++obj-$(CONFIG_I2C_SLAVE_MQUEUE) += i2c-slave-mqueue.o
+
+ ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
+diff --git a/drivers/i2c/i2c-slave-mqueue.c b/drivers/i2c/i2c-slave-mqueue.c
+new file mode 100644
+index 000000000000..6014bca0ff2a
+--- /dev/null
++++ b/drivers/i2c/i2c-slave-mqueue.c
+@@ -0,0 +1,217 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2017 - 2018, Intel Corporation.
++
++#include <linux/i2c.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/sysfs.h>
++
++#define MQ_MSGBUF_SIZE CONFIG_I2C_SLAVE_MQUEUE_MESSAGE_SIZE
++#define MQ_QUEUE_SIZE CONFIG_I2C_SLAVE_MQUEUE_QUEUE_SIZE
++#define MQ_QUEUE_NEXT(x) (((x) + 1) & (MQ_QUEUE_SIZE - 1))
++
++struct mq_msg {
++ int len;
++ u8 *buf;
++};
++
++struct mq_queue {
++ struct bin_attribute bin;
++ struct kernfs_node *kn;
++
++ spinlock_t lock; /* spinlock for queue index handling */
++ int in;
++ int out;
++
++ struct mq_msg *curr;
++ int truncated; /* drop current if truncated */
++ struct mq_msg *queue;
++};
++
++static int i2c_slave_mqueue_callback(struct i2c_client *client,
++ enum i2c_slave_event event, u8 *val)
++{
++ struct mq_queue *mq = i2c_get_clientdata(client);
++ struct mq_msg *msg = mq->curr;
++ int ret = 0;
++
++ switch (event) {
++ case I2C_SLAVE_WRITE_REQUESTED:
++ mq->truncated = 0;
++
++ msg->len = 1;
++ msg->buf[0] = client->addr << 1;
++ break;
++
++ case I2C_SLAVE_WRITE_RECEIVED:
++ if (msg->len < MQ_MSGBUF_SIZE) {
++ msg->buf[msg->len++] = *val;
++ } else {
++ dev_err(&client->dev, "message is truncated!\n");
++ mq->truncated = 1;
++ ret = -EINVAL;
++ }
++ break;
++
++ case I2C_SLAVE_STOP:
++ if (unlikely(mq->truncated || msg->len < 2))
++ break;
++
++ spin_lock(&mq->lock);
++ mq->in = MQ_QUEUE_NEXT(mq->in);
++ mq->curr = &mq->queue[mq->in];
++ mq->curr->len = 0;
++
++ /* Flush the oldest message */
++ if (mq->out == mq->in)
++ mq->out = MQ_QUEUE_NEXT(mq->out);
++ spin_unlock(&mq->lock);
++
++ kernfs_notify(mq->kn);
++ break;
++
++ default:
++ *val = 0xFF;
++ break;
++ }
++
++ return ret;
++}
++
++static ssize_t i2c_slave_mqueue_bin_read(struct file *filp,
++ struct kobject *kobj,
++ struct bin_attribute *attr,
++ char *buf, loff_t pos, size_t count)
++{
++ struct mq_queue *mq;
++ struct mq_msg *msg;
++ unsigned long flags;
++ bool more = false;
++ ssize_t ret = 0;
++
++ mq = dev_get_drvdata(container_of(kobj, struct device, kobj));
++
++ spin_lock_irqsave(&mq->lock, flags);
++ if (mq->out != mq->in) {
++ msg = &mq->queue[mq->out];
++
++ if (msg->len <= count) {
++ ret = msg->len;
++ memcpy(buf, msg->buf, ret);
++ } else {
++ ret = -EOVERFLOW; /* Drop this HUGE one. */
++ }
++
++ mq->out = MQ_QUEUE_NEXT(mq->out);
++ if (mq->out != mq->in)
++ more = true;
++ }
++ spin_unlock_irqrestore(&mq->lock, flags);
++
++ if (more)
++ kernfs_notify(mq->kn);
++
++ return ret;
++}
++
++static int i2c_slave_mqueue_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct device *dev = &client->dev;
++ struct mq_queue *mq;
++ int ret, i;
++ void *buf;
++
++ mq = devm_kzalloc(dev, sizeof(*mq), GFP_KERNEL);
++ if (!mq)
++ return -ENOMEM;
++
++ BUILD_BUG_ON(!is_power_of_2(MQ_QUEUE_SIZE));
++
++ buf = devm_kmalloc_array(dev, MQ_QUEUE_SIZE, MQ_MSGBUF_SIZE,
++ GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ mq->queue = devm_kzalloc(dev, sizeof(*mq->queue) * MQ_QUEUE_SIZE,
++ GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ for (i = 0; i < MQ_QUEUE_SIZE; i++)
++ mq->queue[i].buf = buf + i * MQ_MSGBUF_SIZE;
++
++ i2c_set_clientdata(client, mq);
++
++ spin_lock_init(&mq->lock);
++ mq->curr = &mq->queue[0];
++
++ sysfs_bin_attr_init(&mq->bin);
++ mq->bin.attr.name = "slave-mqueue";
++ mq->bin.attr.mode = 0400;
++ mq->bin.read = i2c_slave_mqueue_bin_read;
++ mq->bin.size = MQ_MSGBUF_SIZE * MQ_QUEUE_SIZE;
++
++ ret = sysfs_create_bin_file(&dev->kobj, &mq->bin);
++ if (ret)
++ return ret;
++
++ mq->kn = kernfs_find_and_get(dev->kobj.sd, mq->bin.attr.name);
++ if (!mq->kn) {
++ sysfs_remove_bin_file(&dev->kobj, &mq->bin);
++ return -EFAULT;
++ }
++
++ ret = i2c_slave_register(client, i2c_slave_mqueue_callback);
++ if (ret) {
++ kernfs_put(mq->kn);
++ sysfs_remove_bin_file(&dev->kobj, &mq->bin);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int i2c_slave_mqueue_remove(struct i2c_client *client)
++{
++ struct mq_queue *mq = i2c_get_clientdata(client);
++
++ i2c_slave_unregister(client);
++
++ kernfs_put(mq->kn);
++ sysfs_remove_bin_file(&client->dev.kobj, &mq->bin);
++
++ return 0;
++}
++
++static const struct i2c_device_id i2c_slave_mqueue_id[] = {
++ { "slave-mqueue", 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, i2c_slave_mqueue_id);
++
++#if IS_ENABLED(CONFIG_OF)
++static const struct of_device_id i2c_slave_mqueue_of_match[] = {
++ { .compatible = "slave-mqueue", .data = (void *)0 },
++ { },
++};
++MODULE_DEVICE_TABLE(of, i2c_slave_mqueue_of_match);
++#endif
++
++static struct i2c_driver i2c_slave_mqueue_driver = {
++ .driver = {
++ .name = "i2c-slave-mqueue",
++ .of_match_table = of_match_ptr(i2c_slave_mqueue_of_match),
++ },
++ .probe = i2c_slave_mqueue_probe,
++ .remove = i2c_slave_mqueue_remove,
++ .id_table = i2c_slave_mqueue_id,
++};
++module_i2c_driver(i2c_slave_mqueue_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
++MODULE_DESCRIPTION("I2C slave mode for receiving and queuing messages");
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch
new file mode 100644
index 000000000..95302aae8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch
@@ -0,0 +1,623 @@
+From 7d5cd323d3b05a00f8b8a6eb38a5a1ec7925660a Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@intel.com>
+Date: Mon, 13 Nov 2017 16:29:44 +0800
+Subject: [PATCH] Aspeed LPC SIO driver
+
+Add lpc sio device driver for AST2500/2400
+
+Signed-off-by: Yong Li <yong.b.li@intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ .../devicetree/bindings/misc/aspeed-sio.txt | 18 +
+ arch/arm/boot/dts/aspeed-g4.dtsi | 7 +
+ arch/arm/boot/dts/aspeed-g5.dtsi | 7 +
+ drivers/misc/Kconfig | 9 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/aspeed-lpc-sio.c | 450 +++++++++++++++++++++
+ include/uapi/linux/aspeed-lpc-sio.h | 44 ++
+ 7 files changed, 536 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/misc/aspeed-sio.txt
+ create mode 100644 drivers/misc/aspeed-lpc-sio.c
+ create mode 100644 include/uapi/linux/aspeed-lpc-sio.h
+
+diff --git a/Documentation/devicetree/bindings/misc/aspeed-sio.txt b/Documentation/devicetree/bindings/misc/aspeed-sio.txt
+new file mode 100644
+index 000000000000..3530c2b02f5c
+--- /dev/null
++++ b/Documentation/devicetree/bindings/misc/aspeed-sio.txt
+@@ -0,0 +1,18 @@
++* Aspeed LPC SIO driver.
++
++Required properties:
++- compatible : Should be one of:
++ "aspeed,ast2400-lpc-sio"
++ "aspeed,ast2500-lpc-sio"
++- reg : Should contain lpc-sio registers location and length
++- clocks: contains a phandle to the syscon node describing the clocks.
++ There should then be one cell representing the clock to use.
++
++Example:
++lpc_sio: lpc-sio@100 {
++ compatible = "aspeed,ast2500-lpc-sio";
++ reg = <0x100 0x20>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++};
++
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index e8bcfc90bf7c..a87fd5ee1c84 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -340,6 +340,13 @@
+ compatible = "aspeed,bmc-misc";
+ };
+
++ lpc_sio: lpc-sio@100 {
++ compatible = "aspeed,ast2400-lpc-sio";
++ reg = <0x100 0x20>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
++
+ mbox: mbox@180 {
+ compatible = "aspeed,ast2400-mbox";
+ reg = <0x180 0x5c>;
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index e5c0ba0f87c8..a568699c28f4 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -451,6 +451,13 @@
+ compatible = "aspeed,bmc-misc";
+ };
+
++ lpc_sio: lpc-sio@100 {
++ compatible = "aspeed,ast2500-lpc-sio";
++ reg = <0x100 0x20>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
++
+ mbox: mbox@180 {
+ compatible = "aspeed,ast2500-mbox";
+ reg = <0x180 0x5c>;
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 00d1c547ece7..3ffb18f915e8 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -493,6 +493,15 @@ config ASPEED_LPC_CTRL
+ ioctl()s, the driver also provides a read/write interface to a BMC ram
+ region where the host LPC read/write region can be buffered.
+
++config ASPEED_LPC_SIO
++ depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
++ tristate "Aspeed ast2400/2500 HOST LPC SIO support"
++ help
++ Provides a driver to control the LPC SIO interface
++ on ASPEED platform
++ through
++ ioctl()s.
++
+ config ASPEED_LPC_SNOOP
+ tristate "Aspeed ast2500 HOST LPC snoop support"
+ depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 768278b059c3..de2d5c6d186c 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -56,6 +56,7 @@ obj-$(CONFIG_CXL_BASE) += cxl/
+ obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
+ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
+ obj-$(CONFIG_ASPEED_LPC_MBOX) += aspeed-lpc-mbox.o
++obj-$(CONFIG_ASPEED_LPC_SIO) += aspeed-lpc-sio.o
+ obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
+ obj-$(CONFIG_OCXL) += ocxl/
+ obj-$(CONFIG_MISC_RTSX) += cardreader/
+diff --git a/drivers/misc/aspeed-lpc-sio.c b/drivers/misc/aspeed-lpc-sio.c
+new file mode 100644
+index 000000000000..c717a3182320
+--- /dev/null
++++ b/drivers/misc/aspeed-lpc-sio.c
+@@ -0,0 +1,450 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (C) 2012-2017 ASPEED Technology Inc.
++// Copyright (c) 2017-2019 Intel Corporation
++
++#include <linux/clk.h>
++#include <linux/mfd/syscon.h>
++#include <linux/miscdevice.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/poll.h>
++#include <linux/regmap.h>
++
++#include <linux/aspeed-lpc-sio.h>
++
++#define SOC_NAME "aspeed"
++#define DEVICE_NAME "lpc-sio"
++
++#define AST_LPC_SWCR0300 0x0
++#define LPC_PWRGD_STS (1 << 30)
++#define LPC_PWRGD_RISING_EVT_STS (1 << 29)
++#define LPC_PWRGD_FALLING_EVT_STS (1 << 28)
++#define LPC_PWRBTN_STS (1 << 27)
++#define LPC_PWRBTN_RISING_EVT_STS (1 << 26)
++#define LPC_PWRBTN_FALLING_EVT_STS (1 << 25)
++#define LPC_S5N_STS (1 << 21)
++#define LPC_S5N_RISING_EVT_STS (1 << 20)
++#define LPC_S5N_FALLING_EVT_STS (1 << 19)
++#define LPC_S3N_STS (1 << 18)
++#define LPC_S3N_RISING_EVT_STS (1 << 17)
++#define LPC_S3N_FALLING_EVT_STS (1 << 16)
++#define LPC_PWBTO_RAW_STS (1 << 15)
++#define LPC_LAST_ONCTL_STS (1 << 14)
++#define LPC_WAS_PFAIL_STS (1 << 13)
++#define LPC_POWER_UP_FAIL_STS (1 << 12) /* Crowbar */
++#define LPC_PWRBTN_OVERRIDE_STS (1 << 11)
++
++#define AST_LPC_SWCR0704 0x4
++
++#define AST_LPC_SWCR0B08 0x8
++#define LPC_PWREQ_OUTPUT_LEVEL (1 << 25)
++#define LPC_PWBTO_OUTPUT_LEVEL (1 << 24)
++#define LPC_ONCTL_STS (1 << 15)
++#define LPC_ONCTL_GPIO_LEVEL (1 << 14)
++#define LPC_ONCTL_EN_GPIO_OUTPUT (1 << 13)
++#define LPC_ONCTL_EN_GPIO_MODE (1 << 12)
++
++#define AST_LPC_SWCR0F0C 0xC
++#define AST_LPC_SWCR1310 0x10
++#define AST_LPC_SWCR1714 0x14
++#define AST_LPC_SWCR1B18 0x18
++#define AST_LPC_SWCR1F1C 0x1C
++#define AST_LPC_ACPIE3E0 0x20
++#define AST_LPC_ACPIC1C0 0x24
++#define AST_LPC_ACPIB3B0 0x28
++#define AST_LPC_ACPIB7B4 0x2C
++
++struct aspeed_lpc_sio {
++ struct miscdevice miscdev;
++ struct regmap *regmap;
++ struct clk *clk;
++ struct semaphore lock;
++ unsigned int reg_base;
++};
++
++static struct aspeed_lpc_sio *file_aspeed_lpc_sio(struct file *file)
++{
++ return container_of(file->private_data, struct aspeed_lpc_sio,
++ miscdev);
++}
++
++static int aspeed_lpc_sio_open(struct inode *inode, struct file *filp)
++{
++ return 0;
++}
++
++#define LPC_SLP3N5N_EVENT_STATUS (\
++ LPC_S5N_RISING_EVT_STS | \
++ LPC_S5N_FALLING_EVT_STS | \
++ LPC_S3N_RISING_EVT_STS | \
++ LPC_S3N_FALLING_EVT_STS)
++/*************************************
++ * SLPS3n SLPS5n State
++ * ---------------------------------
++ * 1 1 S12
++ * 0 1 S3I
++ * x 0 S45
++ *************************************
++ */
++
++static long sio_get_acpi_state(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg;
++ u32 val;
++ int rc;
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300;
++ rc = regmap_read(lpc_sio->regmap, reg, &val);
++ if (rc) {
++ dev_err(lpc_sio->miscdev.parent,
++ "regmap_read() failed with %d(reg:0x%x)\n", rc, reg);
++ return rc;
++ }
++
++ /* update the ACPI state event status */
++ if (sio_data->param != 0) {
++ if (val & LPC_SLP3N5N_EVENT_STATUS) {
++ sio_data->param = 1;
++ rc = regmap_write(lpc_sio->regmap, reg,
++ LPC_SLP3N5N_EVENT_STATUS);
++ if (rc) {
++ dev_err(lpc_sio->miscdev.parent,
++ "regmap_write() failed with %d(reg:0x%x)\n",
++ rc, reg);
++ return rc;
++ }
++ } else {
++ sio_data->param = 0;
++ }
++ }
++
++ if ((val & LPC_S3N_STS) && (val & LPC_S5N_STS))
++ sio_data->data = ACPI_STATE_S12;
++ else if ((val & LPC_S3N_STS) == 0 && (val & LPC_S5N_STS))
++ sio_data->data = ACPI_STATE_S3I;
++ else
++ sio_data->data = ACPI_STATE_S45;
++
++ return 0;
++}
++
++#define LPC_PWRGD_EVENT_STATUS ( \
++ LPC_PWRGD_RISING_EVT_STS | \
++ LPC_PWRGD_FALLING_EVT_STS)
++
++static long sio_get_pwrgd_status(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg;
++ u32 val;
++ int rc;
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300;
++ rc = regmap_read(lpc_sio->regmap, reg, &val);
++ if (rc) {
++ dev_err(lpc_sio->miscdev.parent,
++ "regmap_read() failed with %d(reg:0x%x)\n", rc, reg);
++ return rc;
++ }
++
++ /* update the PWRGD event status */
++ if (sio_data->param != 0) {
++ if (val & LPC_PWRGD_EVENT_STATUS) {
++ sio_data->param = 1;
++ rc = regmap_write(lpc_sio->regmap, reg,
++ LPC_PWRGD_EVENT_STATUS);
++ if (rc) {
++ dev_err(lpc_sio->miscdev.parent,
++ "regmap_write() failed with %d(reg:0x%x)\n",
++ rc, reg);
++ return rc;
++ }
++ } else {
++ sio_data->param = 0;
++ }
++ }
++
++ sio_data->data = (val & LPC_PWRGD_STS) != 0 ? 1 : 0;
++
++ return 0;
++}
++
++static long sio_get_onctl_status(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg;
++ u32 val;
++ int rc;
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0B08;
++ rc = regmap_read(lpc_sio->regmap, reg, &val);
++ if (rc) {
++ dev_err(lpc_sio->miscdev.parent,
++ "regmap_read() failed with %d(reg:0x%x)\n", rc, reg);
++ return rc;
++ }
++
++ sio_data->data = (val & LPC_ONCTL_STS) != 0 ? 1 : 0;
++
++ return 0;
++}
++
++static long sio_set_onctl_gpio(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg;
++ u32 val;
++ int rc;
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0B08;
++ rc = regmap_read(lpc_sio->regmap, reg, &val);
++ if (rc) {
++ dev_err(lpc_sio->miscdev.parent,
++ "regmap_read() failed with %d(reg:0x%x)\n", rc, reg);
++ return rc;
++ }
++
++ /* Enable ONCTL GPIO mode */
++ if (sio_data->param != 0) {
++ val |= LPC_ONCTL_EN_GPIO_MODE;
++ val |= LPC_ONCTL_EN_GPIO_OUTPUT;
++
++ if (sio_data->data != 0)
++ val |= LPC_ONCTL_GPIO_LEVEL;
++ else
++ val &= ~LPC_ONCTL_GPIO_LEVEL;
++
++ rc = regmap_write(lpc_sio->regmap, reg, val);
++ if (rc) {
++ dev_err(lpc_sio->miscdev.parent,
++ "regmap_write() failed with %d(reg:0x%x)\n", rc, reg);
++ return rc;
++ }
++ } else {
++ val &= ~LPC_ONCTL_EN_GPIO_MODE;
++ rc = regmap_write(lpc_sio->regmap, reg, val);
++ if (rc) {
++ dev_err(lpc_sio->miscdev.parent,
++ "regmap_write() failed with %d(reg:0x%x)\n", rc, reg);
++ return rc;
++ }
++ }
++
++ return 0;
++}
++
++static long sio_get_pwrbtn_override(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg;
++ u32 val;
++ int rc;
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300;
++ rc = regmap_read(lpc_sio->regmap, reg, &val);
++ if (rc) {
++ dev_err(lpc_sio->miscdev.parent,
++ "regmap_read() failed with %d(reg:0x%x)\n", rc, reg);
++ return rc;
++ }
++
++ /* clear the PWRBTN OVERRIDE status */
++ if (sio_data->param != 0) {
++ if (val & LPC_PWRBTN_OVERRIDE_STS) {
++ rc = regmap_write(lpc_sio->regmap, reg,
++ LPC_PWRBTN_OVERRIDE_STS);
++ if (rc) {
++ dev_err(lpc_sio->miscdev.parent,
++ "regmap_write() failed with %d(reg:0x%x)\n",
++ rc, reg);
++ return rc;
++ }
++ }
++ }
++
++ sio_data->data = (val & LPC_PWRBTN_OVERRIDE_STS) != 0 ? 1 : 0;
++
++ return 0;
++}
++
++static long sio_get_pfail_status(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg;
++ u32 val;
++ int rc;
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300;
++ rc = regmap_read(lpc_sio->regmap, reg, &val);
++ if (rc) {
++ dev_err(lpc_sio->miscdev.parent,
++ "regmap_read() failed with %d(reg:0x%x)\n", rc, reg);
++ return rc;
++ }
++
++ /* [ASPEED]: SWCR_03_00[13] (Was_pfail: default 1) is used to identify
++ * this current booting is from AC loss (not DC loss) if FW cleans this
++ * bit after booting successfully every time.
++ **********************************************************************/
++ if (val & LPC_WAS_PFAIL_STS) {
++ rc = regmap_write(lpc_sio->regmap, reg, 0); /* W0C */
++ if (rc) {
++ dev_err(lpc_sio->miscdev.parent,
++ "regmap_write() failed with %d(reg:0x%x)\n", rc, reg);
++ return rc;
++ }
++ sio_data->data = 1;
++ } else {
++ sio_data->data = 0;
++ }
++
++ return 0;
++}
++
++typedef long (*sio_cmd_fn) (struct aspeed_lpc_sio *sio_dev,
++ struct sio_ioctl_data *sio_data);
++static sio_cmd_fn sio_cmd_handle[SIO_MAX_CMD] = {
++ [SIO_GET_ACPI_STATE] = sio_get_acpi_state,
++ [SIO_GET_PWRGD_STATUS] = sio_get_pwrgd_status,
++ [SIO_GET_ONCTL_STATUS] = sio_get_onctl_status,
++ [SIO_SET_ONCTL_GPIO] = sio_set_onctl_gpio,
++ [SIO_GET_PWRBTN_OVERRIDE] = sio_get_pwrbtn_override,
++ [SIO_GET_PFAIL_STATUS] = sio_get_pfail_status,
++};
++
++static long aspeed_lpc_sio_ioctl(struct file *file, unsigned int cmd,
++ unsigned long param)
++{
++ struct aspeed_lpc_sio *lpc_sio = file_aspeed_lpc_sio(file);
++ long ret;
++ sio_cmd_fn cmd_fn;
++ struct sio_ioctl_data sio_data;
++
++
++ if (copy_from_user(&sio_data, (void __user *)param, sizeof(sio_data)))
++ return -EFAULT;
++
++ if (cmd != SIO_IOC_COMMAND || sio_data.sio_cmd >= SIO_MAX_CMD)
++ return -EINVAL;
++
++ cmd_fn = sio_cmd_handle[sio_data.sio_cmd];
++ if (cmd_fn == NULL)
++ return -EINVAL;
++
++ if (down_interruptible(&lpc_sio->lock) != 0)
++ return -ERESTARTSYS;
++
++ ret = cmd_fn(lpc_sio, &sio_data);
++ if (ret == 0) {
++ if (copy_to_user((void __user *)param, &sio_data,
++ sizeof(sio_data)))
++ ret = -EFAULT;
++ }
++
++ up(&lpc_sio->lock);
++
++ return ret;
++}
++
++static const struct file_operations aspeed_lpc_sio_fops = {
++ .owner = THIS_MODULE,
++ .open = aspeed_lpc_sio_open,
++ .unlocked_ioctl = aspeed_lpc_sio_ioctl,
++};
++
++static int aspeed_lpc_sio_probe(struct platform_device *pdev)
++{
++ struct aspeed_lpc_sio *lpc_sio;
++ struct device *dev;
++ int rc;
++
++ dev = &pdev->dev;
++
++ lpc_sio = devm_kzalloc(dev, sizeof(*lpc_sio), GFP_KERNEL);
++ if (!lpc_sio)
++ return -ENOMEM;
++
++ dev_set_drvdata(&pdev->dev, lpc_sio);
++
++ rc = of_property_read_u32(dev->of_node, "reg", &lpc_sio->reg_base);
++ if (rc) {
++ dev_err(dev, "Couldn't read reg device-tree property\n");
++ return rc;
++ }
++
++ lpc_sio->regmap = syscon_node_to_regmap(
++ pdev->dev.parent->of_node);
++ if (IS_ERR(lpc_sio->regmap)) {
++ dev_err(dev, "Couldn't get regmap\n");
++ return -ENODEV;
++ }
++
++ sema_init(&lpc_sio->lock, 1);
++
++ lpc_sio->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(lpc_sio->clk)) {
++ rc = PTR_ERR(lpc_sio->clk);
++ if (rc != -EPROBE_DEFER)
++ dev_err(dev, "couldn't get clock\n");
++ return rc;
++ }
++ rc = clk_prepare_enable(lpc_sio->clk);
++ if (rc) {
++ dev_err(dev, "couldn't enable clock\n");
++ return rc;
++ }
++
++ lpc_sio->miscdev.minor = MISC_DYNAMIC_MINOR;
++ lpc_sio->miscdev.name = DEVICE_NAME;
++ lpc_sio->miscdev.fops = &aspeed_lpc_sio_fops;
++ lpc_sio->miscdev.parent = dev;
++ rc = misc_register(&lpc_sio->miscdev);
++ if (rc) {
++ dev_err(dev, "Unable to register device\n");
++ goto err;
++ }
++
++ dev_info(dev, "Loaded at %pap (0x%08x)\n", &lpc_sio->regmap,
++ lpc_sio->reg_base);
++
++ return 0;
++
++err:
++ clk_disable_unprepare(lpc_sio->clk);
++
++ return rc;
++}
++
++static int aspeed_lpc_sio_remove(struct platform_device *pdev)
++{
++ struct aspeed_lpc_sio *lpc_sio = dev_get_drvdata(&pdev->dev);
++
++ misc_deregister(&lpc_sio->miscdev);
++ clk_disable_unprepare(lpc_sio->clk);
++
++ return 0;
++}
++
++static const struct of_device_id aspeed_lpc_sio_match[] = {
++ { .compatible = "aspeed,ast2500-lpc-sio" },
++ { },
++};
++MODULE_DEVICE_TABLE(of, aspeed_lpc_sio_match);
++
++static struct platform_driver aspeed_lpc_sio_driver = {
++ .driver = {
++ .name = SOC_NAME "-" DEVICE_NAME,
++ .of_match_table = aspeed_lpc_sio_match,
++ },
++ .probe = aspeed_lpc_sio_probe,
++ .remove = aspeed_lpc_sio_remove,
++};
++module_platform_driver(aspeed_lpc_sio_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
++MODULE_AUTHOR("Yong Li <yong.blli@linux.intel.com>");
++MODULE_DESCRIPTION("ASPEED AST LPC SIO device driver");
+diff --git a/include/uapi/linux/aspeed-lpc-sio.h b/include/uapi/linux/aspeed-lpc-sio.h
+new file mode 100644
+index 000000000000..5dc1efd4a426
+--- /dev/null
++++ b/include/uapi/linux/aspeed-lpc-sio.h
+@@ -0,0 +1,44 @@
++/*
++ * Copyright (C) 2012-2020 ASPEED Technology Inc.
++ * Copyright (c) 2017 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ */
++
++#ifndef _UAPI_LINUX_ASPEED_LPC_SIO_H
++#define _UAPI_LINUX_ASPEED_LPC_SIO_H
++
++#include <linux/ioctl.h>
++
++enum ACPI_SLP_STATE {
++ ACPI_STATE_S12 = 1,
++ ACPI_STATE_S3I,
++ ACPI_STATE_S45
++};
++
++/* SWC & ACPI for SuperIO IOCTL */
++enum SIO_CMD {
++ SIO_GET_ACPI_STATE = 0,
++ SIO_GET_PWRGD_STATUS,
++ SIO_GET_ONCTL_STATUS,
++ SIO_SET_ONCTL_GPIO,
++ SIO_GET_PWRBTN_OVERRIDE,
++ SIO_GET_PFAIL_STATUS, /* Start from AC Loss */
++
++ SIO_MAX_CMD
++};
++
++struct sio_ioctl_data {
++ unsigned short sio_cmd;
++ unsigned short param;
++ unsigned int data;
++};
++
++#define SIO_IOC_BASE 'P'
++#define SIO_IOC_COMMAND _IOWR(SIO_IOC_BASE, 1, struct sio_ioctl_data)
++
++#endif /* _UAPI_LINUX_ASPEED_LPC_SIO_H */
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch
new file mode 100644
index 000000000..120adbbc8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch
@@ -0,0 +1,597 @@
+From a01815b4bb983ede71993d6c761dedd22d148b6b Mon Sep 17 00:00:00 2001
+From: Haiyue Wang <haiyue.wang@linux.intel.com>
+Date: Sat, 24 Feb 2018 11:12:32 +0800
+Subject: [PATCH] eSPI: add ASPEED AST2500 eSPI driver to boot a host with PCH
+ runs on eSPI
+
+When PCH works under eSPI mode, the PMC (Power Management Controller) in
+PCH is waiting for SUS_ACK from BMC after it alerts SUS_WARN. It is in
+dead loop if no SUS_ACK assert. This is the basic requirement for the BMC
+works as eSPI slave.
+
+Also for the host power on / off actions, from BMC side, the following VW
+(Virtual Wire) messages are done in firmware:
+1. SLAVE_BOOT_LOAD_DONE / SLAVE_BOOT_LOAD_STATUS
+2. SUS_ACK
+3. OOB_RESET_ACK
+4. HOST_RESET_ACK
+
+Signed-off-by: Haiyue Wang <haiyue.wang@linux.intel.com>
+---
+ .../devicetree/bindings/misc/aspeed,espi-slave.txt | 20 ++
+ Documentation/misc-devices/espi-slave.rst | 119 +++++++
+ arch/arm/boot/dts/aspeed-g5.dtsi | 4 +
+ drivers/misc/Kconfig | 8 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/aspeed-espi-slave.c | 353 +++++++++++++++++++++
+ 6 files changed, 505 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt
+ create mode 100644 Documentation/misc-devices/espi-slave.rst
+ create mode 100644 drivers/misc/aspeed-espi-slave.c
+
+diff --git a/Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt b/Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt
+new file mode 100644
+index 000000000000..4f5d47ecc882
+--- /dev/null
++++ b/Documentation/devicetree/bindings/misc/aspeed,espi-slave.txt
+@@ -0,0 +1,20 @@
++ASPEED eSPI Slave Controller
++
++Required properties:
++ - compatible: must be one of:
++ - "aspeed,ast2500-espi-slave"
++
++ - reg: physical base address of the controller and length of memory mapped
++ region
++
++ - interrupts: interrupt generated by the controller
++
++Example:
++
++ espi: espi@1e6ee000 {
++ compatible = "aspeed,ast2500-espi-slave";
++ reg = <0x1e6ee000 0x100>;
++ interrupts = <23>;
++ status = "disabled";
++};
++
+diff --git a/Documentation/misc-devices/espi-slave.rst b/Documentation/misc-devices/espi-slave.rst
+new file mode 100644
+index 000000000000..185acd71bd26
+--- /dev/null
++++ b/Documentation/misc-devices/espi-slave.rst
+@@ -0,0 +1,119 @@
++.. SPDX-License-Identifier: GPL-2.0
++
++==========
++eSPI Slave
++==========
++
++:Author: Haiyue Wang <haiyue.wang@linux.intel.com>
++
++The PCH (**eSPI master**) provides the eSPI to support connection of a
++BMC (**eSPI slave**) to the platform.
++
++The LPC and eSPI interfaces are mutually exclusive. Both use the same
++pins, but on power-up, a HW strap determines if the eSPI or the LPC bus
++is operational. Once selected, it’s not possible to change to the other
++interface.
++
++``eSPI Channels and Supported Transactions``
++ +------+---------------------+----------------------+--------------------+
++ | CH # | Channel | Posted Cycles | Non-Posted Cycles |
++ +======+=====================+======================+====================+
++ | 0 | Peripheral | Memory Write, | Memory Read, |
++ | | | Completions | I/O Read/Write |
++ +------+---------------------+----------------------+--------------------+
++ | 1 | Virtual Wire | Virtual Wire GET/PUT | N/A |
++ +------+---------------------+----------------------+--------------------+
++ | 2 | Out-of-Band Message | SMBus Packet GET/PUT | N/A |
++ +------+---------------------+----------------------+--------------------+
++ | 3 | Flash Access | N/A | Flash Read, Write, |
++ | | | | Erase |
++ +------+---------------------+----------------------+--------------------+
++ | N/A | General | Register Accesses | N/A |
++ +------+---------------------+----------------------+--------------------+
++
++Virtual Wire Channel (Channel 1) Overview
++-----------------------------------------
++
++The Virtual Wire channel uses a standard message format to communicate
++several types of signals between the components on the platform::
++
++ - Sideband and GPIO Pins: System events and other dedicated signals
++ between the PCH and eSPI slave. These signals are tunneled between the
++ two components over eSPI.
++
++ - Serial IRQ Interrupts: Interrupts are tunneled from the eSPI slave to
++ the PCH. Both edge and triggered interrupts are supported.
++
++When PCH runs on eSPI mode, from BMC side, the following VW messages are
++done in firmware::
++
++ 1. SLAVE_BOOT_LOAD_DONE / SLAVE_BOOT_LOAD_STATUS
++ 2. SUS_ACK
++ 3. OOB_RESET_ACK
++ 4. HOST_RESET_ACK
++
++``eSPI Virtual Wires (VW)``
++ +----------------------+---------+---------------------------------------+
++ |Virtual Wire |PCH Pin |Comments |
++ | |Direction| |
++ +======================+=========+=======================================+
++ |SUS_WARN# |Output |PCH pin is a GPIO when eSPI is enabled.|
++ | | |eSPI controller receives as VW message.|
++ +----------------------+---------+---------------------------------------+
++ |SUS_ACK# |Input |PCH pin is a GPIO when eSPI is enabled.|
++ | | |eSPI controller receives as VW message.|
++ +----------------------+---------+---------------------------------------+
++ |SLAVE_BOOT_LOAD_DONE |Input |Sent when the BMC has completed its |
++ | | |boot process as an indication to |
++ | | |eSPI-MC to continue with the G3 to S0 |
++ | | |exit. |
++ | | |The eSPI Master waits for the assertion|
++ | | |of this virtual wire before proceeding |
++ | | |with the SLP_S5# deassertion. |
++ | | |The intent is that it is never changed |
++ | | |except on a G3 exit - it is reset on a |
++ | | |G3 entry. |
++ +----------------------+---------+---------------------------------------+
++ |SLAVE_BOOT_LOAD_STATUS|Input |Sent upon completion of the Slave Boot |
++ | | |Load from the attached flash. A stat of|
++ | | |1 indicates that the boot code load was|
++ | | |successful and that the integrity of |
++ | | |the image is intact. |
++ +----------------------+---------+---------------------------------------+
++ |HOST_RESET_WARN |Output |Sent from the MC just before the Host |
++ | | |is about to enter reset. Upon receiving|
++ | | |, the BMC must flush and quiesce its |
++ | | |upstream Peripheral Channel request |
++ | | |queues and assert HOST_RESET_ACK VWire.|
++ | | |The MC subsequently completes any |
++ | | |outstanding posted transactions or |
++ | | |completions and then disables the |
++ | | |Peripheral Channel via a write to |
++ | | |the Slave's Configuration Register. |
++ +----------------------+---------+---------------------------------------+
++ |HOST_RESET_ACK |Input |ACK for the HOST_RESET_WARN message |
++ +----------------------+---------+---------------------------------------+
++ |OOB_RESET_WARN |Output |Sent from the MC just before the OOB |
++ | | |processor is about to enter reset. Upon|
++ | | |receiving, the BMC must flush and |
++ | | |quiesce its OOB Channel upstream |
++ | | |request queues and assert OOB_RESET_ACK|
++ | | |VWire. The-MC subsequently completes |
++ | | |any outstanding posted transactions or |
++ | | |completions and then disables the OOB |
++ | | |Channel via a write to the Slave's |
++ | | |Configuration Register. |
++ +----------------------+---------+---------------------------------------+
++ |OOB_RESET_ACK |Input |ACK for OOB_RESET_WARN message |
++ +----------------------+---------+---------------------------------------+
++
++`Intel C620 Series Chipset Platform Controller Hub
++<https://www.intel.com/content/www/us/en/chipsets/c620-series-chipset-datasheet.html>`_
++
++ -- 17. Enhanced Serial Peripheral Interface
++
++
++`Enhanced Serial Peripheral Interface (eSPI)
++- Interface Base Specification (for Client and Server Platforms)
++<https://www.intel.com/content/dam/support/us/en/documents/software/chipset-software/327432-004_espi_base_specification_rev1.0.pdf>`_
++
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index 4a302d745b09..165a2bddc6cd 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -266,6 +266,7 @@
+ clocks = <&syscon ASPEED_CLK_APB>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
++ status = "disabled";
+ };
+
+ sgpio: sgpio@1e780200 {
+@@ -360,6 +361,9 @@
+ reg = <0x1e6ee000 0x100>;
+ interrupts = <23>;
+ status = "disabled";
++ clocks = <&syscon ASPEED_CLK_GATE_ESPICLK>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_espi_default>;
+ };
+
+ lpc: lpc@1e789000 {
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index fe1e2a4072a8..f2062546250c 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -485,6 +485,14 @@ config VEXPRESS_SYSCFG
+ bus. System Configuration interface is one of the possible means
+ of generating transactions on this bus.
+
++config ASPEED_ESPI_SLAVE
++ depends on ARCH_ASPEED || COMPILE_TEST
++ depends on REGMAP_MMIO
++ tristate "Aspeed ast2500 eSPI slave device driver"
++ ---help---
++ Control Aspeed ast2500 eSPI slave controller to handle event
++ which needs the firmware's processing.
++
+ config ASPEED_LPC_CTRL
+ depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
+ tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control"
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index a2b85ec21d09..bb89694e6b4b 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -53,6 +53,7 @@ obj-$(CONFIG_GENWQE) += genwqe/
+ obj-$(CONFIG_ECHO) += echo/
+ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
+ obj-$(CONFIG_CXL_BASE) += cxl/
++obj-$(CONFIG_ASPEED_ESPI_SLAVE) += aspeed-espi-slave.o
+ obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
+ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
+ obj-$(CONFIG_ASPEED_LPC_MBOX) += aspeed-lpc-mbox.o
+diff --git a/drivers/misc/aspeed-espi-slave.c b/drivers/misc/aspeed-espi-slave.c
+new file mode 100644
+index 000000000000..36ae867ca6f9
+--- /dev/null
++++ b/drivers/misc/aspeed-espi-slave.c
+@@ -0,0 +1,353 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2012-2015, ASPEED Technology Inc.
++ * Copyright (c) 2015-2018, Intel Corporation.
++ */
++
++#include <linux/atomic.h>
++#include <linux/clk.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/poll.h>
++#include <linux/regmap.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/timer.h>
++
++#define DEVICE_NAME "aspeed-espi-slave"
++
++#define ESPI_CTRL 0x00
++#define ESPI_CTRL_SW_RESET GENMASK(31, 24)
++#define ESPI_CTRL_OOB_CHRDY BIT(4)
++#define ESPI_ISR 0x08
++#define ESPI_ISR_HW_RESET BIT(31)
++#define ESPI_ISR_VW_SYS_EVT1 BIT(22)
++#define ESPI_ISR_VW_SYS_EVT BIT(8)
++#define ESPI_IER 0x0C
++#define ESPI_DATA_PORT 0x28
++#define ESPI_DATA_PORT_ASPEED 0xa8
++#define ESPI_SYS_IER 0x94
++#define ESPI_SYS_EVENT 0x98
++#define ESPI_SYS_INT_T0 0x110
++#define ESPI_SYS_INT_T1 0x114
++#define ESPI_SYS_INT_T2 0x118
++#define ESPI_SYS_ISR 0x11C
++#define ESPI_SYSEVT_HOST_RST_ACK BIT(27)
++#define ESPI_SYSEVT_SLAVE_BOOT_STATUS BIT(23)
++#define ESPI_SYSEVT_SLAVE_BOOT_DONE BIT(20)
++#define ESPI_SYSEVT_OOB_RST_ACK BIT(16)
++#define ESPI_SYSEVT_HOST_RST_WARN BIT(8)
++#define ESPI_SYSEVT_OOB_RST_WARN BIT(6)
++#define ESPI_SYSEVT_PLT_RST_N BIT(5)
++#define ESPI_SYS1_IER 0x100
++#define ESPI_SYS1_EVENT 0x104
++#define ESPI_SYS1_INT_T0 0x120
++#define ESPI_SYS1_INT_T1 0x124
++#define ESPI_SYS1_INT_T2 0x128
++#define ESPI_SYS1_ISR 0x12C
++#define ESPI_SYSEVT1_SUS_ACK BIT(20)
++#define ESPI_SYSEVT1_SUS_WARN BIT(0)
++
++struct aspeed_espi_slave_data {
++ struct regmap *map;
++ struct clk *clk;
++};
++
++static void aspeed_espi_slave_sys_event(struct platform_device *pdev)
++{
++ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev);
++ struct device *dev = &pdev->dev;
++ u32 sts, evt;
++
++ if (regmap_read(priv->map, ESPI_SYS_ISR, &sts) != 0 ||
++ regmap_read(priv->map, ESPI_SYS_EVENT, &evt) != 0) {
++ dev_err(dev, "regmap_read failed\n");
++ return;
++ }
++
++ dev_dbg(dev, "sys: sts = %08x, evt = %08x\n", sts, evt);
++
++ if ((evt & ESPI_SYSEVT_SLAVE_BOOT_STATUS) == 0) {
++ dev_info(dev, "Setting espi slave boot done\n");
++ regmap_write(priv->map, ESPI_SYS_EVENT,
++ evt | ESPI_SYSEVT_SLAVE_BOOT_STATUS |
++ ESPI_SYSEVT_SLAVE_BOOT_DONE);
++ }
++#if 0
++ if (sts & ESPI_SYSEVT_HOST_RST_WARN) {
++ dev_info(dev, "ESPI_SYSEVT_HOST_RST_WARN; %s ack\n",
++ (evt & ESPI_SYSEVT_HOST_RST_WARN ? "send" : "clr"));
++ regmap_write_bits(priv->map, ESPI_SYS_EVENT,
++ ESPI_SYSEVT_HOST_RST_ACK,
++ evt & ESPI_SYSEVT_HOST_RST_WARN ?
++ ESPI_SYSEVT_HOST_RST_ACK : 0);
++ }
++ if (sts & ESPI_SYSEVT_OOB_RST_WARN) {
++ dev_info(dev, "ESPI_SYSEVT_OOB_RST_WARN; %s ack\n",
++ (evt & ESPI_SYSEVT_OOB_RST_WARN ? "send" : "clr"));
++ regmap_write_bits(priv->map, ESPI_SYS_EVENT,
++ ESPI_SYSEVT_OOB_RST_ACK,
++ evt & ESPI_SYSEVT_OOB_RST_WARN ?
++ ESPI_SYSEVT_OOB_RST_ACK : 0);
++ }
++#else
++ if (sts & ESPI_SYSEVT_HOST_RST_WARN) {
++ if (evt & ESPI_SYSEVT_HOST_RST_WARN) {
++ dev_info(dev, "ESPI_SYSEVT_HOST_RST_WARN; send ack\n");
++ regmap_write_bits(priv->map, ESPI_SYS_EVENT,
++ ESPI_SYSEVT_HOST_RST_ACK, ESPI_SYSEVT_HOST_RST_ACK);
++ }
++ }
++ if (sts & ESPI_SYSEVT_OOB_RST_WARN) {
++ if (evt & ESPI_SYSEVT_OOB_RST_WARN) {
++ dev_info(dev, "ESPI_SYSEVT_OOB_RST_WARN; send ack\n");
++ regmap_write_bits(priv->map, ESPI_SYS_EVENT,
++ ESPI_SYSEVT_OOB_RST_ACK, ESPI_SYSEVT_OOB_RST_ACK);
++ }
++ }
++#endif
++ regmap_write(priv->map, ESPI_SYS_ISR, sts);
++}
++
++static void aspeed_espi_slave_sys1_event(struct platform_device *pdev)
++{
++ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev);
++ struct device *dev = &pdev->dev;
++ u32 sts, evt;
++
++ if (regmap_read(priv->map, ESPI_SYS1_ISR, &sts) != 0 ||
++ regmap_read(priv->map, ESPI_SYS1_EVENT, &evt) != 0) {
++ dev_err(dev, "regmap_read failed\n");
++ return;
++ }
++ dev_dbg(dev, "sys1: sts = %08x, evt = %08x\n", sts, evt);
++
++#if 0
++ if (sts & ESPI_SYSEVT1_SUS_WARN) {
++ dev_info(dev, "ESPI_SYSEVT1_SUS_WARN; %s ack\n",
++ (evt & ESPI_SYSEVT1_SUS_WARN ? "send" : "clr"));
++ regmap_write_bits(priv->map, ESPI_SYS1_EVENT,
++ ESPI_SYSEVT1_SUS_ACK,
++ evt & ESPI_SYSEVT1_SUS_WARN ?
++ ESPI_SYSEVT1_SUS_ACK : 0);
++ }
++#else
++ if (sts & ESPI_SYSEVT1_SUS_WARN) {
++ if (evt & ESPI_SYSEVT1_SUS_WARN) {
++ dev_info(dev, "ESPI_SYSEVT_OOB_RST_WARN; send ack\n");
++ regmap_write_bits(priv->map, ESPI_SYS1_EVENT,
++ ESPI_SYSEVT1_SUS_ACK, ESPI_SYSEVT1_SUS_ACK);
++ }
++ }
++#endif
++ regmap_write(priv->map, ESPI_SYS1_ISR, sts);
++}
++
++static void aspeed_espi_slave_boot_ack(struct platform_device *pdev)
++{
++ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev);
++ struct device *dev = &pdev->dev;
++ u32 evt;
++
++ if (regmap_read(priv->map, ESPI_SYS_EVENT, &evt) == 0 &&
++ (evt & ESPI_SYSEVT_SLAVE_BOOT_STATUS) == 0) {
++ dev_info(dev, "Setting espi slave boot done\n");
++ regmap_write(priv->map, ESPI_SYS_EVENT,
++ evt | ESPI_SYSEVT_SLAVE_BOOT_STATUS |
++ ESPI_SYSEVT_SLAVE_BOOT_DONE);
++ }
++
++ if (regmap_read(priv->map, ESPI_SYS1_EVENT, &evt) == 0 &&
++ (evt & ESPI_SYSEVT1_SUS_WARN) != 0 &&
++ (evt & ESPI_SYSEVT1_SUS_ACK) == 0) {
++ dev_info(dev, "Boot SUS WARN set; send ack\n");
++ regmap_write(priv->map, ESPI_SYS1_EVENT,
++ evt | ESPI_SYSEVT1_SUS_ACK);
++ }
++}
++
++static irqreturn_t aspeed_espi_slave_irq(int irq, void *arg)
++{
++ struct platform_device *pdev = arg;
++ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev);
++ struct device *dev = &pdev->dev;
++ u32 sts;
++
++ if (regmap_read(priv->map, ESPI_ISR, &sts) != 0) {
++ dev_err(dev, "regmap_read failed\n");
++ return IRQ_NONE;
++ }
++
++ dev_dbg(dev, "ESPI_ISR: %08x\n", sts);
++
++ if (sts & ESPI_ISR_VW_SYS_EVT)
++ aspeed_espi_slave_sys_event(pdev);
++
++ if (sts & ESPI_ISR_VW_SYS_EVT1)
++ aspeed_espi_slave_sys1_event(pdev);
++
++ /*
++ if (sts & ESPI_ISR_HW_RESET) {
++ regmap_write_bits(priv->map, ESPI_CTRL,
++ ESPI_CTRL_SW_RESET, 0);
++ regmap_write_bits(priv->map, ESPI_CTRL,
++ ESPI_CTRL_SW_RESET, ESPI_CTRL_SW_RESET);
++
++ aspeed_espi_slave_boot_ack(pdev);
++ }
++ */
++
++ regmap_write(priv->map, ESPI_ISR, sts);
++
++ return IRQ_HANDLED;
++}
++
++/* Setup Interrupt Type/Enable of System Event from Master
++ * T2 T1 T0
++ * 1). HOST_RST_WARN : Dual Edge 1 0 0
++ * 2). OOB_RST_WARN : Dual Edge 1 0 0
++ * 3). PLTRST_N : Dual Edge 1 0 0
++ */
++#define ESPI_SYS_INT_T0_SET 0x00000000
++#define ESPI_SYS_INT_T1_SET 0x00000000
++#define ESPI_SYS_INT_T2_SET \
++(ESPI_SYSEVT_HOST_RST_WARN | ESPI_SYSEVT_OOB_RST_WARN | ESPI_SYSEVT_PLT_RST_N)
++#define ESPI_SYS_INT_SET \
++(ESPI_SYSEVT_HOST_RST_WARN | ESPI_SYSEVT_OOB_RST_WARN | ESPI_SYSEVT_PLT_RST_N)
++
++/* Setup Interrupt Type/Enable of System Event 1 from Master
++ * T2 T1 T0
++ * 1). SUS_WARN : Rising Edge 0 0 1
++ */
++#define ESPI_SYS1_INT_T0_SET ESPI_SYSEVT1_SUS_WARN
++#define ESPI_SYS1_INT_T1_SET 0x00000000
++#define ESPI_SYS1_INT_T2_SET 0x00000000
++#define ESPI_SYS1_INT_SET ESPI_SYSEVT1_SUS_WARN
++
++static int aspeed_espi_slave_config_irq(struct platform_device *pdev)
++{
++ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev);
++ struct device *dev = &pdev->dev;
++ int irq;
++ int rc;
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0)
++ return irq;
++
++ regmap_write_bits(priv->map, ESPI_CTRL, ESPI_CTRL_OOB_CHRDY,
++ ESPI_CTRL_OOB_CHRDY);
++
++ regmap_write(priv->map, ESPI_SYS_INT_T0, ESPI_SYS_INT_T0_SET);
++ regmap_write(priv->map, ESPI_SYS_INT_T1, ESPI_SYS_INT_T1_SET);
++ regmap_write(priv->map, ESPI_SYS_INT_T2, ESPI_SYS_INT_T2_SET);
++ regmap_write(priv->map, ESPI_SYS_IER, ESPI_SYS_INT_SET);
++
++ regmap_write(priv->map, ESPI_SYS1_INT_T0, ESPI_SYS1_INT_T0_SET);
++ regmap_write(priv->map, ESPI_SYS1_INT_T1, ESPI_SYS1_INT_T1_SET);
++ regmap_write(priv->map, ESPI_SYS1_INT_T2, ESPI_SYS1_INT_T2_SET);
++ regmap_write(priv->map, ESPI_SYS1_IER, ESPI_SYS1_INT_SET);
++
++ regmap_write(priv->map, ESPI_IER, 0xFFFFFFFF);
++
++ aspeed_espi_slave_boot_ack(pdev);
++
++ rc = devm_request_irq(dev, irq, aspeed_espi_slave_irq, IRQF_SHARED,
++ dev_name(dev), pdev);
++ if (rc < 0)
++ return rc;
++
++ return 0;
++}
++
++static const struct regmap_config espi_slave_regmap_cfg = {
++ .reg_bits = 32,
++ .reg_stride = 4,
++ .val_bits = 32,
++ .max_register = ESPI_SYS1_ISR,
++};
++
++static int aspeed_espi_slave_probe(struct platform_device *pdev)
++{
++ struct aspeed_espi_slave_data *priv;
++ struct device *dev = &pdev->dev;
++ struct resource *res;
++ void __iomem *regs;
++ int rc;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ regs = devm_ioremap_resource(dev, res);
++ if (IS_ERR(regs))
++ return PTR_ERR(regs);
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ priv->map = devm_regmap_init_mmio(dev, regs, &espi_slave_regmap_cfg);
++ if (IS_ERR(priv->map))
++ return PTR_ERR(priv->map);
++
++ priv->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(priv->clk)) {
++ dev_err(dev, "couldn't get clock\n");
++ return PTR_ERR(priv->clk);
++ }
++ rc = clk_prepare_enable(priv->clk);
++ if (rc) {
++ dev_err(dev, "couldn't enable clock\n");
++ return rc;
++ }
++
++ dev_set_name(dev, DEVICE_NAME);
++
++ platform_set_drvdata(pdev, priv);
++
++ rc = aspeed_espi_slave_config_irq(pdev);
++ if (rc) {
++ platform_set_drvdata(pdev, NULL);
++ goto err;
++ }
++
++ dev_info(dev, "aspeed,ast2500-espi-slave probe complete\n");
++ return 0;
++
++err:
++ clk_disable_unprepare(priv->clk);
++ return rc;
++}
++
++
++static int aspeed_espi_slave_remove(struct platform_device *pdev)
++{
++ struct aspeed_espi_slave_data *priv = platform_get_drvdata(pdev);
++
++ clk_disable_unprepare(priv->clk);
++
++ return 0;
++}
++
++static const struct of_device_id of_espi_slave_match_table[] = {
++ { .compatible = "aspeed,ast2500-espi-slave" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, of_espi_slave_match_table);
++
++static struct platform_driver aspeed_espi_slave_driver = {
++ .driver = {
++ .name = DEVICE_NAME,
++ .of_match_table = of_match_ptr(of_espi_slave_match_table),
++ },
++ .probe = aspeed_espi_slave_probe,
++ .remove = aspeed_espi_slave_remove,
++};
++module_platform_driver(aspeed_espi_slave_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
++MODULE_DESCRIPTION("Linux device interface to the eSPI slave");
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch
new file mode 100644
index 000000000..922a45787
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch
@@ -0,0 +1,387 @@
+From 23a7407c3f1bab7c01b93eeced4e137601ac1c94 Mon Sep 17 00:00:00 2001
+From: "Jason M. Bills" <jason.m.bills@intel.com>
+Date: Wed, 4 Apr 2018 13:52:39 -0700
+Subject: [PATCH] Add support for new PECI commands
+
+Signed-off-by: Jason M. Bills <jason.m.bills@intel.com>
+---
+ drivers/peci/peci-core.c | 223 ++++++++++++++++++++++++++++++++++++++++
+ include/uapi/linux/peci-ioctl.h | 102 ++++++++++++++++++
+ 2 files changed, 325 insertions(+)
+
+diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c
+index 14048a13ef8a..2f7e795158ce 100644
+--- a/drivers/peci/peci-core.c
++++ b/drivers/peci/peci-core.c
+@@ -344,6 +344,9 @@ static int peci_scan_cmd_mask(struct peci_adapter *adapter)
+ adapter->cmd_mask |= BIT(PECI_CMD_GET_TEMP);
+ adapter->cmd_mask |= BIT(PECI_CMD_GET_DIB);
+ adapter->cmd_mask |= BIT(PECI_CMD_PING);
++ adapter->cmd_mask |= BIT(PECI_CMD_RD_END_PT_CFG);
++ adapter->cmd_mask |= BIT(PECI_CMD_CRASHDUMP_DISC);
++ adapter->cmd_mask |= BIT(PECI_CMD_CRASHDUMP_GET_FRAME);
+
+ out:
+ peci_put_xfer_msg(msg);
+@@ -686,6 +689,223 @@ static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
+ return ret;
+ }
+
++static int peci_cmd_rd_end_pt_cfg(struct peci_adapter *adapter, void *vmsg)
++{
++ struct peci_rd_end_pt_cfg_msg *umsg = vmsg;
++ struct peci_xfer_msg *msg = NULL;
++ u32 address;
++ int ret;
++
++ switch (umsg->msg_type) {
++ case PECI_RDENDPTCFG_TYPE_LOCAL_PCI:
++ case PECI_RDENDPTCFG_TYPE_PCI:
++ /*
++ * Per the PECI spec, the read length must be a byte, word,
++ * or dword
++ */
++ if (umsg->rx_len != 1 && umsg->rx_len != 2 &&
++ umsg->rx_len != 4) {
++ dev_dbg(&adapter->dev,
++ "Invalid read length, rx_len: %d\n",
++ umsg->rx_len);
++ return -EINVAL;
++ }
++
++ msg = peci_get_xfer_msg(PECI_RDENDPTCFG_PCI_WRITE_LEN,
++ PECI_RDENDPTCFG_READ_LEN_BASE +
++ umsg->rx_len);
++ if (!msg)
++ return -ENOMEM;
++
++ address = umsg->params.pci_cfg.reg; /* [11:0] - Register */
++ address |= (u32)umsg->params.pci_cfg.function
++ << 12; /* [14:12] - Function */
++ address |= (u32)umsg->params.pci_cfg.device
++ << 15; /* [19:15] - Device */
++ address |= (u32)umsg->params.pci_cfg.bus
++ << 20; /* [27:20] - Bus */
++ /* [31:28] - Reserved */
++ msg->addr = umsg->addr;
++ msg->tx_buf[0] = PECI_RDENDPTCFG_CMD;
++ msg->tx_buf[1] = 0x00; /* request byte for Host ID|Retry bit */
++ msg->tx_buf[2] = umsg->msg_type; /* Message Type */
++ msg->tx_buf[3] = 0x00; /* Endpoint ID */
++ msg->tx_buf[4] = 0x00; /* Reserved */
++ msg->tx_buf[5] = 0x00; /* Reserved */
++ msg->tx_buf[6] = PECI_RDENDPTCFG_ADDR_TYPE_PCI; /* Addr Type */
++ msg->tx_buf[7] = umsg->params.pci_cfg.seg; /* PCI Segment */
++ msg->tx_buf[8] = (u8)address; /* LSB - PCI Config Address */
++ msg->tx_buf[9] = (u8)(address >> 8); /* PCI Config Address */
++ msg->tx_buf[10] = (u8)(address >> 16); /* PCI Config Address */
++ msg->tx_buf[11] =
++ (u8)(address >> 24); /* MSB - PCI Config Address */
++ break;
++
++ case PECI_RDENDPTCFG_TYPE_MMIO:
++ /*
++ * Per the PECI spec, the read length must be a byte, word,
++ * dword, or qword
++ */
++ if (umsg->rx_len != 1 && umsg->rx_len != 2 &&
++ umsg->rx_len != 4 && umsg->rx_len != 8) {
++ dev_dbg(&adapter->dev,
++ "Invalid read length, rx_len: %d\n",
++ umsg->rx_len);
++ return -EINVAL;
++ }
++ /*
++ * Per the PECI spec, the address type must specify either DWORD
++ * or QWORD
++ */
++ if (umsg->params.mmio.addr_type !=
++ PECI_RDENDPTCFG_ADDR_TYPE_MMIO_D &&
++ umsg->params.mmio.addr_type !=
++ PECI_RDENDPTCFG_ADDR_TYPE_MMIO_Q) {
++ dev_dbg(&adapter->dev,
++ "Invalid address type, addr_type: %d\n",
++ umsg->params.mmio.addr_type);
++ return -EINVAL;
++ }
++
++ msg = peci_get_xfer_msg(PECI_RDENDPTCFG_MMIO_D_WRITE_LEN,
++ PECI_RDENDPTCFG_READ_LEN_BASE +
++ umsg->rx_len);
++ if (!msg)
++ return -ENOMEM;
++
++ address = umsg->params.mmio.function; /* [2:0] - Function */
++ address |= (u32)umsg->params.mmio.device
++ << 3; /* [7:3] - Device */
++
++ msg->addr = umsg->addr;
++ msg->tx_buf[0] = PECI_RDENDPTCFG_CMD;
++ msg->tx_buf[1] = 0x00; /* request byte for Host ID|Retry bit */
++ msg->tx_buf[2] = umsg->msg_type; /* Message Type */
++ msg->tx_buf[3] = 0x00; /* Endpoint ID */
++ msg->tx_buf[4] = 0x00; /* Reserved */
++ msg->tx_buf[5] = umsg->params.mmio.bar; /* BAR # */
++ msg->tx_buf[6] = umsg->params.mmio.addr_type; /* Address Type */
++ msg->tx_buf[7] = umsg->params.mmio.seg; /* PCI Segment */
++ msg->tx_buf[8] = (u8)address; /* Function/Device */
++ msg->tx_buf[9] = umsg->params.mmio.bus; /* PCI Bus */
++ msg->tx_buf[10] = (u8)umsg->params.mmio
++ .offset; /* LSB - Register Offset */
++ msg->tx_buf[11] = (u8)(umsg->params.mmio.offset
++ >> 8); /* Register Offset */
++ msg->tx_buf[12] = (u8)(umsg->params.mmio.offset
++ >> 16); /* Register Offset */
++ msg->tx_buf[13] = (u8)(umsg->params.mmio.offset
++ >> 24); /* MSB - DWORD Register Offset */
++ if (umsg->params.mmio.addr_type ==
++ PECI_RDENDPTCFG_ADDR_TYPE_MMIO_Q) {
++ msg->tx_len = PECI_RDENDPTCFG_MMIO_Q_WRITE_LEN;
++ msg->tx_buf[14] = (u8)(umsg->params.mmio.offset
++ >> 32); /* Register Offset */
++ msg->tx_buf[15] = (u8)(umsg->params.mmio.offset
++ >> 40); /* Register Offset */
++ msg->tx_buf[16] = (u8)(umsg->params.mmio.offset
++ >> 48); /* Register Offset */
++ msg->tx_buf[17] =
++ (u8)(umsg->params.mmio.offset
++ >> 56); /* MSB - QWORD Register Offset */
++ }
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ ret = peci_xfer_with_retries(adapter, msg, false);
++ if (!ret)
++ memcpy(umsg->data, &msg->rx_buf[1], umsg->rx_len);
++
++ peci_put_xfer_msg(msg);
++
++ return ret;
++}
++
++static int peci_cmd_crashdump_disc(struct peci_adapter *adapter, void *vmsg)
++{
++ struct peci_crashdump_disc_msg *umsg = vmsg;
++ struct peci_xfer_msg *msg;
++ int ret;
++
++ /* Per the EDS, the read length must be a byte, word, or qword */
++ if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 8) {
++ dev_dbg(&adapter->dev, "Invalid read length, rx_len: %d\n",
++ umsg->rx_len);
++ return -EINVAL;
++ }
++
++ msg = peci_get_xfer_msg(PECI_CRASHDUMP_DISC_WRITE_LEN,
++ PECI_CRASHDUMP_DISC_READ_LEN_BASE +
++ umsg->rx_len);
++ if (!msg)
++ return -ENOMEM;
++
++ msg->addr = umsg->addr;
++ msg->tx_buf[0] = PECI_CRASHDUMP_CMD;
++ msg->tx_buf[1] = 0x00; /* request byte for Host ID | Retry bit */
++ /* Host ID is 0 for PECI 3.0 */
++ msg->tx_buf[2] = PECI_CRASHDUMP_DISC_VERSION;
++ msg->tx_buf[3] = PECI_CRASHDUMP_DISC_OPCODE;
++ msg->tx_buf[4] = umsg->subopcode;
++ msg->tx_buf[5] = umsg->param0;
++ msg->tx_buf[6] = (u8)umsg->param1;
++ msg->tx_buf[7] = (u8)(umsg->param1 >> 8);
++ msg->tx_buf[8] = umsg->param2;
++
++ ret = peci_xfer_with_retries(adapter, msg, false);
++ if (!ret)
++ memcpy(umsg->data, &msg->rx_buf[1], umsg->rx_len);
++
++ peci_put_xfer_msg(msg);
++
++ return ret;
++}
++
++static int peci_cmd_crashdump_get_frame(struct peci_adapter *adapter,
++ void *vmsg)
++{
++ struct peci_crashdump_get_frame_msg *umsg = vmsg;
++ struct peci_xfer_msg *msg;
++ int ret;
++
++ /* Per the EDS, the read length must be a qword or dqword */
++ if (umsg->rx_len != 8 && umsg->rx_len != 16) {
++ dev_dbg(&adapter->dev, "Invalid read length, rx_len: %d\n",
++ umsg->rx_len);
++ return -EINVAL;
++ }
++
++ msg = peci_get_xfer_msg(PECI_CRASHDUMP_GET_FRAME_WRITE_LEN,
++ PECI_CRASHDUMP_GET_FRAME_READ_LEN_BASE +
++ umsg->rx_len);
++ if (!msg)
++ return -ENOMEM;
++
++ msg->addr = umsg->addr;
++ msg->tx_buf[0] = PECI_CRASHDUMP_CMD;
++ msg->tx_buf[1] = 0x00; /* request byte for Host ID | Retry bit */
++ /* Host ID is 0 for PECI 3.0 */
++ msg->tx_buf[2] = PECI_CRASHDUMP_GET_FRAME_VERSION;
++ msg->tx_buf[3] = PECI_CRASHDUMP_GET_FRAME_OPCODE;
++ msg->tx_buf[4] = (u8)umsg->param0;
++ msg->tx_buf[5] = (u8)(umsg->param0 >> 8);
++ msg->tx_buf[6] = (u8)umsg->param1;
++ msg->tx_buf[7] = (u8)(umsg->param1 >> 8);
++ msg->tx_buf[8] = (u8)umsg->param2;
++ msg->tx_buf[8] = (u8)(umsg->param2 >> 8);
++
++ ret = peci_xfer_with_retries(adapter, msg, false);
++ if (!ret)
++ memcpy(umsg->data, &msg->rx_buf[1], umsg->rx_len);
++
++ peci_put_xfer_msg(msg);
++
++ return ret;
++}
++
+ typedef int (*peci_cmd_fn_type)(struct peci_adapter *, void *);
+
+ static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = {
+@@ -701,6 +921,9 @@ static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = {
+ peci_cmd_wr_pci_cfg,
+ peci_cmd_rd_pci_cfg_local,
+ peci_cmd_wr_pci_cfg_local,
++ peci_cmd_rd_end_pt_cfg,
++ peci_cmd_crashdump_disc,
++ peci_cmd_crashdump_get_frame,
+ };
+
+ /**
+diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h
+index 8467b2fbee1f..090b02c4de49 100644
+--- a/include/uapi/linux/peci-ioctl.h
++++ b/include/uapi/linux/peci-ioctl.h
+@@ -70,6 +70,9 @@ enum peci_cmd {
+ PECI_CMD_WR_PCI_CFG,
+ PECI_CMD_RD_PCI_CFG_LOCAL,
+ PECI_CMD_WR_PCI_CFG_LOCAL,
++ PECI_CMD_RD_END_PT_CFG,
++ PECI_CMD_CRASHDUMP_DISC,
++ PECI_CMD_CRASHDUMP_GET_FRAME,
+ PECI_CMD_MAX
+ };
+
+@@ -420,6 +423,93 @@ struct peci_wr_pci_cfg_local_msg {
+ __u32 value;
+ } __attribute__((__packed__));
+
++struct peci_rd_end_pt_cfg_msg {
++#define PECI_RDENDPTCFG_PCI_WRITE_LEN 0x0C
++#define PECI_RDENDPTCFG_MMIO_D_WRITE_LEN 0x0E
++#define PECI_RDENDPTCFG_MMIO_Q_WRITE_LEN 0x12
++#define PECI_RDENDPTCFG_READ_LEN_BASE 1
++#define PECI_RDENDPTCFG_CMD 0xC1
++
++ __u8 addr;
++ __u8 msg_type;
++#define PECI_RDENDPTCFG_TYPE_LOCAL_PCI 0x03
++#define PECI_RDENDPTCFG_TYPE_PCI 0x04
++#define PECI_RDENDPTCFG_TYPE_MMIO 0x05
++
++ union {
++ struct {
++ __u8 seg;
++ __u8 bus;
++ __u8 device;
++ __u8 function;
++ __u16 reg;
++ } pci_cfg;
++ struct {
++ __u8 seg;
++ __u8 bus;
++ __u8 device;
++ __u8 function;
++ __u8 bar;
++ __u8 addr_type;
++#define PECI_RDENDPTCFG_ADDR_TYPE_PCI 0x04
++#define PECI_RDENDPTCFG_ADDR_TYPE_MMIO_D 0x05
++#define PECI_RDENDPTCFG_ADDR_TYPE_MMIO_Q 0x06
++
++ __u64 offset;
++ } mmio;
++ } params;
++ __u8 rx_len;
++ __u8 padding[3];
++ __u8 data[8];
++} __attribute__((__packed__));
++
++/* Crashdump Agent */
++#define PECI_CRASHDUMP_CORE 0x00
++#define PECI_CRASHDUMP_TOR 0x01
++
++/* Crashdump Agent Param */
++#define PECI_CRASHDUMP_PAYLOAD_SIZE 0x00
++
++/* Crashdump Agent Data Param */
++#define PECI_CRASHDUMP_AGENT_ID 0x00
++#define PECI_CRASHDUMP_AGENT_PARAM 0x01
++
++struct peci_crashdump_disc_msg {
++ __u8 addr;
++ __u8 subopcode;
++#define PECI_CRASHDUMP_ENABLED 0x00
++#define PECI_CRASHDUMP_NUM_AGENTS 0x01
++#define PECI_CRASHDUMP_AGENT_DATA 0x02
++
++ __u8 param0;
++ __u8 padding;
++ __u16 param1;
++ __u8 param2;
++ __u8 rx_len;
++ __u8 data[8];
++} __attribute__((__packed__));
++
++struct peci_crashdump_get_frame_msg {
++#define PECI_CRASHDUMP_DISC_WRITE_LEN 9
++#define PECI_CRASHDUMP_DISC_READ_LEN_BASE 1
++#define PECI_CRASHDUMP_DISC_VERSION 1
++#define PECI_CRASHDUMP_DISC_OPCODE 1
++#define PECI_CRASHDUMP_GET_FRAME_WRITE_LEN 10
++#define PECI_CRASHDUMP_GET_FRAME_READ_LEN_BASE 1
++#define PECI_CRASHDUMP_GET_FRAME_VERSION 3
++#define PECI_CRASHDUMP_GET_FRAME_OPCODE 3
++#define PECI_CRASHDUMP_CMD 0x71
++
++ __u8 addr;
++ __u8 padding0;
++ __u16 param0;
++ __u16 param1;
++ __u16 param2;
++ __u8 rx_len;
++ __u8 padding1[3];
++ __u8 data[16];
++} __attribute__((__packed__));
++
+ #define PECI_IOC_BASE 0xb7
+
+ #define PECI_IOC_XFER \
+@@ -460,4 +550,16 @@ struct peci_wr_pci_cfg_local_msg {
+ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG_LOCAL, \
+ struct peci_wr_pci_cfg_local_msg)
+
++#define PECI_IOC_RD_END_PT_CFG \
++ _IOWR(PECI_IOC_BASE, PECI_CMD_RD_END_PT_CFG, \
++ struct peci_rd_end_pt_cfg_msg)
++
++#define PECI_IOC_CRASHDUMP_DISC \
++ _IOWR(PECI_IOC_BASE, PECI_CMD_CRASHDUMP_DISC, \
++ struct peci_crashdump_disc_msg)
++
++#define PECI_IOC_CRASHDUMP_GET_FRAME \
++ _IOWR(PECI_IOC_BASE, PECI_CMD_CRASHDUMP_GET_FRAME, \
++ struct peci_crashdump_get_frame_msg)
++
+ #endif /* __PECI_IOCTL_H */
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch
new file mode 100644
index 000000000..860a1ba5d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch
@@ -0,0 +1,1138 @@
+From 43470f186979483ba6c1e6374c7ea3a129622862 Mon Sep 17 00:00:00 2001
+From: "Hunt, Bryan" <bryan.hunt@intel.com>
+Date: Fri, 30 Mar 2018 10:48:01 -0700
+Subject: [PATCH] Add AST2500d JTAG driver
+
+Adding aspeed jtag driver
+
+Signed-off-by: Hunt, Bryan <bryan.hunt@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g5.dtsi | 9 +
+ drivers/Kconfig | 1 +
+ drivers/Makefile | 1 +
+ drivers/jtag/Kconfig | 13 +
+ drivers/jtag/Makefile | 1 +
+ drivers/jtag/jtag_aspeed.c | 963 +++++++++++++++++++++++++++++++++++++++
+ include/uapi/linux/jtag_drv.h | 73 +++
+ 7 files changed, 1061 insertions(+)
+ create mode 100644 drivers/jtag/Kconfig
+ create mode 100644 drivers/jtag/Makefile
+ create mode 100644 drivers/jtag/jtag_aspeed.c
+ create mode 100644 include/uapi/linux/jtag_drv.h
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index a7bbc2adecc9..b63003c2c0c7 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -366,6 +366,15 @@
+ pinctrl-0 = <&pinctrl_espi_default>;
+ };
+
++ jtag: jtag@1e6e4000 {
++ compatible = "aspeed,ast2500-jtag";
++ reg = <0x1e6e2004 0x4 0x1e6e4000 0x1c>;
++ clocks = <&syscon ASPEED_CLK_APB>;
++ resets = <&syscon ASPEED_RESET_JTAG_MASTER>;
++ interrupts = <43>;
++ status = "disabled";
++ };
++
+ lpc: lpc@1e789000 {
+ compatible = "aspeed,ast2500-lpc", "simple-mfd";
+ reg = <0x1e789000 0x1000>;
+diff --git a/drivers/Kconfig b/drivers/Kconfig
+index c633db2b41fb..2778a5c33ca5 100644
+--- a/drivers/Kconfig
++++ b/drivers/Kconfig
+@@ -221,4 +221,5 @@ source "drivers/slimbus/Kconfig"
+
+ source "drivers/peci/Kconfig"
+
++source "drivers/jtag/Kconfig"
+ endmenu
+diff --git a/drivers/Makefile b/drivers/Makefile
+index 63c9b425e6e1..714067945fd2 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -187,3 +187,4 @@ obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/
+ obj-$(CONFIG_SIOX) += siox/
+ obj-$(CONFIG_GNSS) += gnss/
+ obj-$(CONFIG_PECI) += peci/
++obj-$(CONFIG_JTAG_ASPEED) += jtag/
+diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig
+new file mode 100644
+index 000000000000..2e5d0a5bea90
+--- /dev/null
++++ b/drivers/jtag/Kconfig
+@@ -0,0 +1,13 @@
++menuconfig JTAG_ASPEED
++ tristate "ASPEED SoC JTAG controller support"
++ depends on HAS_IOMEM
++ depends on ARCH_ASPEED || COMPILE_TEST
++ help
++ This provides a support for ASPEED JTAG device, equipped on
++ ASPEED SoC 24xx and 25xx families. Drivers allows programming
++ of hardware devices, connected to SoC through the JTAG interface.
++
++ If you want this support, you should say Y here.
++
++ To compile this driver as a module, choose M here: the module will
++ be called jtag_aspeed.
+diff --git a/drivers/jtag/Makefile b/drivers/jtag/Makefile
+new file mode 100644
+index 000000000000..db9b660e9f90
+--- /dev/null
++++ b/drivers/jtag/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_JTAG_ASPEED) += jtag_aspeed.o
+diff --git a/drivers/jtag/jtag_aspeed.c b/drivers/jtag/jtag_aspeed.c
+new file mode 100644
+index 000000000000..42e2a131873c
+--- /dev/null
++++ b/drivers/jtag/jtag_aspeed.c
+@@ -0,0 +1,963 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (C) 2012-2017 ASPEED Technology Inc.
++// Copyright (c) 2018 Intel Corporation
++
++#include <linux/bitfield.h>
++#include <linux/delay.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/jtag_drv.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++
++#define SCU_RESET_JTAG BIT(22)
++
++#define AST_JTAG_DATA 0x00
++#define AST_JTAG_INST 0x04
++#define AST_JTAG_CTRL 0x08
++#define AST_JTAG_ISR 0x0C
++#define AST_JTAG_SW 0x10
++#define AST_JTAG_TCK 0x14
++#define AST_JTAG_IDLE 0x18
++
++/* AST_JTAG_CTRL - 0x08 : Engine Control */
++#define JTAG_ENG_EN BIT(31)
++#define JTAG_ENG_OUT_EN BIT(30)
++#define JTAG_ENGINE_EN (JTAG_ENG_EN | JTAG_ENG_OUT_EN)
++#define JTAG_FORCE_TMS BIT(29)
++
++#define JTAG_IR_UPDATE BIT(26) /* AST2500 only */
++#define JTAG_INST_LEN_MASK GENMASK(25, 20)
++#define JTAG_LAST_INST BIT(17)
++#define JTAG_INST_EN BIT(16)
++#define JTAG_DATA_LEN_MASK GENMASK(9, 4)
++
++#define JTAG_DR_UPDATE BIT(10) /* AST2500 only */
++#define JTAG_LAST_DATA BIT(1)
++#define JTAG_DATA_EN BIT(0)
++
++/* AST_JTAG_ISR - 0x0C : Interrupt status and enable */
++#define JTAG_INST_PAUSE BIT(19)
++#define JTAG_INST_COMPLETE BIT(18)
++#define JTAG_DATA_PAUSE BIT(17)
++#define JTAG_DATA_COMPLETE BIT(16)
++
++#define JTAG_INST_PAUSE_EN BIT(3)
++#define JTAG_INST_COMPLETE_EN BIT(2)
++#define JTAG_DATA_PAUSE_EN BIT(1)
++#define JTAG_DATA_COMPLETE_EN BIT(0)
++
++/* AST_JTAG_SW - 0x10 : Software Mode and Status */
++#define JTAG_SW_MODE_EN BIT(19)
++#define JTAG_SW_MODE_TCK BIT(18)
++#define JTAG_SW_MODE_TMS BIT(17)
++#define JTAG_SW_MODE_TDIO BIT(16)
++
++/* AST_JTAG_TCK - 0x14 : TCK Control */
++#define JTAG_TCK_DIVISOR_MASK GENMASK(10, 0)
++
++/* #define USE_INTERRUPTS */
++#define AST_JTAG_NAME "jtag"
++
++static DEFINE_SPINLOCK(jtag_state_lock);
++
++struct ast_jtag_info {
++ void __iomem *reg_base;
++ void __iomem *reg_base_scu;
++ int irq;
++ u32 flag;
++ wait_queue_head_t jtag_wq;
++ bool is_open;
++ struct device *dev;
++ struct miscdevice miscdev;
++};
++
++/*
++ * This structure represents a TMS cycle, as expressed in a set of bits and a
++ * count of bits (note: there are no start->end state transitions that require
++ * more than 1 byte of TMS cycles)
++ */
++struct tms_cycle {
++ unsigned char tmsbits;
++ unsigned char count;
++};
++
++/*
++ * These are the string representations of the TAP states corresponding to the
++ * enums literals in JtagStateEncode
++ */
++static const char * const c_statestr[] = {"TLR", "RTI", "SelDR", "CapDR",
++ "ShfDR", "Ex1DR", "PauDR", "Ex2DR",
++ "UpdDR", "SelIR", "CapIR", "ShfIR",
++ "Ex1IR", "PauIR", "Ex2IR", "UpdIR"};
++
++/*
++ * This is the complete set TMS cycles for going from any TAP state to any
++ * other TAP state, following a “shortest path” rule.
++ */
++static const struct tms_cycle _tms_cycle_lookup[][16] = {
++/* TLR RTI SelDR CapDR SDR Ex1DR PDR Ex2DR UpdDR SelIR CapIR SIR Ex1IR PIR Ex2IR UpdIR*/
++/* TLR */{ {0x00, 0}, {0x00, 1}, {0x02, 2}, {0x02, 3}, {0x02, 4}, {0x0a, 4}, {0x0a, 5}, {0x2a, 6}, {0x1a, 5}, {0x06, 3}, {0x06, 4}, {0x06, 5}, {0x16, 5}, {0x16, 6}, {0x56, 7}, {0x36, 6} },
++/* RTI */{ {0x07, 3}, {0x00, 0}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x0d, 4}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5} },
++/* SelDR*/{ {0x03, 2}, {0x03, 3}, {0x00, 0}, {0x00, 1}, {0x00, 2}, {0x02, 2}, {0x02, 3}, {0x0a, 4}, {0x06, 3}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x0d, 4} },
++/* CapDR*/{ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x00, 0}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2}, {0x0f, 4}, {0x0f, 5}, {0x0f, 6}, {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, {0x6f, 7} },
++/* SDR */{ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x00, 0}, {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2}, {0x0f, 4}, {0x0f, 5}, {0x0f, 6}, {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, {0x6f, 7} },
++/* Ex1DR*/{ {0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x02, 3}, {0x00, 0}, {0x00, 1}, {0x02, 2}, {0x01, 1}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6} },
++/* PDR */{ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x01, 2}, {0x05, 3}, {0x00, 0}, {0x01, 1}, {0x03, 2}, {0x0f, 4}, {0x0f, 5}, {0x0f, 6}, {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, {0x6f, 7} },
++/* Ex2DR*/{ {0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x00, 1}, {0x02, 2}, {0x02, 3}, {0x00, 0}, {0x01, 1}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6} },
++/* UpdDR*/{ {0x07, 3}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x00, 0}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5} },
++/* SelIR*/{ {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x05, 4}, {0x05, 5}, {0x15, 5}, {0x15, 6}, {0x55, 7}, {0x35, 6}, {0x00, 0}, {0x00, 1}, {0x00, 2}, {0x02, 2}, {0x02, 3}, {0x0a, 4}, {0x06, 3} },
++/* CapIR*/{ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, {0x00, 0}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2} },
++/* SIR */{ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, {0x0f, 5}, {0x00, 0}, {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2} },
++/* Ex1IR*/{ {0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5}, {0x07, 3}, {0x07, 4}, {0x02, 3}, {0x00, 0}, {0x00, 1}, {0x02, 2}, {0x01, 1} },
++/* PIR */{ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, {0x0f, 5}, {0x01, 2}, {0x05, 3}, {0x00, 0}, {0x01, 1}, {0x03, 2} },
++/* Ex2IR*/{ {0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5}, {0x07, 3}, {0x07, 4}, {0x00, 1}, {0x02, 2}, {0x02, 3}, {0x00, 0}, {0x01, 1} },
++/* UpdIR*/{ {0x07, 3}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x0d, 4}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x00, 0} },
++};
++
++static const char * const regnames[] = {
++ [AST_JTAG_DATA] = "AST_JTAG_DATA",
++ [AST_JTAG_INST] = "AST_JTAG_INST",
++ [AST_JTAG_CTRL] = "AST_JTAG_CTRL",
++ [AST_JTAG_ISR] = "AST_JTAG_ISR",
++ [AST_JTAG_SW] = "AST_JTAG_SW",
++ [AST_JTAG_TCK] = "AST_JTAG_TCK",
++ [AST_JTAG_IDLE] = "AST_JTAG_IDLE",
++};
++
++static inline u32 ast_jtag_read(struct ast_jtag_info *ast_jtag, u32 reg)
++{
++ u32 val = readl(ast_jtag->reg_base + reg);
++
++ dev_dbg(ast_jtag->dev, "read:%s val = 0x%08x\n", regnames[reg], val);
++ return val;
++}
++
++static inline void ast_jtag_write(struct ast_jtag_info *ast_jtag, u32 val,
++ u32 reg)
++{
++ dev_dbg(ast_jtag->dev, "write:%s val = 0x%08x\n", regnames[reg], val);
++ writel(val, ast_jtag->reg_base + reg);
++}
++
++static void ast_jtag_set_tck(struct ast_jtag_info *ast_jtag,
++ enum xfer_mode mode, uint tck)
++{
++ u32 read_value;
++
++ if (tck == 0)
++ tck = 1;
++ else if (tck > JTAG_TCK_DIVISOR_MASK)
++ tck = JTAG_TCK_DIVISOR_MASK;
++ read_value = ast_jtag_read(ast_jtag, AST_JTAG_TCK);
++ ast_jtag_write(ast_jtag,
++ ((read_value & ~JTAG_TCK_DIVISOR_MASK) | tck),
++ AST_JTAG_TCK);
++}
++
++static void ast_jtag_get_tck(struct ast_jtag_info *ast_jtag,
++ enum xfer_mode mode, uint *tck)
++{
++ *tck = FIELD_GET(JTAG_TCK_DIVISOR_MASK,
++ ast_jtag_read(ast_jtag, AST_JTAG_TCK));
++}
++
++/*
++ * Used only in SW mode to walk the JTAG state machine.
++ */
++static u8 tck_cycle(struct ast_jtag_info *ast_jtag, u8 TMS, u8 TDI,
++ bool do_read)
++{
++ u8 result = 0;
++ u32 regwriteval = JTAG_SW_MODE_EN | (TMS * JTAG_SW_MODE_TMS)
++ | (TDI * JTAG_SW_MODE_TDIO);
++
++ /* TCK = 0 */
++ ast_jtag_write(ast_jtag, regwriteval, AST_JTAG_SW);
++
++ ast_jtag_read(ast_jtag, AST_JTAG_SW);
++
++ /* TCK = 1 */
++ ast_jtag_write(ast_jtag, JTAG_SW_MODE_TCK | regwriteval, AST_JTAG_SW);
++
++ if (do_read) {
++ result = (ast_jtag_read(ast_jtag, AST_JTAG_SW)
++ & JTAG_SW_MODE_TDIO) ? 1 : 0;
++ }
++ return result;
++}
++
++#define WAIT_ITERATIONS 75
++
++static int ast_jtag_wait_instr_pause_complete(struct ast_jtag_info *ast_jtag)
++{
++ int res = 0;
++#ifdef USE_INTERRUPTS
++ res = wait_event_interruptible(ast_jtag->jtag_wq,
++ (ast_jtag->flag == JTAG_INST_PAUSE));
++ ast_jtag->flag = 0;
++#else
++ u32 status = 0;
++ u32 iterations = 0;
++
++ while ((status & JTAG_INST_PAUSE) == 0) {
++ status = ast_jtag_read(ast_jtag, AST_JTAG_ISR);
++ dev_dbg(ast_jtag->dev, "%s = 0x%08x\n", __func__, status);
++ iterations++;
++ if (iterations > WAIT_ITERATIONS) {
++ dev_err(ast_jtag->dev,
++ "ast_jtag driver timed out waiting for instruction pause complete\n");
++ res = -EFAULT;
++ break;
++ }
++ if ((status & JTAG_DATA_COMPLETE) == 0) {
++ if (iterations % 25 == 0)
++ usleep_range(1, 5);
++ else
++ udelay(1);
++ }
++ }
++ ast_jtag_write(ast_jtag, JTAG_INST_PAUSE | (status & 0xf),
++ AST_JTAG_ISR);
++#endif
++ return res;
++}
++
++static int ast_jtag_wait_instr_complete(struct ast_jtag_info *ast_jtag)
++{
++ int res = 0;
++#ifdef USE_INTERRUPTS
++ res = wait_event_interruptible(ast_jtag->jtag_wq,
++ (ast_jtag->flag == JTAG_INST_COMPLETE));
++ ast_jtag->flag = 0;
++#else
++ u32 status = 0;
++ u32 iterations = 0;
++
++ while ((status & JTAG_INST_COMPLETE) == 0) {
++ status = ast_jtag_read(ast_jtag, AST_JTAG_ISR);
++ dev_dbg(ast_jtag->dev, "%s = 0x%08x\n", __func__, status);
++ iterations++;
++ if (iterations > WAIT_ITERATIONS) {
++ dev_err(ast_jtag->dev,
++ "ast_jtag driver timed out waiting for instruction complete\n");
++ res = -EFAULT;
++ break;
++ }
++ if ((status & JTAG_DATA_COMPLETE) == 0) {
++ if (iterations % 25 == 0)
++ usleep_range(1, 5);
++ else
++ udelay(1);
++ }
++ }
++ ast_jtag_write(ast_jtag, JTAG_INST_COMPLETE | (status & 0xf),
++ AST_JTAG_ISR);
++#endif
++ return res;
++}
++
++static int ast_jtag_wait_data_pause_complete(struct ast_jtag_info *ast_jtag)
++{
++ int res = 0;
++#ifdef USE_INTERRUPTS
++ res = wait_event_interruptible(ast_jtag->jtag_wq,
++ (ast_jtag->flag == JTAG_DATA_PAUSE));
++ ast_jtag->flag = 0;
++#else
++ u32 status = 0;
++ u32 iterations = 0;
++
++ while ((status & JTAG_DATA_PAUSE) == 0) {
++ status = ast_jtag_read(ast_jtag, AST_JTAG_ISR);
++ dev_dbg(ast_jtag->dev, "%s = 0x%08x\n", __func__, status);
++ iterations++;
++ if (iterations > WAIT_ITERATIONS) {
++ dev_err(ast_jtag->dev,
++ "ast_jtag driver timed out waiting for data pause complete\n");
++ res = -EFAULT;
++ break;
++ }
++ if ((status & JTAG_DATA_COMPLETE) == 0) {
++ if (iterations % 25 == 0)
++ usleep_range(1, 5);
++ else
++ udelay(1);
++ }
++ }
++ ast_jtag_write(ast_jtag, JTAG_DATA_PAUSE | (status & 0xf),
++ AST_JTAG_ISR);
++#endif
++ return res;
++}
++
++static int ast_jtag_wait_data_complete(struct ast_jtag_info *ast_jtag)
++{
++ int res = 0;
++#ifdef USE_INTERRUPTS
++ res = wait_event_interruptible(ast_jtag->jtag_wq,
++ (ast_jtag->flag == JTAG_DATA_COMPLETE));
++ ast_jtag->flag = 0;
++#else
++ u32 status = 0;
++ u32 iterations = 0;
++
++ while ((status & JTAG_DATA_COMPLETE) == 0) {
++ status = ast_jtag_read(ast_jtag, AST_JTAG_ISR);
++ dev_dbg(ast_jtag->dev, "%s = 0x%08x\n", __func__, status);
++ iterations++;
++ if (iterations > WAIT_ITERATIONS) {
++ dev_err(ast_jtag->dev,
++ "ast_jtag driver timed out waiting for data complete\n");
++ res = -EFAULT;
++ break;
++ }
++ if ((status & JTAG_DATA_COMPLETE) == 0) {
++ if (iterations % 25 == 0)
++ usleep_range(1, 5);
++ else
++ udelay(1);
++ }
++ }
++ ast_jtag_write(ast_jtag,
++ JTAG_DATA_COMPLETE | (status & 0xf),
++ AST_JTAG_ISR);
++#endif
++ return res;
++}
++
++static void ast_jtag_bitbang(struct ast_jtag_info *ast_jtag,
++ struct tck_bitbang *bit_bang)
++{
++ bit_bang->tdo = tck_cycle(ast_jtag, bit_bang->tms, bit_bang->tdi, true);
++}
++
++static void reset_tap(struct ast_jtag_info *ast_jtag, enum xfer_mode mode)
++{
++ unsigned char i;
++
++ if (mode == SW_MODE) {
++ for (i = 0; i < 9; i++)
++ tck_cycle(ast_jtag, 1, 0, false);
++ } else {
++ ast_jtag_write(ast_jtag, 0, AST_JTAG_SW);
++ mdelay(1);
++ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_FORCE_TMS,
++ AST_JTAG_CTRL);
++ mdelay(1);
++ ast_jtag_write(ast_jtag,
++ JTAG_SW_MODE_EN | JTAG_SW_MODE_TDIO,
++ AST_JTAG_SW);
++ }
++}
++
++static int ast_jtag_set_tapstate(struct ast_jtag_info *ast_jtag,
++ enum xfer_mode mode, uint from, uint to)
++{
++ unsigned char num_cycles;
++ unsigned char cycle;
++ unsigned char tms_bits;
++
++ /*
++ * Ensure that the requested and current tap states are within
++ * 0 to 15.
++ */
++ if (from >= ARRAY_SIZE(_tms_cycle_lookup[0]) || /* Column */
++ to >= ARRAY_SIZE(_tms_cycle_lookup)) { /* row */
++ return -1;
++ }
++
++ dev_dbg(ast_jtag->dev, "Set TAP state: %s\n", c_statestr[to]);
++
++ if (mode == SW_MODE) {
++ ast_jtag_write(ast_jtag,
++ JTAG_SW_MODE_EN | JTAG_SW_MODE_TDIO,
++ AST_JTAG_SW);
++
++ if (to == jtag_tlr) {
++ reset_tap(ast_jtag, mode);
++ } else {
++ tms_bits = _tms_cycle_lookup[from][to].tmsbits;
++ num_cycles = _tms_cycle_lookup[from][to].count;
++
++ if (num_cycles == 0)
++ return 0;
++
++ for (cycle = 0; cycle < num_cycles; cycle++) {
++ tck_cycle(ast_jtag, (tms_bits & 1), 0, false);
++ tms_bits >>= 1;
++ }
++ }
++ } else if (to == jtag_tlr) {
++ reset_tap(ast_jtag, mode);
++ }
++ return 0;
++}
++
++static void software_readwrite_scan(struct ast_jtag_info *ast_jtag,
++ struct scan_xfer *scan_xfer)
++{
++ uint bit_index = 0;
++ bool is_IR = (scan_xfer->tap_state == jtag_shf_ir);
++ uint exit_tap_state = is_IR ? jtag_ex1_ir : jtag_ex1_dr;
++ unsigned char *tdi = scan_xfer->tdi;
++ unsigned char *tdo = scan_xfer->tdo;
++
++ dev_dbg(ast_jtag->dev, "SW JTAG SHIFT %s, length = %d\n",
++ is_IR ? "IR" : "DR", scan_xfer->length);
++
++ ast_jtag_write(ast_jtag,
++ JTAG_SW_MODE_EN | JTAG_SW_MODE_TDIO,
++ AST_JTAG_SW);
++
++ while (bit_index < scan_xfer->length) {
++ int bit_offset = (bit_index % 8);
++ int this_input_bit = 0;
++ int tms_high_or_low;
++ int this_output_bit;
++
++ if (bit_index / 8 < scan_xfer->tdi_bytes) {
++ /*
++ * If we are on a byte boundary, increment the byte
++ * pointers. Don't increment on 0, pointer is already
++ * on the first byte.
++ */
++ if (bit_index % 8 == 0 && bit_index != 0)
++ tdi++;
++ this_input_bit = (*tdi >> bit_offset) & 1;
++ }
++ /* If this is the last bit, leave TMS high */
++ tms_high_or_low = (bit_index == scan_xfer->length - 1) &&
++ (scan_xfer->end_tap_state != jtag_shf_dr) &&
++ (scan_xfer->end_tap_state != jtag_shf_ir);
++ this_output_bit = tck_cycle(ast_jtag, tms_high_or_low,
++ this_input_bit, !!tdo);
++ /*
++ * If it was the last bit in the scan and the end_tap_state is
++ * something other than shiftDR or shiftIR then go to Exit1.
++ * IMPORTANT Note: if the end_tap_state is ShiftIR/DR and
++ * the next call to this function is a shiftDR/IR then the
++ * driver will not change state!
++ */
++ if (tms_high_or_low)
++ scan_xfer->tap_state = exit_tap_state;
++ if (tdo && bit_index / 8 < scan_xfer->tdo_bytes) {
++ if (bit_index % 8 == 0) {
++ if (bit_index != 0)
++ tdo++;
++ *tdo = 0;
++ }
++ *tdo |= this_output_bit << bit_offset;
++ }
++ bit_index++;
++ }
++ ast_jtag_set_tapstate(ast_jtag, scan_xfer->mode, scan_xfer->tap_state,
++ scan_xfer->end_tap_state);
++}
++
++static int fire_ir_command(struct ast_jtag_info *ast_jtag, bool last,
++ u32 length)
++{
++ int res;
++
++ if (last) {
++ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_LAST_INST
++ | FIELD_PREP(JTAG_INST_LEN_MASK, length),
++ AST_JTAG_CTRL);
++ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_LAST_INST
++ | FIELD_PREP(JTAG_INST_LEN_MASK, length)
++ | JTAG_INST_EN,
++ AST_JTAG_CTRL);
++ res = ast_jtag_wait_instr_complete(ast_jtag);
++ } else {
++ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_IR_UPDATE
++ | FIELD_PREP(JTAG_INST_LEN_MASK, length),
++ AST_JTAG_CTRL);
++ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_IR_UPDATE
++ | FIELD_PREP(JTAG_INST_LEN_MASK, length)
++ | JTAG_INST_EN,
++ AST_JTAG_CTRL);
++ res = ast_jtag_wait_instr_pause_complete(ast_jtag);
++ }
++ return res;
++}
++
++static int fire_dr_command(struct ast_jtag_info *ast_jtag, bool last,
++ u32 length)
++{
++ int res;
++
++ if (last) {
++ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_LAST_DATA
++ | FIELD_PREP(JTAG_DATA_LEN_MASK, length),
++ AST_JTAG_CTRL);
++ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_LAST_DATA
++ | FIELD_PREP(JTAG_DATA_LEN_MASK, length)
++ | JTAG_DATA_EN,
++ AST_JTAG_CTRL);
++ res = ast_jtag_wait_data_complete(ast_jtag);
++ } else {
++ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_DR_UPDATE
++ | FIELD_PREP(JTAG_DATA_LEN_MASK, length),
++ AST_JTAG_CTRL);
++ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN | JTAG_DR_UPDATE
++ | FIELD_PREP(JTAG_DATA_LEN_MASK, length)
++ | JTAG_DATA_EN,
++ AST_JTAG_CTRL);
++ res = ast_jtag_wait_data_pause_complete(ast_jtag);
++ }
++ return res;
++}
++
++static int hardware_readwrite_scan(struct ast_jtag_info *ast_jtag,
++ struct scan_xfer *scan_xfer)
++{
++ int res = 0;
++ u32 bits_received = 0;
++ u32 bits_to_send = 0;
++ u32 chunk_len = 0;
++ bool is_IR = (scan_xfer->tap_state == jtag_shf_ir);
++ bool is_last = false;
++ u32 length = scan_xfer->length;
++ u32 *tdi = (u32 *)scan_xfer->tdi;
++ u32 *tdo = (u32 *)scan_xfer->tdo;
++ u32 remaining_bytes;
++ int scan_end = 0;
++ u32 ast_reg = is_IR ? AST_JTAG_INST : AST_JTAG_DATA;
++
++ dev_dbg(ast_jtag->dev, "HW JTAG SHIFT %s, length = %d\n",
++ is_IR ? "IR" : "DR", length);
++
++ ast_jtag_write(ast_jtag, 0, AST_JTAG_SW);
++ if (scan_xfer->end_tap_state == jtag_pau_dr ||
++ scan_xfer->end_tap_state == jtag_pau_ir ||
++ scan_xfer->end_tap_state == jtag_shf_dr ||
++ scan_xfer->end_tap_state == jtag_shf_ir) {
++ scan_end = 0;
++ } else {
++ scan_end = 1;
++ }
++
++ while (length > 0) {
++ chunk_len = (length > 32) ? 32 : length;
++
++ if (length <= 32 && scan_end == 1)
++ is_last = true;
++
++ dev_dbg(ast_jtag->dev, "HW SHIFT, length=%d, scan_end=%d, chunk_len=%d, is_last=%d\n",
++ length, scan_end, chunk_len, is_last);
++
++ remaining_bytes = (scan_xfer->length - length) / 8;
++ if (tdi && remaining_bytes < scan_xfer->tdi_bytes) {
++ bits_to_send = *tdi++;
++ ast_jtag_write(ast_jtag, bits_to_send, ast_reg);
++ } else {
++ bits_to_send = 0;
++ ast_jtag_write(ast_jtag, 0, ast_reg);
++ }
++
++ dev_dbg(ast_jtag->dev, "HW SHIFT, len=%d chunk_len=%d is_last=%x bits_to_send=%x\n",
++ length, chunk_len, is_last, bits_to_send);
++
++ if (is_IR)
++ res = fire_ir_command(ast_jtag, is_last, chunk_len);
++ else
++ res = fire_dr_command(ast_jtag, is_last, chunk_len);
++ if (res != 0)
++ break;
++
++ if (tdo) {
++ bits_received = ast_jtag_read(ast_jtag, ast_reg);
++ bits_received >>= (32 - chunk_len);
++ *tdo++ = bits_received;
++ }
++ dev_dbg(ast_jtag->dev,
++ "HW SHIFT, len=%d chunk_len=%d is_last=%x bits_received=%x\n",
++ length, chunk_len, is_last,
++ bits_received);
++ length -= chunk_len;
++ }
++ return res;
++}
++
++static int ast_jtag_readwrite_scan(struct ast_jtag_info *ast_jtag,
++ struct scan_xfer *scan_xfer)
++{
++ int res = 0;
++
++ if (scan_xfer->tap_state != jtag_shf_dr &&
++ scan_xfer->tap_state != jtag_shf_ir) {
++ if (scan_xfer->tap_state < ARRAY_SIZE(c_statestr))
++ dev_err(ast_jtag->dev,
++ "readwrite_scan bad current tap state = %s\n",
++ c_statestr[scan_xfer->tap_state]);
++ else
++ dev_err(ast_jtag->dev,
++ "readwrite_scan bad current tap state = %u\n",
++ scan_xfer->tap_state);
++ return -EFAULT;
++ }
++
++ if (scan_xfer->length == 0) {
++ dev_err(ast_jtag->dev, "readwrite_scan bad length 0\n");
++ return -EFAULT;
++ }
++
++ if (!scan_xfer->tdi && scan_xfer->tdi_bytes != 0) {
++ dev_err(ast_jtag->dev,
++ "readwrite_scan null tdi with non-zero length %u!\n",
++ scan_xfer->tdi_bytes);
++ return -EFAULT;
++ }
++
++ if (!scan_xfer->tdo && scan_xfer->tdo_bytes != 0) {
++ dev_err(ast_jtag->dev,
++ "readwrite_scan null tdo with non-zero length %u!\n",
++ scan_xfer->tdo_bytes);
++ return -EFAULT;
++ }
++
++ if (!scan_xfer->tdi && !scan_xfer->tdo) {
++ dev_err(ast_jtag->dev, "readwrite_scan null tdo and tdi!\n");
++ return -EFAULT;
++ }
++
++ if (scan_xfer->mode == SW_MODE)
++ software_readwrite_scan(ast_jtag, scan_xfer);
++ else
++ res = hardware_readwrite_scan(ast_jtag, scan_xfer);
++ return res;
++}
++
++#ifdef USE_INTERRUPTS
++static irqreturn_t ast_jtag_interrupt(int this_irq, void *dev_id)
++{
++ u32 status;
++ struct ast_jtag_info *ast_jtag = dev_id;
++
++ status = ast_jtag_read(ast_jtag, AST_JTAG_ISR);
++
++ if (status & JTAG_INST_PAUSE) {
++ ast_jtag_write(ast_jtag,
++ JTAG_INST_PAUSE | (status & 0xf),
++ AST_JTAG_ISR);
++ ast_jtag->flag = JTAG_INST_PAUSE;
++ }
++
++ if (status & JTAG_INST_COMPLETE) {
++ ast_jtag_write(ast_jtag,
++ JTAG_INST_COMPLETE | (status & 0xf),
++ AST_JTAG_ISR);
++ ast_jtag->flag = JTAG_INST_COMPLETE;
++ }
++
++ if (status & JTAG_DATA_PAUSE) {
++ ast_jtag_write(ast_jtag,
++ JTAG_DATA_PAUSE | (status & 0xf), AST_JTAG_ISR);
++ ast_jtag->flag = JTAG_DATA_PAUSE;
++ }
++
++ if (status & JTAG_DATA_COMPLETE) {
++ ast_jtag_write(ast_jtag,
++ JTAG_DATA_COMPLETE | (status & 0xf),
++ AST_JTAG_ISR);
++ ast_jtag->flag = JTAG_DATA_COMPLETE;
++ }
++
++ if (ast_jtag->flag) {
++ wake_up_interruptible(&ast_jtag->jtag_wq);
++ return IRQ_HANDLED;
++ } else {
++ return IRQ_NONE;
++ }
++}
++#endif
++
++static inline void ast_jtag_slave(struct ast_jtag_info *ast_jtag)
++{
++ u32 currReg = readl((void *)(ast_jtag->reg_base_scu));
++
++ writel(currReg | SCU_RESET_JTAG, (void *)ast_jtag->reg_base_scu);
++}
++
++static inline void ast_jtag_master(struct ast_jtag_info *ast_jtag)
++{
++ u32 currReg = readl((void *)(ast_jtag->reg_base_scu));
++
++ writel(currReg & ~SCU_RESET_JTAG, (void *)ast_jtag->reg_base_scu);
++ ast_jtag_write(ast_jtag, JTAG_ENGINE_EN, AST_JTAG_CTRL);
++ ast_jtag_write(ast_jtag, JTAG_SW_MODE_EN | JTAG_SW_MODE_TDIO,
++ AST_JTAG_SW);
++ ast_jtag_write(ast_jtag, JTAG_INST_PAUSE | JTAG_INST_COMPLETE |
++ JTAG_DATA_PAUSE | JTAG_DATA_COMPLETE |
++ JTAG_INST_PAUSE_EN | JTAG_INST_COMPLETE_EN |
++ JTAG_DATA_PAUSE_EN | JTAG_DATA_COMPLETE_EN,
++ AST_JTAG_ISR); /* Enable Interrupt */
++}
++
++static long jtag_ioctl(struct file *file, uint cmd, ulong arg)
++{
++ int ret = 0;
++ struct ast_jtag_info *ast_jtag = file->private_data;
++ void __user *argp = (void __user *)arg;
++ struct tck_bitbang bitbang;
++ struct scan_xfer xfer;
++ struct set_tck_param set_tck_param;
++ struct get_tck_param get_tck_param;
++ struct tap_state_param tap_state_param;
++ unsigned char *kern_tdi = NULL;
++ unsigned char *kern_tdo = NULL;
++ unsigned char *user_tdi;
++ unsigned char *user_tdo;
++
++ switch (cmd) {
++ case AST_JTAG_SET_TCK:
++ if (copy_from_user(&set_tck_param, argp,
++ sizeof(struct set_tck_param))) {
++ ret = -EFAULT;
++ } else {
++ ast_jtag_set_tck(ast_jtag,
++ set_tck_param.mode,
++ set_tck_param.tck);
++ }
++ break;
++ case AST_JTAG_GET_TCK:
++ if (copy_from_user(&get_tck_param, argp,
++ sizeof(struct get_tck_param)))
++ ret = -EFAULT;
++ else
++ ast_jtag_get_tck(ast_jtag,
++ get_tck_param.mode,
++ &get_tck_param.tck);
++ if (copy_to_user(argp, &get_tck_param,
++ sizeof(struct get_tck_param)))
++ ret = -EFAULT;
++ break;
++ case AST_JTAG_BITBANG:
++ if (copy_from_user(&bitbang, argp,
++ sizeof(struct tck_bitbang))) {
++ ret = -EFAULT;
++ } else {
++ if (bitbang.tms > 1 || bitbang.tdi > 1)
++ ret = -EFAULT;
++ else
++ ast_jtag_bitbang(ast_jtag, &bitbang);
++ }
++ if (copy_to_user(argp, &bitbang, sizeof(struct tck_bitbang)))
++ ret = -EFAULT;
++ break;
++ case AST_JTAG_SET_TAPSTATE:
++ if (copy_from_user(&tap_state_param, argp,
++ sizeof(struct tap_state_param)))
++ ret = -EFAULT;
++ else
++ ast_jtag_set_tapstate(ast_jtag, tap_state_param.mode,
++ tap_state_param.from_state,
++ tap_state_param.to_state);
++ break;
++ case AST_JTAG_READWRITESCAN:
++ if (copy_from_user(&xfer, argp,
++ sizeof(struct scan_xfer))) {
++ ret = -EFAULT;
++ } else {
++ if (xfer.tdi) {
++ user_tdi = xfer.tdi;
++ kern_tdi = memdup_user(user_tdi,
++ xfer.tdi_bytes);
++ if (IS_ERR(kern_tdi))
++ ret = -EFAULT;
++ else
++ xfer.tdi = kern_tdi;
++ }
++
++ if (ret == 0 && xfer.tdo) {
++ user_tdo = xfer.tdo;
++ kern_tdo = memdup_user(user_tdo,
++ xfer.tdo_bytes);
++ if (IS_ERR(kern_tdo))
++ ret = -EFAULT;
++ else
++ xfer.tdo = kern_tdo;
++ }
++
++ if (ret == 0)
++ ret = ast_jtag_readwrite_scan(ast_jtag, &xfer);
++
++ kfree(kern_tdi);
++ if (kern_tdo) {
++ if (ret == 0) {
++ if (copy_to_user(user_tdo,
++ xfer.tdo,
++ xfer.tdo_bytes))
++ ret = -EFAULT;
++ }
++ kfree(kern_tdo);
++ }
++ }
++ break;
++ default:
++ return -ENOTTY;
++ }
++
++ return ret;
++}
++
++static int jtag_open(struct inode *inode, struct file *file)
++{
++ struct ast_jtag_info *ast_jtag = container_of(file->private_data,
++ struct ast_jtag_info,
++ miscdev);
++
++ spin_lock(&jtag_state_lock);
++ if (ast_jtag->is_open) {
++ spin_unlock(&jtag_state_lock);
++ return -EBUSY;
++ }
++
++ ast_jtag->is_open = true;
++ file->private_data = ast_jtag;
++ ast_jtag_master(ast_jtag);
++ spin_unlock(&jtag_state_lock);
++
++ return 0;
++}
++
++static int jtag_release(struct inode *inode, struct file *file)
++{
++ struct ast_jtag_info *ast_jtag = file->private_data;
++
++ spin_lock(&jtag_state_lock);
++ ast_jtag_slave(ast_jtag);
++ ast_jtag->is_open = false;
++
++ spin_unlock(&jtag_state_lock);
++
++ return 0;
++}
++
++static const struct file_operations ast_jtag_fops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = jtag_ioctl,
++ .open = jtag_open,
++ .release = jtag_release,
++};
++
++static int ast_jtag_probe(struct platform_device *pdev)
++{
++ struct resource *scu_res;
++ struct resource *jtag_res;
++ int ret = 0;
++ struct ast_jtag_info *ast_jtag;
++
++ dev_dbg(&pdev->dev, "%s started\n", __func__);
++
++ scu_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!scu_res) {
++ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM for SCU\n");
++ ret = -ENOENT;
++ goto out;
++ }
++
++ jtag_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!jtag_res) {
++ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM for JTAG\n");
++ ret = -ENOENT;
++ goto out;
++ }
++
++ ast_jtag = devm_kzalloc(&pdev->dev, sizeof(*ast_jtag), GFP_KERNEL);
++ if (!ast_jtag)
++ return -ENOMEM;
++
++ ast_jtag->reg_base_scu = devm_ioremap_resource(&pdev->dev, scu_res);
++ if (!ast_jtag->reg_base_scu) {
++ ret = -EIO;
++ goto out;
++ }
++
++ ast_jtag->reg_base = devm_ioremap_resource(&pdev->dev, jtag_res);
++ if (!ast_jtag->reg_base) {
++ ret = -EIO;
++ goto out;
++ }
++
++ ast_jtag->dev = &pdev->dev;
++
++#ifdef USE_INTERRUPTS
++ ast_jtag->irq = platform_get_irq(pdev, 0);
++ if (ast_jtag->irq < 0) {
++ dev_err(&pdev->dev, "no irq specified.\n");
++ ret = -ENOENT;
++ goto out;
++ }
++
++ ret = devm_request_irq(&pdev->dev, ast_jtag->irq, ast_jtag_interrupt,
++ IRQF_SHARED, "ast-jtag", ast_jtag);
++ if (ret) {
++ dev_err(ast_jtag->dev, "JTAG Unable to get IRQ.\n");
++ goto out;
++ }
++#endif
++
++ ast_jtag->flag = 0;
++ init_waitqueue_head(&ast_jtag->jtag_wq);
++
++ ast_jtag->miscdev.minor = MISC_DYNAMIC_MINOR,
++ ast_jtag->miscdev.name = AST_JTAG_NAME,
++ ast_jtag->miscdev.fops = &ast_jtag_fops,
++ ast_jtag->miscdev.parent = &pdev->dev;
++ ret = misc_register(&ast_jtag->miscdev);
++ if (ret) {
++ dev_err(ast_jtag->dev, "Unable to register misc device.\n");
++ goto out;
++ }
++
++ platform_set_drvdata(pdev, ast_jtag);
++
++ ast_jtag_slave(ast_jtag);
++
++ dev_dbg(&pdev->dev, "%s completed\n", __func__);
++ return 0;
++
++out:
++ dev_warn(&pdev->dev, "ast_jtag: driver init failed (ret=%d).\n", ret);
++ return ret;
++}
++
++static int ast_jtag_remove(struct platform_device *pdev)
++{
++ dev_dbg(&pdev->dev, "%s\n", __func__);
++
++ platform_set_drvdata(pdev, NULL);
++
++ dev_dbg(&pdev->dev, "JTAG driver removed successfully.\n");
++
++ return 0;
++}
++
++static const struct of_device_id ast_jtag_of_match[] = {
++ { .compatible = "aspeed,ast2400-jtag", },
++ { .compatible = "aspeed,ast2500-jtag", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ast_jtag_of_match);
++
++static struct platform_driver ast_jtag_driver = {
++ .probe = ast_jtag_probe,
++ .remove = ast_jtag_remove,
++ .driver = {
++ .name = AST_JTAG_NAME,
++ .of_match_table = of_match_ptr(ast_jtag_of_match),
++ },
++};
++module_platform_driver(ast_jtag_driver);
++
++MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
++MODULE_AUTHOR("Bryan Hunt <bryan.hunt@intel.com>");
++MODULE_DESCRIPTION("ASPEED JTAG driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/include/uapi/linux/jtag_drv.h b/include/uapi/linux/jtag_drv.h
+new file mode 100644
+index 000000000000..4df638f8fa43
+--- /dev/null
++++ b/include/uapi/linux/jtag_drv.h
+@@ -0,0 +1,73 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/* Copyright (C) 2012-2017 ASPEED Technology Inc. */
++/* Copyright (c) 2018 Intel Corporation */
++
++#ifndef __JTAG_DRV_H__
++#define __JTAG_DRV_H__
++
++enum xfer_mode {
++ HW_MODE = 0,
++ SW_MODE
++} xfer_mode;
++
++struct tck_bitbang {
++ __u8 tms;
++ __u8 tdi;
++ __u8 tdo;
++} __attribute__((__packed__));
++
++struct scan_xfer {
++ __u8 mode;
++ __u32 tap_state;
++ __u32 length;
++ __u8 *tdi;
++ __u32 tdi_bytes;
++ __u8 *tdo;
++ __u32 tdo_bytes;
++ __u32 end_tap_state;
++} __attribute__((__packed__));
++
++struct set_tck_param {
++ __u8 mode;
++ __u32 tck;
++} __attribute__((__packed__));
++
++struct get_tck_param {
++ __u8 mode;
++ __u32 tck;
++} __attribute__((__packed__));
++
++struct tap_state_param {
++ __u8 mode;
++ __u32 from_state;
++ __u32 to_state;
++} __attribute__((__packed__));
++
++enum jtag_states {
++ jtag_tlr,
++ jtag_rti,
++ jtag_sel_dr,
++ jtag_cap_dr,
++ jtag_shf_dr,
++ jtag_ex1_dr,
++ jtag_pau_dr,
++ jtag_ex2_dr,
++ jtag_upd_dr,
++ jtag_sel_ir,
++ jtag_cap_ir,
++ jtag_shf_ir,
++ jtag_ex1_ir,
++ jtag_pau_ir,
++ jtag_ex2_ir,
++ jtag_upd_ir
++} jtag_states;
++
++#define JTAGIOC_BASE 'T'
++
++#define AST_JTAG_SET_TCK _IOW(JTAGIOC_BASE, 3, struct set_tck_param)
++#define AST_JTAG_GET_TCK _IOR(JTAGIOC_BASE, 4, struct get_tck_param)
++#define AST_JTAG_BITBANG _IOWR(JTAGIOC_BASE, 5, struct tck_bitbang)
++#define AST_JTAG_SET_TAPSTATE _IOW(JTAGIOC_BASE, 6, struct tap_state_param)
++#define AST_JTAG_READWRITESCAN _IOWR(JTAGIOC_BASE, 7, struct scan_xfer)
++
++#endif
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0029-i2c-aspeed-Improve-driver-to-support-multi-master-us.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0029-i2c-aspeed-Improve-driver-to-support-multi-master-us.patch
new file mode 100644
index 000000000..e2dee0d5b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0029-i2c-aspeed-Improve-driver-to-support-multi-master-us.patch
@@ -0,0 +1,291 @@
+From a7ad8d09cdf0ec86612df0714d3e69ee92e6140b Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 20 Nov 2018 09:30:17 -0800
+Subject: [PATCH] i2c: aspeed: Improve driver to support multi-master use cases
+ stably
+
+In multi-master environment, this driver's master cannot know
+exactly when peer master sends data to this driver's slave so
+cases can be happened that this master tries to send data through
+the master_xfer function but slave data from a peer master is still
+being processed or slave xfer is started by a peer very after it
+queues a master command.
+
+To prevent state corruption in these cases, this patch adds the
+'pending' state of master and its handling code so that the pending
+master xfer can be continued after slave mode session.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+---
+ drivers/i2c/busses/i2c-aspeed.c | 119 ++++++++++++++++++++++++++++++----------
+ 1 file changed, 91 insertions(+), 28 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index 8dc9161ced38..d11b2ea97259 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -117,6 +117,7 @@
+
+ enum aspeed_i2c_master_state {
+ ASPEED_I2C_MASTER_INACTIVE,
++ ASPEED_I2C_MASTER_PENDING,
+ ASPEED_I2C_MASTER_START,
+ ASPEED_I2C_MASTER_TX_FIRST,
+ ASPEED_I2C_MASTER_TX,
+@@ -126,12 +127,13 @@ enum aspeed_i2c_master_state {
+ };
+
+ enum aspeed_i2c_slave_state {
+- ASPEED_I2C_SLAVE_STOP,
++ ASPEED_I2C_SLAVE_INACTIVE,
+ ASPEED_I2C_SLAVE_START,
+ ASPEED_I2C_SLAVE_READ_REQUESTED,
+ ASPEED_I2C_SLAVE_READ_PROCESSED,
+ ASPEED_I2C_SLAVE_WRITE_REQUESTED,
+ ASPEED_I2C_SLAVE_WRITE_RECEIVED,
++ ASPEED_I2C_SLAVE_STOP,
+ };
+
+ struct aspeed_i2c_bus {
+@@ -156,6 +158,8 @@ struct aspeed_i2c_bus {
+ int cmd_err;
+ /* Protected only by i2c_lock_bus */
+ int master_xfer_result;
++ /* Multi-master */
++ bool multi_master;
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
+ struct i2c_client *slave;
+ enum aspeed_i2c_slave_state slave_state;
+@@ -251,7 +255,7 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ }
+
+ /* Slave is not currently active, irq was for someone else. */
+- if (bus->slave_state == ASPEED_I2C_SLAVE_STOP)
++ if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE)
+ return irq_handled;
+
+ dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
+@@ -277,16 +281,15 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP;
+ bus->slave_state = ASPEED_I2C_SLAVE_STOP;
+ }
+- if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
++ if (irq_status & ASPEED_I2CD_INTR_TX_NAK &&
++ bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) {
+ irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
+ bus->slave_state = ASPEED_I2C_SLAVE_STOP;
+ }
+- if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
+- irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
+
+ switch (bus->slave_state) {
+ case ASPEED_I2C_SLAVE_READ_REQUESTED:
+- if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
++ if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_ACK))
+ dev_err(bus->dev, "Unexpected ACK on read request.\n");
+ bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
+ i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
+@@ -294,9 +297,12 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
+ break;
+ case ASPEED_I2C_SLAVE_READ_PROCESSED:
+- if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
++ if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
+ dev_err(bus->dev,
+ "Expected ACK after processed read.\n");
++ break;
++ }
++ irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
+ i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
+ writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
+ writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
+@@ -310,10 +316,15 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ break;
+ case ASPEED_I2C_SLAVE_STOP:
+ i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
++ bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
++ break;
++ case ASPEED_I2C_SLAVE_START:
++ /* Slave was just started. Waiting for the next event. */;
+ break;
+ default:
+- dev_err(bus->dev, "unhandled slave_state: %d\n",
++ dev_err(bus->dev, "unknown slave_state: %d\n",
+ bus->slave_state);
++ bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
+ break;
+ }
+
+@@ -328,7 +339,17 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus)
+ struct i2c_msg *msg = &bus->msgs[bus->msgs_index];
+ u8 slave_addr = i2c_8bit_addr_from_msg(msg);
+
+- bus->master_state = ASPEED_I2C_MASTER_START;
++#if IS_ENABLED(CONFIG_I2C_SLAVE)
++ /*
++ * If it's requested in the middle of a slave session, set the master
++ * state to 'pending' then H/W will continue handling this master
++ * command when the bus comes back to idle state.
++ */
++ if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE)
++ bus->master_state = ASPEED_I2C_MASTER_PENDING;
++ else
++#endif /* CONFIG_I2C_SLAVE */
++ bus->master_state = ASPEED_I2C_MASTER_START;
+ bus->buf_index = 0;
+
+ if (msg->flags & I2C_M_RD) {
+@@ -384,10 +405,6 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
+ irq_handled |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
+ goto out_complete;
+- } else {
+- /* Master is not currently active, irq was for someone else. */
+- if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE)
+- goto out_no_complete;
+ }
+
+ /*
+@@ -399,12 +416,33 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ if (ret) {
+ dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
+ irq_status);
+- bus->cmd_err = ret;
+- bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
+ irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS);
+- goto out_complete;
++ if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
++ bus->cmd_err = ret;
++ bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
++ goto out_complete;
++ }
+ }
+
++#if IS_ENABLED(CONFIG_I2C_SLAVE)
++ /*
++ * A pending master command will be started by H/W when the bus comes
++ * back to idle state after completing a slave operation so change the
++ * master state from 'pending' to 'start' at here if slave is inactive.
++ */
++ if (bus->master_state == ASPEED_I2C_MASTER_PENDING) {
++ if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE)
++ goto out_no_complete;
++
++ bus->master_state = ASPEED_I2C_MASTER_START;
++ }
++#endif /* CONFIG_I2C_SLAVE */
++
++ /* Master is not currently active, irq was for someone else. */
++ if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE ||
++ bus->master_state == ASPEED_I2C_MASTER_PENDING)
++ goto out_no_complete;
++
+ /* We are in an invalid state; reset bus to a known state. */
+ if (!bus->msgs) {
+ dev_err(bus->dev, "bus in unknown state. irq_status: 0x%x\n",
+@@ -423,6 +461,20 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ * then update the state and handle the new state below.
+ */
+ if (bus->master_state == ASPEED_I2C_MASTER_START) {
++#if IS_ENABLED(CONFIG_I2C_SLAVE)
++ /*
++ * If a peer master starts a xfer very after it queues a master
++ * command, change its state to 'pending' then H/W will continue
++ * the queued master xfer just after completing the slave mode
++ * session.
++ */
++ if (unlikely(irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH)) {
++ bus->master_state = ASPEED_I2C_MASTER_PENDING;
++ dev_dbg(bus->dev,
++ "master goes pending due to a slave start\n");
++ goto out_no_complete;
++ }
++#endif /* CONFIG_I2C_SLAVE */
+ if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
+ if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_NAK))) {
+ bus->cmd_err = -ENXIO;
+@@ -566,7 +618,8 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
+ * interrupt bits. Each case needs to be handled using corresponding
+ * handlers depending on the current state.
+ */
+- if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
++ if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE &&
++ bus->master_state != ASPEED_I2C_MASTER_PENDING) {
+ irq_handled = aspeed_i2c_master_irq(bus, irq_remaining);
+ irq_remaining &= ~irq_handled;
+ if (irq_remaining)
+@@ -601,15 +654,14 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
+ {
+ struct aspeed_i2c_bus *bus = i2c_get_adapdata(adap);
+ unsigned long time_left, flags;
+- int ret = 0;
++ int ret;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ bus->cmd_err = 0;
+
+- /* If bus is busy, attempt recovery. We assume a single master
+- * environment.
+- */
+- if (readl(bus->base + ASPEED_I2C_CMD_REG) & ASPEED_I2CD_BUS_BUSY_STS) {
++ /* If bus is busy in a single master environment, attempt recovery. */
++ if (!bus->multi_master &&
++ (readl(bus->base + ASPEED_I2C_CMD_REG) & ASPEED_I2CD_BUS_BUSY_STS)) {
+ spin_unlock_irqrestore(&bus->lock, flags);
+ ret = aspeed_i2c_recover_bus(bus);
+ if (ret)
+@@ -629,10 +681,20 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
+ time_left = wait_for_completion_timeout(&bus->cmd_complete,
+ bus->adap.timeout);
+
+- if (time_left == 0)
++ if (time_left == 0) {
++ /*
++ * If timed out and bus is still busy in a multi master
++ * environment, attempt recovery at here.
++ */
++ if (bus->multi_master &&
++ (readl(bus->base + ASPEED_I2C_CMD_REG) &
++ ASPEED_I2CD_BUS_BUSY_STS))
++ ret = aspeed_i2c_recover_bus(bus);
++
+ return -ETIMEDOUT;
+- else
+- return bus->master_xfer_result;
++ }
++
++ return bus->master_xfer_result;
+ }
+
+ static u32 aspeed_i2c_functionality(struct i2c_adapter *adap)
+@@ -672,7 +734,7 @@ static int aspeed_i2c_reg_slave(struct i2c_client *client)
+ __aspeed_i2c_reg_slave(bus, client->addr);
+
+ bus->slave = client;
+- bus->slave_state = ASPEED_I2C_SLAVE_STOP;
++ bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ return 0;
+@@ -827,7 +889,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus,
+ if (ret < 0)
+ return ret;
+
+- if (!of_property_read_bool(pdev->dev.of_node, "multi-master"))
++ if (of_property_read_bool(pdev->dev.of_node, "multi-master"))
++ bus->multi_master = true;
++ else
+ fun_ctrl_reg |= ASPEED_I2CD_MULTI_MASTER_DIS;
+
+ /* Enable Master Mode */
+@@ -930,7 +994,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+ init_completion(&bus->cmd_complete);
+ bus->adap.owner = THIS_MODULE;
+ bus->adap.retries = 0;
+- bus->adap.timeout = 5 * HZ;
+ bus->adap.algo = &aspeed_i2c_algo;
+ bus->adap.dev.parent = &pdev->dev;
+ bus->adap.dev.of_node = pdev->dev.of_node;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch
new file mode 100644
index 000000000..b735ab38b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch
@@ -0,0 +1,151 @@
+From 577b65960842f4098cdfc85a311261477c051d84 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Fri, 29 Jun 2018 11:00:02 -0700
+Subject: [PATCH] Add dump debug code into I2C drivers
+
+This commit enables dump debug of master and slave I2C drivers.
+This is only for downstream debug purpose so it shouldn't go to
+the upstream.
+
+Usage (in case of bus 5 for an example):
+echo 5 > /sys/module/i2c_aspeed/parameters/dump_debug_bus_id
+echo 1 > /sys/module/i2c_aspeed/parameters/dump_debug
+echo 5 > /sys/module/i2c_slave_mqueue/parameters/dump_debug_bus_id
+echo 1 > /sys/module/i2c_slave_mqueue/parameters/dump_debug
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/i2c/busses/i2c-aspeed.c | 25 +++++++++++++++++++++++++
+ drivers/i2c/i2c-slave-mqueue.c | 24 ++++++++++++++++++++++++
+ 2 files changed, 49 insertions(+)
+
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index d11b2ea97259..506d867b43d9 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -166,6 +166,19 @@ struct aspeed_i2c_bus {
+ #endif /* CONFIG_I2C_SLAVE */
+ };
+
++static bool dump_debug __read_mostly;
++static int dump_debug_bus_id __read_mostly;
++
++#define I2C_HEX_DUMP(bus, addr, flags, buf, len) \
++ if (dump_debug && bus->adap.nr == dump_debug_bus_id) { \
++ char dump_info[100] = {0,}; \
++ snprintf(dump_info, sizeof(dump_info), \
++ "%s (bus_id:%d, addr:0x%02x, flags:0x%02x): ", \
++ __func__, bus->adap.nr, addr, flags); \
++ print_hex_dump(KERN_ERR, dump_info, DUMP_PREFIX_NONE, 16, 1, \
++ buf, len, true); \
++ }
++
+ static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus);
+
+ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
+@@ -655,6 +668,7 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
+ struct aspeed_i2c_bus *bus = i2c_get_adapdata(adap);
+ unsigned long time_left, flags;
+ int ret;
++ int i;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ bus->cmd_err = 0;
+@@ -694,6 +708,11 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
+ return -ETIMEDOUT;
+ }
+
++ for (i = 0; i < num; i++) {
++ I2C_HEX_DUMP(bus, msgs[i].addr, msgs[i].flags,
++ msgs[i].buf, msgs[i].len);
++ }
++
+ return bus->master_xfer_result;
+ }
+
+@@ -1061,6 +1080,12 @@ static struct platform_driver aspeed_i2c_bus_driver = {
+ };
+ module_platform_driver(aspeed_i2c_bus_driver);
+
++module_param_named(dump_debug, dump_debug, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(dump_debug, "debug flag for dump printing");
++module_param_named(dump_debug_bus_id, dump_debug_bus_id, int,
++ S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(dump_debug_bus_id, "bus id for dump debug printing");
++
+ MODULE_AUTHOR("Brendan Higgins <brendanhiggins@google.com>");
+ MODULE_DESCRIPTION("Aspeed I2C Bus Driver");
+ MODULE_LICENSE("GPL v2");
+diff --git a/drivers/i2c/i2c-slave-mqueue.c b/drivers/i2c/i2c-slave-mqueue.c
+index 6014bca0ff2a..0140c0dc4c03 100644
+--- a/drivers/i2c/i2c-slave-mqueue.c
++++ b/drivers/i2c/i2c-slave-mqueue.c
+@@ -21,6 +21,7 @@ struct mq_msg {
+ struct mq_queue {
+ struct bin_attribute bin;
+ struct kernfs_node *kn;
++ struct i2c_client *client;
+
+ spinlock_t lock; /* spinlock for queue index handling */
+ int in;
+@@ -31,6 +32,19 @@ struct mq_queue {
+ struct mq_msg *queue;
+ };
+
++static bool dump_debug __read_mostly;
++static int dump_debug_bus_id __read_mostly;
++
++#define I2C_HEX_DUMP(client, buf, len) \
++ if (dump_debug && client->adapter->nr == dump_debug_bus_id) { \
++ char dump_info[100] = {0,}; \
++ snprintf(dump_info, sizeof(dump_info), \
++ "%s (bus_id:%d, addr:0x%02x): ", \
++ __func__, client->adapter->nr, client->addr); \
++ print_hex_dump(KERN_ERR, dump_info, DUMP_PREFIX_NONE, 16, 1, \
++ buf, len, true); \
++ }
++
+ static int i2c_slave_mqueue_callback(struct i2c_client *client,
+ enum i2c_slave_event event, u8 *val)
+ {
+@@ -49,6 +63,7 @@ static int i2c_slave_mqueue_callback(struct i2c_client *client,
+ case I2C_SLAVE_WRITE_RECEIVED:
+ if (msg->len < MQ_MSGBUF_SIZE) {
+ msg->buf[msg->len++] = *val;
++ I2C_HEX_DUMP(client, val, 1);
+ } else {
+ dev_err(&client->dev, "message is truncated!\n");
+ mq->truncated = 1;
+@@ -101,6 +116,7 @@ static ssize_t i2c_slave_mqueue_bin_read(struct file *filp,
+ if (msg->len <= count) {
+ ret = msg->len;
+ memcpy(buf, msg->buf, ret);
++ I2C_HEX_DUMP(mq->client, buf, ret);
+ } else {
+ ret = -EOVERFLOW; /* Drop this HUGE one. */
+ }
+@@ -131,6 +147,8 @@ static int i2c_slave_mqueue_probe(struct i2c_client *client,
+
+ BUILD_BUG_ON(!is_power_of_2(MQ_QUEUE_SIZE));
+
++ mq->client = client;
++
+ buf = devm_kmalloc_array(dev, MQ_QUEUE_SIZE, MQ_MSGBUF_SIZE,
+ GFP_KERNEL);
+ if (!buf)
+@@ -212,6 +230,12 @@ static struct i2c_driver i2c_slave_mqueue_driver = {
+ };
+ module_i2c_driver(i2c_slave_mqueue_driver);
+
++module_param_named(dump_debug, dump_debug, bool, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(dump_debug, "debug flag for dump printing");
++module_param_named(dump_debug_bus_id, dump_debug_bus_id, int,
++ S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(dump_debug_bus_id, "bus id for dump debug printing");
++
+ MODULE_LICENSE("GPL v2");
+ MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
+ MODULE_DESCRIPTION("I2C slave mode for receiving and queuing messages");
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch
new file mode 100644
index 000000000..8c9d2dce0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch
@@ -0,0 +1,132 @@
+From 7baa65c9bf638265874838401e27a7b6179559ff Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Wed, 2 Jan 2019 15:06:43 +0800
+Subject: [PATCH] Add high speed baud rate support for UART
+
+In order to support high speed baud rate(921600 bps),
+the default UART clock(24MHz) needs to be switched
+to 192MHz(from USB2.0 port1 PHY).
+
+Create a new 192M Hz clock and assign it to uart,
+based on uart clock source configuration in SCU4C.
+
+bootloader(u-boot) will set SCU4C based on the environment configuration
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ drivers/clk/clk-aspeed.c | 41 +++++++++++++++++++++++++++-----
+ include/dt-bindings/clock/aspeed-clock.h | 2 ++
+ 2 files changed, 37 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
+index 5961367..3bbb4fb 100644
+--- a/drivers/clk/clk-aspeed.c
++++ b/drivers/clk/clk-aspeed.c
+@@ -14,7 +14,9 @@
+
+ #include <dt-bindings/clock/aspeed-clock.h>
+
+-#define ASPEED_NUM_CLKS 36
++#define ASPEED_NUM_CLKS ASPEED_CLK_MAX
++#define UART_HIGH_SPEED_CLK 192000000
++#define UART_LOW_SPEED_CLK 24000000
+
+ #define ASPEED_RESET2_OFFSET 32
+
+@@ -28,6 +30,12 @@
+ #define AST2400_HPLL_BYPASS_EN BIT(17)
+ #define ASPEED_MISC_CTRL 0x2c
+ #define UART_DIV13_EN BIT(12)
++#define ASPEED_MISC2_CTRL 0x4c
++#define UART1_HS_CLK_EN BIT(24)
++#define UART2_HS_CLK_EN BIT(25)
++#define UART3_HS_CLK_EN BIT(26)
++#define UART4_HS_CLK_EN BIT(27)
++#define UART5_HS_CLK_EN BIT(28)
+ #define ASPEED_STRAP 0x70
+ #define CLKIN_25MHZ_EN BIT(23)
+ #define AST2400_CLK_SOURCE_SEL BIT(18)
+@@ -425,7 +433,7 @@ static int aspeed_clk_probe(struct platform_device *pdev)
+ struct aspeed_reset *ar;
+ struct regmap *map;
+ struct clk_hw *hw;
+- u32 val, rate;
++ u32 val, uart_clock_div;
+ int i, ret;
+
+ map = syscon_node_to_regmap(dev->of_node);
+@@ -460,15 +468,23 @@ static int aspeed_clk_probe(struct platform_device *pdev)
+ /* UART clock div13 setting */
+ regmap_read(map, ASPEED_MISC_CTRL, &val);
+ if (val & UART_DIV13_EN)
+- rate = 24000000 / 13;
++ uart_clock_div = 13;
+ else
+- rate = 24000000;
++ uart_clock_div = 1;
++
+ /* TODO: Find the parent data for the uart clock */
+- hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate);
++ hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0,
++ UART_LOW_SPEED_CLK / uart_clock_div);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_clk_data->hws[ASPEED_CLK_UART] = hw;
+
++ hw = clk_hw_register_fixed_rate(dev, "uart-hs", "usb-port1-gate", 0,
++ UART_HIGH_SPEED_CLK / uart_clock_div);
++ if (IS_ERR(hw))
++ return PTR_ERR(hw);
++ aspeed_clk_data->hws[ASPEED_CLK_UART_HS] = hw;
++
+ /*
+ * Memory controller (M-PLL) PLL. This clock is configured by the
+ * bootloader, and is exposed to Linux as a read-only clock rate.
+@@ -534,9 +550,22 @@ static int aspeed_clk_probe(struct platform_device *pdev)
+ * Video Engine (ECLK) mux and clock divider
+ */
+
++ /* Get the uart clock source configuration from SCU4C*/
++ regmap_read(map, ASPEED_MISC2_CTRL, &val);
+ for (i = 0; i < ARRAY_SIZE(aspeed_gates); i++) {
+ const struct aspeed_gate_data *gd = &aspeed_gates[i];
+ u32 gate_flags;
++ char *parent_name;
++
++ /* For uart, needs to adjust the clock based on SCU4C value */
++ if ((i == ASPEED_CLK_GATE_UART1CLK && (val & UART1_HS_CLK_EN)) ||
++ (i == ASPEED_CLK_GATE_UART2CLK && (val & UART2_HS_CLK_EN)) ||
++ (i == ASPEED_CLK_GATE_UART5CLK && (val & UART5_HS_CLK_EN)) ||
++ (i == ASPEED_CLK_GATE_UART3CLK && (val & UART3_HS_CLK_EN)) ||
++ (i == ASPEED_CLK_GATE_UART4CLK && (val & UART4_HS_CLK_EN)))
++ parent_name = "uart-hs";
++ else
++ parent_name = gd->parent_name;
+
+ /* Special case: the USB port 1 clock (bit 14) is always
+ * working the opposite way from the other ones.
+@@ -544,7 +573,7 @@ static int aspeed_clk_probe(struct platform_device *pdev)
+ gate_flags = (gd->clock_idx == 14) ? 0 : CLK_GATE_SET_TO_DISABLE;
+ hw = aspeed_clk_hw_register_gate(dev,
+ gd->name,
+- gd->parent_name,
++ parent_name,
+ gd->flags,
+ map,
+ gd->clock_idx,
+diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h
+index f437386..3358795 100644
+--- a/include/dt-bindings/clock/aspeed-clock.h
++++ b/include/dt-bindings/clock/aspeed-clock.h
+@@ -39,6 +39,8 @@
+ #define ASPEED_CLK_BCLK 33
+ #define ASPEED_CLK_MPLL 34
+ #define ASPEED_CLK_24M 35
++#define ASPEED_CLK_UART_HS 36
++#define ASPEED_CLK_MAX 37
+
+ #define ASPEED_RESET_XDMA 0
+ #define ASPEED_RESET_MCTP 1
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch
new file mode 100644
index 000000000..539c976c7
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch
@@ -0,0 +1,556 @@
+From e39e3a3e54cbe8e5a39b4148a9232f4570d009a6 Mon Sep 17 00:00:00 2001
+From: Oskar Senft <osk@google.com>
+Date: Wed, 8 Aug 2018 10:15:05 -0400
+Subject: [PATCH] misc: aspeed: Add Aspeed UART routing control driver.
+
+This driver adds sysfs files that allow the BMC userspace to configure
+how UARTs and physical serial I/O ports are routed.
+
+Tested: Checked correct behavior (both read & write) on TYAN S7106
+board by manually changing routing settings and confirming that bits
+flow as expected. Tested for UART1 and UART3 as this board doesn't have
+the other UARTs wired up in a testable way.
+
+Signed-off-by: Oskar Senft <osk@google.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ .../ABI/stable/sysfs-driver-aspeed-uart-routing | 14 +
+ Documentation/misc-devices/aspeed-uart-routing.txt | 49 +++
+ arch/arm/boot/dts/aspeed-bmc-intel-purley.dts | 4 +
+ arch/arm/boot/dts/aspeed-g5.dtsi | 6 +
+ drivers/misc/Kconfig | 6 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/aspeed-uart-routing.c | 383 +++++++++++++++++++++
+ 7 files changed, 463 insertions(+)
+ create mode 100644 Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing
+ create mode 100644 Documentation/misc-devices/aspeed-uart-routing.txt
+ create mode 100644 drivers/misc/aspeed-uart-routing.c
+
+diff --git a/Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing b/Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing
+new file mode 100644
+index 000000000000..5068737d9c12
+--- /dev/null
++++ b/Documentation/ABI/stable/sysfs-driver-aspeed-uart-routing
+@@ -0,0 +1,14 @@
++What: /sys/bus/platform/drivers/aspeed-uart-routing/*/io*
++Date: August 2018
++Contact: Oskar Senft <osk@google.com>
++Description: Configures the input source for the specific physical
++ serial I/O port.
++Users: OpenBMC. Proposed changes should be mailed to
++ openbmc@lists.ozlabs.org
++
++What: /sys/bus/platform/drivers/aspeed-uart-routing/*/uart*
++Date: August 2018
++Contact: Oskar Senft <osk@google.com>
++Description: Configures the input source for the specific UART.
++Users: OpenBMC. Proposed changes should be mailed to
++ openbmc@lists.ozlabs.org
+diff --git a/Documentation/misc-devices/aspeed-uart-routing.txt b/Documentation/misc-devices/aspeed-uart-routing.txt
+new file mode 100644
+index 000000000000..afaf17cb7eda
+--- /dev/null
++++ b/Documentation/misc-devices/aspeed-uart-routing.txt
+@@ -0,0 +1,49 @@
++Kernel driver aspeed-uart-routing
++=================================
++
++Supported chips:
++ASPEED AST2500
++
++Author:
++Google LLC
++
++Description
++-----------
++
++The Aspeed AST2500 allows to dynamically route the inputs for the built-in
++UARTS and physical serial I/O ports.
++
++This allows, for example, to connect the output of UART to another UART.
++This can be used to enable host<->BMC communication via UARTs, e.g. to allow
++access to the host's serial console.
++
++This driver is for the BMC side. The sysfs files allow the BMC userspace
++which owns the system configuration policy, to configure how UARTs and
++physical serial I/O ports are routed.
++
++The driver provides the following files in sysfs:
++uart1 Configure the input signal to UART1.
++uart2 Configure the input signal to UART2.
++uart3 Configure the input signal to UART3.
++uart4 Configure the input signal to UART4.
++uart5 Configure the input signal to UART5.
++io1 Configure the input signal to physical serial port 1.
++io2 Configure the input signal to physical serial port 2.
++io3 Configure the input signal to physical serial port 3.
++io4 Configure the input signal to physical serial port 4.
++io5 Configure the input signal to physical serial port 5.
++
++When read, each file shows the list of available options with the currently
++selected option marked by square brackets "[]". The list of available options
++depends on the selected file.
++
++Example:
++$ cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1
++[io1] io2 io3 io4 uart2 uart3 uart4 io6
++
++In this case, UART1 gets its input signal from IO1 (physical serial port 1).
++
++$ echo -n "uart3" \
++ >/sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1
++$ cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1
++io1 io2 io3 io4 uart2 [uart3] uart4 io6
+diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
+index 655bb37e422f..eb05f5a2c480 100644
+--- a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
++++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
+@@ -174,6 +174,10 @@
+ status = "okay";
+ };
+
++&uart_routing {
++ status = "okay";
++};
++
+ &mac1 {
+ status = "okay";
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index 3bb31c1daf9d..92843cc1a8f4 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -482,6 +482,12 @@
+ status = "disabled";
+ };
+ };
++
++ uart_routing: uart_routing@9c {
++ compatible = "aspeed,ast2500-uart-routing";
++ reg = <0x9c 0x4>;
++ status = "disabled";
++ };
+ };
+
+ peci: bus@1e78b000 {
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index f2062546250c..8e2fc51dcc44 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -537,6 +537,12 @@ config MISC_RTSX
+ tristate
+ default MISC_RTSX_PCI || MISC_RTSX_USB
+
++config ASPEED_UART_ROUTING
++ tristate "Aspeed ast2500 UART routing control"
++ help
++ If you want to configure UART routing on Aspeed BMC platforms, enable
++ this option.
++
+ source "drivers/misc/c2port/Kconfig"
+ source "drivers/misc/eeprom/Kconfig"
+ source "drivers/misc/cb710/Kconfig"
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index bb89694e6b4b..0f00eb63556c 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -56,6 +56,7 @@ obj-$(CONFIG_CXL_BASE) += cxl/
+ obj-$(CONFIG_ASPEED_ESPI_SLAVE) += aspeed-espi-slave.o
+ obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
+ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
++obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o
+ obj-$(CONFIG_ASPEED_LPC_MBOX) += aspeed-lpc-mbox.o
+ obj-$(CONFIG_ASPEED_LPC_SIO) += aspeed-lpc-sio.o
+ obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
+diff --git a/drivers/misc/aspeed-uart-routing.c b/drivers/misc/aspeed-uart-routing.c
+new file mode 100644
+index 000000000000..21ef5d98c317
+--- /dev/null
++++ b/drivers/misc/aspeed-uart-routing.c
+@@ -0,0 +1,383 @@
++/*
++ * UART Routing driver for Aspeed AST2500
++ *
++ * Copyright (c) 2018 Google LLC
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++
++/* The Aspeed AST2500 allows to dynamically route the inputs for the built-in
++ * UARTS and physical serial I/O ports.
++ *
++ * This allows, for example, to connect the output of UART to another UART.
++ * This can be used to enable host<->BMC communication via UARTs, e.g. to allow
++ * access to the host's serial console.
++ *
++ * This driver is for the BMC side. The sysfs files allow the BMC userspace
++ * which owns the system configuration policy, to configure how UARTs and
++ * physical serial I/O ports are routed.
++ */
++
++#define ASPEED_HICRA_IO1 "io1"
++#define ASPEED_HICRA_IO2 "io2"
++#define ASPEED_HICRA_IO3 "io3"
++#define ASPEED_HICRA_IO4 "io4"
++#define ASPEED_HICRA_IO5 "io5"
++#define ASPEED_HICRA_IO6 "io6"
++#define ASPEED_HICRA_UART1 "uart1"
++#define ASPEED_HICRA_UART2 "uart2"
++#define ASPEED_HICRA_UART3 "uart3"
++#define ASPEED_HICRA_UART4 "uart4"
++#define ASPEED_HICRA_UART5 "uart5"
++
++struct aspeed_uart_routing {
++ struct device *dev;
++ void __iomem *regs;
++ spinlock_t lock;
++};
++
++struct aspeed_uart_routing_selector {
++ struct device_attribute dev_attr;
++ int shift;
++ int mask;
++ const char * const options[];
++};
++
++#define to_routing_selector(_dev_attr) \
++ container_of(_dev_attr, struct aspeed_uart_routing_selector, dev_attr)
++
++
++static ssize_t aspeed_uart_routing_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf);
++
++static ssize_t aspeed_uart_routing_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count);
++
++#define ROUTING_ATTR(_name) { \
++ .attr = {.name = _name, \
++ .mode = VERIFY_OCTAL_PERMISSIONS(S_IWUSR | S_IRUGO) }, \
++ .show = aspeed_uart_routing_show, \
++ .store = aspeed_uart_routing_store, \
++}
++
++static struct aspeed_uart_routing_selector uart5_sel = {
++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART5),
++ .shift = 28,
++ .mask = 0xf,
++ .options = {
++ ASPEED_HICRA_IO5, // 0
++ ASPEED_HICRA_IO1, // 1
++ ASPEED_HICRA_IO2, // 2
++ ASPEED_HICRA_IO3, // 3
++ ASPEED_HICRA_IO4, // 4
++ ASPEED_HICRA_UART1, // 5
++ ASPEED_HICRA_UART2, // 6
++ ASPEED_HICRA_UART3, // 7
++ ASPEED_HICRA_UART4, // 8
++ ASPEED_HICRA_IO6, // 9
++ NULL, // NULL termination
++ },
++};
++
++static struct aspeed_uart_routing_selector uart4_sel = {
++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART4),
++ .shift = 25,
++ .mask = 0x7,
++ .options = {
++ ASPEED_HICRA_IO4, // 0
++ ASPEED_HICRA_IO1, // 1
++ ASPEED_HICRA_IO2, // 2
++ ASPEED_HICRA_IO3, // 3
++ ASPEED_HICRA_UART1, // 4
++ ASPEED_HICRA_UART2, // 5
++ ASPEED_HICRA_UART3, // 6
++ ASPEED_HICRA_IO6, // 7
++ NULL, // NULL termination
++ },
++};
++
++static struct aspeed_uart_routing_selector uart3_sel = {
++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART3),
++ .shift = 22,
++ .mask = 0x7,
++ .options = {
++ ASPEED_HICRA_IO3, // 0
++ ASPEED_HICRA_IO4, // 1
++ ASPEED_HICRA_IO1, // 2
++ ASPEED_HICRA_IO2, // 3
++ ASPEED_HICRA_UART4, // 4
++ ASPEED_HICRA_UART1, // 5
++ ASPEED_HICRA_UART2, // 6
++ ASPEED_HICRA_IO6, // 7
++ NULL, // NULL termination
++ },
++};
++
++static struct aspeed_uart_routing_selector uart2_sel = {
++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART2),
++ .shift = 19,
++ .mask = 0x7,
++ .options = {
++ ASPEED_HICRA_IO2, // 0
++ ASPEED_HICRA_IO3, // 1
++ ASPEED_HICRA_IO4, // 2
++ ASPEED_HICRA_IO1, // 3
++ ASPEED_HICRA_UART3, // 4
++ ASPEED_HICRA_UART4, // 5
++ ASPEED_HICRA_UART1, // 6
++ ASPEED_HICRA_IO6, // 7
++ NULL, // NULL termination
++ },
++};
++
++static struct aspeed_uart_routing_selector uart1_sel = {
++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_UART1),
++ .shift = 16,
++ .mask = 0x7,
++ .options = {
++ ASPEED_HICRA_IO1, // 0
++ ASPEED_HICRA_IO2, // 1
++ ASPEED_HICRA_IO3, // 2
++ ASPEED_HICRA_IO4, // 3
++ ASPEED_HICRA_UART2, // 4
++ ASPEED_HICRA_UART3, // 5
++ ASPEED_HICRA_UART4, // 6
++ ASPEED_HICRA_IO6, // 7
++ NULL, // NULL termination
++ },
++};
++
++static struct aspeed_uart_routing_selector io5_sel = {
++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO5),
++ .shift = 12,
++ .mask = 0x7,
++ .options = {
++ ASPEED_HICRA_UART5, // 0
++ ASPEED_HICRA_UART1, // 1
++ ASPEED_HICRA_UART2, // 2
++ ASPEED_HICRA_UART3, // 3
++ ASPEED_HICRA_UART4, // 4
++ ASPEED_HICRA_IO1, // 5
++ ASPEED_HICRA_IO3, // 6
++ ASPEED_HICRA_IO6, // 7
++ NULL, // NULL termination
++ },
++};
++
++static struct aspeed_uart_routing_selector io4_sel = {
++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO4),
++ .shift = 9,
++ .mask = 0x7,
++ .options = {
++ ASPEED_HICRA_UART4, // 0
++ ASPEED_HICRA_UART5, // 1
++ ASPEED_HICRA_UART1, // 2
++ ASPEED_HICRA_UART2, // 3
++ ASPEED_HICRA_UART3, // 4
++ ASPEED_HICRA_IO1, // 5
++ ASPEED_HICRA_IO2, // 6
++ ASPEED_HICRA_IO6, // 7
++ NULL, // NULL termination
++ },
++};
++
++static struct aspeed_uart_routing_selector io3_sel = {
++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO3),
++ .shift = 6,
++ .mask = 0x7,
++ .options = {
++ ASPEED_HICRA_UART3, // 0
++ ASPEED_HICRA_UART4, // 1
++ ASPEED_HICRA_UART5, // 2
++ ASPEED_HICRA_UART1, // 3
++ ASPEED_HICRA_UART2, // 4
++ ASPEED_HICRA_IO1, // 5
++ ASPEED_HICRA_IO2, // 6
++ ASPEED_HICRA_IO6, // 7
++ NULL, // NULL termination
++ },
++};
++
++static struct aspeed_uart_routing_selector io2_sel = {
++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO2),
++ .shift = 3,
++ .mask = 0x7,
++ .options = {
++ ASPEED_HICRA_UART2, // 0
++ ASPEED_HICRA_UART3, // 1
++ ASPEED_HICRA_UART4, // 2
++ ASPEED_HICRA_UART5, // 3
++ ASPEED_HICRA_UART1, // 4
++ ASPEED_HICRA_IO3, // 5
++ ASPEED_HICRA_IO4, // 6
++ ASPEED_HICRA_IO6, // 7
++ NULL, // NULL termination
++ },
++};
++
++static struct aspeed_uart_routing_selector io1_sel = {
++ .dev_attr = ROUTING_ATTR(ASPEED_HICRA_IO1),
++ .shift = 0,
++ .mask = 0x7,
++ .options = {
++ ASPEED_HICRA_UART1, // 0
++ ASPEED_HICRA_UART2, // 1
++ ASPEED_HICRA_UART3, // 2
++ ASPEED_HICRA_UART4, // 3
++ ASPEED_HICRA_UART5, // 4
++ ASPEED_HICRA_IO3, // 5
++ ASPEED_HICRA_IO4, // 6
++ ASPEED_HICRA_IO6, // 7
++ NULL, // NULL termination
++ },
++};
++
++
++static struct attribute *aspeed_uart_routing_attrs[] = {
++ &uart1_sel.dev_attr.attr,
++ &uart2_sel.dev_attr.attr,
++ &uart3_sel.dev_attr.attr,
++ &uart4_sel.dev_attr.attr,
++ &uart5_sel.dev_attr.attr,
++ &io1_sel.dev_attr.attr,
++ &io2_sel.dev_attr.attr,
++ &io3_sel.dev_attr.attr,
++ &io4_sel.dev_attr.attr,
++ &io5_sel.dev_attr.attr,
++ NULL,
++};
++
++static const struct attribute_group aspeed_uart_routing_attr_group = {
++ .attrs = aspeed_uart_routing_attrs,
++};
++
++static ssize_t aspeed_uart_routing_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct aspeed_uart_routing *uart_routing = dev_get_drvdata(dev);
++ struct aspeed_uart_routing_selector *sel = to_routing_selector(attr);
++ int val, pos, len;
++
++ val = (readl(uart_routing->regs) >> sel->shift) & sel->mask;
++
++ len = 0;
++ for (pos = 0; sel->options[pos] != NULL; ++pos) {
++ if (pos == val) {
++ len += snprintf(buf + len, PAGE_SIZE - 1 - len,
++ "[%s] ", sel->options[pos]);
++ } else {
++ len += snprintf(buf + len, PAGE_SIZE - 1 - len,
++ "%s ", sel->options[pos]);
++ }
++ }
++
++ if (val >= pos) {
++ len += snprintf(buf + len, PAGE_SIZE - 1 - len,
++ "[unknown(%d)]", val);
++ }
++
++ len += snprintf(buf + len, PAGE_SIZE - 1 - len, "\n");
++
++ return len;
++}
++
++static ssize_t aspeed_uart_routing_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct aspeed_uart_routing *uart_routing = dev_get_drvdata(dev);
++ struct aspeed_uart_routing_selector *sel = to_routing_selector(attr);
++ int val;
++ u32 reg;
++
++ val = match_string(sel->options, -1, buf);
++ if (val < 0) {
++ dev_err(dev, "invalid value \"%s\"\n", buf);
++ return -EINVAL;
++ }
++
++ spin_lock(&uart_routing->lock);
++ reg = readl(uart_routing->regs);
++ // Zero out existing value in specified bits.
++ reg &= ~(sel->mask << sel->shift);
++ // Set new value in specified bits.
++ reg |= (val & sel->mask) << sel->shift;
++ writel(reg, uart_routing->regs);
++ spin_unlock(&uart_routing->lock);
++
++ return count;
++}
++
++static int aspeed_uart_routing_probe(struct platform_device *pdev)
++{
++ struct aspeed_uart_routing *uart_routing;
++ struct resource *res;
++ int rc;
++
++ uart_routing = devm_kzalloc(&pdev->dev,
++ sizeof(*uart_routing),
++ GFP_KERNEL);
++ if (!uart_routing)
++ return -ENOMEM;
++
++ spin_lock_init(&uart_routing->lock);
++ uart_routing->dev = &pdev->dev;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ uart_routing->regs = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(uart_routing->regs))
++ return PTR_ERR(uart_routing->regs);
++
++ rc = sysfs_create_group(&uart_routing->dev->kobj,
++ &aspeed_uart_routing_attr_group);
++ if (rc < 0)
++ return rc;
++
++ platform_set_drvdata(pdev, uart_routing);
++
++ return 0;
++}
++
++static int aspeed_uart_routing_remove(struct platform_device *pdev)
++{
++ struct aspeed_uart_routing *uart_routing = platform_get_drvdata(pdev);
++
++ sysfs_remove_group(&uart_routing->dev->kobj,
++ &aspeed_uart_routing_attr_group);
++
++ return 0;
++}
++
++static const struct of_device_id aspeed_uart_routing_table[] = {
++ { .compatible = "aspeed,ast2500-uart-routing" },
++ { },
++};
++
++static struct platform_driver aspeed_uart_routing_driver = {
++ .driver = {
++ .name = "aspeed-uart-routing",
++ .of_match_table = aspeed_uart_routing_table,
++ },
++ .probe = aspeed_uart_routing_probe,
++ .remove = aspeed_uart_routing_remove,
++};
++
++module_platform_driver(aspeed_uart_routing_driver);
++
++MODULE_AUTHOR("Oskar Senft <osk@google.com>");
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("Driver to configure Aspeed UART routing");
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-adpeed-Swap-the-mac-nodes-numbering.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-adpeed-Swap-the-mac-nodes-numbering.patch
new file mode 100644
index 000000000..eef3bee6f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-adpeed-Swap-the-mac-nodes-numbering.patch
@@ -0,0 +1,85 @@
+From 9c509b9450f641c169ee3aeb60e398c43810dcb2 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 3 Oct 2018 10:17:58 -0700
+Subject: [PATCH] arm: dts: adpeed: Swap the mac nodes numbering
+
+This patch swaps the numbering of mac0 and mac1 to make a dedicated
+nic get assigned the first ethernet device number.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g4.dtsi | 16 ++++++++--------
+ arch/arm/boot/dts/aspeed-g5.dtsi | 16 ++++++++--------
+ 2 files changed, 16 insertions(+), 16 deletions(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index 22eab8a952ed..004bbb08dd4a 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -101,14 +101,6 @@
+ reg = <0x1e6c2000 0x80>;
+ };
+
+- mac0: ethernet@1e660000 {
+- compatible = "aspeed,ast2400-mac", "faraday,ftgmac100";
+- reg = <0x1e660000 0x180>;
+- interrupts = <2>;
+- clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>;
+- status = "disabled";
+- };
+-
+ mac1: ethernet@1e680000 {
+ compatible = "aspeed,ast2400-mac", "faraday,ftgmac100";
+ reg = <0x1e680000 0x180>;
+@@ -117,6 +109,14 @@
+ status = "disabled";
+ };
+
++ mac0: ethernet@1e660000 {
++ compatible = "aspeed,ast2400-mac", "faraday,ftgmac100";
++ reg = <0x1e660000 0x180>;
++ interrupts = <2>;
++ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>;
++ status = "disabled";
++ };
++
+ ehci0: usb@1e6a1000 {
+ compatible = "aspeed,ast2400-ehci", "generic-ehci";
+ reg = <0x1e6a1000 0x100>;
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index 92843cc1a8f4..30a7f349feeb 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -142,14 +142,6 @@
+ reg = <0x1e6c2000 0x80>;
+ };
+
+- mac0: ethernet@1e660000 {
+- compatible = "aspeed,ast2500-mac", "faraday,ftgmac100";
+- reg = <0x1e660000 0x180>;
+- interrupts = <2>;
+- clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>;
+- status = "disabled";
+- };
+-
+ mac1: ethernet@1e680000 {
+ compatible = "aspeed,ast2500-mac", "faraday,ftgmac100";
+ reg = <0x1e680000 0x180>;
+@@ -158,6 +150,14 @@
+ status = "disabled";
+ };
+
++ mac0: ethernet@1e660000 {
++ compatible = "aspeed,ast2500-mac", "faraday,ftgmac100";
++ reg = <0x1e660000 0x180>;
++ interrupts = <2>;
++ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>;
++ status = "disabled";
++ };
++
+ ehci0: usb@1e6a1000 {
+ compatible = "aspeed,ast2500-ehci", "generic-ehci";
+ reg = <0x1e6a1000 0x100>;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch
new file mode 100644
index 000000000..51ddbb18e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch
@@ -0,0 +1,249 @@
+From 1d459c15998c9a79ba7a758cef6129ed29f3b958 Mon Sep 17 00:00:00 2001
+From: cyang29 <cheng.c.yang@intel.com>
+Date: Fri, 9 Nov 2018 10:24:37 +0800
+Subject: [PATCH] Implement a memory driver share memory
+
+Implement a memory driver for BMC to access VGA share memory.
+The driver is used by MDRV2. In MDRV2 BIOS will send whole
+SMBIOS table to VGA memory and BMC can get the table from VGA
+memory through this driver.
+
+Signed-off-by: cyang29 <cheng.c.yang@intel.com>
+---
+ .../devicetree/bindings/misc/vga-shared-memory.txt | 20 +++
+ drivers/misc/Kconfig | 10 ++
+ drivers/misc/Makefile | 1 +
+ drivers/misc/aspeed-vga-sharedmem.c | 164 +++++++++++++++++++++
+ 4 files changed, 195 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/misc/vga-shared-memory.txt
+ create mode 100644 drivers/misc/aspeed-vga-sharedmem.c
+
+diff --git a/Documentation/devicetree/bindings/misc/vga-shared-memory.txt b/Documentation/devicetree/bindings/misc/vga-shared-memory.txt
+new file mode 100644
+index 000000000000..03f57c53e844
+--- /dev/null
++++ b/Documentation/devicetree/bindings/misc/vga-shared-memory.txt
+@@ -0,0 +1,20 @@
++* Aspeed VGA shared memory driver
++
++Aspeed VGA shared memory driver allow user to read data from AST2500
++VGA memory. This driver is required by ManagedDataRegionlV2
++specification. In the spec, BIOS will transfer whole SMBIOS table to
++VGA memroy and BMC get the table from VGA memory. 0penBMC project do
++not allow to use /dev/mem for security concerns. To get the data in
++VGA shared memory in user space, implement this driver only allowed
++user to mmap limited memory area.
++
++Required properties:
++- compatible: "aspeed,ast2500-vga-sharedmem"
++ - aspeed,ast2500-vga-sharedmem: Aspeed AST2500 family
++- reg: Should contain VGA shared memory start address and length
++
++Example:
++vga-shared-memory {
++ compatible = "aspeed,ast2500-vga-sharedmem";
++ reg = <0x9ff00000 0x100000>;
++};
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 8e2fc51dcc44..1279a9674537 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -543,6 +543,16 @@ config ASPEED_UART_ROUTING
+ If you want to configure UART routing on Aspeed BMC platforms, enable
+ this option.
+
++config ASPEED_VGA_SHAREDMEM
++ tristate "Aspeed VGA Shared memory"
++ depends on (ARCH_ASPEED || COMPILE_TEST)
++ help
++ To access VGA shared memory on Aspeed BMC, enable this option.
++ This driver used by ManagedDataRegionlV2 specification. In the
++ specification, BIOS will transfer whole SMBIOS table to VGA
++ memory, and BMC can get the table from VGA memory through this
++ driver.
++
+ source "drivers/misc/c2port/Kconfig"
+ source "drivers/misc/eeprom/Kconfig"
+ source "drivers/misc/cb710/Kconfig"
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 0f00eb63556c..f4951a6e435b 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -62,3 +62,4 @@ obj-$(CONFIG_ASPEED_LPC_SIO) += aspeed-lpc-sio.o
+ obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
+ obj-$(CONFIG_OCXL) += ocxl/
+ obj-$(CONFIG_MISC_RTSX) += cardreader/
++obj-$(CONFIG_ASPEED_VGA_SHAREDMEM) += aspeed-vga-sharedmem.o
+diff --git a/drivers/misc/aspeed-vga-sharedmem.c b/drivers/misc/aspeed-vga-sharedmem.c
+new file mode 100644
+index 000000000000..76f60cd67d3a
+--- /dev/null
++++ b/drivers/misc/aspeed-vga-sharedmem.c
+@@ -0,0 +1,164 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2018 Intel Corporation
++ * VGA Shared Memory driver for Aspeed AST2500
++ */
++
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++
++#define SHAREDMEM_NAME "vgasharedmem"
++
++struct aspeed_vga_sharedmem {
++ struct miscdevice miscdev;
++ unsigned int addr;
++ unsigned int size;
++ bool mmap_enable;
++};
++
++static struct aspeed_vga_sharedmem *file_sharemem(struct file *file)
++{
++ return container_of(file->private_data,
++ struct aspeed_vga_sharedmem, miscdev);
++}
++
++static int vga_open(struct inode *inode, struct file *file)
++{
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
++ struct aspeed_vga_sharedmem *vga_sharedmem = file_sharemem(file);
++
++ if (!vga_sharedmem->mmap_enable)
++ return -EPERM;
++
++ return 0;
++}
++
++static int vga_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ struct aspeed_vga_sharedmem *vga_sharedmem = file_sharemem(file);
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
++ vma->vm_flags = (vma->vm_flags & (~VM_WRITE));
++ remap_pfn_range(vma, vma->vm_start, vga_sharedmem->addr >> PAGE_SHIFT,
++ vga_sharedmem->size, vma->vm_page_prot);
++ return 0;
++}
++
++static ssize_t enable_mmap_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct aspeed_vga_sharedmem *vga_sharedmem = dev_get_drvdata(dev);
++
++ return sprintf(buf, "%u\n", vga_sharedmem->mmap_enable);
++}
++
++static ssize_t enable_mmap_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct aspeed_vga_sharedmem *vga_sharedmem =
++ dev_get_drvdata(dev);
++ bool val;
++
++ if (kstrtobool(buf, &val))
++ return -EINVAL;
++
++ vga_sharedmem->mmap_enable = val;
++
++ return count;
++}
++static DEVICE_ATTR_RW(enable_mmap);
++
++static struct attribute *sharedmem_attrs[] = {
++ &dev_attr_enable_mmap.attr,
++ NULL
++};
++
++static const struct attribute_group sharedmem_attr_group = {
++ .attrs = sharedmem_attrs,
++};
++
++static const struct attribute_group *sharedmem_attr_groups[] = {
++ &sharedmem_attr_group,
++ NULL
++};
++
++static const struct file_operations vga_sharedmem_fops = {
++ .owner = THIS_MODULE,
++ .open = vga_open,
++ .mmap = vga_mmap,
++};
++
++static struct miscdevice vga_sharedmem_miscdev = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = SHAREDMEM_NAME,
++ .fops = &vga_sharedmem_fops,
++ .groups = sharedmem_attr_groups,
++};
++
++static int vga_sharedmem_probe(struct platform_device *pdev)
++{
++ struct aspeed_vga_sharedmem *vga_sharedmem;
++ struct device *dev = &pdev->dev;
++ u32 reg[2];
++ struct resource *rc;
++
++ vga_sharedmem = devm_kzalloc(dev, sizeof(*vga_sharedmem), GFP_KERNEL);
++ if (!vga_sharedmem)
++ return -ENOMEM;
++
++ dev_set_drvdata(&pdev->dev, vga_sharedmem);
++
++ rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!rc) {
++ dev_err(dev, "Couldn't read size device-tree property\n");
++ return -ENXIO;
++ }
++
++ vga_sharedmem->addr = rc->start;
++ vga_sharedmem->size = resource_size(rc);
++ vga_sharedmem->mmap_enable = true;
++
++ vga_sharedmem->miscdev = vga_sharedmem_miscdev;
++
++ return misc_register(&vga_sharedmem->miscdev);
++}
++
++static int vga_sharedmem_remove(struct platform_device *pdev)
++{
++ struct aspeed_vga_sharedmem *vga_sharedmem =
++ dev_get_drvdata(&pdev->dev);
++
++ misc_deregister(&vga_sharedmem->miscdev);
++
++ return 0;
++}
++
++static const struct of_device_id vga_sharedmem_match[] = {
++ { .compatible = "aspeed,ast2500-vga-sharedmem", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, vga_sharedmem_match);
++
++static struct platform_driver vga_sharedmem_driver = {
++ .driver = {
++ .name = "VGA-SHAREDMEM",
++ .of_match_table = vga_sharedmem_match,
++ },
++ .probe = vga_sharedmem_probe,
++ .remove = vga_sharedmem_remove,
++};
++
++module_platform_driver(vga_sharedmem_driver);
++
++MODULE_AUTHOR("Yang Cheng <cheng.c.yang@intel.com>");
++MODULE_DESCRIPTION("Shared VGA memory");
++MODULE_LICENSE("GPL v2");
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0036-net-ncsi-backport-ncsi-patches.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0036-net-ncsi-backport-ncsi-patches.patch
new file mode 100644
index 000000000..83717369c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0036-net-ncsi-backport-ncsi-patches.patch
@@ -0,0 +1,1425 @@
+From 58c3299017c5e6022fb2a2a74b662b2a4c0306f5 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 20 Nov 2018 10:14:47 -0800
+Subject: [PATCH] net/ncsi: backport ncsi patches
+
+net/ncsi: Allow enabling multiple packages & channels
+
+This series extends the NCSI driver to configure multiple packages
+and/or channels simultaneously. Since the RFC series this includes a few
+extra changes to fix areas in the driver that either made this harder or
+were roadblocks due to deviations from the NCSI specification.
+
+Patches 1 & 2 fix two issues where the driver made assumptions about the
+capabilities of the NCSI topology.
+Patches 3 & 4 change some internal semantics slightly to make multi-mode
+easier.
+Patch 5 introduces a cleaner way of reconfiguring the NCSI configuration
+and keeping track of channel states.
+Patch 6 implements the main multi-package/multi-channel configuration,
+configured via the Netlink interface.
+
+Readers who have an interesting NCSI setup - especially multi-package
+with HWA - please test! I think I've covered all permutations but I
+don't have infinite hardware to test on.
+
+net/ncsi: Don't enable all channels when HWA available
+
+NCSI hardware arbitration allows multiple packages to be enabled at once
+and share the same wiring. If the NCSI driver recognises that HWA is
+available it unconditionally enables all packages and channels; but that
+is a configuration decision rather than something required by HWA.
+Additionally the current implementation will not failover on link events
+which can cause connectivity to be lost unless the interface is manually
+bounced.
+
+Retain basic HWA support but remove the separate configuration path to
+enable all channels, leaving this to be handled by a later
+implementation.
+
+net/ncsi: Probe single packages to avoid conflict
+
+Currently the NCSI driver sends a select-package command to all possible
+packages simultaneously to discover what packages are available. However
+at this stage in the probe process the driver does not know if
+hardware arbitration is available: if it isn't then this process could
+cause collisions on the RMII bus when packages try to respond.
+
+Update the probe loop to probe each package one by one, and once
+complete check if HWA is universally supported.
+
+net/ncsi: Don't deselect package in suspend if active
+
+When a package is deselected all channels of that package cease
+communication. If there are other channels active on the package of the
+suspended channel this will disable them as well, so only send a
+deselect-package command if no other channels are active.
+
+net/ncsi: Don't mark configured channels inactive
+
+The concepts of a channel being 'active' and it having link are slightly
+muddled in the NCSI driver. Tweak this slightly so that
+NCSI_CHANNEL_ACTIVE represents a channel that has been configured and
+enabled, and NCSI_CHANNEL_INACTIVE represents a de-configured channel.
+This distinction is important because a channel can be 'active' but have
+its link down; in this case the channel may still need to be configured
+so that it may receive AEN link-state-change packets.
+
+net/ncsi: Reset channel state in ncsi_start_dev()
+
+When the NCSI driver is stopped with ncsi_stop_dev() the channel
+monitors are stopped and the state set to "inactive". However the
+channels are still configured and active from the perspective of the
+network controller. We should suspend each active channel but in the
+context of ncsi_stop_dev() the transmit queue has been or is about to be
+stopped so we won't have time to do so.
+
+Instead when ncsi_start_dev() is called if the NCSI topology has already
+been probed then call ncsi_reset_dev() to suspend any channels that were
+previously active. This resets the network controller to a known state,
+provides an up to date view of channel link state, and makes sure that
+mode flags such as NCSI_MODE_TX_ENABLE are properly reset.
+
+In addition to ncsi_start_dev() use ncsi_reset_dev() in ncsi-netlink.c
+to update the channel configuration more cleanly.
+
+net/ncsi: Configure multi-package, multi-channel modes with failover
+
+This patch extends the ncsi-netlink interface with two new commands and
+three new attributes to configure multiple packages and/or channels at
+once, and configure specific failover modes.
+
+NCSI_CMD_SET_PACKAGE mask and NCSI_CMD_SET_CHANNEL_MASK set a whitelist
+of packages or channels allowed to be configured with the
+NCSI_ATTR_PACKAGE_MASK and NCSI_ATTR_CHANNEL_MASK attributes
+respectively. If one of these whitelists is set only packages or
+channels matching the whitelist are considered for the channel queue in
+ncsi_choose_active_channel().
+
+These commands may also use the NCSI_ATTR_MULTI_FLAG to signal that
+multiple packages or channels may be configured simultaneously. NCSI
+hardware arbitration (HWA) must be available in order to enable
+multi-package mode. Multi-channel mode is always available.
+
+If the NCSI_ATTR_CHANNEL_ID attribute is present in the
+NCSI_CMD_SET_CHANNEL_MASK command the it sets the preferred channel as
+with the NCSI_CMD_SET_INTERFACE command. The combination of preferred
+channel and channel whitelist defines a primary channel and the allowed
+failover channels.
+If the NCSI_ATTR_MULTI_FLAG attribute is also present then the preferred
+channel is configured for Tx/Rx and the other channels are enabled only
+for Rx.
+
+Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ include/uapi/linux/ncsi.h | 15 ++
+ net/ncsi/internal.h | 19 +-
+ net/ncsi/ncsi-aen.c | 75 +++++--
+ net/ncsi/ncsi-manage.c | 522 ++++++++++++++++++++++++++++++++--------------
+ net/ncsi/ncsi-netlink.c | 233 ++++++++++++++++++---
+ net/ncsi/ncsi-rsp.c | 2 +-
+ 6 files changed, 660 insertions(+), 206 deletions(-)
+
+diff --git a/include/uapi/linux/ncsi.h b/include/uapi/linux/ncsi.h
+index 0a26a5576645..a3f87c54fdb3 100644
+--- a/include/uapi/linux/ncsi.h
++++ b/include/uapi/linux/ncsi.h
+@@ -26,6 +26,12 @@
+ * @NCSI_CMD_SEND_CMD: send NC-SI command to network card.
+ * Requires NCSI_ATTR_IFINDEX, NCSI_ATTR_PACKAGE_ID
+ * and NCSI_ATTR_CHANNEL_ID.
++ * @NCSI_CMD_SET_PACKAGE_MASK: set a whitelist of allowed packages.
++ * Requires NCSI_ATTR_IFINDEX and NCSI_ATTR_PACKAGE_MASK.
++ * @NCSI_CMD_SET_CHANNEL_MASK: set a whitelist of allowed channels.
++ * Requires NCSI_ATTR_IFINDEX, NCSI_ATTR_PACKAGE_ID, and
++ * NCSI_ATTR_CHANNEL_MASK. If NCSI_ATTR_CHANNEL_ID is present it sets
++ * the primary channel.
+ * @NCSI_CMD_MAX: highest command number
+ */
+ enum ncsi_nl_commands {
+@@ -34,6 +40,8 @@ enum ncsi_nl_commands {
+ NCSI_CMD_SET_INTERFACE,
+ NCSI_CMD_CLEAR_INTERFACE,
+ NCSI_CMD_SEND_CMD,
++ NCSI_CMD_SET_PACKAGE_MASK,
++ NCSI_CMD_SET_CHANNEL_MASK,
+
+ __NCSI_CMD_AFTER_LAST,
+ NCSI_CMD_MAX = __NCSI_CMD_AFTER_LAST - 1
+@@ -48,6 +56,10 @@ enum ncsi_nl_commands {
+ * @NCSI_ATTR_PACKAGE_ID: package ID
+ * @NCSI_ATTR_CHANNEL_ID: channel ID
+ * @NCSI_ATTR_DATA: command payload
++ * @NCSI_ATTR_MULTI_FLAG: flag to signal that multi-mode should be enabled with
++ * NCSI_CMD_SET_PACKAGE_MASK or NCSI_CMD_SET_CHANNEL_MASK.
++ * @NCSI_ATTR_PACKAGE_MASK: 32-bit mask of allowed packages.
++ * @NCSI_ATTR_CHANNEL_MASK: 32-bit mask of allowed channels.
+ * @NCSI_ATTR_MAX: highest attribute number
+ */
+ enum ncsi_nl_attrs {
+@@ -57,6 +69,9 @@ enum ncsi_nl_attrs {
+ NCSI_ATTR_PACKAGE_ID,
+ NCSI_ATTR_CHANNEL_ID,
+ NCSI_ATTR_DATA,
++ NCSI_ATTR_MULTI_FLAG,
++ NCSI_ATTR_PACKAGE_MASK,
++ NCSI_ATTR_CHANNEL_MASK,
+
+ __NCSI_ATTR_AFTER_LAST,
+ NCSI_ATTR_MAX = __NCSI_ATTR_AFTER_LAST - 1
+diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
+index 1dae77c54009..9e3642b802c4 100644
+--- a/net/ncsi/internal.h
++++ b/net/ncsi/internal.h
+@@ -222,6 +222,10 @@ struct ncsi_package {
+ unsigned int channel_num; /* Number of channels */
+ struct list_head channels; /* List of chanels */
+ struct list_head node; /* Form list of packages */
++
++ bool multi_channel; /* Enable multiple channels */
++ u32 channel_whitelist; /* Channels to configure */
++ struct ncsi_channel *preferred_channel; /* Primary channel */
+ };
+
+ struct ncsi_request {
+@@ -287,16 +291,16 @@ struct ncsi_dev_priv {
+ #define NCSI_DEV_PROBED 1 /* Finalized NCSI topology */
+ #define NCSI_DEV_HWA 2 /* Enabled HW arbitration */
+ #define NCSI_DEV_RESHUFFLE 4
++#define NCSI_DEV_RESET 8 /* Reset state of NC */
+ unsigned int gma_flag; /* OEM GMA flag */
+ spinlock_t lock; /* Protect the NCSI device */
+ #if IS_ENABLED(CONFIG_IPV6)
+ unsigned int inet6_addr_num; /* Number of IPv6 addresses */
+ #endif
++ unsigned int package_probe_id;/* Current ID during probe */
+ unsigned int package_num; /* Number of packages */
+ struct list_head packages; /* List of packages */
+ struct ncsi_channel *hot_channel; /* Channel was ever active */
+- struct ncsi_package *force_package; /* Force a specific package */
+- struct ncsi_channel *force_channel; /* Force a specific channel */
+ struct ncsi_request requests[256]; /* Request table */
+ unsigned int request_id; /* Last used request ID */
+ #define NCSI_REQ_START_IDX 1
+@@ -309,6 +313,9 @@ struct ncsi_dev_priv {
+ struct list_head node; /* Form NCSI device list */
+ #define NCSI_MAX_VLAN_VIDS 15
+ struct list_head vlan_vids; /* List of active VLAN IDs */
++
++ bool multi_package; /* Enable multiple packages */
++ u32 package_whitelist; /* Packages to configure */
+ };
+
+ struct ncsi_cmd_arg {
+@@ -341,6 +348,7 @@ extern spinlock_t ncsi_dev_lock;
+ list_for_each_entry_rcu(nc, &np->channels, node)
+
+ /* Resources */
++int ncsi_reset_dev(struct ncsi_dev *nd);
+ void ncsi_start_channel_monitor(struct ncsi_channel *nc);
+ void ncsi_stop_channel_monitor(struct ncsi_channel *nc);
+ struct ncsi_channel *ncsi_find_channel(struct ncsi_package *np,
+@@ -361,6 +369,13 @@ struct ncsi_request *ncsi_alloc_request(struct ncsi_dev_priv *ndp,
+ void ncsi_free_request(struct ncsi_request *nr);
+ struct ncsi_dev *ncsi_find_dev(struct net_device *dev);
+ int ncsi_process_next_channel(struct ncsi_dev_priv *ndp);
++bool ncsi_channel_has_link(struct ncsi_channel *channel);
++bool ncsi_channel_is_last(struct ncsi_dev_priv *ndp,
++ struct ncsi_channel *channel);
++int ncsi_update_tx_channel(struct ncsi_dev_priv *ndp,
++ struct ncsi_package *np,
++ struct ncsi_channel *disable,
++ struct ncsi_channel *enable);
+
+ /* Packet handlers */
+ u32 ncsi_calculate_checksum(unsigned char *data, int len);
+diff --git a/net/ncsi/ncsi-aen.c b/net/ncsi/ncsi-aen.c
+index 25e483e8278b..26d67e27551f 100644
+--- a/net/ncsi/ncsi-aen.c
++++ b/net/ncsi/ncsi-aen.c
+@@ -50,13 +50,15 @@ static int ncsi_validate_aen_pkt(struct ncsi_aen_pkt_hdr *h,
+ static int ncsi_aen_handler_lsc(struct ncsi_dev_priv *ndp,
+ struct ncsi_aen_pkt_hdr *h)
+ {
+- struct ncsi_aen_lsc_pkt *lsc;
+- struct ncsi_channel *nc;
++ struct ncsi_channel *nc, *tmp;
+ struct ncsi_channel_mode *ncm;
+- bool chained;
+- int state;
+ unsigned long old_data, data;
++ struct ncsi_aen_lsc_pkt *lsc;
++ struct ncsi_package *np;
++ bool had_link, has_link;
+ unsigned long flags;
++ bool chained;
++ int state;
+
+ /* Find the NCSI channel */
+ ncsi_find_package_and_channel(ndp, h->common.channel, NULL, &nc);
+@@ -73,6 +75,9 @@ static int ncsi_aen_handler_lsc(struct ncsi_dev_priv *ndp,
+ ncm->data[2] = data;
+ ncm->data[4] = ntohl(lsc->oem_status);
+
++ had_link = !!(old_data & 0x1);
++ has_link = !!(data & 0x1);
++
+ netdev_dbg(ndp->ndev.dev, "NCSI: LSC AEN - channel %u state %s\n",
+ nc->id, data & 0x1 ? "up" : "down");
+
+@@ -80,22 +85,60 @@ static int ncsi_aen_handler_lsc(struct ncsi_dev_priv *ndp,
+ state = nc->state;
+ spin_unlock_irqrestore(&nc->lock, flags);
+
+- if (!((old_data ^ data) & 0x1) || chained)
+- return 0;
+- if (!(state == NCSI_CHANNEL_INACTIVE && (data & 0x1)) &&
+- !(state == NCSI_CHANNEL_ACTIVE && !(data & 0x1)))
++ if (state == NCSI_CHANNEL_INACTIVE)
++ netdev_warn(ndp->ndev.dev,
++ "NCSI: Inactive channel %u received AEN!\n",
++ nc->id);
++
++ if ((had_link == has_link) || chained)
+ return 0;
+
+- if (!(ndp->flags & NCSI_DEV_HWA) &&
+- state == NCSI_CHANNEL_ACTIVE)
+- ndp->flags |= NCSI_DEV_RESHUFFLE;
++ if (!ndp->multi_package && !nc->package->multi_channel) {
++ if (had_link) {
++ ndp->flags |= NCSI_DEV_RESHUFFLE;
++ ncsi_stop_channel_monitor(nc);
++ spin_lock_irqsave(&ndp->lock, flags);
++ list_add_tail_rcu(&nc->link, &ndp->channel_queue);
++ spin_unlock_irqrestore(&ndp->lock, flags);
++ return ncsi_process_next_channel(ndp);
++ }
++ /* Configured channel came up */
++ return 0;
++ }
+
+- ncsi_stop_channel_monitor(nc);
+- spin_lock_irqsave(&ndp->lock, flags);
+- list_add_tail_rcu(&nc->link, &ndp->channel_queue);
+- spin_unlock_irqrestore(&ndp->lock, flags);
++ if (had_link) {
++ ncm = &nc->modes[NCSI_MODE_TX_ENABLE];
++ if (ncsi_channel_is_last(ndp, nc)) {
++ /* No channels left, reconfigure */
++ return ncsi_reset_dev(&ndp->ndev);
++ } else if (ncm->enable) {
++ /* Need to failover Tx channel */
++ ncsi_update_tx_channel(ndp, nc->package, nc, NULL);
++ }
++ } else if (has_link && nc->package->preferred_channel == nc) {
++ /* Return Tx to preferred channel */
++ ncsi_update_tx_channel(ndp, nc->package, NULL, nc);
++ } else if (has_link) {
++ NCSI_FOR_EACH_PACKAGE(ndp, np) {
++ NCSI_FOR_EACH_CHANNEL(np, tmp) {
++ /* Enable Tx on this channel if the current Tx
++ * channel is down.
++ */
++ ncm = &tmp->modes[NCSI_MODE_TX_ENABLE];
++ if (ncm->enable &&
++ !ncsi_channel_has_link(tmp)) {
++ ncsi_update_tx_channel(ndp, nc->package,
++ tmp, nc);
++ break;
++ }
++ }
++ }
++ }
+
+- return ncsi_process_next_channel(ndp);
++ /* Leave configured channels active in a multi-channel scenario so
++ * AEN events are still received.
++ */
++ return 0;
+ }
+
+ static int ncsi_aen_handler_cr(struct ncsi_dev_priv *ndp,
+diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
+index bfc43b28c7a6..92e59f07f9a7 100644
+--- a/net/ncsi/ncsi-manage.c
++++ b/net/ncsi/ncsi-manage.c
+@@ -28,6 +28,29 @@
+ LIST_HEAD(ncsi_dev_list);
+ DEFINE_SPINLOCK(ncsi_dev_lock);
+
++bool ncsi_channel_has_link(struct ncsi_channel *channel)
++{
++ return !!(channel->modes[NCSI_MODE_LINK].data[2] & 0x1);
++}
++
++bool ncsi_channel_is_last(struct ncsi_dev_priv *ndp,
++ struct ncsi_channel *channel)
++{
++ struct ncsi_package *np;
++ struct ncsi_channel *nc;
++
++ NCSI_FOR_EACH_PACKAGE(ndp, np)
++ NCSI_FOR_EACH_CHANNEL(np, nc) {
++ if (nc == channel)
++ continue;
++ if (nc->state == NCSI_CHANNEL_ACTIVE &&
++ ncsi_channel_has_link(nc))
++ return false;
++ }
++
++ return true;
++}
++
+ static void ncsi_report_link(struct ncsi_dev_priv *ndp, bool force_down)
+ {
+ struct ncsi_dev *nd = &ndp->ndev;
+@@ -52,7 +75,7 @@ static void ncsi_report_link(struct ncsi_dev_priv *ndp, bool force_down)
+ continue;
+ }
+
+- if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) {
++ if (ncsi_channel_has_link(nc)) {
+ spin_unlock_irqrestore(&nc->lock, flags);
+ nd->link_up = 1;
+ goto report;
+@@ -113,10 +136,8 @@ static void ncsi_channel_monitor(struct timer_list *t)
+ default:
+ netdev_err(ndp->ndev.dev, "NCSI Channel %d timed out!\n",
+ nc->id);
+- if (!(ndp->flags & NCSI_DEV_HWA)) {
+- ncsi_report_link(ndp, true);
+- ndp->flags |= NCSI_DEV_RESHUFFLE;
+- }
++ ncsi_report_link(ndp, true);
++ ndp->flags |= NCSI_DEV_RESHUFFLE;
+
+ ncsi_stop_channel_monitor(nc);
+
+@@ -269,6 +290,7 @@ struct ncsi_package *ncsi_add_package(struct ncsi_dev_priv *ndp,
+ np->ndp = ndp;
+ spin_lock_init(&np->lock);
+ INIT_LIST_HEAD(&np->channels);
++ np->channel_whitelist = UINT_MAX;
+
+ spin_lock_irqsave(&ndp->lock, flags);
+ tmp = ncsi_find_package(ndp, id);
+@@ -442,12 +464,14 @@ static void ncsi_request_timeout(struct timer_list *t)
+ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
+ {
+ struct ncsi_dev *nd = &ndp->ndev;
+- struct ncsi_package *np = ndp->active_package;
+- struct ncsi_channel *nc = ndp->active_channel;
++ struct ncsi_package *np;
++ struct ncsi_channel *nc, *tmp;
+ struct ncsi_cmd_arg nca;
+ unsigned long flags;
+ int ret;
+
++ np = ndp->active_package;
++ nc = ndp->active_channel;
+ nca.ndp = ndp;
+ nca.req_flags = NCSI_REQ_FLAG_EVENT_DRIVEN;
+ switch (nd->state) {
+@@ -523,6 +547,15 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
+ if (ret)
+ goto error;
+
++ NCSI_FOR_EACH_CHANNEL(np, tmp) {
++ /* If there is another channel active on this package
++ * do not deselect the package.
++ */
++ if (tmp != nc && tmp->state == NCSI_CHANNEL_ACTIVE) {
++ nd->state = ncsi_dev_state_suspend_done;
++ break;
++ }
++ }
+ break;
+ case ncsi_dev_state_suspend_deselect:
+ ndp->pending_req_num = 1;
+@@ -541,8 +574,10 @@ static void ncsi_suspend_channel(struct ncsi_dev_priv *ndp)
+ spin_lock_irqsave(&nc->lock, flags);
+ nc->state = NCSI_CHANNEL_INACTIVE;
+ spin_unlock_irqrestore(&nc->lock, flags);
+- ncsi_process_next_channel(ndp);
+-
++ if (ndp->flags & NCSI_DEV_RESET)
++ ncsi_reset_dev(nd);
++ else
++ ncsi_process_next_channel(ndp);
+ break;
+ default:
+ netdev_warn(nd->dev, "Wrong NCSI state 0x%x in suspend\n",
+@@ -717,13 +752,144 @@ static int ncsi_gma_handler(struct ncsi_cmd_arg *nca, unsigned int mf_id)
+
+ #endif /* CONFIG_NCSI_OEM_CMD_GET_MAC */
+
++/* Determine if a given channel from the channel_queue should be used for Tx */
++static bool ncsi_channel_is_tx(struct ncsi_dev_priv *ndp,
++ struct ncsi_channel *nc)
++{
++ struct ncsi_channel_mode *ncm;
++ struct ncsi_channel *channel;
++ struct ncsi_package *np;
++
++ /* Check if any other channel has Tx enabled; a channel may have already
++ * been configured and removed from the channel queue.
++ */
++ NCSI_FOR_EACH_PACKAGE(ndp, np) {
++ if (!ndp->multi_package && np != nc->package)
++ continue;
++ NCSI_FOR_EACH_CHANNEL(np, channel) {
++ ncm = &channel->modes[NCSI_MODE_TX_ENABLE];
++ if (ncm->enable)
++ return false;
++ }
++ }
++
++ /* This channel is the preferred channel and has link */
++ list_for_each_entry_rcu(channel, &ndp->channel_queue, link) {
++ np = channel->package;
++ if (np->preferred_channel &&
++ ncsi_channel_has_link(np->preferred_channel)) {
++ return np->preferred_channel == nc;
++ }
++ }
++
++ /* This channel has link */
++ if (ncsi_channel_has_link(nc))
++ return true;
++
++ list_for_each_entry_rcu(channel, &ndp->channel_queue, link)
++ if (ncsi_channel_has_link(channel))
++ return false;
++
++ /* No other channel has link; default to this one */
++ return true;
++}
++
++/* Change the active Tx channel in a multi-channel setup */
++int ncsi_update_tx_channel(struct ncsi_dev_priv *ndp,
++ struct ncsi_package *package,
++ struct ncsi_channel *disable,
++ struct ncsi_channel *enable)
++{
++ struct ncsi_cmd_arg nca;
++ struct ncsi_channel *nc;
++ struct ncsi_package *np;
++ int ret = 0;
++
++ if (!package->multi_channel && !ndp->multi_package)
++ netdev_warn(ndp->ndev.dev,
++ "NCSI: Trying to update Tx channel in single-channel mode\n");
++ nca.ndp = ndp;
++ nca.req_flags = 0;
++
++ /* Find current channel with Tx enabled */
++ NCSI_FOR_EACH_PACKAGE(ndp, np) {
++ if (disable)
++ break;
++ if (!ndp->multi_package && np != package)
++ continue;
++
++ NCSI_FOR_EACH_CHANNEL(np, nc)
++ if (nc->modes[NCSI_MODE_TX_ENABLE].enable) {
++ disable = nc;
++ break;
++ }
++ }
++
++ /* Find a suitable channel for Tx */
++ NCSI_FOR_EACH_PACKAGE(ndp, np) {
++ if (enable)
++ break;
++ if (!ndp->multi_package && np != package)
++ continue;
++ if (!(ndp->package_whitelist & (0x1 << np->id)))
++ continue;
++
++ if (np->preferred_channel &&
++ ncsi_channel_has_link(np->preferred_channel)) {
++ enable = np->preferred_channel;
++ break;
++ }
++
++ NCSI_FOR_EACH_CHANNEL(np, nc) {
++ if (!(np->channel_whitelist & 0x1 << nc->id))
++ continue;
++ if (nc->state != NCSI_CHANNEL_ACTIVE)
++ continue;
++ if (ncsi_channel_has_link(nc)) {
++ enable = nc;
++ break;
++ }
++ }
++ }
++
++ if (disable == enable)
++ return -1;
++
++ if (!enable)
++ return -1;
++
++ if (disable) {
++ nca.channel = disable->id;
++ nca.package = disable->package->id;
++ nca.type = NCSI_PKT_CMD_DCNT;
++ ret = ncsi_xmit_cmd(&nca);
++ if (ret)
++ netdev_err(ndp->ndev.dev,
++ "Error %d sending DCNT\n",
++ ret);
++ }
++
++ netdev_info(ndp->ndev.dev, "NCSI: channel %u enables Tx\n", enable->id);
++
++ nca.channel = enable->id;
++ nca.package = enable->package->id;
++ nca.type = NCSI_PKT_CMD_ECNT;
++ ret = ncsi_xmit_cmd(&nca);
++ if (ret)
++ netdev_err(ndp->ndev.dev,
++ "Error %d sending ECNT\n",
++ ret);
++
++ return ret;
++}
++
+ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
+ {
+- struct ncsi_dev *nd = &ndp->ndev;
+- struct net_device *dev = nd->dev;
+ struct ncsi_package *np = ndp->active_package;
+ struct ncsi_channel *nc = ndp->active_channel;
+ struct ncsi_channel *hot_nc = NULL;
++ struct ncsi_dev *nd = &ndp->ndev;
++ struct net_device *dev = nd->dev;
+ struct ncsi_cmd_arg nca;
+ unsigned char index;
+ unsigned long flags;
+@@ -845,20 +1011,29 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
+ } else if (nd->state == ncsi_dev_state_config_ebf) {
+ nca.type = NCSI_PKT_CMD_EBF;
+ nca.dwords[0] = nc->caps[NCSI_CAP_BC].cap;
+- nd->state = ncsi_dev_state_config_ecnt;
++ if (ncsi_channel_is_tx(ndp, nc))
++ nd->state = ncsi_dev_state_config_ecnt;
++ else
++ nd->state = ncsi_dev_state_config_ec;
+ #if IS_ENABLED(CONFIG_IPV6)
+ if (ndp->inet6_addr_num > 0 &&
+ (nc->caps[NCSI_CAP_GENERIC].cap &
+ NCSI_CAP_GENERIC_MC))
+ nd->state = ncsi_dev_state_config_egmf;
+- else
+- nd->state = ncsi_dev_state_config_ecnt;
+ } else if (nd->state == ncsi_dev_state_config_egmf) {
+ nca.type = NCSI_PKT_CMD_EGMF;
+ nca.dwords[0] = nc->caps[NCSI_CAP_MC].cap;
+- nd->state = ncsi_dev_state_config_ecnt;
++ if (ncsi_channel_is_tx(ndp, nc))
++ nd->state = ncsi_dev_state_config_ecnt;
++ else
++ nd->state = ncsi_dev_state_config_ec;
+ #endif /* CONFIG_IPV6 */
+ } else if (nd->state == ncsi_dev_state_config_ecnt) {
++ if (np->preferred_channel &&
++ nc != np->preferred_channel)
++ netdev_info(ndp->ndev.dev,
++ "NCSI: Tx failed over to channel %u\n",
++ nc->id);
+ nca.type = NCSI_PKT_CMD_ECNT;
+ nd->state = ncsi_dev_state_config_ec;
+ } else if (nd->state == ncsi_dev_state_config_ec) {
+@@ -889,6 +1064,16 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
+ netdev_dbg(ndp->ndev.dev, "NCSI: channel %u config done\n",
+ nc->id);
+ spin_lock_irqsave(&nc->lock, flags);
++ nc->state = NCSI_CHANNEL_ACTIVE;
++
++ if (ndp->flags & NCSI_DEV_RESET) {
++ /* A reset event happened during config, start it now */
++ nc->reconfigure_needed = false;
++ spin_unlock_irqrestore(&nc->lock, flags);
++ ncsi_reset_dev(nd);
++ break;
++ }
++
+ if (nc->reconfigure_needed) {
+ /* This channel's configuration has been updated
+ * part-way during the config state - start the
+@@ -909,10 +1094,8 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
+
+ if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) {
+ hot_nc = nc;
+- nc->state = NCSI_CHANNEL_ACTIVE;
+ } else {
+ hot_nc = NULL;
+- nc->state = NCSI_CHANNEL_INACTIVE;
+ netdev_dbg(ndp->ndev.dev,
+ "NCSI: channel %u link down after config\n",
+ nc->id);
+@@ -940,43 +1123,35 @@ static void ncsi_configure_channel(struct ncsi_dev_priv *ndp)
+
+ static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
+ {
+- struct ncsi_package *np, *force_package;
+- struct ncsi_channel *nc, *found, *hot_nc, *force_channel;
++ struct ncsi_channel *nc, *found, *hot_nc;
+ struct ncsi_channel_mode *ncm;
+- unsigned long flags;
++ unsigned long flags, cflags;
++ struct ncsi_package *np;
++ bool with_link;
+
+ spin_lock_irqsave(&ndp->lock, flags);
+ hot_nc = ndp->hot_channel;
+- force_channel = ndp->force_channel;
+- force_package = ndp->force_package;
+ spin_unlock_irqrestore(&ndp->lock, flags);
+
+- /* Force a specific channel whether or not it has link if we have been
+- * configured to do so
+- */
+- if (force_package && force_channel) {
+- found = force_channel;
+- ncm = &found->modes[NCSI_MODE_LINK];
+- if (!(ncm->data[2] & 0x1))
+- netdev_info(ndp->ndev.dev,
+- "NCSI: Channel %u forced, but it is link down\n",
+- found->id);
+- goto out;
+- }
+-
+- /* The search is done once an inactive channel with up
+- * link is found.
++ /* By default the search is done once an inactive channel with up
++ * link is found, unless a preferred channel is set.
++ * If multi_package or multi_channel are configured all channels in the
++ * whitelist are added to the channel queue.
+ */
+ found = NULL;
++ with_link = false;
+ NCSI_FOR_EACH_PACKAGE(ndp, np) {
+- if (ndp->force_package && np != ndp->force_package)
++ if (!(ndp->package_whitelist & (0x1 << np->id)))
+ continue;
+ NCSI_FOR_EACH_CHANNEL(np, nc) {
+- spin_lock_irqsave(&nc->lock, flags);
++ if (!(np->channel_whitelist & (0x1 << nc->id)))
++ continue;
++
++ spin_lock_irqsave(&nc->lock, cflags);
+
+ if (!list_empty(&nc->link) ||
+ nc->state != NCSI_CHANNEL_INACTIVE) {
+- spin_unlock_irqrestore(&nc->lock, flags);
++ spin_unlock_irqrestore(&nc->lock, cflags);
+ continue;
+ }
+
+@@ -988,32 +1163,49 @@ static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
+
+ ncm = &nc->modes[NCSI_MODE_LINK];
+ if (ncm->data[2] & 0x1) {
+- spin_unlock_irqrestore(&nc->lock, flags);
+ found = nc;
+- goto out;
++ with_link = true;
+ }
+
+- spin_unlock_irqrestore(&nc->lock, flags);
++ /* If multi_channel is enabled configure all valid
++ * channels whether or not they currently have link
++ * so they will have AENs enabled.
++ */
++ if (with_link || np->multi_channel) {
++ spin_lock_irqsave(&ndp->lock, flags);
++ list_add_tail_rcu(&nc->link,
++ &ndp->channel_queue);
++ spin_unlock_irqrestore(&ndp->lock, flags);
++
++ netdev_dbg(ndp->ndev.dev,
++ "NCSI: Channel %u added to queue (link %s)\n",
++ nc->id,
++ ncm->data[2] & 0x1 ? "up" : "down");
++ }
++
++ spin_unlock_irqrestore(&nc->lock, cflags);
++
++ if (with_link && !np->multi_channel)
++ break;
+ }
++ if (with_link && !ndp->multi_package)
++ break;
+ }
+
+- if (!found) {
++ if (list_empty(&ndp->channel_queue) && found) {
++ netdev_info(ndp->ndev.dev,
++ "NCSI: No channel with link found, configuring channel %u\n",
++ found->id);
++ spin_lock_irqsave(&ndp->lock, flags);
++ list_add_tail_rcu(&found->link, &ndp->channel_queue);
++ spin_unlock_irqrestore(&ndp->lock, flags);
++ } else if (!found) {
+ netdev_warn(ndp->ndev.dev,
+- "NCSI: No channel found with link\n");
++ "NCSI: No channel found to configure!\n");
+ ncsi_report_link(ndp, true);
+ return -ENODEV;
+ }
+
+- ncm = &found->modes[NCSI_MODE_LINK];
+- netdev_dbg(ndp->ndev.dev,
+- "NCSI: Channel %u added to queue (link %s)\n",
+- found->id, ncm->data[2] & 0x1 ? "up" : "down");
+-
+-out:
+- spin_lock_irqsave(&ndp->lock, flags);
+- list_add_tail_rcu(&found->link, &ndp->channel_queue);
+- spin_unlock_irqrestore(&ndp->lock, flags);
+-
+ return ncsi_process_next_channel(ndp);
+ }
+
+@@ -1050,35 +1242,6 @@ static bool ncsi_check_hwa(struct ncsi_dev_priv *ndp)
+ return false;
+ }
+
+-static int ncsi_enable_hwa(struct ncsi_dev_priv *ndp)
+-{
+- struct ncsi_package *np;
+- struct ncsi_channel *nc;
+- unsigned long flags;
+-
+- /* Move all available channels to processing queue */
+- spin_lock_irqsave(&ndp->lock, flags);
+- NCSI_FOR_EACH_PACKAGE(ndp, np) {
+- NCSI_FOR_EACH_CHANNEL(np, nc) {
+- WARN_ON_ONCE(nc->state != NCSI_CHANNEL_INACTIVE ||
+- !list_empty(&nc->link));
+- ncsi_stop_channel_monitor(nc);
+- list_add_tail_rcu(&nc->link, &ndp->channel_queue);
+- }
+- }
+- spin_unlock_irqrestore(&ndp->lock, flags);
+-
+- /* We can have no channels in extremely case */
+- if (list_empty(&ndp->channel_queue)) {
+- netdev_err(ndp->ndev.dev,
+- "NCSI: No available channels for HWA\n");
+- ncsi_report_link(ndp, false);
+- return -ENOENT;
+- }
+-
+- return ncsi_process_next_channel(ndp);
+-}
+-
+ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
+ {
+ struct ncsi_dev *nd = &ndp->ndev;
+@@ -1110,70 +1273,28 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
+ nd->state = ncsi_dev_state_probe_package;
+ break;
+ case ncsi_dev_state_probe_package:
+- ndp->pending_req_num = 16;
++ ndp->pending_req_num = 1;
+
+- /* Select all possible packages */
+ nca.type = NCSI_PKT_CMD_SP;
+ nca.bytes[0] = 1;
++ nca.package = ndp->package_probe_id;
+ nca.channel = NCSI_RESERVED_CHANNEL;
+- for (index = 0; index < 8; index++) {
+- nca.package = index;
+- ret = ncsi_xmit_cmd(&nca);
+- if (ret)
+- goto error;
+- }
+-
+- /* Disable all possible packages */
+- nca.type = NCSI_PKT_CMD_DP;
+- for (index = 0; index < 8; index++) {
+- nca.package = index;
+- ret = ncsi_xmit_cmd(&nca);
+- if (ret)
+- goto error;
+- }
+-
++ ret = ncsi_xmit_cmd(&nca);
++ if (ret)
++ goto error;
+ nd->state = ncsi_dev_state_probe_channel;
+ break;
+ case ncsi_dev_state_probe_channel:
+- if (!ndp->active_package)
+- ndp->active_package = list_first_or_null_rcu(
+- &ndp->packages, struct ncsi_package, node);
+- else if (list_is_last(&ndp->active_package->node,
+- &ndp->packages))
+- ndp->active_package = NULL;
+- else
+- ndp->active_package = list_next_entry(
+- ndp->active_package, node);
+-
+- /* All available packages and channels are enumerated. The
+- * enumeration happens for once when the NCSI interface is
+- * started. So we need continue to start the interface after
+- * the enumeration.
+- *
+- * We have to choose an active channel before configuring it.
+- * Note that we possibly don't have active channel in extreme
+- * situation.
+- */
++ ndp->active_package = ncsi_find_package(ndp,
++ ndp->package_probe_id);
+ if (!ndp->active_package) {
+- ndp->flags |= NCSI_DEV_PROBED;
+- if (ncsi_check_hwa(ndp))
+- ncsi_enable_hwa(ndp);
+- else
+- ncsi_choose_active_channel(ndp);
+- return;
++ /* No response */
++ nd->state = ncsi_dev_state_probe_dp;
++ schedule_work(&ndp->work);
++ break;
+ }
+-
+- /* Select the active package */
+- ndp->pending_req_num = 1;
+- nca.type = NCSI_PKT_CMD_SP;
+- nca.bytes[0] = 1;
+- nca.package = ndp->active_package->id;
+- nca.channel = NCSI_RESERVED_CHANNEL;
+- ret = ncsi_xmit_cmd(&nca);
+- if (ret)
+- goto error;
+-
+ nd->state = ncsi_dev_state_probe_cis;
++ schedule_work(&ndp->work);
+ break;
+ case ncsi_dev_state_probe_cis:
+ ndp->pending_req_num = NCSI_RESERVED_CHANNEL;
+@@ -1222,22 +1343,35 @@ static void ncsi_probe_channel(struct ncsi_dev_priv *ndp)
+ case ncsi_dev_state_probe_dp:
+ ndp->pending_req_num = 1;
+
+- /* Deselect the active package */
++ /* Deselect the current package */
+ nca.type = NCSI_PKT_CMD_DP;
+- nca.package = ndp->active_package->id;
++ nca.package = ndp->package_probe_id;
+ nca.channel = NCSI_RESERVED_CHANNEL;
+ ret = ncsi_xmit_cmd(&nca);
+ if (ret)
+ goto error;
+
+- /* Scan channels in next package */
+- nd->state = ncsi_dev_state_probe_channel;
++ /* Probe next package */
++ ndp->package_probe_id++;
++ if (ndp->package_probe_id >= 8) {
++ /* Probe finished */
++ ndp->flags |= NCSI_DEV_PROBED;
++ break;
++ }
++ nd->state = ncsi_dev_state_probe_package;
++ ndp->active_package = NULL;
+ break;
+ default:
+ netdev_warn(nd->dev, "Wrong NCSI state 0x%0x in enumeration\n",
+ nd->state);
+ }
+
++ if (ndp->flags & NCSI_DEV_PROBED) {
++ /* Check if all packages have HWA support */
++ ncsi_check_hwa(ndp);
++ ncsi_choose_active_channel(ndp);
++ }
++
+ return;
+ error:
+ netdev_err(ndp->ndev.dev,
+@@ -1556,6 +1690,7 @@ struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
+ INIT_LIST_HEAD(&ndp->channel_queue);
+ INIT_LIST_HEAD(&ndp->vlan_vids);
+ INIT_WORK(&ndp->work, ncsi_dev_work);
++ ndp->package_whitelist = UINT_MAX;
+
+ /* Initialize private NCSI device */
+ spin_lock_init(&ndp->lock);
+@@ -1592,26 +1727,19 @@ EXPORT_SYMBOL_GPL(ncsi_register_dev);
+ int ncsi_start_dev(struct ncsi_dev *nd)
+ {
+ struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
+- int ret;
+
+ if (nd->state != ncsi_dev_state_registered &&
+ nd->state != ncsi_dev_state_functional)
+ return -ENOTTY;
+
+ if (!(ndp->flags & NCSI_DEV_PROBED)) {
++ ndp->package_probe_id = 0;
+ nd->state = ncsi_dev_state_probe;
+ schedule_work(&ndp->work);
+ return 0;
+ }
+
+- if (ndp->flags & NCSI_DEV_HWA) {
+- netdev_info(ndp->ndev.dev, "NCSI: Enabling HWA mode\n");
+- ret = ncsi_enable_hwa(ndp);
+- } else {
+- ret = ncsi_choose_active_channel(ndp);
+- }
+-
+- return ret;
++ return ncsi_reset_dev(nd);
+ }
+ EXPORT_SYMBOL_GPL(ncsi_start_dev);
+
+@@ -1624,7 +1752,10 @@ void ncsi_stop_dev(struct ncsi_dev *nd)
+ int old_state;
+ unsigned long flags;
+
+- /* Stop the channel monitor and reset channel's state */
++ /* Stop the channel monitor on any active channels. Don't reset the
++ * channel state so we know which were active when ncsi_start_dev()
++ * is next called.
++ */
+ NCSI_FOR_EACH_PACKAGE(ndp, np) {
+ NCSI_FOR_EACH_CHANNEL(np, nc) {
+ ncsi_stop_channel_monitor(nc);
+@@ -1632,7 +1763,6 @@ void ncsi_stop_dev(struct ncsi_dev *nd)
+ spin_lock_irqsave(&nc->lock, flags);
+ chained = !list_empty(&nc->link);
+ old_state = nc->state;
+- nc->state = NCSI_CHANNEL_INACTIVE;
+ spin_unlock_irqrestore(&nc->lock, flags);
+
+ WARN_ON_ONCE(chained ||
+@@ -1645,6 +1775,92 @@ void ncsi_stop_dev(struct ncsi_dev *nd)
+ }
+ EXPORT_SYMBOL_GPL(ncsi_stop_dev);
+
++int ncsi_reset_dev(struct ncsi_dev *nd)
++{
++ struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
++ struct ncsi_channel *nc, *active, *tmp;
++ struct ncsi_package *np;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ndp->lock, flags);
++
++ if (!(ndp->flags & NCSI_DEV_RESET)) {
++ /* Haven't been called yet, check states */
++ switch (nd->state & ncsi_dev_state_major) {
++ case ncsi_dev_state_registered:
++ case ncsi_dev_state_probe:
++ /* Not even probed yet - do nothing */
++ spin_unlock_irqrestore(&ndp->lock, flags);
++ return 0;
++ case ncsi_dev_state_suspend:
++ case ncsi_dev_state_config:
++ /* Wait for the channel to finish its suspend/config
++ * operation; once it finishes it will check for
++ * NCSI_DEV_RESET and reset the state.
++ */
++ ndp->flags |= NCSI_DEV_RESET;
++ spin_unlock_irqrestore(&ndp->lock, flags);
++ return 0;
++ }
++ } else {
++ switch (nd->state) {
++ case ncsi_dev_state_suspend_done:
++ case ncsi_dev_state_config_done:
++ case ncsi_dev_state_functional:
++ /* Ok */
++ break;
++ default:
++ /* Current reset operation happening */
++ spin_unlock_irqrestore(&ndp->lock, flags);
++ return 0;
++ }
++ }
++
++ if (!list_empty(&ndp->channel_queue)) {
++ /* Clear any channel queue we may have interrupted */
++ list_for_each_entry_safe(nc, tmp, &ndp->channel_queue, link)
++ list_del_init(&nc->link);
++ }
++ spin_unlock_irqrestore(&ndp->lock, flags);
++
++ active = NULL;
++ NCSI_FOR_EACH_PACKAGE(ndp, np) {
++ NCSI_FOR_EACH_CHANNEL(np, nc) {
++ spin_lock_irqsave(&nc->lock, flags);
++
++ if (nc->state == NCSI_CHANNEL_ACTIVE) {
++ active = nc;
++ nc->state = NCSI_CHANNEL_INVISIBLE;
++ spin_unlock_irqrestore(&nc->lock, flags);
++ ncsi_stop_channel_monitor(nc);
++ break;
++ }
++
++ spin_unlock_irqrestore(&nc->lock, flags);
++ }
++ if (active)
++ break;
++ }
++
++ if (!active) {
++ /* Done */
++ spin_lock_irqsave(&ndp->lock, flags);
++ ndp->flags &= ~NCSI_DEV_RESET;
++ spin_unlock_irqrestore(&ndp->lock, flags);
++ return ncsi_choose_active_channel(ndp);
++ }
++
++ spin_lock_irqsave(&ndp->lock, flags);
++ ndp->flags |= NCSI_DEV_RESET;
++ ndp->active_channel = active;
++ ndp->active_package = active->package;
++ spin_unlock_irqrestore(&ndp->lock, flags);
++
++ nd->state = ncsi_dev_state_suspend;
++ schedule_work(&ndp->work);
++ return 0;
++}
++
+ void ncsi_unregister_dev(struct ncsi_dev *nd)
+ {
+ struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
+diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c
+index 33314381b4f5..5d782445d2fc 100644
+--- a/net/ncsi/ncsi-netlink.c
++++ b/net/ncsi/ncsi-netlink.c
+@@ -30,6 +30,9 @@ static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = {
+ [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 },
+ [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 },
+ [NCSI_ATTR_DATA] = { .type = NLA_BINARY, .len = 2048 },
++ [NCSI_ATTR_MULTI_FLAG] = { .type = NLA_FLAG },
++ [NCSI_ATTR_PACKAGE_MASK] = { .type = NLA_U32 },
++ [NCSI_ATTR_CHANNEL_MASK] = { .type = NLA_U32 },
+ };
+
+ static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex)
+@@ -69,7 +72,7 @@ static int ncsi_write_channel_info(struct sk_buff *skb,
+ nla_put_u32(skb, NCSI_CHANNEL_ATTR_LINK_STATE, m->data[2]);
+ if (nc->state == NCSI_CHANNEL_ACTIVE)
+ nla_put_flag(skb, NCSI_CHANNEL_ATTR_ACTIVE);
+- if (ndp->force_channel == nc)
++ if (nc == nc->package->preferred_channel)
+ nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED);
+
+ nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.version);
+@@ -114,7 +117,7 @@ static int ncsi_write_package_info(struct sk_buff *skb,
+ if (!pnest)
+ return -ENOMEM;
+ nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id);
+- if (ndp->force_package == np)
++ if ((0x1 << np->id) == ndp->package_whitelist)
+ nla_put_flag(skb, NCSI_PKG_ATTR_FORCED);
+ cnest = nla_nest_start(skb, NCSI_PKG_ATTR_CHANNEL_LIST);
+ if (!cnest) {
+@@ -290,49 +293,58 @@ static int ncsi_set_interface_nl(struct sk_buff *msg, struct genl_info *info)
+ package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
+ package = NULL;
+
+- spin_lock_irqsave(&ndp->lock, flags);
+-
+ NCSI_FOR_EACH_PACKAGE(ndp, np)
+ if (np->id == package_id)
+ package = np;
+ if (!package) {
+ /* The user has set a package that does not exist */
+- spin_unlock_irqrestore(&ndp->lock, flags);
+ return -ERANGE;
+ }
+
+ channel = NULL;
+- if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) {
+- /* Allow any channel */
+- channel_id = NCSI_RESERVED_CHANNEL;
+- } else {
++ if (info->attrs[NCSI_ATTR_CHANNEL_ID]) {
+ channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
+ NCSI_FOR_EACH_CHANNEL(package, nc)
+- if (nc->id == channel_id)
++ if (nc->id == channel_id) {
+ channel = nc;
++ break;
++ }
++ if (!channel) {
++ netdev_info(ndp->ndev.dev,
++ "NCSI: Channel %u does not exist!\n",
++ channel_id);
++ return -ERANGE;
++ }
+ }
+
+- if (channel_id != NCSI_RESERVED_CHANNEL && !channel) {
+- /* The user has set a channel that does not exist on this
+- * package
+- */
+- spin_unlock_irqrestore(&ndp->lock, flags);
+- netdev_info(ndp->ndev.dev, "NCSI: Channel %u does not exist!\n",
+- channel_id);
+- return -ERANGE;
+- }
+-
+- ndp->force_package = package;
+- ndp->force_channel = channel;
++ spin_lock_irqsave(&ndp->lock, flags);
++ ndp->package_whitelist = 0x1 << package->id;
++ ndp->multi_package = false;
+ spin_unlock_irqrestore(&ndp->lock, flags);
+
+- netdev_info(ndp->ndev.dev, "Set package 0x%x, channel 0x%x%s as preferred\n",
+- package_id, channel_id,
+- channel_id == NCSI_RESERVED_CHANNEL ? " (any)" : "");
++ spin_lock_irqsave(&package->lock, flags);
++ package->multi_channel = false;
++ if (channel) {
++ package->channel_whitelist = 0x1 << channel->id;
++ package->preferred_channel = channel;
++ } else {
++ /* Allow any channel */
++ package->channel_whitelist = UINT_MAX;
++ package->preferred_channel = NULL;
++ }
++ spin_unlock_irqrestore(&package->lock, flags);
++
++ if (channel)
++ netdev_info(ndp->ndev.dev,
++ "Set package 0x%x, channel 0x%x as preferred\n",
++ package_id, channel_id);
++ else
++ netdev_info(ndp->ndev.dev, "Set package 0x%x as preferred\n",
++ package_id);
+
+- /* Bounce the NCSI channel to set changes */
+- ncsi_stop_dev(&ndp->ndev);
+- ncsi_start_dev(&ndp->ndev);
++ /* Update channel configuration */
++ if (!(ndp->flags & NCSI_DEV_RESET))
++ ncsi_reset_dev(&ndp->ndev);
+
+ return 0;
+ }
+@@ -340,6 +352,7 @@ static int ncsi_set_interface_nl(struct sk_buff *msg, struct genl_info *info)
+ static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info)
+ {
+ struct ncsi_dev_priv *ndp;
++ struct ncsi_package *np;
+ unsigned long flags;
+
+ if (!info || !info->attrs)
+@@ -353,16 +366,24 @@ static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info)
+ if (!ndp)
+ return -ENODEV;
+
+- /* Clear any override */
++ /* Reset any whitelists and disable multi mode */
+ spin_lock_irqsave(&ndp->lock, flags);
+- ndp->force_package = NULL;
+- ndp->force_channel = NULL;
++ ndp->package_whitelist = UINT_MAX;
++ ndp->multi_package = false;
+ spin_unlock_irqrestore(&ndp->lock, flags);
++
++ NCSI_FOR_EACH_PACKAGE(ndp, np) {
++ spin_lock_irqsave(&np->lock, flags);
++ np->multi_channel = false;
++ np->channel_whitelist = UINT_MAX;
++ np->preferred_channel = NULL;
++ spin_unlock_irqrestore(&np->lock, flags);
++ }
+ netdev_info(ndp->ndev.dev, "NCSI: Cleared preferred package/channel\n");
+
+- /* Bounce the NCSI channel to set changes */
+- ncsi_stop_dev(&ndp->ndev);
+- ncsi_start_dev(&ndp->ndev);
++ /* Update channel configuration */
++ if (!(ndp->flags & NCSI_DEV_RESET))
++ ncsi_reset_dev(&ndp->ndev);
+
+ return 0;
+ }
+@@ -563,6 +584,138 @@ int ncsi_send_netlink_err(struct net_device *dev,
+ return nlmsg_unicast(net->genl_sock, skb, snd_portid);
+ }
+
++static int ncsi_set_package_mask_nl(struct sk_buff *msg,
++ struct genl_info *info)
++{
++ struct ncsi_dev_priv *ndp;
++ unsigned long flags;
++ int rc;
++
++ if (!info || !info->attrs)
++ return -EINVAL;
++
++ if (!info->attrs[NCSI_ATTR_IFINDEX])
++ return -EINVAL;
++
++ if (!info->attrs[NCSI_ATTR_PACKAGE_MASK])
++ return -EINVAL;
++
++ ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
++ nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
++ if (!ndp)
++ return -ENODEV;
++
++ spin_lock_irqsave(&ndp->lock, flags);
++ if (nla_get_flag(info->attrs[NCSI_ATTR_MULTI_FLAG])) {
++ if (ndp->flags & NCSI_DEV_HWA) {
++ ndp->multi_package = true;
++ rc = 0;
++ } else {
++ netdev_err(ndp->ndev.dev,
++ "NCSI: Can't use multiple packages without HWA\n");
++ rc = -EPERM;
++ }
++ } else {
++ ndp->multi_package = false;
++ rc = 0;
++ }
++
++ if (!rc)
++ ndp->package_whitelist =
++ nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_MASK]);
++ spin_unlock_irqrestore(&ndp->lock, flags);
++
++ if (!rc) {
++ /* Update channel configuration */
++ if (!(ndp->flags & NCSI_DEV_RESET))
++ ncsi_reset_dev(&ndp->ndev);
++ }
++
++ return rc;
++}
++
++static int ncsi_set_channel_mask_nl(struct sk_buff *msg,
++ struct genl_info *info)
++{
++ struct ncsi_package *np, *package;
++ struct ncsi_channel *nc, *channel;
++ u32 package_id, channel_id;
++ struct ncsi_dev_priv *ndp;
++ unsigned long flags;
++
++ if (!info || !info->attrs)
++ return -EINVAL;
++
++ if (!info->attrs[NCSI_ATTR_IFINDEX])
++ return -EINVAL;
++
++ if (!info->attrs[NCSI_ATTR_PACKAGE_ID])
++ return -EINVAL;
++
++ if (!info->attrs[NCSI_ATTR_CHANNEL_MASK])
++ return -EINVAL;
++
++ ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
++ nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
++ if (!ndp)
++ return -ENODEV;
++
++ package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
++ package = NULL;
++ NCSI_FOR_EACH_PACKAGE(ndp, np)
++ if (np->id == package_id) {
++ package = np;
++ break;
++ }
++ if (!package)
++ return -ERANGE;
++
++ spin_lock_irqsave(&package->lock, flags);
++
++ channel = NULL;
++ if (info->attrs[NCSI_ATTR_CHANNEL_ID]) {
++ channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
++ NCSI_FOR_EACH_CHANNEL(np, nc)
++ if (nc->id == channel_id) {
++ channel = nc;
++ break;
++ }
++ if (!channel) {
++ spin_unlock_irqrestore(&package->lock, flags);
++ return -ERANGE;
++ }
++ netdev_dbg(ndp->ndev.dev,
++ "NCSI: Channel %u set as preferred channel\n",
++ channel->id);
++ }
++
++ package->channel_whitelist =
++ nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_MASK]);
++ if (package->channel_whitelist == 0)
++ netdev_dbg(ndp->ndev.dev,
++ "NCSI: Package %u set to all channels disabled\n",
++ package->id);
++
++ package->preferred_channel = channel;
++
++ if (nla_get_flag(info->attrs[NCSI_ATTR_MULTI_FLAG])) {
++ package->multi_channel = true;
++ netdev_info(ndp->ndev.dev,
++ "NCSI: Multi-channel enabled on package %u\n",
++ package_id);
++ } else {
++ package->multi_channel = false;
++ }
++
++ spin_unlock_irqrestore(&package->lock, flags);
++
++ /* Update channel configuration */
++ if (!(ndp->flags & NCSI_DEV_RESET))
++ ncsi_reset_dev(&ndp->ndev);
++
++ return 0;
++}
++
+ static const struct genl_ops ncsi_ops[] = {
+ {
+ .cmd = NCSI_CMD_PKG_INFO,
+@@ -589,6 +742,18 @@ static const struct genl_ops ncsi_ops[] = {
+ .doit = ncsi_send_cmd_nl,
+ .flags = GENL_ADMIN_PERM,
+ },
++ {
++ .cmd = NCSI_CMD_SET_PACKAGE_MASK,
++ .policy = ncsi_genl_policy,
++ .doit = ncsi_set_package_mask_nl,
++ .flags = GENL_ADMIN_PERM,
++ },
++ {
++ .cmd = NCSI_CMD_SET_CHANNEL_MASK,
++ .policy = ncsi_genl_policy,
++ .doit = ncsi_set_channel_mask_nl,
++ .flags = GENL_ADMIN_PERM,
++ },
+ };
+
+ static struct genl_family ncsi_genl_family __ro_after_init = {
+diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
+index 77e07ba3f493..de7737a27889 100644
+--- a/net/ncsi/ncsi-rsp.c
++++ b/net/ncsi/ncsi-rsp.c
+@@ -256,7 +256,7 @@ static int ncsi_rsp_handler_dcnt(struct ncsi_request *nr)
+ if (!ncm->enable)
+ return 0;
+
+- ncm->enable = 1;
++ ncm->enable = 0;
+ return 0;
+ }
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0038-media-aspeed-backport-ikvm-patches.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0038-media-aspeed-backport-ikvm-patches.patch
new file mode 100644
index 000000000..02e423057
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0038-media-aspeed-backport-ikvm-patches.patch
@@ -0,0 +1,1995 @@
+From feb75b023dfd0ebe3e8ca46f0e74603f07542c29 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Fri, 9 Nov 2018 11:32:27 -0800
+Subject: [PATCH] Add Aspeed Video Engine Driver
+
+The Video Engine (VE) embedded in the Aspeed AST2400 and AST2500 SOCs
+can capture and compress video data from digital or analog sources. With
+the Aspeed chip acting a service processor, the Video Engine can capture
+the host processor graphics output.
+
+Add a V4L2 driver to capture video data and compress it to JPEG images.
+Make the video frames available through the V4L2 streaming interface.
+
+media: platform: Fix missing spin_lock_init()
+
+The driver allocates the spinlock but not initialize it.
+Use spin_lock_init() on it to initialize it correctly.
+
+This is detected by Coccinelle semantic patch.
+
+Fixes: d2b4387f3bdf ("media: platform: Add Aspeed Video Engine driver")
+
+Signed-off-by: Eddie James <eajames@linux.ibm.com>
+Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+---
+ .../devicetree/bindings/media/aspeed-video.txt | 26 +
+ MAINTAINERS | 8 +
+ arch/arm/boot/dts/aspeed-g5.dtsi | 11 +
+ drivers/clk/clk-aspeed.c | 41 +-
+ drivers/media/platform/Kconfig | 9 +
+ drivers/media/platform/Makefile | 1 +
+ drivers/media/platform/aspeed-video.c | 1730 ++++++++++++++++++++
+ include/dt-bindings/clock/aspeed-clock.h | 1 +
+ 8 files changed, 1825 insertions(+), 2 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/media/aspeed-video.txt
+ create mode 100644 drivers/media/platform/aspeed-video.c
+
+diff --git a/Documentation/devicetree/bindings/media/aspeed-video.txt b/Documentation/devicetree/bindings/media/aspeed-video.txt
+new file mode 100644
+index 000000000000..78b464ae2672
+--- /dev/null
++++ b/Documentation/devicetree/bindings/media/aspeed-video.txt
+@@ -0,0 +1,26 @@
++* Device tree bindings for Aspeed Video Engine
++
++The Video Engine (VE) embedded in the Aspeed AST2400 and AST2500 SOCs can
++capture and compress video data from digital or analog sources.
++
++Required properties:
++ - compatible: "aspeed,ast2400-video-engine" or
++ "aspeed,ast2500-video-engine"
++ - reg: contains the offset and length of the VE memory region
++ - clocks: clock specifiers for the syscon clocks associated with
++ the VE (ordering must match the clock-names property)
++ - clock-names: "vclk" and "eclk"
++ - resets: reset specifier for the syscon reset associated with
++ the VE
++ - interrupts: the interrupt associated with the VE on this platform
++
++Example:
++
++video-engine@1e700000 {
++ compatible = "aspeed,ast2500-video-engine";
++ reg = <0x1e700000 0x20000>;
++ clocks = <&syscon ASPEED_CLK_GATE_VCLK>, <&syscon ASPEED_CLK_GATE_ECLK>;
++ clock-names = "vclk", "eclk";
++ resets = <&syscon ASPEED_RESET_VIDEO>;
++ interrupts = <7>;
++};
+diff --git a/MAINTAINERS b/MAINTAINERS
+index b98a5763f6c1..cdd8f824b6da 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -2358,6 +2358,14 @@ S: Maintained
+ F: Documentation/hwmon/asc7621
+ F: drivers/hwmon/asc7621.c
+
++ASPEED VIDEO ENGINE DRIVER
++M: Eddie James <eajames@linux.ibm.com>
++L: linux-media@vger.kernel.org
++L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
++S: Maintained
++F: drivers/media/platform/aspeed-video.c
++F: Documentation/devicetree/bindings/media/aspeed-video.txt
++
+ ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS
+ M: Corentin Chary <corentin.chary@gmail.com>
+ L: acpi4asus-user@lists.sourceforge.net
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index 69330ae2efd3..946c13eaa1d4 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -243,6 +243,17 @@
+ interrupts = <0x19>;
+ };
+
++ video: video@1e700000 {
++ compatible = "aspeed,ast2500-video-engine";
++ reg = <0x1e700000 0x20000>;
++ clocks = <&syscon ASPEED_CLK_GATE_VCLK>,
++ <&syscon ASPEED_CLK_GATE_ECLK>;
++ clock-names = "vclk", "eclk";
++ resets = <&syscon ASPEED_RESET_VIDEO>;
++ interrupts = <7>;
++ status = "disabled";
++ };
++
+ adc: adc@1e6e9000 {
+ compatible = "aspeed,ast2500-adc";
+ reg = <0x1e6e9000 0xb0>;
+diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
+index 3bbb4fbf00c9..6cea55de485f 100644
+--- a/drivers/clk/clk-aspeed.c
++++ b/drivers/clk/clk-aspeed.c
+@@ -95,7 +95,7 @@ struct aspeed_clk_gate {
+ /* TODO: ask Aspeed about the actual parent data */
+ static const struct aspeed_gate_data aspeed_gates[] = {
+ /* clk rst name parent flags */
+- [ASPEED_CLK_GATE_ECLK] = { 0, -1, "eclk-gate", "eclk", 0 }, /* Video Engine */
++ [ASPEED_CLK_GATE_ECLK] = { 0, 6, "eclk-gate", "eclk", 0 }, /* Video Engine */
+ [ASPEED_CLK_GATE_GCLK] = { 1, 7, "gclk-gate", NULL, 0 }, /* 2D engine */
+ [ASPEED_CLK_GATE_MCLK] = { 2, -1, "mclk-gate", "mpll", CLK_IS_CRITICAL }, /* SDRAM */
+ [ASPEED_CLK_GATE_VCLK] = { 3, 6, "vclk-gate", NULL, 0 }, /* Video Capture */
+@@ -121,6 +121,24 @@ static const struct aspeed_gate_data aspeed_gates[] = {
+ [ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */
+ };
+
++static const char * const eclk_parent_names[] = {
++ "mpll",
++ "hpll",
++ "dpll",
++};
++
++static const struct clk_div_table ast2500_eclk_div_table[] = {
++ { 0x0, 2 },
++ { 0x1, 2 },
++ { 0x2, 3 },
++ { 0x3, 4 },
++ { 0x4, 5 },
++ { 0x5, 6 },
++ { 0x6, 7 },
++ { 0x7, 8 },
++ { 0 }
++};
++
+ static const struct clk_div_table ast2500_mac_div_table[] = {
+ { 0x0, 4 }, /* Yep, really. Aspeed confirmed this is correct */
+ { 0x1, 4 },
+@@ -200,18 +218,21 @@ static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val)
+
+ struct aspeed_clk_soc_data {
+ const struct clk_div_table *div_table;
++ const struct clk_div_table *eclk_div_table;
+ const struct clk_div_table *mac_div_table;
+ struct clk_hw *(*calc_pll)(const char *name, u32 val);
+ };
+
+ static const struct aspeed_clk_soc_data ast2500_data = {
+ .div_table = ast2500_div_table,
++ .eclk_div_table = ast2500_eclk_div_table,
+ .mac_div_table = ast2500_mac_div_table,
+ .calc_pll = aspeed_ast2500_calc_pll,
+ };
+
+ static const struct aspeed_clk_soc_data ast2400_data = {
+ .div_table = ast2400_div_table,
++ .eclk_div_table = ast2400_div_table,
+ .mac_div_table = ast2400_div_table,
+ .calc_pll = aspeed_ast2400_calc_pll,
+ };
+@@ -325,6 +346,7 @@ static const u8 aspeed_resets[] = {
+ [ASPEED_RESET_PECI] = 10,
+ [ASPEED_RESET_I2C] = 2,
+ [ASPEED_RESET_AHB] = 1,
++ [ASPEED_RESET_VIDEO] = 6,
+
+ /*
+ * SCUD4 resets start at an offset to separate them from
+@@ -538,6 +560,22 @@ static int aspeed_clk_probe(struct platform_device *pdev)
+ return PTR_ERR(hw);
+ aspeed_clk_data->hws[ASPEED_CLK_24M] = hw;
+
++ hw = clk_hw_register_mux(dev, "eclk-mux", eclk_parent_names,
++ ARRAY_SIZE(eclk_parent_names), 0,
++ scu_base + ASPEED_CLK_SELECTION, 2, 0x3, 0,
++ &aspeed_clk_lock);
++ if (IS_ERR(hw))
++ return PTR_ERR(hw);
++ aspeed_clk_data->hws[ASPEED_CLK_ECLK_MUX] = hw;
++
++ hw = clk_hw_register_divider_table(dev, "eclk", "eclk-mux", 0,
++ scu_base + ASPEED_CLK_SELECTION, 28,
++ 3, 0, soc_data->eclk_div_table,
++ &aspeed_clk_lock);
++ if (IS_ERR(hw))
++ return PTR_ERR(hw);
++ aspeed_clk_data->hws[ASPEED_CLK_ECLK] = hw;
++
+ /*
+ * TODO: There are a number of clocks that not included in this driver
+ * as more information is required:
+@@ -547,7 +585,6 @@ static int aspeed_clk_probe(struct platform_device *pdev)
+ * RGMII
+ * RMII
+ * UART[1..5] clock source mux
+- * Video Engine (ECLK) mux and clock divider
+ */
+
+ /* Get the uart clock source configuration from SCU4C*/
+diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
+index 54fe90acb5b2..d6edf2d28f9b 100644
+--- a/drivers/media/platform/Kconfig
++++ b/drivers/media/platform/Kconfig
+@@ -32,6 +32,15 @@ source "drivers/media/platform/davinci/Kconfig"
+
+ source "drivers/media/platform/omap/Kconfig"
+
++config VIDEO_ASPEED
++ tristate "Aspeed AST2400 and AST2500 Video Engine driver"
++ depends on VIDEO_V4L2
++ select VIDEOBUF2_DMA_CONTIG
++ help
++ Support for the Aspeed Video Engine (VE) embedded in the Aspeed
++ AST2400 and AST2500 SOCs. The VE can capture and compress video data
++ from digital or analog sources.
++
+ config VIDEO_SH_VOU
+ tristate "SuperH VOU video output driver"
+ depends on MEDIA_CAMERA_SUPPORT
+diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
+index 41322ab65802..205c33a004fc 100644
+--- a/drivers/media/platform/Makefile
++++ b/drivers/media/platform/Makefile
+@@ -3,6 +3,7 @@
+ # Makefile for the video capture/playback device drivers.
+ #
+
++obj-$(CONFIG_VIDEO_ASPEED) += aspeed-video.o
+ obj-$(CONFIG_VIDEO_CADENCE) += cadence/
+ obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
+ obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/
+diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
+new file mode 100644
+index 000000000000..692e08ef38c0
+--- /dev/null
++++ b/drivers/media/platform/aspeed-video.c
+@@ -0,0 +1,1730 @@
++// SPDX-License-Identifier: GPL-2.0+
++
++#include <linux/atomic.h>
++#include <linux/bitfield.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/jiffies.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/of_reserved_mem.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/string.h>
++#include <linux/v4l2-controls.h>
++#include <linux/videodev2.h>
++#include <linux/wait.h>
++#include <linux/workqueue.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-dev.h>
++#include <media/v4l2-device.h>
++#include <media/v4l2-dv-timings.h>
++#include <media/v4l2-event.h>
++#include <media/v4l2-ioctl.h>
++#include <media/videobuf2-dma-contig.h>
++
++#define DEVICE_NAME "aspeed-video"
++
++#define ASPEED_VIDEO_JPEG_NUM_QUALITIES 12
++#define ASPEED_VIDEO_JPEG_HEADER_SIZE 10
++#define ASPEED_VIDEO_JPEG_QUANT_SIZE 116
++#define ASPEED_VIDEO_JPEG_DCT_SIZE 34
++
++#define MAX_FRAME_RATE 60
++#define MAX_HEIGHT 1200
++#define MAX_WIDTH 1920
++#define MIN_HEIGHT 480
++#define MIN_WIDTH 640
++
++#define NUM_POLARITY_CHECKS 10
++#define INVALID_RESOLUTION_RETRIES 2
++#define INVALID_RESOLUTION_DELAY msecs_to_jiffies(250)
++#define RESOLUTION_CHANGE_DELAY msecs_to_jiffies(500)
++#define MODE_DETECT_TIMEOUT msecs_to_jiffies(500)
++#define STOP_TIMEOUT msecs_to_jiffies(1000)
++#define DIRECT_FETCH_THRESHOLD 0x0c0000 /* 1024 * 768 */
++
++#define VE_MAX_SRC_BUFFER_SIZE 0x8ca000 /* 1920 * 1200, 32bpp */
++#define VE_JPEG_HEADER_SIZE 0x006000 /* 512 * 12 * 4 */
++
++#define VE_PROTECTION_KEY 0x000
++#define VE_PROTECTION_KEY_UNLOCK 0x1a038aa8
++
++#define VE_SEQ_CTRL 0x004
++#define VE_SEQ_CTRL_TRIG_MODE_DET BIT(0)
++#define VE_SEQ_CTRL_TRIG_CAPTURE BIT(1)
++#define VE_SEQ_CTRL_FORCE_IDLE BIT(2)
++#define VE_SEQ_CTRL_MULT_FRAME BIT(3)
++#define VE_SEQ_CTRL_TRIG_COMP BIT(4)
++#define VE_SEQ_CTRL_AUTO_COMP BIT(5)
++#define VE_SEQ_CTRL_EN_WATCHDOG BIT(7)
++#define VE_SEQ_CTRL_YUV420 BIT(10)
++#define VE_SEQ_CTRL_COMP_FMT GENMASK(11, 10)
++#define VE_SEQ_CTRL_HALT BIT(12)
++#define VE_SEQ_CTRL_EN_WATCHDOG_COMP BIT(14)
++#define VE_SEQ_CTRL_TRIG_JPG BIT(15)
++#define VE_SEQ_CTRL_CAP_BUSY BIT(16)
++#define VE_SEQ_CTRL_COMP_BUSY BIT(18)
++
++#ifdef CONFIG_MACH_ASPEED_G5
++#define VE_SEQ_CTRL_JPEG_MODE BIT(13) /* AST2500 */
++#else
++#define VE_SEQ_CTRL_JPEG_MODE BIT(8) /* AST2400 */
++#endif /* CONFIG_MACH_ASPEED_G5 */
++
++#define VE_CTRL 0x008
++#define VE_CTRL_HSYNC_POL BIT(0)
++#define VE_CTRL_VSYNC_POL BIT(1)
++#define VE_CTRL_SOURCE BIT(2)
++#define VE_CTRL_INT_DE BIT(4)
++#define VE_CTRL_DIRECT_FETCH BIT(5)
++#define VE_CTRL_YUV BIT(6)
++#define VE_CTRL_RGB BIT(7)
++#define VE_CTRL_CAPTURE_FMT GENMASK(7, 6)
++#define VE_CTRL_AUTO_OR_CURSOR BIT(8)
++#define VE_CTRL_CLK_INVERSE BIT(11)
++#define VE_CTRL_CLK_DELAY GENMASK(11, 9)
++#define VE_CTRL_INTERLACE BIT(14)
++#define VE_CTRL_HSYNC_POL_CTRL BIT(15)
++#define VE_CTRL_FRC GENMASK(23, 16)
++
++#define VE_TGS_0 0x00c
++#define VE_TGS_1 0x010
++#define VE_TGS_FIRST GENMASK(28, 16)
++#define VE_TGS_LAST GENMASK(12, 0)
++
++#define VE_SCALING_FACTOR 0x014
++#define VE_SCALING_FILTER0 0x018
++#define VE_SCALING_FILTER1 0x01c
++#define VE_SCALING_FILTER2 0x020
++#define VE_SCALING_FILTER3 0x024
++
++#define VE_CAP_WINDOW 0x030
++#define VE_COMP_WINDOW 0x034
++#define VE_COMP_PROC_OFFSET 0x038
++#define VE_COMP_OFFSET 0x03c
++#define VE_JPEG_ADDR 0x040
++#define VE_SRC0_ADDR 0x044
++#define VE_SRC_SCANLINE_OFFSET 0x048
++#define VE_SRC1_ADDR 0x04c
++#define VE_COMP_ADDR 0x054
++
++#define VE_STREAM_BUF_SIZE 0x058
++#define VE_STREAM_BUF_SIZE_N_PACKETS GENMASK(5, 3)
++#define VE_STREAM_BUF_SIZE_P_SIZE GENMASK(2, 0)
++
++#define VE_COMP_CTRL 0x060
++#define VE_COMP_CTRL_VQ_DCT_ONLY BIT(0)
++#define VE_COMP_CTRL_VQ_4COLOR BIT(1)
++#define VE_COMP_CTRL_QUANTIZE BIT(2)
++#define VE_COMP_CTRL_EN_BQ BIT(4)
++#define VE_COMP_CTRL_EN_CRYPTO BIT(5)
++#define VE_COMP_CTRL_DCT_CHR GENMASK(10, 6)
++#define VE_COMP_CTRL_DCT_LUM GENMASK(15, 11)
++#define VE_COMP_CTRL_EN_HQ BIT(16)
++#define VE_COMP_CTRL_RSVD BIT(19)
++#define VE_COMP_CTRL_ENCODE GENMASK(21, 20)
++#define VE_COMP_CTRL_HQ_DCT_CHR GENMASK(26, 22)
++#define VE_COMP_CTRL_HQ_DCT_LUM GENMASK(31, 27)
++
++#define VE_OFFSET_COMP_STREAM 0x078
++
++#define VE_SRC_LR_EDGE_DET 0x090
++#define VE_SRC_LR_EDGE_DET_LEFT GENMASK(11, 0)
++#define VE_SRC_LR_EDGE_DET_NO_V BIT(12)
++#define VE_SRC_LR_EDGE_DET_NO_H BIT(13)
++#define VE_SRC_LR_EDGE_DET_NO_DISP BIT(14)
++#define VE_SRC_LR_EDGE_DET_NO_CLK BIT(15)
++#define VE_SRC_LR_EDGE_DET_RT_SHF 16
++#define VE_SRC_LR_EDGE_DET_RT GENMASK(27, VE_SRC_LR_EDGE_DET_RT_SHF)
++#define VE_SRC_LR_EDGE_DET_INTERLACE BIT(31)
++
++#define VE_SRC_TB_EDGE_DET 0x094
++#define VE_SRC_TB_EDGE_DET_TOP GENMASK(12, 0)
++#define VE_SRC_TB_EDGE_DET_BOT_SHF 16
++#define VE_SRC_TB_EDGE_DET_BOT GENMASK(28, VE_SRC_TB_EDGE_DET_BOT_SHF)
++
++#define VE_MODE_DETECT_STATUS 0x098
++#define VE_MODE_DETECT_H_PIXELS GENMASK(11, 0)
++#define VE_MODE_DETECT_V_LINES_SHF 16
++#define VE_MODE_DETECT_V_LINES GENMASK(27, VE_MODE_DETECT_V_LINES_SHF)
++#define VE_MODE_DETECT_STATUS_VSYNC BIT(28)
++#define VE_MODE_DETECT_STATUS_HSYNC BIT(29)
++
++#define VE_SYNC_STATUS 0x09c
++#define VE_SYNC_STATUS_HSYNC GENMASK(11, 0)
++#define VE_SYNC_STATUS_VSYNC_SHF 16
++#define VE_SYNC_STATUS_VSYNC GENMASK(27, VE_SYNC_STATUS_VSYNC_SHF)
++
++#define VE_INTERRUPT_CTRL 0x304
++#define VE_INTERRUPT_STATUS 0x308
++#define VE_INTERRUPT_MODE_DETECT_WD BIT(0)
++#define VE_INTERRUPT_CAPTURE_COMPLETE BIT(1)
++#define VE_INTERRUPT_COMP_READY BIT(2)
++#define VE_INTERRUPT_COMP_COMPLETE BIT(3)
++#define VE_INTERRUPT_MODE_DETECT BIT(4)
++#define VE_INTERRUPT_FRAME_COMPLETE BIT(5)
++#define VE_INTERRUPT_DECODE_ERR BIT(6)
++#define VE_INTERRUPT_HALT_READY BIT(8)
++#define VE_INTERRUPT_HANG_WD BIT(9)
++#define VE_INTERRUPT_STREAM_DESC BIT(10)
++#define VE_INTERRUPT_VSYNC_DESC BIT(11)
++
++#define VE_MODE_DETECT 0x30c
++#define VE_MEM_RESTRICT_START 0x310
++#define VE_MEM_RESTRICT_END 0x314
++
++enum {
++ VIDEO_MODE_DETECT_DONE,
++ VIDEO_RES_CHANGE,
++ VIDEO_RES_DETECT,
++ VIDEO_STREAMING,
++ VIDEO_FRAME_INPRG,
++ VIDEO_STOPPED,
++};
++
++struct aspeed_video_addr {
++ unsigned int size;
++ dma_addr_t dma;
++ void *virt;
++};
++
++struct aspeed_video_buffer {
++ struct vb2_v4l2_buffer vb;
++ struct list_head link;
++};
++
++#define to_aspeed_video_buffer(x) \
++ container_of((x), struct aspeed_video_buffer, vb)
++
++struct aspeed_video {
++ void __iomem *base;
++ struct clk *eclk;
++ struct clk *vclk;
++ struct reset_control *rst;
++
++ struct device *dev;
++ struct v4l2_ctrl_handler ctrl_handler;
++ struct v4l2_device v4l2_dev;
++ struct v4l2_pix_format pix_fmt;
++ struct v4l2_bt_timings active_timings;
++ struct v4l2_bt_timings detected_timings;
++ u32 v4l2_input_status;
++ struct vb2_queue queue;
++ struct video_device vdev;
++ struct mutex video_lock; /* v4l2 and videobuf2 lock */
++
++ wait_queue_head_t wait;
++ spinlock_t lock; /* buffer list lock */
++ struct delayed_work res_work;
++ struct list_head buffers;
++ unsigned long flags;
++ unsigned int sequence;
++
++ unsigned int max_compressed_size;
++ struct aspeed_video_addr srcs[2];
++ struct aspeed_video_addr jpeg;
++
++ bool yuv420;
++ unsigned int frame_rate;
++ unsigned int jpeg_quality;
++
++ unsigned int frame_bottom;
++ unsigned int frame_left;
++ unsigned int frame_right;
++ unsigned int frame_top;
++};
++
++#define to_aspeed_video(x) container_of((x), struct aspeed_video, v4l2_dev)
++
++static const u32 aspeed_video_jpeg_header[ASPEED_VIDEO_JPEG_HEADER_SIZE] = {
++ 0xe0ffd8ff, 0x464a1000, 0x01004649, 0x60000101, 0x00006000, 0x0f00feff,
++ 0x00002d05, 0x00000000, 0x00000000, 0x00dbff00
++};
++
++static const u32 aspeed_video_jpeg_quant[ASPEED_VIDEO_JPEG_QUANT_SIZE] = {
++ 0x081100c0, 0x00000000, 0x00110103, 0x03011102, 0xc4ff0111, 0x00001f00,
++ 0x01010501, 0x01010101, 0x00000000, 0x00000000, 0x04030201, 0x08070605,
++ 0xff0b0a09, 0x10b500c4, 0x03010200, 0x03040203, 0x04040505, 0x7d010000,
++ 0x00030201, 0x12051104, 0x06413121, 0x07615113, 0x32147122, 0x08a19181,
++ 0xc1b14223, 0xf0d15215, 0x72623324, 0x160a0982, 0x1a191817, 0x28272625,
++ 0x35342a29, 0x39383736, 0x4544433a, 0x49484746, 0x5554534a, 0x59585756,
++ 0x6564635a, 0x69686766, 0x7574736a, 0x79787776, 0x8584837a, 0x89888786,
++ 0x9493928a, 0x98979695, 0xa3a29a99, 0xa7a6a5a4, 0xb2aaa9a8, 0xb6b5b4b3,
++ 0xbab9b8b7, 0xc5c4c3c2, 0xc9c8c7c6, 0xd4d3d2ca, 0xd8d7d6d5, 0xe2e1dad9,
++ 0xe6e5e4e3, 0xeae9e8e7, 0xf4f3f2f1, 0xf8f7f6f5, 0xc4fffaf9, 0x00011f00,
++ 0x01010103, 0x01010101, 0x00000101, 0x00000000, 0x04030201, 0x08070605,
++ 0xff0b0a09, 0x11b500c4, 0x02010200, 0x04030404, 0x04040507, 0x77020100,
++ 0x03020100, 0x21050411, 0x41120631, 0x71610751, 0x81322213, 0x91421408,
++ 0x09c1b1a1, 0xf0523323, 0xd1726215, 0x3424160a, 0x17f125e1, 0x261a1918,
++ 0x2a292827, 0x38373635, 0x44433a39, 0x48474645, 0x54534a49, 0x58575655,
++ 0x64635a59, 0x68676665, 0x74736a69, 0x78777675, 0x83827a79, 0x87868584,
++ 0x928a8988, 0x96959493, 0x9a999897, 0xa5a4a3a2, 0xa9a8a7a6, 0xb4b3b2aa,
++ 0xb8b7b6b5, 0xc3c2bab9, 0xc7c6c5c4, 0xd2cac9c8, 0xd6d5d4d3, 0xdad9d8d7,
++ 0xe5e4e3e2, 0xe9e8e7e6, 0xf4f3f2ea, 0xf8f7f6f5, 0xdafffaf9, 0x01030c00,
++ 0x03110200, 0x003f0011
++};
++
++static const u32 aspeed_video_jpeg_dct[ASPEED_VIDEO_JPEG_NUM_QUALITIES]
++ [ASPEED_VIDEO_JPEG_DCT_SIZE] = {
++ { 0x0d140043, 0x0c0f110f, 0x11101114, 0x17141516, 0x1e20321e,
++ 0x3d1e1b1b, 0x32242e2b, 0x4b4c3f48, 0x44463f47, 0x61735a50,
++ 0x566c5550, 0x88644644, 0x7a766c65, 0x4d808280, 0x8c978d60,
++ 0x7e73967d, 0xdbff7b80, 0x1f014300, 0x272d2121, 0x3030582d,
++ 0x697bb958, 0xb8b9b97b, 0xb9b8a6a6, 0xb9b9b9b9, 0xb9b9b9b9,
++ 0xb9b9b9b9, 0xb9b9b9b9, 0xb9b9b9b9, 0xb9b9b9b9, 0xb9b9b9b9,
++ 0xb9b9b9b9, 0xb9b9b9b9, 0xb9b9b9b9, 0xffb9b9b9 },
++ { 0x0c110043, 0x0a0d0f0d, 0x0f0e0f11, 0x14111213, 0x1a1c2b1a,
++ 0x351a1818, 0x2b1f2826, 0x4142373f, 0x3c3d373e, 0x55644e46,
++ 0x4b5f4a46, 0x77573d3c, 0x6b675f58, 0x43707170, 0x7a847b54,
++ 0x6e64836d, 0xdbff6c70, 0x1b014300, 0x22271d1d, 0x2a2a4c27,
++ 0x5b6ba04c, 0xa0a0a06b, 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0,
++ 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0,
++ 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, 0xffa0a0a0 },
++ { 0x090e0043, 0x090a0c0a, 0x0c0b0c0e, 0x110e0f10, 0x15172415,
++ 0x2c151313, 0x241a211f, 0x36372e34, 0x31322e33, 0x4653413a,
++ 0x3e4e3d3a, 0x62483231, 0x58564e49, 0x385d5e5d, 0x656d6645,
++ 0x5b536c5a, 0xdbff595d, 0x16014300, 0x1c201818, 0x22223f20,
++ 0x4b58853f, 0x85858558, 0x85858585, 0x85858585, 0x85858585,
++ 0x85858585, 0x85858585, 0x85858585, 0x85858585, 0x85858585,
++ 0x85858585, 0x85858585, 0x85858585, 0xff858585 },
++ { 0x070b0043, 0x07080a08, 0x0a090a0b, 0x0d0b0c0c, 0x11121c11,
++ 0x23110f0f, 0x1c141a19, 0x2b2b2429, 0x27282428, 0x3842332e,
++ 0x313e302e, 0x4e392827, 0x46443e3a, 0x2c4a4a4a, 0x50565137,
++ 0x48425647, 0xdbff474a, 0x12014300, 0x161a1313, 0x1c1c331a,
++ 0x3d486c33, 0x6c6c6c48, 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c,
++ 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c,
++ 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c, 0xff6c6c6c },
++ { 0x06090043, 0x05060706, 0x07070709, 0x0a09090a, 0x0d0e160d,
++ 0x1b0d0c0c, 0x16101413, 0x21221c20, 0x1e1f1c20, 0x2b332824,
++ 0x26302624, 0x3d2d1f1e, 0x3735302d, 0x22393a39, 0x3f443f2b,
++ 0x38334338, 0xdbff3739, 0x0d014300, 0x11130e0e, 0x15152613,
++ 0x2d355026, 0x50505035, 0x50505050, 0x50505050, 0x50505050,
++ 0x50505050, 0x50505050, 0x50505050, 0x50505050, 0x50505050,
++ 0x50505050, 0x50505050, 0x50505050, 0xff505050 },
++ { 0x04060043, 0x03040504, 0x05040506, 0x07060606, 0x09090f09,
++ 0x12090808, 0x0f0a0d0d, 0x16161315, 0x14151315, 0x1d221b18,
++ 0x19201918, 0x281e1514, 0x2423201e, 0x17262726, 0x2a2d2a1c,
++ 0x25222d25, 0xdbff2526, 0x09014300, 0x0b0d0a0a, 0x0e0e1a0d,
++ 0x1f25371a, 0x37373725, 0x37373737, 0x37373737, 0x37373737,
++ 0x37373737, 0x37373737, 0x37373737, 0x37373737, 0x37373737,
++ 0x37373737, 0x37373737, 0x37373737, 0xff373737 },
++ { 0x02030043, 0x01020202, 0x02020203, 0x03030303, 0x04040704,
++ 0x09040404, 0x07050606, 0x0b0b090a, 0x0a0a090a, 0x0e110d0c,
++ 0x0c100c0c, 0x140f0a0a, 0x1211100f, 0x0b131313, 0x1516150e,
++ 0x12111612, 0xdbff1213, 0x04014300, 0x05060505, 0x07070d06,
++ 0x0f121b0d, 0x1b1b1b12, 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b,
++ 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b,
++ 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b, 0xff1b1b1b },
++ { 0x01020043, 0x01010101, 0x01010102, 0x02020202, 0x03030503,
++ 0x06030202, 0x05030404, 0x07070607, 0x06070607, 0x090b0908,
++ 0x080a0808, 0x0d0a0706, 0x0c0b0a0a, 0x070c0d0c, 0x0e0f0e09,
++ 0x0c0b0f0c, 0xdbff0c0c, 0x03014300, 0x03040303, 0x04040804,
++ 0x0a0c1208, 0x1212120c, 0x12121212, 0x12121212, 0x12121212,
++ 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212,
++ 0x12121212, 0x12121212, 0x12121212, 0xff121212 },
++ { 0x01020043, 0x01010101, 0x01010102, 0x02020202, 0x03030503,
++ 0x06030202, 0x05030404, 0x07070607, 0x06070607, 0x090b0908,
++ 0x080a0808, 0x0d0a0706, 0x0c0b0a0a, 0x070c0d0c, 0x0e0f0e09,
++ 0x0c0b0f0c, 0xdbff0c0c, 0x02014300, 0x03030202, 0x04040703,
++ 0x080a0f07, 0x0f0f0f0a, 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f,
++ 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f,
++ 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0xff0f0f0f },
++ { 0x01010043, 0x01010101, 0x01010101, 0x01010101, 0x02020302,
++ 0x04020202, 0x03020303, 0x05050405, 0x05050405, 0x07080606,
++ 0x06080606, 0x0a070505, 0x09080807, 0x05090909, 0x0a0b0a07,
++ 0x09080b09, 0xdbff0909, 0x02014300, 0x02030202, 0x03030503,
++ 0x07080c05, 0x0c0c0c08, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c,
++ 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c,
++ 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0xff0c0c0c },
++ { 0x01010043, 0x01010101, 0x01010101, 0x01010101, 0x01010201,
++ 0x03010101, 0x02010202, 0x03030303, 0x03030303, 0x04050404,
++ 0x04050404, 0x06050303, 0x06050505, 0x03060606, 0x07070704,
++ 0x06050706, 0xdbff0606, 0x01014300, 0x01020101, 0x02020402,
++ 0x05060904, 0x09090906, 0x09090909, 0x09090909, 0x09090909,
++ 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909,
++ 0x09090909, 0x09090909, 0x09090909, 0xff090909 },
++ { 0x01010043, 0x01010101, 0x01010101, 0x01010101, 0x01010101,
++ 0x01010101, 0x01010101, 0x01010101, 0x01010101, 0x02020202,
++ 0x02020202, 0x03020101, 0x03020202, 0x01030303, 0x03030302,
++ 0x03020303, 0xdbff0403, 0x01014300, 0x01010101, 0x01010201,
++ 0x03040602, 0x06060604, 0x06060606, 0x06060606, 0x06060606,
++ 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606,
++ 0x06060606, 0x06060606, 0x06060606, 0xff060606 }
++};
++
++static const struct v4l2_dv_timings_cap aspeed_video_timings_cap = {
++ .type = V4L2_DV_BT_656_1120,
++ .bt = {
++ .min_width = MIN_WIDTH,
++ .max_width = MAX_WIDTH,
++ .min_height = MIN_HEIGHT,
++ .max_height = MAX_HEIGHT,
++ .min_pixelclock = 6574080, /* 640 x 480 x 24Hz */
++ .max_pixelclock = 138240000, /* 1920 x 1200 x 60Hz */
++ .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
++ V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF,
++ .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE |
++ V4L2_DV_BT_CAP_REDUCED_BLANKING |
++ V4L2_DV_BT_CAP_CUSTOM,
++ },
++};
++
++static void aspeed_video_init_jpeg_table(u32 *table, bool yuv420)
++{
++ int i;
++ unsigned int base;
++
++ for (i = 0; i < ASPEED_VIDEO_JPEG_NUM_QUALITIES; i++) {
++ base = 256 * i; /* AST HW requires this header spacing */
++ memcpy(&table[base], aspeed_video_jpeg_header,
++ sizeof(aspeed_video_jpeg_header));
++
++ base += ASPEED_VIDEO_JPEG_HEADER_SIZE;
++ memcpy(&table[base], aspeed_video_jpeg_dct[i],
++ sizeof(aspeed_video_jpeg_dct[i]));
++
++ base += ASPEED_VIDEO_JPEG_DCT_SIZE;
++ memcpy(&table[base], aspeed_video_jpeg_quant,
++ sizeof(aspeed_video_jpeg_quant));
++
++ if (yuv420)
++ table[base + 2] = 0x00220103;
++ }
++}
++
++static void aspeed_video_update(struct aspeed_video *video, u32 reg, u32 clear,
++ u32 bits)
++{
++ u32 t = readl(video->base + reg);
++ u32 before = t;
++
++ t &= ~clear;
++ t |= bits;
++ writel(t, video->base + reg);
++ dev_dbg(video->dev, "update %03x[%08x -> %08x]\n", reg, before,
++ readl(video->base + reg));
++}
++
++static u32 aspeed_video_read(struct aspeed_video *video, u32 reg)
++{
++ u32 t = readl(video->base + reg);
++
++ dev_dbg(video->dev, "read %03x[%08x]\n", reg, t);
++ return t;
++}
++
++static void aspeed_video_write(struct aspeed_video *video, u32 reg, u32 val)
++{
++ writel(val, video->base + reg);
++ dev_dbg(video->dev, "write %03x[%08x]\n", reg,
++ readl(video->base + reg));
++}
++
++static int aspeed_video_start_frame(struct aspeed_video *video)
++{
++ dma_addr_t addr;
++ unsigned long flags;
++ struct aspeed_video_buffer *buf;
++ u32 seq_ctrl = aspeed_video_read(video, VE_SEQ_CTRL);
++
++ if (video->v4l2_input_status) {
++ dev_dbg(video->dev, "No signal; don't start frame\n");
++ return 0;
++ }
++
++ if (!(seq_ctrl & VE_SEQ_CTRL_COMP_BUSY) ||
++ !(seq_ctrl & VE_SEQ_CTRL_CAP_BUSY)) {
++ dev_err(video->dev, "Engine busy; don't start frame\n");
++ return -EBUSY;
++ }
++
++ spin_lock_irqsave(&video->lock, flags);
++ buf = list_first_entry_or_null(&video->buffers,
++ struct aspeed_video_buffer, link);
++ if (!buf) {
++ spin_unlock_irqrestore(&video->lock, flags);
++ dev_dbg(video->dev, "No buffers; don't start frame\n");
++ return -EPROTO;
++ }
++
++ set_bit(VIDEO_FRAME_INPRG, &video->flags);
++ addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
++ spin_unlock_irqrestore(&video->lock, flags);
++
++ aspeed_video_write(video, VE_COMP_PROC_OFFSET, 0);
++ aspeed_video_write(video, VE_COMP_OFFSET, 0);
++ aspeed_video_write(video, VE_COMP_ADDR, addr);
++
++ aspeed_video_update(video, VE_INTERRUPT_CTRL, 0,
++ VE_INTERRUPT_COMP_COMPLETE |
++ VE_INTERRUPT_CAPTURE_COMPLETE);
++
++ aspeed_video_update(video, VE_SEQ_CTRL, 0,
++ VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP);
++
++ return 0;
++}
++
++static void aspeed_video_enable_mode_detect(struct aspeed_video *video)
++{
++ /* Enable mode detect interrupts */
++ aspeed_video_update(video, VE_INTERRUPT_CTRL, 0,
++ VE_INTERRUPT_MODE_DETECT);
++
++ /* Trigger mode detect */
++ aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_TRIG_MODE_DET);
++}
++
++static void aspeed_video_reset(struct aspeed_video *video)
++{
++ /* Reset the engine */
++ reset_control_assert(video->rst);
++
++ /* Don't usleep here; function may be called in interrupt context */
++ udelay(100);
++ reset_control_deassert(video->rst);
++}
++
++static void aspeed_video_off(struct aspeed_video *video)
++{
++ aspeed_video_reset(video);
++
++ /* Turn off the relevant clocks */
++ clk_disable_unprepare(video->vclk);
++ clk_disable_unprepare(video->eclk);
++}
++
++static void aspeed_video_on(struct aspeed_video *video)
++{
++ /* Turn on the relevant clocks */
++ clk_prepare_enable(video->eclk);
++ clk_prepare_enable(video->vclk);
++
++ aspeed_video_reset(video);
++}
++
++static void aspeed_video_bufs_done(struct aspeed_video *video,
++ enum vb2_buffer_state state)
++{
++ unsigned long flags;
++ struct aspeed_video_buffer *buf;
++
++ spin_lock_irqsave(&video->lock, flags);
++ list_for_each_entry(buf, &video->buffers, link)
++ vb2_buffer_done(&buf->vb.vb2_buf, state);
++ INIT_LIST_HEAD(&video->buffers);
++ spin_unlock_irqrestore(&video->lock, flags);
++}
++
++static void aspeed_video_irq_res_change(struct aspeed_video *video)
++{
++ dev_dbg(video->dev, "Resolution changed; resetting\n");
++
++ set_bit(VIDEO_RES_CHANGE, &video->flags);
++ clear_bit(VIDEO_FRAME_INPRG, &video->flags);
++
++ aspeed_video_off(video);
++ aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR);
++
++ schedule_delayed_work(&video->res_work, RESOLUTION_CHANGE_DELAY);
++}
++
++static irqreturn_t aspeed_video_irq(int irq, void *arg)
++{
++ struct aspeed_video *video = arg;
++ u32 sts = aspeed_video_read(video, VE_INTERRUPT_STATUS);
++
++ /*
++ * Resolution changed or signal was lost; reset the engine and
++ * re-initialize
++ */
++ if (sts & VE_INTERRUPT_MODE_DETECT_WD) {
++ aspeed_video_irq_res_change(video);
++ return IRQ_HANDLED;
++ }
++
++ if (sts & VE_INTERRUPT_MODE_DETECT) {
++ if (test_bit(VIDEO_RES_DETECT, &video->flags)) {
++ aspeed_video_update(video, VE_INTERRUPT_CTRL,
++ VE_INTERRUPT_MODE_DETECT, 0);
++ aspeed_video_write(video, VE_INTERRUPT_STATUS,
++ VE_INTERRUPT_MODE_DETECT);
++
++ set_bit(VIDEO_MODE_DETECT_DONE, &video->flags);
++ wake_up_interruptible_all(&video->wait);
++ } else {
++ /*
++ * Signal acquired while NOT doing resolution
++ * detection; reset the engine and re-initialize
++ */
++ aspeed_video_irq_res_change(video);
++ return IRQ_HANDLED;
++ }
++ }
++
++ if ((sts & VE_INTERRUPT_COMP_COMPLETE) &&
++ (sts & VE_INTERRUPT_CAPTURE_COMPLETE)) {
++ struct aspeed_video_buffer *buf;
++ u32 frame_size = aspeed_video_read(video,
++ VE_OFFSET_COMP_STREAM);
++
++ spin_lock(&video->lock);
++ clear_bit(VIDEO_FRAME_INPRG, &video->flags);
++ buf = list_first_entry_or_null(&video->buffers,
++ struct aspeed_video_buffer,
++ link);
++ if (buf) {
++ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, frame_size);
++
++ if (!list_is_last(&buf->link, &video->buffers)) {
++ buf->vb.vb2_buf.timestamp = ktime_get_ns();
++ buf->vb.sequence = video->sequence++;
++ buf->vb.field = V4L2_FIELD_NONE;
++ vb2_buffer_done(&buf->vb.vb2_buf,
++ VB2_BUF_STATE_DONE);
++ list_del(&buf->link);
++ }
++ }
++ spin_unlock(&video->lock);
++
++ aspeed_video_update(video, VE_SEQ_CTRL,
++ VE_SEQ_CTRL_TRIG_CAPTURE |
++ VE_SEQ_CTRL_FORCE_IDLE |
++ VE_SEQ_CTRL_TRIG_COMP, 0);
++ aspeed_video_update(video, VE_INTERRUPT_CTRL,
++ VE_INTERRUPT_COMP_COMPLETE |
++ VE_INTERRUPT_CAPTURE_COMPLETE, 0);
++ aspeed_video_write(video, VE_INTERRUPT_STATUS,
++ VE_INTERRUPT_COMP_COMPLETE |
++ VE_INTERRUPT_CAPTURE_COMPLETE);
++
++ if (test_bit(VIDEO_STREAMING, &video->flags) && buf)
++ aspeed_video_start_frame(video);
++ }
++
++ return IRQ_HANDLED;
++}
++
++static void aspeed_video_check_and_set_polarity(struct aspeed_video *video)
++{
++ int i;
++ int hsync_counter = 0;
++ int vsync_counter = 0;
++ u32 sts;
++
++ for (i = 0; i < NUM_POLARITY_CHECKS; ++i) {
++ sts = aspeed_video_read(video, VE_MODE_DETECT_STATUS);
++ if (sts & VE_MODE_DETECT_STATUS_VSYNC)
++ vsync_counter--;
++ else
++ vsync_counter++;
++
++ if (sts & VE_MODE_DETECT_STATUS_HSYNC)
++ hsync_counter--;
++ else
++ hsync_counter++;
++ }
++
++ if (hsync_counter < 0 || vsync_counter < 0) {
++ u32 ctrl;
++
++ if (hsync_counter < 0) {
++ ctrl = VE_CTRL_HSYNC_POL;
++ video->detected_timings.polarities &=
++ ~V4L2_DV_HSYNC_POS_POL;
++ } else {
++ video->detected_timings.polarities |=
++ V4L2_DV_HSYNC_POS_POL;
++ }
++
++ if (vsync_counter < 0) {
++ ctrl = VE_CTRL_VSYNC_POL;
++ video->detected_timings.polarities &=
++ ~V4L2_DV_VSYNC_POS_POL;
++ } else {
++ video->detected_timings.polarities |=
++ V4L2_DV_VSYNC_POS_POL;
++ }
++
++ aspeed_video_update(video, VE_CTRL, 0, ctrl);
++ }
++}
++
++static bool aspeed_video_alloc_buf(struct aspeed_video *video,
++ struct aspeed_video_addr *addr,
++ unsigned int size)
++{
++ addr->virt = dma_alloc_coherent(video->dev, size, &addr->dma,
++ GFP_KERNEL);
++ if (!addr->virt)
++ return false;
++
++ addr->size = size;
++ return true;
++}
++
++static void aspeed_video_free_buf(struct aspeed_video *video,
++ struct aspeed_video_addr *addr)
++{
++ dma_free_coherent(video->dev, addr->size, addr->virt, addr->dma);
++ addr->size = 0;
++ addr->dma = 0ULL;
++ addr->virt = NULL;
++}
++
++/*
++ * Get the minimum HW-supported compression buffer size for the frame size.
++ * Assume worst-case JPEG compression size is 1/8 raw size. This should be
++ * plenty even for maximum quality; any worse and the engine will simply return
++ * incomplete JPEGs.
++ */
++static void aspeed_video_calc_compressed_size(struct aspeed_video *video,
++ unsigned int frame_size)
++{
++ int i, j;
++ u32 compression_buffer_size_reg = 0;
++ unsigned int size;
++ const unsigned int num_compression_packets = 4;
++ const unsigned int compression_packet_size = 1024;
++ const unsigned int max_compressed_size = frame_size / 2; /* 4bpp / 8 */
++
++ video->max_compressed_size = UINT_MAX;
++
++ for (i = 0; i < 6; ++i) {
++ for (j = 0; j < 8; ++j) {
++ size = (num_compression_packets << i) *
++ (compression_packet_size << j);
++ if (size < max_compressed_size)
++ continue;
++
++ if (size < video->max_compressed_size) {
++ compression_buffer_size_reg = (i << 3) | j;
++ video->max_compressed_size = size;
++ }
++ }
++ }
++
++ aspeed_video_write(video, VE_STREAM_BUF_SIZE,
++ compression_buffer_size_reg);
++
++ dev_dbg(video->dev, "Max compressed size: %x\n",
++ video->max_compressed_size);
++}
++
++#define res_check(v) test_and_clear_bit(VIDEO_MODE_DETECT_DONE, &(v)->flags)
++
++static void aspeed_video_get_resolution(struct aspeed_video *video)
++{
++ bool invalid_resolution = true;
++ int rc;
++ int tries = 0;
++ u32 mds;
++ u32 src_lr_edge;
++ u32 src_tb_edge;
++ u32 sync;
++ struct v4l2_bt_timings *det = &video->detected_timings;
++
++ det->width = MIN_WIDTH;
++ det->height = MIN_HEIGHT;
++ video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
++
++ /*
++ * Since we need max buffer size for detection, free the second source
++ * buffer first.
++ */
++ if (video->srcs[1].size)
++ aspeed_video_free_buf(video, &video->srcs[1]);
++
++ if (video->srcs[0].size < VE_MAX_SRC_BUFFER_SIZE) {
++ if (video->srcs[0].size)
++ aspeed_video_free_buf(video, &video->srcs[0]);
++
++ if (!aspeed_video_alloc_buf(video, &video->srcs[0],
++ VE_MAX_SRC_BUFFER_SIZE)) {
++ dev_err(video->dev,
++ "Failed to allocate source buffers\n");
++ return;
++ }
++ }
++
++ aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma);
++
++ do {
++ if (tries) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (schedule_timeout(INVALID_RESOLUTION_DELAY))
++ return;
++ }
++
++ set_bit(VIDEO_RES_DETECT, &video->flags);
++ aspeed_video_enable_mode_detect(video);
++
++ rc = wait_event_interruptible_timeout(video->wait,
++ res_check(video),
++ MODE_DETECT_TIMEOUT);
++ if (!rc) {
++ dev_err(video->dev, "Timed out; first mode detect\n");
++ clear_bit(VIDEO_RES_DETECT, &video->flags);
++ return;
++ }
++
++ /* Disable mode detect in order to re-trigger */
++ aspeed_video_update(video, VE_SEQ_CTRL,
++ VE_SEQ_CTRL_TRIG_MODE_DET, 0);
++
++ aspeed_video_check_and_set_polarity(video);
++
++ aspeed_video_enable_mode_detect(video);
++
++ rc = wait_event_interruptible_timeout(video->wait,
++ res_check(video),
++ MODE_DETECT_TIMEOUT);
++ clear_bit(VIDEO_RES_DETECT, &video->flags);
++ if (!rc) {
++ dev_err(video->dev, "Timed out; second mode detect\n");
++ return;
++ }
++
++ src_lr_edge = aspeed_video_read(video, VE_SRC_LR_EDGE_DET);
++ src_tb_edge = aspeed_video_read(video, VE_SRC_TB_EDGE_DET);
++ mds = aspeed_video_read(video, VE_MODE_DETECT_STATUS);
++ sync = aspeed_video_read(video, VE_SYNC_STATUS);
++
++ video->frame_bottom = (src_tb_edge & VE_SRC_TB_EDGE_DET_BOT) >>
++ VE_SRC_TB_EDGE_DET_BOT_SHF;
++ video->frame_top = src_tb_edge & VE_SRC_TB_EDGE_DET_TOP;
++ det->vfrontporch = video->frame_top;
++ det->vbackporch = ((mds & VE_MODE_DETECT_V_LINES) >>
++ VE_MODE_DETECT_V_LINES_SHF) - video->frame_bottom;
++ det->vsync = (sync & VE_SYNC_STATUS_VSYNC) >>
++ VE_SYNC_STATUS_VSYNC_SHF;
++ if (video->frame_top > video->frame_bottom)
++ continue;
++
++ video->frame_right = (src_lr_edge & VE_SRC_LR_EDGE_DET_RT) >>
++ VE_SRC_LR_EDGE_DET_RT_SHF;
++ video->frame_left = src_lr_edge & VE_SRC_LR_EDGE_DET_LEFT;
++ det->hfrontporch = video->frame_left;
++ det->hbackporch = (mds & VE_MODE_DETECT_H_PIXELS) -
++ video->frame_right;
++ det->hsync = sync & VE_SYNC_STATUS_HSYNC;
++ if (video->frame_left > video->frame_right)
++ continue;
++
++ invalid_resolution = false;
++ } while (invalid_resolution && (tries++ < INVALID_RESOLUTION_RETRIES));
++
++ if (invalid_resolution) {
++ dev_err(video->dev, "Invalid resolution detected\n");
++ return;
++ }
++
++ det->height = (video->frame_bottom - video->frame_top) + 1;
++ det->width = (video->frame_right - video->frame_left) + 1;
++ video->v4l2_input_status = 0;
++
++ /*
++ * Enable mode-detect watchdog, resolution-change watchdog and
++ * automatic compression after frame capture.
++ */
++ aspeed_video_update(video, VE_INTERRUPT_CTRL, 0,
++ VE_INTERRUPT_MODE_DETECT_WD);
++ aspeed_video_update(video, VE_SEQ_CTRL, 0,
++ VE_SEQ_CTRL_AUTO_COMP | VE_SEQ_CTRL_EN_WATCHDOG);
++
++ dev_dbg(video->dev, "Got resolution: %dx%d\n", det->width,
++ det->height);
++}
++
++static void aspeed_video_set_resolution(struct aspeed_video *video)
++{
++ struct v4l2_bt_timings *act = &video->active_timings;
++ unsigned int size = act->width * act->height;
++
++ aspeed_video_calc_compressed_size(video, size);
++
++ /* Don't use direct mode below 1024 x 768 (irqs don't fire) */
++ if (size < DIRECT_FETCH_THRESHOLD) {
++ aspeed_video_write(video, VE_TGS_0,
++ FIELD_PREP(VE_TGS_FIRST,
++ video->frame_left - 1) |
++ FIELD_PREP(VE_TGS_LAST,
++ video->frame_right));
++ aspeed_video_write(video, VE_TGS_1,
++ FIELD_PREP(VE_TGS_FIRST, video->frame_top) |
++ FIELD_PREP(VE_TGS_LAST,
++ video->frame_bottom + 1));
++ aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_INT_DE);
++ } else {
++ aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_DIRECT_FETCH);
++ }
++
++ /* Set capture/compression frame sizes */
++ aspeed_video_write(video, VE_CAP_WINDOW,
++ act->width << 16 | act->height);
++ aspeed_video_write(video, VE_COMP_WINDOW,
++ act->width << 16 | act->height);
++ aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4);
++
++ size *= 4;
++
++ if (size == video->srcs[0].size / 2) {
++ aspeed_video_write(video, VE_SRC1_ADDR,
++ video->srcs[0].dma + size);
++ } else if (size == video->srcs[0].size) {
++ if (!aspeed_video_alloc_buf(video, &video->srcs[1], size))
++ goto err_mem;
++
++ aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma);
++ } else {
++ aspeed_video_free_buf(video, &video->srcs[0]);
++
++ if (!aspeed_video_alloc_buf(video, &video->srcs[0], size))
++ goto err_mem;
++
++ if (!aspeed_video_alloc_buf(video, &video->srcs[1], size))
++ goto err_mem;
++
++ aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma);
++ aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma);
++ }
++
++ return;
++
++err_mem:
++ dev_err(video->dev, "Failed to allocate source buffers\n");
++
++ if (video->srcs[0].size)
++ aspeed_video_free_buf(video, &video->srcs[0]);
++}
++
++static void aspeed_video_init_regs(struct aspeed_video *video)
++{
++ u32 comp_ctrl = VE_COMP_CTRL_RSVD |
++ FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
++ FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10);
++ u32 ctrl = VE_CTRL_AUTO_OR_CURSOR;
++ u32 seq_ctrl = VE_SEQ_CTRL_JPEG_MODE;
++
++ if (video->frame_rate)
++ ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate);
++
++ if (video->yuv420)
++ seq_ctrl |= VE_SEQ_CTRL_YUV420;
++
++ /* Unlock VE registers */
++ aspeed_video_write(video, VE_PROTECTION_KEY, VE_PROTECTION_KEY_UNLOCK);
++
++ /* Disable interrupts */
++ aspeed_video_write(video, VE_INTERRUPT_CTRL, 0);
++ aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff);
++
++ /* Clear the offset */
++ aspeed_video_write(video, VE_COMP_PROC_OFFSET, 0);
++ aspeed_video_write(video, VE_COMP_OFFSET, 0);
++
++ aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma);
++
++ /* Set control registers */
++ aspeed_video_write(video, VE_SEQ_CTRL, seq_ctrl);
++ aspeed_video_write(video, VE_CTRL, ctrl);
++ aspeed_video_write(video, VE_COMP_CTRL, comp_ctrl);
++
++ /* Don't downscale */
++ aspeed_video_write(video, VE_SCALING_FACTOR, 0x10001000);
++ aspeed_video_write(video, VE_SCALING_FILTER0, 0x00200000);
++ aspeed_video_write(video, VE_SCALING_FILTER1, 0x00200000);
++ aspeed_video_write(video, VE_SCALING_FILTER2, 0x00200000);
++ aspeed_video_write(video, VE_SCALING_FILTER3, 0x00200000);
++
++ /* Set mode detection defaults */
++ aspeed_video_write(video, VE_MODE_DETECT, 0x22666500);
++}
++
++static void aspeed_video_start(struct aspeed_video *video)
++{
++ aspeed_video_on(video);
++
++ aspeed_video_init_regs(video);
++
++ /* Resolution set to 640x480 if no signal found */
++ aspeed_video_get_resolution(video);
++
++ /* Set timings since the device is being opened for the first time */
++ video->active_timings = video->detected_timings;
++ aspeed_video_set_resolution(video);
++
++ video->pix_fmt.width = video->active_timings.width;
++ video->pix_fmt.height = video->active_timings.height;
++ video->pix_fmt.sizeimage = video->max_compressed_size;
++}
++
++static void aspeed_video_stop(struct aspeed_video *video)
++{
++ set_bit(VIDEO_STOPPED, &video->flags);
++ cancel_delayed_work_sync(&video->res_work);
++
++ aspeed_video_off(video);
++
++ if (video->srcs[0].size)
++ aspeed_video_free_buf(video, &video->srcs[0]);
++
++ if (video->srcs[1].size)
++ aspeed_video_free_buf(video, &video->srcs[1]);
++
++ video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
++ video->flags = 0;
++}
++
++static int aspeed_video_querycap(struct file *file, void *fh,
++ struct v4l2_capability *cap)
++{
++ strscpy(cap->driver, DEVICE_NAME, sizeof(cap->driver));
++ strscpy(cap->card, "Aspeed Video Engine", sizeof(cap->card));
++ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
++ DEVICE_NAME);
++
++ return 0;
++}
++
++static int aspeed_video_enum_format(struct file *file, void *fh,
++ struct v4l2_fmtdesc *f)
++{
++ if (f->index)
++ return -EINVAL;
++
++ f->pixelformat = V4L2_PIX_FMT_JPEG;
++
++ return 0;
++}
++
++static int aspeed_video_get_format(struct file *file, void *fh,
++ struct v4l2_format *f)
++{
++ struct aspeed_video *video = video_drvdata(file);
++
++ f->fmt.pix = video->pix_fmt;
++
++ return 0;
++}
++
++static int aspeed_video_enum_input(struct file *file, void *fh,
++ struct v4l2_input *inp)
++{
++ struct aspeed_video *video = video_drvdata(file);
++
++ if (inp->index)
++ return -EINVAL;
++
++ strscpy(inp->name, "Host VGA capture", sizeof(inp->name));
++ inp->type = V4L2_INPUT_TYPE_CAMERA;
++ inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
++ inp->status = video->v4l2_input_status;
++
++ return 0;
++}
++
++static int aspeed_video_get_input(struct file *file, void *fh, unsigned int *i)
++{
++ *i = 0;
++
++ return 0;
++}
++
++static int aspeed_video_set_input(struct file *file, void *fh, unsigned int i)
++{
++ if (i)
++ return -EINVAL;
++
++ return 0;
++}
++
++static int aspeed_video_get_parm(struct file *file, void *fh,
++ struct v4l2_streamparm *a)
++{
++ struct aspeed_video *video = video_drvdata(file);
++
++ a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
++ a->parm.capture.readbuffers = 3;
++ a->parm.capture.timeperframe.numerator = 1;
++ if (!video->frame_rate)
++ a->parm.capture.timeperframe.denominator = MAX_FRAME_RATE;
++ else
++ a->parm.capture.timeperframe.denominator = video->frame_rate;
++
++ return 0;
++}
++
++static int aspeed_video_set_parm(struct file *file, void *fh,
++ struct v4l2_streamparm *a)
++{
++ unsigned int frame_rate = 0;
++ struct aspeed_video *video = video_drvdata(file);
++
++ a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
++ a->parm.capture.readbuffers = 3;
++
++ if (a->parm.capture.timeperframe.numerator)
++ frame_rate = a->parm.capture.timeperframe.denominator /
++ a->parm.capture.timeperframe.numerator;
++
++ if (!frame_rate || frame_rate > MAX_FRAME_RATE) {
++ frame_rate = 0;
++ a->parm.capture.timeperframe.denominator = MAX_FRAME_RATE;
++ a->parm.capture.timeperframe.numerator = 1;
++ }
++
++ if (video->frame_rate != frame_rate) {
++ video->frame_rate = frame_rate;
++ aspeed_video_update(video, VE_CTRL, VE_CTRL_FRC,
++ FIELD_PREP(VE_CTRL_FRC, frame_rate));
++ }
++
++ return 0;
++}
++
++static int aspeed_video_enum_framesizes(struct file *file, void *fh,
++ struct v4l2_frmsizeenum *fsize)
++{
++ struct aspeed_video *video = video_drvdata(file);
++
++ if (fsize->index)
++ return -EINVAL;
++
++ if (fsize->pixel_format != V4L2_PIX_FMT_JPEG)
++ return -EINVAL;
++
++ fsize->discrete.width = video->pix_fmt.width;
++ fsize->discrete.height = video->pix_fmt.height;
++ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
++
++ return 0;
++}
++
++static int aspeed_video_enum_frameintervals(struct file *file, void *fh,
++ struct v4l2_frmivalenum *fival)
++{
++ struct aspeed_video *video = video_drvdata(file);
++
++ if (fival->index)
++ return -EINVAL;
++
++ if (fival->width != video->detected_timings.width ||
++ fival->height != video->detected_timings.height)
++ return -EINVAL;
++
++ if (fival->pixel_format != V4L2_PIX_FMT_JPEG)
++ return -EINVAL;
++
++ fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
++
++ fival->stepwise.min.denominator = MAX_FRAME_RATE;
++ fival->stepwise.min.numerator = 1;
++ fival->stepwise.max.denominator = 1;
++ fival->stepwise.max.numerator = 1;
++ fival->stepwise.step = fival->stepwise.max;
++
++ return 0;
++}
++
++static int aspeed_video_set_dv_timings(struct file *file, void *fh,
++ struct v4l2_dv_timings *timings)
++{
++ struct aspeed_video *video = video_drvdata(file);
++
++ if (timings->bt.width == video->active_timings.width &&
++ timings->bt.height == video->active_timings.height)
++ return 0;
++
++ if (vb2_is_busy(&video->queue))
++ return -EBUSY;
++
++ video->active_timings = timings->bt;
++
++ aspeed_video_set_resolution(video);
++
++ video->pix_fmt.width = timings->bt.width;
++ video->pix_fmt.height = timings->bt.height;
++ video->pix_fmt.sizeimage = video->max_compressed_size;
++
++ timings->type = V4L2_DV_BT_656_1120;
++
++ return 0;
++}
++
++static int aspeed_video_get_dv_timings(struct file *file, void *fh,
++ struct v4l2_dv_timings *timings)
++{
++ struct aspeed_video *video = video_drvdata(file);
++
++ timings->type = V4L2_DV_BT_656_1120;
++ timings->bt = video->active_timings;
++
++ return 0;
++}
++
++static int aspeed_video_query_dv_timings(struct file *file, void *fh,
++ struct v4l2_dv_timings *timings)
++{
++ int rc;
++ struct aspeed_video *video = video_drvdata(file);
++
++ /*
++ * This blocks only if the driver is currently in the process of
++ * detecting a new resolution; in the event of no signal or timeout
++ * this function is woken up.
++ */
++ if (file->f_flags & O_NONBLOCK) {
++ if (test_bit(VIDEO_RES_CHANGE, &video->flags))
++ return -EAGAIN;
++ } else {
++ rc = wait_event_interruptible(video->wait,
++ !test_bit(VIDEO_RES_CHANGE,
++ &video->flags));
++ if (rc)
++ return -EINTR;
++ }
++
++ timings->type = V4L2_DV_BT_656_1120;
++ timings->bt = video->detected_timings;
++
++ return video->v4l2_input_status ? -ENOLINK : 0;
++}
++
++static int aspeed_video_enum_dv_timings(struct file *file, void *fh,
++ struct v4l2_enum_dv_timings *timings)
++{
++ return v4l2_enum_dv_timings_cap(timings, &aspeed_video_timings_cap,
++ NULL, NULL);
++}
++
++static int aspeed_video_dv_timings_cap(struct file *file, void *fh,
++ struct v4l2_dv_timings_cap *cap)
++{
++ *cap = aspeed_video_timings_cap;
++
++ return 0;
++}
++
++static int aspeed_video_sub_event(struct v4l2_fh *fh,
++ const struct v4l2_event_subscription *sub)
++{
++ switch (sub->type) {
++ case V4L2_EVENT_SOURCE_CHANGE:
++ return v4l2_src_change_event_subscribe(fh, sub);
++ }
++
++ return v4l2_ctrl_subscribe_event(fh, sub);
++}
++
++static const struct v4l2_ioctl_ops aspeed_video_ioctl_ops = {
++ .vidioc_querycap = aspeed_video_querycap,
++
++ .vidioc_enum_fmt_vid_cap = aspeed_video_enum_format,
++ .vidioc_g_fmt_vid_cap = aspeed_video_get_format,
++ .vidioc_s_fmt_vid_cap = aspeed_video_get_format,
++ .vidioc_try_fmt_vid_cap = aspeed_video_get_format,
++
++ .vidioc_reqbufs = vb2_ioctl_reqbufs,
++ .vidioc_querybuf = vb2_ioctl_querybuf,
++ .vidioc_qbuf = vb2_ioctl_qbuf,
++ .vidioc_expbuf = vb2_ioctl_expbuf,
++ .vidioc_dqbuf = vb2_ioctl_dqbuf,
++ .vidioc_create_bufs = vb2_ioctl_create_bufs,
++ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
++ .vidioc_streamon = vb2_ioctl_streamon,
++ .vidioc_streamoff = vb2_ioctl_streamoff,
++
++ .vidioc_enum_input = aspeed_video_enum_input,
++ .vidioc_g_input = aspeed_video_get_input,
++ .vidioc_s_input = aspeed_video_set_input,
++
++ .vidioc_g_parm = aspeed_video_get_parm,
++ .vidioc_s_parm = aspeed_video_set_parm,
++ .vidioc_enum_framesizes = aspeed_video_enum_framesizes,
++ .vidioc_enum_frameintervals = aspeed_video_enum_frameintervals,
++
++ .vidioc_s_dv_timings = aspeed_video_set_dv_timings,
++ .vidioc_g_dv_timings = aspeed_video_get_dv_timings,
++ .vidioc_query_dv_timings = aspeed_video_query_dv_timings,
++ .vidioc_enum_dv_timings = aspeed_video_enum_dv_timings,
++ .vidioc_dv_timings_cap = aspeed_video_dv_timings_cap,
++
++ .vidioc_subscribe_event = aspeed_video_sub_event,
++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
++};
++
++static void aspeed_video_update_jpeg_quality(struct aspeed_video *video)
++{
++ u32 comp_ctrl = FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
++ FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10);
++
++ aspeed_video_update(video, VE_COMP_CTRL,
++ VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR,
++ comp_ctrl);
++}
++
++static void aspeed_video_update_subsampling(struct aspeed_video *video)
++{
++ if (video->jpeg.virt)
++ aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420);
++
++ if (video->yuv420)
++ aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_YUV420);
++ else
++ aspeed_video_update(video, VE_SEQ_CTRL, VE_SEQ_CTRL_YUV420, 0);
++}
++
++static int aspeed_video_set_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct aspeed_video *video = container_of(ctrl->handler,
++ struct aspeed_video,
++ ctrl_handler);
++
++ switch (ctrl->id) {
++ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
++ video->jpeg_quality = ctrl->val;
++ aspeed_video_update_jpeg_quality(video);
++ break;
++ case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
++ if (ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_420) {
++ video->yuv420 = true;
++ aspeed_video_update_subsampling(video);
++ } else {
++ video->yuv420 = false;
++ aspeed_video_update_subsampling(video);
++ }
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static const struct v4l2_ctrl_ops aspeed_video_ctrl_ops = {
++ .s_ctrl = aspeed_video_set_ctrl,
++};
++
++static void aspeed_video_resolution_work(struct work_struct *work)
++{
++ struct delayed_work *dwork = to_delayed_work(work);
++ struct aspeed_video *video = container_of(dwork, struct aspeed_video,
++ res_work);
++ u32 input_status = video->v4l2_input_status;
++
++ aspeed_video_on(video);
++
++ /* Exit early in case no clients remain */
++ if (test_bit(VIDEO_STOPPED, &video->flags))
++ goto done;
++
++ aspeed_video_init_regs(video);
++
++ aspeed_video_get_resolution(video);
++
++ if (video->detected_timings.width != video->active_timings.width ||
++ video->detected_timings.height != video->active_timings.height ||
++ input_status != video->v4l2_input_status) {
++ static const struct v4l2_event ev = {
++ .type = V4L2_EVENT_SOURCE_CHANGE,
++ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
++ };
++
++ v4l2_event_queue(&video->vdev, &ev);
++ } else if (test_bit(VIDEO_STREAMING, &video->flags)) {
++ /* No resolution change so just restart streaming */
++ aspeed_video_start_frame(video);
++ }
++
++done:
++ clear_bit(VIDEO_RES_CHANGE, &video->flags);
++ wake_up_interruptible_all(&video->wait);
++}
++
++static int aspeed_video_open(struct file *file)
++{
++ int rc;
++ struct aspeed_video *video = video_drvdata(file);
++
++ mutex_lock(&video->video_lock);
++
++ rc = v4l2_fh_open(file);
++ if (rc) {
++ mutex_unlock(&video->video_lock);
++ return rc;
++ }
++
++ if (v4l2_fh_is_singular_file(file))
++ aspeed_video_start(video);
++
++ mutex_unlock(&video->video_lock);
++
++ return 0;
++}
++
++static int aspeed_video_release(struct file *file)
++{
++ int rc;
++ struct aspeed_video *video = video_drvdata(file);
++
++ mutex_lock(&video->video_lock);
++
++ if (v4l2_fh_is_singular_file(file))
++ aspeed_video_stop(video);
++
++ rc = _vb2_fop_release(file, NULL);
++
++ mutex_unlock(&video->video_lock);
++
++ return rc;
++}
++
++static const struct v4l2_file_operations aspeed_video_v4l2_fops = {
++ .owner = THIS_MODULE,
++ .read = vb2_fop_read,
++ .poll = vb2_fop_poll,
++ .unlocked_ioctl = video_ioctl2,
++ .mmap = vb2_fop_mmap,
++ .open = aspeed_video_open,
++ .release = aspeed_video_release,
++};
++
++static int aspeed_video_queue_setup(struct vb2_queue *q,
++ unsigned int *num_buffers,
++ unsigned int *num_planes,
++ unsigned int sizes[],
++ struct device *alloc_devs[])
++{
++ struct aspeed_video *video = vb2_get_drv_priv(q);
++
++ if (*num_planes) {
++ if (sizes[0] < video->max_compressed_size)
++ return -EINVAL;
++
++ return 0;
++ }
++
++ *num_planes = 1;
++ sizes[0] = video->max_compressed_size;
++
++ return 0;
++}
++
++static int aspeed_video_buf_prepare(struct vb2_buffer *vb)
++{
++ struct aspeed_video *video = vb2_get_drv_priv(vb->vb2_queue);
++
++ if (vb2_plane_size(vb, 0) < video->max_compressed_size)
++ return -EINVAL;
++
++ return 0;
++}
++
++static int aspeed_video_start_streaming(struct vb2_queue *q,
++ unsigned int count)
++{
++ int rc;
++ struct aspeed_video *video = vb2_get_drv_priv(q);
++
++ video->sequence = 0;
++
++ rc = aspeed_video_start_frame(video);
++ if (rc) {
++ aspeed_video_bufs_done(video, VB2_BUF_STATE_QUEUED);
++ return rc;
++ }
++
++ set_bit(VIDEO_STREAMING, &video->flags);
++ return 0;
++}
++
++static void aspeed_video_stop_streaming(struct vb2_queue *q)
++{
++ int rc;
++ struct aspeed_video *video = vb2_get_drv_priv(q);
++
++ clear_bit(VIDEO_STREAMING, &video->flags);
++
++ rc = wait_event_timeout(video->wait,
++ !test_bit(VIDEO_FRAME_INPRG, &video->flags),
++ STOP_TIMEOUT);
++ if (!rc) {
++ dev_err(video->dev, "Timed out when stopping streaming\n");
++
++ /*
++ * Need to force stop any DMA and try and get HW into a good
++ * state for future calls to start streaming again.
++ */
++ aspeed_video_reset(video);
++ aspeed_video_init_regs(video);
++
++ aspeed_video_get_resolution(video);
++ }
++
++ aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR);
++}
++
++static void aspeed_video_buf_queue(struct vb2_buffer *vb)
++{
++ bool empty;
++ struct aspeed_video *video = vb2_get_drv_priv(vb->vb2_queue);
++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
++ struct aspeed_video_buffer *avb = to_aspeed_video_buffer(vbuf);
++ unsigned long flags;
++
++ spin_lock_irqsave(&video->lock, flags);
++ empty = list_empty(&video->buffers);
++ list_add_tail(&avb->link, &video->buffers);
++ spin_unlock_irqrestore(&video->lock, flags);
++
++ if (test_bit(VIDEO_STREAMING, &video->flags) &&
++ !test_bit(VIDEO_FRAME_INPRG, &video->flags) && empty)
++ aspeed_video_start_frame(video);
++}
++
++static const struct vb2_ops aspeed_video_vb2_ops = {
++ .queue_setup = aspeed_video_queue_setup,
++ .wait_prepare = vb2_ops_wait_prepare,
++ .wait_finish = vb2_ops_wait_finish,
++ .buf_prepare = aspeed_video_buf_prepare,
++ .start_streaming = aspeed_video_start_streaming,
++ .stop_streaming = aspeed_video_stop_streaming,
++ .buf_queue = aspeed_video_buf_queue,
++};
++
++static int aspeed_video_setup_video(struct aspeed_video *video)
++{
++ const u64 mask = ~(BIT(V4L2_JPEG_CHROMA_SUBSAMPLING_444) |
++ BIT(V4L2_JPEG_CHROMA_SUBSAMPLING_420));
++ struct v4l2_device *v4l2_dev = &video->v4l2_dev;
++ struct vb2_queue *vbq = &video->queue;
++ struct video_device *vdev = &video->vdev;
++ int rc;
++
++ video->pix_fmt.pixelformat = V4L2_PIX_FMT_JPEG;
++ video->pix_fmt.field = V4L2_FIELD_NONE;
++ video->pix_fmt.colorspace = V4L2_COLORSPACE_SRGB;
++ video->pix_fmt.quantization = V4L2_QUANTIZATION_FULL_RANGE;
++ video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
++
++ rc = v4l2_device_register(video->dev, v4l2_dev);
++ if (rc) {
++ dev_err(video->dev, "Failed to register v4l2 device\n");
++ return rc;
++ }
++
++ v4l2_ctrl_handler_init(&video->ctrl_handler, 2);
++ v4l2_ctrl_new_std(&video->ctrl_handler, &aspeed_video_ctrl_ops,
++ V4L2_CID_JPEG_COMPRESSION_QUALITY, 0,
++ ASPEED_VIDEO_JPEG_NUM_QUALITIES - 1, 1, 0);
++ v4l2_ctrl_new_std_menu(&video->ctrl_handler, &aspeed_video_ctrl_ops,
++ V4L2_CID_JPEG_CHROMA_SUBSAMPLING,
++ V4L2_JPEG_CHROMA_SUBSAMPLING_420, mask,
++ V4L2_JPEG_CHROMA_SUBSAMPLING_444);
++
++ if (video->ctrl_handler.error) {
++ v4l2_ctrl_handler_free(&video->ctrl_handler);
++ v4l2_device_unregister(v4l2_dev);
++
++ dev_err(video->dev, "Failed to init controls: %d\n",
++ video->ctrl_handler.error);
++ return rc;
++ }
++
++ v4l2_dev->ctrl_handler = &video->ctrl_handler;
++
++ vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ vbq->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
++ vbq->dev = v4l2_dev->dev;
++ vbq->lock = &video->video_lock;
++ vbq->ops = &aspeed_video_vb2_ops;
++ vbq->mem_ops = &vb2_dma_contig_memops;
++ vbq->drv_priv = video;
++ vbq->buf_struct_size = sizeof(struct aspeed_video_buffer);
++ vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
++ vbq->min_buffers_needed = 3;
++
++ rc = vb2_queue_init(vbq);
++ if (rc) {
++ v4l2_ctrl_handler_free(&video->ctrl_handler);
++ v4l2_device_unregister(v4l2_dev);
++
++ dev_err(video->dev, "Failed to init vb2 queue\n");
++ return rc;
++ }
++
++ vdev->queue = vbq;
++ vdev->fops = &aspeed_video_v4l2_fops;
++ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
++ V4L2_CAP_STREAMING;
++ vdev->v4l2_dev = v4l2_dev;
++ strscpy(vdev->name, DEVICE_NAME, sizeof(vdev->name));
++ vdev->vfl_type = VFL_TYPE_GRABBER;
++ vdev->vfl_dir = VFL_DIR_RX;
++ vdev->release = video_device_release_empty;
++ vdev->ioctl_ops = &aspeed_video_ioctl_ops;
++ vdev->lock = &video->video_lock;
++
++ video_set_drvdata(vdev, video);
++ rc = video_register_device(vdev, VFL_TYPE_GRABBER, 0);
++ if (rc) {
++ vb2_queue_release(vbq);
++ v4l2_ctrl_handler_free(&video->ctrl_handler);
++ v4l2_device_unregister(v4l2_dev);
++
++ dev_err(video->dev, "Failed to register video device\n");
++ return rc;
++ }
++
++ return 0;
++}
++
++static int aspeed_video_init(struct aspeed_video *video)
++{
++ int irq;
++ int rc;
++ struct device *dev = video->dev;
++
++ irq = irq_of_parse_and_map(dev->of_node, 0);
++ if (!irq) {
++ dev_err(dev, "Unable to find IRQ\n");
++ return -ENODEV;
++ }
++
++ rc = devm_request_irq(dev, irq, aspeed_video_irq, IRQF_SHARED,
++ DEVICE_NAME, video);
++ if (rc < 0) {
++ dev_err(dev, "Unable to request IRQ %d\n", irq);
++ return rc;
++ }
++
++ video->eclk = devm_clk_get(dev, "eclk");
++ if (IS_ERR(video->eclk)) {
++ dev_err(dev, "Unable to get ECLK\n");
++ return PTR_ERR(video->eclk);
++ }
++
++ video->vclk = devm_clk_get(dev, "vclk");
++ if (IS_ERR(video->vclk)) {
++ dev_err(dev, "Unable to get VCLK\n");
++ return PTR_ERR(video->vclk);
++ }
++
++ video->rst = devm_reset_control_get_exclusive(dev, NULL);
++ if (IS_ERR(video->rst)) {
++ dev_err(dev, "Unable to get VE reset\n");
++ return PTR_ERR(video->rst);
++ }
++
++ rc = of_reserved_mem_device_init(dev);
++ if (rc) {
++ dev_err(dev, "Unable to reserve memory\n");
++ return rc;
++ }
++
++ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
++ if (rc) {
++ dev_err(dev, "Failed to set DMA mask\n");
++ of_reserved_mem_device_release(dev);
++ return rc;
++ }
++
++ if (!aspeed_video_alloc_buf(video, &video->jpeg,
++ VE_JPEG_HEADER_SIZE)) {
++ dev_err(dev, "Failed to allocate DMA for JPEG header\n");
++ of_reserved_mem_device_release(dev);
++ return rc;
++ }
++
++ aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420);
++
++ return 0;
++}
++
++static int aspeed_video_probe(struct platform_device *pdev)
++{
++ int rc;
++ struct resource *res;
++ struct aspeed_video *video = kzalloc(sizeof(*video), GFP_KERNEL);
++
++ if (!video)
++ return -ENOMEM;
++
++ video->frame_rate = 30;
++ video->dev = &pdev->dev;
++ spin_lock_init(&video->lock);
++ mutex_init(&video->video_lock);
++ init_waitqueue_head(&video->wait);
++ INIT_DELAYED_WORK(&video->res_work, aspeed_video_resolution_work);
++ INIT_LIST_HEAD(&video->buffers);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++ video->base = devm_ioremap_resource(video->dev, res);
++
++ if (IS_ERR(video->base))
++ return PTR_ERR(video->base);
++
++ rc = aspeed_video_init(video);
++ if (rc)
++ return rc;
++
++ rc = aspeed_video_setup_video(video);
++ if (rc)
++ return rc;
++
++ return 0;
++}
++
++static int aspeed_video_remove(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
++ struct aspeed_video *video = to_aspeed_video(v4l2_dev);
++
++ video_unregister_device(&video->vdev);
++
++ vb2_queue_release(&video->queue);
++
++ v4l2_ctrl_handler_free(&video->ctrl_handler);
++
++ v4l2_device_unregister(v4l2_dev);
++
++ dma_free_coherent(video->dev, VE_JPEG_HEADER_SIZE, video->jpeg.virt,
++ video->jpeg.dma);
++
++ of_reserved_mem_device_release(dev);
++
++ return 0;
++}
++
++static const struct of_device_id aspeed_video_of_match[] = {
++ { .compatible = "aspeed,ast2400-video-engine" },
++ { .compatible = "aspeed,ast2500-video-engine" },
++ {}
++};
++MODULE_DEVICE_TABLE(of, aspeed_video_of_match);
++
++static struct platform_driver aspeed_video_driver = {
++ .driver = {
++ .name = DEVICE_NAME,
++ .of_match_table = aspeed_video_of_match,
++ },
++ .probe = aspeed_video_probe,
++ .remove = aspeed_video_remove,
++};
++
++module_platform_driver(aspeed_video_driver);
++
++MODULE_DESCRIPTION("ASPEED Video Engine Driver");
++MODULE_AUTHOR("Eddie James");
++MODULE_LICENSE("GPL v2");
+diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h
+index 335879505a72..0b0f3a0ebe9b 100644
+--- a/include/dt-bindings/clock/aspeed-clock.h
++++ b/include/dt-bindings/clock/aspeed-clock.h
+@@ -52,5 +52,6 @@
+ #define ASPEED_RESET_I2C 7
+ #define ASPEED_RESET_AHB 8
+ #define ASPEED_RESET_CRT1 9
++#define ASPEED_RESET_VIDEO 10
+
+ #endif
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch
new file mode 100644
index 000000000..7400e2848
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch
@@ -0,0 +1,702 @@
+From a771e5448ed259f768434d498daf8d8b292713de Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Mon, 11 Feb 2019 17:02:35 -0800
+Subject: [PATCH] Add Aspeed PWM driver which uses FTTMR010 timer IP
+
+This commit adds Aspeed PWM driver which uses timer pulse output
+feature in Aspeed SoCs. The timer IP is derived from Faraday
+Technologies FTTMR010 IP but has some customized register
+structure changes only for Aspeed SoCs.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g5.dtsi | 2 +-
+ drivers/clocksource/timer-fttmr010.c | 25 ++
+ drivers/input/misc/pwm-beeper.c | 8 +-
+ drivers/pwm/Kconfig | 9 +
+ drivers/pwm/Makefile | 1 +
+ drivers/pwm/pwm-fttmr010.c | 465 +++++++++++++++++++++++++++++++++++
+ include/clocksource/timer-fttmr010.h | 17 ++
+ 7 files changed, 522 insertions(+), 5 deletions(-)
+ create mode 100644 drivers/pwm/pwm-fttmr010.c
+ create mode 100644 include/clocksource/timer-fttmr010.h
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index 6686a13a5354..ccf2845cd788 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -301,7 +301,7 @@
+
+ timer: timer@1e782000 {
+ /* This timer is a Faraday FTTMR010 derivative */
+- compatible = "aspeed,ast2400-timer";
++ compatible = "aspeed,ast2500-timer";
+ reg = <0x1e782000 0x90>;
+ interrupts = <16 17 18 35 36 37 38 39>;
+ clocks = <&syscon ASPEED_CLK_APB>;
+diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c
+index cf93f6419b51..8226ccf5cc2c 100644
+--- a/drivers/clocksource/timer-fttmr010.c
++++ b/drivers/clocksource/timer-fttmr010.c
+@@ -20,6 +20,8 @@
+ #include <linux/bitops.h>
+ #include <linux/delay.h>
+
++#include <clocksource/timer-fttmr010.h>
++
+ /*
+ * Register definitions for the timers
+ */
+@@ -77,6 +79,9 @@
+ #define TIMER_3_INT_OVERFLOW BIT(8)
+ #define TIMER_INT_ALL_MASK 0x1ff
+
++DEFINE_SPINLOCK(timer_fttmr010_lock);
++EXPORT_SYMBOL(timer_fttmr010_lock);
++
+ struct fttmr010 {
+ void __iomem *base;
+ unsigned int tick_rate;
+@@ -123,8 +128,11 @@ static int fttmr010_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+ {
+ struct fttmr010 *fttmr010 = to_fttmr010(evt);
++ unsigned long flags;
+ u32 cr;
+
++ spin_lock_irqsave(&timer_fttmr010_lock, flags);
++
+ /* Stop */
+ cr = readl(fttmr010->base + TIMER_CR);
+ cr &= ~fttmr010->t1_enable_val;
+@@ -147,27 +155,37 @@ static int fttmr010_timer_set_next_event(unsigned long cycles,
+ cr |= fttmr010->t1_enable_val;
+ writel(cr, fttmr010->base + TIMER_CR);
+
++ spin_unlock_irqrestore(&timer_fttmr010_lock, flags);
++
+ return 0;
+ }
+
+ static int fttmr010_timer_shutdown(struct clock_event_device *evt)
+ {
+ struct fttmr010 *fttmr010 = to_fttmr010(evt);
++ unsigned long flags;
+ u32 cr;
+
++ spin_lock_irqsave(&timer_fttmr010_lock, flags);
++
+ /* Stop */
+ cr = readl(fttmr010->base + TIMER_CR);
+ cr &= ~fttmr010->t1_enable_val;
+ writel(cr, fttmr010->base + TIMER_CR);
+
++ spin_unlock_irqrestore(&timer_fttmr010_lock, flags);
++
+ return 0;
+ }
+
+ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
+ {
+ struct fttmr010 *fttmr010 = to_fttmr010(evt);
++ unsigned long flags;
+ u32 cr;
+
++ spin_lock_irqsave(&timer_fttmr010_lock, flags);
++
+ /* Stop */
+ cr = readl(fttmr010->base + TIMER_CR);
+ cr &= ~fttmr010->t1_enable_val;
+@@ -186,6 +204,8 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
+ cr |= TIMER_1_INT_MATCH1;
+ writel(cr, fttmr010->base + TIMER_INTR_MASK);
+
++ spin_unlock_irqrestore(&timer_fttmr010_lock, flags);
++
+ return 0;
+ }
+
+@@ -193,8 +213,11 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
+ {
+ struct fttmr010 *fttmr010 = to_fttmr010(evt);
+ u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ);
++ unsigned long flags;
+ u32 cr;
+
++ spin_lock_irqsave(&timer_fttmr010_lock, flags);
++
+ /* Stop */
+ cr = readl(fttmr010->base + TIMER_CR);
+ cr &= ~fttmr010->t1_enable_val;
+@@ -221,6 +244,8 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
+ cr |= fttmr010->t1_enable_val;
+ writel(cr, fttmr010->base + TIMER_CR);
+
++ spin_unlock_irqrestore(&timer_fttmr010_lock, flags);
++
+ return 0;
+ }
+
+diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
+index edca0d737750..a3baa52f187f 100644
+--- a/drivers/input/misc/pwm-beeper.c
++++ b/drivers/input/misc/pwm-beeper.c
+@@ -52,7 +52,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period)
+ if (error)
+ return error;
+
+- if (!beeper->amplifier_on) {
++ if (beeper->amplifier && !beeper->amplifier_on) {
+ error = regulator_enable(beeper->amplifier);
+ if (error) {
+ pwm_disable(beeper->pwm);
+@@ -67,7 +67,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period)
+
+ static void pwm_beeper_off(struct pwm_beeper *beeper)
+ {
+- if (beeper->amplifier_on) {
++ if (beeper->amplifier && beeper->amplifier_on) {
+ regulator_disable(beeper->amplifier);
+ beeper->amplifier_on = false;
+ }
+@@ -163,9 +163,9 @@ static int pwm_beeper_probe(struct platform_device *pdev)
+ if (IS_ERR(beeper->amplifier)) {
+ error = PTR_ERR(beeper->amplifier);
+ if (error != -EPROBE_DEFER)
+- dev_err(dev, "Failed to get 'amp' regulator: %d\n",
++ dev_dbg(dev, "Failed to get 'amp' regulator: %d\n",
+ error);
+- return error;
++ beeper->amplifier = NULL;
+ }
+
+ INIT_WORK(&beeper->work, pwm_beeper_work);
+diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
+index 504d252716f2..9d4642c668c9 100644
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -168,6 +168,15 @@ config PWM_FSL_FTM
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-fsl-ftm.
+
++config PWM_FTTMR010
++ tristate "Faraday Technology FTTMR010 timer PWM support"
++ help
++ Generic PWM framework driver for Faraday Technology FTTMR010 Timer
++ PWM output
++
++ To compile this driver as a module, choose M here: the module
++ will be called pwm-fttmr010
++
+ config PWM_HIBVT
+ tristate "HiSilicon BVT PWM support"
+ depends on ARCH_HISI || COMPILE_TEST
+diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
+index 9c676a0dadf5..13b7b20ad5ab 100644
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CRC) += pwm-crc.o
+ obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o
+ obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
+ obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
++obj-$(CONFIG_PWM_FTTMR010) += pwm-fttmr010.o
+ obj-$(CONFIG_PWM_HIBVT) += pwm-hibvt.o
+ obj-$(CONFIG_PWM_IMG) += pwm-img.o
+ obj-$(CONFIG_PWM_IMX) += pwm-imx.o
+diff --git a/drivers/pwm/pwm-fttmr010.c b/drivers/pwm/pwm-fttmr010.c
+new file mode 100644
+index 000000000000..459ace3eba6a
+--- /dev/null
++++ b/drivers/pwm/pwm-fttmr010.c
+@@ -0,0 +1,465 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2019 Intel Corporation
++
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pwm.h>
++
++/* For timer_fttmr010_lock */
++#include <clocksource/timer-fttmr010.h>
++
++#define TIMER_CR 0x30
++
++#define TIMER5_ASPEED_COUNT 0x50
++#define TIMER5_ASPEED_LOAD 0x54
++#define TIMER5_ASPEED_MATCH1 0x58
++#define TIMER5_ASPEED_MATCH2 0x5c
++#define TIMER6_ASPEED_COUNT 0x60
++#define TIMER6_ASPEED_LOAD 0x64
++#define TIMER6_ASPEED_MATCH1 0x68
++#define TIMER6_ASPEED_MATCH2 0x6c
++#define TIMER7_ASPEED_COUNT 0x70
++#define TIMER7_ASPEED_LOAD 0x74
++#define TIMER7_ASPEED_MATCH1 0x78
++#define TIMER7_ASPEED_MATCH2 0x7c
++#define TIMER8_ASPEED_COUNT 0x80
++#define TIMER8_ASPEED_LOAD 0x84
++#define TIMER8_ASPEED_MATCH1 0x88
++#define TIMER8_ASPEED_MATCH2 0x8c
++
++#define TIMER_5_CR_ASPEED_ENABLE BIT(16)
++#define TIMER_5_CR_ASPEED_CLOCK BIT(17)
++#define TIMER_5_CR_ASPEED_INT BIT(18)
++#define TIMER_5_CR_ASPEED_PULSE_OUT BIT(19)
++#define TIMER_6_CR_ASPEED_ENABLE BIT(20)
++#define TIMER_6_CR_ASPEED_CLOCK BIT(21)
++#define TIMER_6_CR_ASPEED_INT BIT(22)
++#define TIMER_6_CR_ASPEED_PULSE_OUT BIT(23)
++#define TIMER_7_CR_ASPEED_ENABLE BIT(24)
++#define TIMER_7_CR_ASPEED_CLOCK BIT(25)
++#define TIMER_7_CR_ASPEED_INT BIT(26)
++#define TIMER_7_CR_ASPEED_PULSE_OUT BIT(27)
++#define TIMER_8_CR_ASPEED_ENABLE BIT(28)
++#define TIMER_8_CR_ASPEED_CLOCK BIT(29)
++#define TIMER_8_CR_ASPEED_INT BIT(30)
++#define TIMER_8_CR_ASPEED_PULSE_OUT BIT(31)
++
++/**
++ * struct pwm_fttmr010_variant - variant data depends on SoC
++ * @bits: timer counter resolution
++ * @chan_min: lowest timer channel which has pwm pulse output
++ * @chan_max: highest timer channel which has pwm pulse output
++ * @output_mask: pwm pulse output mask which is defined in device tree
++ */
++struct pwm_fttmr010_variant {
++ u8 bits;
++ u8 chan_min;
++ u8 chan_max;
++ u8 output_mask;
++};
++
++/**
++ * struct pwm_fttmr010_chan - private data of FTTMR010 PWM channel
++ * @period_ns: current period in nanoseconds programmed to the hardware
++ * @duty_ns: current duty time in nanoseconds programmed to the hardware
++ */
++struct pwm_fttmr010_chan {
++ u32 period_ns;
++ u32 duty_ns;
++};
++
++/**
++ * struct pwm_fttmr010 - private data of FTTMR010 PWM
++ * @chip: generic PWM chip
++ * @variant: local copy of hardware variant data
++ * @disabled_mask: disabled status for all channels - one bit per channel
++ * @base: base address of mapped PWM registers
++ * @clk: clock used to drive the timers
++ */
++struct pwm_fttmr010 {
++ struct pwm_chip chip;
++ struct pwm_fttmr010_variant variant;
++ u8 disabled_mask;
++ void __iomem *base;
++ struct clk *clk;
++ u32 clk_tick_ns;
++};
++
++#if !defined(CONFIG_FTTMR010_TIMER)
++/*
++ * Timer block is shared between timer-fttmr010 and pwm-fttmr010 drivers
++ * and some registers need access synchronization. If both drivers are
++ * compiled in, the spinlock is defined in the clocksource driver,
++ * otherwise following definition is used.
++ *
++ * Currently we do not need any more complex synchronization method
++ * because all the supported SoCs contain only one instance of the Timer
++ * IP. Once this changes, both drivers will need to be modified to
++ * properly synchronize accesses to particular instances.
++ */
++static DEFINE_SPINLOCK(timer_fttmr010_lock);
++#endif
++
++static inline
++struct pwm_fttmr010 *to_pwm_fttmr010(struct pwm_chip *chip)
++{
++ return container_of(chip, struct pwm_fttmr010, chip);
++}
++
++static int pwm_fttmr010_request(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct pwm_fttmr010 *priv = to_pwm_fttmr010(chip);
++ struct pwm_fttmr010_chan *chan;
++
++ if (!(priv->variant.output_mask & BIT(pwm->hwpwm))) {
++ dev_warn(chip->dev,
++ "tried to request PWM channel %d without output\n",
++ pwm->hwpwm);
++ return -EINVAL;
++ }
++
++ chan = devm_kzalloc(chip->dev, sizeof(*chan), GFP_KERNEL);
++ if (!chan)
++ return -ENOMEM;
++
++ pwm_set_chip_data(pwm, chan);
++
++ return 0;
++}
++
++static void pwm_fttmr010_free(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ devm_kfree(chip->dev, pwm_get_chip_data(pwm));
++ pwm_set_chip_data(pwm, NULL);
++}
++
++static int pwm_fttmr010_enable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct pwm_fttmr010 *priv = to_pwm_fttmr010(chip);
++ ulong flags;
++ u32 cr;
++
++ spin_lock_irqsave(&timer_fttmr010_lock, flags);
++
++ cr = readl(priv->base + TIMER_CR);
++
++ switch (pwm->hwpwm) {
++ case 5:
++ cr |= (TIMER_5_CR_ASPEED_ENABLE | TIMER_5_CR_ASPEED_PULSE_OUT);
++ break;
++ case 6:
++ cr |= (TIMER_6_CR_ASPEED_ENABLE | TIMER_6_CR_ASPEED_PULSE_OUT);
++ break;
++ case 7:
++ cr |= (TIMER_7_CR_ASPEED_ENABLE | TIMER_7_CR_ASPEED_PULSE_OUT);
++ break;
++ case 8:
++ cr |= (TIMER_8_CR_ASPEED_ENABLE | TIMER_8_CR_ASPEED_PULSE_OUT);
++ break;
++ }
++
++ writel(cr, priv->base + TIMER_CR);
++
++ spin_unlock_irqrestore(&timer_fttmr010_lock, flags);
++
++ priv->disabled_mask &= ~BIT(pwm->hwpwm);
++
++ return 0;
++}
++
++static void pwm_fttmr010_disable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct pwm_fttmr010 *priv = to_pwm_fttmr010(chip);
++ ulong flags;
++ u32 cr;
++
++ spin_lock_irqsave(&timer_fttmr010_lock, flags);
++
++ cr = readl(priv->base + TIMER_CR);
++
++ switch (pwm->hwpwm) {
++ case 5:
++ cr &= ~(TIMER_5_CR_ASPEED_ENABLE | TIMER_5_CR_ASPEED_PULSE_OUT);
++ break;
++ case 6:
++ cr &= ~(TIMER_6_CR_ASPEED_ENABLE | TIMER_6_CR_ASPEED_PULSE_OUT);
++ break;
++ case 7:
++ cr &= ~(TIMER_7_CR_ASPEED_ENABLE | TIMER_7_CR_ASPEED_PULSE_OUT);
++ break;
++ case 8:
++ cr &= ~(TIMER_8_CR_ASPEED_ENABLE | TIMER_8_CR_ASPEED_PULSE_OUT);
++ break;
++ }
++
++ writel(cr, priv->base + TIMER_CR);
++
++ spin_unlock_irqrestore(&timer_fttmr010_lock, flags);
++
++ priv->disabled_mask |= BIT(pwm->hwpwm);
++}
++
++static int pwm_fttmr010_config(struct pwm_chip *chip, struct pwm_device *pwm,
++ int duty_ns, int period_ns)
++{
++ u32 tload, tmatch, creg_offset, lreg_offset, mreg_offset;
++ struct pwm_fttmr010_chan *chan = pwm_get_chip_data(pwm);
++ struct pwm_fttmr010 *priv = to_pwm_fttmr010(chip);
++
++ /*
++ * We currently avoid using 64bit arithmetic by using the
++ * fact that anything faster than 1Hz is easily representable
++ * by 32bits.
++ */
++ if (period_ns > NSEC_PER_SEC)
++ return -ERANGE;
++
++ /* No need to update */
++ if (chan->period_ns == period_ns || chan->duty_ns == duty_ns)
++ return 0;
++
++ tload = period_ns / priv->clk_tick_ns;
++
++ /* Period is too short */
++ if (tload <= 1)
++ return -ERANGE;
++
++ tmatch = duty_ns / priv->clk_tick_ns;
++
++ /* 0% duty is not available */
++ if (!tmatch)
++ ++tmatch;
++
++ tmatch = tload - tmatch;
++
++ /* Decrement to get tick numbers, instead of tick counts */
++ --tload;
++ --tmatch;
++
++ if (tload == 0 || tmatch == 0)
++ return -ERANGE;
++
++ dev_dbg(priv->chip.dev, "clk_tick_ns:%u, tload:%u, tmatch:%u\n",
++ priv->clk_tick_ns, tload, tmatch);
++
++ switch (pwm->hwpwm) {
++ case 5:
++ creg_offset = TIMER5_ASPEED_COUNT;
++ lreg_offset = TIMER5_ASPEED_LOAD;
++ mreg_offset = TIMER5_ASPEED_MATCH1;
++ break;
++ case 6:
++ creg_offset = TIMER6_ASPEED_COUNT;
++ lreg_offset = TIMER6_ASPEED_LOAD;
++ mreg_offset = TIMER6_ASPEED_MATCH1;
++ break;
++ case 7:
++ creg_offset = TIMER7_ASPEED_COUNT;
++ lreg_offset = TIMER7_ASPEED_LOAD;
++ mreg_offset = TIMER7_ASPEED_MATCH1;
++ break;
++ case 8:
++ creg_offset = TIMER8_ASPEED_COUNT;
++ lreg_offset = TIMER8_ASPEED_LOAD;
++ mreg_offset = TIMER8_ASPEED_MATCH1;
++ break;
++ }
++
++ writel(tload, priv->base + creg_offset);
++ writel(tload, priv->base + lreg_offset);
++ writel(tmatch, priv->base + mreg_offset);
++
++ chan->period_ns = period_ns;
++ chan->duty_ns = duty_ns;
++
++ return 0;
++}
++
++static const struct pwm_ops pwm_fttmr010_ops = {
++ .request = pwm_fttmr010_request,
++ .free = pwm_fttmr010_free,
++ .enable = pwm_fttmr010_enable,
++ .disable = pwm_fttmr010_disable,
++ .config = pwm_fttmr010_config,
++ .owner = THIS_MODULE,
++};
++
++#ifdef CONFIG_OF
++static const struct pwm_fttmr010_variant aspeed_variant = {
++ .bits = 32,
++ .chan_min = 5,
++ .chan_max = 8,
++};
++
++static const struct of_device_id pwm_fttmr010_matches[] = {
++ { .compatible = "aspeed,ast2400-timer", .data = &aspeed_variant },
++ { .compatible = "aspeed,ast2500-timer", .data = &aspeed_variant },
++ { },
++};
++MODULE_DEVICE_TABLE(of, pwm_fttmr010_matches);
++
++static int pwm_fttmr010_parse_dt(struct pwm_fttmr010 *priv)
++{
++ struct device_node *np = priv->chip.dev->of_node;
++ const struct of_device_id *match;
++ struct property *prop;
++ const __be32 *cur;
++ u32 val;
++
++ match = of_match_node(pwm_fttmr010_matches, np);
++ if (!match)
++ return -ENODEV;
++
++ memcpy(&priv->variant, match->data, sizeof(priv->variant));
++
++ of_property_for_each_u32(np, "fttmr010,pwm-outputs", prop, cur, val) {
++ if (val < priv->variant.chan_min ||
++ val > priv->variant.chan_max) {
++ dev_err(priv->chip.dev,
++ "invalid channel index in fttmr010,pwm-outputs property\n");
++ continue;
++ }
++ priv->variant.output_mask |= BIT(val);
++ }
++
++ return 0;
++}
++#else
++static int pwm_fttmr010_parse_dt(struct pwm_fttmr010 *priv)
++{
++ return -ENODEV;
++}
++#endif
++
++static int pwm_fttmr010_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct pwm_fttmr010 *priv;
++ struct resource *res;
++ ulong clk_rate;
++ int ret;
++
++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ priv->chip.dev = &pdev->dev;
++ priv->chip.ops = &pwm_fttmr010_ops;
++ priv->chip.base = -1;
++
++ if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
++ ret = pwm_fttmr010_parse_dt(priv);
++ if (ret)
++ return ret;
++
++ priv->chip.of_xlate = of_pwm_xlate_with_flags;
++ priv->chip.of_pwm_n_cells = 3;
++ } else {
++ if (!pdev->dev.platform_data) {
++ dev_err(&pdev->dev, "no platform data specified\n");
++ return -EINVAL;
++ }
++
++ memcpy(&priv->variant, pdev->dev.platform_data,
++ sizeof(priv->variant));
++ }
++
++ priv->chip.npwm = priv->variant.chan_max + 1;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ priv->base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(priv->base))
++ return PTR_ERR(priv->base);
++
++ priv->clk = devm_clk_get(&pdev->dev, "PCLK");
++ if (IS_ERR(priv->clk)) {
++ dev_err(dev, "failed to get timer base clk\n");
++ return PTR_ERR(priv->clk);
++ }
++
++ ret = clk_prepare_enable(priv->clk);
++ if (ret < 0) {
++ dev_err(dev, "failed to enable base clock\n");
++ return ret;
++ }
++
++ clk_rate = clk_get_rate(priv->clk);
++ priv->clk_tick_ns = NSEC_PER_SEC / clk_rate;
++
++ platform_set_drvdata(pdev, priv);
++
++ ret = pwmchip_add(&priv->chip);
++ if (ret < 0) {
++ dev_err(dev, "failed to register PWM chip\n");
++ clk_disable_unprepare(priv->clk);
++ return ret;
++ }
++
++ dev_dbg(dev, "clk at %lu\n", clk_rate);
++
++ return 0;
++}
++
++static int pwm_fttmr010_remove(struct platform_device *pdev)
++{
++ struct pwm_fttmr010 *priv = platform_get_drvdata(pdev);
++ int ret;
++
++ ret = pwmchip_remove(&priv->chip);
++ if (ret < 0)
++ return ret;
++
++ clk_disable_unprepare(priv->clk);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int pwm_fttmr010_resume(struct device *dev)
++{
++ struct pwm_fttmr010 *priv = dev_get_drvdata(dev);
++ struct pwm_chip *chip = &priv->chip;
++ unsigned int i;
++
++ for (i = chip->variant.chan_min; i < chip->variant.chan_max; i++) {
++ struct pwm_device *pwm = &chip->pwms[i];
++ struct pwm_fttmr010_chan *chan = pwm_get_chip_data(pwm);
++
++ if (!chan)
++ continue;
++
++ if (chan->period_ns) {
++ pwm_fttmr010_config(chip, pwm, chan->duty_ns,
++ chan->period_ns);
++ }
++
++ if (priv->disabled_mask & BIT(i))
++ pwm_fttmr010_disable(chip, pwm);
++ else
++ pwm_fttmr010_enable(chip, pwm);
++ }
++
++ return 0;
++}
++#endif
++
++static SIMPLE_DEV_PM_OPS(pwm_fttmr010_pm_ops, NULL, pwm_fttmr010_resume);
++
++static struct platform_driver pwm_fttmr010_driver = {
++ .driver = {
++ .name = "fttmr010-timer-pwm",
++ .pm = &pwm_fttmr010_pm_ops,
++ .of_match_table = of_match_ptr(pwm_fttmr010_matches),
++ },
++ .probe = pwm_fttmr010_probe,
++ .remove = pwm_fttmr010_remove,
++};
++module_platform_driver(pwm_fttmr010_driver);
++
++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
++MODULE_DESCRIPTION("FTTMR010 PWM Driver for timer pulse outputs");
++MODULE_LICENSE("GPL v2");
+diff --git a/include/clocksource/timer-fttmr010.h b/include/clocksource/timer-fttmr010.h
+new file mode 100644
+index 000000000000..d8d6a2f14130
+--- /dev/null
++++ b/include/clocksource/timer-fttmr010.h
+@@ -0,0 +1,17 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++
++#ifndef __CLOCKSOURCE_TIMER_FTTMR010_H
++#define __CLOCKSOURCE_TIMER_FTTMR010_H
++
++#include <linux/spinlock.h>
++
++/*
++ * Following declaration must be in an ifdef due to this symbol being static
++ * in timer-fttmr010 driver if the clocksource driver is not compiled in and the
++ * spinlock is not shared between both drivers.
++ */
++#ifdef CONFIG_FTTMR010_TIMER
++extern spinlock_t timer_fttmr010_lock;
++#endif
++
++#endif /* __CLOCKSOURCE_TIMER_FTTMR010_H */
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch
new file mode 100644
index 000000000..85b2f45a1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch
@@ -0,0 +1,492 @@
+From 38ba0a960fcd17f7b3480fe3025c261fd60fe979 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Fri, 15 Feb 2019 16:05:09 -0800
+Subject: [PATCH] i2c: Add mux hold/unhold msg types
+
+This commit adds mux hold/unhold message types to support extended
+mux control for IPMB and MCTP devices. A hold or an unhold message
+can be added at the end of I2C message stream wrapped by
+repeated-start, also can be used as a single message independantly.
+
+This mux hold/unhold message will be delivered throughout all mux
+levels in the path. Means that if it goes to multi-level mux path,
+all muxes will be held/unheld by this message.
+
+1. Hold message
+ struct i2c_msg msg;
+ uint16_t timeout = 5000; // timeout in ms. 5 secs in this example.
+
+ msg.addr = 0x0; // any value can be used. addr will be ignored in this packet.
+ msg.flags = I2C_M_HOLD; // set this flag to indicate it's a hold message.
+ msg.len = sizeof(uint16_t); // timeout value will be delivered using two bytes buffer.
+ msg.buf = (uint8_t *)&timeout; // set timeout value.
+
+2. Unhold message
+ struct i2c_msg msg;
+ uint16_t timeout = 0; // set 0 for an unhold message.
+
+ msg.addr = 0x0; // any value can be used. addr will be ignored in this packet.
+ msg.flags = I2C_M_HOLD; // set this flag to indicate it's an unhold message.
+ msg.len = sizeof(uint16_t); // timeout value will be delivered using two bytes buffer.
+ msg.buf = (uint8_t *)&timeout; // set timeout value.
+
+ This unhold message can be delivered to a mux adapter even when
+ a bus is locked so that any holding state can be unheld
+ immediately by invoking this unhold message.
+
+This patch would not be welcomed from upstream so it should be kept
+in downstream only.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/i2c/i2c-core-base.c | 79 +++++++++++++++++++++++++++----
+ drivers/i2c/i2c-core-smbus.c | 17 ++++++-
+ drivers/i2c/i2c-mux.c | 109 +++++++++++++++++++++++++++++++++++++++----
+ include/linux/i2c-mux.h | 3 ++
+ include/linux/i2c.h | 25 ++++++++++
+ include/uapi/linux/i2c.h | 1 +
+ 6 files changed, 215 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
+index 9200e349f29e..728b818501b1 100644
+--- a/drivers/i2c/i2c-core-base.c
++++ b/drivers/i2c/i2c-core-base.c
+@@ -1211,6 +1211,25 @@ int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr)
+ }
+ EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify);
+
++static void i2c_adapter_hold(struct i2c_adapter *adapter, unsigned long timeout)
++{
++ mutex_lock(&adapter->hold_lock);
++ mod_timer(&adapter->hold_timer, jiffies + timeout);
++}
++
++static void i2c_adapter_unhold(struct i2c_adapter *adapter)
++{
++ del_timer_sync(&adapter->hold_timer);
++ mutex_unlock(&adapter->hold_lock);
++}
++
++static void i2c_adapter_hold_timer_callback(struct timer_list *t)
++{
++ struct i2c_adapter *adapter = from_timer(adapter, t, hold_timer);
++
++ i2c_adapter_unhold(adapter);
++}
++
+ static int i2c_register_adapter(struct i2c_adapter *adap)
+ {
+ int res = -EINVAL;
+@@ -1292,6 +1311,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
+ bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
+ mutex_unlock(&core_lock);
+
++ mutex_init(&adap->hold_lock);
++ timer_setup(&adap->hold_timer, i2c_adapter_hold_timer_callback, 0);
++
+ return 0;
+
+ out_reg:
+@@ -1512,6 +1534,8 @@ void i2c_del_adapter(struct i2c_adapter *adap)
+ idr_remove(&i2c_adapter_idr, adap->nr);
+ mutex_unlock(&core_lock);
+
++ i2c_adapter_unhold(adap);
++
+ /* Clear the device structure in case this adapter is ever going to be
+ added again */
+ memset(&adap->dev, 0, sizeof(adap->dev));
+@@ -1861,7 +1885,9 @@ static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ */
+ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+ {
++ enum i2c_hold_msg_type hold_msg;
+ unsigned long orig_jiffies;
++ unsigned long timeout;
+ int ret, try;
+
+ if (WARN_ON(!msgs || num < 1))
+@@ -1870,6 +1896,25 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+ if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
+ return -EOPNOTSUPP;
+
++ /* Do not deliver a mux hold msg to root bus adapter */
++ if (!i2c_parent_is_i2c_adapter(adap)) {
++ hold_msg = i2c_check_hold_msg(msgs[num - 1].flags,
++ msgs[num - 1].len,
++ (u16 *)msgs[num - 1].buf);
++ if (hold_msg == I2C_HOLD_MSG_SET) {
++ timeout = msecs_to_jiffies(*(u16 *)msgs[num - 1].buf);
++ i2c_adapter_hold(adap, timeout);
++
++ if (--num == 0)
++ return 0;
++ } else if (hold_msg == I2C_HOLD_MSG_RESET) {
++ i2c_adapter_unhold(adap);
++ return 0;
++ } else if (hold_msg == I2C_HOLD_MSG_NONE) {
++ mutex_lock(&adap->hold_lock);
++ }
++ }
++
+ /*
+ * i2c_trace_msg_key gets enabled when tracepoint i2c_transfer gets
+ * enabled. This is an efficient way of keeping the for-loop from
+@@ -1902,6 +1947,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+ trace_i2c_result(adap, num, ret);
+ }
+
++ if (!i2c_parent_is_i2c_adapter(adap) && hold_msg == I2C_HOLD_MSG_NONE)
++ mutex_unlock(&adap->hold_lock);
++
+ return ret;
+ }
+ EXPORT_SYMBOL(__i2c_transfer);
+@@ -1920,6 +1968,7 @@ EXPORT_SYMBOL(__i2c_transfer);
+ */
+ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+ {
++ bool do_bus_lock = true;
+ int ret;
+
+ /* REVISIT the fault reporting model here is weak:
+@@ -1949,18 +1998,30 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+ (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
+ }
+ #endif
+-
+- if (in_atomic() || irqs_disabled()) {
+- ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT);
+- if (!ret)
+- /* I2C activity is ongoing. */
+- return -EAGAIN;
+- } else {
+- i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
++ /*
++ * Do not lock a bus for delivering an unhold msg to a mux
++ * adpater. This is just for a single length unhold msg case.
++ */
++ if (num == 1 && i2c_parent_is_i2c_adapter(adap) &&
++ i2c_check_hold_msg(msgs[0].flags, msgs[0].len,
++ (u16 *)msgs[0].buf) ==
++ I2C_HOLD_MSG_RESET)
++ do_bus_lock = false;
++
++ if (do_bus_lock) {
++ if (in_atomic() || irqs_disabled()) {
++ ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT);
++ if (!ret)
++ /* I2C activity is ongoing. */
++ return -EAGAIN;
++ } else {
++ i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
++ }
+ }
+
+ ret = __i2c_transfer(adap, msgs, num);
+- i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
++ if (do_bus_lock)
++ i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
+
+ return ret;
+ } else {
+diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c
+index 9cd66cabb84f..64c58911bf21 100644
+--- a/drivers/i2c/i2c-core-smbus.c
++++ b/drivers/i2c/i2c-core-smbus.c
+@@ -528,12 +528,25 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int protocol, union i2c_smbus_data *data)
+ {
++ bool do_bus_lock = true;
+ s32 res;
+
+- i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);
++ /*
++ * Do not lock a bus for delivering an unhold msg to a mux adpater.
++ * This is just for a single length unhold msg case.
++ */
++ if (i2c_parent_is_i2c_adapter(adapter) &&
++ i2c_check_hold_msg(flags,
++ protocol == I2C_SMBUS_WORD_DATA ? 2 : 0,
++ &data->word) == I2C_HOLD_MSG_RESET)
++ do_bus_lock = false;
++
++ if (do_bus_lock)
++ i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);
+ res = __i2c_smbus_xfer(adapter, addr, flags, read_write,
+ command, protocol, data);
+- i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);
++ if (do_bus_lock)
++ i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);
+
+ return res;
+ }
+diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
+index f330690b4125..4d8909a0f90a 100644
+--- a/drivers/i2c/i2c-mux.c
++++ b/drivers/i2c/i2c-mux.c
+@@ -26,6 +26,7 @@
+ #include <linux/module.h>
+ #include <linux/of.h>
+ #include <linux/slab.h>
++#include <linux/timer.h>
+
+ /* multiplexer per channel data */
+ struct i2c_mux_priv {
+@@ -35,21 +36,57 @@ struct i2c_mux_priv {
+ u32 chan_id;
+ };
+
++static void i2c_mux_hold(struct i2c_mux_core *muxc, unsigned long timeout)
++{
++ mutex_lock(&muxc->hold_lock);
++ mod_timer(&muxc->hold_timer, jiffies + timeout);
++}
++
++static void i2c_mux_unhold(struct i2c_mux_core *muxc)
++{
++ del_timer_sync(&muxc->hold_timer);
++ mutex_unlock(&muxc->hold_lock);
++}
++
++static void i2c_mux_hold_timer_callback(struct timer_list *t)
++{
++ struct i2c_mux_core *muxc = from_timer(muxc, t, hold_timer);
++
++ i2c_mux_unhold(muxc);
++}
++
+ static int __i2c_mux_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[], int num)
+ {
+ struct i2c_mux_priv *priv = adap->algo_data;
+ struct i2c_mux_core *muxc = priv->muxc;
+ struct i2c_adapter *parent = muxc->parent;
++ enum i2c_hold_msg_type hold_msg;
++ unsigned long timeout;
+ int ret;
+
+ /* Switch to the right mux port and perform the transfer. */
+
++ hold_msg = i2c_check_hold_msg(msgs[num - 1].flags,
++ msgs[num - 1].len,
++ (u16 *)msgs[num - 1].buf);
++ if (hold_msg == I2C_HOLD_MSG_SET) {
++ timeout = msecs_to_jiffies(*(u16 *)msgs[num - 1].buf);
++ i2c_mux_hold(muxc, timeout);
++ } else if (hold_msg == I2C_HOLD_MSG_NONE) {
++ mutex_lock(&muxc->hold_lock);
++ }
+ ret = muxc->select(muxc, priv->chan_id);
+ if (ret >= 0)
+ ret = __i2c_transfer(parent, msgs, num);
+- if (muxc->deselect)
+- muxc->deselect(muxc, priv->chan_id);
++ if (hold_msg != I2C_HOLD_MSG_SET) {
++ if (muxc->deselect)
++ muxc->deselect(muxc, priv->chan_id);
++ if (hold_msg == I2C_HOLD_MSG_RESET)
++ i2c_mux_unhold(muxc);
++ else
++ mutex_unlock(&muxc->hold_lock);
++ }
+
+ return ret;
+ }
+@@ -60,15 +97,32 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
+ struct i2c_mux_priv *priv = adap->algo_data;
+ struct i2c_mux_core *muxc = priv->muxc;
+ struct i2c_adapter *parent = muxc->parent;
++ enum i2c_hold_msg_type hold_msg;
++ unsigned long timeout;
+ int ret;
+
+ /* Switch to the right mux port and perform the transfer. */
+
++ hold_msg = i2c_check_hold_msg(msgs[num - 1].flags,
++ msgs[num - 1].len,
++ (u16 *)msgs[num - 1].buf);
++ if (hold_msg == I2C_HOLD_MSG_SET) {
++ timeout = msecs_to_jiffies(*(u16 *)msgs[num - 1].buf);
++ i2c_mux_hold(muxc, timeout);
++ } else if (hold_msg == I2C_HOLD_MSG_NONE) {
++ mutex_lock(&muxc->hold_lock);
++ }
+ ret = muxc->select(muxc, priv->chan_id);
+ if (ret >= 0)
+ ret = i2c_transfer(parent, msgs, num);
+- if (muxc->deselect)
+- muxc->deselect(muxc, priv->chan_id);
++ if (hold_msg != I2C_HOLD_MSG_SET) {
++ if (muxc->deselect)
++ muxc->deselect(muxc, priv->chan_id);
++ if (hold_msg == I2C_HOLD_MSG_RESET)
++ i2c_mux_unhold(muxc);
++ else
++ mutex_unlock(&muxc->hold_lock);
++ }
+
+ return ret;
+ }
+@@ -81,16 +135,33 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,
+ struct i2c_mux_priv *priv = adap->algo_data;
+ struct i2c_mux_core *muxc = priv->muxc;
+ struct i2c_adapter *parent = muxc->parent;
++ enum i2c_hold_msg_type hold_msg;
++ unsigned long timeout;
+ int ret;
+
+ /* Select the right mux port and perform the transfer. */
+
++ hold_msg = i2c_check_hold_msg(flags,
++ size == I2C_SMBUS_WORD_DATA ? 2 : 0,
++ &data->word);
++ if (hold_msg == I2C_HOLD_MSG_SET) {
++ timeout = msecs_to_jiffies(data->word);
++ i2c_mux_hold(muxc, timeout);
++ } else if (hold_msg == I2C_HOLD_MSG_NONE) {
++ mutex_lock(&muxc->hold_lock);
++ }
+ ret = muxc->select(muxc, priv->chan_id);
+ if (ret >= 0)
+ ret = __i2c_smbus_xfer(parent, addr, flags,
+ read_write, command, size, data);
+- if (muxc->deselect)
+- muxc->deselect(muxc, priv->chan_id);
++ if (hold_msg != I2C_HOLD_MSG_SET) {
++ if (muxc->deselect)
++ muxc->deselect(muxc, priv->chan_id);
++ if (hold_msg == I2C_HOLD_MSG_RESET)
++ i2c_mux_unhold(muxc);
++ else
++ mutex_unlock(&muxc->hold_lock);
++ }
+
+ return ret;
+ }
+@@ -103,16 +174,33 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
+ struct i2c_mux_priv *priv = adap->algo_data;
+ struct i2c_mux_core *muxc = priv->muxc;
+ struct i2c_adapter *parent = muxc->parent;
++ enum i2c_hold_msg_type hold_msg;
++ unsigned long timeout;
+ int ret;
+
+ /* Select the right mux port and perform the transfer. */
+
++ hold_msg = i2c_check_hold_msg(flags,
++ size == I2C_SMBUS_WORD_DATA ? 2 : 0,
++ &data->word);
++ if (hold_msg == I2C_HOLD_MSG_SET) {
++ timeout = msecs_to_jiffies(data->word);
++ i2c_mux_hold(muxc, timeout);
++ } else if (hold_msg == I2C_HOLD_MSG_NONE) {
++ mutex_lock(&muxc->hold_lock);
++ }
+ ret = muxc->select(muxc, priv->chan_id);
+ if (ret >= 0)
+ ret = i2c_smbus_xfer(parent, addr, flags,
+ read_write, command, size, data);
+- if (muxc->deselect)
+- muxc->deselect(muxc, priv->chan_id);
++ if (hold_msg != I2C_HOLD_MSG_SET) {
++ if (muxc->deselect)
++ muxc->deselect(muxc, priv->chan_id);
++ if (hold_msg == I2C_HOLD_MSG_RESET)
++ i2c_mux_unhold(muxc);
++ else
++ mutex_unlock(&muxc->hold_lock);
++ }
+
+ return ret;
+ }
+@@ -263,6 +351,9 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
+ muxc->deselect = deselect;
+ muxc->max_adapters = max_adapters;
+
++ mutex_init(&muxc->hold_lock);
++ timer_setup(&muxc->hold_timer, i2c_mux_hold_timer_callback, 0);
++
+ return muxc;
+ }
+ EXPORT_SYMBOL_GPL(i2c_mux_alloc);
+@@ -435,6 +526,8 @@ void i2c_mux_del_adapters(struct i2c_mux_core *muxc)
+ {
+ char symlink_name[20];
+
++ i2c_mux_unhold(muxc);
++
+ while (muxc->num_adapters) {
+ struct i2c_adapter *adap = muxc->adapter[--muxc->num_adapters];
+ struct i2c_mux_priv *priv = adap->algo_data;
+diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
+index bd74d5706f3b..bc6f778eaf9d 100644
+--- a/include/linux/i2c-mux.h
++++ b/include/linux/i2c-mux.h
+@@ -41,6 +41,9 @@ struct i2c_mux_core {
+ int (*select)(struct i2c_mux_core *, u32 chan_id);
+ int (*deselect)(struct i2c_mux_core *, u32 chan_id);
+
++ struct mutex hold_lock; /* mutex for channel holding */
++ struct timer_list hold_timer;
++
+ int num_adapters;
+ int max_adapters;
+ struct i2c_adapter *adapter[0];
+diff --git a/include/linux/i2c.h b/include/linux/i2c.h
+index 65b4eaed1d96..eadde70c0d4a 100644
+--- a/include/linux/i2c.h
++++ b/include/linux/i2c.h
+@@ -692,6 +692,13 @@ struct i2c_adapter {
+ const struct i2c_adapter_quirks *quirks;
+
+ struct irq_domain *host_notify_domain;
++
++ /*
++ * These will be used by root adpaters only. For muxes, each mux core
++ * has these individually.
++ */
++ struct mutex hold_lock; /* mutex for bus holding */
++ struct timer_list hold_timer;
+ };
+ #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
+
+@@ -949,4 +956,22 @@ static inline struct i2c_client *i2c_acpi_new_device(struct device *dev,
+ }
+ #endif /* CONFIG_ACPI */
+
++enum i2c_hold_msg_type {
++ I2C_HOLD_MSG_NONE,
++ I2C_HOLD_MSG_SET,
++ I2C_HOLD_MSG_RESET
++};
++
++static inline enum i2c_hold_msg_type i2c_check_hold_msg(u16 flags, u16 len, u16 *buf)
++{
++ if (flags & I2C_M_HOLD && len == sizeof(u16)) {
++ if (*buf)
++ return I2C_HOLD_MSG_SET;
++
++ return I2C_HOLD_MSG_RESET;
++ }
++
++ return I2C_HOLD_MSG_NONE;
++}
++
+ #endif /* _LINUX_I2C_H */
+diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h
+index f71a1751cacf..a1db9b17ed36 100644
+--- a/include/uapi/linux/i2c.h
++++ b/include/uapi/linux/i2c.h
+@@ -72,6 +72,7 @@ struct i2c_msg {
+ #define I2C_M_RD 0x0001 /* read data, from slave to master */
+ /* I2C_M_RD is guaranteed to be 0x0001! */
+ #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
++#define I2C_M_HOLD 0x0100 /* for holding a mux path */
+ #define I2C_M_DMA_SAFE 0x0200 /* the buffer of this message is DMA safe */
+ /* makes only sense in kernelspace */
+ /* userspace buffers are copied anyway */
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0041-Enable-passthrough-based-gpio-character-device.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0041-Enable-passthrough-based-gpio-character-device.patch
new file mode 100644
index 000000000..9e7757011
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0041-Enable-passthrough-based-gpio-character-device.patch
@@ -0,0 +1,287 @@
+From d34efc982a9206db87da49be3d9b1e20f59be56f Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Thu, 31 Jan 2019 17:47:39 +0800
+Subject: [PATCH] Enable passthrough based gpio character device.
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ drivers/gpio/gpio-aspeed.c | 47 ++++++++++++++++++++++-
+ drivers/gpio/gpiolib.c | 51 +++++++++++++++++++++++--
+ drivers/gpio/gpiolib.h | 1 +
+ include/linux/gpio/consumer.h | 9 +++++
+ include/linux/pinctrl/pinconf-generic.h | 2 +
+ include/uapi/linux/gpio.h | 1 +
+ 6 files changed, 106 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
+index 2342e154029b..06fd95197684 100644
+--- a/drivers/gpio/gpio-aspeed.c
++++ b/drivers/gpio/gpio-aspeed.c
+@@ -17,9 +17,11 @@
+ #include <linux/init.h>
+ #include <linux/io.h>
+ #include <linux/kernel.h>
++#include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/pinctrl/consumer.h>
+ #include <linux/platform_device.h>
++#include <linux/regmap.h>
+ #include <linux/spinlock.h>
+ #include <linux/string.h>
+
+@@ -58,6 +60,7 @@ struct aspeed_gpio {
+ struct gpio_chip chip;
+ spinlock_t lock;
+ void __iomem *base;
++ struct regmap *scu;
+ int irq;
+ const struct aspeed_gpio_config *config;
+
+@@ -91,6 +94,13 @@ struct aspeed_gpio_bank {
+ * and thus can be used to read back what was last written
+ * reliably.
+ */
++#define SCU8C 0x8C /* Multi-function Pin Control #4 */
++#define PASS_THROUGH1 32
++#define PASS_THROUGH2 34
++#define PASS_THROUGH2_MASK 0x2000
++#define PASS_THROUGH1_MASK 0x1000
++#define PASS_THROUGH2_ON 0x2000
++#define PASS_THROUGH1_ON 0x1000
+
+ static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 };
+
+@@ -988,12 +998,38 @@ static int set_debounce(struct gpio_chip *chip, unsigned int offset,
+ return disable_debounce(chip, offset);
+ }
+
++static int aspeed_gpio_pass_through(struct gpio_chip *chip, unsigned int offset,
++ unsigned long param)
++{
++ struct aspeed_gpio *gpio = gpiochip_get_data(chip);
++ u32 value;
++
++ if (!gpio->scu)
++ return -ENOTSUPP;
++ if (param == PIN_CONFIG_PASS_THROUGH_ENABLE){
++ if (offset == PASS_THROUGH2){
++ regmap_update_bits(gpio->scu, SCU8C, PASS_THROUGH2_MASK, PASS_THROUGH2_ON);
++ } else if (offset == PASS_THROUGH1){
++ regmap_update_bits(gpio->scu, SCU8C, PASS_THROUGH1_MASK, PASS_THROUGH1_ON);
++ }
++ } else if (param == PIN_CONFIG_PASS_THROUGH_DISABLE){
++ if (offset == PASS_THROUGH2){
++ regmap_update_bits(gpio->scu, SCU8C, PASS_THROUGH2_MASK, ~(PASS_THROUGH2_ON));
++ } else if (offset == PASS_THROUGH1){
++ regmap_update_bits(gpio->scu, SCU8C, PASS_THROUGH1_MASK, ~(PASS_THROUGH1_ON));
++ }
++ } else {
++ return -ENOTSUPP;
++ }
++
++ return 0;
++}
++
+ static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ unsigned long config)
+ {
+ unsigned long param = pinconf_to_config_param(config);
+ u32 arg = pinconf_to_config_argument(config);
+-
+ if (param == PIN_CONFIG_INPUT_DEBOUNCE)
+ return set_debounce(chip, offset, arg);
+ else if (param == PIN_CONFIG_BIAS_DISABLE ||
+@@ -1006,6 +1042,9 @@ static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+ return -ENOTSUPP;
+ else if (param == PIN_CONFIG_PERSIST_STATE)
+ return aspeed_gpio_reset_tolerance(chip, offset, arg);
++ else if (param == PIN_CONFIG_PASS_THROUGH_ENABLE ||
++ param == PIN_CONFIG_PASS_THROUGH_DISABLE)
++ return aspeed_gpio_pass_through(chip, offset, param);
+
+ return -ENOTSUPP;
+ }
+@@ -1167,7 +1206,11 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
+ gpio->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gpio->base))
+ return PTR_ERR(gpio->base);
+-
++ gpio->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu");
++ if (IS_ERR(gpio->scu)) {
++ dev_err(&pdev->dev, "Failed to find SCU regmap\n");
++ gpio->scu = NULL;
++ }
+ spin_lock_init(&gpio->lock);
+
+ gpio_id = of_match_node(aspeed_gpio_of_table, pdev->dev.of_node);
+diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
+index a8e01d99919c..21eeca17583d 100644
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -419,6 +419,7 @@ struct linehandle_state {
+ GPIOHANDLE_REQUEST_OUTPUT | \
+ GPIOHANDLE_REQUEST_ACTIVE_LOW | \
+ GPIOHANDLE_REQUEST_OPEN_DRAIN | \
++ GPIOHANDLE_REQUEST_PASS_THROUGH | \
+ GPIOHANDLE_REQUEST_OPEN_SOURCE)
+
+ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
+@@ -519,7 +520,6 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
+ return -EINVAL;
+
+ lflags = handlereq.flags;
+-
+ /* Return an error if an unknown flag is set */
+ if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS)
+ return -EINVAL;
+@@ -579,6 +579,8 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
+ set_bit(FLAG_OPEN_DRAIN, &desc->flags);
+ if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
+ set_bit(FLAG_OPEN_SOURCE, &desc->flags);
++ if (lflags & GPIOHANDLE_REQUEST_PASS_THROUGH)
++ set_bit(FLAG_PASS_THROUGH, &desc->flags);
+
+ ret = gpiod_set_transitory(desc, false);
+ if (ret < 0)
+@@ -598,6 +600,11 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
+ ret = gpiod_direction_input(desc);
+ if (ret)
+ goto out_free_descs;
++ } else if (lflags & GPIOHANDLE_REQUEST_PASS_THROUGH) {
++ int val = !!handlereq.default_values[i];
++ ret = gpiod_direction_pass_through(desc, val);
++ if (ret)
++ goto out_free_descs;
+ }
+ dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
+ offset);
+@@ -1010,7 +1017,6 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ struct gpio_device *gdev = filp->private_data;
+ struct gpio_chip *chip = gdev->chip;
+ void __user *ip = (void __user *)arg;
+-
+ /* We fail any subsequent ioctl():s when the chip is gone */
+ if (!chip)
+ return -ENODEV;
+@@ -1018,7 +1024,6 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ /* Fill in the struct and pass to userspace */
+ if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
+ struct gpiochip_info chipinfo;
+-
+ memset(&chipinfo, 0, sizeof(chipinfo));
+
+ strncpy(chipinfo.name, dev_name(&gdev->dev),
+@@ -2643,6 +2648,46 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
+ }
+ EXPORT_SYMBOL_GPL(gpiod_direction_output);
+
++/**
++ * gpiod_direction_pass_through - set the GPIO direction to pass-through
++ * @desc: GPIO to set to pass-through
++ *
++ * Set the direction of the passed GPIO to passthrough.
++ *
++ * Return 0 in case of success, else an error code.
++ */
++int gpiod_direction_pass_through(struct gpio_desc *desc, int val)
++{
++ struct gpio_chip *gc;
++
++ VALIDATE_DESC(desc);
++ /* GPIOs used for IRQs shall not be set as pass-through */
++ if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
++ gpiod_err(desc,
++ "%s: tried to set a GPIO tied to an IRQ as pass-through\n",
++ __func__);
++ return -EIO;
++ }
++ gc = desc->gdev->chip;
++ val = !!val;
++ if (test_bit(FLAG_PASS_THROUGH, &desc->flags)) {
++ if (val)
++ gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
++ PIN_CONFIG_PASS_THROUGH_ENABLE);
++ else
++ gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
++ PIN_CONFIG_PASS_THROUGH_DISABLE);
++ } else {
++ gpiod_err(desc,
++ "%s: desc->flags is not set to FLAG_PASS_THROUGH\n",
++ __func__);
++ return -EIO;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(gpiod_direction_pass_through);
++
+ /**
+ * gpiod_set_debounce - sets @debounce time for a GPIO
+ * @desc: descriptor of the GPIO for which to set debounce time
+diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
+index a7e49fef73d4..b143ee47870a 100644
+--- a/drivers/gpio/gpiolib.h
++++ b/drivers/gpio/gpiolib.h
+@@ -210,6 +210,7 @@ struct gpio_desc {
+ #define FLAG_IS_OUT 1
+ #define FLAG_EXPORT 2 /* protected by sysfs_lock */
+ #define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
++#define FLAG_PASS_THROUGH 4 /*Gpio is passthrough type*/
+ #define FLAG_ACTIVE_LOW 6 /* value has active low */
+ #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
+ #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
+diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
+index 21ddbe440030..96551839c191 100644
+--- a/include/linux/gpio/consumer.h
++++ b/include/linux/gpio/consumer.h
+@@ -99,6 +99,7 @@ void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs);
+ int gpiod_get_direction(struct gpio_desc *desc);
+ int gpiod_direction_input(struct gpio_desc *desc);
+ int gpiod_direction_output(struct gpio_desc *desc, int value);
++int gpiod_direction_pass_through(struct gpio_desc *desc, int val);
+ int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
+
+ /* Value get/set from non-sleeping context */
+@@ -314,6 +315,14 @@ static inline int gpiod_direction_output(struct gpio_desc *desc, int value)
+ WARN_ON(1);
+ return -ENOSYS;
+ }
++
++static inline int gpiod_direction_pass_through(struct gpio_desc *desc, int val)
++{
++ /* GPIO can never have been requested */
++ WARN_ON(1);
++ return -ENOSYS;
++}
++
+ static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
+ {
+ /* GPIO can never have been requested */
+diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h
+index 6c0680641108..59f0cbabb685 100644
+--- a/include/linux/pinctrl/pinconf-generic.h
++++ b/include/linux/pinctrl/pinconf-generic.h
+@@ -124,6 +124,8 @@ enum pin_config_param {
+ PIN_CONFIG_SLEW_RATE,
+ PIN_CONFIG_SKEW_DELAY,
+ PIN_CONFIG_PERSIST_STATE,
++ PIN_CONFIG_PASS_THROUGH_ENABLE,
++ PIN_CONFIG_PASS_THROUGH_DISABLE,
+ PIN_CONFIG_END = 0x7F,
+ PIN_CONFIG_MAX = 0xFF,
+ };
+diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h
+index 1bf6e6df084b..384ced158412 100644
+--- a/include/uapi/linux/gpio.h
++++ b/include/uapi/linux/gpio.h
+@@ -62,6 +62,7 @@ struct gpioline_info {
+ #define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2)
+ #define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3)
+ #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4)
++#define GPIOHANDLE_REQUEST_PASS_THROUGH (1UL << 5)
+
+ /**
+ * struct gpiohandle_request - Information about a GPIO handle request
+--
+2.19.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch
new file mode 100644
index 000000000..901d63645
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch
@@ -0,0 +1,105 @@
+From ca4f6555620212ffccd943ea4c58e7ee7b1b0571 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 7 Mar 2019 15:17:40 -0800
+Subject: [PATCH] Add bus-timeout-ms and #retries device tree properties
+
+BMC uses I2C bus 7 as a PMBus channel to communicate with PSUs,
+also ME uses this bus as SMLink to control PSUs so this bus is
+managed by multi-masters. In this use case, some arbitration errors
+are expected so we need to add retry logic. And PMBus subsystem
+uses I2C bus in kernel internally so retry logic should be
+supported in kernel level.
+
+To support the use case, this commit adds 'bus-timeout-ms' and
+'#retries' device tree properties to set the bus specific
+parameters at kernel boot time without using any additional ioctls
+from user space.
+
+This patch would not be accepted by I2C maintainer in linux
+upstream because he doesn't like adding these legacy properties
+into device tree, so keep it only in downstream.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ Documentation/devicetree/bindings/i2c/i2c-aspeed.txt | 3 +++
+ Documentation/devicetree/bindings/i2c/i2c.txt | 6 ++++++
+ drivers/i2c/busses/i2c-aspeed.c | 1 -
+ drivers/i2c/i2c-core-base.c | 12 ++++++++++--
+ 4 files changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+index 8fbd8633a387..7da7e813b2b0 100644
+--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+@@ -16,6 +16,9 @@ Optional Properties:
+ - bus-frequency : frequency of the bus clock in Hz defaults to 100 kHz when not
+ specified
+ - multi-master : states that there is another master active on this bus.
++- bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not
++ specified.
++- #retries : Number of retries for master transfer.
+
+ Example:
+
+diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
+index 11263982470e..bdead91f82a4 100644
+--- a/Documentation/devicetree/bindings/i2c/i2c.txt
++++ b/Documentation/devicetree/bindings/i2c/i2c.txt
+@@ -80,6 +80,12 @@ wants to support one of the below features, it should adapt the bindings below.
+ Names of map programmable addresses.
+ It can contain any map needing another address than default one.
+
++- bus-timeout-ms
++ Bus timeout in milliseconds.
++
++- #retries
++ Number of retries for master transfer.
++
+ Binding may contain optional "interrupts" property, describing interrupts
+ used by the device. I2C core will assign "irq" interrupt (or the very first
+ interrupt if not using interrupt names) as primary interrupt for the slave.
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index 506d867b43d9..84237c5d0aca 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -1012,7 +1012,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+ spin_lock_init(&bus->lock);
+ init_completion(&bus->cmd_complete);
+ bus->adap.owner = THIS_MODULE;
+- bus->adap.retries = 0;
+ bus->adap.algo = &aspeed_i2c_algo;
+ bus->adap.dev.parent = &pdev->dev;
+ bus->adap.dev.of_node = pdev->dev.of_node;
+diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
+index 728b818501b1..17cf0fb037ac 100644
+--- a/drivers/i2c/i2c-core-base.c
++++ b/drivers/i2c/i2c-core-base.c
+@@ -1232,6 +1232,7 @@ static void i2c_adapter_hold_timer_callback(struct timer_list *t)
+
+ static int i2c_register_adapter(struct i2c_adapter *adap)
+ {
++ u32 bus_timeout_ms = 0;
+ int res = -EINVAL;
+
+ /* Can't register until after driver model init */
+@@ -1258,8 +1259,15 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
+ INIT_LIST_HEAD(&adap->userspace_clients);
+
+ /* Set default timeout to 1 second if not already set */
+- if (adap->timeout == 0)
+- adap->timeout = HZ;
++ if (adap->timeout == 0) {
++ device_property_read_u32(&adap->dev, "bus-timeout-ms",
++ &bus_timeout_ms);
++ adap->timeout = bus_timeout_ms ?
++ msecs_to_jiffies(bus_timeout_ms) : HZ;
++ }
++
++ /* Set retries count if it has the property setting */
++ device_property_read_u32(&adap->dev, "#retries", &adap->retries);
+
+ /* register soft irqs for Host Notify */
+ res = i2c_setup_host_notify_irq_domain(adap);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch
new file mode 100644
index 000000000..f04824c0e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch
@@ -0,0 +1,140 @@
+From d82aacea62f2cc3f5c4f6654bd8920255edf24fd Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 13 Mar 2019 15:04:16 -0700
+Subject: [PATCH] char: ipmi: Add clock control logic into Aspeed LPC BT driver
+
+If LPC BT driver is registered ahead of lpc-ctrl module, LPC BT
+block will be enabled without heart beating of LCLK until lpc-ctrl
+enables the LCLK. This issue causes improper handling on host
+interrupts when the host sends interrupt in that time frame. Then
+kernel eventually forcibly disables the interrupt with dumping
+stack and printing a 'nobody cared this irq' message out.
+
+To prevent this issue, all LPC sub-nodes should enable LCLK
+individually so this patch adds clock control logic into the LPC
+BT driver.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ .../bindings/ipmi/aspeed,ast2400-ibt-bmc.txt | 3 +++
+ arch/arm/boot/dts/aspeed-g4.dtsi | 1 +
+ arch/arm/boot/dts/aspeed-g5.dtsi | 1 +
+ drivers/char/ipmi/bt-bmc.c | 24 +++++++++++++++++++++-
+ 4 files changed, 28 insertions(+), 1 deletion(-)
+
+diff --git a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt
+index 028268fd99ee..d13887d60f19 100644
+--- a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt
++++ b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt
+@@ -10,6 +10,8 @@ Required properties:
+ "aspeed,ast2400-ibt-bmc"
+ "aspeed,ast2500-ibt-bmc"
+ - reg: physical address and size of the registers
++- clocks: contains a phandle to the syscon node describing the clocks.
++ There should then be one cell representing the clock to use.
+
+ Optional properties:
+
+@@ -22,4 +24,5 @@ Example:
+ compatible = "aspeed,ast2400-ibt-bmc";
+ reg = <0x1e789140 0x18>;
+ interrupts = <8>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ };
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index 6e6f50a0fbab..3a7e31f3de07 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -333,6 +333,7 @@
+ ibt: ibt@c0 {
+ compatible = "aspeed,ast2400-ibt-bmc";
+ reg = <0xc0 0x18>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ interrupts = <8>;
+ };
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index 4cd4a8258e42..a6720bc952b0 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -468,6 +468,7 @@
+ ibt: ibt@c0 {
+ compatible = "aspeed,ast2500-ibt-bmc";
+ reg = <0xc0 0x18>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ interrupts = <8>;
+ };
+
+diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
+index 40b9927c072c..a4ec9d1743d7 100644
+--- a/drivers/char/ipmi/bt-bmc.c
++++ b/drivers/char/ipmi/bt-bmc.c
+@@ -5,6 +5,7 @@
+
+ #include <linux/atomic.h>
+ #include <linux/bt-bmc.h>
++#include <linux/clk.h>
+ #include <linux/errno.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+@@ -60,6 +61,7 @@ struct bt_bmc {
+ struct device dev;
+ struct miscdevice miscdev;
+ struct regmap *map;
++ struct clk *clk;
+ int offset;
+ int irq;
+ wait_queue_head_t queue;
+@@ -467,6 +469,19 @@ static int bt_bmc_probe(struct platform_device *pdev)
+ mutex_init(&bt_bmc->mutex);
+ init_waitqueue_head(&bt_bmc->queue);
+
++ bt_bmc->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(bt_bmc->clk)) {
++ rc = PTR_ERR(bt_bmc->clk);
++ if (rc != -EPROBE_DEFER)
++ dev_err(dev, "couldn't get clock\n");
++ return rc;
++ }
++ rc = clk_prepare_enable(bt_bmc->clk);
++ if (rc) {
++ dev_err(dev, "couldn't enable clock\n");
++ return rc;
++ }
++
+ bt_bmc->miscdev.minor = MISC_DYNAMIC_MINOR,
+ bt_bmc->miscdev.name = DEVICE_NAME,
+ bt_bmc->miscdev.fops = &bt_bmc_fops,
+@@ -474,7 +489,7 @@ static int bt_bmc_probe(struct platform_device *pdev)
+ rc = misc_register(&bt_bmc->miscdev);
+ if (rc) {
+ dev_err(dev, "Unable to register misc device\n");
+- return rc;
++ goto err;
+ }
+
+ bt_bmc_config_irq(bt_bmc, pdev);
+@@ -498,6 +513,11 @@ static int bt_bmc_probe(struct platform_device *pdev)
+ clr_b_busy(bt_bmc);
+
+ return 0;
++
++err:
++ clk_disable_unprepare(bt_bmc->clk);
++
++ return rc;
+ }
+
+ static int bt_bmc_remove(struct platform_device *pdev)
+@@ -507,6 +527,8 @@ static int bt_bmc_remove(struct platform_device *pdev)
+ misc_deregister(&bt_bmc->miscdev);
+ if (!bt_bmc->irq)
+ del_timer_sync(&bt_bmc->poll_timer);
++ clk_disable_unprepare(bt_bmc->clk);
++
+ return 0;
+ }
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch
new file mode 100644
index 000000000..0559ef5be
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch
@@ -0,0 +1,125 @@
+From 1ebca05f5cb04162e124e59cac701291f23d9091 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 13 Mar 2019 15:27:48 -0700
+Subject: [PATCH] misc: Add clock control logic into Aspeed LPC SNOOP driver
+
+If LPC SNOOP driver is registered ahead of lpc-ctrl module, LPC
+SNOOP block will be enabled without heart beating of LCLK until
+lpc-ctrl enables the LCLK. This issue causes improper handling on
+host interrupts when the host sends interrupt in that time frame.
+Then kernel eventually forcibly disables the interrupt with
+dumping stack and printing a 'nobody cared this irq' message out.
+
+To prevent this issue, all LPC sub-nodes should enable LCLK
+individually so this patch adds clock control logic into the LPC
+SNOOP driver.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g4.dtsi | 1 +
+ arch/arm/boot/dts/aspeed-g5.dtsi | 1 +
+ drivers/misc/aspeed-lpc-snoop.c | 30 +++++++++++++++++++++++++++---
+ 3 files changed, 29 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index 3a7e31f3de07..bedfb77c0158 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -316,6 +316,7 @@
+ compatible = "aspeed,ast2400-lpc-snoop";
+ reg = <0x0 0x80>;
+ interrupts = <8>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index a6720bc952b0..a26e8b3c09bf 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -451,6 +451,7 @@
+ compatible = "aspeed,ast2500-lpc-snoop";
+ reg = <0x0 0x80>;
+ interrupts = <8>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+
+diff --git a/drivers/misc/aspeed-lpc-snoop.c b/drivers/misc/aspeed-lpc-snoop.c
+index 2feb4347d67f..39a0471f0b8f 100644
+--- a/drivers/misc/aspeed-lpc-snoop.c
++++ b/drivers/misc/aspeed-lpc-snoop.c
+@@ -15,6 +15,7 @@
+ */
+
+ #include <linux/bitops.h>
++#include <linux/clk.h>
+ #include <linux/interrupt.h>
+ #include <linux/fs.h>
+ #include <linux/kfifo.h>
+@@ -71,6 +72,7 @@ struct aspeed_lpc_snoop_channel {
+ struct aspeed_lpc_snoop {
+ struct regmap *regmap;
+ int irq;
++ struct clk *clk;
+ struct aspeed_lpc_snoop_channel chan[NUM_SNOOP_CHANNELS];
+ };
+
+@@ -286,22 +288,42 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev)
+ return -ENODEV;
+ }
+
++ lpc_snoop->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(lpc_snoop->clk)) {
++ rc = PTR_ERR(lpc_snoop->clk);
++ if (rc != -EPROBE_DEFER)
++ dev_err(dev, "couldn't get clock\n");
++ return rc;
++ }
++ rc = clk_prepare_enable(lpc_snoop->clk);
++ if (rc) {
++ dev_err(dev, "couldn't enable clock\n");
++ return rc;
++ }
++
+ rc = aspeed_lpc_snoop_config_irq(lpc_snoop, pdev);
+ if (rc)
+- return rc;
++ goto err;
+
+ rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 0, port);
+ if (rc)
+- return rc;
++ goto err;
+
+ /* Configuration of 2nd snoop channel port is optional */
+ if (of_property_read_u32_index(dev->of_node, "snoop-ports",
+ 1, &port) == 0) {
+ rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 1, port);
+- if (rc)
++ if (rc) {
+ aspeed_lpc_disable_snoop(lpc_snoop, 0);
++ goto err;
++ }
+ }
+
++ return 0;
++
++err:
++ clk_disable_unprepare(lpc_snoop->clk);
++
+ return rc;
+ }
+
+@@ -313,6 +335,8 @@ static int aspeed_lpc_snoop_remove(struct platform_device *pdev)
+ aspeed_lpc_disable_snoop(lpc_snoop, 0);
+ aspeed_lpc_disable_snoop(lpc_snoop, 1);
+
++ clk_disable_unprepare(lpc_snoop->clk);
++
+ return 0;
+ }
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch
new file mode 100644
index 000000000..d9b6d05f9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch
@@ -0,0 +1,235 @@
+From 1326920183042bb91583eb56dabd29ec921f8f65 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 13 Mar 2019 15:36:34 -0700
+Subject: [PATCH] char: ipmi: Add clock control logic into Aspeed LPC KCS
+ driver
+
+If LPC KCS driver is registered ahead of lpc-ctrl module, LPC KCS
+block will be enabled without heart beating of LCLK until lpc-ctrl
+enables the LCLK. This issue causes improper handling on host
+interrupts when the host sends interrupt in that time frame. Then
+kernel eventually forcibly disables the interrupt with dumping
+stack and printing a 'nobody cared this irq' message out.
+
+To prevent this issue, all LPC sub-nodes should enable LCLK
+individually so this patch adds clock control logic into the LPC
+KCS driver.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ .../devicetree/bindings/ipmi/aspeed-kcs-bmc.txt | 3 ++
+ arch/arm/boot/dts/aspeed-g4.dtsi | 35 ++++++++++++++++++++
+ arch/arm/boot/dts/aspeed-g5.dtsi | 6 +++-
+ drivers/char/ipmi/kcs_bmc_aspeed.c | 37 ++++++++++++++++++----
+ 4 files changed, 73 insertions(+), 8 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
+index d98a9bf45d6c..3453eb0bf8f2 100644
+--- a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
++++ b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
+@@ -9,6 +9,8 @@ Required properties:
+ "aspeed,ast2400-kcs-bmc"
+ "aspeed,ast2500-kcs-bmc"
+ - interrupts : interrupt generated by the controller
++- clocks: contains a phandle to the syscon node describing the clocks.
++ There should then be one cell representing the clock to use.
+ - kcs_chan : The LPC channel number in the controller
+ - kcs_addr : The host CPU IO map address
+
+@@ -19,6 +21,7 @@ Example:
+ compatible = "aspeed,ast2500-kcs-bmc";
+ reg = <0x0 0x80>;
+ interrupts = <8>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ kcs_chan = <3>;
+ kcs_addr = <0xCA2>;
+ status = "okay";
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index bedfb77c0158..a5072ed1f823 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -294,6 +294,33 @@
+ lpc_bmc: lpc-bmc@0 {
+ compatible = "aspeed,ast2400-lpc-bmc";
+ reg = <0x0 0x80>;
++ reg-io-width = <4>;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges = <0x0 0x0 0x80>;
++
++ kcs1: kcs1@0 {
++ compatible = "aspeed,ast2400-kcs-bmc";
++ interrupts = <8>;
++ kcs_chan = <1>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
++ kcs2: kcs2@0 {
++ compatible = "aspeed,ast2400-kcs-bmc";
++ interrupts = <8>;
++ kcs_chan = <2>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
++ kcs3: kcs3@0 {
++ compatible = "aspeed,ast2400-kcs-bmc";
++ interrupts = <8>;
++ kcs_chan = <3>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
+ };
+
+ lpc_host: lpc-host@80 {
+@@ -305,6 +332,14 @@
+ #size-cells = <1>;
+ ranges = <0x0 0x80 0x1e0>;
+
++ kcs4: kcs4@0 {
++ compatible = "aspeed,ast2400-kcs-bmc";
++ interrupts = <8>;
++ kcs_chan = <4>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
++
+ lpc_ctrl: lpc-ctrl@0 {
+ compatible = "aspeed,ast2400-lpc-ctrl";
+ reg = <0x0 0x80>;
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index a26e8b3c09bf..6a2f161e7548 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -128,7 +128,7 @@
+ };
+
+ vic: interrupt-controller@1e6c0080 {
+- compatible = "aspeed,ast2400-vic";
++ compatible = "aspeed,ast2500-vic";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ valid-sources = <0xfefff7ff 0x0807ffff>;
+@@ -408,18 +408,21 @@
+ compatible = "aspeed,ast2500-kcs-bmc";
+ interrupts = <8>;
+ kcs_chan = <1>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+ kcs2: kcs2@0 {
+ compatible = "aspeed,ast2500-kcs-bmc";
+ interrupts = <8>;
+ kcs_chan = <2>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+ kcs3: kcs3@0 {
+ compatible = "aspeed,ast2500-kcs-bmc";
+ interrupts = <8>;
+ kcs_chan = <3>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+ };
+@@ -437,6 +440,7 @@
+ compatible = "aspeed,ast2500-kcs-bmc";
+ interrupts = <8>;
+ kcs_chan = <4>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+
+diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c
+index 3c955946e647..bd1912dc5a21 100644
+--- a/drivers/char/ipmi/kcs_bmc_aspeed.c
++++ b/drivers/char/ipmi/kcs_bmc_aspeed.c
+@@ -1,11 +1,10 @@
+ // SPDX-License-Identifier: GPL-2.0
+-/*
+- * Copyright (c) 2015-2018, Intel Corporation.
+- */
++// Copyright (c) 2015-2019, Intel Corporation.
+
+ #define pr_fmt(fmt) "aspeed-kcs-bmc: " fmt
+
+ #include <linux/atomic.h>
++#include <linux/clk.h>
+ #include <linux/errno.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+@@ -63,6 +62,7 @@
+
+ struct aspeed_kcs_bmc {
+ struct regmap *map;
++ struct clk *clk;
+ };
+
+
+@@ -264,36 +264,59 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
+ return -ENODEV;
+ }
+
++ priv->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(priv->clk)) {
++ rc = PTR_ERR(priv->clk);
++ if (rc != -EPROBE_DEFER)
++ dev_err(dev, "couldn't get clock\n");
++ return rc;
++ }
++ rc = clk_prepare_enable(priv->clk);
++ if (rc) {
++ dev_err(dev, "couldn't enable clock\n");
++ return rc;
++ }
++
+ kcs_bmc->ioreg = ast_kcs_bmc_ioregs[chan - 1];
+ kcs_bmc->io_inputb = aspeed_kcs_inb;
+ kcs_bmc->io_outputb = aspeed_kcs_outb;
+
+ dev_set_drvdata(dev, kcs_bmc);
+
+- aspeed_kcs_set_address(kcs_bmc, addr);
+- aspeed_kcs_enable_channel(kcs_bmc, true);
+ rc = aspeed_kcs_config_irq(kcs_bmc, pdev);
+ if (rc)
+- return rc;
++ goto err;
+
+ rc = misc_register(&kcs_bmc->miscdev);
+ if (rc) {
+ dev_err(dev, "Unable to register device\n");
+- return rc;
++ goto err;
+ }
+
++ aspeed_kcs_set_address(kcs_bmc, addr);
++ aspeed_kcs_enable_channel(kcs_bmc, true);
++
+ pr_info("channel=%u addr=0x%x idr=0x%x odr=0x%x str=0x%x\n",
+ chan, addr,
+ kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str);
+
+ return 0;
++
++err:
++ aspeed_kcs_enable_channel(kcs_bmc, false);
++ clk_disable_unprepare(priv->clk);
++
++ return rc;
+ }
+
+ static int aspeed_kcs_remove(struct platform_device *pdev)
+ {
+ struct kcs_bmc *kcs_bmc = dev_get_drvdata(&pdev->dev);
++ struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+
+ misc_deregister(&kcs_bmc->miscdev);
++ aspeed_kcs_enable_channel(kcs_bmc, false);
++ clk_disable_unprepare(priv->clk);
+
+ return 0;
+ }
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0046-misc-Add-clock-control-logic-into-Aspeed-LPC-MBOX-dr.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0046-misc-Add-clock-control-logic-into-Aspeed-LPC-MBOX-dr.patch
new file mode 100644
index 000000000..220283e24
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0046-misc-Add-clock-control-logic-into-Aspeed-LPC-MBOX-dr.patch
@@ -0,0 +1,166 @@
+From db310b43e5b444a4e2854f3d69d002c2f0d0605c Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 13 Mar 2019 15:53:24 -0700
+Subject: [PATCH] misc: Add clock control logic into Aspeed LPC MBOX driver
+
+If LPC MBOX driver is registered ahead of lpc-ctrl module, LPC
+MBOX block will be enabled without heart beating of LCLK until
+lpc-ctrl enables the LCLK. This issue causes improper handling on
+host interrupts when the host sends interrupt in that time frame.
+Then kernel eventually forcibly disables the interrupt with dumping
+stack and printing a 'nobody cared this irq' message out.
+
+To prevent this issue, all LPC sub-nodes should enable LCLK
+individually so this patch adds clock control logic into the LPC
+MBOX driver.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g4.dtsi | 1 +
+ arch/arm/boot/dts/aspeed-g5.dtsi | 1 +
+ drivers/misc/aspeed-lpc-mbox.c | 42 +++++++++++++++++++++++++++++++---------
+ 3 files changed, 35 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index a5072ed1f823..729245b74c13 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -389,6 +389,7 @@
+ reg = <0x180 0x5c>;
+ interrupts = <46>;
+ #mbox-cells = <1>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+ };
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index 6a2f161e7548..df9d63a94264 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -493,6 +493,7 @@
+ reg = <0x180 0x5c>;
+ interrupts = <46>;
+ #mbox-cells = <1>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+ };
+diff --git a/drivers/misc/aspeed-lpc-mbox.c b/drivers/misc/aspeed-lpc-mbox.c
+index 0933e0553953..f105d27786ac 100644
+--- a/drivers/misc/aspeed-lpc-mbox.c
++++ b/drivers/misc/aspeed-lpc-mbox.c
+@@ -7,6 +7,7 @@
+ * 2 of the License, or (at your option) any later version.
+ */
+
++#include <linux/clk.h>
+ #include <linux/interrupt.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/miscdevice.h>
+@@ -37,7 +38,9 @@
+ struct aspeed_mbox {
+ struct miscdevice miscdev;
+ struct regmap *regmap;
++ struct clk *clk;
+ unsigned int base;
++ int irq;
+ wait_queue_head_t queue;
+ struct mutex mutex;
+ };
+@@ -237,16 +240,16 @@ static int aspeed_mbox_config_irq(struct aspeed_mbox *mbox,
+ struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+- int rc, irq;
++ int rc;
+
+- irq = irq_of_parse_and_map(dev->of_node, 0);
+- if (!irq)
++ mbox->irq = platform_get_irq(pdev, 0);
++ if (!mbox->irq)
+ return -ENODEV;
+
+- rc = devm_request_irq(dev, irq, aspeed_mbox_irq,
+- IRQF_SHARED, DEVICE_NAME, mbox);
++ rc = devm_request_irq(dev, mbox->irq, aspeed_mbox_irq,
++ IRQF_SHARED, DEVICE_NAME, mbox);
+ if (rc < 0) {
+- dev_err(dev, "Unable to request IRQ %d\n", irq);
++ dev_err(dev, "Unable to request IRQ %d\n", mbox->irq);
+ return rc;
+ }
+
+@@ -301,6 +304,19 @@ static int aspeed_mbox_probe(struct platform_device *pdev)
+ mutex_init(&mbox->mutex);
+ init_waitqueue_head(&mbox->queue);
+
++ mbox->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(mbox->clk)) {
++ rc = PTR_ERR(mbox->clk);
++ if (rc != -EPROBE_DEFER)
++ dev_err(dev, "couldn't get clock\n");
++ return rc;
++ }
++ rc = clk_prepare_enable(mbox->clk);
++ if (rc) {
++ dev_err(dev, "couldn't enable clock\n");
++ return rc;
++ }
++
+ mbox->miscdev.minor = MISC_DYNAMIC_MINOR;
+ mbox->miscdev.name = DEVICE_NAME;
+ mbox->miscdev.fops = &aspeed_mbox_fops;
+@@ -308,17 +324,24 @@ static int aspeed_mbox_probe(struct platform_device *pdev)
+ rc = misc_register(&mbox->miscdev);
+ if (rc) {
+ dev_err(dev, "Unable to register device\n");
+- return rc;
++ goto err;
+ }
+
+ rc = aspeed_mbox_config_irq(mbox, pdev);
+ if (rc) {
+ dev_err(dev, "Failed to configure IRQ\n");
+ misc_deregister(&mbox->miscdev);
+- return rc;
++ goto err;
+ }
+
++ dev_info(&pdev->dev, "LPC mbox registered, irq %d\n", mbox->irq);
++
+ return 0;
++
++err:
++ clk_disable_unprepare(mbox->clk);
++
++ return rc;
+ }
+
+ static int aspeed_mbox_remove(struct platform_device *pdev)
+@@ -326,6 +349,7 @@ static int aspeed_mbox_remove(struct platform_device *pdev)
+ struct aspeed_mbox *mbox = dev_get_drvdata(&pdev->dev);
+
+ misc_deregister(&mbox->miscdev);
++ clk_disable_unprepare(mbox->clk);
+
+ return 0;
+ }
+@@ -335,6 +359,7 @@ static const struct of_device_id aspeed_mbox_match[] = {
+ { .compatible = "aspeed,ast2500-mbox" },
+ { },
+ };
++MODULE_DEVICE_TABLE(of, aspeed_mbox_match);
+
+ static struct platform_driver aspeed_mbox_driver = {
+ .driver = {
+@@ -347,7 +372,6 @@ static struct platform_driver aspeed_mbox_driver = {
+
+ module_platform_driver(aspeed_mbox_driver);
+
+-MODULE_DEVICE_TABLE(of, aspeed_mbox_match);
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>");
+ MODULE_DESCRIPTION("Aspeed mailbox device driver");
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch
new file mode 100644
index 000000000..40c26e31b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch
@@ -0,0 +1,43 @@
+From 4762687044ec864719ca14d8efa3dccdc3807e70 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 13 Mar 2019 15:57:08 -0700
+Subject: [PATCH] misc: Block error printing on probe defer case in Aspeed LPC
+ ctrl
+
+This commit adds a checking code when it gets -EPROBE_DEFER while
+getting a clock resource. In this case it doesn't need to print
+out an error message because the probing will be re-visited.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/misc/aspeed-lpc-ctrl.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/misc/aspeed-lpc-ctrl.c b/drivers/misc/aspeed-lpc-ctrl.c
+index a024f8042259..c0818c7b0ffb 100644
+--- a/drivers/misc/aspeed-lpc-ctrl.c
++++ b/drivers/misc/aspeed-lpc-ctrl.c
+@@ -239,8 +239,10 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
+
+ lpc_ctrl->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(lpc_ctrl->clk)) {
+- dev_err(dev, "couldn't get clock\n");
+- return PTR_ERR(lpc_ctrl->clk);
++ rc = PTR_ERR(lpc_ctrl->clk);
++ if (rc != -EPROBE_DEFER)
++ dev_err(dev, "couldn't get clock\n");
++ return rc;
+ }
+ rc = clk_prepare_enable(lpc_ctrl->clk);
+ if (rc) {
+@@ -264,6 +266,7 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
+
+ err:
+ clk_disable_unprepare(lpc_ctrl->clk);
++
+ return rc;
+ }
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0048-ARM-dts-aspeed-Set-default-status-of-LPC-BT-as-disab.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0048-ARM-dts-aspeed-Set-default-status-of-LPC-BT-as-disab.patch
new file mode 100644
index 000000000..efbea1be8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0048-ARM-dts-aspeed-Set-default-status-of-LPC-BT-as-disab.patch
@@ -0,0 +1,40 @@
+From abf63c03805bf7df31133b720e165eab759ea702 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 14 Mar 2019 13:11:49 -0700
+Subject: [PATCH] ARM: dts: aspeed: Set default status of LPC BT as 'disabled'
+
+LPC BT is not widely used so set its default status as 'disabled'.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g4.dtsi | 1 +
+ arch/arm/boot/dts/aspeed-g5.dtsi | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index 729245b74c13..d4e1e29c6ed2 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -371,6 +371,7 @@
+ reg = <0xc0 0x18>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ interrupts = <8>;
++ status = "disabled";
+ };
+
+ sio_regs: regs {
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index df9d63a94264..a3850644b10e 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -475,6 +475,7 @@
+ reg = <0xc0 0x18>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ interrupts = <8>;
++ status = "disabled";
+ };
+
+ sio_regs: regs {
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg
new file mode 100644
index 000000000..41530dd6e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg
@@ -0,0 +1 @@
+CONFIG_BLK_DEV_RAM=y
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend
new file mode 100644
index 000000000..1e25709a9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend
@@ -0,0 +1,38 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+do_compile_prepend(){
+ # device tree compiler flags
+ export DTC_FLAGS=-@
+}
+
+SRC_URI += " \
+ file://intel.cfg \
+ file://0005-arm-dts-aspeed-g5-add-espi.patch \
+ file://0007-New-flash-map-for-intel.patch \
+ file://0008-Add-ASPEED-SGPIO-driver.patch \
+ file://0009-SGPIO-DT-and-pinctrl-fixup.patch \
+ file://0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch \
+ file://0019-Add-I2C-IPMB-support.patch \
+ file://0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch \
+ file://0022-Add-AST2500-eSPI-driver.patch \
+ file://0026-Add-support-for-new-PECI-commands.patch \
+ file://0028-Add-AST2500-JTAG-driver.patch \
+ file://0029-i2c-aspeed-Improve-driver-to-support-multi-master-us.patch \
+ file://0030-Add-dump-debug-code-into-I2C-drivers.patch \
+ file://0031-Add-high-speed-baud-rate-support-for-UART.patch \
+ file://0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch \
+ file://0034-arm-dts-adpeed-Swap-the-mac-nodes-numbering.patch \
+ file://0035-Implement-a-memory-driver-share-memory.patch \
+ file://0036-net-ncsi-backport-ncsi-patches.patch \
+ file://0038-media-aspeed-backport-ikvm-patches.patch \
+ file://0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch \
+ file://0040-i2c-Add-mux-hold-unhold-msg-types.patch \
+ file://0041-Enable-passthrough-based-gpio-character-device.patch \
+ file://0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch \
+ file://0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch \
+ file://0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch \
+ file://0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch \
+ file://0046-misc-Add-clock-control-logic-into-Aspeed-LPC-MBOX-dr.patch \
+ file://0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch \
+ file://0048-ARM-dts-aspeed-Set-default-status-of-LPC-BT-as-disab.patch \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-libc-headers/0001-Enable-passthrough-based-gpio-character-device.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-libc-headers/0001-Enable-passthrough-based-gpio-character-device.patch
new file mode 100644
index 000000000..15e845ebc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-libc-headers/0001-Enable-passthrough-based-gpio-character-device.patch
@@ -0,0 +1,26 @@
+From 61a5796d151337fd537d1aeb3fb072dcdf96abbe Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Sun, 3 Feb 2019 16:08:11 +0800
+Subject: [PATCH] Enable passthrough based gpio character device.
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ include/uapi/linux/gpio.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h
+index 1bf6e6df..8883ca90 100644
+--- a/include/uapi/linux/gpio.h
++++ b/include/uapi/linux/gpio.h
+@@ -62,7 +62,7 @@ struct gpioline_info {
+ #define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2)
+ #define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3)
+ #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4)
+-
++#define GPIOHANDLE_REQUEST_PASS_THROUGH (1UL << 5)
+ /**
+ * struct gpiohandle_request - Information about a GPIO handle request
+ * @lineoffsets: an array desired lines, specified by offset index for the
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-libc-headers_%.bbappend b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-libc-headers_%.bbappend
new file mode 100644
index 000000000..703af71df
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-libc-headers_%.bbappend
@@ -0,0 +1,5 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += " \
+ file://0001-Enable-passthrough-based-gpio-character-device.patch \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/network/0001-Patch-to-keep-consistent-MAC-and-IP-address-inbetwee.patch b/meta-openbmc-mods/meta-common/recipes-network/network/network/0001-Patch-to-keep-consistent-MAC-and-IP-address-inbetwee.patch
new file mode 100644
index 000000000..03460302d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/network/0001-Patch-to-keep-consistent-MAC-and-IP-address-inbetwee.patch
@@ -0,0 +1,456 @@
+From 15f9ba436815307c1df7ace505e6f6ee04a4762b Mon Sep 17 00:00:00 2001
+From: David Cobbley <david.j.cobbley@linux.intel.com>
+Date: Thu, 8 Mar 2018 12:18:00 -0800
+Subject: [PATCH 1/3] Patch to keep consistent MAC and IP address inbetween
+ power cycles
+
+Currently, your mac will reset upon AC cycle unless you ask systemd use
+a MAC provided in your network configuration file. This will write your
+randomly generate MAC to the config file upond first boot up.
+
+Change-Id: Id47d24c62e459cde101add18be2f46c0b010e7fe
+Signed-off-by: David Cobbley <david.j.cobbley@linux.intel.com>
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+---
+ ethernet_interface.cpp | 4 +-
+ ethernet_interface.hpp | 360 +++++++++++++++++++++--------------------
+ network_config.cpp | 22 +--
+ 3 files changed, 195 insertions(+), 191 deletions(-)
+
+diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
+index 3fd7835..fd09b7a 100644
+--- a/ethernet_interface.cpp
++++ b/ethernet_interface.cpp
+@@ -200,8 +200,8 @@ InterfaceInfo EthernetInterface::getInterfaceInfo() const
+ * @return macaddress on success
+ */
+
+-std::string
+- EthernetInterface::getMACAddress(const std::string& interfaceName) const
++std::string EthernetInterface::getMACAddress(
++ const std::string& interfaceName)
+ {
+ ifreq ifr{};
+ char macAddress[mac_address::size]{};
+diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp
+index bfe1d54..d62ca34 100644
+--- a/ethernet_interface.hpp
++++ b/ethernet_interface.hpp
+@@ -59,185 +59,187 @@ using VlanInterfaceMap =
+ */
+ class EthernetInterface : public Ifaces
+ {
+- public:
+- EthernetInterface() = delete;
+- EthernetInterface(const EthernetInterface&) = delete;
+- EthernetInterface& operator=(const EthernetInterface&) = delete;
+- EthernetInterface(EthernetInterface&&) = delete;
+- EthernetInterface& operator=(EthernetInterface&&) = delete;
+- virtual ~EthernetInterface() = default;
+-
+- /** @brief Constructor to put object onto bus at a dbus path.
+- * @param[in] bus - Bus to attach to.
+- * @param[in] objPath - Path to attach at.
+- * @param[in] dhcpEnabled - is dhcp enabled(true/false).
+- * @param[in] parent - parent object.
+- * @param[in] emitSignal - true if the object added signal needs to be
+- * send.
+- */
+- EthernetInterface(sdbusplus::bus::bus& bus, const std::string& objPath,
+- bool dhcpEnabled, Manager& parent,
+- bool emitSignal = true);
+-
+- /** @brief Function to create ipaddress dbus object.
+- * @param[in] addressType - Type of ip address.
+- * @param[in] ipaddress- IP address.
+- * @param[in] prefixLength - Length of prefix.
+- * @param[in] gateway - Gateway ip address.
+- */
+-
+- void iP(IP::Protocol addressType, std::string ipaddress,
+- uint8_t prefixLength, std::string gateway) override;
+-
+- /* @brief delete the dbus object of the given ipaddress.
+- * @param[in] ipaddress - IP address.
+- */
+- void deleteObject(const std::string& ipaddress);
+-
+- /* @brief delete the vlan dbus object of the given interface.
+- * Also deletes the device file and the network file.
+- * @param[in] interface - VLAN Interface.
+- */
+- void deleteVLANObject(const std::string& interface);
+-
+- /* @brief creates the dbus object(IPaddres) given in the address list.
+- * @param[in] addrs - address list for which dbus objects needs
+- * to create.
+- */
+- void createIPAddressObjects();
+-
+- /* @brief Gets all the ip addresses.
+- * @returns the list of ipaddress.
+- */
+- const AddressMap& getAddresses() const
+- {
+- return addrs;
+- }
+-
+- /** Set value of DHCPEnabled */
+- bool dHCPEnabled(bool value) override;
+-
+- /** @brief sets the MAC address.
+- * @param[in] value - MAC address which needs to be set on the system.
+- * @returns macAddress of the interface or throws an error.
+- */
+- std::string mACAddress(std::string value) override;
+-
+- /** @brief sets the NTP servers.
+- * @param[in] value - vector of NTP servers.
+- */
+- ServerList nTPServers(ServerList value) override;
+-
+- /** @brief sets the DNS/nameservers.
+- * @param[in] value - vector of DNS servers.
+- */
+- ServerList nameservers(ServerList value) override;
+-
+- /** @brief create Vlan interface.
+- * @param[in] id- VLAN identifier.
+- */
+- void createVLAN(VlanId id);
+-
+- /** @brief load the vlan info from the system
+- * and creates the ip address dbus objects.
+- * @param[in] vlanID- VLAN identifier.
+- */
+- void loadVLAN(VlanId vlanID);
+-
+- /** @brief write the network conf file with the in-memory objects.
+- */
+- void writeConfigurationFile();
+-
+- /** @brief delete all dbus objects.
+- */
+- void deleteAll();
+-
+- using EthernetInterfaceIntf::dHCPEnabled;
+- using EthernetInterfaceIntf::interfaceName;
+- using MacAddressIntf::mACAddress;
+-
+- /** @brief Absolute path of the resolv conf file */
+- static constexpr auto resolvConfFile = "/etc/resolv.conf";
+-
+- protected:
+- /** @brief get the info of the ethernet interface.
+- * @return tuple having the link speed,autonegotiation,duplexmode .
+- */
+- InterfaceInfo getInterfaceInfo() const;
+-
+- /* @brief delete the vlan interface from system.
+- * @param[in] interface - vlan Interface.
+- */
+- void deleteVLANFromSystem(const std::string& interface);
+-
+- /** @brief get the mac address of the interface.
+- * @param[in] interfaceName - Network interface name.
+- * @return macaddress on success
+- */
+-
+- std::string getMACAddress(const std::string& interfaceName) const;
+-
+- /** @brief construct the ip address dbus object path.
+- * @param[in] addressType - Type of ip address.
+- * @param[in] ipaddress - IP address.
+- * @param[in] prefixLength - Length of prefix.
+- * @param[in] gateway - Gateway address.
+-
+- * @return path of the address object.
+- */
+-
+- std::string generateObjectPath(IP::Protocol addressType,
+- const std::string& ipaddress,
+- uint8_t prefixLength,
+- const std::string& gateway) const;
+-
+- /** @brief generates the id by doing hash of ipaddress,
+- * prefixlength and the gateway.
+- * @param[in] ipaddress - IP address.
+- * @param[in] prefixLength - Length of prefix.
+- * @param[in] gateway - Gateway address.
+- * @return hash string.
+- */
+-
+- static std::string generateId(const std::string& ipaddress,
+- uint8_t prefixLength,
+- const std::string& gateway);
+-
+- /** @brief write the dhcp section **/
+- void writeDHCPSection(std::fstream& stream);
+-
+- /** @brief get the NTP server list from the network conf
+- *
+- */
+- ServerList getNTPServersFromConf();
+-
+- /** @brief write the DNS entries to resolver file.
+- * @param[in] dnsList - DNS server list which needs to be written.
+- * @param[in] file - File to write the name server entries to.
+- */
+- void writeDNSEntries(const ServerList& dnsList, const std::string& file);
+-
+- /** @brief get the name server details from the network conf
+- *
+- */
+- ServerList getNameServerFromConf();
+-
+- /** @brief Persistent sdbusplus DBus bus connection. */
+- sdbusplus::bus::bus& bus;
+-
+- /** @brief Network Manager object. */
+- Manager& manager;
+-
+- /** @brief Persistent map of IPAddress dbus objects and their names */
+- AddressMap addrs;
+-
+- /** @brief Persistent map of VLAN interface dbus objects and their names */
+- VlanInterfaceMap vlanInterfaces;
+-
+- /** @brief Dbus object path */
+- std::string objPath;
+-
+- friend class TestEthernetInterface;
++ public:
++ EthernetInterface() = delete;
++ EthernetInterface(const EthernetInterface&) = delete;
++ EthernetInterface& operator=(const EthernetInterface&) = delete;
++ EthernetInterface(EthernetInterface&&) = delete;
++ EthernetInterface& operator=(EthernetInterface&&) = delete;
++ virtual ~EthernetInterface() = default;
++
++ /** @brief Constructor to put object onto bus at a dbus path.
++ * @param[in] bus - Bus to attach to.
++ * @param[in] objPath - Path to attach at.
++ * @param[in] dhcpEnabled - is dhcp enabled(true/false).
++ * @param[in] parent - parent object.
++ * @param[in] emitSignal - true if the object added signal needs to be
++ * send.
++ */
++ EthernetInterface(sdbusplus::bus::bus& bus,
++ const std::string& objPath,
++ bool dhcpEnabled,
++ Manager& parent,
++ bool emitSignal = true);
++
++ /** @brief Function to create ipaddress dbus object.
++ * @param[in] addressType - Type of ip address.
++ * @param[in] ipaddress- IP address.
++ * @param[in] prefixLength - Length of prefix.
++ * @param[in] gateway - Gateway ip address.
++ */
++
++ void iP(IP::Protocol addressType,
++ std::string ipaddress,
++ uint8_t prefixLength,
++ std::string gateway) override;
++
++ /* @brief delete the dbus object of the given ipaddress.
++ * @param[in] ipaddress - IP address.
++ */
++ void deleteObject(const std::string& ipaddress);
++
++ /* @brief delete the vlan dbus object of the given interface.
++ * Also deletes the device file and the network file.
++ * @param[in] interface - VLAN Interface.
++ */
++ void deleteVLANObject(const std::string& interface);
++
++ /* @brief creates the dbus object(IPaddres) given in the address list.
++ * @param[in] addrs - address list for which dbus objects needs
++ * to create.
++ */
++ void createIPAddressObjects();
++
++ /* @brief Gets all the ip addresses.
++ * @returns the list of ipaddress.
++ */
++ const AddressMap& getAddresses() const { return addrs; }
++
++ /** Set value of DHCPEnabled */
++ bool dHCPEnabled(bool value) override;
++
++ /** @brief sets the MAC address.
++ * @param[in] value - MAC address which needs to be set on the system.
++ * @returns macAddress of the interface or throws an error.
++ */
++ std::string mACAddress(std::string value) override;
++
++ /** @brief sets the NTP servers.
++ * @param[in] value - vector of NTP servers.
++ */
++ ServerList nTPServers(ServerList value) override;
++
++ /** @brief sets the DNS/nameservers.
++ * @param[in] value - vector of DNS servers.
++ */
++ ServerList nameservers(ServerList value) override;
++
++ /** @brief create Vlan interface.
++ * @param[in] id- VLAN identifier.
++ */
++ void createVLAN(VlanId id);
++
++ /** @brief load the vlan info from the system
++ * and creates the ip address dbus objects.
++ * @param[in] vlanID- VLAN identifier.
++ */
++ void loadVLAN(VlanId vlanID);
++
++ /** @brief write the network conf file with the in-memory objects.
++ */
++ void writeConfigurationFile();
++
++ /** @brief delete all dbus objects.
++ */
++ void deleteAll();
++
++ /** @brief get the mac address of the interface.
++ * @param[in] interfaceName - Network interface name.
++ * @return macaddress on success
++ */
++
++ static std::string getMACAddress(const std::string& interfaceName);
++
++ using EthernetInterfaceIntf::dHCPEnabled;
++ using EthernetInterfaceIntf::interfaceName;
++ using MacAddressIntf::mACAddress;
++
++ /** @brief Absolute path of the resolv conf file */
++ static constexpr auto resolvConfFile = "/etc/resolv.conf";
++
++ protected:
++ /** @brief get the info of the ethernet interface.
++ * @return tuple having the link speed,autonegotiation,duplexmode .
++ */
++ InterfaceInfo getInterfaceInfo() const;
++
++ /* @brief delete the vlan interface from system.
++ * @param[in] interface - vlan Interface.
++ */
++ void deleteVLANFromSystem(const std::string& interface);
++
++ /** @brief construct the ip address dbus object path.
++ * @param[in] addressType - Type of ip address.
++ * @param[in] ipaddress - IP address.
++ * @param[in] prefixLength - Length of prefix.
++ * @param[in] gateway - Gateway address.
++
++ * @return path of the address object.
++ */
++
++ std::string generateObjectPath(IP::Protocol addressType,
++ const std::string& ipaddress,
++ uint8_t prefixLength,
++ const std::string& gateway) const;
++
++ /** @brief generates the id by doing hash of ipaddress,
++ * prefixlength and the gateway.
++ * @param[in] ipaddress - IP address.
++ * @param[in] prefixLength - Length of prefix.
++ * @param[in] gateway - Gateway address.
++ * @return hash string.
++ */
++
++ static std::string generateId(const std::string& ipaddress,
++ uint8_t prefixLength,
++ const std::string& gateway);
++
++ /** @brief write the dhcp section **/
++ void writeDHCPSection(std::fstream& stream);;
++
++ /** @brief get the NTP server list from the network conf
++ *
++ */
++ ServerList getNTPServersFromConf();
++
++ /** @brief write the DNS entries to resolver file.
++ * @param[in] dnsList - DNS server list which needs to be written.
++ * @param[in] file - File to write the name server entries to.
++ */
++ void writeDNSEntries(const ServerList& dnsList,
++ const std::string& file);
++
++ /** @brief get the name server details from the network conf
++ *
++ */
++ ServerList getNameServerFromConf();
++
++ /** @brief Persistent sdbusplus DBus bus connection. */
++ sdbusplus::bus::bus& bus;
++
++ /** @brief Network Manager object. */
++ Manager& manager;
++
++ /** @brief Persistent map of IPAddress dbus objects and their names */
++ AddressMap addrs;
++
++ /** @brief Persistent map of VLAN interface dbus objects and their names */
++ VlanInterfaceMap vlanInterfaces;
++
++ /** @brief Dbus object path */
++ std::string objPath;
++
++ friend class TestEthernetInterface;
+ };
+
+ } // namespace network
+diff --git a/network_config.cpp b/network_config.cpp
+index e83b16c..8ebad54 100644
+--- a/network_config.cpp
++++ b/network_config.cpp
+@@ -1,3 +1,5 @@
++#include "network_config.hpp"
++#include "ethernet_interface.hpp"
+ #include "config.h"
+
+ #include "network_config.hpp"
+@@ -5,27 +7,27 @@
+ #include <fstream>
+ #include <string>
+
+-namespace phosphor
+-{
+-namespace network
+-{
++namespace phosphor {
++namespace network {
+
+-namespace bmc
+-{
+-void writeDHCPDefault(const std::string& filename, const std::string& interface)
++namespace bmc {
++void writeDHCPDefault(const std::string &filename, const std::string &interface)
+ {
++
+ std::ofstream filestream;
+
+ filestream.open(filename);
+ filestream << "[Match]\nName=" << interface <<
+- "\n[Network]\nDHCP=true\n"
++ "\n[Network]\nDHCP=true\n"
+ #ifdef LINK_LOCAL_AUTOCONFIGURATION
+ "LinkLocalAddressing=yes\n"
+ #else
+ "LinkLocalAddressing=no\n"
+ #endif
+- "IPv6AcceptRA=false\n"
+- "[DHCP]\nClientIdentifier=mac\n";
++ "IPv6AcceptRA=false\n"
++ "[DHCP]\nClientIdentifier=mac\n"
++ "[Link]\nMACAddress="
++ << EthernetInterface::getMACAddress(interface) << "\n";
+ filestream.close();
+ }
+ } // namespace bmc
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/network/0002-IPv6-Network-changes-to-configuration-file.patch b/meta-openbmc-mods/meta-common/recipes-network/network/network/0002-IPv6-Network-changes-to-configuration-file.patch
new file mode 100644
index 000000000..251f68319
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/network/0002-IPv6-Network-changes-to-configuration-file.patch
@@ -0,0 +1,210 @@
+From ebb359773b8a5c03a25c3a48c5080bb246c07c71 Mon Sep 17 00:00:00 2001
+From: David Cobbley <david.j.cobbley@linux.intel.com>
+Date: Wed, 6 Jun 2018 11:11:43 -0700
+Subject: [PATCH 2/3] IPv6 Network changes to configuration file
+
+Allow Additional parameters to be set for IPv6
+
+Change-Id: If662f1ce2d265bc525073890c49231bf6f2b8a30
+---
+ ethernet_interface.cpp | 109 +++++++++++++++++++++++++++++++++++++++--
+ ethernet_interface.hpp | 19 ++++++-
+ util.cpp | 3 +-
+ 3 files changed, 124 insertions(+), 7 deletions(-)
+
+diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
+index fd09b7a..63f1160 100644
+--- a/ethernet_interface.cpp
++++ b/ethernet_interface.cpp
+@@ -46,6 +46,8 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
+ std::replace(intfName.begin(), intfName.end(), '_', '.');
+ interfaceName(intfName);
+ EthernetInterfaceIntf::dHCPEnabled(dhcpEnabled);
++ EthernetInterfaceIntf::iPAddressEnables(getIPAddressEnablesFromConf());
++ EthernetInterfaceIntf::iPv6AcceptRA(getIPv6AcceptRAFromConf());
+ MacAddressIntf::mACAddress(getMACAddress(intfName));
+ EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
+ EthernetInterfaceIntf::nameservers(getNameServerFromConf());
+@@ -322,7 +324,16 @@ std::string EthernetInterface::generateObjectPath(
+ objectPath /= generateId(ipaddress, prefixLength, gateway);
+ return objectPath.string();
+ }
+-
++bool EthernetInterface::iPv6AcceptRA(bool value)
++{
++ if (value == EthernetInterfaceIntf::iPv6AcceptRA())
++ {
++ return value;
++ }
++ EthernetInterfaceIntf::iPv6AcceptRA(value);
++ manager.writeToConfigurationFile();
++ return value;
++}
+ bool EthernetInterface::dHCPEnabled(bool value)
+ {
+ if (value == EthernetInterfaceIntf::dHCPEnabled())
+@@ -433,7 +444,80 @@ void EthernetInterface::createVLAN(VlanId id)
+ // write the new vlan device entry to the configuration(network) file.
+ manager.writeToConfigurationFile();
+ }
++bool EthernetInterface::getIPv6AcceptRAFromConf()
++{
++ fs::path confPath = manager.getConfDir();
++
++ std::string fileName = systemd::config::networkFilePrefix +
++ interfaceName() + systemd::config::networkFileSuffix;
++ confPath /= fileName;
++ config::ValueList values;
++ config::Parser parser(confPath.string());
++ auto rc = config::ReturnCode::SUCCESS;
++ std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
++ if (rc != config::ReturnCode::SUCCESS)
++ {
++ log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
++ entry("rc=%d", rc));
++ return false;
++ }
++ if (values[0] == "true")
++ {
++ return true;
++ }
++
++ return false;
++}
++EthernetInterface::IPAllowed EthernetInterface::getIPAddressEnablesFromConf()
++{
++ fs::path confPath = manager.getConfDir();
++
++ std::string fileName = systemd::config::networkFilePrefix +
++ interfaceName() + systemd::config::networkFileSuffix;
++ confPath /= fileName;
++ config::ValueList values;
++ config::Parser parser(confPath.string());
++ auto rc = config::ReturnCode::SUCCESS;
++ std::tie(rc, values) = parser.getValues("Network", "DHCP");
++ if (rc != config::ReturnCode::SUCCESS)
++ {
++ log<level::DEBUG>("Unable to get the value for Network[DHCP]",
++ entry("rc=%d", rc));
++ return EthernetInterface::IPAllowed::IPv4AndIPv6;
++ }
++ // true, false, ipv4, ipv6
++ if (values[0] == "ipv6")
++ {
++ return EthernetInterface::IPAllowed::IPv6Only;
++ }
++ else if (values[0] == "ipv4")
++ {
++ return EthernetInterface::IPAllowed::IPv4Only;
++ }
++ else if (values[0] == "off")
++ {
++ // This function should not get called if DHCP == off
++ log<level::DEBUG>("Function not available in static mode");
++ return EthernetInterface::IPAllowed::IPv4AndIPv6;
++ }
++ else
++ {
++ return EthernetInterface::IPAllowed::IPv4AndIPv6;
++ }
++}
++EthernetInterface::IPAllowed
++ EthernetInterface::iPAddressEnables(EthernetInterface::IPAllowed iPAllowed)
++{
++ if (iPAllowed == EthernetInterfaceIntf::iPAddressEnables())
++ {
++ return iPAllowed;
++ }
++
++ EthernetInterfaceIntf::iPAddressEnables(iPAllowed);
++ writeConfigurationFile();
+
++ return iPAllowed;
++}
+ ServerList EthernetInterface::getNTPServersFromConf()
+ {
+ fs::path confPath = manager.getConfDir();
+@@ -515,7 +599,8 @@ void EthernetInterface::writeConfigurationFile()
+ #else
+ stream << "LinkLocalAddressing=no\n";
+ #endif
+- stream << "IPv6AcceptRA=false\n";
++ stream << std::boolalpha
++ << "IPv6AcceptRA=" << EthernetInterfaceIntf::iPv6AcceptRA() << "\n";
+
+ // Add the VLAN entry
+ for (const auto& intf : vlanInterfaces)
+@@ -524,8 +609,24 @@ void EthernetInterface::writeConfigurationFile()
+ << "\n";
+ }
+ // Add the DHCP entry
+- auto value = dHCPEnabled() ? "true"s : "false"s;
+- stream << "DHCP="s + value + "\n";
++ std::string dhcpValue = "false";
++ if (dHCPEnabled())
++ {
++ IPAllowed ipAllowed = EthernetInterfaceIntf::iPAddressEnables();
++ if (ipAllowed == IPAllowed::IPv4AndIPv6)
++ {
++ dhcpValue = "true";
++ }
++ else if (ipAllowed == IPAllowed::IPv4Only)
++ {
++ dhcpValue = "ipv4";
++ }
++ else if (ipAllowed == IPAllowed::IPv6Only)
++ {
++ dhcpValue = "ipv6";
++ }
++ }
++ stream << "DHCP=" << dhcpValue << "\n";
+
+ // When the interface configured as dhcp, we don't need below given entries
+ // in config file.
+diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp
+index d62ca34..7116b47 100644
+--- a/ethernet_interface.hpp
++++ b/ethernet_interface.hpp
+@@ -205,7 +205,24 @@ class EthernetInterface : public Ifaces
+ const std::string& gateway);
+
+ /** @brief write the dhcp section **/
+- void writeDHCPSection(std::fstream& stream);;
++ void writeDHCPSection(std::fstream& stream);
++
++ /** @brief get the IPv6AcceptRA flag from the network configuration file
++ *
++ */
++ bool getIPv6AcceptRAFromConf();
++
++ /** @brief check conf file for Router Advertisements
++ *
++ */
++ bool iPv6AcceptRA(bool value) override;
++
++ /** @brief get the allowed network modes. Similar to DHCP enabled, but
++ * more specific
++ */
++ IPAllowed getIPAddressEnablesFromConf();
++
++ IPAllowed iPAddressEnables(IPAllowed) override;
+
+ /** @brief get the NTP server list from the network conf
+ *
+diff --git a/util.cpp b/util.cpp
+index b66f908..9f06e2e 100644
+--- a/util.cpp
++++ b/util.cpp
+@@ -405,8 +405,7 @@ bool getDHCPValue(const std::string& confDir, const std::string& intf)
+ entry("RC=%d", rc));
+ return dhcp;
+ }
+- // There will be only single value for DHCP key.
+- if (values[0] == "true")
++ if (values[0] != "false")
+ {
+ dhcp = true;
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/network/0003-Adding-channel-specific-privilege-to-network.patch b/meta-openbmc-mods/meta-common/recipes-network/network/network/0003-Adding-channel-specific-privilege-to-network.patch
new file mode 100755
index 000000000..4610b8b32
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/network/0003-Adding-channel-specific-privilege-to-network.patch
@@ -0,0 +1,800 @@
+From 64fff77b31de705a42c5061e9d14946255c6aca1 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Wed, 5 Sep 2018 14:16:54 +0530
+Subject: [PATCH] Adding channel specific privilege to network
+
+ - Adding the channel access information to the network
+ interface object. This privilege will be used in
+ channel specific authorization.
+ - Get supported priv from user manager service dynamically.
+ - Signal handling for capturing the supported priv list
+ changes from user managerment.
+
+Tested-by:
+Verified channel access through ipmitool get/set channel
+access command
+
+Change-Id: I3b592a19363eef684e31d5f7c34dad8f2f9211df
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ ethernet_interface.cpp | 119 +++++++++++++-
+ ethernet_interface.hpp | 433 ++++++++++++++++++++++++++-----------------------
+ network_manager.cpp | 104 ++++++++++++
+ network_manager.hpp | 9 +
+ 4 files changed, 464 insertions(+), 201 deletions(-)
+
+diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
+index 9437b4c..6d23b3d 100644
+--- a/ethernet_interface.cpp
++++ b/ethernet_interface.cpp
+@@ -35,6 +35,9 @@ using namespace phosphor::logging;
+ using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+ using Argument = xyz::openbmc_project::Common::InvalidArgument;
+
++static constexpr const char* networkChannelCfgFile =
++ "/var/channel_intf_data.json";
++static constexpr const char* defaultChannelPriv = "priv-admin";
+ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
+ const std::string& objPath,
+ bool dhcpEnabled, Manager& parent,
+@@ -51,6 +54,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
+ MacAddressIntf::mACAddress(getMACAddress(intfName));
+ EthernetInterfaceIntf::nTPServers(getNTPServersFromConf());
+ EthernetInterfaceIntf::nameservers(getNameServerFromConf());
++ getChannelPrivilege(intfName);
+
+ // Emit deferred signal.
+ if (emitSignal)
+@@ -208,8 +212,7 @@ InterfaceInfo EthernetInterface::getInterfaceInfo() const
+ * @return macaddress on success
+ */
+
+-std::string EthernetInterface::getMACAddress(
+- const std::string& interfaceName)
++std::string EthernetInterface::getMACAddress(const std::string& interfaceName)
+ {
+ ifreq ifr{};
+ char macAddress[mac_address::size]{};
+@@ -829,5 +832,117 @@ void EthernetInterface::deleteAll()
+ manager.writeToConfigurationFile();
+ }
+
++nlohmann::json EthernetInterface::readJsonFile(const std::string& configFile)
++{
++ std::ifstream jsonFile(configFile);
++ if (!jsonFile.good())
++ {
++ log<level::ERR>("JSON file not found");
++ return nullptr;
++ }
++
++ nlohmann::json data = nullptr;
++ try
++ {
++ data = nlohmann::json::parse(jsonFile, nullptr, false);
++ }
++ catch (nlohmann::json::parse_error& e)
++ {
++ log<level::DEBUG>("Corrupted channel config.",
++ entry("MSG: %s", e.what()));
++ throw std::runtime_error("Corrupted channel config file");
++ }
++
++ return data;
++}
++
++int EthernetInterface::writeJsonFile(const std::string& configFile,
++ const nlohmann::json& jsonData)
++{
++ std::ofstream jsonFile(configFile);
++ if (!jsonFile.good())
++ {
++ log<level::ERR>("JSON file open failed",
++ entry("FILE=%s", networkChannelCfgFile));
++ return -1;
++ }
++
++ // Write JSON to file
++ jsonFile << jsonData;
++
++ jsonFile.flush();
++ return 0;
++}
++
++std::string
++ EthernetInterface::getChannelPrivilege(const std::string& interfaceName)
++{
++ std::string priv(defaultChannelPriv);
++ std::string retPriv;
++
++ nlohmann::json jsonData = readJsonFile(networkChannelCfgFile);
++ if (jsonData != nullptr)
++ {
++ try
++ {
++ priv = jsonData[interfaceName].get<std::string>();
++ retPriv = ChannelAccessIntf::maxPrivilege(std::move(priv));
++ return retPriv;
++ }
++ catch (const nlohmann::json::exception& e)
++ {
++ jsonData[interfaceName] = priv;
++ }
++ }
++ else
++ {
++ jsonData[interfaceName] = priv;
++ }
++
++ if (writeJsonFile(networkChannelCfgFile, jsonData) != 0)
++ {
++ log<level::DEBUG>("Error in write JSON data to file",
++ entry("FILE=%s", networkChannelCfgFile));
++ elog<InternalFailure>();
++ }
++
++ retPriv = ChannelAccessIntf::maxPrivilege(std::move(priv));
++
++ return retPriv;
++}
++
++std::string EthernetInterface::maxPrivilege(std::string priv)
++{
++ std::string intfName = interfaceName();
++
++ if (!priv.empty() && (std::find(manager.supportedPrivList.begin(),
++ manager.supportedPrivList.end(),
++ priv) == manager.supportedPrivList.end()))
++ {
++ log<level::ERR>("Invalid privilege");
++ elog<InvalidArgument>(Argument::ARGUMENT_NAME("Privilege"),
++ Argument::ARGUMENT_VALUE(priv.c_str()));
++ }
++
++ if (ChannelAccessIntf::maxPrivilege() == priv)
++ {
++ // No change in privilege so just return.
++ return priv;
++ }
++
++ nlohmann::json jsonData = readJsonFile(networkChannelCfgFile);
++ jsonData[intfName] = priv;
++
++ if (writeJsonFile(networkChannelCfgFile, jsonData) != 0)
++ {
++ log<level::DEBUG>("Error in write JSON data to file",
++ entry("FILE=%s", networkChannelCfgFile));
++ elog<InternalFailure>();
++ }
++
++ // Property change signal will be sent
++ return ChannelAccessIntf::maxPrivilege(std::move(priv));
++}
++
+ } // namespace network
+ } // namespace phosphor
+diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp
+index 7116b47..7b1da9a 100644
+--- a/ethernet_interface.hpp
++++ b/ethernet_interface.hpp
+@@ -2,10 +2,13 @@
+
+ #include "types.hpp"
+ #include "util.hpp"
++#include "xyz/openbmc_project/Channel/ChannelAccess/server.hpp"
+ #include "xyz/openbmc_project/Network/IP/Create/server.hpp"
+
+ #include <experimental/filesystem>
++#include <nlohmann/json.hpp>
+ #include <sdbusplus/bus.hpp>
++#include <sdbusplus/bus/match.hpp>
+ #include <sdbusplus/server/object.hpp>
+ #include <string>
+ #include <xyz/openbmc_project/Collection/DeleteAll/server.hpp>
+@@ -21,7 +24,8 @@ using Ifaces = sdbusplus::server::object::object<
+ sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface,
+ sdbusplus::xyz::openbmc_project::Network::server::MACAddress,
+ sdbusplus::xyz::openbmc_project::Network::IP::server::Create,
+- sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll>;
++ sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll,
++ sdbusplus::xyz::openbmc_project::Channel::server::ChannelAccess>;
+
+ using IP = sdbusplus::xyz::openbmc_project::Network::server::IP;
+
+@@ -29,9 +33,14 @@ using EthernetInterfaceIntf =
+ sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
+ using MacAddressIntf =
+ sdbusplus::xyz::openbmc_project::Network::server::MACAddress;
++using ChannelAccessIntf =
++ sdbusplus::xyz::openbmc_project::Channel::server::ChannelAccess;
+
+ using ServerList = std::vector<std::string>;
+
++using DbusVariant =
++ sdbusplus::message::variant<std::string, std::vector<std::string>>;
++
+ namespace fs = std::experimental::filesystem;
+
+ class Manager; // forward declaration of network manager.
+@@ -59,204 +68,230 @@ using VlanInterfaceMap =
+ */
+ class EthernetInterface : public Ifaces
+ {
+- public:
+- EthernetInterface() = delete;
+- EthernetInterface(const EthernetInterface&) = delete;
+- EthernetInterface& operator=(const EthernetInterface&) = delete;
+- EthernetInterface(EthernetInterface&&) = delete;
+- EthernetInterface& operator=(EthernetInterface&&) = delete;
+- virtual ~EthernetInterface() = default;
+-
+- /** @brief Constructor to put object onto bus at a dbus path.
+- * @param[in] bus - Bus to attach to.
+- * @param[in] objPath - Path to attach at.
+- * @param[in] dhcpEnabled - is dhcp enabled(true/false).
+- * @param[in] parent - parent object.
+- * @param[in] emitSignal - true if the object added signal needs to be
+- * send.
+- */
+- EthernetInterface(sdbusplus::bus::bus& bus,
+- const std::string& objPath,
+- bool dhcpEnabled,
+- Manager& parent,
+- bool emitSignal = true);
+-
+- /** @brief Function to create ipaddress dbus object.
+- * @param[in] addressType - Type of ip address.
+- * @param[in] ipaddress- IP address.
+- * @param[in] prefixLength - Length of prefix.
+- * @param[in] gateway - Gateway ip address.
+- */
+-
+- void iP(IP::Protocol addressType,
+- std::string ipaddress,
+- uint8_t prefixLength,
+- std::string gateway) override;
+-
+- /* @brief delete the dbus object of the given ipaddress.
+- * @param[in] ipaddress - IP address.
+- */
+- void deleteObject(const std::string& ipaddress);
+-
+- /* @brief delete the vlan dbus object of the given interface.
+- * Also deletes the device file and the network file.
+- * @param[in] interface - VLAN Interface.
+- */
+- void deleteVLANObject(const std::string& interface);
+-
+- /* @brief creates the dbus object(IPaddres) given in the address list.
+- * @param[in] addrs - address list for which dbus objects needs
+- * to create.
+- */
+- void createIPAddressObjects();
+-
+- /* @brief Gets all the ip addresses.
+- * @returns the list of ipaddress.
+- */
+- const AddressMap& getAddresses() const { return addrs; }
+-
+- /** Set value of DHCPEnabled */
+- bool dHCPEnabled(bool value) override;
+-
+- /** @brief sets the MAC address.
+- * @param[in] value - MAC address which needs to be set on the system.
+- * @returns macAddress of the interface or throws an error.
+- */
+- std::string mACAddress(std::string value) override;
+-
+- /** @brief sets the NTP servers.
+- * @param[in] value - vector of NTP servers.
+- */
+- ServerList nTPServers(ServerList value) override;
+-
+- /** @brief sets the DNS/nameservers.
+- * @param[in] value - vector of DNS servers.
+- */
+- ServerList nameservers(ServerList value) override;
+-
+- /** @brief create Vlan interface.
+- * @param[in] id- VLAN identifier.
+- */
+- void createVLAN(VlanId id);
+-
+- /** @brief load the vlan info from the system
+- * and creates the ip address dbus objects.
+- * @param[in] vlanID- VLAN identifier.
+- */
+- void loadVLAN(VlanId vlanID);
+-
+- /** @brief write the network conf file with the in-memory objects.
+- */
+- void writeConfigurationFile();
+-
+- /** @brief delete all dbus objects.
+- */
+- void deleteAll();
+-
+- /** @brief get the mac address of the interface.
+- * @param[in] interfaceName - Network interface name.
+- * @return macaddress on success
+- */
+-
+- static std::string getMACAddress(const std::string& interfaceName);
+-
+- using EthernetInterfaceIntf::dHCPEnabled;
+- using EthernetInterfaceIntf::interfaceName;
+- using MacAddressIntf::mACAddress;
+-
+- /** @brief Absolute path of the resolv conf file */
+- static constexpr auto resolvConfFile = "/etc/resolv.conf";
+-
+- protected:
+- /** @brief get the info of the ethernet interface.
+- * @return tuple having the link speed,autonegotiation,duplexmode .
+- */
+- InterfaceInfo getInterfaceInfo() const;
+-
+- /* @brief delete the vlan interface from system.
+- * @param[in] interface - vlan Interface.
+- */
+- void deleteVLANFromSystem(const std::string& interface);
+-
+- /** @brief construct the ip address dbus object path.
+- * @param[in] addressType - Type of ip address.
+- * @param[in] ipaddress - IP address.
+- * @param[in] prefixLength - Length of prefix.
+- * @param[in] gateway - Gateway address.
+-
+- * @return path of the address object.
+- */
+-
+- std::string generateObjectPath(IP::Protocol addressType,
+- const std::string& ipaddress,
+- uint8_t prefixLength,
+- const std::string& gateway) const;
+-
+- /** @brief generates the id by doing hash of ipaddress,
+- * prefixlength and the gateway.
+- * @param[in] ipaddress - IP address.
+- * @param[in] prefixLength - Length of prefix.
+- * @param[in] gateway - Gateway address.
+- * @return hash string.
+- */
+-
+- static std::string generateId(const std::string& ipaddress,
+- uint8_t prefixLength,
+- const std::string& gateway);
+-
+- /** @brief write the dhcp section **/
+- void writeDHCPSection(std::fstream& stream);
+-
+- /** @brief get the IPv6AcceptRA flag from the network configuration file
+- *
+- */
+- bool getIPv6AcceptRAFromConf();
+-
+- /** @brief check conf file for Router Advertisements
+- *
+- */
+- bool iPv6AcceptRA(bool value) override;
+-
+- /** @brief get the allowed network modes. Similar to DHCP enabled, but
+- * more specific
+- */
+- IPAllowed getIPAddressEnablesFromConf();
+-
+- IPAllowed iPAddressEnables(IPAllowed) override;
+-
+- /** @brief get the NTP server list from the network conf
+- *
+- */
+- ServerList getNTPServersFromConf();
+-
+- /** @brief write the DNS entries to resolver file.
+- * @param[in] dnsList - DNS server list which needs to be written.
+- * @param[in] file - File to write the name server entries to.
+- */
+- void writeDNSEntries(const ServerList& dnsList,
+- const std::string& file);
+-
+- /** @brief get the name server details from the network conf
+- *
+- */
+- ServerList getNameServerFromConf();
+-
+- /** @brief Persistent sdbusplus DBus bus connection. */
+- sdbusplus::bus::bus& bus;
+-
+- /** @brief Network Manager object. */
+- Manager& manager;
+-
+- /** @brief Persistent map of IPAddress dbus objects and their names */
+- AddressMap addrs;
+-
+- /** @brief Persistent map of VLAN interface dbus objects and their names */
+- VlanInterfaceMap vlanInterfaces;
+-
+- /** @brief Dbus object path */
+- std::string objPath;
+-
+- friend class TestEthernetInterface;
++ public:
++ EthernetInterface() = delete;
++ EthernetInterface(const EthernetInterface&) = delete;
++ EthernetInterface& operator=(const EthernetInterface&) = delete;
++ EthernetInterface(EthernetInterface&&) = delete;
++ EthernetInterface& operator=(EthernetInterface&&) = delete;
++ virtual ~EthernetInterface() = default;
++
++ /** @brief Constructor to put object onto bus at a dbus path.
++ * @param[in] bus - Bus to attach to.
++ * @param[in] objPath - Path to attach at.
++ * @param[in] dhcpEnabled - is dhcp enabled(true/false).
++ * @param[in] parent - parent object.
++ * @param[in] emitSignal - true if the object added signal needs to be
++ * send.
++ */
++ EthernetInterface(sdbusplus::bus::bus& bus, const std::string& objPath,
++ bool dhcpEnabled, Manager& parent,
++ bool emitSignal = true);
++
++ /** @brief Function to create ipaddress dbus object.
++ * @param[in] addressType - Type of ip address.
++ * @param[in] ipaddress- IP address.
++ * @param[in] prefixLength - Length of prefix.
++ * @param[in] gateway - Gateway ip address.
++ */
++
++ void iP(IP::Protocol addressType, std::string ipaddress,
++ uint8_t prefixLength, std::string gateway) override;
++
++ /* @brief delete the dbus object of the given ipaddress.
++ * @param[in] ipaddress - IP address.
++ */
++ void deleteObject(const std::string& ipaddress);
++
++ /* @brief delete the vlan dbus object of the given interface.
++ * Also deletes the device file and the network file.
++ * @param[in] interface - VLAN Interface.
++ */
++ void deleteVLANObject(const std::string& interface);
++
++ /* @brief creates the dbus object(IPaddres) given in the address list.
++ * @param[in] addrs - address list for which dbus objects needs
++ * to create.
++ */
++ void createIPAddressObjects();
++
++ /* @brief Gets all the ip addresses.
++ * @returns the list of ipaddress.
++ */
++ const AddressMap& getAddresses() const
++ {
++ return addrs;
++ }
++
++ /** Set value of DHCPEnabled */
++ bool dHCPEnabled(bool value) override;
++
++ /** @brief sets the MAC address.
++ * @param[in] value - MAC address which needs to be set on the system.
++ * @returns macAddress of the interface or throws an error.
++ */
++ std::string mACAddress(std::string value) override;
++
++ /** @brief sets the NTP servers.
++ * @param[in] value - vector of NTP servers.
++ */
++ ServerList nTPServers(ServerList value) override;
++
++ /** @brief sets the DNS/nameservers.
++ * @param[in] value - vector of DNS servers.
++ */
++ ServerList nameservers(ServerList value) override;
++
++ /** @brief create Vlan interface.
++ * @param[in] id- VLAN identifier.
++ */
++ void createVLAN(VlanId id);
++
++ /** @brief load the vlan info from the system
++ * and creates the ip address dbus objects.
++ * @param[in] vlanID- VLAN identifier.
++ */
++ void loadVLAN(VlanId vlanID);
++
++ /** @brief write the network conf file with the in-memory objects.
++ */
++ void writeConfigurationFile();
++
++ /** @brief delete all dbus objects.
++ */
++ void deleteAll();
++
++ /** @brief get the mac address of the interface.
++ * @param[in] interfaceName - Network interface name.
++ * @return macaddress on success
++ */
++
++ static std::string getMACAddress(const std::string& interfaceName);
++
++ /** @brief sets the channel maxium privilege.
++ * @param[in] value - Channel privilege which needs to be set on the
++ * system.
++ * @returns privilege of the interface or throws an error.
++ */
++ std::string maxPrivilege(std::string value) override;
++
++ using ChannelAccessIntf::maxPrivilege;
++ using EthernetInterfaceIntf::dHCPEnabled;
++ using EthernetInterfaceIntf::interfaceName;
++ using MacAddressIntf::mACAddress;
++
++ /** @brief Absolute path of the resolv conf file */
++ static constexpr auto resolvConfFile = "/etc/resolv.conf";
++
++ protected:
++ /** @brief get the info of the ethernet interface.
++ * @return tuple having the link speed,autonegotiation,duplexmode .
++ */
++ InterfaceInfo getInterfaceInfo() const;
++
++ /* @brief delete the vlan interface from system.
++ * @param[in] interface - vlan Interface.
++ */
++ void deleteVLANFromSystem(const std::string& interface);
++
++ /** @brief construct the ip address dbus object path.
++ * @param[in] addressType - Type of ip address.
++ * @param[in] ipaddress - IP address.
++ * @param[in] prefixLength - Length of prefix.
++ * @param[in] gateway - Gateway address.
++
++ * @return path of the address object.
++ */
++
++ std::string generateObjectPath(IP::Protocol addressType,
++ const std::string& ipaddress,
++ uint8_t prefixLength,
++ const std::string& gateway) const;
++
++ /** @brief generates the id by doing hash of ipaddress,
++ * prefixlength and the gateway.
++ * @param[in] ipaddress - IP address.
++ * @param[in] prefixLength - Length of prefix.
++ * @param[in] gateway - Gateway address.
++ * @return hash string.
++ */
++
++ static std::string generateId(const std::string& ipaddress,
++ uint8_t prefixLength,
++ const std::string& gateway);
++
++ /** @brief write the dhcp section **/
++ void writeDHCPSection(std::fstream& stream);
++
++ /** @brief get the IPv6AcceptRA flag from the network configuration file
++ *
++ */
++ bool getIPv6AcceptRAFromConf();
++
++ /** @brief check conf file for Router Advertisements
++ *
++ */
++ bool iPv6AcceptRA(bool value) override;
++
++ /** @brief get the allowed network modes. Similar to DHCP enabled, but
++ * more specific
++ */
++ IPAllowed getIPAddressEnablesFromConf();
++
++ IPAllowed iPAddressEnables(IPAllowed) override;
++
++ /** @brief get the NTP server list from the network conf
++ *
++ */
++ ServerList getNTPServersFromConf();
++
++ /** @brief write the DNS entries to resolver file.
++ * @param[in] dnsList - DNS server list which needs to be written.
++ * @param[in] file - File to write the name server entries to.
++ */
++ void writeDNSEntries(const ServerList& dnsList, const std::string& file);
++
++ /** @brief get the name server details from the network conf
++ *
++ */
++ ServerList getNameServerFromConf();
++
++ /** @brief Persistent sdbusplus DBus bus connection. */
++ sdbusplus::bus::bus& bus;
++
++ /** @brief Network Manager object. */
++ Manager& manager;
++
++ /** @brief Persistent map of IPAddress dbus objects and their names */
++ AddressMap addrs;
++
++ /** @brief Persistent map of VLAN interface dbus objects and their names */
++ VlanInterfaceMap vlanInterfaces;
++
++ /** @brief Dbus object path */
++ std::string objPath;
++
++ friend class TestEthernetInterface;
++
++ /** @brief gets the channel privilege.
++ * @param[in] interfaceName - Network interface name.
++ * @returns privilege of the interface
++ */
++ std::string getChannelPrivilege(const std::string& interfaceName);
++
++ /** @brief reads the channel access info from file.
++ * @param[in] configFile - channel access filename
++ * @returns json file data
++ */
++ nlohmann::json readJsonFile(const std::string& configFile);
++
++ /** @brief writes the channel access info to file.
++ * @param[in] configFile - channel access filename
++ * @param[in] jsonData - json data to write
++ * @returns success or failure
++ */
++ int writeJsonFile(const std::string& configFile,
++ const nlohmann::json& jsonData);
+ };
+
+ } // namespace network
+diff --git a/network_manager.cpp b/network_manager.cpp
+index c4ab0da..c573d01 100644
+--- a/network_manager.cpp
++++ b/network_manager.cpp
+@@ -30,6 +30,13 @@ extern std::unique_ptr<Timer> restartTimer;
+ using namespace phosphor::logging;
+ using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+
++static constexpr const char* userMgrObjBasePath = "/xyz/openbmc_project/user";
++static constexpr const char* userMgrInterface =
++ "xyz.openbmc_project.User.Manager";
++static constexpr const char* propNameAllPrivileges = "AllPrivileges";
++
++std::unique_ptr<sdbusplus::bus::match_t> usrMgmtSignal(nullptr);
++
+ Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath,
+ const std::string& path) :
+ details::VLANCreateIface(bus, objPath, true),
+@@ -37,6 +44,103 @@ Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath,
+ {
+ fs::path confDir(path);
+ setConfDir(confDir);
++ initSupportedPrivilges();
++}
++
++std::string getUserService(sdbusplus::bus::bus& bus, const std::string& intf,
++ const std::string& path)
++{
++ auto mapperCall =
++ bus.new_method_call("xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject");
++
++ mapperCall.append(path);
++ mapperCall.append(std::vector<std::string>({intf}));
++
++ auto mapperResponseMsg = bus.call(mapperCall);
++
++ std::map<std::string, std::vector<std::string>> mapperResponse;
++ mapperResponseMsg.read(mapperResponse);
++
++ if (mapperResponse.begin() == mapperResponse.end())
++ {
++ throw std::runtime_error("ERROR in reading the mapper response");
++ }
++
++ return mapperResponse.begin()->first;
++}
++
++std::string Manager::getUserServiceName()
++{
++ static std::string userMgmtService;
++ if (userMgmtService.empty())
++ {
++ try
++ {
++ userMgmtService =
++ getUserService(bus, userMgrInterface, userMgrObjBasePath);
++ }
++ catch (const std::exception& e)
++ {
++ log<level::ERR>("Exception caught in getUserServiceName.");
++ userMgmtService.clear();
++ }
++ }
++ return userMgmtService;
++}
++
++void Manager::initSupportedPrivilges()
++{
++ std::string userServiceName = getUserServiceName();
++ if (!userServiceName.empty())
++ {
++ auto method = bus.new_method_call(
++ getUserServiceName().c_str(), userMgrObjBasePath,
++ "org.freedesktop.DBus.Properties", "Get");
++ method.append(userMgrInterface, propNameAllPrivileges);
++
++ auto reply = bus.call(method);
++ if (reply.is_method_error())
++ {
++ log<level::DEBUG>("get-property AllPrivileges failed",
++ entry("OBJPATH:%s", userMgrObjBasePath),
++ entry("INTERFACE:%s", userMgrInterface));
++ return;
++ }
++
++ sdbusplus::message::variant<std::vector<std::string>> result;
++ reply.read(result);
++
++ supportedPrivList =
++ sdbusplus::message::variant_ns::get<std::vector<std::string>>(
++ result);
++ }
++
++ // Resgister the signal
++ if (usrMgmtSignal == nullptr)
++ {
++ log<level::DEBUG>("Registering User.Manager propertychange signal.");
++ usrMgmtSignal = std::make_unique<sdbusplus::bus::match_t>(
++ bus,
++ sdbusplus::bus::match::rules::propertiesChanged(userMgrObjBasePath,
++ userMgrInterface),
++ [&](sdbusplus::message::message& msg) {
++ log<level::DEBUG>("UserMgr properties changed signal");
++ std::map<std::string, DbusVariant> props;
++ std::string iface;
++ msg.read(iface, props);
++ for (const auto& t : props)
++ {
++ if (t.first == propNameAllPrivileges)
++ {
++ supportedPrivList = sdbusplus::message::variant_ns::get<
++ std::vector<std::string>>(t.second);
++ }
++ }
++ });
++ }
++ return;
+ }
+
+ bool Manager::createDefaultNetworkFiles(bool force)
+diff --git a/network_manager.hpp b/network_manager.hpp
+index e2dfea9..22eef04 100644
+--- a/network_manager.hpp
++++ b/network_manager.hpp
+@@ -137,6 +137,9 @@ class Manager : public details::VLANCreateIface
+ return (interfaces.find(intf) != interfaces.end());
+ }
+
++ /** supported privilege list **/
++ std::vector<std::string> supportedPrivList;
++
+ protected:
+ /** @brief Persistent sdbusplus DBus bus connection. */
+ sdbusplus::bus::bus& bus;
+@@ -159,6 +162,12 @@ class Manager : public details::VLANCreateIface
+
+ /** @brief Network Configuration directory. */
+ fs::path confDir;
++
++ /** Get the user management service name dynamically **/
++ std::string getUserServiceName();
++
++ /** @brief initializes the supportedPrivilege List */
++ void initSupportedPrivilges();
+ };
+
+ } // namespace network
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/network_%.bbappend b/meta-openbmc-mods/meta-common/recipes-network/network/network_%.bbappend
new file mode 100644
index 000000000..275051e19
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/network_%.bbappend
@@ -0,0 +1,9 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+DEPENDS += "nlohmann-json"
+
+SRC_URI += "file://0001-Patch-to-keep-consistent-MAC-and-IP-address-inbetwee.patch \
+ file://0002-IPv6-Network-changes-to-configuration-file.patch \
+ file://0003-Adding-channel-specific-privilege-to-network.patch \
+ "
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/xyz.openbmc_project.CloseMuxes.service b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/xyz.openbmc_project.CloseMuxes.service
new file mode 100644
index 000000000..bc05fa1a1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager/xyz.openbmc_project.CloseMuxes.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Close Muxes
+ConditionFileNotEmpty=/usr/bin/CloseMuxes.py
+
+[Service]
+ExecStart=/usr/bin/env CloseMuxes.py
+Type=oneshot
+
+[Install]
+WantedBy=basic.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend
new file mode 100644
index 000000000..b059a35d7
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend
@@ -0,0 +1,18 @@
+# this is here just to bump faster than upstream
+SRC_URI = "git://github.com/openbmc/entity-manager.git"
+SRCREV = "4133426a04bf46e275416362205bc29c1b3c0935"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+RDEPENDS_${PN} += "python"
+SRC_URI += " file://xyz.openbmc_project.CloseMuxes.service"
+SYSTEMD_SERVICE_${PN} += " xyz.openbmc_project.CloseMuxes.service"
+
+EXTRA_OECMAKE = "-DYOCTO=1 -DUSE_OVERLAYS=0"
+
+do_install_prepend() {
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/scripts/CloseMuxes.py ${D}${bindir}
+ install -d ${D}${base_libdir}/systemd/system
+ install -m 0644 ${WORKDIR}/xyz.openbmc_project.CloseMuxes.service ${D}${base_libdir}/systemd/system
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0002-Modify-Dbus-for-IPv6.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0002-Modify-Dbus-for-IPv6.patch
new file mode 100644
index 000000000..5b86d3154
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0002-Modify-Dbus-for-IPv6.patch
@@ -0,0 +1,55 @@
+From 066ecddebc29a87b05f8c66491eec19bb27d1d33 Mon Sep 17 00:00:00 2001
+From: David Cobbley <david.j.cobbley@linux.intel.com>
+Date: Wed, 6 Jun 2018 10:11:58 -0700
+Subject: [PATCH 3/3] Modify Dbus for IPv6.
+
+Add additional interfaces for IPv6 use.
+---
+ .../Network/EthernetInterface.interface.yaml | 18 ++++++++++++++++++
+ xyz/openbmc_project/Network/IP.interface.yaml | 4 ++++
+ 2 files changed, 22 insertions(+)
+
+diff --git a/xyz/openbmc_project/Network/EthernetInterface.interface.yaml b/xyz/openbmc_project/Network/EthernetInterface.interface.yaml
+index fc744fc..fd19e27 100644
+--- a/xyz/openbmc_project/Network/EthernetInterface.interface.yaml
++++ b/xyz/openbmc_project/Network/EthernetInterface.interface.yaml
+@@ -37,3 +37,21 @@ properties:
+ Implementation of this Dbus-interface is required to implement this property.
+ This property supports read/write operation.
+ Configure the NTP servers on the system during write operation.
++ - name: IPv6AcceptRA
++ type: boolean
++ description: >
++ Boolean for accepting router advertisements in IPv6
++ - name: IPAddressEnables
++ type: enum[self.IPAllowed]
++ description: >
++ The type of IP connection is allowed on this channel
++
++enumerations:
++ - name: IPAllowed
++ description: >
++ Determines whether the system allows both IPv6 & IPv4, or disables on
++ or the other
++ values:
++ - name: IPv4AndIPv6
++ - name: IPv4Only
++ - name: IPv6Only
+diff --git a/xyz/openbmc_project/Network/IP.interface.yaml b/xyz/openbmc_project/Network/IP.interface.yaml
+index 565dcd6..2ffb016 100644
+--- a/xyz/openbmc_project/Network/IP.interface.yaml
++++ b/xyz/openbmc_project/Network/IP.interface.yaml
+@@ -22,6 +22,10 @@ properties:
+ type: string
+ description: >
+ This is the IP gateway for this address.
++ - name: BackupGateway
++ type: string
++ description: >
++ This is the IP address of the backup gateway.
+ - name: Type
+ type: enum[self.Protocol]
+ description: >
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0003-Chassis-Power-Control-are-implemented.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0003-Chassis-Power-Control-are-implemented.patch
new file mode 100644
index 000000000..79d02ca9b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0003-Chassis-Power-Control-are-implemented.patch
@@ -0,0 +1,257 @@
+From 35271230690c5d85dc7a6502031b38d93ddd683f Mon Sep 17 00:00:00 2001
+From: Ed Tanous <ed.tanous@intel.com>
+Date: Thu, 24 Jan 2019 09:29:01 -0800
+Subject: [PATCH] Chassis Power Control are implemented.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Feature level:
+Power on server is ready
+Power off server is ready
+Power cycle server is ready
+Power reset server is ready
+
+Framework level:
+WebUI is enabled.
+IPMI Commands is enabled.
+Restful API is enabled.
+Physical buttons (Power/Reset/ID) are enabled.
+Chassis state manager is enabled.
+Host state manager is enabled.
+
+Enabled IPMI commands:
+ipmitool -H <ip_addr> -P <pass_word> -I lanplus chassis status
+ipmitool -H <ip_addr>  -P <pass_word> -I lanplus chassis power status
+ipmitool -H <ip_addr>  -P <pass_word> -I lanplus chassis power on
+ipmitool -H <ip_addr>  -P <pass_word> -I lanplus chassis power off
+ipmitool -H <ip_addr>  -P <pass_word> -I lanplus chassis power cycle
+ipmitool -H <ip_addr>  -P <pass_word> -I lanplus chassis power reset
+
+Enabled Restful APIs:
+Login: curl --noproxy <ip_addr> -c cjar -b cjar -k -H "Content-Type: application/json" -X POST https://<ip_addr>/login -d "{\"data\": [ \"root\", \"0penBmc\" ] }“
+Host State: curl --noproxy <ip_addr> -b cjar -k https://<ip_addr>/xyz/openbmc_project/state/host0
+Chassis State: curl --noproxy <ip_addr> -b cjar -k https://<ip_addr>/xyz/openbmc_project/state/chassis0
+Power state: curl --noproxy <ip_addr> -b cjar -k https://<ip_addr>/xyz/openbmc_project/Chassis/Control/Power0
+Power on/off: curl --noproxy <ip_addr> -q1c cjar -b cjar -k -H "Content-Type: application/json" -d '{"data": "xyz.openbmc_project.State.Host.Transition.Off"}' -X PUT https://<ip_addr>/xyz/openbmc_project/state/host0/attr/RequestedHostTransition
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ .../Chassis/Control/Chassis.interface.yaml | 94 +++++++++++++++++++
+ .../Chassis/Control/Power.interface.yaml | 85 ++++++++++++++---
+ 2 files changed, 166 insertions(+), 13 deletions(-)
+ create mode 100644 xyz/openbmc_project/Chassis/Control/Chassis.interface.yaml
+
+diff --git a/xyz/openbmc_project/Chassis/Control/Chassis.interface.yaml b/xyz/openbmc_project/Chassis/Control/Chassis.interface.yaml
+new file mode 100644
+index 0000000..c28492a
+--- /dev/null
++++ b/xyz/openbmc_project/Chassis/Control/Chassis.interface.yaml
+@@ -0,0 +1,94 @@
++description: >
++ chassis control service
++methods:
++ - name: powerOn
++ description: >
++ Power on system.
++ returns:
++ - name: state
++ type: int32
++ description: >
++ The result of command.
++ errors:
++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand
++
++ - xyz.openbmc_project.Chassis.Common.Error.IOError
++
++ - name: powerOff
++ description: >
++ Power Off system.
++ returns:
++ - name: state
++ type: int32
++ description: >
++ The result of command.
++ errors:
++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand
++
++ - xyz.openbmc_project.Chassis.Common.Error.IOError
++
++ - name: softPowerOff
++ description: >
++ Soft Power off system.
++ returns:
++ - name: state
++ type: int32
++ description: >
++ The result of command.
++ errors:
++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand
++
++ - xyz.openbmc_project.Chassis.Common.Error.IOError
++
++ - name: reboot
++ description: >
++ reboot system.
++ returns:
++ - name: state
++ type: int32
++ description: >
++ The result of command.
++ errors:
++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand
++
++ - xyz.openbmc_project.Chassis.Common.Error.IOError
++
++ - name: softReboot
++ description: >
++ Soft Reboot system.
++ returns:
++ - name: state
++ type: int32
++ description: >
++ The result of command.
++ errors:
++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand
++
++ - xyz.openbmc_project.Chassis.Common.Error.IOError
++
++ - name: quiesce
++ description: >
++ Quiesce system.
++ returns:
++ - name: state
++ type: int32
++ description: >
++ The result of command.
++ errors:
++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand
++
++ - xyz.openbmc_project.Chassis.Common.Error.IOError
++
++ - name: getPowerState
++ description: >
++ Get system power state.
++ returns:
++ - name: state
++ type: int32
++ description: >
++ The result of command.
++ errors:
++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand
++
++ - xyz.openbmc_project.Chassis.Common.Error.IOError
++
+diff --git a/xyz/openbmc_project/Chassis/Control/Power.interface.yaml b/xyz/openbmc_project/Chassis/Control/Power.interface.yaml
+index 082586f..e77598b 100644
+--- a/xyz/openbmc_project/Chassis/Control/Power.interface.yaml
++++ b/xyz/openbmc_project/Chassis/Control/Power.interface.yaml
+@@ -1,31 +1,90 @@
+ description: >
+- Power control service
++ Chassis control service
+ methods:
++ - name: setPowerState
++ description: >
++ set host power state.
++ parameters:
++ - name: state
++ type: int32
++ description: >
++ 0 for force power off host
++ 1 for power on host
++ returns:
++ - name: status
++ type: int32
++ description: >
++ The result of command.
++ errors:
++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand
++
++ - xyz.openbmc_project.Chassis.Common.Error.IOError
++
++ - name: getPowerState
++ description: >
++ Get current host power status.
++ returns:
++ - name: status
++ type: int32
++ description: >
++ Current host status,
++ 0 for host power off
++ 1 for host power on
++ errors:
++ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand
++
++ - xyz.openbmc_project.Chassis.Common.Error.IOError
++
+ - name: forcePowerOff
+ description: >
+ Force power off the host.
+ returns:
+ - name: status
+- type: boolean
++ type: int32
+ description: >
+ The result of power off command.
+ errors:
+ - xyz.openbmc_project.Chassis.Common.Error.UnsupportedCommand
++
+ - xyz.openbmc_project.Chassis.Common.Error.IOError
+
+ properties:
+- - name: PGood
+- type: boolean
+- default: false
++ - name: vrd_good
++ type: int32
++ default: 0
+ description: >
+- PSU Power good property
+- It is a read-only property.
+- - name: State
++ ACPI status
++ - name: s4s5_state
+ type: int32
+ default: 0
+ description: >
+- System power status
+- 0: power is off
+- 1: power is on
+- Setting its value to change the system state
+- Read its value to get the system state.
+\ No newline at end of file
++ ACPI status
++ - name: pgood
++ type: int32
++ default: 0
++ description: >
++ pgood property
++ - name: state
++ type: int32
++ default: 0
++ description: >
++ state property
++ - name: pgood_timeout
++ type: int32
++ default: 0
++ description: >
++ pgoodtimeout property
++ - name: post_complete
++ type: boolean
++ default: false
++ description: >
++ The current BIOS POST state,
++ false means not completed or system reset,
++ true means BIOS POST completed.
++signals:
++ - name: PowerGood
++ description: >
++ Signal for powergood
++ - name: PowerLost
++ description: >
++ Signal for powerlost
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch
new file mode 100644
index 000000000..7568f8ce9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch
@@ -0,0 +1,120 @@
+From a30a09f58b9ebfb267c0b9cce9ae25994ea025ca Mon Sep 17 00:00:00 2001
+From: cyang29 <cheng.c.yang@intel.com>
+Date: Tue, 17 Jul 2018 16:04:58 +0800
+Subject: [PATCH] Add DBUS interface of CPU and Memory's properties Feature
+ Support: SMBIOS service interface. CPU DIMM information redfish
+ interface. Base on smbios spec DSP0134_3.0.0
+
+Signed-off-by: cyang29 <cheng.c.yang@intel.com>
+---
+ .../Inventory/Item/Cpu.interface.yaml | 41 +++++++++++++++++++
+ .../Inventory/Item/Dimm.interface.yaml | 46 +++++++++++++++++++++-
+ 2 files changed, 86 insertions(+), 1 deletion(-)
+
+diff --git a/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml b/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml
+index ab29cf3..313eada 100644
+--- a/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml
++++ b/xyz/openbmc_project/Inventory/Item/Cpu.interface.yaml
+@@ -1,4 +1,45 @@
+ description: >
+ Implement to provide CPU attributes.
++properties:
++ - name: ProcessorSocket
++ type: string
++ description: >
++ Processor Socket on MotherBoard
++ - name: ProcessorType
++ type: string
++ description: >
++ Processor Type of CPU
++ - name: ProcessorFamily
++ type: string
++ description: >
++ Processor Family of CPU
++ - name: ProcessorManufacturer
++ type: string
++ description: >
++ Processor Manufacturer of CPU
++ - name: ProcessorId
++ type: uint32
++ description: >
++ Processor ID of CPU
++ - name: ProcessorVersion
++ type: string
++ description: >
++ Processor Version of CPU
++ - name: ProcessorMaxSpeed
++ type: uint16
++ description: >
++ Max Speed CPU Can Support
++ - name: ProcessorCharacteristics
++ type: string
++ description: >
++ The Characteristics CPU Has
++ - name: ProcessorCoreCount
++ type: uint16
++ description: >
++ The Count of Core in CPU
++ - name: ProcessorThreadCount
++ type: uint16
++ description: >
++ The Count of Thread CPU Can Support
+
+ # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
+diff --git a/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml b/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml
+index d85326d..b750320 100644
+--- a/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml
++++ b/xyz/openbmc_project/Inventory/Item/Dimm.interface.yaml
+@@ -1,4 +1,48 @@
+ description: >
+ Implement to provide DIMM attributes.
+-
++properties:
++ - name: MemoryDataWidth
++ type: uint16
++ description: >
++ Data width of Memory.
++ - name: MemorySizeInKB
++ type: uint32
++ description: >
++ Memory size of DIMM in Kilobyte.
++ - name: MemoryDeviceLocator
++ type: string
++ description: >
++ Socket on base board where Memory located.
++ - name: MemoryType
++ type: string
++ description: >
++ Type of memory.
++ - name: MemoryTypeDetail
++ type: string
++ description: >
++ Additional detail on Memory.
++ - name: MemorySpeed
++ type: uint16
++ description: >
++ The maximun capable speed of Memory.
++ - name: MemoryManufacturer
++ type: string
++ description: >
++ Manufacturer of memory.
++ - name: MemorySerialNum
++ type: string
++ description: >
++ Memory Serial Number.
++ - name: MemoryPartNum
++ type: string
++ description: >
++ Memory Part Number.
++ - name: MemoryAttributes
++ type: byte
++ description: >
++ Rank attributes of Memory.
++ - name: MemoryConfClockSpeed
++ type: uint16
++ description: >
++ Configured clock speed to Memory.
+ # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0006-dbus-interface-add-boot-option-support-for-floppy-an.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0006-dbus-interface-add-boot-option-support-for-floppy-an.patch
new file mode 100644
index 000000000..f0d7b03f8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0006-dbus-interface-add-boot-option-support-for-floppy-an.patch
@@ -0,0 +1,77 @@
+From 643772fc7f6021fbfba3b14de0c86501ae3e7f3a Mon Sep 17 00:00:00 2001
+From: "Jia, Chunhui" <chunhui.jia@intel.com>
+Date: Fri, 13 Jul 2018 15:22:05 +0800
+Subject: [PATCH] [dbus interface]add boot option support for floppy and USB
+
+Current implementations use ExternalMedia type to specify both CD/DVD/USB
+/Floppy. But in IPMI spec, they are different. CD/DVD type is 0x5 and
+USB/Floppy type is 0xF.
+
+This causes a bug that we can not force BIOS boots into USB/Floppy.
+
+Test:
+$ ipmitool -H 10.239.56.91 -P 0penBmc -I lanplus raw
+ 0x0 0x8 0x5 0x80 0x14 0x00 0x00 0x00
+$ ipmitool -H 10.239.56.91 -P 0penBmc -I lanplus chassis bootparam get 5
+Boot parameter version: 1
+Boot parameter 5 is valid/unlocked
+Boot parameter data: 8014000000
+ Boot Flags :
+ - Boot Flag Valid
+ - Options apply to only next boot
+ - BIOS PC Compatible (legacy) boot
+ - Boot Device Selector : Force Boot from CD/DVD
+ - Console Redirection control : System Default
+ - BIOS verbosity : Console redirection occurs per BIOS
+ configuration setting (default)
+ - BIOS Mux Control Override :
+ BIOS uses recommended setting of the mux at the end of POST
+
+$ipmitool -H 10.239.56.91 -P 0penBmc -I lanplus raw
+ 0x0 0x8 0x5 0x80 0x3c 0x00 0x00 0x00
+$ipmitool -H 10.239.56.91 -P 0penBmc -I lanplus chassis bootparam get 5
+Boot parameter version: 1
+Boot parameter 5 is valid/unlocked
+Boot parameter data: 803c000000
+ Boot Flags :
+ - Boot Flag Valid
+ - Options apply to only next boot
+ - BIOS PC Compatible (legacy) boot
+ - Boot Device Selector : Force Boot from Floppy/primary removable media
+ - Console Redirection control : System Default
+ - BIOS verbosity :
+ Console redirection occurs per BIOS configuration setting (default)
+
+ - BIOS Mux Control Override :
+ BIOS uses recommended setting of the mux at the end of POST
+
+Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com>
+---
+ xyz/openbmc_project/Control/Boot/Source.interface.yaml | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/xyz/openbmc_project/Control/Boot/Source.interface.yaml b/xyz/openbmc_project/Control/Boot/Source.interface.yaml
+index ea811bd..8e5916f 100644
+--- a/xyz/openbmc_project/Control/Boot/Source.interface.yaml
++++ b/xyz/openbmc_project/Control/Boot/Source.interface.yaml
+@@ -15,12 +15,15 @@ enumerations:
+ - name: Disk
+ description: >
+ Boot from the local hard disk.
+- - name: ExternalMedia
++ - name: DVD
+ description: >
+- Boot from CD/DVD/USB, etc.
++ Boot from CD/DVD.
+ - name: Network
+ description: >
+ Boot from a remote source over a network.
+ - name: Default
+ description: >
+ Boot from an implementation defined source.
++ - name: Removable
++ description: >
++ Boot from floppy/primary removable media(USB).
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch
new file mode 100644
index 000000000..c87b2d89d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0007-ipmi-set-BIOS-id.patch
@@ -0,0 +1,32 @@
+From 49debd0955b672d591f35e74119b288bd6df2992 Mon Sep 17 00:00:00 2001
+From: "Jia, Chunhui" <chunhui.jia@intel.com>
+Date: Tue, 24 Jul 2018 11:40:49 +0800
+Subject: [PATCH] [ipmi] set BIOS id
+
+change#2
+add new dbus interface for BIOS attributes
+
+Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com>
+---
+ xyz/openbmc_project/Inventory/Item/Bios.interface.yaml | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+ create mode 100644 xyz/openbmc_project/Inventory/Item/Bios.interface.yaml
+
+diff --git a/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml b/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml
+new file mode 100644
+index 0000000..d7a6b95
+--- /dev/null
++++ b/xyz/openbmc_project/Inventory/Item/Bios.interface.yaml
+@@ -0,0 +1,9 @@
++description: >
++ Implement to provide BIOS attributes.
++properties:
++ - name: BiosId
++ type: string
++ description: >
++ BIOS ID (version) string
++
++# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0009-Add-host-restart-cause-property.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0009-Add-host-restart-cause-property.patch
new file mode 100644
index 000000000..1221a0ab4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0009-Add-host-restart-cause-property.patch
@@ -0,0 +1,98 @@
+From 72b7b30a5dda56c170ee2ce82c1082c26f4663e3 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Tue, 31 Jul 2018 16:55:21 +0800
+Subject: [PATCH] Add host restart cause property.
+
+Add host restart cause property to track the information about what
+action last caused the system to restart.
+According to IPMI Spec, it includes 12 types as following:
+1. Unknown 0x0
+2. IpmiCommand 0x1
+3. ResetButton 0x2
+4. PowerButton 0x3
+5. WatchdogTimer 0x4
+6. OEM 0x5
+7. PowerPolicyAlwaysOn 0x6
+8. PowerPolicyPreviousState 0x7
+9. PEF-Reset 0x8
+10. PEF-PowerCycle 0x9
+11. SoftReset 0xA
+12. RTC-Wakeup 0xB
+
+Change-Id: Id2cc6a18b98e485a978940e5ffc085bf5c4fbed8
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ xyz/openbmc_project/State/Host.interface.yaml | 52 +++++++++++++++++++
+ 1 file changed, 52 insertions(+)
+
+diff --git a/xyz/openbmc_project/State/Host.interface.yaml b/xyz/openbmc_project/State/Host.interface.yaml
+index 8f481b8..a4d88d0 100644
+--- a/xyz/openbmc_project/State/Host.interface.yaml
++++ b/xyz/openbmc_project/State/Host.interface.yaml
+@@ -17,6 +17,12 @@ properties:
+ comparing the CurrentHostState and the RequestedHostTransition
+ properties.
+
++ - name: HostRestartCause
++ type: enum[self.RestartCause]
++ default: Unknown
++ description: >
++ The information about what action last caused the system to restart.
++
+ enumerations:
+ - name: Transition
+ description: >
+@@ -45,3 +51,49 @@ enumerations:
+ - name: 'Quiesced'
+ description: >
+ Host firmware is quiesced
++
++ - name: RestartCause
++ description: >
++ The information about what action last caused the system to restart.
++ values:
++ - name: Unknown
++ description: >
++ System start/restart detected but the reason is unknown.
++ - name: IpmiCommand
++ description: >
++ System start/restart detected and caused by ipmi command.
++ - name: ResetButton
++ description: >
++ System start/restart detected and caused by reset button.
++ - name: PowerButton
++ description: >
++ System start/restart detected and caused by power button.
++ - name: WatchdogTimer
++ description: >
++ System start/restart detected and casued by watchdog expiration.
++ - name: OEM
++ description: >
++ System start/restart detected and caused by OEM command.
++ - name: PowerPolicyAlwaysOn
++ description: >
++ System start/restart detected and caused by power restore policy
++ "chassis always powers up after AC/mains is applied or returns".
++ - name: PowerPolicyPreviousState
++ description: >
++ System start/restart detected and caused by power restore policy
++ "after AC/mains is applied or returns, power is restored to the
++ state was in effect when AC/mains removed or lost".
++ - name: PEFReset
++ description: >
++ System start/restart detected and caused by PEF(reset).
++ - name: PEFPowerCycle
++ description: >
++ System start/restart detected and caused by PEF(power-cycle).
++ - name: SoftReset
++ description: >
++ System start/restart detected and caused by soft reset like
++ "CTRL-ALT-DEL".
++ - name: RTCWakeup
++ description: >
++ System start/restart detected and caused by system real time
++ clock(RTC) wakeup.
+\ No newline at end of file
+--
+2.17.0
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch
new file mode 100644
index 000000000..2c9344306
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0010-Increase-the-default-watchdog-timeout-value.patch
@@ -0,0 +1,34 @@
+From 631deef0ca88a77283741edeae8078d2185f414c Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Fri, 10 Aug 2018 16:23:13 +0800
+Subject: [PATCH] Increase the default watchdog timeout value
+
+The default timeout for poweron is 30 seconds,
+but currently the host power on needs 120+ seconds
+due to unimplemented ipmi commands for BIOS.
+
+Increase the value as a workaround,
+to avoid the watchdog timeout during power on.
+Will adjust this value in the future
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ xyz/openbmc_project/State/Watchdog.interface.yaml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/xyz/openbmc_project/State/Watchdog.interface.yaml b/xyz/openbmc_project/State/Watchdog.interface.yaml
+index f76dbf2..402e1a8 100644
+--- a/xyz/openbmc_project/State/Watchdog.interface.yaml
++++ b/xyz/openbmc_project/State/Watchdog.interface.yaml
+@@ -37,7 +37,7 @@ properties:
+ type: uint64
+ description: >
+ Time interval to arm the watchdog, in milli-second.
+- default: 30000
++ default: 600000
+ - name: TimeRemaining
+ type: uint64
+ description: >
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch
new file mode 100644
index 000000000..9052435ca
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0012-Add-RestoreDelay-interface-for-power-restore-delay.patch
@@ -0,0 +1,34 @@
+From eeac4cf4528994aeb213d549daf4c033ac9d3bbc Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Fri, 24 Aug 2018 17:55:35 +0800
+Subject: [PATCH] Add RestoreDelay interface for power restore delay
+
+Which provide one property "PowerRestoreDelay"
+
+Change-Id: I4e6d3e45948b1e288301b4aa52cc08cace4f1bc2
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ .../Control/Power/RestoreDelay.interface.yaml | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+ create mode 100644 xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml
+
+diff --git a/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml b/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml
+new file mode 100644
+index 0000000..55ee80a
+--- /dev/null
++++ b/xyz/openbmc_project/Control/Power/RestoreDelay.interface.yaml
+@@ -0,0 +1,11 @@
++description: >
++ Implement to specify power transition behavior on a BMC reset.
++ The implementation based on restore policy and set a delay time
++ for power restore.
++
++properties:
++ - name: PowerRestoreDelay
++ type: uint16
++ description: >
++ The delay time for power restore.
++ Power Restore Delay is NOT applied on power policy is "Always Off"
+--
+2.17.0
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch
new file mode 100644
index 000000000..9471c7ab2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch
@@ -0,0 +1,86 @@
+From 7260c24b201759f3a5168eebfee215072c13e641 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Thu, 30 Aug 2018 16:22:43 +0800
+Subject: [PATCH] Add ErrConfig.yaml interface for processor error
+ configuration.
+
+Which provide 3 properties:
+ ResetCfg
+ type: byte
+ description: >
+ Reset Configuration
+ [0]: CATERR Reset Enabled
+ 0b: Disabled
+ 1b: Enabled
+ [1]: ERR2 Reset Enabled
+ 0b: Disabled
+ 1b: Enabled
+ [7:2]: Reserved
+ ResetErrorOccurrenceCounts
+ type: byte
+ description: >
+ Reset Error Occurrence Counts
+ [0]: Reset CPU Error Counts
+ 0b: Keep CPU Error Counts
+ 1b: Reset all CPU Error Counts to zero
+ [7:1]: Reserved
+ CATERRStatus
+ type: array[byte]
+ description: >
+ For all CPUs including the non-legacy socket CPU
+ CPU CATERR (Core Error) occurrence
+ [5:0]: Error Occurrence Count
+ [7:6]: CPU Status
+ 00b: Disabled
+ 01b: Enabled
+ 11b: Not Present
+
+Change-Id: Ibc5a7a5e15c998e56c04e23b1043d99243a91171
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ .../Processor/ErrConfig.interface.yaml | 33 +++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+ create mode 100644 xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml
+
+diff --git a/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml b/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml
+new file mode 100644
+index 0000000..2304263
+--- /dev/null
++++ b/xyz/openbmc_project/Control/Processor/ErrConfig.interface.yaml
+@@ -0,0 +1,33 @@
++description: >
++ This defines processor error configuration.
++properties:
++ - name: ResetCfg
++ type: byte
++ description: >
++ Reset Configuration
++ [0]: CATERR Reset Enabled
++ 0b: Disabled
++ 1b: Enabled
++ [1]: ERR2 Reset Enabled
++ 0b: Disabled
++ 1b: Enabled
++ [7:2]: Reserved
++
++ - name: ResetErrorOccurrenceCounts
++ type: byte
++ description: >
++ Reset Error Occurrence Counts
++ [0]: Reset CPU Error Counts
++ 0b: Keep CPU Error Counts
++ 1b: Reset all CPU Error Counts to zero
++ [7:1]: Reserved
++ - name: CATERRStatus
++ type: array[byte]
++ description: >
++ For all CPUs including the non-legacy socket CPU
++ CPU CATERR (Core Error) occurrence
++ [5:0]: Error Occurrence Count
++ [7:6]: CPU Status
++ 00b: Disabled
++ 01b: Enabled
++ 11b: Not Present
+--
+2.17.0
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0014-Add-multiple-state-signal-for-host-start-and-stop.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0014-Add-multiple-state-signal-for-host-start-and-stop.patch
new file mode 100644
index 000000000..a8d732dab
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0014-Add-multiple-state-signal-for-host-start-and-stop.patch
@@ -0,0 +1,63 @@
+From 6d0069f4a2b4637c58fd321c9db3034ac9dd17c7 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Wed, 12 Sep 2018 15:03:26 +0800
+Subject: [PATCH] Add multiple state signal for host start and stop
+
+Add six host state signals like following:
+ - name: PreHostStart
+ description: >
+ This is the signal to indicate host is at pre start stage.
+ - name: PostHostStart
+ description: >
+ This is the signal to indicate host is at start complete stage.
+ - name: HostStarting
+ description: >
+ This is the signal to indicate host is at starting stage.
+ - name: HostStoping
+ description: >
+ This is the signal to indicate host is at stoping stage.
+ - name: PreHostStop
+ description: >
+ This is the signal to indicate host is at pre stop stage.
+ - name: PostHostStop
+ description: >
+ This is the signal to indicate host is at stop complete stage.
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ xyz/openbmc_project/State/Host.interface.yaml | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/xyz/openbmc_project/State/Host.interface.yaml b/xyz/openbmc_project/State/Host.interface.yaml
+index 8531a27..1ceba13 100644
+--- a/xyz/openbmc_project/State/Host.interface.yaml
++++ b/xyz/openbmc_project/State/Host.interface.yaml
+@@ -96,4 +96,23 @@ enumerations:
+ - name: RTCWakeup
+ description: >
+ System start/restart detected and caused by system real time
+- clock(RTC) wakeup.
+\ No newline at end of file
++ clock(RTC) wakeup.
++signals:
++ - name: PreHostStart
++ description: >
++ This is the signal to indicate host is at pre start stage.
++ - name: PostHostStart
++ description: >
++ This is the signal to indicate host is at start complete stage.
++ - name: HostStarting
++ description: >
++ This is the signal to indicate host is at starting stage.
++ - name: HostStoping
++ description: >
++ This is the signal to indicate host is at stoping stage.
++ - name: PreHostStop
++ description: >
++ This is the signal to indicate host is at pre stop stage.
++ - name: PostHostStop
++ description: >
++ This is the signal to indicate host is at stop complete stage.
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch
new file mode 100644
index 000000000..576bae81a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch
@@ -0,0 +1,227 @@
+From 9490574667485cd407193ff9f0d6a96f8c2c87d3 Mon Sep 17 00:00:00 2001
+From: cyang29 <cheng.c.yang@intel.com>
+Date: Wed, 12 Sep 2018 00:27:23 +0800
+Subject: [PATCH] Add DBUS interface of SMBIOS MDR V2
+
+Support:
+ SMBIOS MDR V2 service interface.
+ SMBIOS MDR V2 IPMI Command
+ SMBIOS MDR V2 Redfish interface.
+Base on SMBIOS spec DSP0134_3.0.0 and Managed Data Region
+Specification Revision 4
+---
+ xyz/openbmc_project/Smbios/MDR_V2.errors.yaml | 9 +
+ xyz/openbmc_project/Smbios/MDR_V2.interface.yaml | 158 +++++++++++++++++++++++
+ xyz/openbmc_project/Smbios/README.md | 21 +++
+ 3 files changed, 188 insertions(+)
+ create mode 100644 xyz/openbmc_project/Smbios/MDR_V2.errors.yaml
+ create mode 100644 xyz/openbmc_project/Smbios/MDR_V2.interface.yaml
+ create mode 100644 xyz/openbmc_project/Smbios/README.md
+
+diff --git a/xyz/openbmc_project/Smbios/MDR_V2.errors.yaml b/xyz/openbmc_project/Smbios/MDR_V2.errors.yaml
+new file mode 100644
+index 0000000..88bd6db
+--- /dev/null
++++ b/xyz/openbmc_project/Smbios/MDR_V2.errors.yaml
+@@ -0,0 +1,9 @@
++- name: InvalidParameter
++ description: >
++ An invalid parameter is attempted.
++- name: UpdateInProgress
++ description: >
++ Update is in progress.
++- name: InvalidId
++ description: >
++ An invalid Id is attempted.
+diff --git a/xyz/openbmc_project/Smbios/MDR_V2.interface.yaml b/xyz/openbmc_project/Smbios/MDR_V2.interface.yaml
+new file mode 100644
+index 0000000..f97700a
+--- /dev/null
++++ b/xyz/openbmc_project/Smbios/MDR_V2.interface.yaml
+@@ -0,0 +1,158 @@
++description: >
++ SMBIOS MDR V2 service
++methods:
++ - name: GetDirectoryInformation
++ description: >
++ Get the directory with directory index.
++ parameters:
++ - name: dirIndex
++ type: byte
++ description: >
++ Directory index of SMBIOS.
++ returns:
++ - name: dir
++ type: array[byte]
++ description: >
++ Directory of agent.
++ errors:
++ - self.Error.InvalidParameter
++
++ - name: GetDataInformation
++ description: >
++ Get the data info with id index and data set ID.
++ parameters:
++ - name: idIndex
++ type: byte
++ description: >
++ Index of SMBIOS directory.
++ returns:
++ - name: dataInfo
++ type: array[byte]
++ description: >
++ Data information of SMBIOS.
++ errors:
++ - self.Error.InvalidParameter
++
++ - name: SendDirectoryInformation
++ description: >
++ Send directory information to SMBIOS directory.
++ parameters:
++ - name: dirVersion
++ type: byte
++ description: >
++ A counter which increments each time directory updated.
++ - name: dirIndex
++ type: byte
++ description: >
++ Directory index of SMBIOS.
++ - name: returnedEntries
++ type: byte
++ description: >
++ Indicates number of directory entries.
++ - name: remainingEntries
++ type: byte
++ description: >
++ Remaining entries which are higher than index in this transfer.
++ - name: dirEntry
++ type: array[byte]
++ description: >
++ Data set ID of SMBIOS table.
++ returns:
++ - name: status
++ type: boolean
++ description: >
++ Need to continue directory transmisson or not.
++ errors:
++ - self.Error.InvalidParameter
++
++ - name: GetDataOffer
++ description: >
++ Get data set ID.
++ returns:
++ - name: offer
++ type: array[byte]
++ description: >
++ Data set ID.
++ errors:
++ - self.Error.UpdateInProgress
++
++ - name: SendDataInformation
++ description: >
++ Send data information with directory index.
++ parameters:
++ - name: idIndex
++ type: byte
++ description: >
++ Index of SMBIOS directory.
++ - name: flag
++ type: byte
++ description: >
++ Valid flag to set dir entry status.
++ - name: dataLen
++ type: uint32
++ description: >
++ The length of the data in bytes.
++ - name: dataVer
++ type: uint32
++ description: >
++ The version number of this data.
++ - name: timeStamp
++ type: uint32
++ description: >
++ Timestamp determinded by the agent.
++ returns:
++ - name: status
++ type: boolean
++ description: >
++ Whether data changes.
++ errors:
++ - self.Error.InvalidParameter
++
++ - name: FindIdIndex
++ description: >
++ Find id index by data info.
++ parameters:
++ - name: dataInfo
++ type: array[byte]
++ description: >
++ Data info of data entry.
++ returns:
++ - name: idIndex
++ type: int32
++ description: >
++ Id index of data entry.
++ errors:
++ - self.Error.InvalidId
++
++ - name: AgentSynchronizeData
++ description: >
++ Synchronize SMBIOS data from file.
++ returns:
++ - name: status
++ type: boolean
++ description: >
++ Whether synchronization succeed or not.
++
++ - name: SynchronizeDirectoryCommonData
++ description: >
++ Synchronize directory common data.
++ parameters:
++ - name: idIndex
++ type: byte
++ description: >
++ Index of SMBIOS directory.
++ - name: size
++ type: uint32
++ description: >
++ Size of data that BIOS prepare to transfer.
++ returns:
++ - name: commonData
++ type: array[uint32]
++ description: >
++ Directory common data includes data size, version and timestamp.
++
++properties:
++ - name: DirectoryEntries
++ type: byte
++ description: >
++ Numbers of directory entries.
+diff --git a/xyz/openbmc_project/Smbios/README.md b/xyz/openbmc_project/Smbios/README.md
+new file mode 100644
+index 0000000..415ac52
+--- /dev/null
++++ b/xyz/openbmc_project/Smbios/README.md
+@@ -0,0 +1,22 @@
++# SMBIOS MDR V2
++
++## Overview
++SMBIOS MDR V2 service exposes D-Bus methods for SMBIOS Version 2 operations.
++
++### SMBIOS MDR V2 Interface
++SMBIOS MDR V2 interface `xyz.openbmc_project.Smbios.MDR_V2` provides following
++methods.
++#### methods
++* GetDirectoryInformation - Get the directory with directory index.
++* GetDataInformation - Get the data information with id index and data set ID.
++* SendDirectoryInformation - Send directory information to SMBIOS directory.
++* GetDataOffer - Get data set ID.
++* SendDataInformation - Send data information with directory index.
++* FindIdIndex - Find id index by data info.
++* SynchronizeDirectoryCommonData - Synchronize directory common data before
++SMBIOS data start to transfer.
++* AgentSynchronizeData - Synchronize SMBIOS data from file after data transfer
++complete.
++
++#### properties
++* DirEntries - Numbers of directory entries. Default: 0
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0017-Add-shutdown-policy-interface-for-get-set-shutdown-p.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0017-Add-shutdown-policy-interface-for-get-set-shutdown-p.patch
new file mode 100644
index 000000000..587bcebf1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0017-Add-shutdown-policy-interface-for-get-set-shutdown-p.patch
@@ -0,0 +1,42 @@
+From 7ebb72a93922a0163a5b35c277f3bbd241bdf78c Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Mon, 22 Oct 2018 16:20:36 +0800
+Subject: [PATCH] Add shutdown policy interface for get/set shutdown policy OEM
+ IPMI commands
+
+The policy property is used to store the shutdown policy.
+
+Tested by:
+busctl get-property "xyz.openbmc_project.Settings" \
+"/xyz/openbmc_project/control/shutdown_policy_config" \
+"xyz.openbmc_project.Control.ShutdownPolicy" "Policy"
+
+busctl set-property "xyz.openbmc_project.Settings" \
+"/xyz/openbmc_project/control/shutdown_policy_config" \
+"xyz.openbmc_project.Control.ShutdownPolicy" "Policy" y 1
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ xyz/openbmc_project/Control/ShutdownPolicy.interface.yaml | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+ create mode 100644 xyz/openbmc_project/Control/ShutdownPolicy.interface.yaml
+
+diff --git a/xyz/openbmc_project/Control/ShutdownPolicy.interface.yaml b/xyz/openbmc_project/Control/ShutdownPolicy.interface.yaml
+new file mode 100644
+index 0000000..e562ea8
+--- /dev/null
++++ b/xyz/openbmc_project/Control/ShutdownPolicy.interface.yaml
+@@ -0,0 +1,10 @@
++description: >
++ An interface for node shutdown policy on multi-node products.
++properties:
++ - name: Policy
++ type: byte
++ description: >
++ 0: Do not shutdown node on a power supply over current(OC)
++ or a power supply over temperature(OT) event.
++ 1: Shutdown node on an OC/OT event.
++ Only available on multi-node products.
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0018-Define-post-code-interfaces-for-post-code-manager.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0018-Define-post-code-interfaces-for-post-code-manager.patch
new file mode 100644
index 000000000..ce23c222b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0018-Define-post-code-interfaces-for-post-code-manager.patch
@@ -0,0 +1,64 @@
+From f88cac8364d5312e29208018909827d2da4a0f87 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Tue, 19 Feb 2019 16:52:51 +0800
+Subject: [PATCH] Define post code interfaces for post code manager
+
+It includes one method and 2 properties.
+properties:
+ - name: CurrentBootCycleIndex
+ description: >
+ It is used to indicate current boot cycle index.
+ - name: MaxBootCycleNum
+ description: >
+ The max cached boot cycles for post code.
+methods:
+ - name: GetPostCodes
+ description: >
+ Method to get the cached post code for each boot cycle.
+TestBy: bitbake build
+
+Signeoff-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ .../State/Boot/PostCode.interface.yaml | 30 ++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+ create mode 100644 xyz/openbmc_project/State/Boot/PostCode.interface.yaml
+
+diff --git a/xyz/openbmc_project/State/Boot/PostCode.interface.yaml b/xyz/openbmc_project/State/Boot/PostCode.interface.yaml
+new file mode 100644
+index 0000000..711749d
+--- /dev/null
++++ b/xyz/openbmc_project/State/Boot/PostCode.interface.yaml
+@@ -0,0 +1,30 @@
++description: >
++ Monitor Post code coming and buffer all of them based on boot cycle
++ into file system.
++
++properties:
++ - name: CurrentBootCycleIndex
++ type: uint16
++ description: >
++ It is used to indicate current boot cycle index.
++ - name: MaxBootCycleNum
++ type: uint16
++ description: >
++ The max cached boot cycles for post code.
++methods:
++ - name: GetPostCodes
++ description: >
++ Method to get the cached post code for each boot cycle.
++ parameters:
++ - name: Index
++ type: uint16
++ description: >
++ Index indicates which boot cycle of post codes is requested.
++ returns:
++ - name: codes
++ type: array[uint64]
++ description: >
++ An array of post codes of one boot cycle.
++ errors:
++ - xyz.openbmc_project.Common.Error.InternalFailure
++ - xyz.openbmc_project.Common.Error.InvalidArgument
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0019-Creating-the-Session-interface-for-Host-and-LAN.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0019-Creating-the-Session-interface-for-Host-and-LAN.patch
new file mode 100644
index 000000000..e1208cf5b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0019-Creating-the-Session-interface-for-Host-and-LAN.patch
@@ -0,0 +1,126 @@
+From f805522921d69eb4ea70248fe7e54557363aacea Mon Sep 17 00:00:00 2001
+From: Suryakanth Sekar <suryakanth.sekar@linux.intel.com>
+Date: Sat, 2 Mar 2019 03:31:09 +0530
+Subject: [PATCH] Creating the Session interface- for Host and LAN
+
+Defined all needed session properites to manage the session in
+host and also in LAN
+
+Change-Id: Ic7cccfc3333a602ee07fcd60077ec58fd8f06304
+Signed-off-by: Suryakanth Sekar <suryakanth.sekar@linux.intel.com>
+---
+ xyz/openbmc_project/Session/Info.interface.yaml | 56 +++++++++++++++++++++++++
+ xyz/openbmc_project/Session/README.md | 38 +++++++++++++++++
+ 2 files changed, 94 insertions(+)
+ create mode 100644 xyz/openbmc_project/Session/Info.interface.yaml
+ create mode 100644 xyz/openbmc_project/Session/README.md
+
+diff --git a/xyz/openbmc_project/Session/Info.interface.yaml b/xyz/openbmc_project/Session/Info.interface.yaml
+new file mode 100644
+index 0000000..fbb5a45
+--- /dev/null
++++ b/xyz/openbmc_project/Session/Info.interface.yaml
+@@ -0,0 +1,56 @@
++description: >
++ Provides properties for session objects.
++ As communication to this service is done through authenticated
++ & authorized session, there won't be any validation for the both.
++
++properties:
++ - name: SessionHandle
++ type: byte
++ description: >
++ Session Handle,unique number to locate the session.
++ errors:
++ - xyz.openbmc_project.Common.Error.InternalFailure
++ - name: ChannelNum
++ type: byte
++ description: >
++ channelnumber which session is created.
++ errors:
++ - xyz.openbmc_project.Common.Error.InternalFailure
++ - name: CurrentPrivilege
++ type: byte
++ description: >
++ Privilege of the session.
++ errors:
++ - xyz.openbmc_project.Common.Error.InternalFailure
++ - name: RemoteIPAddr
++ type: uint32
++ description: >
++ Remote IP address.
++ errors:
++ - xyz.openbmc_project.Common.Error.InternalFailure
++ - name: RemotePort
++ type: uint16
++ description: >
++ Remote IP Port.
++ errors:
++ - xyz.openbmc_project.Common.Error.InternalFailure
++ - name: RemoteMACAddress
++ type: array[byte]
++ description: >
++ Remote MAC address.
++ errors:
++ - xyz.openbmc_project.Common.Error.InternalFailure
++ - name: UserID
++ type: byte
++ description: >
++ Session created by given user ID.
++ errors:
++ - xyz.openbmc_project.Common.Error.InternalFailure
++ - name: State
++ type: byte
++ description: >
++ Session state.
++ errors:
++ - xyz.openbmc_project.Common.Error.InternalFailure
++
++# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
+diff --git a/xyz/openbmc_project/Session/README.md b/xyz/openbmc_project/Session/README.md
+new file mode 100644
+index 0000000..f220885
+--- /dev/null
++++ b/xyz/openbmc_project/Session/README.md
+@@ -0,0 +1,38 @@
++# Session Management
++
++## Overview
++Session Manager service exposes D-Bus methods for session management operations.
++
++### Session Manager Interface
++Session manager interface `xyz.openbmc_project.Session.Manager` provides following
++methods, properties and signals.
++
++#### xyz.openbmc_project.Session.Manager interface
++##### methods
++* CreateSession - To create new session object to the system.
++
++##### properties
++* MaxSessionSupported - To list all the groups supported in the system.
++* ActiveSessionCount - To hold the no of active sessions.
++
++Session manager service will create session objects for every session
++in the system under object path `/xyz/openbmc_project/session/<SessionIndex>`.
++Each session object can be handled through 'org.freedesktop.DBus.ObjectManager'.
++session object will expose following properties and methods.
++
++#### xyz.openbmc_project.Session.Info interface
++##### properties
++* SessionID - Session ID,random unique number to locate the session.
++* Channel - Session created Channel.
++* SessionPrivilege - Privilege of the session.
++* RemoteIPAddr – Remote IP address.
++* RemotePort - Remote Port address.
++* RemoteMACAddress -Remote MAC Address.
++* UserID - Session created by given user id.
++
++
++
++#### xyz.openbmc_project.Object.Delete
++#### methods
++* Delete - To delete the session object in the system.
++
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch
new file mode 100644
index 000000000..68d2c92b7
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0020-Create-dbus-interface-for-SOL-commands.patch
@@ -0,0 +1,76 @@
+From 2820ca36ab21c52341cdbde477756f960eaeb68b Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@intel.com>
+Date: Wed, 13 Mar 2019 11:19:07 +0800
+Subject: [PATCH] Create dbus interface for SOL commands
+
+Create dbus properties for Set/Get SOL config parameter command.
+Some platforms need to call Set/Get SOL config parameter command
+through KCS, and since sol manager in net-ipmid cannot be accessed
+by commands in host-ipmid, need to create a dbus interface in
+phospher-settings to transfer properties from host-ipmid to
+net-ipmid.
+
+TestedBy:
+With the related code change in net-ipmid, busctl introspect
+xyz.openbmc_project.Ipmi.SOL /xyz/openbmc_project/SOL
+can show all the properties needed.
+
+Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com>
+---
+ xyz/openbmc_project/Ipmi/SOL.interface.yaml | 44 ++++++++++++++++++++++++++
+ 1 file changed, 44 insertions(+)
+ create mode 100644 xyz/openbmc_project/Ipmi/SOL.interface.yaml
+
+diff --git a/xyz/openbmc_project/Ipmi/SOL.interface.yaml b/xyz/openbmc_project/Ipmi/SOL.interface.yaml
+new file mode 100644
+index 0000000..94db59f
+--- /dev/null
++++ b/xyz/openbmc_project/Ipmi/SOL.interface.yaml
+@@ -0,0 +1,44 @@
++description: >
++ SOL properties use for Get/Set SOL config parameter command in host-ipmid
++ sending config to SOL process in net-ipmid.
++ Since some platforms need to access Get/Set SOL config parameter command
++ through KCS, and current sol manager is implemented in net-ipmid and
++ cannot be accessed by host-ipmid, add a dbus interface for host-ipmid
++ command to transfer properties to net-ipmid.
++ This interface will be implemented in phosphor-settings.
++properties:
++ - name: Progress
++ type: byte
++ description: >
++ Set In Progress property, indicate when any parameters are being
++ updated.
++ - name: Enable
++ type: boolean
++ description: >
++ SOL Enable property, this controls whether the SOL payload type
++ can be activated.
++ - name: Authentication
++ type: byte
++ description: >
++ If SOL enable Force Payload Encryption and Authenticaton.
++ And the minimun operating privilege level SOL required.
++ - name: AccumulateIntervalMS
++ type: byte
++ description: >
++ Character Accumulate Interval in 5ms increments.
++ BMC will wait this time before transmitting a packet.
++ - name: Threshold
++ type: byte
++ description: >
++ BMC will automatically send an SOL character data packet containing
++ this number of characters as soon as this number of characters
++ (or greater) has been accepted from the baseboard serial controller.
++ - name: RetryCount
++ type: byte
++ description: >
++ Packet will be dropped if no ACK/NACK received by time retries
++ expire.
++ - name: RetryIntervalMS
++ type: byte
++ description: >
++ Retry Interval in 10ms increments.
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend
new file mode 100644
index 000000000..a2eb6649c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend
@@ -0,0 +1,20 @@
+SRC_URI = "git://github.com/openbmc/phosphor-dbus-interfaces.git"
+SRCREV = "5515c34fded4c217e3cc07f551d59d34cd3329c5"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://0002-Modify-Dbus-for-IPv6.patch \
+ file://0003-Chassis-Power-Control-are-implemented.patch \
+ file://0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch \
+ file://0006-dbus-interface-add-boot-option-support-for-floppy-an.patch \
+ file://0007-ipmi-set-BIOS-id.patch \
+ file://0009-Add-host-restart-cause-property.patch \
+ file://0010-Increase-the-default-watchdog-timeout-value.patch \
+ file://0012-Add-RestoreDelay-interface-for-power-restore-delay.patch \
+ file://0013-Add-ErrConfig.yaml-interface-for-processor-error-config.patch \
+ file://0014-Add-multiple-state-signal-for-host-start-and-stop.patch \
+ file://0016-Add-DBUS-interface-of-SMBIOS-MDR-V2.patch \
+ file://0017-Add-shutdown-policy-interface-for-get-set-shutdown-p.patch \
+ file://0018-Define-post-code-interfaces-for-post-code-manager.patch \
+ file://0019-Creating-the-Session-interface-for-Host-and-LAN.patch \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service
new file mode 100644
index 000000000..9af9af254
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper/xyz.openbmc_project.ObjectMapper.service
@@ -0,0 +1,20 @@
+[Unit]
+Description=Phosphor DBus Service Discovery Manager
+Before=obmc-mapper.target
+After=dbus.socket
+
+[Service]
+Restart=always
+Type=dbus
+ExecStart=/usr/bin/env mapperx \
+ --service-namespaces="xyz. com. org." \
+ --interface-namespaces="org. com. xyz." \
+ --service-blacklists="org.freedesktop.systemd1"
+SyslogIdentifier=phosphor-mapper
+BusName={BUSNAME}
+TimeoutStartSec=300
+RestartSec=5
+EnvironmentFile={envfiledir}/obmc/mapper
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend
new file mode 100644
index 000000000..72d991c7e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-mapper_%.bbappend
@@ -0,0 +1 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service
new file mode 100644
index 000000000..f4ffa17a0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Phosphor-Pid-Control Margin-based Fan Control Daemon
+
+[Service]
+Restart=always
+ExecStart={sbindir}/swampd
+RestartSec=5
+StartLimitInterval=0
+Type=simple
+
+[Install]
+WantedBy=basic.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend
new file mode 100644
index 000000000..0c56a8fe5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend
@@ -0,0 +1,8 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+inherit obmc-phosphor-systemd
+SYSTEMD_SERVICE_${PN} = "phosphor-pid-control.service"
+EXTRA_OECONF = "--enable-configure-dbus=yes"
+
+SRC_URI = "git://github.com/openbmc/phosphor-pid-control.git"
+SRCREV = "90e9dbcae6c1df3127dd3de41f9d1e1b5a438828"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service
new file mode 100644
index 000000000..d51fee312
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/fwupd@.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Flash BMC with fwupd script : %I
+
+[Service]
+Type=oneshot
+RemainAfterExit=no
+ExecStart=/usr/bin/fwupd.sh file:////tmp/images/%i/image-runtime
+SyslogIdentifier=fwupd \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend
new file mode 100644
index 000000000..80c5ea9d3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend
@@ -0,0 +1,11 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+EXTRA_OECONF += "--enable-fwupd_script"
+
+SYSTEMD_SERVICE_${PN}-updater += "fwupd@.service"
+
+SRC_URI_remove = "git://github.com/openbmc/phosphor-bmc-code-mgmt"
+SRC_URI += "git://git@github.com/Intel-BMC/phosphor-bmc-code-mgmt;protocol=ssh"
+SRCREV = "f8f76c29dbe2806a6eacd15847563cdf7f7567f4"
+
+#Currently enforcing image signature validation only for PFR images
+PACKAGECONFIG_append = "${@bb.utils.contains('IMAGE_TYPE', 'pfr', ' verify_signature', '', d)}"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/gpiodaemon/gpiodaemon.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/gpiodaemon/gpiodaemon.bb
new file mode 100644
index 000000000..c04069fb9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/gpiodaemon/gpiodaemon.bb
@@ -0,0 +1,18 @@
+SUMMARY = "Gpio daemon service for handling gpio operations"
+DESCRIPTION = "Daemon allows to block gpio access under certain conditions"
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git/gpiodaemon"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh"
+
+SRCREV = "f4d4bfc3296cb27feb17aa5d1d93b3061b56ce10"
+
+inherit cmake systemd
+SYSTEMD_SERVICE_${PN} = "gpiodaemon.service"
+
+DEPENDS = "boost systemd sdbusplus phosphor-logging"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend
new file mode 100644
index 000000000..5326680f6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/host/obmc-op-control-host%.bbappend
@@ -0,0 +1,6 @@
+SYSTEMD_LINK_${PN}_remove += "../op-start-host@.service:obmc-host-startmin@0.target.requires/op-start-host@0.service"
+SYSTEMD_LINK_${PN}_remove += "../op-init-pnor@.service:obmc-host-startmin@0.target.requires/op-init-pnor@0.service"
+
+FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires"
+FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires/op-start-host@0.service"
+FILES_${PN}_remove = "${systemd_unitdir}/system/obmc-host-startmin@0.target.requires/op-init-pnor@0.service" \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket
new file mode 100644
index 000000000..8782e4dd3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/bmcweb.socket
@@ -0,0 +1,9 @@
+[Unit]
+Description=BMC Webserver socket
+
+[Socket]
+ListenStream=443
+ReusePort=true
+
+[Install]
+WantedBy=sockets.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend
new file mode 100644
index 000000000..fe09e6da2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend
@@ -0,0 +1,17 @@
+SRC_URI = "git://github.com/openbmc/bmcweb.git"
+SRCREV = "b01bf2991955ef267ce2be8e7a18eac984990de8"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+# add a user called bmcweb for the server to assume
+# bmcweb is part of group shadow for non-root pam authentication
+USERADD_PARAM_${PN} = "-r -s /usr/sbin/nologin -d /home/bmcweb -m -G shadow bmcweb"
+
+GROUPADD_PARAM_${PN} = "web; redfish "
+
+# Enable CPU Log and Raw PECI support
+EXTRA_OECMAKE += "-DBMCWEB_ENABLE_REDFISH_CPU_LOG=ON"
+EXTRA_OECMAKE += "-DBMCWEB_ENABLE_REDFISH_RAW_PECI=ON"
+
+# Enable Redfish BMC Journal support
+EXTRA_OECMAKE += "-DBMCWEB_ENABLE_REDFISH_BMC_JOURNAL=ON"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend
new file mode 100644
index 000000000..616fb9a75
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config.bbappend
@@ -0,0 +1,21 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+SRC_URI += " file://dev_id.json \
+ file://channel_access.json \
+ file://channel_config.json \
+ file://master_write_read_white_list.json \
+ "
+
+FILES_${PN} += " \
+ ${datadir}/ipmi-providers/channel_access.json \
+ ${datadir}/ipmi-providers/channel_config.json \
+ ${datadir}/ipmi-providers/master_write_read_white_list.json \
+ "
+
+do_install_append() {
+ install -m 0644 -D ${WORKDIR}/channel_access.json \
+ ${D}${datadir}/ipmi-providers/channel_access.json
+ install -m 0644 -D ${WORKDIR}/channel_config.json \
+ ${D}${datadir}/ipmi-providers/channel_config.json
+ install -m 0644 -D ${WORKDIR}/master_write_read_white_list.json \
+ ${D}${datadir}/ipmi-providers/master_write_read_white_list.json
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json
new file mode 100644
index 000000000..299483121
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_access.json
@@ -0,0 +1,23 @@
+{
+ "1" : {
+ "access_mode" : "always_available",
+ "user_auth_disabled" : false,
+ "per_msg_auth_disabled" : false,
+ "alerting_disabled" : false,
+ "priv_limit" : "priv-admin"
+ },
+ "2" : {
+ "access_mode" : "always_available",
+ "user_auth_disabled" : false,
+ "per_msg_auth_disabled" : false,
+ "alerting_disabled" : false,
+ "priv_limit" : "priv-admin"
+ },
+ "3" : {
+ "access_mode" : "always_available",
+ "user_auth_disabled" : false,
+ "per_msg_auth_disabled" : false,
+ "alerting_disabled" : false,
+ "priv_limit" : "priv-admin"
+ }
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json
new file mode 100644
index 000000000..13b945fd0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/channel_config.json
@@ -0,0 +1,178 @@
+{
+ "0" : {
+ "name" : "IPMB",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "1" : {
+ "name" : "eth1",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "lan-802.3",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "multi-session",
+ "is_ipmi" : true
+ }
+ },
+ "2" : {
+ "name" : "eth2",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "lan-802.3",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "multi-session",
+ "is_ipmi" : true
+ }
+ },
+ "3" : {
+ "name" : "eth0",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "lan-802.3",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "multi-session",
+ "is_ipmi" : true
+ }
+ },
+ "4" : {
+ "name" : "EMP",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "5" : {
+ "name" : "ICMB",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "6" : {
+ "name" : "SMLINK",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "7" : {
+ "name" : "SMM",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "8" : {
+ "name" : "INTRABMC",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "9" : {
+ "name" : "SIPMB",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "10" : {
+ "name" : "PCIE",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "11" : {
+ "name" : "RESERVED",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "12" : {
+ "name" : "INTERNAL",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "13" : {
+ "name" : "RESERVED",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "14" : {
+ "name" : "SELF",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "15" : {
+ "name" : "SMS",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "ipmb",
+ "protocol_type" : "ipmb-1.0",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ }
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json
new file mode 100644
index 000000000..e561569d9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/dev_id.json
@@ -0,0 +1,2 @@
+{"id": 35, "revision": 0, "addn_dev_support": 191,
+ "manuf_id": 343, "prod_id": 123, "aux": 0}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json
new file mode 100644
index 000000000..9fdb3c916
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json
@@ -0,0 +1,49 @@
+{
+ "filters": [
+ {
+ "busId": "0x01",
+ "slaveAddr": "0x4d",
+ "command": "0x00"
+ },
+ {
+ "busId": "0x01",
+ "slaveAddr": "0x57",
+ "command": "0x00"
+ },
+ {
+ "busId": "0x02",
+ "slaveAddr": "0x40",
+ "command": "0x00"
+ },
+ {
+ "busId": "0x02",
+ "slaveAddr": "0x49",
+ "command": "0x00"
+ },
+ {
+ "busId": "0x02",
+ "slaveAddr": "0x51",
+ "command": "0x00"
+ },
+ {
+ "busId": "0x03",
+ "slaveAddr": "0x44",
+ "command": "0x00"
+ },
+ {
+ "busId": "0x03",
+ "slaveAddr": "0x68",
+ "command": "0x00"
+ },
+ {
+ "busId": "0x06",
+ "slaveAddr": "0x40",
+ "command": "0x00"
+ },
+ {
+ "busId": "0x07",
+ "slaveAddr": "0x51",
+ "command": "0x00"
+ }
+ ]
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend
new file mode 100644
index 000000000..2d892ad1a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native.bbappend
@@ -0,0 +1,8 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+SRC_URI += " file://config.yaml"
+
+#override source file before it is used for final FRU file (merged from multiple sources)
+do_install() {
+ cp ${WORKDIR}/config.yaml ${config_datadir}/
+}
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml
new file mode 100644
index 000000000..e9b7a621e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-fru-merge-config-native/config.yaml
@@ -0,0 +1,31 @@
+# A YAML similar to this example would have to be generated, for eg with MRW
+# inputs and system configuration, to depict IPMI Fru information.
+#
+# This file maps IPMI properties to phosphor dbus inventory properties
+#
+# This YAML could help generate C++ code.
+# Format of the YAML:
+# Fruid:
+# Associated Fru paths
+# d-bus Interfaces
+# d-bus Properties
+# IPMI Fru mapping
+0:
+ /system/board/WFP_Baseboard:
+ entityID: 23
+ entityInstance: 1
+ interfaces:
+ xyz.openbmc_project.Inventory.Item:
+ name:
+ IPMIFruProperty: Product Name
+ IPMIFruSection: Product
+ xyz.openbmc_project.Inventory.Decorator.Asset:
+ Manufacturer:
+ IPMIFruProperty: Manufacturer
+ IPMIFruSection: Product
+ PartNumber:
+ IPMIFruProperty: Part Number
+ IPMIFruSection: Product
+ SerialNumber:
+ IPMIFruProperty: Serial Number
+ IPMIFruSection: Product
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Modify-dbus-interface-for-power-control.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Modify-dbus-interface-for-power-control.patch
new file mode 100644
index 000000000..236bd18f4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0002-Modify-dbus-interface-for-power-control.patch
@@ -0,0 +1,31 @@
+From 39df500f277eca01d6a0538d4db8ec34894d9441 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Mon, 17 Sep 2018 12:59:12 +0800
+Subject: [PATCH] Modify dbus interface for power control
+
+Switch power control service namespace from "org" to "xyz",
+to compatible with new intel-chassis services
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ chassishandler.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/chassishandler.cpp b/chassishandler.cpp
+index 6002e7a..0e83bba 100644
+--- a/chassishandler.cpp
++++ b/chassishandler.cpp
+@@ -786,8 +786,8 @@ ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_data_len_t data_len,
+ ipmi_context_t context)
+ {
+- const char* objname = "/org/openbmc/control/power0";
+- const char* intf = "org.openbmc.control.Power";
++ const char* objname = "/xyz/openbmc_project/Chassis/Control/Power0";
++ const char* intf = "xyz.openbmc_project.Chassis.Control.Power";
+
+ sd_bus* bus = NULL;
+ sd_bus_message* reply = NULL;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0003-Modify-dbus-interface-for-chassis-control.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0003-Modify-dbus-interface-for-chassis-control.patch
new file mode 100644
index 000000000..9061481ac
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0003-Modify-dbus-interface-for-chassis-control.patch
@@ -0,0 +1,33 @@
+From 48ac37551cd51415deafe8b1dcb23ebeef1e8ade Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Mon, 17 Sep 2018 13:04:42 +0800
+Subject: [PATCH] Modify-dbus-interface-for-chassis-control
+
+Switch chassis control service namespace from "org" to "xyz",
+to compatible with new intel-chassis services
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ apphandler.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/apphandler.cpp b/apphandler.cpp
+index b089331..f2889c5 100644
+--- a/apphandler.cpp
++++ b/apphandler.cpp
+@@ -393,9 +393,9 @@ ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_data_len_t data_len,
+ ipmi_context_t context)
+ {
+- const char* objname = "/org/openbmc/control/chassis0";
++ const char* objname = "/xyz/openbmc_project/Chassis/Control/Chassis";
+ const char* iface = "org.freedesktop.DBus.Properties";
+- const char* chassis_iface = "org.openbmc.control.Chassis";
++ const char* chassis_iface = "xyz.openbmc_project.Chassis.Control.Chassis";
+ sd_bus_message* reply = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r = 0;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch
new file mode 100644
index 000000000..3d9179ce5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0009-IPv6-Network-changes.patch
@@ -0,0 +1,909 @@
+From cd4bc9e4291771f638f66efa205bf8fbec518546 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Mon, 4 Feb 2019 10:30:12 -0800
+Subject: [PATCH] IPv6 Network changes
+
+Allow IPv6 IPMI set/get commands
+
+Signed-off-by: David Cobbley <david.j.cobbley@linux.intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+
+Change-Id: If5528d3b7294c5f8c17db5919439235d0fad0446
+---
+ transporthandler.cpp | 667 ++++++++++++++++++++++++++++++++++++++++++-
+ transporthandler.hpp | 68 +++++
+ types.hpp | 9 +
+ utils.hpp | 1 +
+ 4 files changed, 744 insertions(+), 1 deletion(-)
+
+Index: phosphor-host-ipmid.clean/transporthandler.cpp
+===================================================================
+--- phosphor-host-ipmid.clean.orig/transporthandler.cpp
++++ phosphor-host-ipmid.clean/transporthandler.cpp
+@@ -41,6 +41,12 @@ extern std::unique_ptr<phosphor::Timer>
+
+ const int SIZE_MAC = 18; // xx:xx:xx:xx:xx:xx
+ constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
++constexpr auto ipv6Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv6";
++
++static const std::array<std::string, 3> ipAddressEnablesType = {
++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv4Only",
++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv6Only",
++ "xyz.openbmc_project.Network.EthernetInterface.IPAllowed.IPv4AndIPv6"};
+
+ std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig;
+
+@@ -400,7 +406,6 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n
+ ipmi_context_t context)
+ {
+ ipmi_ret_t rc = IPMI_CC_OK;
+- *data_len = 0;
+
+ using namespace std::chrono_literals;
+
+@@ -414,6 +419,9 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n
+ auto reqptr = reinterpret_cast<const set_lan_t*>(request);
+ sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
+
++ size_t reqLen = *data_len;
++ *data_len = 0;
++
+ // channel number is the lower nibble
+ int channel = reqptr->channel & CHANNEL_MASK;
+ auto ethdevice = ipmi::network::ChanneltoEthernet(channel);
+@@ -437,6 +445,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n
+
+ case LanParam::IPSRC:
+ {
++ if (reqLen != LAN_PARAM_IPSRC_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
+ uint8_t ipsrc{};
+ std::memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE);
+ channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc);
+@@ -445,6 +458,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n
+
+ case LanParam::MAC:
+ {
++ if (reqLen != LAN_PARAM_MAC_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
+ char mac[SIZE_MAC];
+
+ std::snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT,
+@@ -465,6 +483,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n
+
+ case LanParam::SUBNET:
+ {
++ if (reqLen != LAN_PARAM_SUBNET_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
+ std::snprintf(netmask, INET_ADDRSTRLEN,
+ ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0],
+ reqptr->data[1], reqptr->data[2], reqptr->data[3]);
+@@ -474,6 +497,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n
+
+ case LanParam::GATEWAY:
+ {
++ if (reqLen != LAN_PARAM_GATEWAY_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
+ std::snprintf(gateway, INET_ADDRSTRLEN,
+ ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0],
+ reqptr->data[1], reqptr->data[2], reqptr->data[3]);
+@@ -483,6 +511,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n
+
+ case LanParam::VLAN:
+ {
++ if (reqLen != LAN_PARAM_VLAN_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
+ uint16_t vlan{};
+ std::memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE);
+ // We are not storing the enable bit
+@@ -495,6 +528,11 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n
+
+ case LanParam::INPROGRESS:
+ {
++ if (reqLen != LAN_PARAM_INPROGRESS_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
+ if (reqptr->data[0] == SET_COMPLETE)
+ {
+ channelConf->lan_set_in_progress = SET_COMPLETE;
+@@ -523,6 +561,122 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n
+ }
+ break;
+
++ case LanParam::IPV6_AND_IPV4_ENABLES:
++ {
++ if (reqLen != LAN_PARAM_IPV6_AND_IPV4_ENABLES_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
++ channelConf->ipv6AddressingEnables = reqptr->data[0];
++ break;
++ }
++
++ case LanParam::IPV6_STATIC_ADDRESSES:
++ {
++ if (reqLen != LAN_PARAM_IPV6_STATIC_ADDRESSES_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
++ channelConf->ipv6AddressSource =
++ reqptr->data[1] & 0x81; // Looking at bit 0 and bit 7
++ char tmpIPV6[INET6_ADDRSTRLEN];
++ inet_ntop(AF_INET6, &reqptr->data[2], tmpIPV6, INET6_ADDRSTRLEN);
++ channelConf->ipv6Addr.assign(tmpIPV6);
++ channelConf->ipv6Prefix = reqptr->data[19];
++ break;
++ }
++
++ case LanParam::IPV6_ROUTER_ADDRESS_CONF_CTRL:
++ {
++ if (reqLen != LAN_PARAM_IPV6_ROUTER_ADDRESS_CONF_CTRL_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
++ channelConf->ipv6RouterAddressConfigControl = reqptr->data[0];
++ break;
++ }
++
++ case LanParam::IPV6_STATIC_ROUTER_1_IP_ADDR:
++ {
++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_1_IP_ADDR_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
++ char tmpIPV6[INET6_ADDRSTRLEN];
++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data),
++ tmpIPV6, INET6_ADDRSTRLEN);
++ channelConf->ipv6GatewayAddr.assign(tmpIPV6);
++ break;
++ }
++
++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_LEN:
++ {
++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_LEN_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
++ channelConf->ipv6GatewayPrefixLength = reqptr->data[0];
++ break;
++ }
++
++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_VAL:
++ {
++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_VAL_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
++ char tmpIPV6[INET6_ADDRSTRLEN];
++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data),
++ tmpIPV6, INET6_ADDRSTRLEN);
++ channelConf->ipv6GatewayPrefixValue.assign(tmpIPV6);
++ break;
++ }
++
++ case LanParam::IPV6_STATIC_ROUTER_2_IP_ADDR:
++ {
++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_2_IP_ADDR_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
++ char tmpIPV6[INET6_ADDRSTRLEN];
++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data),
++ tmpIPV6, INET6_ADDRSTRLEN);
++ channelConf->ipv6BackupGatewayAddr.assign(tmpIPV6);
++ break;
++ }
++
++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_LEN:
++ {
++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_LEN_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
++ channelConf->ipv6BackupGatewayPrefixLength = reqptr->data[0];
++ break;
++ }
++
++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_VAL:
++ {
++ if (reqLen != LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_VAL_SIZE)
++ {
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
++ char tmpIPV6[INET6_ADDRSTRLEN];
++ inet_ntop(AF_INET6, reinterpret_cast<const void*>(reqptr->data),
++ tmpIPV6, INET6_ADDRSTRLEN);
++ channelConf->ipv6BackupGatewayPrefixValue.assign(tmpIPV6);
++ break;
++ }
++
+ default:
+ {
+ rc = IPMI_CC_PARM_NOT_SUPPORTED;
+@@ -549,6 +703,7 @@ ipmi_ret_t ipmi_transport_get_lan(ipmi_n
+ ipmi_ret_t rc = IPMI_CC_OK;
+ *data_len = 0;
+ const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
++ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+
+ get_lan_t* reqptr = (get_lan_t*)request;
+ // channel number is the lower nibble
+@@ -687,6 +842,489 @@ ipmi_ret_t ipmi_transport_get_lan(ipmi_n
+ static_cast<uint8_t>(cipherList.size());
+ break;
+ }
++ case LanParam::IPV6_AND_IPV4_SUPPORTED:
++ {
++ uint8_t addressSupport =
++ 0x1; // Allow both IPv4 & IPv6 simultaneously
++ std::array<uint8_t, 2> buf = {current_revision, addressSupport};
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_AND_IPV4_ENABLES:
++ {
++ // If DHCP, check if you have an ipv6 and ipv4 address. If static
++ // return not supported
++
++ // 00h check if conf DHCP == ipv4 or off
++ // 01h check if conf DHCP == ipv6
++ // 02h check if DHCP == true
++
++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE;
++ std::string networkInterfacePath;
++ uint8_t ipVAddressEnables = 0;
++
++ if (channelConf->lan_set_in_progress == SET_COMPLETE)
++ {
++ try
++ {
++ ipmi::ObjectTree ancestorMap;
++ // if the system has an ip object,then
++ // get the IP object.
++ auto ipObject =
++ ipmi::getDbusObject(bus, ipmi::network::IP_INTERFACE,
++ ipmi::network::ROOT, ethIP);
++ // Get the parent interface of the IP object.
++ try
++ {
++ ipmi::InterfaceList interfaces;
++ interfaces.emplace_back(
++ ipmi::network::ETHERNET_INTERFACE);
++
++ ancestorMap = ipmi::getAllAncestors(
++ bus, ipObject.first, std::move(interfaces));
++ }
++ catch (InternalFailure& e)
++ {
++ // if unable to get the parent interface
++ // then commit the error and return.
++ log<level::ERR>(
++ "Unable to get the parent interface",
++ entry("PATH=%s", ipObject.first.c_str()),
++ entry("INTERFACE=%s",
++ ipmi::network::ETHERNET_INTERFACE));
++ return IPMI_CC_UNSPECIFIED_ERROR;
++ }
++ // for an ip object there would be single parent
++ // interface.
++ networkInterfacePath = ancestorMap.begin()->first;
++ }
++ catch (InternalFailure& e)
++ {
++ // if there is no ip configured on the system,then
++ // get the network interface object.
++ auto networkInterfaceObject = ipmi::getDbusObject(
++ bus, ipmi::network::ETHERNET_INTERFACE,
++ ipmi::network::ROOT, ethdevice);
++
++ networkInterfacePath = networkInterfaceObject.first;
++ }
++
++ std::string ipEnables =
++ sdbusplus::message::variant_ns::get<std::string>(
++ ipmi::getDbusProperty(bus, ipmi::network::SERVICE,
++ networkInterfacePath,
++ ipmi::network::ETHERNET_INTERFACE,
++ "IPAddressEnables"));
++
++ // check if on off ipv4 ipv6, etc.
++ bool found = false;
++ for (uint8_t ii = 0; ii < ipAddressEnablesType.size(); ii++)
++ {
++ if (ipEnables == ipAddressEnablesType[ii])
++ {
++ ipVAddressEnables = ii;
++ found = true;
++ break;
++ }
++ }
++ if (!found)
++ {
++ return IPMI_CC_PARM_NOT_SUPPORTED;
++ }
++ }
++ else
++ {
++ ipVAddressEnables = channelConf->ipv6AddressingEnables;
++ }
++
++ std::array<uint8_t, 2> buf = {current_revision, ipVAddressEnables};
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_STATUS:
++ {
++ // Number of IPV6 addresses that are supported
++ constexpr std::array<uint8_t, 3> statusData = {1, 1, 3};
++
++ std::array<uint8_t, 4> buf = {current_revision, statusData[0],
++ statusData[1], statusData[2]};
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_STATIC_ADDRESSES:
++ {
++ // Only return set selector 0
++ uint8_t ipv6SetSelector = 0;
++ std::string ipaddress;
++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE;
++ uint8_t ipv6AddressSource = 0;
++ uint8_t prefixLength = 0;
++ uint8_t status = 0;
++ if (channelConf->lan_set_in_progress == SET_COMPLETE)
++ {
++ try
++ {
++ auto ipObjectInfo =
++ ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE,
++ ipmi::network::ROOT, ethIP);
++
++ auto properties = ipmi::getAllDbusProperties(
++ bus, ipObjectInfo.second, ipObjectInfo.first,
++ ipmi::network::IP_INTERFACE);
++
++ std::string origin =
++ sdbusplus::message::variant_ns::get<std::string>(
++ properties["Origin"]);
++ if (sdbusplus::message::variant_ns::get<std::string>(
++ properties["Origin"]) ==
++ "xyz.openbmc_project.Network.IP.AddressOrigin.Static")
++ {
++ ipaddress =
++ sdbusplus::message::variant_ns::get<std::string>(
++ properties["Address"]);
++ ipv6AddressSource = 0x81; // Looking at bit 0 and bit 7
++ prefixLength =
++ sdbusplus::message::variant_ns::get<uint8_t>(
++ properties["PrefixLength"]);
++ status = 0;
++ }
++ }
++ // ignore the exception, as it is a valid condition that
++ // the system is not configured with any IP.
++ catch (InternalFailure& e)
++ {
++ // nothing to do.
++ }
++ }
++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
++ {
++ ipv6AddressSource = channelConf->ipv6AddressSource;
++ ipaddress = channelConf->ipv6Addr.c_str();
++ prefixLength = channelConf->ipv6Prefix;
++ status = 1;
++ }
++
++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_STATUS_SIZE> buf = {
++ current_revision, ipv6SetSelector, ipv6AddressSource};
++ inet_pton(AF_INET6, ipaddress.c_str(),
++ reinterpret_cast<void*>(&buf[3]));
++ buf[20] = prefixLength;
++ buf[21] = status;
++
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_DHCPV6_STATIC_DUID_STORAGE_LENGTH:
++ {
++ // DHCP unique identified
++ // Only 1 read-only 16-byte Block needed
++ uint8_t duidLength = 1;
++ std::array<uint8_t, 2> buf = {current_revision, duidLength};
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_DHCPV6_STATIC_DUIDS:
++ {
++ std::string macAddress;
++ if (channelConf->lan_set_in_progress == SET_COMPLETE)
++ {
++ auto macObjectInfo =
++ ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE,
++ ipmi::network::ROOT, ethdevice);
++
++ auto variant = ipmi::getDbusProperty(
++ bus, macObjectInfo.second, macObjectInfo.first,
++ ipmi::network::MAC_INTERFACE, "MACAddress");
++
++ macAddress =
++ sdbusplus::message::variant_ns::get<std::string>(variant);
++ }
++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
++ {
++ macAddress = channelConf->macAddress;
++ }
++
++ std::array<uint8_t,
++ ipmi::network::IPV6_DUID_SIZE + sizeof(current_revision)>
++ buf;
++ buf = {current_revision,
++ reqptr->parameter_set,
++ reqptr->parameter_block,
++ DUID_LEN,
++ 0, // Filler byte
++ DUID_LL_TYPE,
++ 0, // Filler byte
++ DUIC_ETH_HW_TYPE};
++ sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
++ (&buf[8]), (&buf[9]), (&buf[10]), (&buf[11]), (&buf[12]),
++ (&buf[13]));
++
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_DYNAMIC_ADDRESSES:
++ {
++ std::string ipaddress;
++ uint8_t ipv6AddressSource = 0;
++ uint8_t prefixLength = 0;
++ uint8_t status = 0;
++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE;
++
++ if (channelConf->lan_set_in_progress == SET_COMPLETE)
++ {
++ try
++ {
++ auto ipObjectInfo =
++ ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE,
++ ipmi::network::ROOT, ethIP);
++
++ auto properties = ipmi::getAllDbusProperties(
++ bus, ipObjectInfo.second, ipObjectInfo.first,
++ ipmi::network::IP_INTERFACE);
++
++ if (sdbusplus::message::variant_ns::get<std::string>(
++ properties["Origin"]) ==
++ "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
++ {
++ ipaddress =
++ sdbusplus::message::variant_ns::get<std::string>(
++ properties["Address"]);
++ ipv6AddressSource = 0x81; // Looking at bit 0 and bit 7
++ prefixLength =
++ sdbusplus::message::variant_ns::get<uint8_t>(
++ properties["PrefixLength"]);
++ status = 0;
++ }
++ else
++ {
++ status = 1;
++ }
++ }
++ // ignore the exception, as it is a valid condition that
++ // the system is not configured with any IP.
++ catch (InternalFailure& e)
++ {
++ // nothing to do.
++ }
++ }
++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
++ {
++ ipaddress = channelConf->ipv6Addr;
++ ipv6AddressSource = channelConf->ipv6AddressSource;
++ prefixLength = channelConf->ipv6Prefix;
++ status = channelConf->ipv6AddressStatus;
++ }
++
++ uint8_t ipv6SetSelector = 0;
++ std::array<uint8_t, 22> buf = {current_revision, ipv6SetSelector,
++ ipv6AddressSource};
++ inet_pton(AF_INET6, ipaddress.c_str(),
++ reinterpret_cast<void*>(&buf[3]));
++ buf[20] = prefixLength;
++ buf[21] = status;
++
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_DHCPV6_DYNAMIC_DUID_STOR_LEN:
++ {
++ uint8_t duidLength = 0;
++ // Only 1 read-only 16-byte Block needed
++ duidLength = 1;
++
++ std::array<uint8_t, 2> buf = {current_revision, duidLength};
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_DHCPV6_DYNAMIC_DUIDS:
++ {
++ std::string macAddress;
++ if (channelConf->lan_set_in_progress == SET_COMPLETE)
++ {
++ auto macObjectInfo =
++ ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE,
++ ipmi::network::ROOT, ethdevice);
++
++ auto variant = ipmi::getDbusProperty(
++ bus, macObjectInfo.second, macObjectInfo.first,
++ ipmi::network::MAC_INTERFACE, "MACAddress");
++
++ macAddress =
++ sdbusplus::message::variant_ns::get<std::string>(variant);
++ }
++ else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS)
++ {
++ macAddress = channelConf->macAddress;
++ }
++
++ std::array<uint8_t,
++ ipmi::network::IPV6_DUID_SIZE + sizeof(current_revision)>
++ buf;
++ buf = {current_revision,
++ reqptr->parameter_set,
++ reqptr->parameter_block,
++ DUID_LEN,
++ 0, // Filler byte
++ DUID_LL_TYPE,
++ 0, // Filler byte
++ DUIC_ETH_HW_TYPE};
++
++ sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
++ (&buf[8]), (&buf[9]), (&buf[10]), (&buf[11]), (&buf[12]),
++ (&buf[13]));
++
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_ROUTER_ADDRESS_CONF_CTRL:
++ {
++ // Determine if automated router discovery occurs when static
++ // addresses are used for the bmc
++
++ auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE;
++ std::string networkInterfacePath;
++ uint8_t dynamicRA;
++ if (channelConf->lan_set_in_progress == SET_COMPLETE)
++ {
++
++ try
++ {
++ ipmi::ObjectTree ancestorMap;
++ // if the system is having ip object,then
++ // get the IP object.
++ auto ipObject =
++ ipmi::getDbusObject(bus, ipmi::network::IP_INTERFACE,
++ ipmi::network::ROOT, ethIP);
++
++ // Get the parent interface of the IP object.
++ try
++ {
++ ipmi::InterfaceList interfaces;
++ interfaces.emplace_back(
++ ipmi::network::ETHERNET_INTERFACE);
++
++ ancestorMap = ipmi::getAllAncestors(
++ bus, ipObject.first, std::move(interfaces));
++ }
++ catch (InternalFailure& e)
++ {
++ // if unable to get the parent interface
++ // then commit the error and return.
++ log<level::ERR>(
++ "Unable to get the parent interface",
++ entry("PATH=%s", ipObject.first.c_str()),
++ entry("INTERFACE=%s",
++ ipmi::network::ETHERNET_INTERFACE));
++ return IPMI_CC_UNSPECIFIED_ERROR;
++ }
++ // for an ip object there would be single parent
++ // interface.
++ networkInterfacePath = ancestorMap.begin()->first;
++ }
++ catch (InternalFailure& e)
++ {
++ // if there is no ip configured on the system,then
++ // get the network interface object.
++ auto networkInterfaceObject = ipmi::getDbusObject(
++ bus, ipmi::network::ETHERNET_INTERFACE,
++ ipmi::network::ROOT, ethdevice);
++
++ networkInterfacePath = networkInterfaceObject.first;
++ }
++
++ auto variant = ipmi::getDbusProperty(
++ bus, ipmi::network::SERVICE, networkInterfacePath,
++ ipmi::network::ETHERNET_INTERFACE, "IPv6AcceptRA");
++ dynamicRA = sdbusplus::message::variant_ns::get<bool>(variant);
++ }
++ else
++ {
++ dynamicRA = channelConf->ipv6RouterAddressConfigControl;
++ }
++
++ std::array<uint8_t, 2> buf = {current_revision, dynamicRA};
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_STATIC_ROUTER_1_IP_ADDR:
++ {
++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_SIZE_BYTE +
++ sizeof(current_revision)>
++ buf = {current_revision};
++ inet_pton(AF_INET6, channelConf->ipv6GatewayAddr.c_str(),
++ reinterpret_cast<void*>(&buf[1]));
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_LEN:
++ {
++ std::array<uint8_t, 2> buf = {current_revision,
++ channelConf->ipv6GatewayPrefixLength};
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_STATIC_ROUTER_1_PREFIX_VAL:
++ {
++ constexpr uint8_t setSelector = 0;
++ std::array<uint8_t, sizeof(setSelector) +
++ ipmi::network::IPV6_ADDRESS_SIZE_BYTE +
++ sizeof(current_revision)>
++ buf = {current_revision, setSelector};
++
++ inet_pton(AF_INET6, channelConf->ipv6GatewayPrefixValue.c_str(),
++ reinterpret_cast<void*>(&buf[2]));
++
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_STATIC_ROUTER_2_IP_ADDR:
++ {
++ std::array<uint8_t, ipmi::network::IPV6_ADDRESS_SIZE_BYTE +
++ sizeof(current_revision)>
++ buf = {current_revision};
++ inet_pton(AF_INET6, channelConf->ipv6BackupGatewayAddr.c_str(),
++ reinterpret_cast<void*>(&buf[1]));
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_LEN:
++ {
++ std::array<uint8_t, 2> buf = {
++ current_revision, channelConf->ipv6BackupGatewayPrefixLength};
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
++ case LanParam::IPV6_STATIC_ROUTER_2_PREFIX_VAL:
++ {
++
++ constexpr uint8_t setSelector = 0;
++ std::array<uint8_t, sizeof(setSelector) +
++ ipmi::network::IPV6_ADDRESS_SIZE_BYTE +
++ sizeof(current_revision)>
++ buf = {current_revision, setSelector};
++ inet_pton(AF_INET6,
++ channelConf->ipv6BackupGatewayPrefixValue.c_str(),
++ reinterpret_cast<void*>(&buf[2]));
++
++ std::copy(buf.begin(), buf.end(), static_cast<uint8_t*>(response));
++ *data_len = buf.size();
++ break;
++ }
+ default:
+ log<level::ERR>("Unsupported parameter",
+ entry("PARAMETER=0x%x", reqptr->parameter));
+@@ -932,6 +1570,16 @@ void applyChanges(int channel)
+ ipaddress, prefix);
+ }
+
++ if (!channelConf->ipv6Addr.empty() &&
++ channelConf->ipv6AddressSource ==
++ 0x80) // Check if IPv6 static addresses are enabled
++ {
++ ipmi::network::createIP(bus, ipmi::network::SERVICE,
++ networkInterfacePath, ipv6Protocol,
++ channelConf->ipv6Addr,
++ channelConf->ipv6Prefix);
++ }
++
+ if (!gateway.empty())
+ {
+ ipmi::setDbusProperty(bus, systemObject.second,
+@@ -939,7 +1587,24 @@ void applyChanges(int channel)
+ ipmi::network::SYSTEMCONFIG_INTERFACE,
+ "DefaultGateway", std::string(gateway));
+ }
++ else if (!channelConf->ipv6GatewayAddr.empty())
++ {
++ ipmi::setDbusProperty(
++ bus, systemObject.second, systemObject.first,
++ ipmi::network::SYSTEMCONFIG_INTERFACE, "DefaultGateway",
++ std::string(channelConf->ipv6GatewayAddr));
++ }
+ }
++ // set IPAddress Enables
++ ipmi::setDbusProperty(
++ bus, ipmi::network::SERVICE, networkInterfaceObject.first,
++ ipmi::network::ETHERNET_INTERFACE, "IPAddressEnables",
++ ipAddressEnablesType[channelConf->ipv6AddressingEnables]);
++
++ ipmi::setDbusProperty(
++ bus, ipmi::network::SERVICE, networkInterfaceObject.first,
++ ipmi::network::ETHERNET_INTERFACE, "IPv6AcceptRA",
++ (bool)channelConf->ipv6RouterAddressConfigControl);
+ }
+ catch (InternalFailure& e)
+ {
+Index: phosphor-host-ipmid.clean/transporthandler.hpp
+===================================================================
+--- phosphor-host-ipmid.clean.orig/transporthandler.hpp
++++ phosphor-host-ipmid.clean/transporthandler.hpp
+@@ -80,6 +80,28 @@ enum class LanParam : uint8_t
+ IPV6_NEIGHBOR_TIMING_CONFIGURATION = 80,
+ };
+
++// Data length of parameters
++constexpr size_t LAN_PARAM_INPROGRESS_SIZE = 3;
++constexpr size_t LAN_PARAM_IP_SIZE = 6;
++constexpr size_t LAN_PARAM_IPSRC_SIZE = 3;
++constexpr size_t LAN_PARAM_MAC_SIZE = 8;
++constexpr size_t LAN_PARAM_SUBNET_SIZE = 6;
++constexpr size_t LAN_PARAM_GATEWAY_SIZE = 6;
++constexpr size_t LAN_PARAM_VLAN_SIZE = 4;
++constexpr size_t LAN_PARAM_IPV6_AND_IPV4_ENABLES_SIZE = 3;
++constexpr size_t LAN_PARAM_IPV6_STATIC_ADDRESSES_SIZE = 23;
++constexpr size_t LAN_PARAM_IPV6_ROUTER_ADDRESS_CONF_CTRL_SIZE = 3;
++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_1_IP_ADDR_SIZE = 18;
++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_LEN_SIZE = 3;
++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_1_PREFIX_VAL_SIZE = 19;
++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_2_IP_ADDR_SIZE = 18;
++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_LEN_SIZE = 3;
++constexpr size_t LAN_PARAM_IPV6_STATIC_ROUTER_2_PREFIX_VAL_SIZE = 19;
++
++constexpr uint8_t DUID_LEN = 10;
++constexpr uint8_t DUID_LL_TYPE = 3;
++constexpr uint8_t DUIC_ETH_HW_TYPE = 1;
++
+ constexpr uint8_t SET_COMPLETE = 0;
+ constexpr uint8_t SET_IN_PROGRESS = 1;
+ constexpr uint8_t SET_COMMIT_WRITE = 2; // Optional
+@@ -102,6 +124,20 @@ struct ChannelConfig_t
+ uint8_t lan_set_in_progress = SET_COMPLETE;
+ bool flush = false;
+
++ // IPV6 parameters
++ uint8_t ipv6AddressSource = 0x0;
++ uint8_t ipv6AddressingEnables = 0x2;
++ std::string ipv6Addr;
++ uint8_t ipv6Prefix = 32;
++ uint8_t ipv6AddressStatus = 0x0;
++ uint8_t ipv6RouterAddressConfigControl = 0x0;
++ std::string ipv6GatewayAddr;
++ std::string ipv6BackupGatewayAddr;
++ uint8_t ipv6GatewayPrefixLength;
++ std::string ipv6GatewayPrefixValue;
++ uint8_t ipv6BackupGatewayPrefixLength = 0x0;
++ std::string ipv6BackupGatewayPrefixValue;
++
+ void clear()
+ {
+ ipaddr.clear();
+@@ -112,6 +148,20 @@ struct ChannelConfig_t
+ ipsrc = ipmi::network::IPOrigin::UNSPECIFIED;
+ lan_set_in_progress = SET_COMPLETE;
+ flush = false;
++
++ // IPv6
++ ipv6Addr.clear();
++ ipv6GatewayAddr.clear();
++ ipv6BackupGatewayAddr.clear();
++ ipv6AddressingEnables = 0x2;
++ ipv6AddressSource = 0x0;
++ ipv6Prefix = 32;
++ ipv6AddressStatus = 0x0;
++ ipv6RouterAddressConfigControl = 0x0;
++ ipv6GatewayPrefixLength = 0x0;
++ ipv6GatewayPrefixValue.clear();
++ ipv6BackupGatewayPrefixLength = 0x0;
++ ipv6BackupGatewayPrefixValue.clear();
+ }
+ };
+
+Index: phosphor-host-ipmid.clean/types.hpp
+===================================================================
+--- phosphor-host-ipmid.clean.orig/types.hpp
++++ phosphor-host-ipmid.clean/types.hpp
+@@ -209,6 +209,7 @@ constexpr auto ADDR_TYPE_FORMAT = "%hhx"
+
+ constexpr auto IPV4_ADDRESS_SIZE_BYTE = 4;
+ constexpr auto IPV6_ADDRESS_SIZE_BYTE = 16;
++constexpr auto IPV6_ADDRESS_STATUS_SIZE = 22;
+
+ constexpr auto DEFAULT_MAC_ADDRESS = "00:00:00:00:00:00";
+ constexpr auto DEFAULT_ADDRESS = "0.0.0.0";
+@@ -220,6 +221,7 @@ constexpr auto BITS_32 = 32;
+ constexpr auto MASK_32_BIT = 0xFFFFFFFF;
+ constexpr auto VLAN_ID_MASK = 0x00000FFF;
+ constexpr auto VLAN_ENABLE_MASK = 0x8000;
++constexpr auto IPV6_DUID_SIZE = 18;
+
+ enum class IPOrigin : uint8_t
+ {
+@@ -228,5 +230,12 @@ enum class IPOrigin : uint8_t
+ DHCP = 2,
+ };
+
++enum class AddressingEnables : uint8_t
++{
++ IPv4Only = 0,
++ IPv6Only = 1,
++ IPv4AndIPv6 = 2,
++};
++
+ } // namespace network
+ } // namespace ipmi
+Index: phosphor-host-ipmid.clean/utils.hpp
+===================================================================
+--- phosphor-host-ipmid.clean.orig/utils.hpp
++++ phosphor-host-ipmid.clean/utils.hpp
+@@ -246,6 +246,7 @@ namespace network
+ constexpr auto ROOT = "/xyz/openbmc_project/network";
+ constexpr auto SERVICE = "xyz.openbmc_project.Network";
+ constexpr auto IP_TYPE = "ipv4";
++constexpr auto IPV6_TYPE = "ipv6";
+ constexpr auto IPV4_PREFIX = "169.254";
+ constexpr auto IPV6_PREFIX = "fe80";
+ constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP";
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch
new file mode 100644
index 000000000..c1ec6ac6e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch
@@ -0,0 +1,56 @@
+From 4953a9f2233fd24a28da84443cea6aebecd14fbc Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Mon, 17 Sep 2018 13:20:54 +0800
+Subject: [PATCH] fix "get system GUID" ipmi command
+
+Change-Id: I15c71607c24ad8b3e2c9065a5470002ecb1761bb
+Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ apphandler.cpp | 7 ++-----
+ host-ipmid-whitelist.conf | 1 +
+ 2 files changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/apphandler.cpp b/apphandler.cpp
+index f2889c5..9149373 100644
+--- a/apphandler.cpp
++++ b/apphandler.cpp
+@@ -48,7 +48,7 @@ extern sd_bus* bus;
+
+ constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC";
+ constexpr auto bmc_state_property = "CurrentBMCState";
+-constexpr auto bmc_interface = "xyz.openbmc_project.Inventory.Item.Bmc";
++// phosphor-setting-manager is the unique service that holds this interface
+ constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID";
+ constexpr auto bmc_guid_property = "UUID";
+ constexpr auto bmc_guid_len = 16;
+@@ -546,8 +545,7 @@ ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ {
+ // Get the Inventory object implementing BMC interface
+ ipmi::DbusObjectInfo bmcObject =
+- ipmi::getDbusObject(bus, bmc_interface);
+-
++ ipmi::getDbusObject(bus, bmc_guid_interface);
+ // Read UUID property value from bmcObject
+ // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
+ auto variant =
+@@ -591,7 +589,6 @@ ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ catch (const InternalFailure& e)
+ {
+ log<level::ERR>("Failed in reading BMC UUID property",
+- entry("INTERFACE=%s", bmc_interface),
+ entry("PROPERTY_INTERFACE=%s", bmc_guid_interface),
+ entry("PROPERTY=%s", bmc_guid_property));
+ return IPMI_CC_UNSPECIFIED_ERROR;
+diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
+index 2c37ac9..164edbe 100644
+--- a/host-ipmid-whitelist.conf
++++ b/host-ipmid-whitelist.conf
+@@ -40,3 +40,4 @@
+ 0x2C:0x06 //<Group Extension>:<Get Asset Tag>
+ 0x2C:0x07 //<Group Extension>:<Get Sensor Info>
+ 0x2C:0x10 //<Group Extension>:<Get Temperature Readings>
++0x30:0x41 //<OEM>:<Set System GUID>
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0012-ipmi-set-get-boot-options.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0012-ipmi-set-get-boot-options.patch
new file mode 100644
index 000000000..243015c95
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0012-ipmi-set-get-boot-options.patch
@@ -0,0 +1,64 @@
+From 7b5c6a54c049a447b1fd3a42f9d63322dcee4dc7 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Sun, 16 Sep 2018 19:45:10 +0800
+Subject: [PATCH] [ipmi] set/get boot options
+
+1. fix issue for handling unsupported paramter
+2. add support for floppy/USB boot
+
+Change-Id: I2b888c1ad67fec7924dd5825f78622cd216a55f4
+Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ chassishandler.cpp | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/chassishandler.cpp b/chassishandler.cpp
+index 666addb..77af2dc 100644
+--- a/chassishandler.cpp
++++ b/chassishandler.cpp
+@@ -1244,7 +1244,8 @@ constexpr auto ipmiDefault = 0;
+ std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
+ {0x01, Source::Sources::Network},
+ {0x02, Source::Sources::Disk},
+- {0x05, Source::Sources::ExternalMedia},
++ {0x05, Source::Sources::DVD},
++ {0x0f, Source::Sources::Removable},
+ {ipmiDefault, Source::Sources::Default}};
+
+ std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
+@@ -1255,7 +1256,8 @@ std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
+ std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
+ {Source::Sources::Network, 0x01},
+ {Source::Sources::Disk, 0x02},
+- {Source::Sources::ExternalMedia, 0x05},
++ {Source::Sources::DVD, 0x05},
++ {Source::Sources::Removable, 0x0f},
+ {Source::Sources::Default, ipmiDefault}};
+
+ std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
+@@ -1533,7 +1535,7 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ setBootMode(Mode::Modes::Regular);
+ }
+ }
+- if (modeIpmiToDbus.end() != modeItr)
++ else if (modeIpmiToDbus.end() != modeItr)
+ {
+ rc = setBootMode(modeItr->second);
+ if (rc != IPMI_CC_OK)
+@@ -1550,6 +1552,12 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ setBootSource(Source::Sources::Default);
+ }
+ }
++ else
++ {
++ // if boot option is not in support list, return error
++ *data_len = 0;
++ return IPMI_CC_INVALID_FIELD_REQUEST;
++ }
+ }
+ catch (InternalFailure& e)
+ {
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch
new file mode 100644
index 000000000..ae10ab60a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0013-ipmi-add-set-bios-id-to-whitelist.patch
@@ -0,0 +1,25 @@
+From ad7276f3aedb6f5aed315db57406c98f2bf71a09 Mon Sep 17 00:00:00 2001
+From: "Jia, Chunhui" <chunhui.jia@intel.com>
+Date: Tue, 24 Jul 2018 13:21:52 +0800
+Subject: [PATCH] [ipmi] add set bios id to whitelist
+
+Add "SetBIOSId" and "GetDeviceInfo" 2 OEM commands into whitelist
+
+Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com>
+---
+ host-ipmid-whitelist.conf | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
+index 164edbe..db54a49 100644
+--- a/host-ipmid-whitelist.conf
++++ b/host-ipmid-whitelist.conf
+@@ -41,3 +41,5 @@
+ 0x2C:0x07 //<Group Extension>:<Get Sensor Info>
+ 0x2C:0x10 //<Group Extension>:<Get Temperature Readings>
+ 0x30:0x41 //<OEM>:<Set System GUID>
++0x30:0x26 //<OEM>:<Set BIOS ID>
++0x30:0x27 //<OEM>:<Get Device Info>
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0014-Enable-get-device-guid-ipmi-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0014-Enable-get-device-guid-ipmi-command.patch
new file mode 100644
index 000000000..46dd99466
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0014-Enable-get-device-guid-ipmi-command.patch
@@ -0,0 +1,45 @@
+From 482a6cc52d0ec514d6da5f4bcb04b4991f3cc36e Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Mon, 17 Sep 2018 13:41:25 +0800
+Subject: [PATCH] Enable get device guid ipmi command
+
+The UUID interface is changed, modify the API to get the correct UUID
+for device guid
+
+Change-Id: I0c0c7bd350992ac03f928707986a7180407d8f3f
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ apphandler.cpp | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/apphandler.cpp b/apphandler.cpp
+index 937be71..89d797a 100644
+--- a/apphandler.cpp
++++ b/apphandler.cpp
+@@ -392,9 +392,10 @@ ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_data_len_t data_len,
+ ipmi_context_t context)
+ {
+- const char* objname = "/xyz/openbmc_project/Chassis/Control/Chassis";
++ const char* objname =
++ "/xyz/openbmc_project/inventory/system/chassis/motherboard/bmc";
+ const char* iface = "org.freedesktop.DBus.Properties";
+- const char* chassis_iface = "xyz.openbmc_project.Chassis.Control.Chassis";
++ const char* uuid_iface = "xyz.openbmc_project.Common.UUID";
+ sd_bus_message* reply = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r = 0;
+@@ -426,8 +427,9 @@ ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ entry("ERRNO=0x%X", -r));
+ goto finish;
+ }
++
+ r = sd_bus_call_method(bus, busname, objname, iface, "Get", &error, &reply,
+- "ss", chassis_iface, "uuid");
++ "ss", uuid_iface, "UUID");
+ if (r < 0)
+ {
+ log<level::ERR>("Failed to call Get Method", entry("ERRNO=0x%X", -r));
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0016-add-better-sdbusplus-exception-handling.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0016-add-better-sdbusplus-exception-handling.patch
new file mode 100644
index 000000000..873eb6b16
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0016-add-better-sdbusplus-exception-handling.patch
@@ -0,0 +1,153 @@
+From a445f287d4aebca68dc0321e292933311caf59ba Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Sun, 16 Sep 2018 20:14:55 +0800
+Subject: [PATCH] add better sdbusplus exception handling
+
+Now that sdbusplus throws, we need to catch more stuff. To compound the
+problem, even though sdbusplus::exception::exception inherits from
+std::exception, there is a problem that prevents the code from simply
+catching std::exception.
+
+Change-Id: I2a330e542f5d87722a4c04e6d47de2cfb2f7d7c9
+Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+
+---
+ apphandler.cpp | 14 +++++++--
+ ipmid.cpp | 77 +++++++++++++++++++++++++++++++++++---------------
+ 2 files changed, 66 insertions(+), 25 deletions(-)
+
+diff --git a/apphandler.cpp b/apphandler.cpp
+index 126de33..3cae6d5 100644
+--- a/apphandler.cpp
++++ b/apphandler.cpp
+@@ -312,9 +312,19 @@ ipmi_ret_t ipmi_app_get_device_id(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ auto version = getActiveSoftwareVersionInfo();
+ r = convert_version(version.c_str(), &rev);
+ }
+- catch (const std::exception& e)
++ catch (sdbusplus::exception::exception& e)
+ {
+- log<level::ERR>(e.what());
++ log<level::ERR>("sdbusplus::exception",
++ entry("ERROR=%s", e.what()));
++ }
++ catch (std::exception& e)
++ {
++ log<level::ERR>("unexpected exception",
++ entry("ERROR=%s", e.what()));
++ }
++ catch (...)
++ {
++ log<level::ERR>("unknown exception");
+ }
+
+ if (r >= 0)
+diff --git a/ipmid.cpp b/ipmid.cpp
+index 2d48bfe..8d2fb37 100644
+--- a/ipmid.cpp
++++ b/ipmid.cpp
+@@ -273,6 +273,10 @@ ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ }
+ // IPMI command handlers can throw unhandled exceptions, catch those
+ // and return sane error code.
++ catch (sdbusplus::exception::exception& e)
++ {
++ log<level::ERR>("sdbusplus exception", entry("EXCEPTION=%s", e.what()));
++ }
+ catch (const std::exception& e)
+ {
+ log<level::ERR>(e.what(), entry("NET_FUN=0x%X", netfn),
+@@ -281,6 +285,23 @@ ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ *data_len = 0;
+ // fall through
+ }
++ catch (...)
++ {
++ std::exception_ptr eptr = std::current_exception();
++ try
++ {
++ std::rethrow_exception(eptr);
++ }
++ catch (std::exception& e)
++ {
++ log<level::ERR>("unexpected uncaught exception",
++ entry("EXCEPTION=%s", e.what()),
++ entry("NET_FUN=0x%X", netfn),
++ entry("CMD=0x%X", cmd));
++ rc = IPMI_CC_UNSPECIFIED_ERROR;
++ *data_len = 0;
++ }
++ }
+ // Now copy the return code that we got from handler and pack it in first
+ // byte.
+ std::memcpy(response, &rc, IPMI_CC_LEN);
+@@ -361,32 +382,42 @@ final:
+ void cache_restricted_mode()
+ {
+ restricted_mode = false;
+- using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
+- using namespace internal;
+- using namespace internal::cache;
+- sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
+- const auto& restrictionModeSetting =
+- objects->map.at(restrictionModeIntf).front();
+- auto method = dbus.new_method_call(
+- objects->service(restrictionModeSetting, restrictionModeIntf).c_str(),
+- restrictionModeSetting.c_str(), "org.freedesktop.DBus.Properties",
+- "Get");
+- method.append(restrictionModeIntf, "RestrictionMode");
+- auto resp = dbus.call(method);
+- if (resp.is_method_error())
++ try
+ {
+- log<level::ERR>("Error in RestrictionMode Get");
+- // Fail-safe to true.
+- restricted_mode = true;
+- return;
++ using namespace sdbusplus::xyz::openbmc_project::Control::Security::
++ server;
++ using namespace internal;
++ using namespace internal::cache;
++ sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
++ const auto& restrictionModeSetting =
++ objects->map.at(restrictionModeIntf).front();
++ auto method = dbus.new_method_call(
++ objects->service(restrictionModeSetting, restrictionModeIntf)
++ .c_str(),
++ restrictionModeSetting.c_str(), "org.freedesktop.DBus.Properties",
++ "Get");
++ method.append(restrictionModeIntf, "RestrictionMode");
++ auto resp = dbus.call(method);
++ if (resp.is_method_error())
++ {
++ log<level::ERR>("Error in RestrictionMode Get");
++ // Fail-safe to true.
++ restricted_mode = true;
++ return;
++ }
++ sdbusplus::message::variant<std::string> result;
++ resp.read(result);
++ auto restrictionMode = RestrictionMode::convertModesFromString(
++ sdbusplus::message::variant_ns::get<std::string>(result));
++ if (RestrictionMode::Modes::Whitelist == restrictionMode)
++ {
++ restricted_mode = true;
++ }
+ }
+- sdbusplus::message::variant<std::string> result;
+- resp.read(result);
+- auto restrictionMode = RestrictionMode::convertModesFromString(
+- variant_ns::get<std::string>(result));
+- if (RestrictionMode::Modes::Whitelist == restrictionMode)
++ catch (sdbusplus::exception::exception& e)
+ {
+- restricted_mode = true;
++ // restrictionModeIntf does not exist; default to not enforcing
++ log<level::ERR>("sdbusplus exception", entry("EXCEPTION=%s", e.what()));
+ }
+ }
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0018-Catch-sdbusplus-exceptions-in-IPMI-net.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0018-Catch-sdbusplus-exceptions-in-IPMI-net.patch
new file mode 100644
index 000000000..6fa69b602
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0018-Catch-sdbusplus-exceptions-in-IPMI-net.patch
@@ -0,0 +1,49 @@
+From 4490ee7a9fd054640af7a9da3400f76195dc2880 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Sun, 16 Sep 2018 21:03:58 +0800
+Subject: [PATCH] Catch sdbusplus exceptions in IPMI net
+
+Missing the correct exception was causing issues with setting the IPV4
+address
+
+Change-Id: Ieaaacfcbaec82a0c3b110889817a7ceb9cda8d3c
+Signed-off-by: Dave Cobbley <david.j.cobbley@linux.intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ transporthandler.cpp | 2 +-
+ utils.cpp | 5 +++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/transporthandler.cpp b/transporthandler.cpp
+index 6f4ec3f..6cb3feb 100644
+--- a/transporthandler.cpp
++++ b/transporthandler.cpp
+@@ -1559,7 +1559,7 @@ void applyChanges(int channel)
+ ipmi::network::ETHERNET_INTERFACE, "IPv6AcceptRA",
+ (bool)channelConf->ipv6RouterAddressConfigControl);
+ }
+- catch (InternalFailure& e)
++ catch (sdbusplus::exception::exception& e)
+ {
+ log<level::ERR>(
+ "Failed to set network data", entry("PREFIX=%d", prefix),
+diff --git a/utils.cpp b/utils.cpp
+index 225b1cc..d10b5de 100644
+--- a/utils.cpp
++++ b/utils.cpp
+@@ -358,9 +358,10 @@ void deleteAllDbusObjects(sdbusplus::bus::bus& bus,
+ "Delete");
+ }
+ }
+- catch (InternalFailure& e)
++ catch (sdbusplus::exception::exception& e)
+ {
+- log<level::INFO>("Unable to delete the objects having",
++ log<level::INFO>("sdbusplus exception - Unable to delete the objects",
++ entry("ERROR=%s", e.what()),
+ entry("INTERFACE=%s", interface.c_str()),
+ entry("SERVICE=%s", serviceRoot.c_str()));
+ }
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0021-Implement-IPMI-Commmand-Get-Host-Restart-Cause.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0021-Implement-IPMI-Commmand-Get-Host-Restart-Cause.patch
new file mode 100644
index 000000000..af526c177
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0021-Implement-IPMI-Commmand-Get-Host-Restart-Cause.patch
@@ -0,0 +1,143 @@
+From c14e31ebc35e0bb7b843d84683f9f2698c9c08d7 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Sun, 16 Sep 2018 21:32:38 +0800
+Subject: [PATCH] Implement IPMI Commmand - Get Host Restart Cause.
+
+It supports to track the information about what
+action last caused the system to restart.
+Return value includes: restart_cause and channel_number.
+
+According to IPMI Spec, it includes 12 types as following:
+1. Unknown 0x0
+2. IpmiCommand 0x1
+3. ResetButton 0x2
+4. PowerButton 0x3
+5. WatchdogTimer 0x4
+6. OEM 0x5
+7. PowerPolicyAlwaysOn 0x6
+8. PowerPolicyPreviousState 0x7
+9. PEF-Reset 0x8
+10. PEF-PowerCycle 0x9
+11. SoftReset 0xA
+12. RTC-Wakeup 0xB
+
+Change-Id: Id3b32e271b85b5fc4c69d5ca40227f8f9c08ce48
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ chassishandler.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++
+ chassishandler.hpp | 1 +
+ host-ipmid-whitelist.conf | 1 +
+ 3 files changed, 56 insertions(+)
+
+diff --git a/chassishandler.cpp b/chassishandler.cpp
+index 77af2dc..2a29755 100644
+--- a/chassishandler.cpp
++++ b/chassishandler.cpp
+@@ -107,6 +107,11 @@ static constexpr auto chassisPOHStateIntf =
+ "xyz.openbmc_project.State.PowerOnHours";
+ static constexpr auto pOHCounterProperty = "POHCounter";
+ static constexpr auto match = "chassis0";
++const static constexpr char* stateHostInterface =
++ "xyz.openbmc_project.State.Host";
++const static constexpr char* hostRestartCauseInterface =
++ "xyz.openbmc_project.State.Host.HostRestartCause";
++const static constexpr char* hostRestartCause = "HostRestartCause";
+ const static constexpr char chassisCapIntf[] =
+ "xyz.openbmc_project.Control.ChassisCapabilities";
+ const static constexpr char chassisCapFlagsProp[] = "CapabilitiesFlags";
+@@ -324,6 +329,13 @@ struct set_sys_boot_options_t
+ uint8_t data[SIZE_BOOT_OPTION];
+ } __attribute__((packed));
+
++struct GetSysRestartCauseResponse
++{
++ uint8_t restartCause;
++ uint8_t channelNum;
++
++} __attribute__((packed));
++
+ int getHostNetworkData(get_sys_boot_options_response_t* respptr)
+ {
+ ipmi::PropertyMap properties;
+@@ -1598,6 +1610,44 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ return rc;
+ }
+
++ipmi_ret_t ipmi_chassis_get_sys_restart_cause(
++ ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
++ ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
++{
++ ipmi_ret_t rc = IPMI_CC_OK;
++
++ GetSysRestartCauseResponse* resp = (GetSysRestartCauseResponse*)response;
++ std::fill(reinterpret_cast<uint8_t*>(resp),
++ reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
++ if (*data_len != 0)
++ {
++ rc = IPMI_CC_REQ_DATA_LEN_INVALID;
++ return rc;
++ }
++
++ try
++ {
++ sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
++ ipmi::DbusObjectInfo hostObject =
++ ipmi::getDbusObject(bus, stateHostInterface);
++ ipmi::Value variant =
++ ipmi::getDbusProperty(bus, hostObject.second, hostObject.first,
++ hostRestartCauseInterface, hostRestartCause);
++ resp->restartCause = variant.get<uint8_t>();
++ }
++
++ catch (std::exception& e)
++ {
++ log<level::ERR>(e.what());
++ rc = IPMI_CC_UNSPECIFIED_ERROR;
++ return rc;
++ }
++ resp->channelNum = 0; // Fix to primary channel.
++ *data_len = sizeof(GetSysRestartCauseResponse);
++
++ return rc;
++}
++
+ ipmi_ret_t ipmiGetPOHCounter(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+@@ -1739,4 +1789,8 @@ void register_netfn_chassis_functions()
+ ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_RESTORE_POLICY, NULL,
+ ipmi_chassis_set_power_restore_policy,
+ PRIVILEGE_OPERATOR);
++
++ // <get Host Restart Cause>
++ ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_SYS_RESTART_CAUSE, NULL,
++ ipmi_chassis_get_sys_restart_cause, PRIVILEGE_USER);
+ }
+diff --git a/chassishandler.hpp b/chassishandler.hpp
+index 0c6d5a2..e37c4f1 100644
+--- a/chassishandler.hpp
++++ b/chassishandler.hpp
+@@ -17,6 +17,7 @@ enum ipmi_netfn_chassis_cmds
+ // Set Power Restore Policy
+ IPMI_CMD_SET_RESTORE_POLICY = 0x06,
+ // Get capability bits
++ IPMI_CMD_GET_SYS_RESTART_CAUSE = 0x07,
+ IPMI_CMD_SET_SYS_BOOT_OPTIONS = 0x08,
+ IPMI_CMD_GET_SYS_BOOT_OPTIONS = 0x09,
+ IPMI_CMD_GET_POH_COUNTER = 0x0F,
+diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
+index db54a49..827e2dc 100644
+--- a/host-ipmid-whitelist.conf
++++ b/host-ipmid-whitelist.conf
+@@ -3,6 +3,7 @@
+ 0x00:0x02 //<Chassis>:<Chassis Control>
+ 0x00:0x05 //<Chassis>:<Set Chassis Capabilities>
+ 0x00:0x06 //<Chassis>:<Set Power Restore Policy>
++0x00:0x07 //<Chassis>:<Get System Restart Cause>
+ 0x00:0x08 //<Chassis>:<Set System Boot Options>
+ 0x00:0x09 //<Chassis>:<Get System Boot Options>
+ 0x00:0x0F //<Chassis>:<Get POH Counter Command>
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch
new file mode 100644
index 000000000..fdaa91085
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch
@@ -0,0 +1,25 @@
+From cf466ba2c66a95825ae0014d7c378ad63b050d2f Mon Sep 17 00:00:00 2001
+From: "Jia, Chunhui" <chunhui.jia@intel.com>
+Date: Wed, 15 Aug 2018 14:50:04 +0800
+Subject: [PATCH] [ipmi] add oem command "get AIC FRU" to whitelist
+
+Intel BIOS requires this oem command to get addon card FRU info.
+Add to whitelist to unblock.
+
+Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com>
+---
+ host-ipmid-whitelist.conf | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
+index db54a49..49746a2 100644
+--- a/host-ipmid-whitelist.conf
++++ b/host-ipmid-whitelist.conf
+@@ -43,3 +43,4 @@
+ 0x30:0x41 //<OEM>:<Set System GUID>
+ 0x30:0x26 //<OEM>:<Set BIOS ID>
+ 0x30:0x27 //<OEM>:<Get Device Info>
++0x30:0x31 //<OEM>:<Get AIC card FRU>
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch
new file mode 100644
index 000000000..4018dbffe
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0048-Implement-IPMI-Master-Write-Read-command.patch
@@ -0,0 +1,322 @@
+From cd25f43461b41b74d19cd1f93ce301df9c3bd4f2 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Fri, 21 Sep 2018 09:21:14 +0800
+Subject: [PATCH] Implement IPMI Master Write-Read command
+
+This command can be used for low-level I2C/SMBus write, read, or write-read
+accesses to the IPMB or private busses behind a management controller.
+
+The command can also be used for providing low-level access to devices
+that provide an SMBus slave interface.
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ apphandler.cpp | 236 ++++++++++++++++++++++++++++++++++++++++++++++
+ apphandler.hpp | 1 +
+ host-ipmid-whitelist.conf | 1 +
+ 3 files changed, 238 insertions(+)
+
+diff --git a/apphandler.cpp b/apphandler.cpp
+index 17aff2a..2fe79f6 100644
+--- a/apphandler.cpp
++++ b/apphandler.cpp
+@@ -8,6 +8,14 @@
+ #include "types.hpp"
+ #include "utils.hpp"
+
++#include <fcntl.h>
++#include <linux/i2c-dev.h>
++#include <linux/i2c.h>
++#include <sys/ioctl.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++#include <unistd.h>
++
+ #include <arpa/inet.h>
+ #include <host-ipmid/ipmid-api.h>
+ #include <limits.h>
+@@ -55,6 +63,8 @@ constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID";
+ constexpr auto bmc_guid_property = "UUID";
+ constexpr auto bmc_guid_len = 16;
+
++static constexpr uint8_t maxIPMIWriteReadSize = 144;
++
+ static constexpr auto redundancyIntf =
+ "xyz.openbmc_project.Software.RedundancyPriority";
+ static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version";
+@@ -86,6 +96,34 @@ typedef struct
+ uint8_t aux[4];
+ } __attribute__((packed)) ipmi_device_id_t;
+
++typedef struct
++{
++ uint8_t busId;
++ uint8_t slaveAddr;
++ uint8_t readCount;
++} __attribute__((packed)) ipmiI2cRwReq;
++
++typedef struct
++{
++ uint8_t busId;
++ uint8_t slaveAddr;
++ std::vector<uint8_t> data;
++} ipmiMasterRwWhitelist;
++
++static std::vector<ipmiMasterRwWhitelist>& getWhiteList()
++{
++ static std::vector<ipmiMasterRwWhitelist> rwWhiteList;
++ return rwWhiteList;
++}
++
++static constexpr const char* whiteListFilename =
++ "/usr/share/ipmi-providers/master_write_read_white_list.json";
++
++static constexpr const char* filtersStr = "filters";
++static constexpr const char* busIdStr = "busId";
++static constexpr const char* slaveAddrStr = "slaveAddr";
++static constexpr const char* cmdStr = "command";
++
+ /**
+ * @brief Returns the Version info from primary s/w object
+ *
+@@ -1089,8 +1127,195 @@ writeResponse:
+ return IPMI_CC_OK;
+ }
+
++static int loadI2CWhiteList()
++{
++ nlohmann::json data = nullptr;
++ std::ifstream jsonFile(whiteListFilename);
++
++ if (!jsonFile.good())
++ {
++ log<level::WARNING>("whitelist file not found!");
++ return -1;
++ }
++
++ try
++ {
++ data = nlohmann::json::parse(jsonFile, nullptr, false);
++ }
++ catch (nlohmann::json::parse_error& e)
++ {
++ log<level::ERR>("Corrupted whitelist config file",
++ entry("MSG: %s", e.what()));
++ return -1;
++ }
++
++ try
++ {
++ unsigned int i = 0;
++ nlohmann::json filters = data[filtersStr].get<nlohmann::json>();
++ getWhiteList().resize(filters.size());
++
++ for (const auto& it : filters.items())
++ {
++ nlohmann::json filter = it.value();
++ if (filter.is_null())
++ {
++ log<level::ERR>("Incorrect filter");
++ return -1;
++ }
++
++ getWhiteList()[i].busId =
++ std::stoul(filter[busIdStr].get<std::string>(), nullptr, 16);
++
++ getWhiteList()[i].slaveAddr = std::stoul(
++ filter[slaveAddrStr].get<std::string>(), nullptr, 16);
++
++ std::string command = filter[cmdStr].get<std::string>();
++
++ log<level::DEBUG>("IPMI I2C whitelist ", entry("INDEX=%d", i),
++ entry("BUS=%d", getWhiteList()[i].busId),
++ entry("ADDR=0x%x", getWhiteList()[i].slaveAddr),
++ entry("LEN=0x%x", command.length()),
++ entry("COMMAND=[%s]", command.c_str()));
++
++ // convert data string
++ std::istringstream iss(command);
++ std::string token;
++ while (std::getline(iss, token, ' '))
++ {
++ log<level::DEBUG>("IPMI I2C command\n",
++ entry("TOKEN=%s", token.c_str()));
++ getWhiteList()[i].data.emplace_back(
++ std::stoul(token, nullptr, 16));
++ }
++ i++;
++ }
++ }
++ catch (std::exception& e)
++ {
++ log<level::ERR>("unexpected exception", entry("ERROR=%s", e.what()));
++ return -1;
++ }
++ return 0;
++}
++
++ipmi_ret_t ipmiMasterWriteRead(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
++ ipmi_request_t request, ipmi_response_t response,
++ ipmi_data_len_t data_len, ipmi_context_t context)
++{
++ bool foundInList = false;
++ int ret = 0;
++ i2c_rdwr_ioctl_data msgRdwr = {0};
++ i2c_msg i2cmsg[2] = {0};
++ ipmiI2cRwReq* reqi2c = reinterpret_cast<ipmiI2cRwReq*>(request);
++
++ if (*data_len <= sizeof(ipmiI2cRwReq))
++ {
++ log<level::ERR>("Failed in request", entry("LEN=%d", *data_len));
++ *data_len = 0;
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++
++ if (reqi2c->readCount > maxIPMIWriteReadSize)
++ {
++ log<level::ERR>("Failed in request", entry("R=%d", reqi2c->readCount));
++ *data_len = 0;
++ return IPMI_CC_PARM_OUT_OF_RANGE;
++ }
++
++ uint8_t* resptr = reinterpret_cast<uint8_t*>(response);
++ uint8_t busId = (reqi2c->busId & 0xFF) >> 1;
++ // Convert the I2C address from 7-bit format
++ uint8_t i2cAddr = reqi2c->slaveAddr >> 1;
++ size_t writeCount = *data_len - sizeof(ipmiI2cRwReq);
++
++ log<level::DEBUG>(
++ "INPUT: ", entry("LEN=%d", *data_len), entry("ID=0x%x", busId),
++ entry("ADDR=0x%x", reqi2c->slaveAddr), entry("R=%d", reqi2c->readCount),
++ entry("W=%d", writeCount));
++
++ *data_len = 0;
++
++ std::vector<uint8_t> inBuf(reqi2c->readCount);
++ std::vector<uint8_t> outBuf(writeCount);
++ uint8_t* reqptr = reinterpret_cast<uint8_t*>(request);
++
++ reqptr += sizeof(ipmiI2cRwReq);
++ std::copy(reqptr, reqptr + writeCount, outBuf.begin());
++
++ log<level::DEBUG>("checking list ", entry("SIZE=%d", getWhiteList().size()));
++ // command whitelist checking
++ for (unsigned int i = 0; i < getWhiteList().size(); i++)
++ {
++ // TODO add wildchard/regex support
++ if ((busId == getWhiteList()[i].busId) &&
++ (i2cAddr == getWhiteList()[i].slaveAddr) &&
++ (outBuf == getWhiteList()[i].data))
++ {
++ log<level::DEBUG>("In whitelist");
++ foundInList = true;
++ break;
++ }
++ }
++
++ if (!foundInList)
++ {
++ log<level::ERR>("Request blocked!", entry("BUS=%d", busId),
++ entry("ADDR=0x%x", reqi2c->slaveAddr));
++ return IPMI_CC_INVALID_FIELD_REQUEST;
++ }
++
++ log<level::DEBUG>("IPMI Master WriteRead ", entry("BUS=%d", busId),
++ entry("ADDR=0x%x", reqi2c->slaveAddr),
++ entry("R=%d", reqi2c->readCount),
++ entry("W=%d", writeCount));
++
++ std::string i2cBus = "/dev/i2c-" + std::to_string(busId);
++
++ int i2cDev = ::open(i2cBus.c_str(), O_RDWR | O_CLOEXEC);
++ if (i2cDev < 0)
++ {
++ log<level::ERR>("Failed in opening i2c device",
++ entry("BUS=%s", i2cBus.c_str()));
++ return IPMI_CC_UNSPECIFIED_ERROR;
++ }
++
++ // write message
++ i2cmsg[0].addr = i2cAddr;
++ i2cmsg[0].flags = 0x00;
++ i2cmsg[0].len = writeCount;
++ i2cmsg[0].buf = outBuf.data();
++
++ // read message
++ i2cmsg[1].addr = i2cAddr;
++ i2cmsg[1].flags = I2C_M_RD;
++ i2cmsg[1].len = reqi2c->readCount;
++ i2cmsg[1].buf = inBuf.data();
++
++ msgRdwr.msgs = i2cmsg;
++ msgRdwr.nmsgs = 2;
++
++ ret = ::ioctl(i2cDev, I2C_RDWR, &msgRdwr);
++ ::close(i2cDev);
++
++ // TODO add completion code support
++ if (ret < 0)
++ {
++ log<level::ERR>("RDWR ioctl error", entry("RET=%d", ret));
++ return IPMI_CC_UNSPECIFIED_ERROR;
++ }
++
++ *data_len = msgRdwr.msgs[1].len;
++ std::copy(msgRdwr.msgs[1].buf, msgRdwr.msgs[1].buf + msgRdwr.msgs[1].len,
++ resptr);
++
++ return IPMI_CC_OK;
++}
++
+ void register_netfn_app_functions()
+ {
++ int ret = -1;
++
+ // <Get BT Interface Capabilities>
+ ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CAP_BIT, NULL,
+ ipmi_app_get_bt_capabilities, PRIVILEGE_USER);
+@@ -1145,6 +1370,17 @@ void register_netfn_app_functions()
+ ipmi_app_channel_info, PRIVILEGE_USER);
+ #endif
+
++ ret = loadI2CWhiteList();
++ log<level::DEBUG>("i2c white list is loaded", entry("RET=%d", ret),
++ entry("SIZE=%d", getWhiteList().size()));
++ if (ret == 0)
++ {
++ log<level::DEBUG>("Register Master RW command");
++ // <Master Write Read Command>
++ ipmi_register_callback(NETFUN_APP, IPMI_CMD_MASTER_WRITE_READ, NULL,
++ ipmiMasterWriteRead, PRIVILEGE_OPERATOR);
++ }
++
+ // <Get System GUID Command>
+ ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYS_GUID, NULL,
+ ipmi_app_get_sys_guid, PRIVILEGE_USER);
+diff --git a/apphandler.hpp b/apphandler.hpp
+index d4dd8e8..f9e5c59 100644
+--- a/apphandler.hpp
++++ b/apphandler.hpp
+@@ -19,6 +19,7 @@ enum ipmi_netfn_app_cmds
+ IPMI_CMD_SET_CHAN_ACCESS = 0x40,
+ IPMI_CMD_GET_CHANNEL_ACCESS = 0x41,
+ IPMI_CMD_GET_CHAN_INFO = 0x42,
++ IPMI_CMD_MASTER_WRITE_READ = 0x52,
+ IPMI_CMD_GET_CHAN_CIPHER_SUITES = 0x54,
+ IPMI_CMD_SET_SYSTEM_INFO = 0x58,
+ IPMI_CMD_GET_SYSTEM_INFO = 0x59,
+diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
+index c7eb2d8..22a2a3c 100644
+--- a/host-ipmid-whitelist.conf
++++ b/host-ipmid-whitelist.conf
+@@ -25,6 +25,7 @@
+ 0x06:0x36 //<App>:<Get BT Interface Capabilities>
+ 0x06:0x37 //<App>:<Get System GUID>
+ 0x06:0x42 //<App>:<Get Channel Info Command>
++0x06:0x52 //<App>:<Master Write Read Command>
+ 0x06:0x54 //<App>:<Get Channel Cipher Suites>
+ 0x0A:0x10 //<Storage>:<Get FRU Inventory Area Info>
+ 0x0A:0x11 //<Storage>:<Read FRU Data>
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0049-Fix-Unspecified-error-on-ipmi-restart-cause-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0049-Fix-Unspecified-error-on-ipmi-restart-cause-command.patch
new file mode 100644
index 000000000..aba5eb095
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0049-Fix-Unspecified-error-on-ipmi-restart-cause-command.patch
@@ -0,0 +1,71 @@
+From 59287a8869b5253a1b4203e0cc8a92f063dcc7e6 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Tue, 25 Sep 2018 16:08:22 +0800
+Subject: [PATCH] Fix "Unspecified error" on ipmi restart cause command
+
+Needs to convert the dbus value(enum) into ipmi value(uint8)
+
+Tested by:
+ipmitool chassis restart_cause
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ chassishandler.cpp | 28 ++++++++++++++++++++++++++--
+ 1 file changed, 26 insertions(+), 2 deletions(-)
+
+diff --git a/chassishandler.cpp b/chassishandler.cpp
+index 40eb4f5..c3d4931 100644
+--- a/chassishandler.cpp
++++ b/chassishandler.cpp
+@@ -106,7 +106,7 @@ static constexpr auto match = "chassis0";
+ const static constexpr char* stateHostInterface =
+ "xyz.openbmc_project.State.Host";
+ const static constexpr char* hostRestartCauseInterface =
+- "xyz.openbmc_project.State.Host.HostRestartCause";
++ "xyz.openbmc_project.State.Host";
+ const static constexpr char* hostRestartCause = "HostRestartCause";
+ const static constexpr char chassisCapIntf[] =
+ "xyz.openbmc_project.Control.ChassisCapabilities";
+@@ -1764,6 +1764,26 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ return rc;
+ }
+
++namespace restart_cause
++{
++
++using namespace sdbusplus::xyz::openbmc_project::State::server;
++
++std::map<Host::RestartCause, uint8_t> dbusToIpmi = {
++ {Host::RestartCause::Unknown, 0x0},
++ {Host::RestartCause::IpmiCommand, 0x1},
++ {Host::RestartCause::ResetButton, 0x2},
++ {Host::RestartCause::PowerButton, 0x3},
++ {Host::RestartCause::WatchdogTimer, 0x4},
++ {Host::RestartCause::OEM, 0x5},
++ {Host::RestartCause::PowerPolicyAlwaysOn, 0x6},
++ {Host::RestartCause::PowerPolicyPreviousState, 0x7},
++ {Host::RestartCause::PEFReset, 0x8},
++ {Host::RestartCause::PEFPowerCycle, 0x9},
++ {Host::RestartCause::SoftReset, 0xa},
++ {Host::RestartCause::RTCWakeup, 0xb}};
++} // namespace restart_cause
++
+ ipmi_ret_t ipmi_chassis_get_sys_restart_cause(
+ ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
+ ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
+@@ -1787,7 +1807,11 @@ ipmi_ret_t ipmi_chassis_get_sys_restart_cause(
+ ipmi::Value variant =
+ ipmi::getDbusProperty(bus, hostObject.second, hostObject.first,
+ hostRestartCauseInterface, hostRestartCause);
+- resp->restartCause = variant.get<uint8_t>();
++
++ std::string restartCause =
++ sdbusplus::message::variant_ns::get<std::string>(variant);
++ resp->restartCause = restart_cause::dbusToIpmi.at(
++ restart_cause::Host::convertRestartCauseFromString(restartCause));
+ }
+
+ catch (std::exception& e)
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch
new file mode 100644
index 000000000..b800632cc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0050-enable-6-oem-commands.patch
@@ -0,0 +1,15 @@
+diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
+index 22a2a3c..5d71698 100644
+--- a/host-ipmid-whitelist.conf
++++ b/host-ipmid-whitelist.conf
+@@ -49,3 +49,10 @@
+ 0x30:0x26 //<OEM>:<Set BIOS ID>
+ 0x30:0x27 //<OEM>:<Get Device Info>
+ 0x30:0x31 //<OEM>:<Get AIC card FRU>
++0x30:0x54 //<OEM>:<Set Power Restore Delay>
++0x30:0x55 //<OEM>:<Get Power Restore Delay>
++0x30:0x9A //<OEM>:<Get Processor Error Config>
++0x30:0x9B //<OEM>:<Set Processor Error Config>
++0x30:0xB0 //<OEM>:<Get LED Status>
++0x30:0xE9 //<OEM>:<Get BIOS Post Codes>
++
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0051-Fix-Set-LAN-Config-to-work-without-SetInProgress.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0051-Fix-Set-LAN-Config-to-work-without-SetInProgress.patch
new file mode 100644
index 000000000..3990c6b5c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0051-Fix-Set-LAN-Config-to-work-without-SetInProgress.patch
@@ -0,0 +1,142 @@
+From cae9e21f88e6f12c80c89402473a17a10258c843 Mon Sep 17 00:00:00 2001
+From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
+Date: Thu, 17 Jan 2019 21:22:30 +0530
+Subject: [PATCH] Fix: Set LAN Config to work without SetInProgress
+
+Set LAN Configuration parameters in up-stream code works
+with SetInProgress (parameter selector 0), to be marked
+as SET_IN_PROGRESS before fields update, and SET_COMPLETE to
+make the changes effective. This is not mandatory as per
+IPMI Spec, and we must support individual fields update.
+Fix:
+1. After SET_COMPLETE for parameter selector, changes has
+to be applied immediately, and doesn't require to rely on
+network timer, as purpose of this logic itself is to stage
+and commit.
+2. Allow individual parameter changes to take effect based
+on timer. For the time being reduced the timer to 5 sec
+to have quicker turn-around and group things together.
+
+TODO:
+Still need to introduce lock between ChannelConfig variable
+between Timer & Get / Set LAN Configuration command to avoid
+race condition
+
+Unit-Test:
+1. Verified the BIOS Setup page, able to set the IPV4 to static
+IP, afte disabling IPV6, and configuring IPV4 to static, after
+save and reset, the changes of IPV4 static is preserved.
+
+Change-Id: I7c2edad2861b5dba5ad1ca97cc5e39ac02871746
+Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
+---
+ transporthandler.cpp | 54 ++++++++++++++++++++++++++++++++++++----------------
+ transporthandler.hpp | 2 ++
+ 2 files changed, 40 insertions(+), 16 deletions(-)
+
+Index: phosphor-host-ipmid.clean/transporthandler.cpp
+===================================================================
+--- phosphor-host-ipmid.clean.orig/transporthandler.cpp
++++ phosphor-host-ipmid.clean/transporthandler.cpp
+@@ -399,6 +399,41 @@ struct set_lan_t
+ uint8_t data[8]; // Per IPMI spec, not expecting more than this size
+ } __attribute__((packed));
+
++ipmi_ret_t checkAndUpdateNetwork(int channel)
++{
++ auto channelConf = getChannelConfig(channel);
++ using namespace std::chrono_literals;
++ // time to wait before applying the network changes.
++ constexpr auto networkTimeout = 5000000us; // 5 sec
++
++ if (channelConf->lan_set_in_progress == SET_COMPLETE &&
++ ((channelConf->flush == false) ||
++ (channelConf->updateInProgress == true)))
++ {
++ channelConf->flush = true;
++ // used to indicate that network timer update is in progress.
++ channelConf->updateInProgress = true;
++ if (!networkTimer)
++ {
++ log<level::ERR>("Network timer is not instantiated");
++ return IPMI_CC_UNSPECIFIED_ERROR;
++ }
++ // start/restart the timer
++ // TODO: Need to implement locking mechansim between networkTimer &
++ // get/set to avoid race condition.
++ networkTimer->start(networkTimeout);
++ }
++ else if (channelConf->lan_set_in_progress == SET_COMPLETE &&
++ channelConf->flush == true &&
++ channelConf->updateInProgress == false)
++ {
++ // Apply the network changes immediately, if proper SET_IN_PROGRESS,
++ // followed by SET_COMPLETE is issued.
++ applyChanges(channel);
++ }
++ return IPMI_CC_OK;
++}
++
+ ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request,
+ ipmi_response_t response,
+@@ -406,12 +441,6 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n
+ ipmi_context_t context)
+ {
+ ipmi_ret_t rc = IPMI_CC_OK;
+-
+- using namespace std::chrono_literals;
+-
+- // time to wait before applying the network changes.
+- constexpr auto networkTimeout = 10000000us; // 10 sec
+-
+ char ipaddr[INET_ADDRSTRLEN];
+ char netmask[INET_ADDRSTRLEN];
+ char gateway[INET_ADDRSTRLEN];
+@@ -543,15 +572,6 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n
+ entry("ADDRESS=%s", channelConf->ipaddr.c_str()),
+ entry("GATEWAY=%s", channelConf->gateway.c_str()),
+ entry("VLAN=%d", channelConf->vlanID));
+-
+- if (!networkTimer)
+- {
+- log<level::ERR>("Network timer is not instantiated");
+- return IPMI_CC_UNSPECIFIED_ERROR;
+- }
+-
+- // start/restart the timer
+- networkTimer->start(networkTimeout);
+ }
+ else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress
+ {
+@@ -680,8 +700,10 @@ ipmi_ret_t ipmi_transport_set_lan(ipmi_n
+ default:
+ {
+ rc = IPMI_CC_PARM_NOT_SUPPORTED;
++ return rc;
+ }
+ }
++ rc = checkAndUpdateNetwork(channel);
+
+ return rc;
+ }
+Index: phosphor-host-ipmid.clean/transporthandler.hpp
+===================================================================
+--- phosphor-host-ipmid.clean.orig/transporthandler.hpp
++++ phosphor-host-ipmid.clean/transporthandler.hpp
+@@ -140,6 +140,7 @@ struct ChannelConfig_t
+ // vlan id is in 12 bits and the 16th bit is for enable mask.
+ uint32_t vlanID = ipmi::network::VLAN_ID_MASK;
+ uint8_t lan_set_in_progress = SET_COMPLETE;
++ uint8_t updateInProgress = false;
+ bool flush = false;
+
+ // IPV6 parameters
+@@ -165,6 +166,7 @@ struct ChannelConfig_t
+ vlanID = ipmi::network::VLAN_ID_MASK;
+ ipsrc = ipmi::network::IPOrigin::UNSPECIFIED;
+ lan_set_in_progress = SET_COMPLETE;
++ updateInProgress = false;
+ flush = false;
+
+ // IPv6
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch
new file mode 100644
index 000000000..2a4cc9bb1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0053-Fix-keep-looping-issue-when-entering-OS.patch
@@ -0,0 +1,80 @@
+From 9ed3fd11047f8c360b7d808946939ef280813811 Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@linux.intel.com>
+Date: Wed, 23 Jan 2019 17:02:40 +0800
+Subject: [PATCH] Fix keep looping issue when entering OS
+
+Sometimes when entering OS, OS will keep continuously sending ipmi command
+"READ EVENT MESSAGE BUFFER" to BMC. This issue is caused by incorrect KCS
+status. If restart the host immediately while OS is still running, SMS_ATN
+will be set, after that KCS come into an incorrect status, and then KCS
+communction between BMC and OS crash. To make KCS go back to correct status
+and fix the issue, clear SMS_ATN after every time power cycle happen.
+
+Unit Test:
+ After entered OS, force reset system, after enter OS again, OS can start
+normally without keep sending READ EVENT MESSAGE BUFFER command.
+ After power on system, enter EFI SHELL, check cmdtool.efi can work
+correctly through KCS channel.
+---
+ host-cmd-manager.cpp | 24 ++++++++++++++++++------
+ 1 file changed, 18 insertions(+), 6 deletions(-)
+
+diff --git a/host-cmd-manager.cpp b/host-cmd-manager.cpp
+index 0a61e63..6e50684 100644
+--- a/host-cmd-manager.cpp
++++ b/host-cmd-manager.cpp
+@@ -26,6 +26,8 @@ constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
+ constexpr auto HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
+ constexpr auto HOST_STATE_INTERFACE = "xyz.openbmc_project.State.Host";
+ constexpr auto HOST_TRANS_PROP = "RequestedHostTransition";
++constexpr const char* IPMI_PATH = "/org/openbmc/HostIpmi/1";
++constexpr const char* IPMI_INTERFACE = "org.openbmc.HostIpmi";
+
+ // For throwing exceptions
+ using namespace phosphor::logging;
+@@ -107,6 +109,20 @@ void Manager::clearQueue()
+ // `false` indicating Failure
+ std::get<CallBack>(command)(ipmiCmdData, false);
+ }
++
++ auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH);
++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH,
++ IPMI_INTERFACE, "clearAttention");
++
++ try
++ {
++ auto reply = this->bus.call(method);
++ }
++ catch (sdbusplus::exception_t&)
++ {
++ log<level::ERR>("Error in clearing SMS attention");
++ elog<InternalFailure>();
++ }
+ }
+
+ // Called for alerting the host
+@@ -116,9 +132,6 @@ void Manager::checkQueueAndAlertHost()
+ {
+ log<level::DEBUG>("Asserting SMS Attention");
+
+- std::string IPMI_PATH("/org/openbmc/HostIpmi/1");
+- std::string IPMI_INTERFACE("org.openbmc.HostIpmi");
+-
+ auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH);
+
+ // Start the timer for this transaction
+@@ -132,9 +145,8 @@ void Manager::checkQueueAndAlertHost()
+ return;
+ }
+
+- auto method =
+- this->bus.new_method_call(host.c_str(), IPMI_PATH.c_str(),
+- IPMI_INTERFACE.c_str(), "setAttention");
++ auto method = this->bus.new_method_call(host.c_str(), IPMI_PATH,
++ IPMI_INTERFACE, "setAttention");
+ auto reply = this->bus.call(method);
+
+ if (reply.is_method_error())
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch
new file mode 100644
index 000000000..bf6f672cf
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0054-Fix-User-commands-require-channel-layer-lib.patch
@@ -0,0 +1,37 @@
+From 5d0c9d2217dbe369daffb8a92d7b5e7d7d34d566 Mon Sep 17 00:00:00 2001
+From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
+Date: Sat, 2 Mar 2019 20:08:32 +0530
+Subject: [PATCH] Fix: User commands require channel layer lib
+
+As channel layer is separated out from user layer lib, it
+has to be manually included in libusercommands, as user
+command handlers use channel layer API's
+
+Tested-by:
+1. Made sure that libusercommands are loaded on it's own
+without any undefined symbol error.
+2. ipmitool user list 1 works on host interface
+
+Change-Id: I6652ad248e01afc1349e3a9612754dbdb84b96ad
+Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
+---
+ Makefile.am | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index bb7bdbf..4e9101e 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -120,7 +120,8 @@ libipmi20_la_CXXFLAGS = $(COMMON_CXX)
+ providers_LTLIBRARIES += libusercmds.la
+ libusercmds_la_LIBADD = \
+ libipmid/libipmid.la \
+- user_channel/libuserlayer.la
++ user_channel/libuserlayer.la \
++ user_channel/libchannellayer.la
+ libusercmds_la_SOURCES = \
+ user_channel/usercommands.cpp
+ libusercmds_la_LDFLAGS = \
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0055-Implement-set-front-panel-button-enables-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0055-Implement-set-front-panel-button-enables-command.patch
new file mode 100644
index 000000000..170e530f9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0055-Implement-set-front-panel-button-enables-command.patch
@@ -0,0 +1,185 @@
+From b8b88a5c0f9e9cb6023cb8d5453e5cfadaa1a375 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Fri, 4 Jan 2019 10:50:21 +0800
+Subject: [PATCH] Implement set front panel button enables command
+
+Through modify buttons' property "Enabled" to disable/enable
+corresponding button.
+Currently support power and reset button.
+
+Test-By: ipmitool raw 0x0 0xa 0x2 //disable reset button
+ ipmitool raw 0x0 0xa 0x1 //disable power button
+ ipmitool raw 0x0 0xa 0x0 //enable all buttons
+
+Change-Id: Ice6f58edb898689f7a7fa08ad078d25fccaab27e
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ chassishandler.cpp | 98 +++++++++++++++++++++++++++++++++++++++
+ chassishandler.hpp | 1 +
+ host-ipmid-whitelist.conf | 1 +
+ 3 files changed, 100 insertions(+)
+
+diff --git a/chassishandler.cpp b/chassishandler.cpp
+index 4b42b3c..1a5b805 100644
+--- a/chassishandler.cpp
++++ b/chassishandler.cpp
+@@ -112,6 +112,8 @@ const static constexpr char chassisSMDevAddrProp[] = "SMDeviceAddress";
+ const static constexpr char chassisBridgeDevAddrProp[] = "BridgeDeviceAddress";
+ static constexpr uint8_t chassisCapFlagMask = 0x0f;
+ static constexpr uint8_t chassisCapAddrMask = 0xfe;
++static constexpr uint8_t disableResetButton = 0x2;
++static constexpr uint8_t disablePowerButton = 0x1;
+
+ typedef struct
+ {
+@@ -140,6 +142,19 @@ struct GetPOHCountResponse
+ uint8_t counterReading[4]; ///< Counter reading
+ } __attribute__((packed));
+
++typedef struct
++{
++ uint8_t disables; // Front Panel Button Enables
++ //[7:4] - reserved
++ //[3] - 1b = disable Standby (sleep) button for entering standby (sleep)
++ //(control can still be used to wake the system)
++ //[2] - 1b = disable Diagnostic Interrupt button
++ //[1] - 1b = disable Reset button
++ //[0] - 1b = disable Power off button for power off only (in the case there
++ // is a single combined power/standby (sleep) button, then this also
++ // disables sleep requests via that button)
++} __attribute__((packed)) IPMISetFrontPanelButtonEnablesReq;
++
+ // Phosphor Host State manager
+ namespace State = sdbusplus::xyz::openbmc_project::State::server;
+
+@@ -948,6 +963,8 @@ ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+
+ // Front Panel Button Capabilities and disable/enable status(Optional)
+ // set to 0, for we don't support them.
++ // TODO, it is tracked by an issue:
++ // https://github.com/openbmc/phosphor-host-ipmid/issues/122
+ chassis_status.front_panel_button_cap_status = 0;
+
+ // Pack the actual response
+@@ -1721,6 +1738,82 @@ ipmi_ret_t ipmi_chassis_set_power_restore_policy(
+ return IPMI_CC_OK;
+ }
+
++ipmi_ret_t ipmiSetFrontPanelButtonEnables(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
++ ipmi_request_t request,
++ ipmi_response_t response,
++ ipmi_data_len_t data_len,
++ ipmi_context_t context)
++{
++ bool enable = false;
++ constexpr const char* powerButtonIntf =
++ "xyz.openbmc_project.Chassis.Buttons.Power";
++ constexpr const char* powerButtonPath =
++ "/xyz/openbmc_project/Chassis/Buttons/Power0";
++ constexpr const char* resetButtonIntf =
++ "xyz.openbmc_project.Chassis.Buttons.Reset";
++ constexpr const char* resetButtonPath =
++ "/xyz/openbmc_project/Chassis/Buttons/Reset0";
++ using namespace chassis::internal;
++
++ IPMISetFrontPanelButtonEnablesReq* req =
++ static_cast<IPMISetFrontPanelButtonEnablesReq*>(request);
++ if (*data_len != 1)
++ {
++ *data_len = 0;
++ log<level::ERR>("IPMI request len is invalid");
++ return IPMI_CC_REQ_DATA_LEN_INVALID;
++ }
++ *data_len = 0;
++ if (req->disables & disablePowerButton)
++ {
++ // Disable power button
++ enable = false;
++ }
++ else
++ {
++ // Enable power button
++ enable = true;
++ }
++ // set power button Enabled property
++ try
++ {
++ auto service = ipmi::getService(dbus, powerButtonIntf, powerButtonPath);
++ ipmi::setDbusProperty(dbus, service, powerButtonPath, powerButtonIntf,
++ "Enabled", enable);
++ }
++ catch (sdbusplus::exception::SdBusError& e)
++ {
++ log<level::ERR>(e.what());
++ log<level::ERR>("Fail to set power button Enabled property");
++ return IPMI_CC_UNSPECIFIED_ERROR;
++ }
++
++ if (req->disables & disableResetButton)
++ {
++ // disable reset button
++ enable = false;
++ }
++ else
++ {
++ // enable reset button
++ enable = true;
++ }
++ // set reset button Enabled property
++ try
++ {
++ auto service = ipmi::getService(dbus, resetButtonIntf, resetButtonPath);
++ ipmi::setDbusProperty(dbus, service, resetButtonPath, resetButtonIntf,
++ "Enabled", enable);
++ }
++ catch (sdbusplus::exception::SdBusError& e)
++ {
++ log<level::ERR>(e.what());
++ log<level::ERR>("Fail to set reset button Enabled property");
++ return IPMI_CC_UNSPECIFIED_ERROR;
++ }
++ return IPMI_CC_OK;
++}
++
+ void register_netfn_chassis_functions()
+ {
+ createIdentifyTimer();
+@@ -1733,6 +1826,11 @@ void register_netfn_chassis_functions()
+ ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_CHASSIS_CAP, NULL,
+ ipmi_get_chassis_cap, PRIVILEGE_USER);
+
++ // Set Front Panel Button Enables
++ ipmi_register_callback(NETFUN_CHASSIS,
++ IPMI_CMD_SET_FRONT_PANEL_BUTTON_ENABLES, NULL,
++ ipmiSetFrontPanelButtonEnables, PRIVILEGE_ADMIN);
++
+ // Set Chassis Capabilities
+ ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_CHASSIS_CAP, NULL,
+ ipmi_set_chassis_cap, PRIVILEGE_USER);
+diff --git a/chassishandler.hpp b/chassishandler.hpp
+index 49b5ef8..f4a6bff 100644
+--- a/chassishandler.hpp
++++ b/chassishandler.hpp
+@@ -19,6 +19,7 @@ enum ipmi_netfn_chassis_cmds
+ // Get capability bits
+ IPMI_CMD_SET_SYS_BOOT_OPTIONS = 0x08,
+ IPMI_CMD_GET_SYS_BOOT_OPTIONS = 0x09,
++ IPMI_CMD_SET_FRONT_PANEL_BUTTON_ENABLES = 0x0A,
+ IPMI_CMD_GET_POH_COUNTER = 0x0F,
+ };
+
+diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
+index e5cd0b5..d96d9ed 100644
+--- a/host-ipmid-whitelist.conf
++++ b/host-ipmid-whitelist.conf
+@@ -6,6 +6,7 @@
+ 0x00:0x06 //<Chassis>:<Set Power Restore Policy>
+ 0x00:0x08 //<Chassis>:<Set System Boot Options>
+ 0x00:0x09 //<Chassis>:<Get System Boot Options>
++0x00:0x0A //<Chassis>:<Set Front Panel Button Enables>
+ 0x00:0x0F //<Chassis>:<Get POH Counter Command>
+ 0x04:0x2D //<Sensor/Event>:<Get Sensor Reading>
+ 0x04:0x2F //<Sensor/Event>:<Get Sensor Type>
+--
+2.19.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch
new file mode 100644
index 000000000..3a77887a0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch
@@ -0,0 +1,102 @@
+From 949db3a985719335d3df77db368eb2b296756749 Mon Sep 17 00:00:00 2001
+From: "Jia, chunhui" <chunhui.jia@linux.intel.com>
+Date: Tue, 19 Mar 2019 16:09:06 +0800
+Subject: [PATCH] add SetInProgress to get/set boot option cmd
+
+It is required by BIOS. BIOS will check setinprogress first.
+If this flag is not supported, BIOS will bypass all boot
+option flow.
+
+Change-Id: Ibb0501ea5bc36c4f1f72339efef03724dd4e613f
+Signed-off-by: Jia, chunhui <chunhui.jia@linux.intel.com>
+---
+ chassishandler.cpp | 26 +++++++++++++++++++++++++-
+ chassishandler.hpp | 3 +++
+ 2 files changed, 28 insertions(+), 1 deletion(-)
+
+diff --git a/chassishandler.cpp b/chassishandler.cpp
+index 6d14d1b..553afa8 100644
+--- a/chassishandler.cpp
++++ b/chassishandler.cpp
+@@ -1351,6 +1351,10 @@ static ipmi_ret_t setBootMode(const Mode::Modes& mode)
+ return IPMI_CC_OK;
+ }
+
++static constexpr uint8_t setComplete = 0x0;
++static constexpr uint8_t setInProgress = 0x1;
++static uint8_t transferStatus = setComplete;
++
+ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request,
+ ipmi_response_t response,
+@@ -1365,11 +1369,21 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ get_sys_boot_options_t* reqptr = (get_sys_boot_options_t*)request;
+ IpmiValue bootOption = ipmiDefault;
+
++ if (reqptr->parameter ==
++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS))
++ {
++ *data_len =
++ static_cast<uint8_t>(BootOptionResponseSize::SET_IN_PROGRESS);
++ resp->version = SET_PARM_VERSION;
++ resp->parm = static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS);
++ resp->data[0] = transferStatus;
++ return IPMI_CC_OK;
++ }
++
+ std::memset(resp, 0, sizeof(*resp));
+ resp->version = SET_PARM_VERSION;
+ resp->parm = 5;
+ resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME;
+-
+ /*
+ * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
+ * This is the only parameter used by petitboot.
+@@ -1505,6 +1519,16 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ // This IPMI command does not have any resposne data
+ *data_len = 0;
+
++ if (reqptr->parameter ==
++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS))
++ {
++ if (transferStatus == setInProgress) {
++ return IPMI_CC_FAIL_SET_IN_PROGRESS;
++ }
++ transferStatus = reqptr->data[0];
++ return IPMI_CC_OK;
++ }
++
+ /* 000101
+ * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
+ * This is the only parameter used by petitboot.
+diff --git a/chassishandler.hpp b/chassishandler.hpp
+index 2c42b11..6a24507 100644
+--- a/chassishandler.hpp
++++ b/chassishandler.hpp
+@@ -28,6 +28,7 @@ enum ipmi_chassis_return_codes
+ {
+ IPMI_OK = 0x0,
+ IPMI_CC_PARM_NOT_SUPPORTED = 0x80,
++ IPMI_CC_FAIL_SET_IN_PROGRESS = 0x81,
+ };
+
+ // Generic completion codes,
+@@ -49,6 +50,7 @@ enum ipmi_chassis_control_cmds : uint8_t
+ };
+ enum class BootOptionParameter : size_t
+ {
++ SET_IN_PROGRESS = 0x0,
+ BOOT_INFO = 0x4,
+ BOOT_FLAGS = 0x5,
+ OPAL_NETWORK_SETTINGS = 0x61
+@@ -56,6 +58,7 @@ enum class BootOptionParameter : size_t
+
+ enum class BootOptionResponseSize : size_t
+ {
++ SET_IN_PROGRESS = 3,
+ BOOT_FLAGS = 5,
+ OPAL_NETWORK_SETTINGS = 50
+ };
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch
new file mode 100644
index 000000000..5813cceae
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0057-Add-timer-use-actions-support.patch
@@ -0,0 +1,195 @@
+From 6e37e02a4f200507627a82f6dba00a9c9d877cb2 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Mon, 18 Mar 2019 23:05:16 +0800
+Subject: [PATCH] Add timer use/actions support
+
+Based on IPMI spec, add timer use/actions support,
+and add input data checking
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ app/watchdog.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++-----
+ app/watchdog_service.cpp | 8 +++++++
+ app/watchdog_service.hpp | 8 +++++++
+ 3 files changed, 72 insertions(+), 6 deletions(-)
+
+diff --git a/app/watchdog.cpp b/app/watchdog.cpp
+index 1a5d19c..3b61055 100644
+--- a/app/watchdog.cpp
++++ b/app/watchdog.cpp
+@@ -89,6 +89,13 @@ static constexpr uint8_t wd_dont_stop = 0x1 << 6;
+ static constexpr uint8_t wd_timeout_action_mask = 0x3;
+
+ static constexpr uint8_t wdTimerUseMask = 0x7;
++static constexpr uint8_t wdTimerUseResTimer1 = 0x0;
++static constexpr uint8_t wdTimerUseResTimer2 = 0x6;
++static constexpr uint8_t wdTimerUseResTimer3 = 0x7;
++static constexpr uint8_t wdTimerUseRes = 0x38;
++
++static constexpr uint8_t wdTimerActionMask = 0xcc;
++static constexpr uint8_t wdTimerUseExpMask = 0xc1;
+
+ enum class IpmiAction : uint8_t
+ {
+@@ -186,6 +193,11 @@ static_assert(sizeof(wd_set_req) == 6, "wd_set_req has invalid size.");
+ static_assert(sizeof(wd_set_req) <= MAX_IPMI_BUFFER,
+ "wd_get_res can't fit in request buffer.");
+
++static uint8_t timerLogFlags = 0;
++static uint8_t timerActions = 0;
++
++static uint8_t timerUseExpirationFlags = 0;
++
+ ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request,
+ ipmi_response_t response,
+@@ -203,6 +215,24 @@ ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ req.initial_countdown = le16toh(req.initial_countdown);
+ *data_len = 0;
+
++ if (((req.timer_use & wdTimerUseMask) == wdTimerUseResTimer1) ||
++ ((req.timer_use & wdTimerUseMask) == wdTimerUseResTimer2) ||
++ ((req.timer_use & wdTimerUseMask) == wdTimerUseResTimer3) ||
++ (req.timer_use & wdTimerUseRes) ||
++ (req.timer_action & wdTimerActionMask) ||
++ (req.expire_flags & wdTimerUseExpMask))
++ {
++ return IPMI_CC_INVALID_FIELD_REQUEST;
++ }
++
++ if (req.pretimeout > (req.initial_countdown / 10))
++ {
++ return IPMI_CC_INVALID_FIELD_REQUEST;
++ }
++
++ timerLogFlags = req.timer_use & 0x80;
++ timerActions = req.timer_action;
++
+ try
+ {
+ WatchdogService wd_service;
+@@ -221,6 +251,10 @@ ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ static_cast<IpmiTimerUse>(req.timer_use & wdTimerUseMask);
+ wd_service.setTimerUse(ipmiTimerUseToWdTimerUse(ipmiTimerUse));
+
++ wd_service.setExpiredTimerUse(WatchdogService::TimerUse::Reserved);
++
++ timerUseExpirationFlags &= ~req.expire_flags;
++
+ // Set the new interval and the time remaining deci -> mill seconds
+ const uint64_t interval = req.initial_countdown * 100;
+ wd_service.setInterval(interval);
+@@ -339,7 +373,6 @@ static_assert(sizeof(wd_get_res) == 8, "wd_get_res has invalid size.");
+ static_assert(sizeof(wd_get_res) <= MAX_IPMI_BUFFER,
+ "wd_get_res can't fit in response buffer.");
+
+-static constexpr uint8_t wd_dont_log = 0x1 << 7;
+ static constexpr uint8_t wd_running = 0x1 << 6;
+
+ ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+@@ -358,20 +391,37 @@ ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+
+ // Build and return the response
+ wd_get_res res;
+- res.timer_use = wd_dont_log;
+- res.timer_action =
+- static_cast<uint8_t>(wdActionToIpmiAction(wd_prop.expireAction));
++ res.timer_use |= timerLogFlags;
++ res.timer_action = timerActions;
+
+ // Interval and timeRemaining need converted from milli -> deci seconds
+ res.initial_countdown = htole16(wd_prop.interval / 100);
++
++ if (wd_prop.expiredTimerUse != WatchdogService::TimerUse::Reserved)
++ {
++ timerUseExpirationFlags |=
++ 1 << static_cast<uint8_t>(
++ wdTimerUseToIpmiTimerUse(wd_prop.expiredTimerUse));
++ }
++
+ if (wd_prop.enabled)
+ {
+ res.timer_use |= wd_running;
+ res.present_countdown = htole16(wd_prop.timeRemaining / 100);
++ res.expire_flags = 0;
+ }
+ else
+ {
+- res.present_countdown = res.initial_countdown;
++ if (wd_prop.expiredTimerUse == WatchdogService::TimerUse::Reserved)
++ {
++ res.present_countdown = res.initial_countdown;
++ res.expire_flags = 0;
++ }
++ else
++ {
++ res.present_countdown = 0;
++ res.expire_flags = timerUseExpirationFlags;
++ }
+ }
+
+ res.timer_use |=
+@@ -379,7 +429,7 @@ ipmi_ret_t ipmi_app_watchdog_get(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+
+ // TODO: Do something about having pretimeout support
+ res.pretimeout = 0;
+- res.expire_flags = 0;
++
+ memcpy(response, &res, sizeof(res));
+ *data_len = sizeof(res);
+ lastCallSuccessful = true;
+diff --git a/app/watchdog_service.cpp b/app/watchdog_service.cpp
+index e65ea63..8b1aa47 100644
+--- a/app/watchdog_service.cpp
++++ b/app/watchdog_service.cpp
+@@ -83,6 +83,9 @@ WatchdogService::Properties WatchdogService::getProperties()
+ wd_prop.timerUse = Watchdog::convertTimerUseFromString(
+ get<std::string>(properties.at("CurrentTimerUse")));
+
++ wd_prop.expiredTimerUse = Watchdog::convertTimerUseFromString(
++ get<std::string>(properties.at("ExpiredTimerUse")));
++
+ wd_prop.interval = get<uint64_t>(properties.at("Interval"));
+ wd_prop.timeRemaining = get<uint64_t>(properties.at("TimeRemaining"));
+ return wd_prop;
+@@ -187,6 +190,11 @@ void WatchdogService::setTimerUse(TimerUse timerUse)
+ setProperty("CurrentTimerUse", convertForMessage(timerUse));
+ }
+
++void WatchdogService::setExpiredTimerUse(TimerUse timerUse)
++{
++ setProperty("ExpiredTimerUse", convertForMessage(timerUse));
++}
++
+ void WatchdogService::setInterval(uint64_t interval)
+ {
+ setProperty("Interval", interval);
+diff --git a/app/watchdog_service.hpp b/app/watchdog_service.hpp
+index 75afc1e..d0cc1a8 100644
+--- a/app/watchdog_service.hpp
++++ b/app/watchdog_service.hpp
+@@ -36,6 +36,7 @@ class WatchdogService
+ bool enabled;
+ Action expireAction;
+ TimerUse timerUse;
++ TimerUse expiredTimerUse;
+ uint64_t interval;
+ uint64_t timeRemaining;
+ };
+@@ -79,6 +80,13 @@ class WatchdogService
+ */
+ void setTimerUse(TimerUse timerUse);
+
++ /** @brief Sets the value of the ExpiredTimerUse property on the host
++ * watchdog
++ *
++ * @param[in] timerUse - The new timerUse value
++ */
++ void setExpiredTimerUse(TimerUse timerUse);
++
+ /** @brief Sets the value of the interval property on the host watchdog
+ *
+ * @param[in] interval - The new interval value
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service
new file mode 100644
index 000000000..d855eaa5b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service
@@ -0,0 +1,26 @@
+[Unit]
+Description=Phosphor Inband IPMI
+# TODO openbmc/openbmc#2059 - The wants/after below should be based on providers
+Wants=mapper-wait@-xyz-openbmc_project-control-host0-boot.service
+After=mapper-wait@-xyz-openbmc_project-control-host0-boot.service
+Wants=mapper-wait@-xyz-openbmc_project-control-host0-boot-one_time.service
+After=mapper-wait@-xyz-openbmc_project-control-host0-boot-one_time.service
+Wants=mapper-wait@-xyz-openbmc_project-control-host0-power_restore_policy.service
+After=mapper-wait@-xyz-openbmc_project-control-host0-power_restore_policy.service
+Wants=mapper-wait@-xyz-openbmc_project-control-host0-restriction_mode.service
+After=mapper-wait@-xyz-openbmc_project-control-host0-restriction_mode.service
+Wants=clear-once.service
+After=clear-once.service
+
+[Service]
+Restart=always
+RestartSec=5
+StartLimitBurst=10
+ExecStart=/usr/bin/env ipmid
+SyslogIdentifier=ipmid
+RuntimeDirectory = ipmi
+RuntimeDirectoryPreserve = yes
+StateDirectory = ipmi
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend
new file mode 100644
index 000000000..2d47fdfff
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend
@@ -0,0 +1,37 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+# TODO: This should be removed, once up-stream bump up
+# issue is resolved
+#SRC_URI = "git://github.com/openbmc/phosphor-host-ipmid"
+SRCREV = "55768e3548ef7476d4fdbe7be7a3ddb4d4896f14"
+
+SRC_URI += "file://phosphor-ipmi-host.service \
+ file://0002-Modify-dbus-interface-for-power-control.patch \
+ file://0003-Modify-dbus-interface-for-chassis-control.patch \
+ file://0009-IPv6-Network-changes.patch \
+ file://0010-fix-get-system-GUID-ipmi-command.patch \
+ file://0012-ipmi-set-get-boot-options.patch \
+ file://0013-ipmi-add-set-bios-id-to-whitelist.patch \
+ file://0014-Enable-get-device-guid-ipmi-command.patch \
+ file://0016-add-better-sdbusplus-exception-handling.patch \
+ file://0018-Catch-sdbusplus-exceptions-in-IPMI-net.patch \
+ file://0021-Implement-IPMI-Commmand-Get-Host-Restart-Cause.patch \
+ file://0039-ipmi-add-oem-command-get-AIC-FRU-to-whitelist.patch \
+ file://0048-Implement-IPMI-Master-Write-Read-command.patch \
+ file://0049-Fix-Unspecified-error-on-ipmi-restart-cause-command.patch \
+ file://0050-enable-6-oem-commands.patch \
+ file://0051-Fix-Set-LAN-Config-to-work-without-SetInProgress.patch \
+ file://0053-Fix-keep-looping-issue-when-entering-OS.patch \
+ file://0055-Implement-set-front-panel-button-enables-command.patch \
+ file://0056-add-SetInProgress-to-get-set-boot-option-cmd.patch \
+ file://0057-Add-timer-use-actions-support.patch \
+ "
+
+do_install_append(){
+ install -d ${D}${includedir}/phosphor-ipmi-host
+ install -d ${D}${libdir}/phosphor-ipmi-host
+ install -m 0644 -D ${S}/*.h ${D}${includedir}/phosphor-ipmi-host
+ install -m 0644 -D ${S}/*.hpp ${D}${includedir}/phosphor-ipmi-host
+ install -m 0644 -D ${S}/utils.cpp ${D}${libdir}/phosphor-ipmi-host
+
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend
new file mode 100644
index 000000000..d5d38a0ce
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-ipmb_%.bbappend
@@ -0,0 +1,2 @@
+SRC_URI = "git://github.com/openbmc/ipmbbridge.git"
+SRCREV = "25e85c79257723b1cb754c20299196685373ce24"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.SMM.service b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.SMM.service
new file mode 100644
index 000000000..288fa422d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.SMM.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Phosphor IPMI KCS DBus Bridge(SMM)
+After=phosphor-ipmi-host.service
+
+[Service]
+Restart=always
+ExecStart={sbindir}/kcsbridged --d="/dev/ipmi-kcs4" --i="SMM"
+SyslogIdentifier=kcsbridged_SMM
+Type=dbus
+BusName={BUSNAME}
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.service b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.service
new file mode 100644
index 000000000..177062e27
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/org.openbmc.HostIpmi.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Phosphor IPMI KCS DBus Bridge(SMS)
+After=phosphor-ipmi-host.service
+
+[Service]
+Restart=always
+ExecStart={sbindir}/kcsbridged --d="/dev/ipmi-kcs3"
+SyslogIdentifier=kcsbridged
+Type=dbus
+BusName={BUSNAME}
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend
new file mode 100644
index 000000000..ac7a03108
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend
@@ -0,0 +1,9 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+DBUS_SERVICE_${PN} += "org.openbmc.HostIpmi.SMM.service"
+
+SYSTEMD_SUBSTITUTIONS_remove = "KCS_DEVICE:${KCS_DEVICE}:${DBUS_SERVICE_${PN}}"
+
+SRC_URI = "git://github.com/openbmc/kcsbridge.git"
+SRCREV = "17a2ab7f39a78ff0603aa68cf35108ea94eb442f"
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch
new file mode 100644
index 000000000..7225c7529
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch
@@ -0,0 +1,39 @@
+From 6fc55bb689272d34ff6616cdd4b24367ea39c749 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Mon, 2 Jul 2018 15:51:52 +0800
+Subject: [PATCH] Modify dbus namespace of chassis control for guid.cpp
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Switch chassis control service namespace for guid.cpp from “org” to “xyz”,
+to compatible with new intel-chassis services
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ command/guid.cpp | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+Index: phosphor-net-ipmid.clean/command/guid.cpp
+===================================================================
+--- phosphor-net-ipmid.clean.orig/command/guid.cpp
++++ phosphor-net-ipmid.clean/command/guid.cpp
+@@ -21,7 +21,8 @@ namespace command
+
+ std::unique_ptr<sdbusplus::bus::match_t> matchPtr(nullptr);
+
+-static constexpr auto guidObjPath = "/org/openbmc/control/chassis0";
++static constexpr auto guidObjPath =
++ "/xyz/openbmc_project/Chassis/Control/Chassis0";
+ static constexpr auto propInterface = "org.freedesktop.DBus.Properties";
+
+ Guid getSystemGUID()
+@@ -31,7 +32,7 @@ Guid getSystemGUID()
+ Guid guid = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
+
+- constexpr auto chassisIntf = "org.openbmc.control.Chassis";
++ constexpr auto chassisIntf = "xyz.openbmc_project.Chassis.Control.Chassis";
+
+ sd_bus_message* reply = nullptr;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0007-Adding-support-for-GetSessionInfo-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0007-Adding-support-for-GetSessionInfo-command.patch
new file mode 100644
index 000000000..fda7ed2ca
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0007-Adding-support-for-GetSessionInfo-command.patch
@@ -0,0 +1,421 @@
+From f5c7d30be4a097998d9390614c0faa2d77109ca5 Mon Sep 17 00:00:00 2001
+From: ssekar <suryakanth.sekar@linux.intel.com>
+Date: Wed, 12 Dec 2018 16:04:15 +0530
+Subject: [PATCH] Adding support for GetSessionInfo command
+
+Description: user can get all session info (remote ip,port,
+session id, priv, etc) using this command.
+
+Verification :we can get all active and non active session
+info by session handle session id.
+Updated the Remote IP addr and Port update for sessioninfo.
+Unit testing are done.
+
+Change-Id: I662ef2b9f0c1d6bda331eb6481d7b9f34534541b
+Signed-off-by: ssekar <suryakanth.sekar@linux.intel.com>
+---
+ comm_module.cpp | 8 +++
+ command/session_cmds.cpp | 147 +++++++++++++++++++++++++++++++++++++++
+ command/session_cmds.hpp | 55 +++++++++++++++
+ message_handler.cpp | 1 +
+ sessions_manager.cpp | 55 +++++++++++++++
+ sessions_manager.hpp | 7 ++
+ socket_channel.cpp | 27 ++++++-
+ socket_channel.hpp | 3 +-
+ 8 files changed, 301 insertions(+), 2 deletions(-)
+
+Index: phosphor-net-ipmid.clean/comm_module.cpp
+===================================================================
+--- phosphor-net-ipmid.clean.orig/comm_module.cpp
++++ phosphor-net-ipmid.clean/comm_module.cpp
+@@ -53,6 +53,14 @@ void sessionSetupCommands()
+ &closeSession,
+ session::Privilege::CALLBACK,
+ false},
++ // Session Info Command
++ {
++ {
++ (static_cast<uint32_t>(message::PayloadType::IPMI) << 16) |
++ static_cast<uint16_t>(command::NetFns::APP) | 0x3D
++ },
++ &getSessionInfo, session::Privilege::USER, false
++ },
+ };
+
+ for (auto& iter : commands)
+Index: phosphor-net-ipmid.clean/command/session_cmds.cpp
+===================================================================
+--- phosphor-net-ipmid.clean.orig/command/session_cmds.cpp
++++ phosphor-net-ipmid.clean/command/session_cmds.cpp
+@@ -5,11 +5,19 @@
+
+ #include <host-ipmid/ipmid-api.h>
+
++#include <iostream>
+ #include <user_channel/channel_layer.hpp>
+ #include <user_channel/user_layer.hpp>
+
+ namespace command
+ {
++// Defined as per IPMI sepcification
++static constexpr uint8_t searchCurrentSession = 0x00;
++static constexpr uint8_t searchSessionByHandle = 0xFE;
++static constexpr uint8_t searchSessionByID = 0xFF;
++
++static constexpr uint8_t ipmi15VerSession = 0x00;
++static constexpr uint8_t ipmi20VerSession = 0x01;
+
+ std::vector<uint8_t>
+ setSessionPrivilegeLevel(const std::vector<uint8_t>& inPayload,
+@@ -110,4 +118,143 @@ std::vector<uint8_t> closeSession(const
+ return outPayload;
+ }
+
++std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload,
++ const message::Handler& handler)
++
++{
++ std::vector<uint8_t> outPayload(sizeof(GetSessionInfoResponse));
++ auto request =
++ reinterpret_cast<const GetSessionInfoRequest*>(inPayload.data());
++ auto response =
++ reinterpret_cast<GetSessionInfoResponse*>(outPayload.data());
++ uint32_t reqSessionID = handler.sessionID;
++ response->completionCode = IPMI_CC_OK;
++ if (inPayload.size() == 1 && request->sessionIndex != 0)
++ {
++ if (request->sessionIndex <= session::MAX_SESSION_COUNT)
++ {
++ reqSessionID = std::get<session::Manager&>(singletonPool)
++ .getSessionIDbyHandle(request->sessionIndex);
++ }
++ else
++ {
++ response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
++ outPayload.resize(sizeof(response->completionCode));
++ return std::move(outPayload);
++ }
++ }
++
++ // Here we look for session info according to session index parameter
++ switch (request->sessionIndex)
++ {
++ // Look for current active session which this cmd is received over
++ case searchCurrentSession:
++ // Request data should only contain session index byte
++ if (inPayload.size() != 1)
++ {
++ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID;
++ outPayload.resize(sizeof(response->completionCode));
++ return std::move(outPayload);
++ }
++ // To look for current active session which the command came over,
++ // the session ID cannot be 0.
++ if (0 == reqSessionID)
++ {
++ response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
++ outPayload.resize(sizeof(response->completionCode));
++ return std::move(outPayload);
++ }
++ break;
++ case searchSessionByHandle:
++ // Request data should only contain session index byte and Session
++ // handle
++ if (inPayload.size() != 2)
++ {
++ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID;
++ outPayload.resize(sizeof(response->completionCode));
++ return std::move(outPayload);
++ }
++
++ // Retrieve session id based on session handle
++ if (request->sessionHandle <= session::MAX_SESSION_COUNT)
++ {
++ reqSessionID =
++ std::get<session::Manager&>(singletonPool)
++ .getSessionIDbyHandle(request->sessionHandle);
++ }
++ else
++ {
++ response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
++ outPayload.resize(sizeof(response->completionCode));
++ return std::move(outPayload);
++ }
++ break;
++ case searchSessionByID:
++ // Request data should only contain session index byte and Session
++ // handle
++ if (inPayload.size() != sizeof(GetSessionInfoRequest))
++ {
++ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID;
++ outPayload.resize(sizeof(response->completionCode));
++ return std::move(outPayload);
++ }
++ reqSessionID = endian::from_ipmi(request->sessionID);
++
++ break;
++ default:
++ if (inPayload.size() != 1)
++ {
++ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID;
++ outPayload.resize(sizeof(response->completionCode));
++ return std::move(outPayload);
++ }
++ }
++
++ response->totalSessionCount = session::MAX_SESSION_COUNT;
++ response->activeSessioncount =
++ std::get<session::Manager&>(singletonPool).getNoOfActiveSession();
++ response->sessionHandle = 0;
++ if (reqSessionID != 0)
++ {
++
++ std::shared_ptr<session::Session> sessionInfo;
++ try
++ {
++ sessionInfo = std::get<session::Manager&>(singletonPool)
++ .getSession(reqSessionID);
++ }
++ catch (std::exception& e)
++ {
++ response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
++ outPayload.resize(sizeof(response->completionCode));
++ return std::move(outPayload);
++ }
++ response->sessionHandle = std::get<session::Manager&>(singletonPool)
++ .getSessionHandle(reqSessionID);
++ uint8_t userId = ipmi::ipmiUserGetUserId(sessionInfo->userName);
++ if (userId == ipmi::invalidUserId)
++ {
++ response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
++ outPayload.resize(sizeof(response->completionCode));
++ return std::move(outPayload);
++ }
++ response->userID = userId; // userId;
++ response->privLevel = static_cast<uint8_t>(sessionInfo->curPrivLevel);
++ response->chanNum = sessionInfo->chNum; // byte7 3:0
++ response->ipmiVer = ipmi20VerSession; // byte7 7:4
++ response->remoteIpAddr =
++ sessionInfo->channelPtr->getRemoteAddressInbytes();
++ response->remotePort =
++ sessionInfo->channelPtr->getPort(); // remoteSessionPort;
++
++ std::cerr << "\nSessionInfo:" << (int)reqSessionID;
++ // TODO: Filling the Remote MACAddress
++ }
++ else
++ {
++ outPayload.resize(4);
++ }
++ return std::move(outPayload);
++}
++
+ } // namespace command
+Index: phosphor-net-ipmid.clean/command/session_cmds.hpp
+===================================================================
+--- phosphor-net-ipmid.clean.orig/command/session_cmds.hpp
++++ phosphor-net-ipmid.clean/command/session_cmds.hpp
+@@ -116,4 +116,59 @@ struct CloseSessionResponse
+ std::vector<uint8_t> closeSession(const std::vector<uint8_t>& inPayload,
+ const message::Handler& handler);
+
++/**
++ * @struct GetSessionInfoRequest
++ *
++ * IPMI Request data for getSession info command
++ */
++struct GetSessionInfoRequest
++{
++ uint8_t sessionIndex;
++ union
++ {
++ uint8_t sessionHandle;
++ uint32_t sessionID;
++ };
++} __attribute__((packed));
++
++/**
++ * @struct getSessionInfoResponse
++ *
++ * IPMI Response data for getSession info command
++ */
++struct GetSessionInfoResponse
++{
++ uint8_t completionCode;
++ uint8_t sessionHandle;
++ uint8_t totalSessionCount;
++ uint8_t activeSessioncount;
++ uint8_t userID;
++ uint8_t privLevel;
++#if BYTE_ORDER == LITTLE_ENDIAN
++ uint8_t chanNum : 4;
++ uint8_t ipmiVer : 4;
++#endif
++#if BYTE_ORDER == BIG_ENDIAN
++ uint8_t ipmiVer : 4;
++ uint8_t chanNum : 4;
++#endif
++ uint32_t remoteIpAddr; // for channel private data
++ uint8_t remoteMACAddr[6];
++ uint16_t remotePort;
++} __attribute__((packed));
++
++/**
++ * @brief GetSessionInfo Command
++ *
++ * This command is used to get the session information based on
++ * session handle or session ID. Retreive all session information.
++
++ * @param[in] inPayload - Request Data for the command
++ * @param[in] handler - Reference to the Message Handler
++ *
++ * @return Response data for the command
++ */
++std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload,
++ const message::Handler& handler);
++
+ } // namespace command
+Index: phosphor-net-ipmid.clean/message_handler.cpp
+===================================================================
+--- phosphor-net-ipmid.clean.orig/message_handler.cpp
++++ phosphor-net-ipmid.clean/message_handler.cpp
+@@ -43,6 +43,7 @@ std::shared_ptr<Message> Handler::receiv
+ sessionID = message->bmcSessionID;
+ message->rcSessionID = session->getRCSessionID();
+ session->updateLastTransactionTime();
++ session->channelPtr = channel;
+
+ return message;
+ }
+Index: phosphor-net-ipmid.clean/sessions_manager.cpp
+===================================================================
+--- phosphor-net-ipmid.clean.orig/sessions_manager.cpp
++++ phosphor-net-ipmid.clean/sessions_manager.cpp
+@@ -88,6 +88,9 @@ std::shared_ptr<Session>
+ }
+ sessionID = session->getBMCSessionID();
+ sessionsMap.emplace(sessionID, session);
++ storeSessionHandle(sessionID);
++
++
+ return session;
+ }
+
+@@ -149,12 +152,15 @@ std::shared_ptr<Session> Manager::getSes
+
+ void Manager::cleanStaleEntries()
+ {
++ uint8_t sessionIndex = 0;
+ for (auto iter = sessionsMap.begin(); iter != sessionsMap.end();)
+ {
+ auto session = iter->second;
+ if ((session->getBMCSessionID() != SESSION_ZERO) &&
+ !(session->isSessionActive()))
+ {
++ sessionIndex = getSessionHandle(session->getBMCSessionID());
++ sessionHandleMap[sessionIndex] = 0;
+ iter = sessionsMap.erase(iter);
+ }
+ else
+@@ -164,4 +170,53 @@ void Manager::cleanStaleEntries()
+ }
+ }
+
++uint8_t Manager::storeSessionHandle(SessionID bmcSessionID)
++{
++ // Zero handler is reserved for invalid session.
++ //index starts with 1, for direct usage. Index 0 reserved
++ for (uint8_t i = 1; i <= MAX_SESSION_COUNT; i++)
++ {
++ if (sessionHandleMap[i] == 0)
++ {
++ sessionHandleMap[i] = bmcSessionID;
++ break;
++ }
++ }
++ return 0;
++}
++
++uint32_t Manager::getSessionIDbyHandle(uint8_t sessionHandle) const
++{
++ if (sessionHandle <= MAX_SESSION_COUNT)
++ {
++ return sessionHandleMap[sessionHandle];
++ }
++ return 0;
++}
++
++uint8_t Manager::getSessionHandle(SessionID bmcSessionID) const
++{
++
++ for (uint8_t i = 1; i <= MAX_SESSION_COUNT; i++)
++ {
++ if (sessionHandleMap[i] == bmcSessionID)
++ {
++ return i;
++ }
++ }
++ return 0;
++}
++uint8_t Manager::getNoOfActiveSession() const
++{
++ uint8_t count = 0;
++ for (const auto& it : sessionsMap)
++ {
++ const auto& session = it.second;
++ if (session->state == State::ACTIVE)
++ {
++ count++;
++ }
++ }
++ return count;
++}
+ } // namespace session
+Index: phosphor-net-ipmid.clean/sessions_manager.hpp
+===================================================================
+--- phosphor-net-ipmid.clean.orig/sessions_manager.hpp
++++ phosphor-net-ipmid.clean/sessions_manager.hpp
+@@ -82,8 +82,15 @@ class Manager
+ std::shared_ptr<Session>
+ getSession(SessionID sessionID,
+ RetrieveOption option = RetrieveOption::BMC_SESSION_ID);
++ uint8_t getNoOfActiveSession() const;
++ uint8_t getSessionHandle(SessionID bmcSessionID) const;
++ uint8_t storeSessionHandle(SessionID bmcSessionID);
++ uint32_t getSessionIDbyHandle(uint8_t sessionHandle) const;
+
+ private:
++ //+1 for session, as 0 is reserved for sessionless command
++ std::array<uint32_t, MAX_SESSION_COUNT + 1> sessionHandleMap;
++
+ /**
+ * @brief Session Manager keeps the session objects as a sorted
+ * associative container with Session ID as the unique key
+Index: phosphor-net-ipmid.clean/socket_channel.hpp
+===================================================================
+--- phosphor-net-ipmid.clean.orig/socket_channel.hpp
++++ phosphor-net-ipmid.clean/socket_channel.hpp
+@@ -65,6 +65,23 @@ class Channel
+ }
+
+ /**
++ * @brief Return the binary representation of the remote IPv4 address
++ *
++ * getSessionInfo needs to return the remote IPv4 addresses of each session
++ *
++ * @return A uint32_t representation of the remote IPv4 address
++ */
++ std::uint32_t getRemoteAddressInbytes()
++ {
++ const boost::asio::ip::address& addr = endpoint.address();
++ if (addr.is_v4())
++ {
++ return addr.to_v4().to_uint();
++ }
++ return 0;
++ }
++
++ /**
+ * @brief Read the incoming packet
+ *
+ * Reads the data available on the socket
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0008-Sync-GetSession-Info-cmd-based-on-Upstream-review.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0008-Sync-GetSession-Info-cmd-based-on-Upstream-review.patch
new file mode 100644
index 000000000..1a109a571
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0008-Sync-GetSession-Info-cmd-based-on-Upstream-review.patch
@@ -0,0 +1,318 @@
+From 0ecc7c816ad4836f8f54922ba92cb527f5978d5a Mon Sep 17 00:00:00 2001
+From: Suryakanth Sekar <suryakanth.sekar@linux.intel.com>
+Date: Wed, 6 Mar 2019 10:35:56 +0530
+Subject: [PATCH] Sync GetSession Info cmd based on Upstream review
+
+Signed-off-by: Suryakanth Sekar <suryakanth.sekar@linux.intel.com>
+---
+ comm_module.cpp | 12 ++++----
+ command/session_cmds.cpp | 72 +++++++++++++++++++++---------------------------
+ sessions_manager.cpp | 10 +++----
+ sessions_manager.hpp | 2 +-
+ socket_channel.hpp | 33 +++++++++++-----------
+ 5 files changed, 59 insertions(+), 70 deletions(-)
+
+diff --git a/comm_module.cpp b/comm_module.cpp
+index 7a1a17d..2546583 100644
+--- a/comm_module.cpp
++++ b/comm_module.cpp
+@@ -54,13 +54,11 @@ void sessionSetupCommands()
+ session::Privilege::CALLBACK,
+ false},
+ // Session Info Command
+- {
+- {
+- (static_cast<uint32_t>(message::PayloadType::IPMI) << 16) |
+- static_cast<uint16_t>(command::NetFns::APP) | 0x3D
+- },
+- &getSessionInfo, session::Privilege::USER, false
+- },
++ {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) |
++ static_cast<uint16_t>(command::NetFns::APP) | 0x3D},
++ &getSessionInfo,
++ session::Privilege::USER,
++ false},
+ };
+
+ for (auto& iter : commands)
+diff --git a/command/session_cmds.cpp b/command/session_cmds.cpp
+index 7563b18..fc996a4 100644
+--- a/command/session_cmds.cpp
++++ b/command/session_cmds.cpp
+@@ -5,13 +5,12 @@
+
+ #include <ipmid/api.h>
+
+-#include <iostream>
+ #include <user_channel/channel_layer.hpp>
+ #include <user_channel/user_layer.hpp>
+
+ namespace command
+ {
+-// Defined as per IPMI sepcification
++// Defined as per IPMI specification
+ static constexpr uint8_t searchCurrentSession = 0x00;
+ static constexpr uint8_t searchSessionByHandle = 0xFE;
+ static constexpr uint8_t searchSessionByID = 0xFF;
+@@ -129,20 +128,6 @@ std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload,
+ reinterpret_cast<GetSessionInfoResponse*>(outPayload.data());
+ uint32_t reqSessionID = handler.sessionID;
+ response->completionCode = IPMI_CC_OK;
+- if (inPayload.size() == 1 && request->sessionIndex != 0)
+- {
+- if (request->sessionIndex <= session::MAX_SESSION_COUNT)
+- {
+- reqSessionID = std::get<session::Manager&>(singletonPool)
+- .getSessionIDbyHandle(request->sessionIndex);
+- }
+- else
+- {
+- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
+- outPayload.resize(sizeof(response->completionCode));
+- return std::move(outPayload);
+- }
+- }
+
+ // Here we look for session info according to session index parameter
+ switch (request->sessionIndex)
+@@ -150,29 +135,22 @@ std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload,
+ // Look for current active session which this cmd is received over
+ case searchCurrentSession:
+ // Request data should only contain session index byte
+- if (inPayload.size() != 1)
++ if (inPayload.size() != sizeof(request->sessionIndex))
+ {
+ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID;
+ outPayload.resize(sizeof(response->completionCode));
+- return std::move(outPayload);
+- }
+- // To look for current active session which the command came over,
+- // the session ID cannot be 0.
+- if (0 == reqSessionID)
+- {
+- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
+- outPayload.resize(sizeof(response->completionCode));
+- return std::move(outPayload);
++ return outPayload;
+ }
+ break;
+ case searchSessionByHandle:
+ // Request data should only contain session index byte and Session
+ // handle
+- if (inPayload.size() != 2)
++ if (inPayload.size() != (sizeof(request->sessionIndex) +
++ sizeof(request->sessionHandle)))
+ {
+ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID;
+ outPayload.resize(sizeof(response->completionCode));
+- return std::move(outPayload);
++ return outPayload;
+ }
+
+ // Retrieve session id based on session handle
+@@ -186,7 +164,7 @@ std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload,
+ {
+ response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
+ outPayload.resize(sizeof(response->completionCode));
+- return std::move(outPayload);
++ return outPayload;
+ }
+ break;
+ case searchSessionByID:
+@@ -196,23 +174,38 @@ std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload,
+ {
+ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID;
+ outPayload.resize(sizeof(response->completionCode));
+- return std::move(outPayload);
++ return outPayload;
+ }
+ reqSessionID = endian::from_ipmi(request->sessionID);
+
+ break;
+ default:
+- if (inPayload.size() != 1)
++ if (inPayload.size() == sizeof(request->sessionIndex))
++ {
++ if (request->sessionIndex <= session::MAX_SESSION_COUNT)
++ {
++ reqSessionID =
++ std::get<session::Manager&>(singletonPool)
++ .getSessionIDbyHandle(request->sessionIndex);
++ }
++ else
++ {
++ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID;
++ outPayload.resize(sizeof(response->completionCode));
++ return outPayload;
++ }
++ }
++ else
+ {
+ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID;
+ outPayload.resize(sizeof(response->completionCode));
+- return std::move(outPayload);
++ return outPayload;
+ }
+ }
+
+ response->totalSessionCount = session::MAX_SESSION_COUNT;
+ response->activeSessioncount =
+- std::get<session::Manager&>(singletonPool).getNoOfActiveSession();
++ std::get<session::Manager&>(singletonPool).getActiveSessionCount();
+ response->sessionHandle = 0;
+ if (reqSessionID != 0)
+ {
+@@ -225,9 +218,9 @@ std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload,
+ }
+ catch (std::exception& e)
+ {
+- response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
++ response->completionCode = IPMI_CC_REQ_DATA_LEN_INVALID;
+ outPayload.resize(sizeof(response->completionCode));
+- return std::move(outPayload);
++ return outPayload;
+ }
+ response->sessionHandle = std::get<session::Manager&>(singletonPool)
+ .getSessionHandle(reqSessionID);
+@@ -236,25 +229,24 @@ std::vector<uint8_t> getSessionInfo(const std::vector<uint8_t>& inPayload,
+ {
+ response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
+ outPayload.resize(sizeof(response->completionCode));
+- return std::move(outPayload);
++ return outPayload;
+ }
+ response->userID = userId; // userId;
+ response->privLevel = static_cast<uint8_t>(sessionInfo->curPrivLevel);
+ response->chanNum = sessionInfo->chNum; // byte7 3:0
+ response->ipmiVer = ipmi20VerSession; // byte7 7:4
+- response->remoteIpAddr =
+- sessionInfo->channelPtr->getRemoteAddressInbytes();
+ response->remotePort =
+ sessionInfo->channelPtr->getPort(); // remoteSessionPort;
++ response->remoteIpAddr =
++ sessionInfo->channelPtr->getRemoteAddressInBytes();
+
+- std::cerr << "\nSessionInfo:" << (int)reqSessionID;
+ // TODO: Filling the Remote MACAddress
+ }
+ else
+ {
+ outPayload.resize(4);
+ }
+- return std::move(outPayload);
++ return outPayload;
+ }
+
+ } // namespace command
+diff --git a/sessions_manager.cpp b/sessions_manager.cpp
+index 9f3210b..c6897c6 100644
+--- a/sessions_manager.cpp
++++ b/sessions_manager.cpp
+@@ -152,15 +152,13 @@ std::shared_ptr<Session> Manager::getSession(SessionID sessionID,
+
+ void Manager::cleanStaleEntries()
+ {
+- uint8_t sessionIndex = 0;
+ for (auto iter = sessionsMap.begin(); iter != sessionsMap.end();)
+ {
+ auto session = iter->second;
+ if ((session->getBMCSessionID() != SESSION_ZERO) &&
+ !(session->isSessionActive()))
+ {
+- sessionIndex = getSessionHandle(session->getBMCSessionID());
+- sessionHandleMap[sessionIndex] = 0;
++ sessionHandleMap[getSessionHandle(session->getBMCSessionID())] = 0;
+ iter = sessionsMap.erase(iter);
+ }
+ else
+@@ -172,8 +170,8 @@ void Manager::cleanStaleEntries()
+
+ uint8_t Manager::storeSessionHandle(SessionID bmcSessionID)
+ {
+- // Zero handler is reserved for invalid session.
+- //index starts with 1, for direct usage. Index 0 reserved
++ // Handler index 0 is reserved for invalid session.
++ // index starts with 1, for direct usage. Index 0 reserved
+ for (uint8_t i = 1; i <= MAX_SESSION_COUNT; i++)
+ {
+ if (sessionHandleMap[i] == 0)
+@@ -206,7 +204,7 @@ uint8_t Manager::getSessionHandle(SessionID bmcSessionID) const
+ }
+ return 0;
+ }
+-uint8_t Manager::getNoOfActiveSession() const
++uint8_t Manager::getActiveSessionCount() const
+ {
+ uint8_t count = 0;
+ for (const auto& it : sessionsMap)
+diff --git a/sessions_manager.hpp b/sessions_manager.hpp
+index c4caad4..3a3825d 100644
+--- a/sessions_manager.hpp
++++ b/sessions_manager.hpp
+@@ -82,7 +82,7 @@ class Manager
+ std::shared_ptr<Session>
+ getSession(SessionID sessionID,
+ RetrieveOption option = RetrieveOption::BMC_SESSION_ID);
+- uint8_t getNoOfActiveSession() const;
++ uint8_t getActiveSessionCount() const;
+ uint8_t getSessionHandle(SessionID bmcSessionID) const;
+ uint8_t storeSessionHandle(SessionID bmcSessionID);
+ uint32_t getSessionIDbyHandle(uint8_t sessionHandle) const;
+diff --git a/socket_channel.hpp b/socket_channel.hpp
+index 349701e..8b64740 100644
+--- a/socket_channel.hpp
++++ b/socket_channel.hpp
+@@ -52,33 +52,34 @@ class Channel
+ }
+
+ /**
+- * @brief Fetch the port number of the remote peer
+- *
+- * Returns the port number of the remote peer
++ * @brief Fetch the IP address of the remote peer
+ *
+- * @return Port number
++ * Returns the IP address of the remote peer which is connected to this
++ * socket
+ *
++ * @return IP address of the remote peer
+ */
+- auto getPort() const
++ std::uint32_t getRemoteAddressInBytes() const
+ {
+- return endpoint.port();
++ const boost::asio::ip::address& addr = endpoint.address();
++ if (addr.is_v4())
++ {
++ return addr.to_v4().to_uint();
++ }
++ return 0;
+ }
+
+ /**
+- * @brief Return the binary representation of the remote IPv4 address
++ * @brief Fetch the port number of the remote peer
+ *
+- * getSessionInfo needs to return the remote IPv4 addresses of each session
++ * Returns the port number of the remote peer
++ *
++ * @return Port number
+ *
+- * @return A uint32_t representation of the remote IPv4 address
+ */
+- std::uint32_t getRemoteAddressInbytes()
++ auto getPort() const
+ {
+- const boost::asio::ip::address& addr = endpoint.address();
+- if (addr.is_v4())
+- {
+- return addr.to_v4().to_uint();
+- }
+- return 0;
++ return endpoint.port();
+ }
+
+ /**
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch
new file mode 100644
index 000000000..771120120
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch
@@ -0,0 +1,311 @@
+From 6b9aaf0304aed06e4b5ac53e7c163089568d4171 Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@intel.com>
+Date: Sat, 23 Mar 2019 04:03:07 +0800
+Subject: [PATCH] Add dbus interface for sol commands
+
+Add dbus interface for sol config parameters so that after move set/get
+sol config parameter command from net-ipmid to host-ipmid, the command
+can send config parameters to net-ipmid sol service through the dbus
+interface.
+
+Tested by:
+busctl introspect xyz.openbmc_project.Settings /xyz/openbmc_project
+/network/host0/sol can show correct dbus properties of sol parameters.
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x00 0x01
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x01 0x00
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0x83
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x03 0x5 0x03
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x04 0x5 0x03
+all these commands can change the dbus properties as the value in
+above commands.
+Before and after run these commands, ipmitool -I lanplus -H x -U x
+-P x sol activate can start sol session correctly.
+After reboot BMC, "Progress" property in dbus interface change back
+to 0 and other properties will not reset to default value.
+
+Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com>
+---
+ command/payload_cmds.cpp | 1 +
+ command/sol_cmds.cpp | 84 ---------------------------------
+ sol/sol_manager.cpp | 119 +++++++++++++++++++++++++++++++++++++++++++++++
+ sol/sol_manager.hpp | 1 +
+ sol_module.cpp | 6 ---
+ 5 files changed, 121 insertions(+), 90 deletions(-)
+
+diff --git a/command/payload_cmds.cpp b/command/payload_cmds.cpp
+index 3b5b4f8..570cdff 100644
+--- a/command/payload_cmds.cpp
++++ b/command/payload_cmds.cpp
+@@ -34,6 +34,7 @@ std::vector<uint8_t> activatePayload(const std::vector<uint8_t>& inPayload,
+ return outPayload;
+ }
+
++ std::get<sol::Manager&>(singletonPool).updateSOLParameter();
+ if (!std::get<sol::Manager&>(singletonPool).enable)
+ {
+ response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED;
+diff --git a/command/sol_cmds.cpp b/command/sol_cmds.cpp
+index a8fa410..804b5ea 100644
+--- a/command/sol_cmds.cpp
++++ b/command/sol_cmds.cpp
+@@ -65,90 +65,6 @@ void activating(uint8_t payloadInstance, uint32_t sessionID)
+ outPayload);
+ }
+
+-std::vector<uint8_t> setConfParams(const std::vector<uint8_t>& inPayload,
+- const message::Handler& handler)
+-{
+- std::vector<uint8_t> outPayload(sizeof(SetConfParamsResponse));
+- auto request =
+- reinterpret_cast<const SetConfParamsRequest*>(inPayload.data());
+- auto response = reinterpret_cast<SetConfParamsResponse*>(outPayload.data());
+- response->completionCode = IPMI_CC_OK;
+-
+- switch (static_cast<Parameter>(request->paramSelector))
+- {
+- case Parameter::PROGRESS:
+- {
+- uint8_t progress = request->value & progressMask;
+- std::get<sol::Manager&>(singletonPool).progress = progress;
+- break;
+- }
+- case Parameter::ENABLE:
+- {
+- bool enable = request->value & enableMask;
+- std::get<sol::Manager&>(singletonPool).enable = enable;
+- break;
+- }
+- case Parameter::AUTHENTICATION:
+- {
+- if (!request->auth.auth || !request->auth.encrypt)
+- {
+- response->completionCode = ipmiCCWriteReadParameter;
+- }
+- else if (request->auth.privilege <
+- static_cast<uint8_t>(session::Privilege::USER) ||
+- request->auth.privilege >
+- static_cast<uint8_t>(session::Privilege::OEM))
+- {
+- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
+- }
+- else
+- {
+- std::get<sol::Manager&>(singletonPool).solMinPrivilege =
+- static_cast<session::Privilege>(request->auth.privilege);
+- }
+- break;
+- }
+- case Parameter::ACCUMULATE:
+- {
+- using namespace std::chrono_literals;
+-
+- if (request->acc.threshold == 0)
+- {
+- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
+- break;
+- }
+-
+- std::get<sol::Manager&>(singletonPool).accumulateInterval =
+- request->acc.interval * sol::accIntervalFactor * 1ms;
+- std::get<sol::Manager&>(singletonPool).sendThreshold =
+- request->acc.threshold;
+- break;
+- }
+- case Parameter::RETRY:
+- {
+- using namespace std::chrono_literals;
+-
+- std::get<sol::Manager&>(singletonPool).retryCount =
+- request->retry.count;
+- std::get<sol::Manager&>(singletonPool).retryInterval =
+- request->retry.interval * sol::retryIntervalFactor * 1ms;
+- break;
+- }
+- case Parameter::PORT:
+- {
+- response->completionCode = ipmiCCWriteReadParameter;
+- break;
+- }
+- case Parameter::NVBITRATE:
+- case Parameter::VBITRATE:
+- case Parameter::CHANNEL:
+- default:
+- response->completionCode = ipmiCCParamNotSupported;
+- }
+-
+- return outPayload;
+-}
+-
+ std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload,
+ const message::Handler& handler)
+ {
+diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp
+index 2046fe4..de36723 100644
+--- a/sol/sol_manager.cpp
++++ b/sol/sol_manager.cpp
+@@ -12,7 +12,13 @@
+ #include <boost/asio/write.hpp>
+ #include <chrono>
+ #include <cmath>
++#include <phosphor-ipmi-host/utils.hpp>
+ #include <phosphor-logging/log.hpp>
++#include <sdbusplus/message/types.hpp>
++
++constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
++constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol";
++constexpr const char* PROP_INTF = "org.freedesktop.DBus.Properties";
+
+ namespace sol
+ {
+@@ -93,6 +99,119 @@ void Manager::stopHostConsole()
+ }
+ }
+
++std::string getService(sdbusplus::bus::bus& bus, const std::string& intf,
++ const std::string& path)
++{
++ auto mapperCall =
++ bus.new_method_call("xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject");
++
++ mapperCall.append(path);
++ mapperCall.append(std::vector<std::string>({intf}));
++
++ std::map<std::string, std::vector<std::string>> mapperResponse;
++
++ try
++ {
++ auto mapperResponseMsg = bus.call(mapperCall);
++ mapperResponseMsg.read(mapperResponse);
++ }
++ catch (sdbusplus::exception_t&)
++ {
++ throw std::runtime_error("ERROR in mapper call");
++ }
++
++ if (mapperResponse.begin() == mapperResponse.end())
++ {
++ throw std::runtime_error("ERROR in reading the mapper response");
++ }
++
++ return mapperResponse.begin()->first;
++}
++
++ipmi::PropertyMap getAllDbusProperties(sdbusplus::bus::bus& bus,
++ const std::string& service,
++ const std::string& objPath,
++ const std::string& interface)
++{
++ ipmi::PropertyMap properties;
++
++ sdbusplus::message::message method = bus.new_method_call(
++ service.c_str(), objPath.c_str(), PROP_INTF, "GetAll");
++
++ method.append(interface);
++
++ try
++ {
++ sdbusplus::message::message reply = bus.call(method);
++ reply.read(properties);
++ }
++ catch (sdbusplus::exception_t&)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Failed to get all properties",
++ phosphor::logging::entry("PATH=%s", objPath.c_str()),
++ phosphor::logging::entry("INTERFACE=%s", interface.c_str()));
++ throw std::runtime_error("ERROR in reading proerties");
++ }
++
++ return properties;
++}
++
++void Manager::updateSOLParameter()
++{
++ std::variant<uint8_t, bool> value;
++ sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
++ static std::string solService{};
++ ipmi::PropertyMap properties;
++ if (solService.empty())
++ {
++ try
++ {
++ solService = getService(dbus, solInterface, solPath);
++ }
++ catch (const std::runtime_error& e)
++ {
++ solService.clear();
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error: get SOL service failed");
++ return;
++ }
++ }
++ try
++ {
++ properties =
++ getAllDbusProperties(dbus, solService, solPath, solInterface);
++ }
++ catch (const std::runtime_error&)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error setting sol parameter");
++ return;
++ }
++
++ progress = std::get<uint8_t>(properties["Progress"]);
++
++ enable = std::get<bool>(properties["Enable"]);
++
++ solMinPrivilege = static_cast<session::Privilege>(
++ std::get<uint8_t>(properties["Authentication"]));
++
++ accumulateInterval =
++ std::get<uint8_t>((properties["AccumulateIntervalMS"])) *
++ sol::accIntervalFactor * 1ms;
++
++ sendThreshold = std::get<uint8_t>(properties["Threshold"]);
++
++ retryCount = std::get<uint8_t>(properties["RetryCount"]);
++
++ retryInterval = std::get<uint8_t>(properties["RetryIntervalMS"]) *
++ sol::retryIntervalFactor * 1ms;
++
++ return;
++}
++
+ void Manager::startPayloadInstance(uint8_t payloadInstance,
+ session::SessionID sessionID)
+ {
+diff --git a/sol/sol_manager.hpp b/sol/sol_manager.hpp
+index 5d96890..b7eb89e 100644
+--- a/sol/sol_manager.hpp
++++ b/sol/sol_manager.hpp
+@@ -248,6 +248,7 @@ class Manager
+ * @return 0 on success and errno on failure.
+ */
+ int writeConsoleSocket(const std::vector<uint8_t>& input) const;
++ void updateSOLParameter(void);
+
+ private:
+ SOLPayloadMap payloadMap;
+diff --git a/sol_module.cpp b/sol_module.cpp
+index 8200e74..2b1fb46 100644
+--- a/sol_module.cpp
++++ b/sol_module.cpp
+@@ -42,12 +42,6 @@ void registerCommands()
+ &getPayloadInfo,
+ session::Privilege::USER,
+ false},
+- // Set SOL Configuration Parameters
+- {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) |
+- static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x21},
+- &setConfParams,
+- session::Privilege::ADMIN,
+- false},
+ // Get SOL Configuration Parameters
+ {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) |
+ static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x22},
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend
new file mode 100644
index 000000000..4b82cc21c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend
@@ -0,0 +1,19 @@
+inherit useradd
+
+# TODO: This should be removed, once up-stream bump up
+# issue is resolved
+#SRC_URI += "git://github.com/openbmc/phosphor-net-ipmid"
+SRCREV = "7e5d38d2fb51fc746624ff2f2b3701cea245a8fb"
+
+USERADD_PACKAGES = "${PN}"
+# add a group called ipmi
+GROUPADD_PARAM_${PN} = "ipmi "
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += " file://0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch \
+ file://0007-Adding-support-for-GetSessionInfo-command.patch \
+ file://0008-Sync-GetSession-Info-cmd-based-on-Upstream-review.patch \
+ file://0009-Add-dbus-interface-for-sol-commands.patch \
+ "
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend
new file mode 100644
index 000000000..72d991c7e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend
@@ -0,0 +1 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb
new file mode 100644
index 000000000..09d2f9c41
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb
@@ -0,0 +1,19 @@
+SUMMARY = "Node Manager Proxy"
+DESCRIPTION = "The Node Manager Proxy provides a simple interface for communicating \
+with Management Engine via IPMB"
+
+SRC_URI = "git://git@github.com/Intel-BMC/node-manager;protocol=ssh"
+SRCREV = "81133dd32bd0337aec9e026d1c9c2788028c7bdd"
+PV = "0.1+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SYSTEMD_SERVICE_${PN} = "node-manager-proxy.service"
+
+DEPENDS = "sdbusplus \
+ phosphor-logging \
+ boost"
+
+S = "${WORKDIR}/git/"
+inherit cmake systemd
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb
new file mode 100644
index 000000000..dd48df0c6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb
@@ -0,0 +1,21 @@
+SUMMARY = "Phosphor LED Group Management for Intel"
+PR = "r1"
+
+inherit native
+inherit obmc-phosphor-utils
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+PROVIDES += "virtual/phosphor-led-manager-config-native"
+
+SRC_URI += "file://led.yaml"
+S = "${WORKDIR}"
+
+# Overwrite the example led layout yaml file prior
+# to building the phosphor-led-manager package
+do_install() {
+ SRC=${S}
+ DEST=${D}${datadir}/phosphor-led-manager
+ install -D ${SRC}/led.yaml ${DEST}/led.yaml
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml
new file mode 100755
index 000000000..7b193f85b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml
@@ -0,0 +1,44 @@
+bmc_booted:
+
+power_on:
+
+status_ok:
+ status_green:
+ Action: 'On'
+ status_amber:
+ Action: 'Off'
+
+status_degraded:
+ status_green:
+ Action: 'Blink'
+ DutyOn: 50
+ Period: 1000
+ status_amber:
+ Action: 'Off'
+
+status_non_critical:
+ status_green:
+ Action: 'Off'
+ status_amber:
+ Action: 'Blink'
+ DutyOn: 50
+ Period: 1000
+
+status_critical:
+ status_green:
+ Action: 'Off'
+ status_amber:
+ Action: 'On'
+
+enclosure_identify:
+ identify:
+ Action: 'On'
+
+cpu0_fault:
+ cpu0fault:
+ Action: 'On'
+
+cpu1_fault:
+ cpu1fault:
+ Action: 'On'
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/logging/phosphor-logging_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/logging/phosphor-logging_%.bbappend
new file mode 100644
index 000000000..b1f4c1ce5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/logging/phosphor-logging_%.bbappend
@@ -0,0 +1,2 @@
+SRCREV = "30047bf9647215951ba5dfe21ceb3e58a1b405a4"
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend
new file mode 100644
index 000000000..dc22b3c95
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend
@@ -0,0 +1,3 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI = "file://init" \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init
new file mode 100755
index 000000000..c5b2eb040
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init
@@ -0,0 +1,180 @@
+#!/bin/sh
+
+# Copyright 2017-2019 Intel Corporation
+#
+# 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.
+#
+#
+# provide a couple of places in the RO root filesystem
+# that can be made RW with an overlayfs
+
+# start with /proc and /tmp mounted
+[ -e /proc/mounts ] || mount -t proc proc /proc
+grep -q /tmp /proc/mounts || mount -t tmpfs -o rw,nosuid,nodev tmp /tmp
+grep -q /sys /proc/mounts || mount -t sysfs -o rw,nosuid,nodev,noexec sys /sys
+
+# list of things that need to be rw at boot
+NV_OVERLAYS="/etc /var /home"
+
+# place to mount the real ubifs backing store
+RWFS_MNT=/tmp/.rwfs
+
+if grep -q "$RWFS_MNT" /proc/mounts; then
+ # quit - we have already run
+ exit 0
+fi
+mkdir -p "$RWFS_MNT"
+
+mtd_by_name() {
+ local name="$1"
+ local mtd="/dev/$(grep "$name" /proc/mtd | cut -d : -f 1)"
+ echo "$mtd"
+}
+
+mtdnum_by_name() {
+ local name="$1"
+ local mtdnum="$(grep "$name" /proc/mtd | cut -c 4)"
+ echo "$mtdnum"
+}
+
+NV_MTD=rwfs
+NV_MTD_DEV="$(mtd_by_name ${NV_MTD})"
+NV_MTD_NUM="$(mtdnum_by_name ${NV_MTD})"
+
+nvrw() {
+ local p="$1"
+ mkdir -p "${RWFS_MNT}${p}" "${RWFS_MNT}${p}.work"
+ local mname=$(echo "rwnv${p}" | sed 's,/,,g')
+ local opts="lowerdir=${p},upperdir=${RWFS_MNT}${p},workdir=${RWFS_MNT}${p}.work"
+ mount -t overlay -o "$opts" "$mname" "$p"
+}
+
+targetted_clean() {
+ local LOG_TAG="restore-defaults"
+ # Do not delete server certificates for the web server or ssh
+ echo "removing targetted contents:"
+ cd "${RWFS_MNT}/etc"
+ for file in *; do
+ case $file in
+ # The only files that stay are here:
+ CA|RestoreDefaultConfiguration|dropbear|sdr|server.pem);;
+ # All else get removed.
+ *) echo "remove $file"
+ rm -rf $file;;
+ esac
+ done
+ # nothing should be in the workdir, but clear it just in case
+ rm -rf "${RWFS_MNT}/etc.work"
+
+ # Log files remaining - but not to stdout.
+ echo "Files remaining: $(ls)"
+
+ # clean everything out of /var
+ rm -rf "${RWFS_MNT}/var" "${RWFS_MNT}/var.work"
+}
+
+full_clean() {
+ local OVL=''
+ for OVL in $NV_OVERLAYS; do
+ rm -rf "${RWFS_MNT}${OVL}" "${RWFS_MNT}${OVL}.work"
+ done
+}
+
+# check for full factory reset: if so, ubiformat $NV_MTD_DEV
+bootflags="0x$(sed -n 's/^.*bootflags=\([0-9a-f]*\).*$/\1/p' /proc/cmdline)"
+bootflags=$((bootflags + 0))
+let "restore_op = $bootflags & 0x3"
+if [ $restore_op -eq 3 ]; then
+ ubiformat -y "$NV_MTD_DEV"
+fi
+
+# attach a UBI device to the MTD device
+NV_UBI_DEV="/dev/ubi${NV_MTD_NUM}"
+if [ ! -e $NV_UBI_DEV ]; then
+ if ! ubiattach -m "$NV_MTD_NUM" -d "$NV_MTD_NUM"; then
+ # the attach failed, so format the MTD device and try again
+ echo "Warning! Failed to attach $NV_UBI_DEV to $NV_MTD_DEV."
+ echo "UBI-formatting $NV_MTD_DEV to attach again. Data on this device will be lost."
+ ubiformat -y "$NV_MTD_DEV"
+ ubiattach -m "$NV_MTD_NUM" -d "$NV_MTD_NUM"
+ fi
+fi
+
+# make a UBI volume on the UBI device
+NV_UBI_VOL="${NV_UBI_DEV}_0"
+if [ ! -e $NV_UBI_VOL ]; then
+ ubimkvol "$NV_UBI_DEV" -N "$NV_MTD" -m
+fi
+
+# mount a UBIFS on the UBI volume
+mount -t ubifs "$NV_UBI_VOL" "$RWFS_MNT"
+
+if [ $restore_op -eq 1 ]; then
+ targetted_clean
+elif [ $restore_op -eq 2 ]; then
+ full_clean
+fi
+
+for FS in $NV_OVERLAYS; do
+ nvrw "$FS"
+done
+
+# make sure that /etc/fw_env.config mirrors our current uboot environment
+UENV_MTD_INFO=$(grep UENV /proc/mtd)
+if [ -n "$UENV_MTD_INFO" ]; then
+ UENV_MTD_INFO=$(echo "$UENV_MTD_INFO" | sed 's,^\([^:]*\): \([0-9a-f]*\) \([0-9a-f]*\) .*,/dev/\1 0 0x\2 0x\3,')
+ if ! grep -q "^${UENV_MTD_INFO}$" /etc/fw_env.config; then
+ echo "${UENV_MTD_INFO}" > /etc/fw_env.config
+ echo "Updated fw_env.config"
+ fi
+fi
+
+# work around bug where /etc/machine-id will be mounted with a temporary file
+# if rootfs is read-only and the file is empty
+MACHINE_ID=/etc/machine-id
+if [ ! -s "$MACHINE_ID" ]; then
+ systemd-machine-id-setup
+fi
+
+# mount persistent NV filesystem, where immortal settings live
+if ! grep -q sofs /proc/mounts; then
+ mkdir -p /var/sofs
+ SOFS_MTD=sofs
+ SOFS_MTD_DEV="$(mtd_by_name ${SOFS_MTD})"
+ SOFS_MTD_NUM="$(mtdnum_by_name ${SOFS_MTD})"
+ SOFS_UBI_DEV="/dev/ubi${SOFS_MTD_NUM}"
+
+ # attach a UBI device to the MTD device
+ if [ ! -e $SOFS_UBI_DEV ]; then
+ if ! ubiattach -m "$SOFS_MTD_NUM" -d "$SOFS_MTD_NUM"; then
+ # the attach failed, so format the MTD device and try again
+ echo "Warning! Failed to attach $SOFS_UBI_DEV to $SOFS_MTD_DEV."
+ echo "UBI-formatting $SOFS_MTD_DEV to attach again. Data on this device will be lost."
+ ubiformat -y "$SOFS_MTD_DEV"
+ ubiattach -m "$SOFS_MTD_NUM" -d "$SOFS_MTD_NUM"
+ fi
+ fi
+
+ # make a UBI volume on the UBI device
+ SOFS_UBI_VOL="${SOFS_UBI_DEV}_0"
+ if [ ! -e $SOFS_UBI_VOL ]; then
+ ubimkvol "$SOFS_UBI_DEV" -N "$SOFS_MTD" -m
+ fi
+
+ # mount a UBIFS on the UBI volume
+ mount -t ubifs "$SOFS_UBI_VOL" /var/sofs
+fi
+
+echo "Finished mounting non-volatile overlays"
+
+exec /lib/systemd/systemd
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend
new file mode 100644
index 000000000..809d05b94
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend
@@ -0,0 +1,6 @@
+# Enable downstream autobump
+SRC_URI = "git://github.com/openbmc/phosphor-sel-logger.git"
+SRCREV = "2b9704d7eb666c945c73dd74a426a0af2292b0ea"
+
+# Enable threshold monitoring
+EXTRA_OECMAKE += "-DSEL_LOGGER_MONITOR_THRESHOLD_EVENTS=ON"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service
new file mode 100644
index 000000000..b8c3554ae
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test/xyz.openbmc_project.selftest.service
@@ -0,0 +1,10 @@
+[Unit]
+Description= BMC Self-Test
+
+[Service]
+Restart=always
+ExecStart=/usr/bin/env selftest
+SyslogIdentifier=selftest
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb
new file mode 100644
index 000000000..da1d74207
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/selftest/intel-self-test_git.bb
@@ -0,0 +1,38 @@
+SUMMARY = "BMC Self Test service"
+DESCRIPTION = "BMC Self Test service for subsystem diagnosis failure info"
+
+SRC_URI = "git://git@github.com/Intel-BMC/intel-self-test;protocol=ssh"
+
+PV = "1.0+git${SRCPV}"
+SRCREV = "d039998ad2c55aeae4191af30e15bbd3032508c1"
+
+S = "${WORKDIR}/git"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=fa818a259cbed7ce8bc2a22d35a464fc"
+
+inherit cmake
+inherit obmc-phosphor-dbus-service
+inherit obmc-phosphor-systemd
+inherit pkgconfig pythonnative
+
+SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.selftest.service"
+
+DEPENDS += " \
+ autoconf-archive-native \
+ systemd \
+ sdbusplus \
+ sdbusplus-native \
+ phosphor-logging \
+ phosphor-dbus-interfaces \
+ phosphor-dbus-interfaces-native \
+ "
+
+RDEPENDS_${PN} += " \
+ libsystemd \
+ sdbusplus \
+ phosphor-logging \
+ phosphor-dbus-interfaces \
+ "
+
+EXTRA_OECMAKE = " -DENABLE_GTEST=OFF -DCMAKE_SKIP_RPATH=ON"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend
new file mode 100644
index 000000000..dff1647e8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend
@@ -0,0 +1,4 @@
+SRCREV = "209ec56cca898725213140fd0d1205a4d2f1c6a4"
+SRC_URI = "git://github.com/openbmc/dbus-sensors.git"
+
+DEPENDS_append = " i2c-tools"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native.bbappend
new file mode 100644
index 000000000..436623234
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native.bbappend
@@ -0,0 +1,4 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://defaults.yaml \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native/defaults.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native/defaults.yaml
new file mode 100644
index 000000000..24816fb4c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-defaults-native/defaults.yaml
@@ -0,0 +1,181 @@
+/xyz/openbmc_project/control/minimum_ship_level_required:
+ - Interface: xyz.openbmc_project.Control.MinimumShipLevel
+ Properties:
+ MinimumShipLevelRequired:
+ Default: 'true'
+
+/xyz/openbmc_project/control/host0/auto_reboot:
+ - Interface: xyz.openbmc_project.Control.Boot.RebootPolicy
+ Properties:
+ AutoReboot:
+ Default: 'false'
+
+/xyz/openbmc_project/control/host0/boot:
+ - Interface: xyz.openbmc_project.Control.Boot.Source
+ Properties:
+ BootSource:
+ Default: Source::Sources::Default
+ - Interface: xyz.openbmc_project.Control.Boot.Mode
+ Properties:
+ BootMode:
+ Default: Mode::Modes::Regular
+
+/xyz/openbmc_project/control/host0/boot/one_time:
+ - Interface: xyz.openbmc_project.Control.Boot.Source
+ Properties:
+ BootSource:
+ Default: Source::Sources::Default
+ - Interface: xyz.openbmc_project.Control.Boot.Mode
+ Properties:
+ BootMode:
+ Default: Mode::Modes::Regular
+ - Interface: xyz.openbmc_project.Object.Enable
+ Properties:
+ Enabled:
+ Default: 'true'
+
+/xyz/openbmc_project/control/host0/power_cap:
+ - Interface: xyz.openbmc_project.Control.Power.Cap
+ Properties:
+ PowerCap:
+ Default: 0
+ Validation:
+ Type: "range"
+ Validator: "0..1000"
+ Unit: "Watts"
+ PowerCapEnable:
+ Default: 'false'
+
+/xyz/openbmc_project/control/host0/power_restore_policy:
+ - Interface: xyz.openbmc_project.Control.Power.RestorePolicy
+ Properties:
+ PowerRestorePolicy:
+ Default: RestorePolicy::Policy::AlwaysOff
+
+/xyz/openbmc_project/control/power_restore_delay:
+ - Interface: xyz.openbmc_project.Control.Power.RestoreDelay
+ Properties:
+ PowerRestoreDelay:
+ Default: 0
+
+/xyz/openbmc_project/control/host0/acpi_power_state:
+ - Interface: xyz.openbmc_project.Control.Power.ACPIPowerState
+ Properties:
+ SysACPIStatus:
+ Default: ACPIPowerState::ACPI::Unknown
+ DevACPIStatus:
+ Default: ACPIPowerState::ACPI::Unknown
+
+/xyz/openbmc_project/time/owner:
+ - Interface: xyz.openbmc_project.Time.Owner
+ Properties:
+ TimeOwner:
+ Default: Owner::Owners::BMC
+
+/xyz/openbmc_project/time/sync_method:
+ - Interface: xyz.openbmc_project.Time.Synchronization
+ Properties:
+ TimeSyncMethod:
+ Default: Synchronization::Method::NTP
+
+/xyz/openbmc_project/network/host0/intf:
+ - Interface: xyz.openbmc_project.Network.MACAddress
+ Properties:
+ MACAddress:
+ Default: '"00:00:00:00:00:00"'
+ Validation:
+ Type: "regex"
+ Validator: '^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$'
+
+#needs to implement address validation TODO openbmc/issues/2046
+/xyz/openbmc_project/network/host0/intf/addr:
+ - Interface: xyz.openbmc_project.Network.IP
+ Properties:
+ Address:
+ Default: '"0.0.0.0"'
+ PrefixLength:
+ Default: 0
+ Validation:
+ Type: "range"
+ Validator: 0..128
+ Unit: "bits"
+ Origin:
+ Default: IP::AddressOrigin::Static
+ Gateway:
+ Default: '"0.0.0.0"'
+ Type:
+ Default: IP::Protocol::IPv4
+
+/xyz/openbmc_project/control/host0/restriction_mode:
+ - Interface: xyz.openbmc_project.Control.Security.RestrictionMode
+ Properties:
+ RestrictionMode:
+ Default: RestrictionMode::Modes::None
+
+/xyz/openbmc_project/control/host0/TPMEnable:
+ - Interface: xyz.openbmc_project.Control.TPM.Policy
+ Properties:
+ TPMEnable:
+ Default: 'false'
+
+/xyz/openbmc_project/control/power_supply_redundancy:
+ - Interface: xyz.openbmc_project.Control.PowerSupplyRedundancy
+ Properties:
+ PowerSupplyRedundancyEnabled:
+ Default: 'true'
+
+/xyz/openbmc_project/control/host0/turbo_allowed:
+ - Interface: xyz.openbmc_project.Control.Host.TurboAllowed
+ Properties:
+ TurboAllowed:
+ Default: 'true'
+
+/xyz/openbmc_project/control/host0/systemGUID:
+ - Interface: xyz.openbmc_project.Common.UUID
+ Properties:
+ UUID:
+ Default: '"00000000-0000-0000-0000-000000000000"'
+
+/xyz/openbmc_project/bios:
+ - Interface: xyz.openbmc_project.Inventory.Item.Bios
+ Properties:
+ BiosId:
+ Default: '"NA"'
+
+/xyz/openbmc_project/control/processor_error_config:
+ - Interface: xyz.openbmc_project.Control.Processor.ErrConfig
+ Properties:
+ ResetCfg:
+ Default: 0
+ ResetErrorOccurrenceCounts:
+ Default: 0
+
+/xyz/openbmc_project/control/shutdown_policy_config:
+ - Interface: xyz.openbmc_project.Control.ShutdownPolicy
+ Properties:
+ Policy:
+ Default: 0
+
+/xyz/openbmc_project/control/chassis_capabilities_config:
+ - Interface: xyz.openbmc_project.Control.ChassisCapabilities
+ Properties:
+ CapabilitiesFlags:
+ Default: 0
+ FRUDeviceAddress:
+ Default: 0x20
+ SDRDeviceAddress:
+ Default: 0x20
+ SELDeviceAddress:
+ Default: 0x20
+ SMDeviceAddress:
+ Default: 0x20
+ BridgeDeviceAddress:
+ Default: 0x20
+
+/xyz/openbmc_project/control/thermal_mode:
+ - Interface: xyz.openbmc_project.Control.ThermalMode
+ Properties:
+ Current:
+ Default: '"Performance"'
+ Supported:
+ Default: '{"Acoustic", "Performance"}'
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager/0001-settings-initialize-data-file-with-default-setting.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager/0001-settings-initialize-data-file-with-default-setting.patch
new file mode 100644
index 000000000..fcf2415d6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager/0001-settings-initialize-data-file-with-default-setting.patch
@@ -0,0 +1,37 @@
+From 9e99aa4f72f4420e03ec2e4a29816eae43c5e748 Mon Sep 17 00:00:00 2001
+From: "Jia, Chunhui" <chunhui.jia@intel.com>
+Date: Tue, 29 May 2018 16:16:06 +0800
+Subject: [PATCH] [settings] initialize data file with default setting
+
+Current code trys to load settings from file at startup. When file
+does not exist, it will just use default setting. However, it will
+still load default on next reboot because no one create files.
+
+This change creates file as well when daemon loads default so next
+time daemon could load/save from file.
+
+Signed-off-by: Jia, Chunhui <chunhui.jia@intel.com>
+---
+ settings_manager.mako.hpp | 3 +++
+ 1 file changed, 3 insertions(+)
+ mode change 100644 => 100755 settings_manager.mako.hpp
+
+diff --git a/settings_manager.mako.hpp b/settings_manager.mako.hpp
+old mode 100644
+new mode 100755
+index 09a5a1f..cd592a0
+--- a/settings_manager.mako.hpp
++++ b/settings_manager.mako.hpp
+@@ -323,6 +323,9 @@ class Manager
+ else
+ {
+ initSetting${index}();
++ std::ofstream ostr(path.c_str(), std::ios::out);
++ cereal::JSONOutputArchive oarchive(ostr);
++ oarchive(*std::get<${index}>(settings)); //create file with default
+ }
+ }
+ catch (cereal::Exception& e)
+--
+2.16.2
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager_%.bbappend
new file mode 100644
index 000000000..bc695abe8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/phosphor-settings-manager_%.bbappend
@@ -0,0 +1,4 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://0001-settings-initialize-data-file-with-default-setting.patch \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb
new file mode 100644
index 000000000..01c93490b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/srvcfg-manager/srvcfg-manager_git.bb
@@ -0,0 +1,28 @@
+SUMMARY = "Service configuration manager daemon to control service properties"
+DESCRIPTION = "Daemon controls service properies like port, channels, state etc.."
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git/srvcfg-manager"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SRC_URI = "git://git@github.com/Intel-BMC/provingground.git;protocol=ssh"
+SRCREV = "f4d4bfc3296cb27feb17aa5d1d93b3061b56ce10"
+
+inherit cmake systemd
+SYSTEMD_SERVICE_${PN} = "srvcfg-manager.service"
+
+DEPENDS += " \
+ systemd \
+ sdbusplus \
+ sdbusplus-native \
+ phosphor-logging \
+ boost \
+ "
+RDEPENDS_${PN} += " \
+ libsystemd \
+ sdbusplus \
+ phosphor-logging \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0001-Modify-dbus-interface-for-power-control.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0001-Modify-dbus-interface-for-power-control.patch
new file mode 100644
index 000000000..fac9b52f1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0001-Modify-dbus-interface-for-power-control.patch
@@ -0,0 +1,38 @@
+From d34a2a5f6ca0564275ed0e2664624525cad64585 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Fri, 13 Jul 2018 09:08:52 +0800
+Subject: [PATCH] Modify dbus interface for power control
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Switch power control service namespace from “org” to “xyz”,
+to compatible with new intel-chassis services
+
+Change-Id: I1bf5e218f72eb9fd4fb6f203c35479818d12b1fa
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ chassis_state_manager.cpp | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/chassis_state_manager.cpp b/chassis_state_manager.cpp
+index 03dd176..05e2440 100644
+--- a/chassis_state_manager.cpp
++++ b/chassis_state_manager.cpp
+@@ -63,10 +63,11 @@ void Chassis::determineInitialState()
+ {
+ sdbusplus::message::variant<int> pgood = -1;
+ auto method = this->bus.new_method_call(
+- "org.openbmc.control.Power", "/org/openbmc/control/power0",
++ "xyz.openbmc_project.Chassis.Control.Power",
++ "/xyz/openbmc_project/Chassis/Control/Power0",
+ "org.freedesktop.DBus.Properties", "Get");
+
+- method.append("org.openbmc.control.Power", "pgood");
++ method.append("xyz.openbmc_project.Chassis.Control.Power", "pgood");
+ try
+ {
+ auto reply = this->bus.call(method);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0002-Capture-host-restart-cause.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0002-Capture-host-restart-cause.patch
new file mode 100644
index 000000000..7d70b29fa
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0002-Capture-host-restart-cause.patch
@@ -0,0 +1,234 @@
+From c0f01261572cb527cf9dc62fa732b28c658ff013 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Tue, 7 Aug 2018 16:43:00 +0800
+Subject: [PATCH] Capture host restart cause
+
+Capture host restart cause on power/reset button pressed,
+and power restore policy settings.
+Save the restart cause into file system.
+And restort it when BMC boot up.
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ configure.ac | 4 ++--
+ discover_system_state.cpp | 14 ++++++++++++
+ host_state_manager.cpp | 16 ++++++++++++++
+ host_state_manager.hpp | 56 ++++++++++++++++++++++++++++++++++++++++++++---
+ 4 files changed, 85 insertions(+), 5 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index e985a95..b9e64c8 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -56,9 +56,9 @@ AC_ARG_VAR(HOST_RUNNING_FILE, [File to create if host is running])
+ AS_IF([test "x$HOST_RUNNING_FILE" == "x"], [HOST_RUNNING_FILE="/run/openbmc/host@%u-on"])
+ AC_DEFINE_UNQUOTED([HOST_RUNNING_FILE], ["$HOST_RUNNING_FILE"], [File to create if host is running])
+
+-AC_ARG_VAR(HOST_STATE_PERSIST_PATH, [Path of file for storing requested host state.])
++AC_ARG_VAR(HOST_STATE_PERSIST_PATH, [Path of file for storing host state.])
+ AS_IF([test "x$HOST_STATE_PERSIST_PATH" == "x"], \
+- [HOST_STATE_PERSIST_PATH="/var/lib/phosphor-state-manager/requestedHostTransition"])
++ [HOST_STATE_PERSIST_PATH="/var/lib/phosphor-state-manager/hostState"])
+ AC_DEFINE_UNQUOTED([HOST_STATE_PERSIST_PATH], ["$HOST_STATE_PERSIST_PATH"], \
+ [Path of file for storing requested host state.])
+
+diff --git a/discover_system_state.cpp b/discover_system_state.cpp
+index 3a38152..0b5798a 100644
+--- a/discover_system_state.cpp
++++ b/discover_system_state.cpp
+@@ -12,6 +12,7 @@
+ #include "settings.hpp"
+ #include "xyz/openbmc_project/Common/error.hpp"
+ #include "xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp"
++#include <xyz/openbmc_project/State/Host/server.hpp>
+
+ namespace phosphor
+ {
+@@ -181,6 +182,10 @@ int main(int argc, char** argv)
+ log<level::INFO>("power_policy=ALWAYS_POWER_ON, powering host on");
+ setProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition",
+ convertForMessage(server::Host::Transition::On));
++
++ setProperty(
++ bus, hostPath, HOST_BUSNAME, "HostRestartCause",
++ convertForMessage(server::Host::RestartCause::PowerPolicyAlwaysOn));
+ }
+ else if (RestorePolicy::Policy::Restore ==
+ RestorePolicy::convertPolicyFromString(powerPolicy))
+@@ -192,6 +197,15 @@ int main(int argc, char** argv)
+ getProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition");
+ setProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition",
+ hostReqState);
++
++ if (server::Host::convertTransitionFromString(hostReqState) ==
++ server::Host::Transition::On)
++ {
++ setProperty(
++ bus, hostPath, HOST_BUSNAME, "HostRestartCause",
++ convertForMessage(
++ server::Host::RestartCause::PowerPolicyPreviousState));
++ }
+ }
+
+ return 0;
+diff --git a/host_state_manager.cpp b/host_state_manager.cpp
+index 7d661dd..03d210d 100644
+--- a/host_state_manager.cpp
++++ b/host_state_manager.cpp
+@@ -308,6 +308,15 @@ bool Host::deserialize(const fs::path& path)
+ }
+ }
+
++void Host::restoreHostRestartCause()
++{
++ if (!deserialize(HOST_STATE_PERSIST_PATH))
++ {
++ // set to default value
++ server::Host::hostRestartCause(server::Host::RestartCause::Unknown);
++ }
++}
++
+ Host::Transition Host::requestedHostTransition(Transition value)
+ {
+ log<level::INFO>("Host State transaction request",
+@@ -353,6 +362,13 @@ Host::HostState Host::currentHostState(HostState value)
+ return server::Host::currentHostState(value);
+ }
+
++Host::RestartCause Host::hostRestartCause(RestartCause value)
++{
++ auto retVal = server::Host::hostRestartCause(value);
++ serialize();
++ return retVal;
++}
++
+ } // namespace manager
+ } // namespace state
+ } // namespace phosphor
+diff --git a/host_state_manager.hpp b/host_state_manager.hpp
+index 2b00777..e74fab7 100644
+--- a/host_state_manager.hpp
++++ b/host_state_manager.hpp
+@@ -32,6 +32,15 @@ using namespace phosphor::logging;
+ namespace sdbusRule = sdbusplus::bus::match::rules;
+ namespace fs = std::experimental::filesystem;
+
++const static constexpr char* powerButtonPath =
++ "/xyz/openbmc_project/Chassis/Buttons/Power0";
++const static constexpr char* powerButtonIntf =
++ "xyz.openbmc_project.Chassis.Buttons.Power";
++const static constexpr char* resetButtonPath =
++ "/xyz/openbmc_project/Chassis/Buttons/Reset0";
++const static constexpr char* resetButtonIntf =
++ "xyz.openbmc_project.Chassis.Buttons.Reset";
++
+ /** @class Host
+ * @brief OpenBMC host state management implementation.
+ * @details A concrete implementation for xyz.openbmc_project.State.Host
+@@ -59,7 +68,31 @@ class Host : public HostInherit
+ sdbusRule::interface("org.freedesktop.systemd1.Manager"),
+ std::bind(std::mem_fn(&Host::sysStateChange), this,
+ std::placeholders::_1)),
+- settings(bus)
++ settings(bus),
++ powerButtonPressedSignal(
++ bus,
++ sdbusRule::type::signal() + sdbusRule::member("Pressed") +
++ sdbusRule::path(powerButtonPath) +
++ sdbusRule::interface(powerButtonIntf),
++ [this](sdbusplus::message::message &msg) {
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "powerButtonPressedSignal callback function is called...");
++ this->hostRestartCause(this->RestartCause::PowerButton);
++ return;
++ }
++ ),
++ resetButtonPressedSignal(
++ bus,
++ sdbusRule::type::signal() + sdbusRule::member("Pressed") +
++ sdbusRule::path(resetButtonPath) +
++ sdbusRule::interface(resetButtonIntf),
++ [this](sdbusplus::message::message &msg) {
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "resetButtonPressedSignal callback function is called...");
++ this->hostRestartCause(this->RestartCause::ResetButton);
++ return;
++ }
++ )
+ {
+ // Enable systemd signals
+ subscribeToSystemdSignals();
+@@ -69,6 +102,8 @@ class Host : public HostInherit
+
+ attemptsLeft(BOOT_COUNT_MAX_ALLOWED);
+
++ restoreHostRestartCause(); // restore host restart cause from persisted file
++
+ // We deferred this until we could get our property correct
+ this->emit_object_added();
+ }
+@@ -85,6 +120,9 @@ class Host : public HostInherit
+ /** @brief Set value of CurrentHostState */
+ HostState currentHostState(HostState value) override;
+
++ /** @brief Set value of HostRestartCause */
++ RestartCause hostRestartCause(RestartCause value) override;
++
+ /**
+ * @brief Set host reboot count to default
+ *
+@@ -192,7 +230,10 @@ class Host : public HostInherit
+ server::Progress::bootProgress()),
+ convertForMessage(
+ sdbusplus::xyz::openbmc_project::State::OperatingSystem::
+- server::Status::operatingSystemState()));
++ server::Status::operatingSystemState()),
++ convertForMessage(sdbusplus::xyz::openbmc_project::State::
++ server::Host::hostRestartCause())
++ );
+ }
+
+ /** @brief Function required by Cereal to perform deserialization.
+@@ -208,7 +249,8 @@ class Host : public HostInherit
+ std::string reqTranState;
+ std::string bootProgress;
+ std::string osState;
+- archive(reqTranState, bootProgress, osState);
++ std::string restartCause;
++ archive(reqTranState, bootProgress, osState, restartCause);
+ auto reqTran = Host::convertTransitionFromString(reqTranState);
+ // When restoring, set the requested state with persistent value
+ // but don't call the override which would execute it
+@@ -219,6 +261,8 @@ class Host : public HostInherit
+ sdbusplus::xyz::openbmc_project::State::OperatingSystem::server::
+ Status::operatingSystemState(
+ Host::convertOSStatusFromString(osState));
++ sdbusplus::xyz::openbmc_project::State::server::Host::
++ hostRestartCause(Host::convertRestartCauseFromString(restartCause));
+ }
+
+ /** @brief Serialize and persist requested host state
+@@ -239,6 +283,9 @@ class Host : public HostInherit
+ */
+ bool deserialize(const fs::path& path);
+
++ /** @brief Used to restore HostRestartCause value from persisted file */
++ void restoreHostRestartCause();
++
+ /** @brief Persistent sdbusplus DBus bus connection. */
+ sdbusplus::bus::bus& bus;
+
+@@ -247,6 +294,9 @@ class Host : public HostInherit
+
+ // Settings objects of interest
+ settings::Objects settings;
++
++ sdbusplus::bus::match_t powerButtonPressedSignal;
++ sdbusplus::bus::match_t resetButtonPressedSignal;
+ };
+
+ } // namespace manager
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0003-Use-warm-reboot-for-the-Reboot-host-state-transition.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0003-Use-warm-reboot-for-the-Reboot-host-state-transition.patch
new file mode 100644
index 000000000..40722c3c9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0003-Use-warm-reboot-for-the-Reboot-host-state-transition.patch
@@ -0,0 +1,71 @@
+From 8a7f73a0688524c71023da89e8cb5578dac16f5d Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Fri, 8 Mar 2019 17:21:49 +0800
+Subject: [PATCH] Use warm-reboot for the Reboot host state transition
+
+The same as reset button pressing, the pgood signal will keep on during the reboot
+
+Tested By:
+ipmitool chassis power reset
+The pgood(gpio219) will be keep high during the reset process
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ host_state_manager.cpp | 20 +++++++++++++-------
+ 1 file changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/host_state_manager.cpp b/host_state_manager.cpp
+index 03d210d..8fac348 100644
+--- a/host_state_manager.cpp
++++ b/host_state_manager.cpp
+@@ -44,8 +44,9 @@ constexpr auto HOST_STATE_SOFT_POWEROFF_TGT = "obmc-host-shutdown@0.target";
+ constexpr auto HOST_STATE_POWEROFF_TGT = "obmc-host-stop@0.target";
+ constexpr auto HOST_STATE_POWERON_TGT = "obmc-host-start@0.target";
+ constexpr auto HOST_STATE_POWERON_MIN_TGT = "obmc-host-startmin@0.target";
+-constexpr auto HOST_STATE_REBOOT_TGT = "obmc-host-reboot@0.target";
++constexpr auto HOST_STATE_REBOOT_TGT = "obmc-host-warm-reset@0.target";
+ constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-host-quiesce@0.target";
++constexpr auto hostStateRebootService = "intel-power-warm-reset@0.service";
+
+ constexpr auto ACTIVE_STATE = "active";
+ constexpr auto ACTIVATING_STATE = "activating";
+@@ -168,6 +169,7 @@ bool Host::stateActive(const std::string& target)
+
+ const auto& currentStateStr =
+ sdbusplus::message::variant_ns::get<std::string>(currentState);
++
+ return currentStateStr == ACTIVE_STATE ||
+ currentStateStr == ACTIVATING_STATE;
+ }
+@@ -236,18 +238,22 @@ void Host::sysStateChange(sdbusplus::message::message& msg)
+ // Read the msg and populate each variable
+ msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
+
+- if ((newStateUnit == HOST_STATE_POWEROFF_TGT) &&
+- (newStateResult == "done") &&
+- (!stateActive(HOST_STATE_POWERON_MIN_TGT)))
++ if (((newStateUnit == HOST_STATE_POWEROFF_TGT) &&
++ (newStateResult == "done") &&
++ (!stateActive(HOST_STATE_POWERON_MIN_TGT))) ||
++ ((newStateUnit == hostStateRebootService) &&
++ (newStateResult == "done")))
+ {
+ log<level::INFO>("Received signal that host is off");
+ this->currentHostState(server::Host::HostState::Off);
+ this->bootProgress(bootprogress::Progress::ProgressStages::Unspecified);
+ this->operatingSystemState(osstatus::Status::OSStatus::Inactive);
+ }
+- else if ((newStateUnit == HOST_STATE_POWERON_MIN_TGT) &&
+- (newStateResult == "done") &&
+- (stateActive(HOST_STATE_POWERON_MIN_TGT)))
++ else if (((newStateUnit == HOST_STATE_POWERON_MIN_TGT) &&
++ (newStateResult == "done") &&
++ (stateActive(HOST_STATE_POWERON_MIN_TGT))) ||
++ ((newStateUnit == HOST_STATE_REBOOT_TGT) &&
++ (newStateResult == "done")))
+ {
+ log<level::INFO>("Received signal that host is running");
+ this->currentHostState(server::Host::HostState::Running);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reboot-host@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reboot-host@.service
new file mode 100644
index 000000000..ffde01ca3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reboot-host@.service
@@ -0,0 +1,18 @@
+[Unit]
+Description=Reboot host%i
+Wants=obmc-host-stop@%i.target
+After=obmc-host-stop@%i.target
+
+[Service]
+#ExecStart={base_bindir}/systemctl start obmc-host-start@%i.target
+# This service is starting another target that conflicts with the
+# target this service is running in. OpenBMC needs a refactor of
+# how it does its host reset path. Until then, this short term
+# solution does the job.
+# Since this is a part of the reboot target, call the startmin
+# target which does the minimum required to start the host.
+ExecStart=/bin/sh -c "sleep 10 && systemctl start obmc-host-startmin@%i.target"
+
+
+[Install]
+WantedBy=obmc-host-reboot@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-check@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-check@.service
new file mode 100644
index 000000000..13b8f0fca
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-check@.service
@@ -0,0 +1,19 @@
+[Unit]
+Description=Check Host%i status on BMC reset
+Wants=mapper-wait@-xyz-openbmc_project-control-host%i.service
+After=mapper-wait@-xyz-openbmc_project-control-host%i.service
+Wants=obmc-host-reset-running@%i.target
+Before=obmc-host-reset-running@%i.target
+Wants=op-reset-chassis-on@%i.service
+After=op-reset-chassis-on@%i.service
+Conflicts=obmc-host-stop@%i.target
+ConditionPathExists=/run/openbmc/chassis@%i-on
+
+[Service]
+RemainAfterExit=yes
+Type=oneshot
+ExecStart=/bin/sh -c "if [ $(busctl get-property `mapper get-service /xyz/openbmc_project/Chassis/Control/Power%i` /xyz/openbmc_project/Chassis/Control/Power%i xyz.openbmc_project.Chassis.Control.Power vrd_good | sed 's/i\s*[1]/on/' | grep on | wc -l) != 0 ]; then mkdir -p /run/openbmc/ && touch /run/openbmc/host@%i-on; fi"
+SyslogIdentifier=phosphor-host-check
+
+[Install]
+WantedBy=obmc-host-reset@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-reboot-attempts@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-reboot-attempts@.service
new file mode 100644
index 000000000..87c750c57
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/phosphor-reset-host-reboot-attempts@.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Reset host reboot counter
+Wants=mapper-wait@-xyz-openbmc_project-state-host%i.service
+After=mapper-wait@-xyz-openbmc_project-state-host%i.service
+ConditionPathExists=!/run/openbmc/host@%i-on
+
+[Service]
+Restart=no
+Type=oneshot
+ExecStart=/bin/sh -c "busctl set-property `mapper get-service /xyz/openbmc_project/state/host%i` /xyz/openbmc_project/state/host%i xyz.openbmc_project.Control.Boot.RebootAttempts AttemptsLeft u 3"
+StartLimitInterval=0
+
+[Install]
+WantedBy=obmc-host-start@%i.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend
new file mode 100644
index 000000000..4c50ecf5e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend
@@ -0,0 +1,9 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://0001-Modify-dbus-interface-for-power-control.patch \
+ file://phosphor-reboot-host@.service \
+ file://phosphor-reset-host-reboot-attempts@.service \
+ file://phosphor-reset-host-check@.service \
+ file://0002-Capture-host-restart-cause.patch \
+ file://0003-Use-warm-reboot-for-the-Reboot-host-state-transition.patch \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager/0001-Implement-post-code-manager.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager/0001-Implement-post-code-manager.patch
new file mode 100644
index 000000000..8915484cd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager/0001-Implement-post-code-manager.patch
@@ -0,0 +1,499 @@
+From 7d78e70735e1bce51ef34cfe128be68758de3447 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Tue, 19 Feb 2019 15:00:11 +0800
+Subject: [PATCH] Implement post code manager
+
+Implement method and properties defined in PostCode.interface.yaml
+under phosphor-dbus-interfaces/xyz/openbmc_project/State/Boot
+1. Method: std::vector<uint64_t> PostCode::getPostCodes(uint16_t index)
+2. Properties: CurrentBootCycleIndex/MaxBootCycleNum
+
+Test-By:
+ Every cycle post codes is saved in "/var/lib/phosphor-post-code-manager"
+ "1" file is saved all post codes for cycle 1
+ "2" file is saved all post codes for cycle 2
+ "CurrentBootCycleIndex" file is saved the current boot cycle number.
+ root@wolfpass:/var/lib/phosphor-post-code-manager# ls
+ 1 2 CurrentBootCycleIndex
+
+Change-Id: Ia89b9121983261fef5573092d890beb84626ceeb
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ CMakeLists.txt | 45 ++++++
+ MAINTAINERS | 45 ++++++
+ inc/post_code.hpp | 152 ++++++++++++++++++
+ ...penbmc_project.State.Boot.PostCode.service | 11 ++
+ src/main.cpp | 61 +++++++
+ src/post_code.cpp | 109 +++++++++++++
+ 6 files changed, 423 insertions(+)
+ create mode 100644 CMakeLists.txt
+ create mode 100644 MAINTAINERS
+ create mode 100644 inc/post_code.hpp
+ create mode 100644 service_files/xyz.openbmc_project.State.Boot.PostCode.service
+ create mode 100644 src/main.cpp
+ create mode 100644 src/post_code.cpp
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+new file mode 100644
+index 0000000..594d839
+--- /dev/null
++++ b/CMakeLists.txt
+@@ -0,0 +1,45 @@
++cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
++project(post-code-manager CXX)
++set(CMAKE_CXX_STANDARD 17)
++set(CMAKE_CXX_STANDARD_REQUIRED ON)
++
++set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
++include(GNUInstallDirs)
++include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)
++include_directories(${CMAKE_CURRENT_BINARY_DIR})
++
++set(DBUS_OBJECT_NAME "xyz/openbmc_project/State/Boot/PostCode")
++set(DBUS_INTF_NAME "xyz.openbmc_project.State.Boot.PostCode")
++
++add_definitions(-DDBUS_OBJECT_NAME="/${DBUS_OBJECT_NAME}")
++add_definitions(-DDBUS_INTF_NAME="${DBUS_INTF_NAME}")
++set(SRC_FILES src/post_code.cpp
++ src/main.cpp )
++set ( SERVICE_FILES
++ service_files/xyz.openbmc_project.State.Boot.PostCode.service )
++
++# import sdbusplus
++find_package(PkgConfig REQUIRED)
++pkg_check_modules(SDBUSPLUSPLUS sdbusplus REQUIRED)
++include_directories(${SDBUSPLUSPLUS_INCLUDE_DIRS})
++link_directories(${SDBUSPLUSPLUS_LIBRARY_DIRS})
++find_program(SDBUSPLUSPLUS sdbus++)
++
++# import phosphor-logging
++find_package(PkgConfig REQUIRED)
++pkg_check_modules(LOGGING phosphor-logging REQUIRED)
++include_directories(${LOGGING_INCLUDE_DIRS})
++link_directories(${LOGGING_LIBRARY_DIRS})
++
++# phosphor-dbus-interfaces
++find_package(PkgConfig REQUIRED)
++pkg_check_modules(DBUSINTERFACE phosphor-dbus-interfaces REQUIRED)
++include_directories(${DBUSINTERFACE_INCLUDE_DIRS})
++link_directories(${DBUSINTERFACE_LIBRARY_DIRS})
++
++add_executable(${PROJECT_NAME} ${SRC_FILES})
++target_link_libraries(${PROJECT_NAME} ${DBUSINTERFACE_LIBRARIES} )
++target_link_libraries(${PROJECT_NAME} "${SDBUSPLUSPLUS_LIBRARIES} -lstdc++fs -lphosphor_dbus")
++
++install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
++install (FILES ${SERVICE_FILES} DESTINATION /lib/systemd/system/)
+\ No newline at end of file
+diff --git a/MAINTAINERS b/MAINTAINERS
+new file mode 100644
+index 0000000..de6cc54
+--- /dev/null
++++ b/MAINTAINERS
+@@ -0,0 +1,45 @@
++How to use this list:
++ Find the most specific section entry (described below) that matches where
++ your change lives and add the reviewers (R) and maintainers (M) as
++ reviewers. You can use the same method to track down who knows a particular
++ code base best.
++
++ Your change/query may span multiple entries; that is okay.
++
++ If you do not find an entry that describes your request at all, someone
++ forgot to update this list; please at least file an issue or send an email
++ to a maintainer, but preferably you should just update this document.
++
++Description of section entries:
++
++ Section entries are structured according to the following scheme:
++
++ X: NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!>
++ X: ...
++ .
++ .
++ .
++
++ Where REPO_NAME is the name of the repository within the OpenBMC GitHub
++ organization; FILE_PATH is a file path within the repository, possibly with
++ wildcards; X is a tag of one of the following types:
++
++ M: Denotes maintainer; has fields NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!>;
++ if omitted from an entry, assume one of the maintainers from the
++ MAINTAINERS entry.
++ R: Denotes reviewer; has fields NAME <EMAIL_USERNAME@DOMAIN> <IRC_USERNAME!>;
++ these people are to be added as reviewers for a change matching the repo
++ path.
++ F: Denotes forked from an external repository; has fields URL.
++
++ Line comments are to be denoted "# SOME COMMENT" (typical shell style
++ comment); it is important to follow the correct syntax and semantics as we
++ may want to use automated tools with this file in the future.
++
++ A change cannot be added to an OpenBMC repository without a MAINTAINER's
++ approval; thus, a MAINTAINER should always be listed as a reviewer.
++
++START OF MAINTAINERS LIST
++-------------------------
++
++M: Kuiying Wang <kuiying.wang@intel.com> <kuiyingw>
+\ No newline at end of file
+diff --git a/inc/post_code.hpp b/inc/post_code.hpp
+new file mode 100644
+index 0000000..84c8b3e
+--- /dev/null
++++ b/inc/post_code.hpp
+@@ -0,0 +1,152 @@
++/*
++// Copyright (c) 2019 Intel Corporation
++//
++// 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.
++*/
++#pragma once
++#include <fcntl.h>
++#include <unistd.h>
++#include <cereal/cereal.hpp>
++#include <experimental/filesystem>
++#include <cereal/access.hpp>
++#include <cereal/archives/json.hpp>
++#include <iostream>
++#include <fstream>
++#include <cereal/types/vector.hpp>
++
++#include <xyz/openbmc_project/State/Boot/PostCode/server.hpp>
++#include <xyz/openbmc_project/Common/error.hpp>
++#include <phosphor-logging/elog-errors.hpp>
++#include <xyz/openbmc_project/State/Host/server.hpp>
++
++#define MaxPostCodeCycles 100
++
++const static constexpr char *PostCodePath =
++ "/xyz/openbmc_project/state/boot/raw";
++const static constexpr char *PropertiesIntf =
++ "org.freedesktop.DBus.Properties";
++const static constexpr char *PostCodeListPath =
++ "/var/lib/phosphor-post-code-manager/";
++const static constexpr char *CurrentBootCycleIndexName =
++ "CurrentBootCycleIndex";
++const static constexpr char *HostStatePath =
++ "/xyz/openbmc_project/state/host0";
++
++
++struct EventDeleter
++{
++ void operator()(sd_event *event) const
++ {
++ event = sd_event_unref(event);
++ }
++};
++using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
++namespace fs = std::experimental::filesystem;
++namespace StateServer = sdbusplus::xyz::openbmc_project::State::server;
++
++using post_code =
++ sdbusplus::xyz::openbmc_project::State::Boot::server::PostCode;
++
++struct PostCode : sdbusplus::server::object_t<post_code>
++{
++ PostCode(sdbusplus::bus::bus& bus, const char* path,
++ EventPtr &event) :
++ sdbusplus::server::object_t<post_code>(bus, path),
++ bus(bus),
++ propertiesChangedSignalRaw(
++ bus,
++ sdbusplus::bus::match::rules::type::signal() +
++ sdbusplus::bus::match::rules::member("PropertiesChanged") +
++ sdbusplus::bus::match::rules::path(PostCodePath) +
++ sdbusplus::bus::match::rules::interface(PropertiesIntf),
++ [this](sdbusplus::message::message &msg) {
++ std::string objectName;
++ std::map<std::string, sdbusplus::message::variant<uint64_t>> msgData;
++ msg.read(objectName, msgData);
++ // Check if it was the Value property that changed.
++ auto valPropMap = msgData.find("Value");
++ {
++ if (valPropMap != msgData.end())
++ {
++ this->savePostCodes(sdbusplus::message::variant_ns::get<uint64_t>(valPropMap->second));
++ }
++ }
++ }),
++ propertiesChangedSignalCurrentHostState(
++ bus,
++ sdbusplus::bus::match::rules::type::signal() +
++ sdbusplus::bus::match::rules::member("PropertiesChanged") +
++ sdbusplus::bus::match::rules::path(HostStatePath) +
++ sdbusplus::bus::match::rules::interface(PropertiesIntf),
++ [this](sdbusplus::message::message &msg) {
++ std::string objectName;
++ std::map<std::string, sdbusplus::message::variant<std::string>> msgData;
++ msg.read(objectName, msgData);
++ // Check if it was the Value property that changed.
++ auto valPropMap = msgData.find("CurrentHostState");
++ {
++ if (valPropMap != msgData.end())
++ {
++ StateServer::Host::HostState currentHostState =
++ StateServer::Host::convertHostStateFromString(
++ sdbusplus::message::variant_ns::get<std::string>(valPropMap->second));
++ if (currentHostState == StateServer::Host::HostState::Off)
++ {
++ if (this->currentBootCycleIndex() >= this->maxBootCycleNum())
++ {
++ this->currentBootCycleIndex(1);
++ } else{
++ this->currentBootCycleIndex(this->currentBootCycleIndex() + 1);
++ }
++ this->postCodes.clear();
++ }
++ }
++ }
++ })
++ {
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "PostCode is created");
++ auto dir = fs::path(PostCodeListPath);
++ fs::create_directories(dir);
++ strPostCodeListPath = PostCodeListPath;
++ strCurrentBootCycleIndexName = CurrentBootCycleIndexName;
++ uint16_t index = 0;
++ deserialize(fs::path(strPostCodeListPath + strCurrentBootCycleIndexName), index);
++ currentBootCycleIndex(index);
++ maxBootCycleNum(MaxPostCodeCycles);
++ if (currentBootCycleIndex() >= maxBootCycleNum())
++ {
++ currentBootCycleIndex(1);
++ } else{
++ currentBootCycleIndex(currentBootCycleIndex() + 1);
++ }
++ }
++ ~PostCode()
++ {
++
++ }
++
++ std::vector<uint64_t> getPostCodes(uint16_t index) override;
++
++ private:
++ sdbusplus::bus::bus& bus;
++ std::vector<uint64_t> postCodes;
++ std::string strPostCodeListPath;
++ std::string strCurrentBootCycleIndexName;
++ void savePostCodes(uint64_t code);
++ sdbusplus::bus::match_t propertiesChangedSignalRaw;
++ sdbusplus::bus::match_t propertiesChangedSignalCurrentHostState;
++ fs::path serialize(const std::string& path);
++ bool deserialize(const fs::path& path, uint16_t& index);
++ bool deserializePostCodes(const fs::path& path, std::vector<uint64_t> &codes);
++};
+diff --git a/service_files/xyz.openbmc_project.State.Boot.PostCode.service b/service_files/xyz.openbmc_project.State.Boot.PostCode.service
+new file mode 100644
+index 0000000..67bc43f
+--- /dev/null
++++ b/service_files/xyz.openbmc_project.State.Boot.PostCode.service
+@@ -0,0 +1,11 @@
++[Unit]
++Description=Post code manager
++
++[Service]
++ExecStart=/usr/bin/env post-code-manager
++SyslogIdentifier=post-code-manager
++Type=dbus
++BusName=xyz.openbmc_project.State.Boot.PostCode
++
++[Install]
++WantedBy=obmc-standby.target
+diff --git a/src/main.cpp b/src/main.cpp
+new file mode 100644
+index 0000000..4a74b29
+--- /dev/null
++++ b/src/main.cpp
+@@ -0,0 +1,61 @@
++/*
++// Copyright (c) 2019 Intel Corporation
++//
++// 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.
++*/
++#include "post_code.hpp"
++
++int main(int argc, char* argv[])
++{
++ int ret = 0;
++
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "Start post code manager service...");
++
++ sd_event* event = nullptr;
++ ret = sd_event_default(&event);
++ if (ret < 0)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error creating a default sd_event handler");
++ return ret;
++ }
++ EventPtr eventP{event};
++ event = nullptr;
++
++ sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
++ sdbusplus::server::manager_t m{bus, DBUS_OBJECT_NAME};
++
++ bus.request_name(DBUS_INTF_NAME);
++
++ PostCode postCode{bus, DBUS_OBJECT_NAME, eventP};
++
++ try
++ {
++ bus.attach_event(eventP.get(), SD_EVENT_PRIORITY_NORMAL);
++ ret = sd_event_loop(eventP.get());
++ if (ret < 0)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error occurred during the sd_event_loop",
++ phosphor::logging::entry("RET=%d", ret));
++ }
++ }
++ catch (std::exception& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
++ return -1;
++ }
++ return 0;
++
++}
+diff --git a/src/post_code.cpp b/src/post_code.cpp
+new file mode 100644
+index 0000000..983eeee
+--- /dev/null
++++ b/src/post_code.cpp
+@@ -0,0 +1,109 @@
++/*
++// Copyright (c) 2019 Intel Corporation
++//
++// 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.
++*/
++#include "post_code.hpp"
++std::vector<uint64_t> PostCode::getPostCodes(uint16_t index)
++{
++ std::vector<uint64_t> codes;
++
++ if (currentBootCycleIndex() == index)
++ return postCodes;
++ deserializePostCodes(fs::path(strPostCodeListPath + std::to_string(index)), codes);
++ return codes;
++}
++void PostCode::savePostCodes(uint64_t code)
++{
++ postCodes.push_back(code);
++ serialize(fs::path(PostCodeListPath));
++ return;
++}
++
++fs::path PostCode::serialize(const std::string& path)
++{
++ try
++ {
++ uint16_t index = currentBootCycleIndex();
++ fs::path fullPath(path + strCurrentBootCycleIndexName);
++ std::ofstream os(fullPath.c_str(), std::ios::binary);
++ cereal::JSONOutputArchive oarchive(os);
++ oarchive(index);
++
++ std::ofstream osPostCodes((path + std::to_string(currentBootCycleIndex())).c_str(), std::ios::binary);
++ cereal::JSONOutputArchive oarchivePostCodes(osPostCodes);
++ oarchivePostCodes(postCodes);
++
++ return path;
++ }
++ catch (cereal::Exception& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
++ }
++ catch (const fs::filesystem_error& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
++ }
++}
++
++bool PostCode::deserialize(const fs::path& path, uint16_t& index)
++{
++ try
++ {
++ if (fs::exists(path))
++ {
++ std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
++ cereal::JSONInputArchive iarchive(is);
++ iarchive(index);
++ return true;
++ }
++ return false;
++ }
++ catch (cereal::Exception& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
++ return false;
++ }
++ catch (const fs::filesystem_error& e)
++ {
++ return false;
++ }
++
++ return false;
++}
++
++bool PostCode::deserializePostCodes(const fs::path& path, std::vector<uint64_t> &codes)
++{
++ try
++ {
++ if (fs::exists(path))
++ {
++ std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
++ cereal::JSONInputArchive iarchive(is);
++ iarchive(codes);
++ return true;
++ }
++ return false;
++ }
++ catch (cereal::Exception& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
++ return false;
++ }
++ catch (const fs::filesystem_error& e)
++ {
++ return false;
++ }
++
++ return false;
++}
+--
+2.19.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb
new file mode 100644
index 000000000..8f2ead18a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb
@@ -0,0 +1,34 @@
+SUMMARY = "Phosphor post code manager"
+DESCRIPTION = "Post Code Manager"
+
+SRC_URI = "git://github.com/openbmc/phosphor-post-code-manager.git"
+SRCREV = "7f50dcaa6feb66cf5307b8a0e4742a36a50eed29"
+
+S = "${WORKDIR}/git"
+
+PV = "1.0+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327"
+
+inherit cmake pkgconfig systemd
+
+SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.State.Boot.PostCode.service"
+
+DEPENDS += " \
+ autoconf-archive-native \
+ systemd \
+ sdbusplus \
+ sdbusplus-native \
+ phosphor-dbus-interfaces \
+ phosphor-dbus-interfaces-native \
+ phosphor-logging \
+ "
+RDEPENDS_${PN} += " \
+ libsystemd \
+ sdbusplus \
+ phosphor-dbus-interfaces \
+ phosphor-logging \
+ "
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+SRC_URI += "file://0001-Implement-post-code-manager.patch"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb
new file mode 100644
index 000000000..6d614590d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb
@@ -0,0 +1,19 @@
+SUMMARY = "Callback Manager"
+DESCRIPTION = "D-Bus daemon that registers matches that trigger method calls"
+
+SRC_URI = "git://git@github.com/Intel-BMC/provingground;protocol=ssh"
+
+inherit cmake systemd
+DEPENDS = "boost sdbusplus"
+
+PV = "0.1+git${SRCPV}"
+SRCREV = "f4d4bfc3296cb27feb17aa5d1d93b3061b56ce10"
+
+S = "${WORKDIR}/git/callback-manager"
+
+SYSTEMD_SERVICE_${PN} += "callback-manager.service"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENCE;md5=7becf906c8f8d03c237bad13bc3dac53"
+
+EXTRA_OECMAKE = "-DYOCTO=1"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch
new file mode 100644
index 000000000..5c2879d8f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch
@@ -0,0 +1,1648 @@
+From 726be648df955f5ae94f34391adc0e88f6956345 Mon Sep 17 00:00:00 2001
+From: Radivoje Jovanovic <radivoje.jovanovic@intel.com>
+Date: Mon, 2 Jul 2018 19:23:25 -0700
+Subject: [PATCH] Added suport for multiple user manager services
+
+Support added for SSSD service implementation
+
+Signed-off-by: Alberto Salazar Perez <alberto.salazar.perez@intel.com>
+Signed-off-by: Radivoje Jovanovic <radivoje.jovanovic@intel.com>
+Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
+---
+ Makefile.am | 5 +-
+ mainapp.cpp | 89 ++++++-
+ user_mgr.cpp | 293 +++------------------
+ user_mgr.hpp | 9 +-
+ user_service.cpp | 781 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ user_service.hpp | 233 +++++++++++++++++
+ 6 files changed, 1141 insertions(+), 269 deletions(-)
+ create mode 100644 user_service.cpp
+ create mode 100644 user_service.hpp
+
+diff --git a/Makefile.am b/Makefile.am
+index b138aea..288b780 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,11 +1,12 @@
+ sbin_PROGRAMS = phosphor-user-manager
+
+-noinst_HEADERS = user_mgr.hpp users.hpp
++noinst_HEADERS = user_mgr.hpp users.hpp user_service.hpp
+
+ phosphor_user_manager_SOURCES = \
+ mainapp.cpp \
+ user_mgr.cpp \
+- users.cpp
++ users.cpp \
++ user_service.cpp
+
+ phosphor_user_manager_LDFLAGS = $(SDBUSPLUS_LIBS) \
+ $(PHOSPHOR_DBUS_INTERFACES_LIBS) \
+diff --git a/mainapp.cpp b/mainapp.cpp
+index c9da030..03c406a 100644
+--- a/mainapp.cpp
++++ b/mainapp.cpp
+@@ -14,18 +14,105 @@
+ * limitations under the License.
+ */
+ #include <string>
++#include <iostream>
++#include <getopt.h>
+ #include "user_mgr.hpp"
++#include "user_service.hpp"
+ #include "config.h"
+
+ // D-Bus root for user manager
+ constexpr auto USER_MANAGER_ROOT = "/xyz/openbmc_project/user";
+
++void printUsage()
++{
++ std::string usage =
++ R"(Usage:
++ phosphor-user-manager [OPTIONS]
++
++Backend DBUS service for OpenBMC User Management.
++If no OPTIONS are specified, shadow file will be used.
++
++Options:
++ -s, --service={shadow|sssd}
++ Specify the authentication service to use:
++ 'shadow' will use the /etc/shadow file.
++ 'sssd' will use the sssd service domains.
++ -h, --help Displays this help message.
++)";
++ std::cerr << usage;
++}
++
++void parseArgs(int argc, char** argv,
++ phosphor::user::UserService::ServiceType& srvc)
++{
++ const std::string shortOpts{"s:h"};
++ const struct option longOpts[] = {{"service", 1, nullptr, 's'},
++ {"help", 0, nullptr, 'h'},
++ {nullptr, 0, nullptr, 0}};
++
++ while (true)
++ {
++ const auto opt =
++ getopt_long(argc, argv, shortOpts.c_str(), longOpts, nullptr);
++
++ if (opt == -1)
++ {
++ if (srvc == phosphor::user::UserService::ServiceType::none)
++ {
++ srvc = phosphor::user::UserService::ServiceType::shadow;
++ }
++ break;
++ }
++
++ switch (opt)
++ {
++ case 's':
++ {
++ std::string srvcStr{optarg};
++ if (!srvcStr.compare("shadow"))
++ {
++ srvc = phosphor::user::UserService::ServiceType::shadow;
++ }
++ else if (!srvcStr.compare("sssd"))
++ {
++ srvc = phosphor::user::UserService::ServiceType::sssd;
++ }
++ else
++ {
++ std::cerr << "Error. '" << srvcStr << "' is not a valid"
++ << " authentication service." << std::endl;
++ printUsage();
++ exit(1);
++ }
++ }
++ break;
++
++ case 'h':
++ {
++ printUsage();
++ exit(0);
++ }
++
++ default:
++ {
++ printUsage();
++ exit(1);
++ }
++ }
++ }
++}
++
+ int main(int argc, char** argv)
+ {
++ // Check command line options. Exit if error.
++ phosphor::user::UserService::ServiceType srvc =
++ phosphor::user::UserService::ServiceType::none;
++ parseArgs(argc, argv, srvc);
++
+ auto bus = sdbusplus::bus::new_default();
+ sdbusplus::server::manager::manager objManager(bus, USER_MANAGER_ROOT);
+
+- phosphor::user::UserMgr userMgr(bus, USER_MANAGER_ROOT);
++ phosphor::user::UserMgr userMgr(bus, USER_MANAGER_ROOT, srvc);
+
+ // Claim the bus now
+ bus.request_name(USER_MANAGER_BUSNAME);
+diff --git a/user_mgr.cpp b/user_mgr.cpp
+index 47edf7d..32f3f4c 100644
+--- a/user_mgr.cpp
++++ b/user_mgr.cpp
+@@ -14,26 +14,20 @@
+ // limitations under the License.
+ */
+
+-#include <shadow.h>
+-#include <unistd.h>
+-#include <sys/types.h>
+-#include <sys/wait.h>
++#include <cstdio>
++
+ #include <fstream>
+ #include <grp.h>
+ #include <pwd.h>
+ #include <regex>
+-#include <algorithm>
+-#include <numeric>
+-#include <boost/process/child.hpp>
+-#include <boost/process/io.hpp>
+ #include <boost/algorithm/string/split.hpp>
+ #include <xyz/openbmc_project/Common/error.hpp>
+ #include <xyz/openbmc_project/User/Common/error.hpp>
+ #include <phosphor-logging/log.hpp>
+ #include <phosphor-logging/elog.hpp>
+ #include <phosphor-logging/elog-errors.hpp>
++#include <stdexcept>
+ #include "shadowlock.hpp"
+-#include "file.hpp"
+ #include "user_mgr.hpp"
+ #include "users.hpp"
+ #include "config.h"
+@@ -43,12 +37,10 @@ namespace phosphor
+ namespace user
+ {
+
+-static constexpr const char *passwdFileName = "/etc/passwd";
+ static constexpr size_t ipmiMaxUsers = 15;
+ static constexpr size_t ipmiMaxUserNameLen = 16;
+ static constexpr size_t systemMaxUserNameLen = 30;
+ static constexpr size_t maxSystemUsers = 30;
+-static constexpr const char *grpSsh = "ssh";
+ static constexpr uint8_t minPasswdLength = 8;
+ static constexpr int success = 0;
+ static constexpr int failure = -1;
+@@ -94,79 +86,6 @@ using NoResource =
+
+ using Argument = xyz::openbmc_project::Common::InvalidArgument;
+
+-template <typename... ArgTypes>
+-static std::vector<std::string> executeCmd(const char *path,
+- ArgTypes &&... tArgs)
+-{
+- std::vector<std::string> stdOutput;
+- boost::process::ipstream stdOutStream;
+- boost::process::child execProg(path, const_cast<char *>(tArgs)...,
+- boost::process::std_out > stdOutStream);
+- std::string stdOutLine;
+-
+- while (stdOutStream && std::getline(stdOutStream, stdOutLine) &&
+- !stdOutLine.empty())
+- {
+- stdOutput.emplace_back(stdOutLine);
+- }
+-
+- execProg.wait();
+-
+- int retCode = execProg.exit_code();
+- if (retCode)
+- {
+- log<level::ERR>("Command execution failed", entry("PATH=%d", path),
+- entry("RETURN_CODE:%d", retCode));
+- elog<InternalFailure>();
+- }
+-
+- return stdOutput;
+-}
+-
+-static std::string getCSVFromVector(std::vector<std::string> vec)
+-{
+- switch (vec.size())
+- {
+- case 0:
+- {
+- return "";
+- }
+- break;
+-
+- case 1:
+- {
+- return std::string{vec[0]};
+- }
+- break;
+-
+- default:
+- {
+- return std::accumulate(
+- std::next(vec.begin()), vec.end(), vec[0],
+- [](std::string a, std::string b) { return a + ',' + b; });
+- }
+- }
+-}
+-
+-static bool removeStringFromCSV(std::string &csvStr, const std::string &delStr)
+-{
+- std::string::size_type delStrPos = csvStr.find(delStr);
+- if (delStrPos != std::string::npos)
+- {
+- // need to also delete the comma char
+- if (delStrPos == 0)
+- {
+- csvStr.erase(delStrPos, delStr.size() + 1);
+- }
+- else
+- {
+- csvStr.erase(delStrPos - 1, delStr.size() + 1);
+- }
+- return true;
+- }
+- return false;
+-}
+-
+ bool UserMgr::isUserExist(const std::string &userName)
+ {
+ if (userName.empty())
+@@ -293,39 +212,14 @@ void UserMgr::createUser(std::string userName,
+ {
+ throwForInvalidPrivilege(priv);
+ throwForInvalidGroups(groupNames);
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+ throwForUserExists(userName);
+ throwForUserNameConstraints(userName, groupNames);
+ throwForMaxGrpUserCount(groupNames);
+
+- std::string groups = getCSVFromVector(groupNames);
+- bool sshRequested = removeStringFromCSV(groups, grpSsh);
+-
+- // treat privilege as a group - This is to avoid using different file to
+- // store the same.
+- if (!priv.empty())
+- {
+- if (groups.size() != 0)
+- {
+- groups += ",";
+- }
+- groups += priv;
+- }
+- try
+- {
+- executeCmd("/usr/sbin/useradd", userName.c_str(), "-G", groups.c_str(),
+- "-m", "-N", "-s",
+- (sshRequested ? "/bin/sh" : "/bin/nologin"), "-e",
+- (enabled ? "" : "1970-01-02"));
+- }
+- catch (const InternalFailure &e)
+- {
+- log<level::ERR>("Unable to create new user");
+- elog<InternalFailure>();
+- }
++ // Tell the User Service to create a new user with the info provided.
++ userSrvc->createUser(userName, groupNames, priv, enabled);
+
+- // Add the users object before sending out the signal
++ // Add the users to the local list before sending out the signal
+ std::string userObj = std::string(usersObjPath) + "/" + userName;
+ std::sort(groupNames.begin(), groupNames.end());
+ usersList.emplace(
+@@ -339,19 +233,11 @@ void UserMgr::createUser(std::string userName,
+
+ void UserMgr::deleteUser(std::string userName)
+ {
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+ throwForUserDoesNotExist(userName);
+- try
+- {
+- executeCmd("/usr/sbin/userdel", userName.c_str(), "-r");
+- }
+- catch (const InternalFailure &e)
+- {
+- log<level::ERR>("User delete failed",
+- entry("USER_NAME=%s", userName.c_str()));
+- elog<InternalFailure>();
+- }
++
++ // Tell the User Service to delete user
++ userSrvc->deleteUser(userName);
++ // Then delete user from local list
+
+ usersList.erase(userName);
+
+@@ -362,24 +248,13 @@ void UserMgr::deleteUser(std::string userName)
+
+ void UserMgr::renameUser(std::string userName, std::string newUserName)
+ {
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+ throwForUserDoesNotExist(userName);
+ throwForUserExists(newUserName);
+ throwForUserNameConstraints(newUserName,
+ usersList[userName].get()->userGroups());
+- try
+- {
+- std::string newHomeDir = "/home/" + newUserName;
+- executeCmd("/usr/sbin/usermod", "-l", newUserName.c_str(),
+- userName.c_str(), "-d", newHomeDir.c_str(), "-m");
+- }
+- catch (const InternalFailure &e)
+- {
+- log<level::ERR>("User rename failed",
+- entry("USER_NAME=%s", userName.c_str()));
+- elog<InternalFailure>();
+- }
++ // Call The User Service to rename user on the system
++ userSrvc->renameUser(userName, newUserName);
++ // Update local list to reflect the name change
+ const auto &user = usersList[userName];
+ std::string priv = user.get()->userPrivilege();
+ std::vector<std::string> groupNames = user.get()->userGroups();
+@@ -403,8 +278,6 @@ void UserMgr::updateGroupsAndPriv(const std::string &userName,
+ {
+ throwForInvalidPrivilege(priv);
+ throwForInvalidGroups(groupNames);
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+ throwForUserDoesNotExist(userName);
+ const std::vector<std::string> &oldGroupNames =
+ usersList[userName].get()->userGroups();
+@@ -420,29 +293,8 @@ void UserMgr::updateGroupsAndPriv(const std::string &userName,
+ throwForMaxGrpUserCount(groupNames);
+ }
+
+- std::string groups = getCSVFromVector(groupNames);
+- bool sshRequested = removeStringFromCSV(groups, grpSsh);
+-
+- // treat privilege as a group - This is to avoid using different file to
+- // store the same.
+- if (!priv.empty())
+- {
+- if (groups.size() != 0)
+- {
+- groups += ",";
+- }
+- groups += priv;
+- }
+- try
+- {
+- executeCmd("/usr/sbin/usermod", userName.c_str(), "-G", groups.c_str(),
+- "-s", (sshRequested ? "/bin/sh" : "/bin/nologin"));
+- }
+- catch (const InternalFailure &e)
+- {
+- log<level::ERR>("Unable to modify user privilege / groups");
+- elog<InternalFailure>();
+- }
++ // Call The User Service to update user groups and priv on the system
++ userSrvc->updateGroupsAndPriv(userName, groupNames, priv);
+
+ log<level::INFO>("User groups / privilege updated successfully",
+ entry("USER_NAME=%s", userName.c_str()));
+@@ -638,19 +490,9 @@ int UserMgr::setPamModuleArgValue(const std::string &moduleName,
+
+ void UserMgr::userEnable(const std::string &userName, bool enabled)
+ {
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+ throwForUserDoesNotExist(userName);
+- try
+- {
+- executeCmd("/usr/sbin/usermod", userName.c_str(), "-e",
+- (enabled ? "" : "1970-01-02"));
+- }
+- catch (const InternalFailure &e)
+- {
+- log<level::ERR>("Unable to modify user enabled state");
+- elog<InternalFailure>();
+- }
++ // Call The User Service to update user groups and priv on the system
++ userSrvc->updateUserStatus(userName, enabled);
+
+ log<level::INFO>("User enabled/disabled state updated successfully",
+ entry("USER_NAME=%s", userName.c_str()),
+@@ -728,49 +570,8 @@ bool UserMgr::userLockedForFailedAttempt(const std::string &userName,
+
+ UserSSHLists UserMgr::getUserAndSshGrpList()
+ {
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+-
+- std::vector<std::string> userList;
+- std::vector<std::string> sshUsersList;
+- struct passwd pw, *pwp = nullptr;
+- std::array<char, 1024> buffer{};
+-
+- phosphor::user::File passwd(passwdFileName, "r");
+- if ((passwd)() == NULL)
+- {
+- log<level::ERR>("Error opening the passwd file");
+- elog<InternalFailure>();
+- }
+-
+- while (true)
+- {
+- auto r = fgetpwent_r((passwd)(), &pw, buffer.data(), buffer.max_size(),
+- &pwp);
+- if ((r != 0) || (pwp == NULL))
+- {
+- // Any error, break the loop.
+- break;
+- }
+- // Add all users whose UID >= 1000 and < 65534
+- // and special UID 0.
+- if ((pwp->pw_uid == 0) ||
+- ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534)))
+- {
+- std::string userName(pwp->pw_name);
+- userList.emplace_back(userName);
+-
+- // ssh doesn't have separate group. Check login shell entry to
+- // get all users list which are member of ssh group.
+- std::string loginShell(pwp->pw_shell);
+- if (loginShell == "/bin/sh")
+- {
+- sshUsersList.emplace_back(userName);
+- }
+- }
+- }
+- endpwent();
+- return std::make_pair(std::move(userList), std::move(sshUsersList));
++ // Call The User Service to get the User and SSUsers lists
++ return std::move(userSrvc->getUserAndSshGrpList());
+ }
+
+ size_t UserMgr::getIpmiUsersCount()
+@@ -781,49 +582,14 @@ size_t UserMgr::getIpmiUsersCount()
+
+ bool UserMgr::isUserEnabled(const std::string &userName)
+ {
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+- std::array<char, 4096> buffer{};
+- struct spwd spwd;
+- struct spwd *resultPtr = nullptr;
+- int status = getspnam_r(userName.c_str(), &spwd, buffer.data(),
+- buffer.max_size(), &resultPtr);
+- if (!status && (&spwd == resultPtr))
+- {
+- if (resultPtr->sp_expire >= 0)
+- {
+- return false; // user locked out
+- }
+- return true;
+- }
+- return false; // assume user is disabled for any error.
++ // Call The User Service to verify if user is enabled
++ return userSrvc->isUserEnabled(userName);
+ }
+
+ std::vector<std::string> UserMgr::getUsersInGroup(const std::string &groupName)
+ {
+- std::vector<std::string> usersInGroup;
+- // Should be more than enough to get the pwd structure.
+- std::array<char, 4096> buffer{};
+- struct group grp;
+- struct group *resultPtr = nullptr;
+-
+- int status = getgrnam_r(groupName.c_str(), &grp, buffer.data(),
+- buffer.max_size(), &resultPtr);
+-
+- if (!status && (&grp == resultPtr))
+- {
+- for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem))
+- {
+- usersInGroup.emplace_back(*(grp.gr_mem));
+- }
+- }
+- else
+- {
+- log<level::ERR>("Group not found",
+- entry("GROUP=%s", groupName.c_str()));
+- // Don't throw error, just return empty userList - fallback
+- }
+- return usersInGroup;
++ // Call The User Service to get the users that belong to a group
++ return std::move(userSrvc->getUsersInGroup(groupName));
+ }
+
+ DbusUserObj UserMgr::getPrivilegeMapperObject(void)
+@@ -1018,11 +784,9 @@ void UserMgr::initUserObjects(void)
+ {
+ // All user management lock has to be based on /etc/shadow
+ phosphor::user::shadow::Lock lock();
+- std::vector<std::string> userNameList;
+- std::vector<std::string> sshGrpUsersList;
+ UserSSHLists userSSHLists = getUserAndSshGrpList();
+- userNameList = std::move(userSSHLists.first);
+- sshGrpUsersList = std::move(userSSHLists.second);
++ std::vector<std::string> userNameList = std::move(userSSHLists.first);
++ std::vector<std::string> sshGrpUsersList = std::move(userSSHLists.second);
+
+ if (!userNameList.empty())
+ {
+@@ -1077,8 +841,10 @@ void UserMgr::initUserObjects(void)
+ }
+ }
+
+-UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path) :
+- UserMgrIface(bus, path), AccountPolicyIface(bus, path), bus(bus), path(path)
++UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path,
++ UserService::ServiceType srvc) :
++ UserMgrIface(bus, path),
++ AccountPolicyIface(bus, path), bus(bus), path(path)
+ {
+ UserMgrIface::allPrivileges(privMgr);
+ std::sort(groupsMgr.begin(), groupsMgr.end());
+@@ -1186,6 +952,7 @@ UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path) :
+ }
+ AccountPolicyIface::accountUnlockTimeout(value32);
+ }
++ userSrvc = std::make_unique<UserService>(srvc, groupsMgr, privMgr);
+ initUserObjects();
+ }
+
+diff --git a/user_mgr.hpp b/user_mgr.hpp
+index c78174d..9d9c842 100644
+--- a/user_mgr.hpp
++++ b/user_mgr.hpp
+@@ -21,6 +21,7 @@
+ #include <unordered_map>
+ #include <variant>
+ #include "users.hpp"
++#include "user_service.hpp"
+
+ namespace phosphor
+ {
+@@ -28,8 +29,6 @@ namespace user
+ {
+
+ using UserMgrIface = sdbusplus::xyz::openbmc_project::User::server::Manager;
+-using UserSSHLists =
+- std::pair<std::vector<std::string>, std::vector<std::string>>;
+ using AccountPolicyIface =
+ sdbusplus::xyz::openbmc_project::User::server::AccountPolicy;
+
+@@ -71,8 +70,10 @@ class UserMgr : public UserMgrIface, AccountPolicyIface
+ *
+ * @param[in] bus - sdbusplus handler
+ * @param[in] path - D-Bus path
++ * @param[in] srvc - User service to be used
+ */
+- UserMgr(sdbusplus::bus::bus &bus, const char *path);
++ UserMgr(sdbusplus::bus::bus &bus, const char *path,
++ UserService::ServiceType srvc);
+
+ /** @brief create user method.
+ * This method creates a new user as requested
+@@ -181,6 +182,8 @@ class UserMgr : public UserMgrIface, AccountPolicyIface
+ /** @brief object path */
+ const std::string path;
+
++ /** @brief user service to be used */
++ std::unique_ptr<UserService> userSrvc;
+ /** @brief privilege manager container */
+ std::vector<std::string> privMgr = {"priv-admin", "priv-operator",
+ "priv-user", "priv-callback"};
+diff --git a/user_service.cpp b/user_service.cpp
+new file mode 100644
+index 0000000..9bb602c
+--- /dev/null
++++ b/user_service.cpp
+@@ -0,0 +1,781 @@
++/*
++// Copyright (c) 2018 Intel Corporation
++//
++// 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.
++*/
++
++#include <grp.h>
++#include <pwd.h>
++#include <numeric>
++#include <boost/process/child.hpp>
++#include <boost/process/io.hpp>
++#include <boost/algorithm/string/split.hpp>
++#include "shadowlock.hpp"
++#include "file.hpp"
++#include "user_service.hpp"
++
++/* anonymous namespace for User Service interface implementations.
++// Each class inside this namespace implements a special service
++// to be used for the User Manager class. This can be extended to use
++// other user management services and it should be as simple as
++// adding a new class which inherits from phosphor::user::UserServiceInterface
++*/
++
++namespace
++{
++
++std::string getCSVFromVector(std::vector<std::string> vec)
++{
++ switch (vec.size())
++ {
++ case 0:
++ {
++ return "";
++ }
++ break;
++
++ case 1:
++ {
++ return std::string{vec[0]};
++ }
++ break;
++
++ default:
++ {
++ return std::accumulate(
++ std::next(vec.begin()), vec.end(), vec[0],
++ [](std::string a, std::string b) { return a + ',' + b; });
++ }
++ }
++}
++
++bool removeStringFromCSV(std::string &csvStr, const std::string &delStr)
++{
++ std::string::size_type delStrPos = csvStr.find(delStr);
++ if (delStrPos != std::string::npos)
++ {
++ // need to also delete the comma char
++ if (delStrPos == 0)
++ {
++ csvStr.erase(delStrPos, delStr.size() + 1);
++ }
++ else
++ {
++ csvStr.erase(delStrPos - 1, delStr.size() + 1);
++ }
++ return true;
++ }
++ return false;
++}
++
++class ShadowService : public phosphor::user::UserServiceInterface
++{
++ public:
++ ShadowService() = default;
++
++ ~ShadowService() = default;
++
++ phosphor::user::UserSSHLists getUserAndSshGrpList() const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ phosphor::user::shadow::Lock lock();
++
++ std::vector<std::string> userList;
++ std::vector<std::string> sshUsersList;
++
++ struct passwd pw, *pwp = nullptr;
++ std::array<char, 1024> buffer{};
++
++ phosphor::user::File passwd(passwdFileName, "r");
++ if ((passwd)() == NULL)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error opening the passwd file");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++
++ while (true)
++ {
++ auto r = fgetpwent_r((passwd)(), &pw, buffer.data(),
++ buffer.max_size(), &pwp);
++ if ((r != 0) || (pwp == NULL))
++ {
++ // Any error, break the loop.
++ break;
++ }
++ // Add all users whose UID >= 1000 and < 65534
++ // and special UID 0.
++ if ((pwp->pw_uid == 0) ||
++ ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534)))
++ {
++ std::string userName(pwp->pw_name);
++ userList.emplace_back(userName);
++
++ // ssh doesn't have separate group. Check login shell entry to
++ // get all users list which are member of ssh group.
++ std::string loginShell(pwp->pw_shell);
++ if (loginShell == "/bin/sh")
++ {
++ sshUsersList.emplace_back(userName);
++ }
++ }
++ }
++ endpwent();
++ return std::make_pair(std::move(userList), std::move(sshUsersList));
++ }
++
++ std::vector<std::string>
++ getUsersInGroup(const std::string &groupName) const override
++ {
++ std::vector<std::string> usersInGroup;
++ // Should be more than enough to get the pwd structure.
++ std::array<char, 4096> buffer{};
++ struct group grp;
++ struct group *grpPtr = &grp;
++ struct group *resultPtr;
++
++ int status = getgrnam_r(groupName.c_str(), grpPtr, buffer.data(),
++ buffer.max_size(), &resultPtr);
++
++ if (!status && (grpPtr == resultPtr))
++ {
++ for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem))
++ {
++ usersInGroup.emplace_back(*(grp.gr_mem));
++ }
++ }
++ else
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Group not found",
++ phosphor::logging::entry("GROUP=%s", groupName.c_str()));
++ // Don't throw error, just return empty usersInGroup - fallback
++ }
++ return usersInGroup;
++ }
++
++ void createUser(const std::string &userName,
++ const std::vector<std::string> &groupNames,
++ const std::string &priv, const bool &enabled) const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ phosphor::user::shadow::Lock lock();
++
++ std::string groups = getCSVFromVector(groupNames);
++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh);
++
++ // treat privilege as a group - This is to avoid using different file to
++ // store the same
++ if (!priv.empty())
++ {
++ if (groups.size() != 0)
++ {
++ groups.append(",");
++ }
++ groups.append(priv);
++ }
++
++ try
++ {
++ phosphor::user::executeCmd(
++ "/usr/sbin/useradd", userName.c_str(), "-G", groups.c_str(),
++ "-m", "-N", "-s", (sshRequested ? "/bin/sh" : "/bin/nologin"),
++ "-e", (enabled ? "" : "1970-01-02"));
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to create new user");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ void renameUser(const std::string &userName,
++ const std::string &newUserName) const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ phosphor::user::shadow::Lock lock();
++ try
++ {
++ std::string newHomeDir = "/home/" + newUserName;
++ phosphor::user::executeCmd("/usr/sbin/usermod", "-l",
++ newUserName.c_str(), userName.c_str(),
++ "-d", newHomeDir.c_str(), "-m");
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "User rename failed",
++ phosphor::logging::entry("USER_NAME=%s", userName.c_str()));
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ void deleteUser(const std::string &userName) const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ phosphor::user::shadow::Lock lock();
++
++ try
++ {
++ phosphor::user::executeCmd("/usr/sbin/userdel", userName.c_str(),
++ "-r");
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "User delete failed",
++ phosphor::logging::entry("USER_NAME=%s", userName.c_str()));
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ void updateGroupsAndPriv(const std::string &userName,
++ const std::vector<std::string> &groupNames,
++ const std::string &priv) const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ phosphor::user::shadow::Lock lock();
++
++ std::string groups = getCSVFromVector(groupNames);
++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh);
++
++ // treat privilege as a group - This is to avoid using different file to
++ // store the same.
++ if (!priv.empty())
++ {
++ if (groups.size() != 0)
++ {
++ groups += ",";
++ }
++ groups += priv;
++ }
++
++ try
++ {
++ phosphor::user::executeCmd(
++ "/usr/sbin/usermod", userName.c_str(), "-G", groups.c_str(),
++ "-s", (sshRequested ? "/bin/sh" : "/bin/nologin"));
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to modify user privilege / groups");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ void updateUserStatus(const std::string &userName,
++ const bool &enabled) const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ phosphor::user::shadow::Lock lock();
++ try
++ {
++ phosphor::user::executeCmd("/usr/sbin/usermod", userName.c_str(),
++ "-e", (enabled ? "" : "1970-01-02"));
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to modify user enabled state");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ bool isUserEnabled(const std::string &userName) const override
++ {
++ // All user management lock has to be based on /etc/shadow
++ phosphor::user::shadow::Lock lock();
++ std::array<char, 4096> buffer{};
++ struct spwd spwd;
++ struct spwd *resultPtr = nullptr;
++ int status = getspnam_r(userName.c_str(), &spwd, buffer.data(),
++ buffer.max_size(), &resultPtr);
++ if (!status && (&spwd == resultPtr))
++ {
++ if (resultPtr->sp_expire >= 0)
++ {
++ return false; // user locked out
++ }
++ return true;
++ }
++ return false; // assume user is disabled for any error.
++ }
++
++ std::vector<std::string>
++ getUserGroups(const std::string &userName) const override
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "ShadowService::getUserGroups not implemented!");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ return std::vector<std::string>();
++ }
++
++ void createGroup(const std::string &groupName) const override
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "ShadowService::createGroup not implemented!");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++
++ private:
++ static constexpr const char *passwdFileName = "/etc/passwd";
++};
++
++class SSSDService : public phosphor::user::UserServiceInterface
++{
++ public:
++ SSSDService(const std::vector<std::string> &groups,
++ const std::vector<std::string> &privs)
++ {
++
++ createGroup(lockedGrp);
++ for (const auto &g : groups)
++ {
++ createGroup(g);
++ }
++ for (const auto &p : privs)
++ {
++ createGroup(p);
++ }
++ }
++
++ ~SSSDService() = default;
++
++ phosphor::user::UserSSHLists getUserAndSshGrpList() const override
++ {
++ std::vector<std::string> users;
++ std::vector<std::string> sshGroup;
++ std::vector<std::string> exeOutput;
++
++ try
++ {
++ exeOutput = phosphor::user::executeCmd("/usr/bin/getent", "-s",
++ "sss", "passwd");
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to get users information "
++ "from sssd service");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++
++ for (const auto &userLine : exeOutput)
++ {
++ std::vector<std::string> userInfo;
++ boost::algorithm::split(userInfo, userLine,
++ boost::algorithm::is_any_of(":"));
++ // At this point userInfo is a vector containing the passwd
++ // info for the user, so we know the correct positions:
++ // 0: User name.
++ // 1: Encrypted password.
++ // 2: User ID number (UID)
++ // 3: User's group ID number (GID)
++ // 4: Full name of the user (GECOS)
++ // 5: User home directory.
++ // 6: Login shell.
++ users.emplace_back(userInfo[0]);
++
++ // ssh doesn't have separate group. Check login shell entry to
++ // get all users list which are member of ssh group.
++ if (userInfo[6] == "/bin/sh")
++ {
++ sshGroup.emplace_back(userInfo[0]);
++ }
++ }
++
++ return std::make_pair(std::move(users), std::move(sshGroup));
++ }
++
++ std::vector<std::string>
++ getUsersInGroup(const std::string &groupName) const override
++ {
++ std::vector<std::string> userList;
++ std::vector<std::string> exeOutput;
++
++ try
++ {
++ exeOutput = phosphor::user::executeCmd("/usr/sbin/sss_groupshow",
++ groupName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to get group users from sssd service");
++ // Don't throw error, just return empty usersInGroup - return
++ return userList;
++ }
++ // exeOutput should have 5 entries
++ // 0: Group
++ // 1: GID number
++ // 2: Member users
++ // 3: Is a member of
++ // 4: Member groups
++ exeOutput[2].erase(
++ exeOutput[2].begin(),
++ std::find(exeOutput[2].begin(), exeOutput[2].end(), ':'));
++ boost::algorithm::trim_left(exeOutput[2]);
++ boost::algorithm::split(userList, exeOutput[2],
++ boost::algorithm::is_any_of(","));
++ return userList;
++ }
++
++ void createUser(const std::string &userName,
++ const std::vector<std::string> &groupNames,
++ const std::string &priv, const bool &enabled) const override
++ {
++ std::string groups = getCSVFromVector(groupNames);
++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh);
++ // treat privilege as a group - This is to avoid using different file to
++ // store the same
++ if (!priv.empty())
++ {
++ if (groups.size() != 0)
++ {
++ groups += ",";
++ }
++ groups += priv;
++ }
++
++ try
++ {
++ phosphor::user::executeCmd(
++ "/usr/sbin/sss_useradd", "-m", "-G", groups.c_str(), "-s",
++ (sshRequested ? "/bin/sh" : "/bin/nologin"), userName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to create new user in sssd service");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++
++ // Sometimes the SSSD service needs some time to actually
++ // reflect the changes to the local DB to the NSS service,
++ // that is why we have this sleep here ...
++ std::this_thread::sleep_for(std::chrono::seconds(1));
++ // update user status (locked/unlocked)
++ updateUserStatus(userName, enabled);
++ }
++
++ void renameUser(const std::string &userName,
++ const std::string &newUserName) const override
++ {
++ std::vector<std::string> exeOutput;
++ // Local Domain for sssd doesn't have a rename feature
++ // so we need to first create a new user and then delete
++ // the old one.
++ // The only issue with this is that the password for the
++ // user will have to be reseted since it is a new user being created.
++
++ // Get original user groups
++ std::vector<std::string> groups = getUserGroups(userName);
++ // Check if it has a "ssh" group by looking for the shell login
++ try
++ {
++ exeOutput = phosphor::user::executeCmd(
++ "/usr/bin/getent", "-s", "sss", "passwd", userName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to get information for user");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ if (exeOutput[0].find("/bin/sh"))
++ {
++ groups.emplace_back(phosphor::user::grpSsh);
++ }
++ // Call create user with the new user names and previous groups
++ // Priv is already part of the groups so that can be empty.
++ createUser(newUserName, groups, "", isUserEnabled(userName));
++
++ // Now delete original user
++ deleteUser(userName);
++ }
++
++ void deleteUser(const std::string &userName) const override
++ {
++ try
++ {
++ phosphor::user::executeCmd("/usr/sbin/sss_userdel", "-r",
++ userName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to delete user from sssd service");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ void updateGroupsAndPriv(const std::string &userName,
++ const std::vector<std::string> &groupNames,
++ const std::string &priv) const override
++ {
++ // local domain sssd do not allow to update all list of groups,
++ // so we will remove all groups first (except for the user one)
++ // and then all all the ones that were passed
++ std::string oldGroups = getCSVFromVector(getUserGroups(userName));
++ std::string groups = getCSVFromVector(groupNames);
++ bool sshRequested = removeStringFromCSV(groups, phosphor::user::grpSsh);
++ // treat privilege as a group - This is to avoid using different file to
++ // store the same
++ if (!priv.empty())
++ {
++ if (groups.size() != 0)
++ {
++ groups += ",";
++ }
++ groups += priv;
++ }
++ try
++ {
++ phosphor::user::executeCmd(
++ "/usr/sbin/sss_usermod", "-r", oldGroups.c_str(), "-a",
++ groups.c_str(), "-s",
++ (sshRequested ? "/bin/sh" : "/bin/nologin"), userName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to update user groups and "
++ "priv from sssd service");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ void updateUserStatus(const std::string &userName,
++ const bool &enabled) const override
++ {
++ std::string enabledStr;
++ std::string lockedStr;
++ if (isUserEnabled(userName) == enabled)
++ {
++ return;
++ }
++ if (enabled)
++ {
++ enabledStr = "-r";
++ lockedStr = "-U";
++ }
++ else
++ {
++ enabledStr = "-a";
++ lockedStr = "-L";
++ }
++ try
++ {
++ // We will add a special locked group to identify the users
++ // that have been locked out of the system.
++ // TODO: sss_usermod is not locking user accounts for the
++ // LOCAL domain, need to find the correct PAM configuration
++ // to actually lockout users for SSSD.
++ // As a workaround we are using the pam module pam_listfile.so
++ // to lockout all users that belong to the locked group.
++ phosphor::user::executeCmd("/usr/sbin/sss_usermod",
++ enabledStr.c_str(), lockedGrp.c_str(),
++ lockedStr.c_str(), userName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to update user status from sssd service");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ bool isUserEnabled(const std::string &userName) const override
++ {
++ std::vector<std::string> userGrps = getUserGroups(userName);
++ return std::find(userGrps.begin(), userGrps.end(), lockedGrp) ==
++ userGrps.end();
++ }
++
++ std::vector<std::string>
++ getUserGroups(const std::string &userName) const override
++ {
++ std::vector<std::string> exeOutput;
++ try
++ {
++ exeOutput =
++ phosphor::user::executeCmd("/usr/bin/groups", userName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to get groups for user");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++
++ std::vector<std::string> groups;
++ boost::algorithm::split(groups, exeOutput[0],
++ boost::algorithm::is_any_of(" "));
++ // Delete group that equals user name if it exists
++ auto userNameGroup = std::find(groups.begin(), groups.end(), userName);
++ if (userNameGroup != groups.end())
++ {
++ groups.erase(userNameGroup);
++ }
++ return groups;
++ }
++
++ void createGroup(const std::string &groupName) const override
++ {
++ try
++ {
++ if (!groupExists(groupName))
++ {
++ phosphor::user::executeCmd("/usr/sbin/sss_groupadd",
++ groupName.c_str());
++ }
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to create group");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ }
++
++ private:
++ static const std::string lockedGrp;
++
++ bool groupExists(const std::string &groupName) const
++ {
++ try
++ {
++ phosphor::user::executeCmd("/usr/sbin/sss_groupshow",
++ groupName.c_str());
++ }
++ catch (const phosphor::user::InternalFailure &e)
++ {
++ return false;
++ }
++ return true;
++ }
++};
++
++const std::string SSSDService::lockedGrp = "sssd_locked";
++} // anonymous namespace
++
++namespace phosphor
++{
++namespace user
++{
++
++UserService::UserService(const ServiceType &srvcType,
++ const std::vector<std::string> &groups,
++ const std::vector<std::string> &privs)
++{
++ setServiceImpl(srvcType, groups, privs);
++}
++
++void UserService::updateServiceType(const ServiceType &srvcType,
++ const std::vector<std::string> &groups,
++ const std::vector<std::string> &privs)
++{
++ usrSrvcImpl.reset();
++ setServiceImpl(srvcType, groups, privs);
++}
++
++void UserService::setServiceImpl(const ServiceType &srvcType,
++ const std::vector<std::string> &groups,
++ const std::vector<std::string> &privs)
++{
++ switch (srvcType)
++ {
++ case ServiceType::shadow:
++ {
++ usrSrvcImpl = std::make_unique<ShadowService>();
++ }
++ break;
++
++ case ServiceType::sssd:
++ {
++ usrSrvcImpl = std::make_unique<SSSDService>(groups, privs);
++ }
++ break;
++
++ case ServiceType::none:
++ default:
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Invalid service type initialization!");
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++ break;
++ }
++}
++
++UserService::~UserService()
++{
++}
++
++phosphor::user::UserSSHLists UserService::getUserAndSshGrpList() const
++{
++ return usrSrvcImpl->getUserAndSshGrpList();
++}
++
++std::vector<std::string>
++ UserService::getUsersInGroup(const std::string &groupName) const
++{
++ return usrSrvcImpl->getUsersInGroup(groupName);
++}
++
++void UserService::createUser(const std::string &userName,
++ const std::vector<std::string> &groupNames,
++ const std::string &priv, const bool &enabled) const
++{
++ usrSrvcImpl->createUser(userName, groupNames, priv, enabled);
++}
++
++void UserService::renameUser(const std::string &userName,
++ const std::string &newUserName) const
++{
++ usrSrvcImpl->renameUser(userName, newUserName);
++}
++
++void UserService::deleteUser(const std::string &userName) const
++{
++ usrSrvcImpl->deleteUser(userName);
++}
++
++void UserService::updateGroupsAndPriv(
++ const std::string &userName, const std::vector<std::string> &groupNames,
++ const std::string &priv) const
++{
++ usrSrvcImpl->updateGroupsAndPriv(userName, groupNames, priv);
++}
++
++void UserService::updateUserStatus(const std::string &userName,
++ const bool &enabled) const
++{
++ usrSrvcImpl->updateUserStatus(userName, enabled);
++}
++
++bool UserService::isUserEnabled(const std::string &userName) const
++{
++ return usrSrvcImpl->isUserEnabled(userName);
++}
++
++std::vector<std::string>
++ UserService::getUserGroups(const std::string &userName) const
++{
++ return usrSrvcImpl->getUserGroups(userName);
++}
++
++} // namespace user
++} // namespace phosphor
+diff --git a/user_service.hpp b/user_service.hpp
+new file mode 100644
+index 0000000..97a049b
+--- /dev/null
++++ b/user_service.hpp
+@@ -0,0 +1,233 @@
++/*
++// Copyright (c) 2018 Intel Corporation
++//
++// 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.
++*/
++
++#pragma once
++#include <xyz/openbmc_project/Common/error.hpp>
++#include <xyz/openbmc_project/User/Common/error.hpp>
++#include <phosphor-logging/log.hpp>
++#include <phosphor-logging/elog.hpp>
++#include <boost/process/child.hpp>
++#include <boost/process/io.hpp>
++
++namespace phosphor
++{
++namespace user
++{
++
++using UserSSHLists =
++ std::pair<std::vector<std::string>, std::vector<std::string>>;
++using InternalFailure =
++ sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
++using InsufficientPermission =
++ sdbusplus::xyz::openbmc_project::Common::Error::InsufficientPermission;
++
++const std::string grpSsh = "ssh";
++
++template <typename... ArgTypes>
++std::vector<std::string> executeCmd(const char *path, ArgTypes &&... tArgs)
++{
++ std::vector<std::string> stdOutput;
++ boost::process::ipstream stdOutStream;
++ boost::process::child execProg(path, const_cast<char *>(tArgs)...,
++ boost::process::std_out > stdOutStream);
++ std::string stdOutLine;
++
++ while (stdOutStream && std::getline(stdOutStream, stdOutLine) &&
++ !stdOutLine.empty())
++ {
++ stdOutput.emplace_back(stdOutLine);
++ }
++
++ execProg.wait();
++
++ int retCode = execProg.exit_code();
++ if (retCode)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Command execution failed",
++ phosphor::logging::entry("PATH=%d", path),
++ phosphor::logging::entry("RETURN_CODE:%d", retCode));
++ phosphor::logging::elog<phosphor::user::InternalFailure>();
++ }
++
++ return stdOutput;
++}
++
++/** @class UserServiceInterface
++ * @brief Interface class for methods provided by the implemmentations
++ * of the user service. Provides the same methods as the UserService
++ * class.
++ */
++class UserServiceInterface
++{
++ public:
++ UserServiceInterface() = default;
++ virtual ~UserServiceInterface() = default;
++ virtual UserSSHLists getUserAndSshGrpList() const = 0;
++ virtual std::vector<std::string>
++ getUsersInGroup(const std::string &groupName) const = 0;
++ virtual void createUser(const std::string &userName,
++ const std::vector<std::string> &groupNames,
++ const std::string &priv,
++ const bool &enabled) const = 0;
++ virtual void renameUser(const std::string &userName,
++ const std::string &newUserName) const = 0;
++ virtual void deleteUser(const std::string &userName) const = 0;
++ virtual void updateGroupsAndPriv(const std::string &userName,
++ const std::vector<std::string> &groupNames,
++ const std::string &priv) const = 0;
++ virtual void updateUserStatus(const std::string &userName,
++ const bool &enabled) const = 0;
++ virtual bool isUserEnabled(const std::string &userName) const = 0;
++ virtual std::vector<std::string>
++ getUserGroups(const std::string &userName) const = 0;
++ virtual void createGroup(const std::string &groupName) const = 0;
++};
++
++/** @class UserService
++ * @brief Responsible for managing the user service for the user manager.
++ * This service is the one responsible to actually change the user information
++ * of the application. It can support sevaral services, currently the ones
++ * supported are:
++ *
++ * 1) Shadow: Which uses the /etc/shadow file for updating the users
++ * 2) SSSD: Which uses the sssd service for a LOCAL domain only right now.
++ */
++class UserService
++{
++ public:
++ UserService() = delete;
++ UserService(const UserService &) = delete;
++ UserService &operator=(const UserService &) = delete;
++ UserService(UserService &&) = delete;
++ UserService &operator=(UserService &&) = delete;
++
++ // Service Types implemented. None is used to validate.
++ enum class ServiceType
++ {
++ none,
++ shadow,
++ sssd
++ };
++
++ UserService(const ServiceType &srvcType,
++ const std::vector<std::string> &groups,
++ const std::vector<std::string> &privs);
++ ~UserService();
++
++ /** @brief update the current Service type of the instance.
++ * This function is used to update in real time the service
++ * being used for the user management without restarting the
++ * whole service.
++ *
++ * @param[in] srvcType
++ * @param[in] groups
++ * @param[in] privs
++ */
++ void updateServiceType(const ServiceType &srvcType,
++ const std::vector<std::string> &groups,
++ const std::vector<std::string> &privs);
++
++ /** @brief get user list and SSH group members list
++ * This method gets the list of users from the service.
++ * If the userlist reference is empty, all the users will be added
++ * and DBus notified about them. If the list is not empty, the function
++ * will only update list adding the missing ones to it. It will not remove
++ * any extra users on the list that are not part of the service!
++ *
++ */
++ UserSSHLists getUserAndSshGrpList() const;
++
++ /** @brief Get users in group.
++ * This method creates a new user as requested
++ *
++ * @param[in] groupName - Name of the group which has to be queried
++ */
++ std::vector<std::string>
++ getUsersInGroup(const std::string &groupName) const;
++
++ /** @brief create user method.
++ * This method creates a new user as requested
++ *
++ * @param[in] userName - Name of the user which has to be created
++ * @param[in] groupNames - Group names list, to which user has to be added.
++ * @param[in] priv - Privilege of the user.
++ * @param[in] enabled - State of the user enabled / disabled.
++ */
++ void createUser(const std::string &userName,
++ const std::vector<std::string> &groupNames,
++ const std::string &priv, const bool &enabled) const;
++
++ /** @brief rename user method.
++ * This method renames the user as requested
++ *
++ * @param[in] userName - current name of the user
++ * @param[in] userName - user name to which it has to be renamed.
++ */
++ void renameUser(const std::string &userName,
++ const std::string &newUserName) const;
++
++ /** @brief delete user method.
++ * This method deletes the user as requested
++ *
++ * @param[in] userName - Name of the user which has to be deleted
++ */
++ void deleteUser(const std::string &userName) const;
++
++ /** @brief Updates user Groups and Privilege.
++ *
++ * @param[in] userName - Name of the user which has to be modified
++ * @param[in] groupNames - Group names list for user.
++ * @param[in] priv - Privilege of the user.
++ */
++ void updateGroupsAndPriv(const std::string &userName,
++ const std::vector<std::string> &groupNames,
++ const std::string &priv) const;
++
++ /** @brief Updates user status
++ * If enabled = false: User will be disabled
++ * If enabled = true : User will be enabled
++ *
++ * @param[in] userName - Name of the user
++ * @param[in] enabled - Status of the user: enabled / disabled?
++ */
++ void updateUserStatus(const std::string &userName,
++ const bool &enabled) const;
++
++ /** @brief Verify if user is enabled or not
++ * If enabled returns true
++ * If not enabled returns false
++ *
++ * @param[in] userName - Name of the user
++ */
++ bool isUserEnabled(const std::string &userName) const;
++
++ /** @brief Get the list of groups a user belongs to
++ *
++ * @param[in] userName - Name of the user
++ */
++ std::vector<std::string> getUserGroups(const std::string &userName) const;
++
++ private:
++ // User service implementation.
++ void setServiceImpl(const ServiceType &srvcType,
++ const std::vector<std::string> &groups,
++ const std::vector<std::string> &privs);
++ std::unique_ptr<UserServiceInterface> usrSrvcImpl;
++};
++
++} // namespace user
++} // namespace phosphor
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend
new file mode 100644
index 000000000..1939e5ad2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend
@@ -0,0 +1,9 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+#SRC_URI = "git://github.com/openbmc/phosphor-user-manager"
+SRCREV = "736648e25eb250d1e200cea961fe75bf791f1355"
+
+
+SRC_URI += " \
+ file://0005-Added-suport-for-multiple-user-manager-services.patch \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb
new file mode 100644
index 000000000..950f4932d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb
@@ -0,0 +1,35 @@
+
+SUMMARY = "FRB2 timer service"
+DESCRIPTION = "The FRB2 timer service will monitor the mailbox register 0\
+and start a watchdog for FRB2 if the data is 1(BIOS will write this value)"
+
+SRC_URI = "\
+ file://CMakeLists.txt \
+ file://frb2-watchdog.cpp \
+ "
+PV = "0.1"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${PHOSPHORBASE}/LICENSE;md5=19407077e42b1ba3d653da313f1f5b4e"
+
+S = "${WORKDIR}"
+
+inherit cmake
+inherit pkgconfig pythonnative
+
+DEPENDS += " \
+ systemd \
+ sdbusplus \
+ sdbusplus-native \
+ phosphor-logging \
+ phosphor-dbus-interfaces \
+ phosphor-dbus-interfaces-native \
+ boost \
+ "
+
+RDEPENDS_${PN} += " \
+ libsystemd \
+ sdbusplus \
+ phosphor-logging \
+ phosphor-dbus-interfaces \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format
new file mode 100644
index 000000000..dd2770837
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format
@@ -0,0 +1,98 @@
+---
+Language: Cpp
+# BasedOnStyle: LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: true
+ AfterControlStatement: true
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: true
+ AfterObjCDeclaration: true
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: true
+ BeforeElse: true
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: AfterColon
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: true
+PointerAlignment: Left
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeBlocks: Regroup
+IncludeCategories:
+ - Regex: '^[<"](gtest|gmock)'
+ Priority: 5
+ - Regex: '^"config.h"'
+ Priority: -1
+ - Regex: '^".*\.hpp"'
+ Priority: 1
+ - Regex: '^<.*\.h>'
+ Priority: 2
+ - Regex: '^<.*'
+ Priority: 3
+ - Regex: '.*'
+ Priority: 4
+IndentCaseLabels: true
+IndentWidth: 4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Right
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 4
+UseTab: Never
+...
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt
new file mode 100644
index 000000000..bd5567d31
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt
@@ -0,0 +1,52 @@
+cmake_minimum_required (VERSION 3.5 FATAL_ERROR)
+project (frb2-watchdog CXX)
+set (CMAKE_CXX_STANDARD 17)
+set (CMAKE_CXX_STANDARD_REQUIRED ON)
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
+set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti")
+
+include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+
+# boost support
+find_package (Boost REQUIRED)
+# pkg_check_modules(Boost boost REQUIRED)
+include_directories (${Boost_INCLUDE_DIRS})
+add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY)
+add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED)
+add_definitions (-DBOOST_ALL_NO_LIB)
+add_definitions (-DBOOST_NO_RTTI)
+add_definitions (-DBOOST_NO_TYPEID)
+add_definitions (-DBOOST_ASIO_DISABLE_THREADS)
+
+# import libsystemd
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (SYSTEMD libsystemd REQUIRED)
+include_directories (${SYSTEMD_INCLUDE_DIRS})
+link_directories (${SYSTEMD_LIBRARY_DIRS})
+
+# import sdbusplus
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED)
+include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS})
+link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS})
+
+# import phosphor-logging
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (LOGGING phosphor-logging REQUIRED)
+include_directories (${LOGGING_INCLUDE_DIRS})
+link_directories (${LOGGING_LIBRARY_DIRS})
+
+# import phosphor-dbus-interfaces
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (DBUSINTERFACE phosphor-dbus-interfaces REQUIRED)
+include_directories (${DBUSINTERFACE_INCLUDE_DIRS})
+link_directories (${DBUSINTERFACE_LIBRARY_DIRS})
+
+add_executable (frb2-watchdog frb2-watchdog.cpp)
+
+target_link_libraries (${PROJECT_NAME} systemd)
+target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})
+target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES})
+target_link_libraries (${PROJECT_NAME} ${DBUSINTERFACE_LIBRARIES}
+ phosphor_logging)
+install (TARGETS frb2-watchdog DESTINATION bin)
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json
new file mode 100644
index 000000000..583c255a3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json
@@ -0,0 +1,12 @@
+{
+ "enum_char": ".",
+ "line_ending": "unix",
+ "bullet_char": "*",
+ "max_subargs_per_line": 99,
+ "command_case": "lower",
+ "tab_size": 4,
+ "line_width": 80,
+ "separate_fn_name_with_space": true,
+ "dangle_parens": true,
+ "separate_ctrl_name_with_space": true
+} \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp
new file mode 100644
index 000000000..5356e95db
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp
@@ -0,0 +1,258 @@
+/* Copyright 2018 Intel
+ *
+ * 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.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <boost/container/flat_set.hpp>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <iostream>
+#include <memory>
+#include <optional>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/bus/match.hpp>
+#include <sdbusplus/message.hpp>
+#include <sdbusplus/timer.hpp>
+#include <vector>
+#include <xyz/openbmc_project/State/Watchdog/server.hpp>
+
+void handleResponse(const boost::system::error_code &err,
+ std::size_t bytes_transferred);
+
+static int mailboxDevFd = -1;
+
+static boost::asio::io_service io;
+static auto conn = std::make_shared<sdbusplus::asio::connection>(io);
+boost::asio::ip::tcp::socket mailBoxDevSocket(io);
+boost::asio::deadline_timer pollTimer(io);
+boost::asio::posix::stream_descriptor inputDevice(io);
+
+// mailbox registre data[0:0] for FRB2 enable bit
+boost::asio::streambuf readBuf(1);
+std::string dataRead;
+
+// FRB2 watchdog timeout is 6 minutes
+static constexpr unsigned int frb2TimerIntervalMs = 360 * 1000;
+
+// mailbox device polling time interval is 2 seconds
+static constexpr unsigned int pollMs = 2000;
+
+static constexpr unsigned int frb2Started = 1;
+static constexpr unsigned int frb2Stopped = 0;
+
+// FRB2 status
+static uint8_t frb2Status = frb2Stopped;
+
+static constexpr const char *mailboxDevName = "/dev/aspeed-mbox";
+
+static constexpr const char frb2Bus[] = "xyz.openbmc_project.FRB2";
+static constexpr const char frb2Obj[] = "/xyz/openbmc_project/FRB2";
+static constexpr const char frb2Intf[] = "xyz.openbmc_project.FRB2";
+
+static constexpr char powerBus[] = "xyz.openbmc_project.Chassis.Control.Power";
+static constexpr char powerPath[] =
+ "/xyz/openbmc_project/Chassis/Control/Power0";
+static constexpr char powerIntf[] = "xyz.openbmc_project.Chassis.Control.Power";
+
+static constexpr char wdBus[] = "xyz.openbmc_project.Watchdog";
+static constexpr char wdPath[] = "/xyz/openbmc_project/watchdog/host0";
+static constexpr char wdIntf[] = "xyz.openbmc_project.State.Watchdog";
+static constexpr char propIntf[] = "org.freedesktop.DBus.Properties";
+
+typedef boost::asio::buffers_iterator<boost::asio::const_buffers_1> iterator;
+
+// check if FRB2 bit is 0x1
+std::pair<iterator, bool> matchFRB2(iterator begin, iterator end)
+{
+ unsigned char ch = 0;
+ iterator i = begin;
+
+ while (i != end)
+ {
+ ch = static_cast<unsigned char>(*i);
+ if (ch & 0x1)
+ {
+ return std::make_pair(i, true);
+ }
+ i++;
+ }
+
+ return std::make_pair(i, false);
+}
+
+static void startRead()
+{
+ boost::asio::async_read_until(inputDevice, readBuf, matchFRB2,
+ [&](const boost::system::error_code &ec,
+ std::size_t bytes_transferred) {
+ handleResponse(ec, bytes_transferred);
+ });
+}
+
+template <typename T> void setProperty(const std::string &key, const T &val)
+{
+ phosphor::logging::log<phosphor::logging::level::DEBUG>(
+ "setProperty", phosphor::logging::entry("KEY=%s", key.c_str()));
+
+ try
+ {
+ conn->async_method_call(
+ [](const boost::system::error_code &err) {
+ if (err)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "async_method_call error!",
+ phosphor::logging::entry(
+ "ERROR=%s",
+ boost::system::system_error(err).what()));
+ }
+ },
+ wdBus, wdPath, propIntf, "Set", wdIntf, key,
+ sdbusplus::message::variant_ns::variant<T>(val));
+ }
+ catch (sdbusplus::exception::SdBusError &e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Dbus error!", phosphor::logging::entry("ERROR=%s", e.what()));
+ }
+}
+void handleResponse(const boost::system::error_code &err,
+ std::size_t bytes_transferred)
+{
+ std::istream responseStream(&readBuf);
+ std::string response;
+ int n = 0;
+ uint64_t interval = frb2TimerIntervalMs;
+
+ std::getline(responseStream, response);
+ responseStream.clear();
+
+ if (err == boost::system::errc::bad_file_descriptor)
+ {
+
+ phosphor::logging::log<phosphor::logging::level::DEBUG>(
+ "bad file descriptor");
+ return; // we're being destroyed
+ }
+
+ if (!err)
+ {
+ // FRB2 is set by BIOS
+ if (frb2Stopped == frb2Status)
+ {
+ // start FRB2 watchdog
+ frb2Status = frb2Started;
+ phosphor::logging::log<phosphor::logging::level::DEBUG>(
+ "FRB2 enable, start FRB2 watchdog");
+ setProperty(
+ "ExpireAction",
+ std::string(
+ "xyz.openbmc_project.State.Watchdog.Action.HardReset"));
+ setProperty("Interval", interval);
+ setProperty("TimeRemaining", interval);
+ setProperty("Initialized", true);
+ setProperty("Enabled", true);
+ }
+ }
+ else if (err == boost::asio::error::misc_errors::not_found)
+ {
+ // FRB2 is clear, stop FRB2 watchdog if it is started
+ if (frb2Started == frb2Status)
+ {
+ frb2Status = frb2Stopped;
+ phosphor::logging::log<phosphor::logging::level::DEBUG>(
+ "FRB2 is unset, stop FRB2 watchdog");
+ setProperty("Enabled", false);
+ }
+ }
+ else
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "handleResponse error!",
+ phosphor::logging::entry("ERROR=%s",
+ boost::system::system_error(err).what()));
+ }
+
+ pollTimer.expires_from_now(boost::posix_time::milliseconds(pollMs));
+ pollTimer.async_wait(
+ [](const boost::system::error_code &ec) { startRead(); });
+}
+
+int main(int argc, char **argv)
+{
+ phosphor::logging::log<phosphor::logging::level::DEBUG>(
+ "Monitor FRB2 signal");
+
+ sdbusplus::bus::match_t biosPostSignal(
+ static_cast<sdbusplus::bus::bus &>(*conn),
+ sdbusplus::bus::match::rules::type::signal() +
+ sdbusplus::bus::match::rules::member("PostCompleted") +
+ sdbusplus::bus::match::rules::path(powerPath) +
+ sdbusplus::bus::match::rules::interface(powerIntf),
+ [](sdbusplus::message::message &msg) {
+ uint8_t value = 0;
+ ssize_t rc = 0;
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "BIOS post completed signal");
+ // stop FRB2 and clean mailbox
+ value = 0;
+ rc = ::pwrite(mailboxDevFd, &value, 1, 0);
+ if (rc != 1)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "mailbox write error!");
+ }
+ setProperty("Enabled", false);
+ frb2Status = frb2Stopped;
+ return;
+ });
+
+ conn->request_name(frb2Bus);
+
+ auto server = sdbusplus::asio::object_server(conn);
+
+ std::shared_ptr<sdbusplus::asio::dbus_interface> frb2Iface =
+ server.add_interface(frb2Obj, frb2Intf);
+
+ frb2Iface->register_property("frb2Status", frb2Status);
+
+ frb2Iface->initialize();
+
+ mailboxDevFd = ::open(mailboxDevName, O_RDWR | O_CLOEXEC);
+ if (mailboxDevFd < 0)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "mailbox device open fail!");
+ return -1;
+ }
+
+ inputDevice.assign(mailboxDevFd);
+
+ startRead();
+
+ io.run();
+
+ ::close(mailboxDevFd);
+
+ return 0;
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Add-expiredTimerUse-property-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Add-expiredTimerUse-property-support.patch
new file mode 100644
index 000000000..54e459245
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Add-expiredTimerUse-property-support.patch
@@ -0,0 +1,28 @@
+From efb3c226fc80243729901f675568b2b41142b1f9 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Mon, 18 Mar 2019 22:54:41 +0800
+Subject: [PATCH] Add expiredTimerUse property support
+
+When the timer expired, set expiredTimerUse property as the timer use
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ watchdog.cpp | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/watchdog.cpp b/watchdog.cpp
+index aed0443..d529746 100644
+--- a/watchdog.cpp
++++ b/watchdog.cpp
+@@ -101,6 +101,8 @@ void Watchdog::timeOutHandler()
+ action = fallback->action;
+ }
+
++ WatchdogInherits::expiredTimerUse(WatchdogInherits::currentTimerUse());
++
+ auto target = actionTargetMap.find(action);
+ if (target == actionTargetMap.end())
+ {
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/obmc-enable-host-watchdog@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/obmc-enable-host-watchdog@.service
new file mode 100644
index 000000000..87a662f7c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/obmc-enable-host-watchdog@.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Start FRB2 Watchdog%i
+Wants=obmc-host-started@%i.target
+After=obmc-host-started@%i.target
+Wants=mapper-wait@-xyz-openbmc_project-watchdog-host%i.service
+After=mapper-wait@-xyz-openbmc_project-watchdog-host%i.service
+Conflicts=obmc-host-stop@%i.target
+ConditionPathExists=!/run/openbmc/host@%i-on
+
+[Service]
+Restart=always
+ExecStart=/usr/bin/env frb2-watchdog
+ExecStopPost=/bin/sh -c "busctl call `mapper get-service /xyz/openbmc_project/watchdog/host%i` /xyz/openbmc_project/watchdog/host%i org.freedesktop.DBus.Properties Set ssv xyz.openbmc_project.State.Watchdog Enabled b false"
+SyslogIdentifier=obmc-enable-host-watchdog
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog@.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog@.service
new file mode 100644
index 000000000..251c2257b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog@.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Phosphor %I watchdog
+
+[Service]
+Restart=no
+EnvironmentFile={envfiledir}/obmc/watchdog/%I
+ExecStart=/usr/bin/env phosphor-watchdog --continue --service=${{SERVICE}} --path=${{DEVPATH}} \
+ --action_target=xyz.openbmc_project.State.Watchdog.Action.HardReset=obmc-host-warm-reset@0.target \
+ --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerOff=obmc-host-shutdown@0.target \
+ --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerCycle=obmc-host-reboot@0.target
+
+SyslogIdentifier=phosphor-watchdog
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend
new file mode 100644
index 000000000..5f8d53976
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend
@@ -0,0 +1,6 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+
+SRC_URI += "file://0001-Add-expiredTimerUse-property-support.patch"
+
+# Remove the override to keep service running after DC cycle
+SYSTEMD_OVERRIDE_${PN}_remove = "poweron.conf:phosphor-watchdog@poweron.service.d/poweron.conf"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb
new file mode 100644
index 000000000..5da053f1d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb
@@ -0,0 +1,13 @@
+SUMMARY = "System watchdog"
+DESCRIPTION = "BMC hardware watchdog service that is used to reset BMC \
+ when unrecoverable events occurs"
+
+inherit allarch
+inherit obmc-phosphor-systemd
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SYSTEMD_SERVICE_${PN} += "system-watchdog.service"
+SYSTEMD_ENVIRONMENT_FILE_${PN} += "obmc/system-watchdog/system-watchdog.conf"
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf
new file mode 100644
index 000000000..defe830a1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/obmc/system-watchdog/system-watchdog.conf
@@ -0,0 +1,3 @@
+TIMEOUT=60
+INTERVAL=10
+DEVICE=/dev/watchdog1
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service
new file mode 100644
index 000000000..1564fda20
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/system-watchdog.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=BMC Hardware Watchdog Daemon
+
+[Service]
+EnvironmentFile=/etc/default/obmc/system-watchdog/system-watchdog.conf
+ExecStart=/sbin/watchdog -T ${{TIMEOUT}} -t ${{INTERVAL}} -F ${{DEVICE}}
+KillSignal=SIGKILL
+
+[Install]
+WantedBy=basic.target
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0001-Implement-KVM-in-webui.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0001-Implement-KVM-in-webui.patch
new file mode 100644
index 000000000..85b0f1009
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0001-Implement-KVM-in-webui.patch
@@ -0,0 +1,238 @@
+From 4c63b4e16fbc3b536a437b2ab5d5df5e846e6b83 Mon Sep 17 00:00:00 2001
+From: Ed tanous <ed@tanous.net>
+Date: Sun, 22 Apr 2018 10:53:28 -0700
+Subject: [PATCH] Implement KVM in webui
+
+This patchset adds the infrastructure to allow KVM sessions
+through the webui. A websocket capable VNC/RFB connection
+on the BMC is needed for KVM sessions.
+
+To access, navigate to Server control -> KVM.
+
+Tested: Ran obmc-ikvm on the BMC, added a KVM Handler to
+ Phosphor Rest Server, and was able to establish a
+ KVM session in the webui on a Witherspoon.
+Change-Id: I7dda5bec41d270ae8d0913697714d4df4ec3a257
+Signed-off-by: Ed Tanous <ed.tanous@intel.com>
+Signed-off-by: Gunnar Mills <gmills@us.ibm.com>
+---
+ app/common/directives/app-navigation.html | 12 +++--
+ app/index.js | 1 +
+ app/server-control/controllers/kvm-controller.html | 5 ++
+ app/server-control/controllers/kvm-controller.js | 55 ++++++++++++++++++++++
+ app/server-control/index.js | 5 ++
+ app/server-control/styles/index.scss | 1 +
+ app/server-control/styles/kvm.scss | 11 +++++
+ package-lock.json | 5 ++
+ package.json | 1 +
+ webpack.config.js | 6 ++-
+ 10 files changed, 96 insertions(+), 6 deletions(-)
+ create mode 100644 app/server-control/controllers/kvm-controller.html
+ create mode 100644 app/server-control/controllers/kvm-controller.js
+ create mode 100644 app/server-control/styles/kvm.scss
+
+diff --git a/app/common/directives/app-navigation.html b/app/common/directives/app-navigation.html
+index a45a24bcbaa1..e54b23631b3e 100644
+--- a/app/common/directives/app-navigation.html
++++ b/app/common/directives/app-navigation.html
+@@ -87,19 +87,21 @@
+ <a href="#/server-control/bmc-reboot" tabindex="13" ng-click="closeSubnav()">Reboot BMC</a></li>
+ <li ng-class="{'active': (path == '/server-control/remote-console')}">
+ <a href="#/server-control/remote-console" tabindex="14" ng-click="closeSubnav()">Serial over LAN console</a></li>
++ <li ng-class="{'active': (path == '/server-control/kvm')}">
++ <a href="#/server-control/kvm" tabindex="15" ng-click="closeSubnav()">KVM</a></li>
+ </ul>
+ <ul class="nav__second-level btn-firmware" ng-style="navStyle" ng-class="{opened: (showSubMenu && firstLevel == 'configuration')}">
+ <li ng-class="{'active': (path == '/configuration' || path == '/configuration/network')}">
+- <a href="#/configuration/network" tabindex="15" ng-click="closeSubnav()">Network settings</a></li>
++ <a href="#/configuration/network" tabindex="16" ng-click="closeSubnav()">Network settings</a></li>
+ <li ng-class="{'active': (path == '/configuration' || path == '/configuration/snmp')}">
+- <a href="#/configuration/snmp" tabindex="16" ng-click="closeSubnav()">SNMP settings</a></li>
++ <a href="#/configuration/snmp" tabindex="17" ng-click="closeSubnav()">SNMP settings</a></li>
+ <li ng-class="{'active': (path == '/configuration' || path == '/configuration/firmware')}">
+- <a href="#/configuration/firmware" tabindex="17" ng-click="closeSubnav()">Firmware</a></li>
++ <a href="#/configuration/firmware" tabindex="18" ng-click="closeSubnav()">Firmware</a></li>
+ <li ng-class="{'active': (path == '/configuration' || path == '/configuration/date-time')}">
+- <a href="#/configuration/date-time" tabindex="18" ng-click="closeSubnav()">Date and time settings</a></li>
++ <a href="#/configuration/date-time" tabindex="19" ng-click="closeSubnav()">Date and time settings</a></li>
+ </ul>
+ <ul class="nav__second-level btn-users" ng-style="navStyle" ng-class="{opened: (showSubMenu && firstLevel == 'users')}">
+ <li ng-class="{'active': (path == '/users' || path == '/users/manage-accounts')}">
+- <a href="#/users/manage-accounts" tabindex="19" ng-click="closeSubnav()">Manage user account</a></li>
++ <a href="#/users/manage-accounts" tabindex="20" ng-click="closeSubnav()">Manage user account</a></li>
+ </ul>
+ </nav>
+diff --git a/app/index.js b/app/index.js
+index 38df0e9896f4..a0dde4df96b7 100644
+--- a/app/index.js
++++ b/app/index.js
+@@ -69,6 +69,7 @@ import power_operations_controller from './server-control/controllers/power-oper
+ import power_usage_controller from './server-control/controllers/power-usage-controller.js';
+ import remote_console_window_controller from './server-control/controllers/remote-console-window-controller.js';
+ import server_led_controller from './server-control/controllers/server-led-controller.js';
++import kvm_controller from './server-control/controllers/kvm-controller.js';
+
+ import server_health_index from './server-health/index.js';
+ import inventory_overview_controller from './server-health/controllers/inventory-overview-controller.js';
+diff --git a/app/server-control/controllers/kvm-controller.html b/app/server-control/controllers/kvm-controller.html
+new file mode 100644
+index 000000000000..40e4d97454bc
+--- /dev/null
++++ b/app/server-control/controllers/kvm-controller.html
+@@ -0,0 +1,5 @@
++<div id="noVNC_container">
++ <div id="noVNC_status_bar">
++ <div id="noVNC_left_dummy_elem"></div>
++ </div>
++</div>
+diff --git a/app/server-control/controllers/kvm-controller.js b/app/server-control/controllers/kvm-controller.js
+new file mode 100644
+index 000000000000..a43f169ddf19
+--- /dev/null
++++ b/app/server-control/controllers/kvm-controller.js
+@@ -0,0 +1,55 @@
++/**
++ * Controller for KVM (Kernel-based Virtual Machine)
++ *
++ * @module app/serverControl
++ * @exports kvmController
++ * @name kvmController
++ */
++
++import RFB from '@novnc/novnc/core/rfb.js';
++
++window.angular && (function(angular) {
++ 'use strict';
++
++ angular.module('app.serverControl').controller('kvmController', [
++ '$scope', '$location', '$log',
++ function($scope, $location, $log) {
++ var rfb;
++
++ $scope.$on('$destroy', function() {
++ if (rfb) {
++ rfb.disconnect();
++ }
++ });
++
++ function sendCtrlAltDel() {
++ rfb.sendCtrlAltDel();
++ return false;
++ };
++
++ function connected(e) {
++ $log.debug('RFB Connected');
++ }
++ function disconnected(e) {
++ $log.debug('RFB disconnected');
++ }
++
++ var host = $location.host();
++ var port = $location.port();
++ var target =
++ angular.element(document.querySelector('#noVNC_container'))[0];
++
++ try {
++ rfb = new RFB(target, 'wss://' + host + ':' + port + '/kvm/0', {});
++
++ rfb.addEventListener('connect', connected);
++ rfb.addEventListener('disconnect', disconnected);
++ } catch (exc) {
++ $log.error(exc);
++ updateState(
++ null, 'fatal', null, 'Unable to create RFB client -- ' + exc);
++ return; // don't continue trying to connect
++ };
++ }
++ ]);
++})(angular);
+diff --git a/app/server-control/index.js b/app/server-control/index.js
+index 739bd1eb8ad9..1b8aad50b702 100644
+--- a/app/server-control/index.js
++++ b/app/server-control/index.js
+@@ -48,6 +48,11 @@ window.angular && (function(angular) {
+ 'controller': 'remoteConsoleWindowController',
+ authenticated: true
+ })
++ .when('/server-control/kvm', {
++ 'template': require('./controllers/kvm-controller.html'),
++ 'controller': 'kvmController',
++ authenticated: true
++ })
+ .when('/server-control', {
+ 'template':
+ require('./controllers/power-operations-controller.html'),
+diff --git a/app/server-control/styles/index.scss b/app/server-control/styles/index.scss
+index f6b15ab6afc9..5e8a99580894 100644
+--- a/app/server-control/styles/index.scss
++++ b/app/server-control/styles/index.scss
+@@ -3,3 +3,4 @@
+ @import "./remote-console.scss";
+ @import "./server-led.scss";
+ @import "./power-usage.scss";
++@import "./kvm.scss";
+diff --git a/app/server-control/styles/kvm.scss b/app/server-control/styles/kvm.scss
+new file mode 100644
+index 000000000000..2f9e2c0c9f37
+--- /dev/null
++++ b/app/server-control/styles/kvm.scss
+@@ -0,0 +1,11 @@
++
++.noNVC_shown {
++ display: inline;
++}
++.noVNC_hidden {
++ display: none;
++}
++
++#noVNC_left_dummy_elem {
++ flex: 1;
++}
+diff --git a/package-lock.json b/package-lock.json
+index 2d9d31b21968..103c9b84b933 100644
+--- a/package-lock.json
++++ b/package-lock.json
+@@ -807,6 +807,11 @@
+ "to-fast-properties": "2.0.0"
+ }
+ },
++ "@novnc/novnc": {
++ "version": "1.0.0",
++ "resolved": "https://registry.npmjs.org/@novnc/novnc/-/novnc-1.0.0.tgz",
++ "integrity": "sha1-drDonm+HOMqBVBlbr1uOaoC8kQU="
++ },
+ "@types/node": {
+ "version": "10.12.18",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz",
+diff --git a/package.json b/package.json
+index 35c6b78e320c..fd253cbb2f02 100644
+--- a/package.json
++++ b/package.json
+@@ -30,6 +30,7 @@
+ "dependencies": {
+ "angular": "^1.7.5",
+ "angular-animate": "^1.7.5",
++ "@novnc/novnc": "^1.0.0",
+ "angular-clipboard": "^1.6.2",
+ "angular-cookies": "^1.7.5",
+ "angular-messages": "^1.7.6",
+diff --git a/webpack.config.js b/webpack.config.js
+index 91cbea8f2952..6c8667cbbc98 100644
+--- a/webpack.config.js
++++ b/webpack.config.js
+@@ -113,7 +113,11 @@ module.exports = (env, options) => {
+ 'base-uri': '\'self\'',
+ 'object-src': '\'none\'',
+ 'script-src': ['\'self\''],
+- 'style-src': ['\'self\'']
++ 'style-src': ['\'self\''],
++ // KVM requires image buffers from data: payloads, so allow that in
++ // img-src
++ // https://stackoverflow.com/questions/18447970/content-security-policy-data-not-working-for-base64-images-in-chrome-28
++ 'img-src': ['\'self\'', 'data:'],
+ }),
+ new MiniCssExtractPlugin(),
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0007-Fix-some-page-keeps-loading-on-IE11.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0007-Fix-some-page-keeps-loading-on-IE11.patch
new file mode 100644
index 000000000..31d810cb6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0007-Fix-some-page-keeps-loading-on-IE11.patch
@@ -0,0 +1,68 @@
+From 5a3750377629725890f949d68e7e0ba7d4752825 Mon Sep 17 00:00:00 2001
+From: Mirage Su <mirage.su@mic.com.tw>
+Date: Fri, 8 Mar 2019 17:12:46 +0800
+Subject: [PATCH] Fix some page keeps loading on IE11
+
+---
+ app/index.js | 1 +
+ package-lock.json | 19 +++++++++++++++++++
+ package.json | 1 +
+ 3 files changed, 21 insertions(+)
+ mode change 100644 => 100755 package-lock.json
+
+diff --git a/app/index.js b/app/index.js
+index c9fed83..c51203e 100644
+--- a/app/index.js
++++ b/app/index.js
+@@ -8,6 +8,7 @@
+ */
+ import 'angular/angular-csp.css';
+ import 'bootstrap/dist/css/bootstrap.css';
++import 'babel-polyfill';
+
+ import angular from 'angular';
+ import angular_animate from 'angular-animate';
+diff --git a/package-lock.json b/package-lock.json
+old mode 100644
+new mode 100755
+index 2d9d31b..61e9787
+--- a/package-lock.json
++++ b/package-lock.json
+@@ -1500,6 +1500,25 @@
+ "babel-runtime": "6.26.0"
+ }
+ },
++ "babel-polyfill": {
++ "version": "6.26.0",
++ "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
++ "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
++ "dev": true,
++ "requires": {
++ "babel-runtime": "^6.26.0",
++ "core-js": "^2.5.0",
++ "regenerator-runtime": "^0.10.5"
++ },
++ "dependencies": {
++ "regenerator-runtime": {
++ "version": "0.10.5",
++ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
++ "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
++ "dev": true
++ }
++ }
++ },
+ "babel-register": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+diff --git a/package.json b/package.json
+index 35c6b78..1bdf934 100644
+--- a/package.json
++++ b/package.json
+@@ -50,6 +50,7 @@
+ "autoprefixer": "9.1.5",
+ "babel-core": "6.26.3",
+ "babel-loader": "8.0.2",
++ "babel-polyfill": "^6.26.0",
+ "compression-webpack-plugin": "2.0.0",
+ "copy-webpack-plugin": "4.5.2",
+ "csp-html-webpack-plugin": "^2.5.0",
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json
new file mode 100644
index 000000000..1543a6249
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json
@@ -0,0 +1,8 @@
+{
+ "customKeyEnable": true,
+ "keyType" : "VT100+",
+ "customConsoleDisplaySize": {
+ "width": 100,
+ "height": 32
+ }
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend
new file mode 100644
index 000000000..9caa37767
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend
@@ -0,0 +1,13 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+
+#SRC_URI = "git://github.com/openbmc/phosphor-webui.git"
+SRCREV = "a2e36e0f479d1a9fa2b6d26448d5e070aea7259b"
+
+SRC_URI += "file://0001-Implement-KVM-in-webui.patch \
+ file://config.json \
+ file://0007-Fix-some-page-keeps-loading-on-IE11.patch \
+ "
+
+do_compile_prepend() {
+ cp -r ${WORKDIR}/config.json ${S}/
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh
new file mode 100644
index 000000000..176bfd7ca
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh
@@ -0,0 +1 @@
+export LDB_MODULES_PATH=/usr/lib/ldb
diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups
new file mode 100644
index 000000000..7c189e231
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups
@@ -0,0 +1 @@
+sssd_locked
diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf
new file mode 100644
index 000000000..d2ffe5ddc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf
@@ -0,0 +1,2 @@
+enable-cache passwd no
+enable-cache group no \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf
new file mode 100644
index 000000000..7a2786bee
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf
@@ -0,0 +1,16 @@
+[sssd]
+domains = LOCAL
+services = nss, pam
+config_file_version = 2
+
+[nss]
+enum_cache_timeout = 1
+filter_groups = root
+filter_users = root
+
+[pam]
+
+[domain/LOCAL]
+enumerate = true
+id_provider = local
+auth_provider = local
diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service
new file mode 100644
index 000000000..fe2bcf8b4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=System Security Services Daemon
+# SSSD must be running before we permit user sessions
+Before=systemd-user-sessions.service nss-user-lookup.target
+Wants=nss-user-lookup.target
+
+[Service]
+Environment=LDB_MODULES_PATH=/usr/lib/ldb DEBUG_LOGGER=-f
+ExecStart=/usr/sbin/sssd $DEBUG_LOGGER
+Type=simple
+Restart=always
+PIDFile=/var/run/sssd.pid
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend b/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend
new file mode 100644
index 000000000..03965ce72
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend
@@ -0,0 +1,26 @@
+inherit obmc-phosphor-systemd
+
+FILESEXTRAPATHS_append := "${THISDIR}/files:"
+SRC_URI += "file://sssd.conf \
+ file://nscd.conf \
+ file://locked_groups \
+ file://ldb.sh \
+ "
+
+PACKAGECONFIG += " systemd "
+SYSTEMD_AUTO_ENABLE = "enable"
+
+EXTRA_OECONF += " --enable-pammoddir=${base_libdir}/security"
+
+do_install_append() {
+ # sssd creates also the /var/run link. Need to remove it to avoid conflicts
+ # with the one created by base-files recipe.
+ rm -rf ${D}/var/run
+ install -m 600 ${WORKDIR}/locked_groups ${D}/${sysconfdir}/${BPN}
+ install -m 600 ${WORKDIR}/nscd.conf ${D}/${sysconfdir}
+ install -d ${D}${sysconfdir}/profile.d
+ install -m 0644 ${WORKDIR}/ldb.sh ${D}${sysconfdir}/profile.d
+}
+
+FILES_${PN} += " /lib/security/pam_sss.so "
+
diff --git a/meta-openbmc-mods/meta-common/recipes-support/boost/boost/0001-Close-the-read-pipe-after-_read_error-completes.patch b/meta-openbmc-mods/meta-common/recipes-support/boost/boost/0001-Close-the-read-pipe-after-_read_error-completes.patch
new file mode 100644
index 000000000..80b1084ad
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-support/boost/boost/0001-Close-the-read-pipe-after-_read_error-completes.patch
@@ -0,0 +1,45 @@
+From a035b099050e0f6e953001ce5b7f415043a12ec6 Mon Sep 17 00:00:00 2001
+From: "Jason M. Bills" <jason.m.bills@linux.intel.com>
+Date: Wed, 20 Mar 2019 18:20:12 -0700
+Subject: [PATCH] Close the read pipe after _read_error() completes
+
+There are exit conditions in _read_error() where the pipe does
+not get closed resulting in a file descriptor leak in the
+parent process after the child exits.
+
+This change moves the responsibility to close the pipe out of
+_read_error() to the caller of _read_error() which aligns
+with the behavior of _write_error().
+
+Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
+---
+ boost/process/detail/posix/executor.hpp | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/boost/process/detail/posix/executor.hpp b/boost/process/detail/posix/executor.hpp
+index 1390a58..661fbc5 100644
+--- a/boost/process/detail/posix/executor.hpp
++++ b/boost/process/detail/posix/executor.hpp
+@@ -296,11 +296,9 @@ class executor
+ //EAGAIN not yet forked, EINTR interrupted, i.e. try again
+ else if ((err != EAGAIN ) && (err != EINTR))
+ {
+- ::close(source);
+ set_error(std::error_code(err, std::system_category()), "Error read pipe");
+ }
+ }
+- ::close(source);
+ set_error(ec, std::move(msg));
+ }
+
+@@ -429,6 +427,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
+
+ ::close(p[1]);
+ _read_error(p[0]);
++ ::close(p[0]);
+
+ if (_ec)
+ {
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend b/meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend
new file mode 100644
index 000000000..d42d7ff6d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend
@@ -0,0 +1,3 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://0001-Close-the-read-pipe-after-_read_error-completes.patch"
diff --git a/meta-openbmc-mods/meta-common/recipes-support/libgpiod/libgpiod/0001-Add-pass-through-setting-in-gpioset.patch b/meta-openbmc-mods/meta-common/recipes-support/libgpiod/libgpiod/0001-Add-pass-through-setting-in-gpioset.patch
new file mode 100644
index 000000000..b90d42ca3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-support/libgpiod/libgpiod/0001-Add-pass-through-setting-in-gpioset.patch
@@ -0,0 +1,265 @@
+From 380a088dbe9fdd69e98bf6da8086e3d664da8338 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Thu, 31 Jan 2019 22:28:48 +0800
+Subject: [PATCH] Add pass through setting in gpioset
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ aclocal.m4 | 2 +-
+ configure | 2 +-
+ include/gpiod.h | 10 ++++++++--
+ src/lib/core.c | 13 +++++++------
+ src/lib/ctxless.c | 8 ++++----
+ src/lib/helpers.c | 3 ++-
+ src/tools/gpioset.c | 13 +++++++++----
+ tests/tests-ctxless.c | 2 +-
+ 8 files changed, 33 insertions(+), 20 deletions(-)
+
+diff --git a/aclocal.m4 b/aclocal.m4
+index b0db596..a5e28ad 100644
+--- a/aclocal.m4
++++ b/aclocal.m4
+@@ -911,7 +911,7 @@ AS_VAR_IF([$1], [""], [$5], [$4])dnl
+ # generated from the m4 files accompanying Automake X.Y.
+ # (This private macro should not be called outside this file.)
+ AC_DEFUN([AM_AUTOMAKE_VERSION],
+-[am__api_version='1.15'
++[am__api_version='1.16'
+ dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+ dnl require some minimum version. Point them to the right macro.
+ m4_if([$1], [1.15], [],
+diff --git a/configure b/configure
+index 3d44cd1..d218338 100755
+--- a/configure
++++ b/configure
+@@ -2477,7 +2477,7 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+
+-am__api_version='1.15'
++am__api_version='1.16'
+
+ # Find a good install program. We prefer a C program (faster),
+ # so one script is as good as another. But avoid the broken or
+diff --git a/include/gpiod.h b/include/gpiod.h
+index ccff977..0f935e6 100644
+--- a/include/gpiod.h
++++ b/include/gpiod.h
+@@ -121,6 +121,7 @@ typedef void (*gpiod_ctxless_set_value_cb)(void *);
+ * @param offset The offset of the GPIO line.
+ * @param value New value (0 or 1).
+ * @param active_low The active state of this line - true if low.
++ * @param pass_through The pass-through state of the lines - true if enabled.
+ * @param consumer Name of the consumer.
+ * @param cb Optional callback function that will be called right after setting
+ * the value. Users can use this, for example, to pause the execution
+@@ -129,7 +130,7 @@ typedef void (*gpiod_ctxless_set_value_cb)(void *);
+ * @return 0 if the operation succeeds, -1 on error.
+ */
+ int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value,
+- bool active_low, const char *consumer,
++ bool active_low, bool pass_through, const char *consumer,
+ gpiod_ctxless_set_value_cb cb,
+ void *data) GPIOD_API;
+
+@@ -140,6 +141,7 @@ int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value,
+ * @param values Array of integers containing new values.
+ * @param num_lines Number of lines, must be > 0.
+ * @param active_low The active state of the lines - true if low.
++ * @param pass_through The pass-through state of the lines - true if enabled.
+ * @param consumer Name of the consumer.
+ * @param cb Optional callback function that will be called right after setting
+ * all values. Works the same as in ::gpiod_ctxless_set_value.
+@@ -149,7 +151,7 @@ int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value,
+ int gpiod_ctxless_set_value_multiple(const char *device,
+ const unsigned int *offsets,
+ const int *values, unsigned int num_lines,
+- bool active_low, const char *consumer,
++ bool active_low, bool pass_through, const char *consumer,
+ gpiod_ctxless_set_value_cb cb,
+ void *data) GPIOD_API;
+
+@@ -766,6 +768,8 @@ enum {
+ /**< Request the line(s) for reading the GPIO line state. */
+ GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
+ /**< Request the line(s) for setting the GPIO line state. */
++ GPIOD_LINE_REQUEST_DIRECTION_PASS_THROUGH,
++ /**< Request the line(s) for setting the GPIO line state. */
+ GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE,
+ /**< Monitor both types of events. */
+ GPIOD_LINE_REQUEST_EVENT_RISING_EDGE,
+@@ -784,6 +788,8 @@ enum {
+ /**< The line is an open-source port. */
+ GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW = GPIOD_BIT(2),
+ /**< The active state of the line is low (high is the default). */
++ GPIOD_LINE_REQUEST_FLAG_PASS_THROUGH = GPIOD_BIT(5),
++ /**< The line is a pass-through port*/
+ };
+
+ /**
+diff --git a/src/lib/core.c b/src/lib/core.c
+index 4f273e3..feec362 100644
+--- a/src/lib/core.c
++++ b/src/lib/core.c
+@@ -472,7 +472,6 @@ static int line_request_values(struct gpiod_line_bulk *bulk,
+ struct gpiohandle_request req;
+ unsigned int i;
+ int rv, fd;
+-
+ if ((config->request_type != GPIOD_LINE_REQUEST_DIRECTION_OUTPUT) &&
+ (config->flags & (GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN |
+ GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE))) {
+@@ -499,14 +498,15 @@ static int line_request_values(struct gpiod_line_bulk *bulk,
+ req.flags |= GPIOHANDLE_REQUEST_INPUT;
+ else if (config->request_type == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
+ req.flags |= GPIOHANDLE_REQUEST_OUTPUT;
+-
++ else if (config->request_type == GPIOD_LINE_REQUEST_DIRECTION_PASS_THROUGH)
++ req.flags |= GPIOHANDLE_REQUEST_PASS_THROUGH;
+ req.lines = gpiod_line_bulk_num_lines(bulk);
+
+ gpiod_line_bulk_foreach_line_off(bulk, line, i) {
+ req.lineoffsets[i] = gpiod_line_offset(line);
+- if (config->request_type ==
+- GPIOD_LINE_REQUEST_DIRECTION_OUTPUT &&
+- default_vals)
++ if ((config->request_type == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT ||
++ config->request_type == GPIOD_LINE_REQUEST_DIRECTION_PASS_THROUGH)&&
++ default_vals)
+ req.default_values[i] = !!default_vals[i];
+ }
+
+@@ -617,7 +617,8 @@ static bool line_request_is_direction(int request)
+ {
+ return request == GPIOD_LINE_REQUEST_DIRECTION_AS_IS ||
+ request == GPIOD_LINE_REQUEST_DIRECTION_INPUT ||
+- request == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
++ request == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT ||
++ request == GPIOD_LINE_REQUEST_DIRECTION_PASS_THROUGH;
+ }
+
+ static bool line_request_is_events(int request)
+diff --git a/src/lib/ctxless.c b/src/lib/ctxless.c
+index 0009504..a16207e 100644
+--- a/src/lib/ctxless.c
++++ b/src/lib/ctxless.c
+@@ -76,17 +76,17 @@ int gpiod_ctxless_get_value_multiple(const char *device,
+ }
+
+ int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value,
+- bool active_low, const char *consumer,
++ bool active_low, bool pass_through, const char *consumer,
+ gpiod_ctxless_set_value_cb cb, void *data)
+ {
+ return gpiod_ctxless_set_value_multiple(device, &offset, &value, 1,
+- active_low, consumer, cb, data);
++ active_low, pass_through, consumer, cb, data);
+ }
+
+ int gpiod_ctxless_set_value_multiple(const char *device,
+ const unsigned int *offsets,
+ const int *values, unsigned int num_lines,
+- bool active_low, const char *consumer,
++ bool active_low, bool pass_through, const char *consumer,
+ gpiod_ctxless_set_value_cb cb, void *data)
+ {
+ struct gpiod_line_bulk bulk;
+@@ -117,7 +117,7 @@ int gpiod_ctxless_set_value_multiple(const char *device,
+ }
+
+ flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0;
+-
++ flags |= pass_through ? GPIOD_LINE_REQUEST_FLAG_PASS_THROUGH : 0;
+ status = gpiod_line_request_bulk_output_flags(&bulk, consumer,
+ flags, values);
+ if (status < 0) {
+diff --git a/src/lib/helpers.c b/src/lib/helpers.c
+index 80b8eff..807fb93 100644
+--- a/src/lib/helpers.c
++++ b/src/lib/helpers.c
+@@ -362,7 +362,8 @@ int gpiod_line_request_bulk_output_flags(struct gpiod_line_bulk *bulk,
+ .request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
+ .flags = flags,
+ };
+-
++ if (flags & GPIOD_LINE_REQUEST_FLAG_PASS_THROUGH)
++ config.request_type = GPIOD_LINE_REQUEST_DIRECTION_PASS_THROUGH;
+ return gpiod_line_request_bulk(bulk, &config, default_vals);
+ }
+
+diff --git a/src/tools/gpioset.c b/src/tools/gpioset.c
+index fb012fa..d5f0b77 100644
+--- a/src/tools/gpioset.c
++++ b/src/tools/gpioset.c
+@@ -22,7 +22,8 @@
+ static const struct option longopts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+- { "active-low", no_argument, NULL, 'l' },
++ { "active-low", no_argument, NULL, 'l' },
++ { "pass-through", no_argument, NULL, 'p' },
+ { "mode", required_argument, NULL, 'm' },
+ { "sec", required_argument, NULL, 's' },
+ { "usec", required_argument, NULL, 'u' },
+@@ -30,7 +31,7 @@ static const struct option longopts[] = {
+ { GETOPT_NULL_LONGOPT },
+ };
+
+-static const char *const shortopts = "+hvlm:s:u:b";
++static const char *const shortopts = "+hvlpm:s:u:b";
+
+ static void print_help(void)
+ {
+@@ -40,8 +41,9 @@ static void print_help(void)
+ printf("\n");
+ printf("Options:\n");
+ printf(" -h, --help:\t\tdisplay this message and exit\n");
+- printf(" -v, --version:\tdisplay the version and exit\n");
+ printf(" -l, --active-low:\tset the line active state to low\n");
++ printf(" -v, --version:\tdisplay the version and exit\n");
++ printf(" -p, --pass-through:\tset it to pass through mode\n");
+ printf(" -m, --mode=[exit|wait|time|signal] (defaults to 'exit'):\n");
+ printf(" tell the program what to do after setting values\n");
+ printf(" -s, --sec=SEC:\tspecify the number of seconds to wait (only valid for --mode=time)\n");
+@@ -179,6 +181,7 @@ int main(int argc, char **argv)
+ int *values, status, optc, opti;
+ struct callback_data cbdata;
+ bool active_low = false;
++ bool pass_through = false;
+ char *device, *end;
+
+ memset(&cbdata, 0, sizeof(cbdata));
+@@ -197,6 +200,8 @@ int main(int argc, char **argv)
+ return EXIT_SUCCESS;
+ case 'l':
+ active_low = true;
++ case 'p':
++ pass_through = true;
+ break;
+ case 'm':
+ mode = parse_mode(optarg);
+@@ -263,7 +268,7 @@ int main(int argc, char **argv)
+ }
+
+ status = gpiod_ctxless_set_value_multiple(device, offsets, values,
+- num_lines, active_low,
++ num_lines, active_low, pass_through,
+ "gpioset", mode->callback,
+ &cbdata);
+ if (status < 0)
+diff --git a/tests/tests-ctxless.c b/tests/tests-ctxless.c
+index ea9403d..228c49d 100644
+--- a/tests/tests-ctxless.c
++++ b/tests/tests-ctxless.c
+@@ -20,7 +20,7 @@ static void ctxless_set_get_value(void)
+ TEST_ASSERT_EQ(ret, 0);
+
+ ret = gpiod_ctxless_set_value(test_chip_name(0), 3, 1,
+- false, TEST_CONSUMER, NULL, NULL);
++ false, false, TEST_CONSUMER, NULL, NULL);
+ TEST_ASSERT_RET_OK(ret);
+
+ ret = gpiod_ctxless_get_value(test_chip_name(0), 3,
+--
+2.19.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-support/libgpiod/libgpiod_%.bbappend b/meta-openbmc-mods/meta-common/recipes-support/libgpiod/libgpiod_%.bbappend
new file mode 100644
index 000000000..aa28e8d85
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-support/libgpiod/libgpiod_%.bbappend
@@ -0,0 +1,5 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += " \
+ file://0001-Add-pass-through-setting-in-gpioset.patch \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/beeper-test.bb b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/beeper-test.bb
new file mode 100644
index 000000000..51cda82e9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/beeper-test.bb
@@ -0,0 +1,17 @@
+SUMMARY = "Beeper Test App"
+DESCRIPTION = "Beeper Test Application for pwm-beeper"
+
+inherit cmake
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM += "\
+ file://beeper-test.cpp;beginline=2;endline=14;md5=c451359f18a13ee69602afce1588c01a \
+ "
+
+SRC_URI = "\
+ file://CMakeLists.txt \
+ file://beeper-test.cpp \
+ "
+
+S = "${WORKDIR}"
+
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format
new file mode 100644
index 000000000..ea71ad6e1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/.clang-format
@@ -0,0 +1,99 @@
+---
+Language: Cpp
+# BasedOnStyle: LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: true
+ AfterControlStatement: true
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: true
+ AfterObjCDeclaration: true
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: true
+ BeforeElse: true
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: AfterColon
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+PointerAlignment: Left
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeBlocks: Regroup
+IncludeCategories:
+ - Regex: '^[<"](gtest|gmock)'
+ Priority: 5
+ - Regex: '^"config.h"'
+ Priority: -1
+ - Regex: '^".*\.hpp"'
+ Priority: 1
+ - Regex: '^<.*\.h>'
+ Priority: 2
+ - Regex: '^<.*'
+ Priority: 3
+ - Regex: '.*'
+ Priority: 4
+IndentCaseLabels: true
+IndentWidth: 4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+ReflowComments: true
+SortIncludes: true
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 4
+UseTab: Never
+...
+
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt
new file mode 100644
index 000000000..81a0c7e81
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
+project(beeper-test CXX)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+add_executable(beeper-test beeper-test.cpp)
+install(TARGETS beeper-test DESTINATION bin)
+
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp
new file mode 100644
index 000000000..31dafdd88
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/beeper-test/files/beeper-test.cpp
@@ -0,0 +1,81 @@
+/*
+// Copyright (c) 2019 Intel Corporation
+//
+// 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.
+//
+// Abstract: pwm-beeper test application
+//
+*/
+
+#include <fcntl.h>
+#include <linux/input.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <cstring>
+#include <iostream>
+
+int main(int argc, char** argv)
+{
+ if (argc < 3)
+ {
+ std::cout << "usage: <input device> <sequence of 'tone in "
+ "Hz','duration in ms' pair>\n";
+ std::cout << "example: beeper-test /dev/input/event0 "
+ "2100,100,0,150,2500,50,0,50,2200,100\n";
+ return 1;
+ }
+
+ int fd;
+ if ((fd = open(argv[1], O_RDWR | O_CLOEXEC)) < 0)
+ {
+ perror("Failed to open input device");
+ return -1;
+ }
+
+ struct input_event event;
+ event.type = EV_SND;
+ event.code = SND_TONE;
+
+ char* pch = strtok(argv[2], ",");
+ while (pch != NULL)
+ {
+ event.value = atoi(pch);
+
+ pch = strtok(NULL, ",");
+ if (!pch)
+ {
+ std::cerr << "Invalid tone,duration pair\n";
+ close(fd);
+ return -1;
+ }
+
+ int durationMs = atoi(pch);
+
+ if (write(fd, &event, sizeof(struct input_event)) !=
+ sizeof(struct input_event))
+ {
+ perror("Failed to write a tone sound event");
+ close(fd);
+ return -1;
+ }
+
+ usleep(durationMs * 1000);
+
+ pch = strtok(NULL, ",");
+ }
+
+ close(fd);
+
+ return 0;
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb
new file mode 100644
index 000000000..78240c0f4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/dimmsensor.bb
@@ -0,0 +1,17 @@
+SUMMARY = "Dimm Sensor"
+DESCRIPTION = "Dimm Sensor Executable"
+
+SRC_URI = "\
+ file://CMakeLists.txt \
+ file://DimmSensor.cpp \
+ "
+
+LICENSE = "CLOSED"
+
+S = "${WORKDIR}"
+
+inherit cmake
+
+# linux-libc-headers guides this way to include custom uapi headers
+CXXFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi"
+do_configure[depends] += "virtual/kernel:do_shared_workdir"
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt
new file mode 100644
index 000000000..6262f8dee
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
+project(dimmsensor CXX)
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+add_executable(dimmsensor DimmSensor.cpp)
+install (TARGETS dimmsensor DESTINATION bin)
+
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp
new file mode 100644
index 000000000..9cc13c2a5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/dimmsensor/files/DimmSensor.cpp
@@ -0,0 +1,143 @@
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <iostream>
+#include <memory>
+#include <vector>
+#include <linux/aspeed_peci_ioctl.h>
+
+#define PECI_DIMM_TEMP_REG 0x150
+#define DIMM_DEFAULT_VALUE 0x55
+
+class DimmConfig {
+ public:
+ uint8_t chanId, bus, device, function, dimmnum;
+};
+
+#define MAX_BUFFER_SIZE 32
+
+// TODO get this from config
+auto GetDimmConfig(uint8_t dimm) {
+ uint8_t chan = dimm / 2;
+ assert(chan < 6);
+
+ auto ret = std::make_unique<DimmConfig>();
+
+ ret->chanId = chan;
+ ret->dimmnum = 2;
+ ret->bus = 2;
+ switch (chan) {
+ case 0:
+ ret->device = 10;
+ ret->function = 2;
+ break;
+ case 1:
+ ret->device = 10;
+ ret->function = 6;
+ break;
+ case 2:
+ ret->device = 11;
+ ret->function = 2;
+ break;
+ case 3:
+ ret->device = 12;
+ ret->function = 2;
+ break;
+ case 4:
+ ret->device = 12;
+ ret->function = 6;
+ break;
+ case 5:
+ ret->device = 13;
+ ret->function = 2;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ return ret;
+}
+
+// returns read vector on success, empty vector on failure
+auto peci_config_local(uint8_t u8target, uint8_t u8bus, uint8_t u8device,
+ uint8_t u8fcn, uint16_t u16reg, uint8_t u8readlen) {
+ auto msg = std::make_unique<peci_xfer_msg>();
+ uint32_t u32Address;
+ int fd;
+ std::vector<uint8_t> ret;
+
+ u32Address = u16reg;
+ u32Address |= u8fcn << 12;
+ u32Address |= u8device << 15;
+ u32Address |= u8bus << 20;
+
+ msg->client_addr = u8target;
+ msg->tx_len = RDPCICFGLOCAL_WRITE_LEN;
+ msg->rx_len = RDPCICFGLOCAL_READ_LEN_BASE + u8readlen;
+
+ msg->tx_buf[0] = RDPCICFGLOCAL_PECI_CMD;
+ msg->tx_buf[2] = u32Address & 0xFF;
+ msg->tx_buf[3] = (u32Address >> 8) & 0xFF;
+ msg->tx_buf[4] = (u32Address >> 16) & 0xFF;
+
+ fd = open("/dev/peci", O_RDWR | O_CLOEXEC);
+ if (fd >= 0) {
+ int success = ioctl(fd, PECI_IOC_XFER, msg.get());
+ if (success == 0) {
+ if (DEV_PECI_CC_SUCCESS == msg->rx_buf[0]) {
+ ret.resize(RDPCICFGLOCAL_READ_LEN_BASE + u8readlen - 1);
+ memcpy(ret.data(), &(msg->rx_buf[1]), ret.size());
+ }
+ }
+ close(fd);
+ }
+ return ret;
+}
+
+int main(int argc, char** argv) {
+ if (argc != 3) {
+ std::cout << argv[0] << " requires 2 arguments: CPUNum, DimmNum.\n";
+ return -1;
+ }
+ uint8_t cpunum = atoi(argv[1]);
+ if (cpunum > 3) {
+ std::cout << cpunum << " greater than cpu max of 3.\n";
+ return -1;
+ }
+ uint8_t dimmnum = atoi(argv[2]);
+ if (dimmnum > 11) {
+ std::cout << dimmnum << " greater than dimm max of 11.\n";
+ return -1;
+ }
+
+ auto dimm_config = GetDimmConfig(dimmnum);
+
+ uint8_t dimmSelect = dimmnum % 2; // dimm 0 or 1 for each config
+
+ auto val = peci_config_local(PECI_BASE_ADDR + cpunum, dimm_config->bus,
+ dimm_config->device, dimm_config->function,
+ PECI_DIMM_TEMP_REG + dimmSelect * 4, 4);
+
+ if (!val.size()) {
+ std::cout << "Peci Error\n";
+ return -1;
+ }
+
+ // TODO dimm offsets needed?
+
+ if (val[0] == 0)
+ std::cout << "Dimm " << unsigned(dimmnum) << " CPU " << unsigned(cpunum)
+ << " not populated.\n";
+ else if(val[0] == DIMM_DEFAULT_VALUE)
+ std::cout << "Dimm " << unsigned(dimmnum) << " CPU " << unsigned(cpunum)
+ << " in illegal state.\n";
+ else
+ std::cout << unsigned(val[0]) << " degrees C.\n";
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini b/meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini
new file mode 100644
index 000000000..619570dbb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/intel-signed-image/files/genimage-si.ini
@@ -0,0 +1,277 @@
+;
+; Copyright 2015 Intel Corporation.
+;
+; The source code, information and material ("Material") contained herein is
+; owned by Intel Corporation or its suppliers or licensors, and title to such
+; Material remains with Intel Corporation or its suppliers or licensors. The
+; Material contains proprietary information of Intel or its suppliers and
+; licensors. The Material is protected by worldwide copyright laws and treaty
+; provisions. No part of the Material may be used, copied, reproduced,
+; modified, published, uploaded, posted, transmitted, distributed or disclosed
+; in any way without Intel's prior express written permission. No license under
+; any patent, copyright or other intellectual property rights in the Material
+; is granted to or conferred upon you, either expressly, by implication,
+; inducement, estoppel or otherwise. Any license under such intellectual
+; property rights must be express and approved by Intel in writing.
+
+;
+; This file is similar to the config.genimage2 file of previous BMC
+; generations but it is not generated. It contains all of the information
+; to generate the signed-image variant of the signtool config file.
+;
+
+[GLOBAL]
+Major = 0
+Minor = 72
+Output = update.bin
+Alloc = 33792K ; 0x2100000
+BlockSize = 64K
+Type = 0xffffffff ; generate top level composite image
+Locate = 0
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Factory ROM file generation
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+RomOutput = rom-a-only.ima
+RomAlloc = 33M
+KeyRegion = Certificate
+NewKeyRegion = ReplacementCertificate
+SecVersion = 0
+
+
+
+; RecoveryOnly items should be place first in the image
+
+[FRISBEE_ROM]
+Major = 1
+Minor = 5
+Type = ROBL
+File = frisbee.bin
+Locate = 0x00000000
+Alloc = 240K
+Compress = 0
+SecVersion = 1
+Unsigned = 1
+
+[Certificate]
+Locate = 0x3c000
+Type = CERT
+Alloc = 8K
+Fill = 0xff
+Unsigned = 1
+ROMOnly = 1
+SecVersion = 0
+
+;[FWPRODUCTID]
+;Major = 1
+;Minor = 0
+;Type = FWID
+;File = fwproductid.bin
+;Locate = 0x0003f000
+;ROMOnly = 1
+;SecVersion = 0
+
+[FRISBEE_UPD]
+Major = 1
+Minor = 5
+Type = RWBL
+File = frisbee.bin
+Locate = 0x040000
+Alloc = 256K
+Compress = 0
+SecVersion = 1
+IndivSign = 1
+SigOffset = 0x03e000
+
+[U-Boot]
+Major = 1
+Minor = 5
+Type = UBT\x00
+File = u-boot.bin
+Alloc = 256K
+Compress = 0
+SecVersion = 1
+IndivSign = 1
+SigOffset = 0x03e000
+
+; Linux OS Image
+[OSIMAGE]
+Major = 1
+Minor = 1
+Type = LKNL
+File = uImage
+SecVersion = 1
+
+[DTB]
+Major = 1
+Minor = 1
+Type = DTB\x00
+File = uImage-aspeed-bmc-intel-purley.dtb
+SecVersion = 0
+
+; Root File System
+[ROOT]
+Major = 1
+Minor = 1
+Type = RtFS
+File = image-rofs.squashfs-xz.u-boot
+Load = 0x83000000
+SecVersion = 1
+;
+; WWW File System in CRAMFS.
+;[WWW]
+;Major = 1
+;Minor = 1
+;Type = WWW\x00
+;File = webfs.bin
+;BlockDev = 1
+;SecVersion = 1
+
+; Replacement certificate for re-keying the BMC
+; Will only be added to image if -rk is specified
+[ReplacementCertificate]
+Major = 1
+Minor = 1
+Type = CRT0
+Alloc = 4K
+SecVersion = 0
+Compress = 0
+IndivSign = 1
+Unbound = 1
+Fill = 0xff
+SigOffset = 0x800
+
+; Manifest goes here
+; This gets some special treatment (this needs to match the location
+; that Frisbee thinks the manifest is at or it won't boot)
+[Manifest]
+Major = 0
+Minor = 0
+Type = MFST
+Alloc = 4K
+Locate = 0x1bff000
+Fill = 0xff
+SecVersion = 0
+
+;
+; NV File System in JFFS2, but it is blank in the ROM version
+; and filled in with defaults from the rootfs
+[PARAMS]
+Major = 1
+Minor = 1
+Type = CONF
+Alloc = 4096K
+Locate = 0x1c00000
+ROMOnly = 1
+BlockDev = 1
+SecVersion = 1
+Unsigned = 1
+
+; notice that these sections have no file
+; and are marked as ROMOnly. This forces them
+; into the allocation so we don't get overlapping
+; sections, but does not actually put anything into
+; the rom at build time.
+
+[UBootEnv]
+Major = 1
+Minor = 0
+Type = UENV
+; File = ; no file makes this a placeholder
+Locate = 0x2000000
+Alloc = 64K
+BlockDev = 1
+ROMOnly = 1
+Unsigned = 1
+SecVersion = 0
+
+[FRUData]
+Major = 1
+Minor = 0
+Type = FRU\x00
+Alloc = 64K
+Locate = 0x2010000
+ROMOnly = 1
+Unsigned = 1
+SecVersion = 0
+
+[SEL]
+Major = 1
+Minor = 0
+Type = SEL\x00
+Alloc = 512K
+Locate = 0x2020000
+BlockDev = 1
+ROMOnly = 1
+Unsigned = 1
+SecVersion = 0
+
+; NV filesystem that survives reset mfg defaults.
+; OEM Web customization goes here.
+[PersistentNV]
+Major = 1
+Minor = 0
+Type = PNV\x00
+Alloc = 2048K
+Locate = 0x20a0000
+BlockDev = 1
+ROMOnly = 1
+Unsigned = 1
+SecVersion = 0
+
+[RubixLog]
+Major = 1
+Minor = 0
+Type = BTLG
+Alloc = 4K
+Locate = 0x23fe000
+BlockDev = 0
+ROMOnly = 1
+Unsigned = 1
+SecVersion = 0
+
+[BootPointer]
+Major = 1
+Minor = 0
+Type = BPTR
+Alloc = 4K
+Locate = 0x23ff000
+BlockDev = 0
+ROMOnly = 1
+Unsigned = 1
+SecVersion = 0
+
+;
+; Example Section with all possible fields with their default
+; values, unless the field is specified mandatory
+;
+;[EXAMPLE]
+;Major = 0 ; Major number of module
+;Minor = 0 ; Minor number of module
+;Type = TYPE ; four bytes hopefully human readable,
+; ; use c-style escapes if non-ascii, \x23\x10\x00\xf3
+; ; or use a number 0xf3001023
+;Alloc = X ; Maximum memory allocated; X = roundup
+;File = name ; File containing the module
+; ; If Alloc is specified, but no File, a blank
+; ; header will be created (only useful for ROMOnly)
+;Locate = addr ; Location in Flash; MANDATORY
+;ROMOnly = 1 ; if ROMOnly is set and non-zero, this section
+; ; will only be present in the ROM image, not the updater image
+;RecoveryOnly = 1 ; if RecoveryOnly is set and non-zero, this section
+; ; will only be present in the recovery image, not the active image
+;BlockDev = 1 ; this will make the signed image code export this
+; ; image as a mtd block device at runtime
+;Unsigned = 1 ; Do not include this section in signatures (NV data)
+;Compress = 1 ; compress image contents (useful for non-compressed items)
+;SecVersion = X ; a 16-bit security revision to enforce no downgrades
+;IndivSign = 1 ; section is individually signed; do not include in full signature
+;Unbound = 1 ; by default, individually signed sections are part of the
+; ; full signature too. This makes them independent
+;SigOffset = X ; offset within individually-signed section to place signature
+;Fill = xx ; fill with pattern xx instead of a file's contents
+;
+; Note: Numeric values can be represented either by decimal or a
+; hexadecimal (Prefixed by 0x)
+; Numeric values can either end with K or M to specify in
+; KiloBytes or MegaBytes
+;
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt
new file mode 100644
index 000000000..0c98160b9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
+project(io-app C)
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+add_executable(io io-app.c)
+install (TARGETS io DESTINATION bin)
+
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c
new file mode 100644
index 000000000..a5ffabd88
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c
@@ -0,0 +1,665 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// 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.
+//
+// Abstract: map io region to read or write to HW registers
+//
+*/
+
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+static int quiet = 0;
+
+static int dump(unsigned long phys, void *addr, size_t len)
+{
+ const uint32_t *ubuf = addr;
+ unsigned int wd = 0, l, iv;
+ unsigned char *h, *a;
+ char line[256];
+ static const char itoh[] = "0123456789abcdef";
+
+ /* 0 1 2 3 4 5 6
+ * 0123456789012345678901234567890123456789012345678901234567890123456789
+ * 00000000: 00000000 00000000 00000000 00000000 ................
+ */
+ while (wd < len)
+ {
+ memset(line, ' ', sizeof(line));
+ sprintf(line, "%08lx: ", phys + (wd*sizeof(uint32_t)));
+ a = (unsigned char*)&line[47];
+ h = (unsigned char*)&line[10];
+ for (l=0; l<4 && (l+wd)<len; l++)
+ {
+ uint32_t v = *ubuf++;
+ for (iv=0; iv<sizeof(v); iv++)
+ {
+ uint8_t b = v >> (8*((sizeof(v)-1)-iv));
+ *h++ = itoh[b>>4];
+ *h++ = itoh[b&0xf];
+ if (isprint(b))
+ *a++ = (char)b;
+ else
+ *a++ = '.';
+ }
+ *h++ = ' ';
+ }
+ *a++ = '\n';
+ *a = 0;
+ wd += l;
+ fputs(line, stdout);
+ }
+ return wd;
+}
+
+
+struct mapping
+{
+ unsigned long phys;
+ void *virt;
+ size_t len;
+};
+
+static struct mapping *maps = NULL;
+static int nr_maps = 0;
+
+static void unmap_all(void)
+{
+ int i;
+ for (i=0; i<nr_maps; i++)
+ {
+ if (maps[i].virt)
+ munmap(maps[i].virt, maps[i].len);
+ maps[i].virt = NULL;
+ }
+}
+
+int add_a_map(unsigned long phys, void *virt, size_t len)
+{
+ void *new_maps;
+ new_maps = realloc(maps, (nr_maps + 1) * sizeof(struct mapping));
+ if (!new_maps)
+ {
+ unmap_all();
+ munmap(virt, len);
+ }
+ else
+ {
+ maps = new_maps;
+ maps[nr_maps].phys = phys;
+ maps[nr_maps].virt = virt;
+ maps[nr_maps].len = len;
+ nr_maps++;
+ return 0;
+ }
+ return -1;
+}
+
+static void *map_fd(int fd, off_t offset, size_t len, int mode, int flags)
+{
+ void *mapped_at;
+ unsigned long phys = -1;
+
+ if (offset != -1)
+ phys = offset;
+ else
+ offset = 0;
+
+ mapped_at = mmap(NULL, len, mode, flags, fd, offset);
+ if (mapped_at != MAP_FAILED)
+ {
+ if (add_a_map(phys, mapped_at, len) != 0)
+ {
+ mapped_at = MAP_FAILED;
+ }
+ }
+
+ return mapped_at;
+}
+
+static void *map_file(const char *fname, size_t *len, int mode, int flags)
+{
+ int fd;
+ struct stat sb;
+ void *ptr;
+ int fmode;
+
+ if (mode & PROT_WRITE)
+ fmode = O_RDWR;
+ else
+ fmode = O_RDONLY;
+
+ fd = open(fname, fmode);
+ if (fd < 0)
+ return MAP_FAILED;
+
+ if (*len == 0)
+ {
+ fstat(fd, &sb);
+ *len = sb.st_size;
+ }
+ ptr = map_fd(fd, -1, *len, mode, flags);
+ close(fd);
+ return ptr;
+}
+
+static int load_maps(const char *cmap_str, size_t mlen)
+{
+ char *tmp_sa = NULL, *tmp_sl = NULL, *endptr = NULL;
+ const void *mapped = NULL;
+ int ret = 0;
+ const char *delim = "\r\n\t ,";
+ unsigned long addr;
+ size_t len;
+ char *map_str = NULL, *paddr = NULL, *plen = NULL;
+ int fd;
+
+ fd = open("/dev/mem", O_RDWR);
+ if (fd < 0)
+ {
+ return -1;
+ }
+
+ len = strlen(cmap_str);
+ map_str = (char *)malloc(len + 1);
+ if (!map_str)
+ {
+ close(fd);
+ return -1;
+ }
+ strncpy(map_str, cmap_str, len);
+ map_str[len] = '\0';
+ paddr = strtok_r(map_str, delim, &tmp_sa);
+ while (paddr)
+ {
+ /* find the next comma or newline */
+ if (!strtok_r(paddr, ":", &tmp_sl))
+ {
+ fprintf(stderr, "malformed map string '%s'\n", paddr);
+ goto _loop;
+ }
+ plen = strtok_r(NULL, ":", &tmp_sl);
+ if (!plen)
+ {
+ goto _loop;
+ }
+ addr = strtoul(paddr, &endptr, 16);
+ if (*endptr)
+ {
+ fprintf(stderr, "Failed to parse address from '%s'\n", paddr);
+ ret = -1;
+ break;
+ }
+ len = strtoul(plen, &endptr, 16);
+ if (*endptr)
+ {
+ fprintf(stderr, "Failed to parse len from '%s'\n", plen);
+ ret = -1;
+ break;
+ }
+ if (MAP_FAILED == (mapped = map_fd(fd, addr, len, PROT_READ|PROT_WRITE, MAP_SHARED)))
+ {
+ fprintf(stderr, "Failed to map %lx +%x\n", addr, len);
+ ret = -1;
+ break;
+ }
+ if (!quiet)
+ printf("added map: %p (%lx..%lx)\n", mapped, addr, addr+len);
+_loop:
+ paddr = strtok_r(NULL, delim, &tmp_sa);
+ }
+ free(map_str);
+ close(fd);
+ return ret;
+}
+
+int md(unsigned long addr, uint32_t unused, size_t len)
+{
+ int i, j;
+
+ (void)unused;
+ for (i=0; i<nr_maps; i++)
+ {
+ if (-1 == maps[i].phys)
+ continue;
+ if (maps[i].phys <= addr &&
+ (addr + len * sizeof(uint32_t)) < (maps[i].phys + maps[i].len))
+ {
+ uint32_t *buf, *pv;
+
+ buf = (uint32_t *)malloc(len*sizeof(uint32_t));
+ if (!buf)
+ return 1;
+ pv = (uint32_t *)(maps[i].virt + (addr - maps[i].phys));
+ for (j=0; j<len; j++)
+ buf[j] = *pv++;
+
+ dump(addr, buf, len);
+ free(buf);
+ return 0;
+ }
+ }
+ fprintf(stderr, "%lx +%x not in mapped memory\n", addr, len);
+ return 1;
+}
+
+int mw(unsigned long addr, uint32_t val, size_t len)
+{
+ int i, j;
+
+ for (i=0; i<nr_maps; i++)
+ {
+ if (-1 == maps[i].phys)
+ continue;
+ if (maps[i].phys <= addr &&
+ (addr + len * sizeof(uint32_t)) < (maps[i].phys + maps[i].len))
+ {
+ for (j=0; j<len; j++)
+ {
+ *((uint32_t*)(maps[i].virt + (addr - maps[i].phys))) = val;
+ }
+ return 0;
+ }
+ }
+ fprintf(stderr, "%lx +%x not in mapped memory\n", addr, len);
+ return 1;
+}
+
+char *readline(char *buf, size_t len, FILE *f)
+{
+ int raw = 0;
+ size_t br = 0;
+ struct termios tios, orig_tios;
+
+ if (!quiet)
+ {
+ /* put terminal in raw mode to get unbuffered io */
+ if (tcgetattr(fileno(f), &orig_tios) == 0)
+ {
+ tios = orig_tios;
+ tios.c_iflag |= IGNPAR;
+ tios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
+ tios.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN);
+ tios.c_oflag &= ~OPOST;
+ tios.c_cc[VMIN] = 1;
+ tios.c_cc[VTIME] = 0;
+ tcsetattr(fileno(f), TCSADRAIN, &tios);
+ raw = 1;
+ }
+ }
+ if (!raw)
+ {
+ return fgets(buf, len, f);
+ }
+ /* read in bytes one at a time and echo them */
+ while (br < (len-1))
+ {
+ int c = fgetc(f);
+ switch (c)
+ {
+ case 3: /* ^C */
+ br = 0;
+ c = '\n';
+ break;
+ case 4:
+ br = 0;
+ c = -1;
+ break;
+ case '\b':
+ if (br > 0)
+ {
+ fputs("\b \b", stdout);
+ br--;
+ }
+ break;
+ case '\r':
+ case '\n':
+ fputs("\r\n", stdout);
+ buf[br++] = '\n';
+ break;
+ case ' '...'~':
+ fputc(c, stdout);
+ buf[br++] = c;
+ break;
+ break;
+ default:
+ break;
+ }
+ if (c == -1)
+ {
+ if (br == 0)
+ buf = NULL;
+ break;
+ }
+ if (c == '\r' || c == '\n')
+ break;
+ }
+ if (buf)
+ buf[br] = 0;
+
+ tcsetattr(fileno(f), TCSADRAIN, &orig_tios);
+ return buf;
+}
+
+#define MAX_LINE_LEN 4096
+int io(void)
+{
+ const char delim1[] = "\r\n;";
+ const char delim2[] = "\t ";
+ char line[MAX_LINE_LEN];
+ char *command, *cmd, *paddr, *pval, *plen, *endptr;
+ char *tmp_s1, *tmp_s2;
+ unsigned long addr;
+ uint32_t val;
+ size_t len;
+ int (*fn)(unsigned long, uint32_t, size_t);
+
+ if (!quiet)
+ fputs("> ", stdout);
+ while (readline(line, MAX_LINE_LEN, stdin) != NULL && *line)
+ {
+ /* read next line or next command (up to newline or ';') */
+ command = strtok_r(line, delim1, &tmp_s1);
+ if (!command || strlen(command) == 0)
+ goto _command_loop;
+ while (NULL != command && strlen(command) > 0)
+ {
+ cmd = strtok_r(command, delim2, &tmp_s2);
+ if (!cmd)
+ goto _cmd_err;
+ if (cmd[0] == 'q' || cmd[0] == 'Q')
+ return 0;
+ paddr = strtok_r(NULL, delim2, &tmp_s2);
+ if (!paddr)
+ goto _cmd_err;
+ addr = strtoul(paddr, &endptr, 16);
+ if (*endptr)
+ goto _cmd_err;
+ fn = NULL;
+ if (strncmp(cmd, "mw", 3) == 0)
+ {
+ fn = mw;
+ pval = strtok_r(NULL, delim2, &tmp_s2);
+ if (!pval)
+ goto _cmd_err;
+ val = strtoul(pval, &endptr, 16);
+ if (*endptr)
+ goto _cmd_err;
+ len = 1;
+ }
+ else if (strncmp(cmd, "md", 3) == 0)
+ {
+ fn = md;
+ len = 0x40;
+ val = 0;
+ }
+ else
+ {
+ goto _cmd_err;
+ }
+ plen = strtok_r(NULL, delim2, &tmp_s2);
+ if (plen)
+ {
+ len = strtoul(plen, &endptr, 16);
+ if (*endptr)
+ goto _cmd_err;
+ }
+
+ if (fn)
+ fn(addr, val, len);
+
+ command = strtok_r(NULL, delim1, &tmp_s1);
+ }
+_command_loop:
+ if (!quiet)
+ fputs("> ", stderr);
+ continue;
+_cmd_err:
+ fprintf(stderr, "md addr [len]\nmw addr val [len]\n"
+ "q[uit] | ctrl-d | ctrl-c to exit\n");
+ if (!quiet)
+ fputs("> ", stderr);
+ }
+ return 0;
+}
+
+typedef enum
+{
+ CPU_NONE = 0,
+ CPU_PILOT3,
+ CPU_PILOT4,
+ CPU_AST2500,
+ CPU_MAX,
+} CPU_TYPE;
+
+static CPU_TYPE probe_cpu(void)
+{
+ FILE *f;
+ char cpuinfo[128];
+ static CPU_TYPE this_cpu = CPU_NONE;
+
+ if (CPU_NONE == this_cpu)
+ {
+ f = fopen("/sys/firmware/devicetree/base/compatible", "r");
+ if (f) {
+ int br = fread(cpuinfo, 1, sizeof(cpuinfo)-1, f);
+ if (br > 0) {
+ cpuinfo[br] = 0;
+ char *v = cpuinfo;
+ while (v < (cpuinfo + sizeof(cpuinfo)) && *v) {
+ if (strncmp("aspeed,ast2500", v, 15) == 0)
+ {
+ if (!quiet)
+ fprintf(stderr, "AST2500\n");
+ this_cpu = CPU_AST2500;
+ }
+ v += 1 + strnlen(v, sizeof(cpuinfo) - (v - cpuinfo));
+ }
+ }
+ fclose(f);
+ }
+ }
+ if (CPU_NONE == this_cpu)
+ {
+ const char delim[] = "\r\n\t :";
+ char *tmp_s;
+ f = fopen("/proc/cpuinfo", "r");
+ if (f != NULL) {
+ while (fgets(cpuinfo, sizeof(cpuinfo), f))
+ {
+ strtok_r(cpuinfo, delim, &tmp_s);
+ if (strncmp("Hardware", cpuinfo, 9) == 0)
+ {
+ char *v = strtok_r(NULL, delim, &tmp_s);
+ if (v)
+ {
+ if (strncmp("AST2500", v, 8) == 0)
+ {
+ if (!quiet)
+ fprintf(stderr, "AST2500\n");
+ this_cpu = CPU_AST2500;
+ }
+ else if (strncmp("ASpeed SoC", v, 11) == 0)
+ {
+ if (!quiet)
+ fprintf(stderr, "Found ASpeed SoC\n");
+ this_cpu = CPU_AST2500;
+ }
+ else if (strncmp("ServerEngines PILOT3", v, 21) == 0)
+ {
+ if (!quiet)
+ fprintf(stderr, "Found PILOT3\n");
+ this_cpu = CPU_PILOT3;
+ }
+ }
+ break;
+ }
+ }
+ fclose(f);
+ }
+ }
+ return this_cpu;
+}
+
+static const char *probe_cpu_for_map(void)
+{
+ switch (probe_cpu())
+ {
+ case CPU_PILOT3:
+ return "0:2000000,10000000:8000,40000000:43b000";
+ case CPU_AST2500:
+ return "0:4000000,1e600000:1a0000,20000000:4000000";
+ default:
+ return "";
+ }
+}
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: io [-c config] [-m map]\n"
+ " md [-c config] [-m map] <addr> [len]\n"
+ " mw [-c config] [-m map] <addr> <val> [len]\n\n"
+ "With: -c config load mappings from file config\n"
+ " -m map load mappings from string map\n"
+ " addr, val, len are all hex numbers\n\n"
+ "When invoked as io, this will start a shell that will\n"
+ "allow the user to type in md and mw commands much like\n"
+ "the U-Boot environment. By default, it will map in all\n"
+ "the addresses for the known processor type.\n\n"
+ "map string is of the format addr:len[,addr2:len2...]\n"
+ "config file is of the same format as map string\n"
+ "but with each mapping on separate lines instead of\n"
+ "comma separated values\n"
+ );
+ exit(1);
+}
+
+#define shift if (++i >= argc) usage()
+
+int main(int argc, const char *argv[])
+{
+ char *exe_full;
+ char *exe;
+ char *endptr;
+ int i, first_arg = 1;
+ const char *cfg_file = NULL;
+ const char *map_str = NULL;
+ size_t flen = 0;
+ size_t len = 0;
+ unsigned long addr;
+ uint32_t val;
+ int ret = 0;
+
+ i = 1;
+ while (i < argc)
+ {
+ if (argv[i][0] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'm':
+ shift;
+ map_str = argv[i];
+ break;
+ case 'c':
+ shift;
+ cfg_file = argv[i];
+ break;
+ default:
+ usage();
+ }
+ }
+ else
+ {
+ first_arg = i;
+ break;
+ }
+ }
+
+ exe_full = strdup(argv[0]);
+ if (exe_full != NULL )
+ exe = basename(exe_full);
+ else
+ return ret;
+
+ if (strncmp(exe, "io", 3) != 0 || !isatty(fileno(stdin)))
+ quiet = 1;
+
+ if (!map_str)
+ {
+ if (!cfg_file)
+ map_str = probe_cpu_for_map();
+ else
+ map_str = map_file(cfg_file, &flen, PROT_READ, MAP_PRIVATE);
+ }
+ else
+ {
+ flen = strlen(map_str);
+ }
+ if (load_maps(map_str, flen) < 0)
+ {
+ fprintf(stderr, "failed to map regions: check map string or config file\n");
+ goto _cleanup;
+ }
+
+ if (strncmp(exe, "md", 3) == 0)
+ {
+ len = 0x40;
+ addr = strtoul(argv[first_arg], &endptr, 16);
+ if ((first_arg + 1) < argc)
+ {
+ len = strtoul(argv[first_arg + 1], &endptr, 16);
+ }
+ ret = md(addr, 0, len);
+ goto _cleanup;
+ }
+
+ if (strncmp(exe, "mw", 3) == 0)
+ {
+ len = 1;
+ addr = strtoul(argv[first_arg], &endptr, 16);
+ if ((first_arg + 1) < argc)
+ {
+ val = strtoul(argv[first_arg + 1], &endptr, 16);
+ }
+ else
+ {
+ usage();
+ }
+ if ((first_arg + 2) < argc)
+ {
+ len = strtoul(argv[first_arg + 2], &endptr, 16);
+ }
+ ret = mw(addr, val, len);
+ goto _cleanup;
+ }
+
+ io();
+
+_cleanup:
+ unmap_all();
+ free(exe_full);
+ return ret;
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb
new file mode 100644
index 000000000..5ac0f0a75
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/io-app.bb
@@ -0,0 +1,17 @@
+SUMMARY = "IO App"
+DESCRIPTION = "IO application for accessing memory-mapped IO regions on the BMC"
+
+inherit cmake
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM += "\
+ file://io-app.c;beginline=2;endline=14;md5=639666a0bf40bb717b46b378297eeceb \
+ "
+
+SRC_URI = "\
+ file://CMakeLists.txt \
+ file://io-app.c \
+ "
+
+S = "${WORKDIR}"
+
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt
new file mode 100644
index 000000000..1cde22b49
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
+project(lpc-cmds C)
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+add_executable(lpc_cmds lpc_cmds.c)
+install (TARGETS lpc_cmds DESTINATION bin)
+
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c
new file mode 100644
index 000000000..2cdf66d88
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c
@@ -0,0 +1,479 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// 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.
+//
+//
+*/
+
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include "lpc_drv.h"
+
+#define SIO_DEVICE_NAME "/dev/lpc-sio"
+#define KCS_DEVICE_NAME "/dev/ipmi-kcs"
+#define MAILBOX_DEVICE_NAME "/dev/aspeed-mbox"
+#define SNOOP_DEVICE_NAME "/dev/aspeed-lpc-snoop"
+
+#define SNOOP_BUF_SIZE 4096
+
+#define SUPPORT_KCS_ADDR_CMD 0
+#define SUPPORT_MAILBOX 1
+#define SUPPORT_SNOOP 1
+
+/*********************************************************************************/
+static void ProcessKCSReq(int fd, unsigned char *pReq, int ReqLen, int NoPrint)
+{
+ int i;
+ unsigned char SendPkt[16];
+
+ if (!NoPrint) {
+ printf("\nKCS Request >>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+ for (i = 0; i < ReqLen; i++)
+ printf("%02X ", pReq[i]);
+ printf("\n======================================\n");
+ }
+
+ SendPkt[0] = pReq[0] | 0x04;
+ SendPkt[1] = pReq[1];
+ SendPkt[2] = 0xC1; /* Always Invalid Command */
+
+ if (!NoPrint) {
+ printf("\nKCS Response <<<<<<<<<<<<<<<<<<<<<<<<<\n");
+ for (i = 0; i < 3; i++)
+ printf("%02X ", SendPkt[i]);
+ printf("\n======================================\n");
+ }
+
+ write(fd, SendPkt, 3);
+}
+
+static void KCSIfcTask(int KCSIfcIdx, int NoPrint)
+{
+ int fd;
+ int RecvPktLen;
+ char KCSDev[16];
+ struct kcs_ioctl_data IOData;
+ unsigned char RecvPkt[512];
+
+ snprintf(KCSDev, sizeof(KCSDev), KCS_DEVICE_NAME"%d", KCSIfcIdx);
+ fd = open(KCSDev, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ printf("Error open KCS device: %s\n", KCSDev);
+ exit(1);
+ }
+
+ IOData.cmd = KCS_FORCE_ABORT;
+ IOData.data = 0;
+ ioctl(fd, KCS_IOC_COMMAND, &IOData);
+
+ while (1) {
+ RecvPktLen = read(fd, RecvPkt, sizeof(RecvPkt));
+ if (RecvPktLen < 2)
+ continue;
+
+ ProcessKCSReq(fd, RecvPkt, RecvPktLen, NoPrint);
+ }
+}
+
+#if SUPPORT_KCS_ADDR_CMD
+static void KCSIfcSetAddr(int KCSIfcIdx, unsigned int addr)
+{
+ int fd;
+ struct kcs_ioctl_data kcs_data;
+ char KCSDev[16];
+
+ snprintf(KCSDev, sizeof(KCSDev), KCS_DEVICE_NAME"%d", KCSIfcIdx);
+ fd = open(KCSDev, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ printf("Error open KCS device: %s\n", KCSDev);
+ exit(1);
+ }
+
+ kcs_data.cmd = KCS_SET_ADDR;
+ kcs_data.data = addr;
+ if (ioctl(fd, KCS_IOC_COMMAND, &kcs_data) == 0)
+ printf("Set KCS%d addr to 0x%X successfully!\n", KCSIfcIdx + 1, addr);
+
+ close(fd);
+}
+
+static void KCSIfcGetAddr(int KCSIfcIdx)
+{
+ int fd;
+ struct kcs_ioctl_data kcs_data;
+ char KCSDev[16];
+
+ snprintf(KCSDev, sizeof(KCSDev), KCS_DEVICE_NAME"%d", KCSIfcIdx);
+ fd = open(KCSDev, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ printf("Error open KCS device: %s\n", KCSDev);
+ exit(1);
+ }
+
+ kcs_data.cmd = KCS_GET_ADDR;
+ if (ioctl(fd, KCS_IOC_COMMAND, &kcs_data) == 0)
+ printf("KCS%d addr is : 0x%X!\n", KCSIfcIdx + 1, kcs_data.data);
+
+ close(fd);
+}
+#endif
+
+/*********************************************************************************/
+
+#if SUPPORT_SNOOP
+static void ReadBiosPOSTCodes(unsigned int if_idx)
+{
+ char snoop_dev[32];
+ int fd;
+ int i;
+ unsigned char buf[SNOOP_BUF_SIZE];
+ int len;
+
+ snprintf(snoop_dev, sizeof(snoop_dev), SNOOP_DEVICE_NAME"%d", if_idx);
+ fd = open(snoop_dev, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+ if (fd < 0) {
+ printf("Error open %s !\n", snoop_dev);
+ return;
+ }
+
+ len = read(fd, &buf, sizeof(buf));
+
+ if (len == 0 || errno == EAGAIN) {
+ printf("No BIOS POST Codes Found!\n");
+ goto out;
+ } else if (len < 0) {
+ printf("Failed to read the POST Codes! (%s)\n",
+ strerror(errno));
+ goto out;
+ }
+
+ printf("BIOS POST Codes in Hex (%d entries):\n", len);
+
+ for (i = 0; i < len; i++)
+ printf(" %d: %02X\n", i, buf[i]);
+
+ printf("\n");
+
+out:
+ close(fd);
+}
+#endif
+
+/*********************************************************************************/
+
+static void SIOGetACPIState(unsigned short changed)
+{
+ int fd;
+ struct sio_ioctl_data sio_data;
+
+ fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ printf("Error open %s\n", SIO_DEVICE_NAME);
+ exit(1);
+ }
+
+ sio_data.sio_cmd = SIO_GET_ACPI_STATE;
+ sio_data.param = changed;
+
+ if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) {
+ if (changed)
+ printf("ACPI SLP state is %s!\n",
+ sio_data.param != 0 ? "Changed" : "Same");
+
+ if (sio_data.data == ACPI_STATE_S12)
+ printf("ACPI SLP state --> SLP_12\n");
+ else if (sio_data.data == ACPI_STATE_S3I)
+ printf("ACPI SLP state --> SLP_3I\n");
+ else if (sio_data.data == ACPI_STATE_S45)
+ printf("ACPI SLP state --> SLP_45\n");
+ }
+
+ close(fd);
+}
+
+static void SIOGetPWRGDStatus(unsigned short changed)
+{
+ int fd;
+ struct sio_ioctl_data sio_data;
+
+ fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ printf("Error open %s\n", SIO_DEVICE_NAME);
+ exit(1);
+ }
+
+ sio_data.sio_cmd = SIO_GET_PWRGD_STATUS;
+ sio_data.param = changed;
+
+ if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0) {
+ if (changed)
+ printf("PWRGD status : %s\n",
+ sio_data.param != 0 ? "Changed" : "Same");
+
+ printf("PWRGD status value :%u\n", sio_data.data);
+ }
+
+ close(fd);
+}
+
+static void SIOGetONCTLStatus(void)
+{
+ int fd;
+ struct sio_ioctl_data sio_data;
+
+ fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ printf("Error open %s\n", SIO_DEVICE_NAME);
+ exit(1);
+ }
+
+ sio_data.sio_cmd = SIO_GET_ONCTL_STATUS;
+
+ if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0)
+ printf("ONCTL status value :%u\n", sio_data.data);
+
+ close(fd);
+}
+
+static void SIOSetONCTLGPIO(unsigned short enable, unsigned int value)
+{
+ int fd;
+ struct sio_ioctl_data sio_data;
+
+ fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ printf("Error open %s\n", SIO_DEVICE_NAME);
+ exit(1);
+ }
+
+ sio_data.sio_cmd = SIO_SET_ONCTL_GPIO;
+ sio_data.param = enable;
+ sio_data.data = value;
+
+ if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0)
+ printf("ONCTL GPIO mode setting is Done!\n");
+
+ close(fd);
+}
+
+static void SIOGetPWRBTNOverride(unsigned short clear)
+{
+ int fd;
+ struct sio_ioctl_data sio_data;
+
+ fd = open(SIO_DEVICE_NAME, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ printf("Error open %s\n", SIO_DEVICE_NAME);
+ exit(1);
+ }
+
+ sio_data.sio_cmd = SIO_GET_PWRBTN_OVERRIDE;
+ sio_data.param = clear;
+
+ if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0)
+ printf("PWRBTN Override status : %u\n", sio_data.data);
+
+ close(fd);
+}
+
+/*********************************************************************************/
+
+#if SUPPORT_MAILBOX
+static void MailBoxRead(int num)
+{
+ int fd;
+ int len;
+ uint8_t data;
+
+ fd = open(MAILBOX_DEVICE_NAME, O_RDWR | O_NONBLOCK | O_CLOEXEC);
+ if (fd < 0) {
+ printf("Error open mailbox\n");
+ exit(1);
+ }
+
+ len = pread(fd, &data, 1, num);
+ if (len == 0 || errno == EAGAIN) {
+ printf("No mailbox message found!\n");
+ goto out;
+ } else if (len < 0) {
+ printf("Error reading from mailbox%d! (%s)\n", num,
+ strerror(errno));
+ goto out;
+ }
+
+ printf("MailBox%d read value : 0x%02X\n", num, data);
+
+out:
+ close(fd);
+}
+
+static void MailBoxWrite(int num, uint8_t value)
+{
+ int fd;
+ ssize_t rc;
+
+ fd = open(MAILBOX_DEVICE_NAME, O_RDWR | O_NONBLOCK | O_CLOEXEC);
+ if (fd < 0) {
+ printf("Error open mailbox\n");
+ exit(1);
+ }
+
+ rc = pwrite(fd, &value, 1, num);
+
+ if (rc == 1)
+ printf("MailBox%d write value : 0x%02X done!\n", num, value);
+ else
+ printf("Error writing to mailbox%d, rc: %d\n", num, rc);
+
+ close(fd);
+}
+#endif
+
+/*********************************************************************************/
+
+static void usage(void)
+{
+ printf("Usage:\n"
+ "\tlpc_cmds sio get_acpi_state\n"
+ "\tlpc_cmds sio get_acpi_changed\n"
+ "\tlpc_cmds sio get_pwrgd_status\n"
+ "\tlpc_cmds sio get_pwrgd_changed\n"
+ "\tlpc_cmds sio get_onctl_status\n"
+ "\tlpc_cmds sio set_onctl_gpio_disable\n"
+ "\tlpc_cmds sio set_onctl_gpio_high\n"
+ "\tlpc_cmds sio set_onctl_gpio_low\n"
+ "\tlpc_cmds sio get_pwrbtn_override_status\n"
+ "\tlpc_cmds sio get_pwrbtn_override_status_clear\n"
+ "\n"
+#if SUPPORT_KCS_ADDR_CMD
+ "\tlpc_cmds kcs [1 ~ 4] (getaddr / setaddr / quiet)\n"
+#else
+ "\tlpc_cmds kcs [1 ~ 4] (quiet)\n"
+#endif
+#if SUPPORT_MAILBOX
+ "\n"
+ "\tlpc_cmds mailbox read (0 ~ 15)\n"
+ "\tlpc_cmds mailbox write (0 ~ 15) (0x00 ~ 0xFF)\n"
+#endif
+#if SUPPORT_SNOOP
+ "\n"
+ "\tlpc_cmds snoop [0 ~ 1] read\n"
+#endif
+ );
+
+ exit(-1);
+}
+
+int main(int argc, char** argv)
+{
+ char *cmd;
+
+ if (argc < 2)
+ usage();
+
+ cmd = argv[1];
+
+ if (strcmp(cmd, "sio") == 0) {
+ if (argc < 3)
+ usage();
+
+ if (strcmp(argv[2], "get_acpi_state") == 0)
+ SIOGetACPIState(0);
+ else if (strcmp(argv[2], "get_acpi_changed") == 0)
+ SIOGetACPIState(1);
+ else if (strcmp(argv[2], "get_pwrgd_status") == 0)
+ SIOGetPWRGDStatus(0);
+ else if (strcmp(argv[2], "get_pwrgd_changed") == 0)
+ SIOGetPWRGDStatus(1);
+ else if (strcmp(argv[2], "get_onctl_status") == 0)
+ SIOGetONCTLStatus();
+ else if (strcmp(argv[2], "set_onctl_gpio_disable") == 0)
+ SIOSetONCTLGPIO(0, 0);
+ else if (strcmp(argv[2], "set_onctl_gpio_high") == 0)
+ SIOSetONCTLGPIO(1, 1);
+ else if (strcmp(argv[2], "set_onctl_gpio_low") == 0)
+ SIOSetONCTLGPIO(1, 0);
+ else if (strcmp(argv[2], "get_pwrbtn_override_status") == 0)
+ SIOGetPWRBTNOverride(0);
+ else if (strcmp(argv[2], "get_pwrbtn_override_status_clear") == 0)
+ SIOGetPWRBTNOverride(1);
+ } else if (strcmp(cmd, "kcs") == 0) {
+ int ifc;
+
+ if (argc < 3)
+ usage();
+
+ ifc = atoi(argv[2]);
+ if (ifc < 1 || ifc > 4) /* ipmi-kcs1 ~ ipmi-kcs4 */
+ usage();
+
+ if (argc == 3)
+ KCSIfcTask(ifc, 0);
+ else if (argc == 4 && strcmp(argv[3], "quiet") == 0)
+ KCSIfcTask(ifc, 1);
+#if SUPPORT_KCS_ADDR_CMD
+ else if (argc == 4 && strcmp(argv[3], "getaddr") == 0)
+ KCSIfcGetAddr(ifc);
+ else if (argc == 5 && strcmp(argv[3], "setaddr") == 0)
+ KCSIfcSetAddr(ifc, strtoul(argv[4], NULL, 16));
+#endif
+#if SUPPORT_MAILBOX
+ } else if (strcmp(cmd, "mailbox") == 0) {
+ if (argc < 4)
+ usage();
+
+ if (strcmp(argv[2], "read") == 0) {
+ MailBoxRead(atoi(argv[3]));
+ } else {
+ if (argc < 5)
+ usage();
+ MailBoxWrite(atoi(argv[3]), strtoul(argv[4], NULL, 16));
+ }
+#endif
+#if SUPPORT_SNOOP
+ } else if (strcmp(cmd, "snoop") == 0) {
+ int ifc;
+
+ if (argc < 3)
+ usage();
+
+ ifc = atoi(argv[2]);
+ if (ifc < 0 || ifc > 1) /* snoop0 ~ snoop1 */
+ usage();
+
+ if (strcmp(argv[3], "read") == 0)
+ ReadBiosPOSTCodes(ifc);
+ else
+ usage();
+#endif
+ }
+
+ return 0;
+}
+
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h
new file mode 100644
index 000000000..56c79d1c1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h
@@ -0,0 +1,78 @@
+/*
+// Copyright (c) 2017 Intel Corporation
+//
+// 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.
+//
+//
+*/
+
+#ifndef __LPC_DRV_H__
+#define __LPC_DRV_H__
+
+#define LPC_DEV_MAJOR 250
+#define LPC_DEV_MINOR 0
+
+/***********************************************************************************/
+
+enum KCS_CMD {
+ KCS_SET_ADDR = 0,
+ KCS_GET_ADDR,
+ KCS_SMS_ATN,
+ KCS_FORCE_ABORT,
+};
+
+struct kcs_ioctl_data {
+ unsigned int cmd;
+ unsigned int data;
+};
+
+#define KCS_IOC_BASE 'K'
+#define KCS_IOC_COMMAND _IOWR(KCS_IOC_BASE, 1, struct kcs_ioctl_data)
+
+/***********************************************************************************/
+
+enum ACPI_SLP_STATE {
+ ACPI_STATE_S12 = 1,
+ ACPI_STATE_S3I,
+ ACPI_STATE_S45
+};
+
+/* SWC & ACPI for SuperIO IOCTL */
+enum SIO_CMD {
+ SIO_GET_ACPI_STATE = 0,
+ SIO_GET_PWRGD_STATUS,
+ SIO_GET_ONCTL_STATUS,
+ SIO_SET_ONCTL_GPIO,
+ SIO_GET_PWRBTN_OVERRIDE,
+ SIO_GET_PFAIL_STATUS, /* Start from AC Loss */
+
+ SIO_MAX_CMD
+};
+
+struct sio_ioctl_data {
+ unsigned short sio_cmd;
+ unsigned short param;
+ unsigned int data;
+};
+
+#define SIO_IOC_BASE 'P'
+#define SIO_IOC_COMMAND _IOWR(SIO_IOC_BASE, 1, struct sio_ioctl_data)
+
+/***********************************************************************************/
+
+#define MAX_MAILBOX_NUM 16
+
+/***********************************************************************************/
+
+#endif
+
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb
new file mode 100644
index 000000000..2fbb1eb2f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb
@@ -0,0 +1,16 @@
+SUMMARY = "LPC tools"
+DESCRIPTION = "command tool for LPC interface test on the BMC"
+
+inherit cmake
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${PHOSPHORBASE}/LICENSE;md5=19407077e42b1ba3d653da313f1f5b4e"
+
+SRC_URI = "\
+ file://CMakeLists.txt \
+ file://lpc_drv.h \
+ file://lpc_cmds.c \
+ "
+
+S = "${WORKDIR}"
+
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py
new file mode 100755
index 000000000..977fcd3a0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/files/peci-hwmon-test.py
@@ -0,0 +1,144 @@
+#!/usr/bin/python
+
+import glob
+import os
+import sys
+import time
+
+if len(sys.argv) == 1:
+ cpuno = 0
+else:
+ cpuno = int(sys.argv[1])
+
+hwmon_path = '/sys/class/hwmon'
+cputemp_name_match = '{}{}'.format('peci_cputemp.cpu', cpuno)
+dimmtemp_name_match = '{}{}'.format('peci_dimmtemp.cpu', cpuno)
+
+dimmtemp_path = ''
+
+os.chdir(hwmon_path)
+
+for dirpath, dirnames, files in os.walk(hwmon_path):
+ for d in dirnames:
+ try:
+ with open('{}/{}'.format(d, 'name')) as f:
+ hwmon_name = f.read().strip()
+ if hwmon_name == cputemp_name_match:
+ cputemp_path = os.path.abspath(d)
+ cputemp_name = hwmon_name
+ elif hwmon_name == dimmtemp_name_match:
+ dimmtemp_path = os.path.abspath(d)
+ dimmtemp_name = hwmon_name
+ except:
+ continue
+
+if not cputemp_path:
+ print "Can't find the " + cputemp_name_match
+ quit()
+
+try:
+ while True:
+ os.system('clear')
+ os.chdir(cputemp_path)
+
+ print '{}/{}: {}'.format(hwmon_path, cputemp_path, cputemp_name)
+ if dimmtemp_path:
+ print '{}/{}: {}'.format(hwmon_path, dimmtemp_path, dimmtemp_name)
+
+ print
+ print 'Package temperature'
+ for input in glob.glob('temp[1-5]_input'):
+ try:
+ with open(input) as f:
+ val = f.read().strip()
+ except IOError:
+ val = 0
+ try:
+ with open(input.replace('input', 'label')) as l:
+ name = l.read().strip()
+ except IOError:
+ name = ''
+ print '{:11s}:{:3d}.{:03d}'.format(
+ name, (int(val) / 1000), (int(val) % 1000))
+
+ print
+ print 'Core temperature'
+ count = 0
+ for input in glob.glob('temp[!1-5]_input'):
+ try:
+ with open(input) as f:
+ val = f.read().strip()
+ except IOError:
+ val = 0
+ try:
+ with open(input.replace('input', 'label')) as l:
+ name = l.read().strip()
+ except IOError:
+ name = ''
+ print ('{:9s}:{:3d}.{:03d}'.format(
+ name, (int(val) / 1000), (int(val) % 1000))),
+ count += 1
+ if count % 3 == 0:
+ print
+ else:
+ print ('\t'),
+ for input in glob.glob('temp??_input'):
+ try:
+ with open(input) as f:
+ val = f.read().strip()
+ except IOError:
+ val = 0
+ try:
+ with open(input.replace('input', 'label')) as l:
+ name = l.read().strip()
+ except IOError:
+ name = ''
+ print ('{:9s}:{:3d}.{:03d}'.format(
+ name, (int(val) / 1000), (int(val) % 1000))),
+ count += 1
+ if count % 3 == 0:
+ print
+ else:
+ print ('\t'),
+ print
+
+ if dimmtemp_path:
+ os.chdir(dimmtemp_path)
+ print
+ print 'DIMM temperature'
+ count = 0
+ for input in glob.glob('temp*_input'):
+ try:
+ with open(input) as f:
+ val = f.read().strip()
+ except IOError:
+ val = 0
+ try:
+ with open(input.replace('input', 'label')) as l:
+ name = l.read().strip()
+ except IOError:
+ name = ''
+ print ('{:9s}:{:3d}.{:03d}'.format(
+ name, (int(val) / 1000), (int(val) % 1000))),
+ count += 1
+ if count % 3 == 0:
+ print
+ else:
+ print ('\t'),
+ print
+ else:
+ os.chdir(hwmon_path)
+ for dirpath, dirnames, files in os.walk(hwmon_path):
+ for d in dirnames:
+ try:
+ with open('{}/{}'.format(d, 'name')) as f:
+ hwmon_name = f.read().strip()
+ if hwmon_name == dimmtemp_name_match:
+ dimmtemp_path = os.path.abspath(d)
+ dimmtemp_name = hwmon_name
+ except:
+ continue
+
+ time.sleep(1)
+except KeyboardInterrupt:
+ print " exiting..."
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb
new file mode 100644
index 000000000..b3b4096a6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/peci-hwmon-test/peci-hwmon-test.bb
@@ -0,0 +1,20 @@
+SUMMARY = "PECI hwmon test tool"
+DESCRIPTION = "command line python tool for testing PECI hwmon"
+
+SRC_URI = "\
+ file://peci-hwmon-test.py \
+ "
+LICENSE = "CLOSED"
+
+RDEPENDS_${PN} += "python"
+
+S = "${WORKDIR}"
+
+do_compile () {
+}
+
+do_install () {
+ install -d ${D}/${bindir}
+ install -m 0755 ${WORKDIR}/peci-hwmon-test.py ${D}/${bindir}
+}
+
diff --git a/meta-openbmc-mods/meta-wolfpass/conf/bblayers.conf.sample b/meta-openbmc-mods/meta-wolfpass/conf/bblayers.conf.sample
new file mode 100644
index 000000000..12d9af86b
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/conf/bblayers.conf.sample
@@ -0,0 +1,24 @@
+# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf
+# changes incompatibly
+LCONF_VERSION = "10"
+
+BBPATH = "${TOPDIR}"
+BBFILES ?= ""
+
+BBLAYERS ?= " \
+ ##OEROOT##/meta \
+ ##OEROOT##/meta-poky \
+ ##OEROOT##/meta-openembedded/meta-oe \
+ ##OEROOT##/meta-openembedded/meta-networking \
+ ##OEROOT##/meta-openembedded/meta-perl \
+ ##OEROOT##/meta-openembedded/meta-python \
+ ##OEROOT##/meta-phosphor \
+ ##OEROOT##/meta-aspeed \
+ ##OEROOT##/meta-x86 \
+ ##OEROOT##/meta-openbmc-mods \
+ ##OEROOT##/meta-intel \
+ ##OEROOT##/meta-openbmc-mods/meta-common \
+ ##OEROOT##/meta-openbmc-mods/meta-common-small \
+ ##OEROOT##/meta-openbmc-mods/meta-wolfpass \
+ ##OEROOT##/meta-security \
+ "
diff --git a/meta-openbmc-mods/meta-wolfpass/conf/conf-notes.txt b/meta-openbmc-mods/meta-wolfpass/conf/conf-notes.txt
new file mode 100644
index 000000000..558487db6
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/conf/conf-notes.txt
@@ -0,0 +1,5 @@
+Common targets are:
+ intel-platforms
+ obmc-phosphor-image
+ virtual/kernel
+ phosphor-ipmi-host
diff --git a/meta-openbmc-mods/meta-wolfpass/conf/layer.conf b/meta-openbmc-mods/meta-wolfpass/conf/layer.conf
new file mode 100644
index 000000000..a9a90e1ae
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/conf/layer.conf
@@ -0,0 +1,12 @@
+LOCALCONF_VERSION = "3"
+# We have a conf and classes directory, add to BBPATH
+BBPATH .= ":${LAYERDIR}"
+
+# We have recipes-* directories, add to BBFILES
+BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
+ ${LAYERDIR}/recipes-*/*/*.bbappend"
+
+BBFILE_COLLECTIONS += "wolfpass"
+BBFILE_PATTERN_wolfpass = ""
+BBFILE_PRIORITY_wolfpass = "6"
+LAYERSERIES_COMPAT_wolfpass = "thud"
diff --git a/meta-openbmc-mods/meta-wolfpass/conf/local.conf.sample b/meta-openbmc-mods/meta-wolfpass/conf/local.conf.sample
new file mode 100644
index 000000000..d39fb371c
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/conf/local.conf.sample
@@ -0,0 +1,25 @@
+MACHINE ??= "wolfpass"
+#DL_DIR ?= "/~YoctoDownloads"
+#SSTATE_DIR ?= "/~YoctoSstate-cache"
+DISTRO ?= "openbmc-phosphor"
+PACKAGE_CLASSES ?= "package_rpm"
+SANITY_TESTED_DISTROS_append ?= " RedHatEnterpriseWorkstation-6.*"
+EXTRA_IMAGE_FEATURES = "debug-tweaks"
+USER_CLASSES ?= "buildstats image-mklibs image-prelink"
+PATCHRESOLVE = "noop"
+BB_DISKMON_DIRS = "\
+ STOPTASKS,${TMPDIR},1G,100K \
+ STOPTASKS,${DL_DIR},1G,100K \
+ STOPTASKS,${SSTATE_DIR},1G,100K \
+ STOPTASKS,/tmp,100M,100K \
+ ABORT,${TMPDIR},100M,1K \
+ ABORT,${DL_DIR},100M,1K \
+ ABORT,${SSTATE_DIR},100M,1K \
+ ABORT,/tmp,10M,1K"
+CONF_VERSION = "3"
+INHERIT += "extrausers"
+
+EXTRA_USERS_PARAMS_append_pn-intel-platforms = " \
+ usermod -p '\$1\$UGMqyqdG\$FZiylVFmRRfl9Z0Ue8G7e/' root; \
+ "
+#BB_NUMBER_THREADS = "70"
diff --git a/meta-openbmc-mods/meta-wolfpass/conf/machine/include/obmc-bsp-si-common.inc b/meta-openbmc-mods/meta-wolfpass/conf/machine/include/obmc-bsp-si-common.inc
new file mode 100644
index 000000000..24ec3113b
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/conf/machine/include/obmc-bsp-si-common.inc
@@ -0,0 +1,31 @@
+#@TYPE: Machine
+#@NAME: OpenBMC
+#@DESCRIPTION: Common machine configuration for OpenBMC chips
+
+MACHINE_EXTRA_RRECOMMENDS = " kernel-modules"
+EXTRA_IMAGEDEPENDS += "u-boot"
+
+IMAGE_FSTYPES += "squashfs-xz"
+IMAGE_FSTYPES += "mtd-auto"
+INITRAMFS_FSTYPES = "squashfs-xz"
+EXTRA_IMAGECMD_squashfs-xz_append = "-processors ${BB_NUMBER_THREADS} -b 262144 -Xdict-size 100% -Xbcj arm"
+
+KERNEL_CLASSES ?= "kernel-fitimage"
+KERNEL_IMAGETYPES ?= "fitImage"
+KERNEL_EXTRA_ARGS += "LOADADDR=${UBOOT_ENTRYPOINT}"
+
+UBOOT_SUFFIX ?= "bin"
+
+MACHINEOVERRIDES =. "openbmc:"
+
+OBMC_PHOSPHOR_IMAGE_OVERLAY= "1"
+OBMC_IMAGE_EXTRA_INSTALL_append = " u-boot-fw-utils-aspeed"
+
+IMAGE_CLASSES += "image_types image_types_phosphor_auto"
+
+INITRAMFS_CTYPE ?= "lzma"
+INITRAMFS_IMAGE = "obmc-phosphor-initramfs"
+
+MACHINE_FEATURES_BACKFILL_CONSIDERED = "qemu-usermode"
+
+KERNEL_IMAGETYPES += "zImage"
diff --git a/meta-openbmc-mods/meta-wolfpass/conf/machine/wolfpass.conf b/meta-openbmc-mods/meta-wolfpass/conf/machine/wolfpass.conf
new file mode 100644
index 000000000..cc9e30495
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/conf/machine/wolfpass.conf
@@ -0,0 +1,19 @@
+KMACHINE = "aspeed"
+KERNEL_DEVICETREE = "${KMACHINE}-bmc-intel-purley.dtb"
+
+require conf/machine/include/ast2500.inc
+require conf/machine/include/obmc-bsp-si-common.inc
+require conf/machine/include/intel.inc
+require conf/distro/include/phosphor-tiny.inc
+
+UBOOT_MACHINE = "ast_g5_phy_config"
+
+#Developer to specify the appropriate IMAGE_TYPE and FLASH_SIZE
+#On Intel Whitley platforms PFR feature requires 128MB flash, default is 64MB
+#IMAGE_TYPE = "default" or "pfr" or "non-pfr"
+# "non-pfr" setting for future which is for BMC secure boot
+#for PFR its 128MB in KBs - 128*1024=131072, for non-pfr its 64MB= 64*1024 = 65536
+#pfr IMAGE_TYPE enforces the image signature verification during the image update
+IMAGE_TYPE = "default"
+
+VIRTUAL-RUNTIME_skeleton_workbook = "${MACHINE}-config"
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-intel/temporary/set-passthrough.bb b/meta-openbmc-mods/meta-wolfpass/recipes-intel/temporary/set-passthrough.bb
new file mode 100644
index 000000000..e20ea75cf
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-intel/temporary/set-passthrough.bb
@@ -0,0 +1,13 @@
+SUMMARY = "Set passthrough"
+DESCRIPTION = "Script to enable / disable passthrough"
+
+S = "${WORKDIR}"
+SRC_URI = "file://set-passthrough.sh"
+
+LICENSE = "CLOSED"
+RDEPENDS_${PN} += "bash"
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/set-passthrough.sh ${D}/${bindir}/set-passthrough.sh
+}
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-intel/temporary/set-passthrough/set-passthrough.sh b/meta-openbmc-mods/meta-wolfpass/recipes-intel/temporary/set-passthrough/set-passthrough.sh
new file mode 100644
index 000000000..3fbe5e7c6
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-intel/temporary/set-passthrough/set-passthrough.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# this script uses devmem to set hardware passthrough
+# it is temporary and should be removed in the future
+
+PASSTHROUGH_ENABLE=0x3000
+
+if [[ -z $1 ]]; then
+ echo "First Argument Must Be 1 To Enable or 0 To Disable"
+ exit 1
+fi
+
+if [[ $1 != "0" && $1 != "1" ]]; then
+ echo "Arg 1 must be 0 or 1"
+ exit 1
+fi
+
+# read register
+var=$(devmem 0x1e6e208C w)
+
+# convert to int
+typeset -i value=$( echo $(( $var )) )
+
+if [[ $1 == "0" ]]; then
+ value=$((value & ~PASSTHROUGH_ENABLE))
+fi
+
+if [[ $1 == "1" ]]; then
+ value=$((value | PASSTHROUGH_ENABLE))
+fi
+
+val=$(printf '0x%x\n' $value)
+
+#echo $val
+
+devmem 0x1e6e208C w $val
+
+# devmem 0x1e6e208C w
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0001-Create-intel-purley-dts.patch b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0001-Create-intel-purley-dts.patch
new file mode 100644
index 000000000..9b4d9bbc7
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0001-Create-intel-purley-dts.patch
@@ -0,0 +1,389 @@
+From f631d7dc034be1de17213b1498651ad37f3ce98b Mon Sep 17 00:00:00 2001
+From: Yuan Li <yuan.li@linux.intel.com>
+Date: Tue, 19 Sep 2017 15:55:39 +0800
+Subject: [PATCH] ARM: dts: purley: Merge all dts node in the unified patch.
+
+The below changes to the dts file are merged together:
+* 0006: the original one for purley
+* 0008: sgpio
+* 0009: peci
+* 0015: leds_gpio
+* 0018: kcs3 & kcs4
+* i2c4 for HSBP access
+* i2c3 for PCH access
+* LPC SIO device
+* i2c0 for IPMB
+* 12c5 bus-freq
+* vuart
+* uart1/serial0
+* uart2/serial1
+* uart3/serial2
+* uart4/serail3
+* enable high speed uart clock
+* timer pwm
+* cpu0/1fault LEDs
+
+Signed-off-by: Yuan Li <yuan.li@linux.intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/boot/dts/aspeed-bmc-intel-purley.dts | 346 ++++++++++++++++++++++++++
+ 1 file changed, 346 insertions(+)
+ create mode 100644 arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
+
+diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
+new file mode 100644
+index 000000000000..144d59642a71
+--- /dev/null
++++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
+@@ -0,0 +1,346 @@
++/dts-v1/;
++
++#include "aspeed-g5.dtsi"
++#include <dt-bindings/gpio/aspeed-gpio.h>
++#include <dt-bindings/i2c/i2c.h>
++
++/ {
++ model = "Purley BMC";
++ compatible = "intel,purley-bmc", "aspeed,ast2500";
++
++ aliases {
++ serial4 = &uart5;
++ };
++
++ chosen {
++ stdout-path = &uart5;
++ bootargs = "console=ttyS4,115200 earlyprintk";
++ };
++
++ memory@80000000 {
++ reg = <0x80000000 0x20000000>;
++ };
++
++ reserved-memory {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ vga_memory: framebuffer@7f000000 {
++ no-map;
++ reg = <0x7f000000 0x01000000>;
++ };
++
++ gfx_memory: framebuffer {
++ size = <0x04000000>;
++ alignment = <0x01000000>;
++ compatible = "shared-dma-pool";
++ reusable;
++ };
++ };
++
++ vga-shared-memory {
++ compatible = "aspeed,ast2500-vga-sharedmem";
++ reg = <0x9ff00000 0x100000>;
++ };
++
++ iio-hwmon {
++ compatible = "iio-hwmon";
++ io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
++ <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>,
++ <&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>,
++ <&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ identify {
++ default-state = "off";
++ gpios = <&gpio ASPEED_GPIO(S, 6) GPIO_ACTIVE_LOW>;
++ };
++
++ status_amber {
++ default-state = "off";
++ gpios = <&gpio ASPEED_GPIO(S, 5) GPIO_ACTIVE_LOW>;
++ };
++
++ status_green {
++ default-state = "keep";
++ gpios = <&gpio ASPEED_GPIO(S, 4) GPIO_ACTIVE_LOW>;
++ };
++
++ cpu0fault {
++ gpios = <&gpio ASPEED_GPIO(F, 4) GPIO_ACTIVE_HIGH>;
++ };
++
++ cpu1fault {
++ gpios = <&gpio ASPEED_GPIO(F, 5) GPIO_ACTIVE_HIGH>;
++ };
++ };
++
++ beeper {
++ compatible = "pwm-beeper";
++ pwms = <&timer 5 1000000 0>;
++ };
++};
++
++&fmc {
++ status = "okay";
++ flash@0 {
++ status = "okay";
++ m25p,fast-read;
++#include "openbmc-flash-layout-intel-64MB.dtsi"
++ };
++};
++
++&espi {
++ status = "okay";
++};
++
++&jtag {
++ status = "okay";
++};
++
++&peci0 {
++ status = "okay";
++};
++
++&syscon {
++ uart-clock-high-speed;
++ status = "okay";
++};
++
++&adc {
++ status = "okay";
++};
++
++&gpio {
++ status = "okay";
++};
++
++&kcs3 {
++ kcs_addr = <0xCA2>;
++ status = "okay";
++};
++
++&kcs4 {
++ kcs_addr = <0xCA4>;
++ status = "okay";
++};
++
++&lpc_sio {
++ status = "okay";
++};
++
++&lpc_snoop {
++ snoop-ports = <0x80>;
++ status = "okay";
++};
++
++&mbox {
++ status = "okay";
++};
++
++/**
++ * SAFS through SPI1 is available only on Wilson Point.
++ * These pins are used as fan presence checking gpios in WFP
++ * so commenting it out for now.
++ * &spi1 {
++ * status = "okay";
++ *
++ * flash@0 {
++ * m25p,fast-read;
++ * status = "okay";
++ * };
++ *};
++ */
++
++&sgpio {
++ status = "okay";
++};
++
++&uart1 {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_txd1_default
++ &pinctrl_rxd1_default
++ &pinctrl_nrts1_default
++ &pinctrl_ndtr1_default
++ &pinctrl_ndsr1_default
++ &pinctrl_ncts1_default
++ &pinctrl_ndcd1_default
++ &pinctrl_nri1_default>;
++};
++
++&uart2 {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_txd2_default
++ &pinctrl_rxd2_default
++ &pinctrl_nrts2_default
++ &pinctrl_ndtr2_default
++ &pinctrl_ndsr2_default
++ &pinctrl_ncts2_default
++ &pinctrl_ndcd2_default
++ &pinctrl_nri2_default>;
++};
++
++&uart3 {
++ status = "okay";
++};
++
++&uart4 {
++ status = "okay";
++};
++
++&uart5 {
++ status = "okay";
++};
++
++&mac1 {
++ status = "okay";
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
++};
++
++&mac0 {
++ status = "okay";
++ use-ncsi;
++
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_rmii1_default>;
++};
++
++&i2c0 {
++ multi-master;
++ status = "okay";
++
++ ipmb0@10 {
++ compatible = "slave-mqueue";
++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
++ };
++};
++
++&i2c1 {
++ multi-master;
++ status = "okay";
++};
++
++&i2c2 {
++ multi-master;
++ status = "okay";
++};
++
++&i2c3 {
++ multi-master;
++ status = "okay";
++};
++
++&i2c4 {
++ multi-master;
++ status = "okay";
++
++ hsbp0@10 {
++ compatible = "slave-mqueue";
++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
++ };
++};
++
++&i2c5 {
++ bus-frequency = <1000000>;
++ multi-master;
++ status = "okay";
++
++ smlink0@10 {
++ compatible = "slave-mqueue";
++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
++ };
++};
++
++&i2c6 {
++ multi-master;
++ status = "okay";
++};
++
++&i2c7 {
++ multi-master;
++ #retries = <3>;
++ status = "okay";
++};
++
++&gfx {
++ status = "okay";
++ memory-region = <&gfx_memory>;
++};
++
++&vuart {
++ status = "okay";
++};
++
++&pwm_tacho {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default
++ &pinctrl_pwm2_default &pinctrl_pwm3_default
++ &pinctrl_pwm4_default &pinctrl_pwm5_default
++ &pinctrl_pwm6_default &pinctrl_pwm7_default>;
++
++ fan@0 {
++ reg = <0x00>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x00 0x01>;
++ };
++ fan@1 {
++ reg = <0x01>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x02 0x03>;
++ };
++ fan@2 {
++ reg = <0x02>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x04 0x05>;
++ };
++ fan@3 {
++ reg = <0x03>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x06 0x07>;
++ };
++ fan@4 {
++ reg = <0x04>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x08 0x09>;
++ };
++ fan@5 {
++ reg = <0x05>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x0A 0x0B>;
++ };
++ fan@6 {
++ reg = <0x06>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x0C 0x0D>;
++ };
++ fan@7 {
++ reg = <0x07>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x0E 0x0F>;
++ };
++
++};
++
++&timer {
++/*
++ * Available settings:
++ * fttmr010,pwm-outputs = <5>, <6>, <7>, <8>;
++ * pinctrl-0 = <&pinctrl_timer5_default &pinctrl_timer6_default
++ * &pinctrl_timer7_default &pinctrl_timer8_default>;
++ */
++ fttmr010,pwm-outputs = <5>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_timer5_default>;
++ #pwm-cells = <3>;
++ status = "okay";
++};
++
++&video {
++ status = "okay";
++ memory-region = <&gfx_memory>;
++};
++
++&vhub {
++ status = "okay";
++};
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0002-Define-the-gpio-line-names-property-for-purley-platform.patch b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0002-Define-the-gpio-line-names-property-for-purley-platform.patch
new file mode 100644
index 000000000..63e8b2006
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0002-Define-the-gpio-line-names-property-for-purley-platform.patch
@@ -0,0 +1,63 @@
+From 971b69835fcafbac02adf828a744af541c7554d0 Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Wed, 19 Sep 2018 17:51:06 +0800
+Subject: [PATCH] Define the gpio-line-names property for purley platform
+
+Based on aspeed AST-2500 Datasheet and Intel Purley platform spec,
+defined following gpios.
+
+"name": "PGOOD", "pin": "AB3";
+"name": "POWER_BUTTON", "pin": "E2";
+"name": "POWER_UP_PIN", "pin": "E3";
+"name": "RESET_BUTTON", "pin": "E0";
+"name": "RESET_OUT", "pin": "E1";
+"name": "ID_BUTTON", "pin": "S6";
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ arch/arm/boot/dts/aspeed-bmc-intel-purley.dts | 29 +++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
+index 1c9aed9fcf94..9e187453750f 100644
+--- a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
++++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
+@@ -91,6 +91,35 @@
+
+ &gpio {
+ status = "okay";
++ gpio-line-names = "A0","A1","A2","A3","A4","A5","A6","A7",
++ "B0","B1","B2","B3","B4","B5","B6","B7",
++ "C0","C1","C2","C3","C4","C5","C6","C7",
++ "D0","D1","D2","D3","D4","D5","D6","D7",
++ "RESET_BUTTON","RESET_OUT","POWER_BUTTON","POWER_UP_PIN","E4","E5","E6","E7",
++ "F0","F1","F2","F3","F4","F5","F6","F7",
++ "G0","G1","G2","G3","G4","G5","G6","G7",
++ "H0","H1","H2","H3","H4","H5","H6","H7",
++ "I0","I1","I2","I3","I4","I5","I6","I7",
++ "J0","J1","J2","J3","J4","J5","J6","J7",
++ "K0","E1","E2","E3","E4","E5","E6","E7",
++ "L0","L1","L2","L3","L4","L5","L6","L7",
++ "M0","M1","M2","M3","M4","M5","M6","M7",
++ "N0","N1","N2","N3","N4","N5","N6","N7",
++ "O0","O1","O2","O3","O4","O5","O6","O7",
++ "P0","P1","P2","P3","P4","P5","P6","P7",
++ "Q0","Q1","Q2","Q3","Q4","Q5","Q6","Q7",
++ "R0","R1","R2","R3","R4","R5","R6","R7",
++ "S0","S1","S2","S3","S4","S5","ID_BUTTON","S7",
++ "T0","T1","T2","T3","T4","T5","T6","T7",
++ "U0","U1","U2","U3","U4","U5","U6","U7",
++ "V0","V1","V2","V3","V4","V5","V6","V7",
++ "W0","W1","W2","W3","W4","W5","W6","W7",
++ "X0","X1","X2","X3","X4","X5","X6","X7",
++ "Y0","Y1","Y2","Y3","Y4","Y5","Y6","Y7",
++ "Z0","Z1","Z2","Z3","Z4","Z5","Z6","Z7",
++ "AA0","AA1","AA2","AA3","AA4","AA5","AA6","AA7",
++ "AB0","AB1","AB2","PGOOD","AB4","AB5","AB6","AB7",
++ "AC0","AC1","AC2","AC3","AC4","AC5","AC6","AC7";
+ };
+
+ &kcs3 {
+--
+2.17.0
+
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0003-Leave-GPIOE-in-passthrough-after-boot.patch b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0003-Leave-GPIOE-in-passthrough-after-boot.patch
new file mode 100644
index 000000000..dd56cab4b
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0003-Leave-GPIOE-in-passthrough-after-boot.patch
@@ -0,0 +1,46 @@
+From 769b30d1b5463291ddffd46f6039321d42f80417 Mon Sep 17 00:00:00 2001
+From: James Feist <james.feist@linux.intel.com>
+Date: Mon, 5 Nov 2018 15:38:19 -0800
+Subject: [PATCH 1/1] Leave GPIOE in passthrough after boot
+
+This is a temporary patch that seems to leave exported
+gpio in passthrough mode. It's hard to understand why this
+works because all the macros are _very_ confusing, but
+SIG_DESC_SET is equal to SIG_DESC_BIT(arg1, arg2, 1) so as
+a test I used SIG_DESC_BIT set to 0 for SCU8C and I noticed
+the correct result for exported gpios. As of today I'm unsure
+why setting 0 results in the bit being 1 and vise versa, but
+as this is only a short-term fix, I don't think we really care.
+This is not a long term fix, but it was a quick and easy
+change that can get us the correct result in the short term.
+
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+---
+ drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 8 ++++----
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+index 0c89647f166f..386ae967835d 100644
+--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+@@ -246,7 +246,7 @@ FUNC_GROUP_DECL(GPID6, G18, C21);
+ FUNC_GROUP_DECL(SD2, F19, E21, F20, D20, D21, E20, G18, C21);
+
+ #define GPIE_DESC SIG_DESC_SET(HW_STRAP1, 22)
+-#define GPIE0_DESC SIG_DESC_SET(SCU8C, 12)
++#define GPIE0_DESC SIG_DESC_BIT(SCU8C, 12, 0)
+
+ #define B20 32
+ SIG_EXPR_LIST_DECL_SINGLE(NCTS3, NCTS3, SIG_DESC_SET(SCU80, 16));
+@@ -266,7 +266,7 @@ FUNC_GROUP_DECL(NDCD3, C20);
+
+ FUNC_GROUP_DECL(GPIE0, B20, C20);
+
+-#define GPIE2_DESC SIG_DESC_SET(SCU8C, 13)
++#define GPIE2_DESC SIG_DESC_BIT(SCU8C, 13, 0)
+
+ #define F18 34
+ SIG_EXPR_LIST_DECL_SINGLE(NDSR3, NDSR3, SIG_DESC_SET(SCU80, 18));
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0004-Test-code-for-LPC-MBOX.patch b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0004-Test-code-for-LPC-MBOX.patch
new file mode 100644
index 000000000..dbb163d20
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0004-Test-code-for-LPC-MBOX.patch
@@ -0,0 +1,112 @@
+From 2f3587cf9e44f261fe74413ef6a54467686c910b Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 20 Nov 2018 15:49:15 -0800
+Subject: [PATCH] Test code for LPC MBOX
+
+Blocked interrupt driven code for test.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/misc/aspeed-lpc-mbox.c | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/misc/aspeed-lpc-mbox.c b/drivers/misc/aspeed-lpc-mbox.c
+index 0f0c711bafee..0933e0553953 100644
+--- a/drivers/misc/aspeed-lpc-mbox.c
++++ b/drivers/misc/aspeed-lpc-mbox.c
+@@ -19,6 +19,8 @@
+
+ #define DEVICE_NAME "aspeed-mbox"
+
++#define MBX_USE_INTERRUPT 0
++
+ #define ASPEED_MBOX_NUM_REGS 16
+
+ #define ASPEED_MBOX_DATA_0 0x00
+@@ -79,12 +81,14 @@ static int aspeed_mbox_open(struct inode *inode, struct file *file)
+ struct aspeed_mbox *mbox = file_mbox(file);
+
+ if (atomic_inc_return(&aspeed_mbox_open_count) == 1) {
++#if MBX_USE_INTERRUPT
+ /*
+ * Clear the interrupt status bit if it was left on and unmask
+ * interrupts.
+ * ASPEED_MBOX_CTRL_RECV bit is W1C, this also unmasks in 1 step
+ */
+ aspeed_mbox_outb(mbox, ASPEED_MBOX_CTRL_RECV, ASPEED_MBOX_BMC_CTRL);
++#endif
+ return 0;
+ }
+
+@@ -106,6 +110,7 @@ static ssize_t aspeed_mbox_read(struct file *file, char __user *buf,
+ if (count + *ppos > ASPEED_MBOX_NUM_REGS)
+ return -EINVAL;
+
++#if MBX_USE_INTERRUPT
+ if (file->f_flags & O_NONBLOCK) {
+ if (!(aspeed_mbox_inb(mbox, ASPEED_MBOX_BMC_CTRL) &
+ ASPEED_MBOX_CTRL_RECV))
+@@ -115,6 +120,7 @@ static ssize_t aspeed_mbox_read(struct file *file, char __user *buf,
+ ASPEED_MBOX_CTRL_RECV)) {
+ return -ERESTARTSYS;
+ }
++#endif
+
+ mutex_lock(&mbox->mutex);
+
+@@ -129,8 +135,10 @@ static ssize_t aspeed_mbox_read(struct file *file, char __user *buf,
+ count--;
+ }
+
++#if MBX_USE_INTERRUPT
+ /* ASPEED_MBOX_CTRL_RECV bit is write to clear, this also unmasks in 1 step */
+ aspeed_mbox_outb(mbox, ASPEED_MBOX_CTRL_RECV, ASPEED_MBOX_BMC_CTRL);
++#endif
+ ret = p - buf;
+
+ out_unlock:
+@@ -180,7 +188,9 @@ static unsigned int aspeed_mbox_poll(struct file *file, poll_table *wait)
+
+ poll_wait(file, &mbox->queue, wait);
+
++#if MBX_USE_INTERRUPT
+ if (aspeed_mbox_inb(mbox, ASPEED_MBOX_BMC_CTRL) & ASPEED_MBOX_CTRL_RECV)
++#endif
+ mask |= POLLIN;
+
+ return mask;
+@@ -206,6 +216,7 @@ static irqreturn_t aspeed_mbox_irq(int irq, void *arg)
+ {
+ struct aspeed_mbox *mbox = arg;
+
++#if MBX_USE_INTERRUPT
+ if (!(aspeed_mbox_inb(mbox, ASPEED_MBOX_BMC_CTRL) & ASPEED_MBOX_CTRL_RECV))
+ return IRQ_NONE;
+
+@@ -216,6 +227,7 @@ static irqreturn_t aspeed_mbox_irq(int irq, void *arg)
+
+ /* Mask it off, we'll clear it when we the data gets read */
+ aspeed_mbox_outb(mbox, ASPEED_MBOX_CTRL_MASK, ASPEED_MBOX_BMC_CTRL);
++#endif
+
+ wake_up(&mbox->queue);
+ return IRQ_HANDLED;
+@@ -248,7 +260,14 @@ static int aspeed_mbox_config_irq(struct aspeed_mbox *mbox,
+ aspeed_mbox_outb(mbox, 0xff, ASPEED_MBOX_STATUS_0);
+ aspeed_mbox_outb(mbox, 0xff, ASPEED_MBOX_STATUS_1);
+
+- aspeed_mbox_outb(mbox, ASPEED_MBOX_CTRL_RECV, ASPEED_MBOX_BMC_CTRL);
++ aspeed_mbox_outb(mbox, aspeed_mbox_inb(mbox, ASPEED_MBOX_BMC_CTRL) | ASPEED_MBOX_CTRL_MASK, ASPEED_MBOX_BMC_CTRL);
++
++ /*
++ * Because mailbox data register init value is random, need to give a
++ * init value to mailbox data register.
++ */
++ aspeed_mbox_outb(mbox, 0x00, ASPEED_MBOX_DATA_0);
++
+ return 0;
+ }
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch
new file mode 100644
index 000000000..6d92227c7
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch
@@ -0,0 +1,31 @@
+From 0b3a20690483d3a04cb10d785b33f01b9bf4079d Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Date: Wed, 6 Feb 2019 15:59:34 +0530
+Subject: [PATCH] Selecting 128MB for PFR
+
+PFR platforms requires 128MB flash mapping.
+This will override the existing 64MB flash map
+and loads 128MB flash map.
+
+Change-Id: If42805139d86061bd409915e8fc6374d6cf69147
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+---
+ arch/arm/boot/dts/aspeed-bmc-intel-purley.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
+index 20cc204..aab14fd 100644
+--- a/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
++++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
+@@ -79,7 +79,7 @@
+ flash@0 {
+ status = "okay";
+ m25p,fast-read;
+-#include "openbmc-flash-layout-intel-64MB.dtsi"
++#include "openbmc-flash-layout-intel-128MB.dtsi"
+ };
+ };
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/wolfpass.cfg b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/wolfpass.cfg
new file mode 100644
index 000000000..480d4cc18
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/wolfpass.cfg
@@ -0,0 +1,69 @@
+CONFIG_HWMON=y
+CONFIG_SENSORS_ASPEED=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_IIO=y
+CONFIG_SENSORS_IIO_HWMON=y
+CONFIG_ASPEED_ADC=y
+CONFIG_SGPIO_ASPEED=y
+CONFIG_CRC8=y
+CONFIG_PECI=y
+CONFIG_PECI_CHARDEV=y
+CONFIG_PECI_ASPEED=y
+CONFIG_SENSORS_PECI_CPUTEMP=y
+CONFIG_SENSORS_PECI_DIMMTEMP=y
+CONFIG_OF_CONFIGFS=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_BLK_DEV_RAM_SIZE=49152
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01
+CONFIG_MAGIC_SYSRQ_SERIAL=y
+CONFIG_ASPEED_ESPI_SLAVE=y
+CONFIG_ASPEED_KCS_IPMI_BMC=y
+CONFIG_I2C_SLAVE=y
+CONFIG_I2C_SLAVE_EEPROM=n
+CONFIG_I2C_SLAVE_MQUEUE=y
+CONFIG_I2C_SLAVE_MQUEUE_MESSAGE_SIZE=256
+CONFIG_I2C_SLAVE_MQUEUE_QUEUE_SIZE=32
+CONFIG_ASPEED_LPC_SIO=y
+CONFIG_JTAG=y
+CONFIG_JTAG_ASPEED=y
+CONFIG_FRAME_VECTOR=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_VIDEO_ASPEED=y
+CONFIG_VIDEOBUF2_CORE=y
+CONFIG_VIDEOBUF2_V4L2=y
+CONFIG_VIDEOBUF2_MEMOPS=y
+CONFIG_VIDEOBUF2_DMA_CONTIG=y
+CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
+CONFIG_USB_LIBCOMPOSITE=y
+CONFIG_USB_F_HID=y
+CONFIG_USB_GADGET=y
+CONFIG_U_SERIAL_CONSOLE=y
+CONFIG_USB_ASPEED_VHUB=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_ASPEED_UART_ROUTING=y
+CONFIG_DEVMEM=y
+CONFIG_ASPEED_VGA_SHAREDMEM=y
+CONFIG_DEVMEM_BOOTPARAM=n
+CONFIG_PWM=y
+CONFIG_PWM_FTTMR010=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PWM_BEEPER=y
+CONFIG_VFAT_FS=y
+CONFIG_NLS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_UTF8=y
+
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed_%.bbappend
new file mode 100644
index 000000000..7a386c848
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed_%.bbappend
@@ -0,0 +1,8 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/linux-aspeed:"
+SRC_URI += "file://wolfpass.cfg \
+ file://0001-Create-intel-purley-dts.patch \
+ file://0002-Define-the-gpio-line-names-property-for-purley-platform.patch \
+ file://0003-Leave-GPIOE-in-passthrough-after-boot.patch \
+ file://0004-Test-code-for-LPC-MBOX.patch \
+ "
+SRC_URI += "${@bb.utils.contains('IMAGE_TYPE', 'pfr', 'file://0005-128MB-flashmap-for-PFR.patch', '', d)}"
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/FCXXPDBASSMBL_PDB.json b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/FCXXPDBASSMBL_PDB.json
new file mode 100644
index 000000000..726ff100c
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/FCXXPDBASSMBL_PDB.json
@@ -0,0 +1,85 @@
+[
+ {
+ "Exposes": [
+ {
+ "Address": "0x48",
+ "Bus": "$bus",
+ "Name": "PDB Temp1",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 80
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 75
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x49",
+ "Bus": "$bus",
+ "Name": "PDB Temp2",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 80
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 75
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "$address",
+ "Bus": "$bus",
+ "Name": "FCXXPDBASSMBL Fru",
+ "Type": "24C01"
+ }
+ ],
+ "Name": "FCXXPDBASSMBL PDB",
+ "Type": "Board",
+ "Probe": "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'FCXXPDBASSMBL', 'ADDRESS' : 85})",
+ "xyz.openbmc_project.Inventory.Decorator.Asset": {
+ "Manufacturer": "$BOARD_MANUFACTURER",
+ "Model": "$BOARD_PRODUCT_NAME",
+ "PartNumber": "$BOARD_PART_NUMBER",
+ "SerialNumber": "$BOARD_SERIAL_NUMBER"
+ }
+ }
+]
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/OPB2RH-Chassis.json b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/OPB2RH-Chassis.json
new file mode 100644
index 000000000..38c661ed6
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/OPB2RH-Chassis.json
@@ -0,0 +1,18 @@
+{
+ "Exposes": [
+
+ ],
+ "Name": "OPB2RH Chassis",
+ "Type": "Chassis",
+ "Probe": [
+ "FOUND('TNP Baseboard')",
+ "AND",
+ "xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'FCXXPDBASSMBL'})"
+ ],
+ "xyz.openbmc_project.Inventory.Decorator.Asset": {
+ "Manufacturer": "Intel Corporation",
+ "Model": "OPB2RH",
+ "PartNumber": "R1234",
+ "SerialNumber": "12345"
+ }
+}
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/TNP-baseboard.json b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/TNP-baseboard.json
new file mode 100644
index 000000000..01b899061
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/TNP-baseboard.json
@@ -0,0 +1,1945 @@
+{
+ "Exposes": [
+ {
+ "Address": "0x4A",
+ "Bus": 6,
+ "Name": "BMC Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Index": 0,
+ "Name": "Baseboard 12 Volt",
+ "PowerState": "On",
+ "ScaleFactor": 0.1124,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 13.494
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 13.101
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 10.945
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 10.616
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Name": "CPU 1 Fan Connector",
+ "Pwm": 7,
+ "Status": "disabled",
+ "Tachs": [
+ 13
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "CPU 2 Fan Connector",
+ "Pwm": 8,
+ "Status": "disabled",
+ "Tachs": [
+ 14
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Address": "0x49",
+ "Bus": 6,
+ "Name": "Left Rear Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Index": 4,
+ "Name": "P0V83_LAN_AUX",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 0.901
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 0.875
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.786
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.763
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 3,
+ "Name": "P105_PCH_AUX",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.139
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.106
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.995
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.966
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 5,
+ "Name": "P12V_AUX",
+ "ScaleFactor": 0.1124,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 13.494
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 13.101
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 10.945
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 10.616
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 6,
+ "Name": "P1V8_PCH",
+ "ScaleFactor": 0.7505,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.961
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.904
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.699
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.648
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 1,
+ "Name": "P3V3",
+ "PowerState": "On",
+ "ScaleFactor": 0.4107,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 3.647
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 3.541
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 3.066
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 2.974
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 7,
+ "Name": "P3VBAT",
+ "ScaleFactor": 0.3333,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 3.296
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 3.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 2.457
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 2.138
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 8,
+ "Name": "PVCCIN_CPU0",
+ "PowerState": "On",
+ "ScaleFactor": 0.7505,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 2.151
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 2.088
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.418
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.376
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 9,
+ "Name": "PVCCIN_CPU1",
+ "PowerState": "On",
+ "ScaleFactor": 0.7505,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 2.151
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 2.088
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.418
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.376
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 14,
+ "Name": "PVCCIO_CPU0",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.19
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.155
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.752
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.729
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 15,
+ "Name": "PVCCIO_CPU1",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.19
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.155
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.752
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.729
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 10,
+ "Name": "PVDQ_ABCD_CPU0",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.301
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.138
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.104
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 12,
+ "Name": "PVDQ_ABCD_CPU1",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.301
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.138
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.104
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 11,
+ "Name": "PVDQ_EFGH_CPU0",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.301
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.138
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.104
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 13,
+ "Name": "PVDQ_EFGH_CPU1",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.301
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.138
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.104
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 2,
+ "Name": "PVNN_PCH_AUX",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.081
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.049
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.807
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.783
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Address": "0x4D",
+ "Bus": 6,
+ "Name": "Right Rear Board Temp",
+ "Name1": "Right Rear TMP421 Internal Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP421"
+ },
+ {
+ "Address": "0x48",
+ "Bus": 6,
+ "Name": "Voltage Regulator 1 Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x4B",
+ "Bus": 6,
+ "Name": "Voltage Regulator 2 Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x30",
+ "Bus": 0,
+ "CpuID": 0,
+ "Name": "Skylake CPU 0",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Label": "DIMM",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 99
+ },
+ {
+ "Direction": "greater than",
+ "Label": "DIMM",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 89
+ }
+ ],
+ "Type": "SkylakeCPU"
+ },
+ {
+ "Address": "0x31",
+ "Bus": 0,
+ "CpuID": 1,
+ "Name": "Skylake CPU 1",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Label": "DIMM",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 99
+ },
+ {
+ "Direction": "greater than",
+ "Label": "DIMM",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 89
+ }
+ ],
+ "Type": "SkylakeCPU"
+ },
+ {
+ "Direction": "In",
+ "Index": 32,
+ "Name": "Reset Button",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 33,
+ "Name": "Reset Out",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Both",
+ "Index": 34,
+ "Name": "Power Button",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Both",
+ "Index": 35,
+ "Name": "Power Up",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 40,
+ "Name": "NMI Out",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 50,
+ "Name": "PCH Thermaltrip",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 51,
+ "Name": "Lcp Enter Button",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 52,
+ "Name": "Lcp Left Button",
+ "Polarity": "High",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 53,
+ "Name": "Lcp Right Button",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 49,
+ "Name": "Cpu Caterr",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 48,
+ "Name": "Cpu Err2",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 63,
+ "Name": "PU 240VA Status",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 208,
+ "Name": "P3v3bat BridgeEn",
+ "Polarity": "High",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 214,
+ "Name": "Nmi Button",
+ "Polarity": "High",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 215,
+ "Name": "Post complete",
+ "Polarity": "High",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 217,
+ "Name": "Nmi Button",
+ "Polarity": "High",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 218,
+ "Name": "ID Button",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 219,
+ "Name": "Power Good",
+ "Polarity": "High",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 232,
+ "Name": "Post Complete led0",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 233,
+ "Name": "Post Complete led1",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 233,
+ "Name": "CPU1 Thermaltrip",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 234,
+ "Name": "Post Complete led2",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 234,
+ "Name": "CPU1 VR Hot",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 235,
+ "Name": "Post Complete led3",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 236,
+ "Name": "Post Complete led4",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 236,
+ "Name": "CPU1 Mem VR Hot1",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 237,
+ "Name": "Post Complete led5",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 237,
+ "Name": "CPU1 Mem VR Hot2",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 238,
+ "Name": "Post Complete led6",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 239,
+ "Name": "Post Complete led7",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 232,
+ "Name": "CPU1 Present",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 235,
+ "Name": "CPU1 FIVR Fault",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 238,
+ "Name": "CPU1 ID0",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 240,
+ "Name": "CPU1 CH1 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 240,
+ "Name": "CPU1 Mismatch",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 241,
+ "Name": "CPU1 CH1 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 241,
+ "Name": "CPU1 DIMM Thermaltrip",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 242,
+ "Name": "CPU1 CH2 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 242,
+ "Name": "CPU2 Present",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 243,
+ "Name": "CPU1 CH2 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 243,
+ "Name": "CPU2 Thermaltrip",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 244,
+ "Name": "CPU1 CH3 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 244,
+ "Name": "CPU2 VR Hot",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 245,
+ "Name": "CPU1 CH3 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 245,
+ "Name": "CPU2 FIVR Fault",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 246,
+ "Name": "CPU1 CH4 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 246,
+ "Name": "CPU2 Mem VR Hot1",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 247,
+ "Name": "CPU1 CH4 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 247,
+ "Name": "CPU1 Mem VR Hot2",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 248,
+ "Name": "CPU1 CH5 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 248,
+ "Name": "CPU2 ID0",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 249,
+ "Name": "CPU1 CH5 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 250,
+ "Name": "CPU1 CH6 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 250,
+ "Name": "CPU2 Mismatch",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 251,
+ "Name": "CPU1 CH6 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 251,
+ "Name": "CPU2 DIMM Thermaltrip",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 252,
+ "Name": "Fan1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 253,
+ "Name": "Fan2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 254,
+ "Name": "Fan3 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 255,
+ "Name": "Fan4 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 256,
+ "Name": "Fan5 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 257,
+ "Name": "Fan6 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 258,
+ "Name": "Fan7 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 259,
+ "Name": "Fan8 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 260,
+ "Name": "CPU2 CH1 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 261,
+ "Name": "CPU1 CH1 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 262,
+ "Name": "CPU2 CH2 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 263,
+ "Name": "CPU2 CH2 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 264,
+ "Name": "CPU2 CH3 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 265,
+ "Name": "CPU2 CH3 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 266,
+ "Name": "CPU2 CH4 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 267,
+ "Name": "CPU2 CH4 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 268,
+ "Name": "CPU2 CH5 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 269,
+ "Name": "CPU2 CH5 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 270,
+ "Name": "CPU2 CH6 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 271,
+ "Name": "CPU2 CH6 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 272,
+ "Name": "CPU3 CH1 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 272,
+ "Name": "PLD Minor Revison Bit 0",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 273,
+ "Name": "CPU3 CH1 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 273,
+ "Name": "PLD Minor Revison Bit 1",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 274,
+ "Name": "CPU3 CH2 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 274,
+ "Name": "PLD Minor Revison Bit 2",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 275,
+ "Name": "CPU3 CH2 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 275,
+ "Name": "PLD Minor Revison Bit 3",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 276,
+ "Name": "CPU3 CH3 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 276,
+ "Name": "PLD Major Revison Bit 0",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 277,
+ "Name": "CPU3 CH3 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 277,
+ "Name": "PLD Major Revison Bit 1",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 278,
+ "Name": "CPU3 CH4 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 278,
+ "Name": "PLD Major Revison Bit 2",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 279,
+ "Name": "CPU3 CH4 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 279,
+ "Name": "PLD Major Revison Bit 2",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 280,
+ "Name": "CPU3 CH5 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 280,
+ "Name": "Main PLD Minor Revison Bit 0",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 281,
+ "Name": "CPU3 CH5 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 281,
+ "Name": "Main PLD Minor Revison Bit 1",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 282,
+ "Name": "CPU3 CH6 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 282,
+ "Name": "Main PLD Minor Revison Bit 2",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 283,
+ "Name": "CPU3 CH6 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 283,
+ "Name": "Main PLD Minor Revison Bit 3",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 284,
+ "Name": "CPU4 CH1 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 284,
+ "Name": "Main PLD Major Revison Bit 0",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 285,
+ "Name": "CPU4 CH1 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 285,
+ "Name": "Main PLD Major Revison Bit 1",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 286,
+ "Name": "CPU4 CH2 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 286,
+ "Name": "Main PLD Major Revison Bit 2",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 287,
+ "Name": "CPU4 CH2 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 287,
+ "Name": "Main PLD Major Revison Bit 3",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 288,
+ "Name": "CPU4 CH3 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 289,
+ "Name": "CPU4 CH3 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 289,
+ "Name": "Memory Pwr Fault",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 290,
+ "Name": "CPU4 CH4 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 290,
+ "Name": "CPU Pwr Fault",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 291,
+ "Name": "CPU4 CH4 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 291,
+ "Name": "P5V P3V3 Pwr Fault",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 292,
+ "Name": "CPU4 CH5 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 292,
+ "Name": "PSU Pwr Fault",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 293,
+ "Name": "CPU4 CH5 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 293,
+ "Name": "SAS Pwr Fault",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 294,
+ "Name": "CPU4 CH6 DIMM1 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 294,
+ "Name": "Lan Aux Pwr Fault",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Out",
+ "Index": 295,
+ "Name": "CPU4 CH6 DIMM2 FAULT",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 295,
+ "Name": "PCH Pwr Fault",
+ "Polarity": "Low",
+ "Type": "Gpio"
+ },
+ {
+ "Address": "0x8",
+ "Class": "METemp",
+ "Name": "SSB Temp",
+ "PowerState": "BiosPost",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 103
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 98
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x7c",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU1 P12V PVCCIO VR Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x70",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU1 P12V PVCCIN VR Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x74",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU1 VR Mem ABC Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x78",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU1 VR Mem DEF Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x9c",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU2 P12V PVCCIO VR Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x50",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU2 P12V PVCCIN VR Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x94",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU2 VR Mem ABC Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x98",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU2 VR Mem DEF Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xAC",
+ "Class": "PxeBridgeTemp",
+ "Name": "VR P1V05 Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x71",
+ "Bus": 2,
+ "ChannelNames": [
+ "M2_Slot1",
+ "M2_Slot2",
+ "",
+ ""
+ ],
+ "Name": "M.2 Mux",
+ "Type": "PCA9543Mux"
+ }
+ ],
+ "Name": "TNP Baseboard",
+ "Probe": "xyz.openbmc_project.FruDevice({'PRODUCT_PRODUCT_NAME': '.*TNP'})",
+ "Type": "Board",
+ "xyz.openbmc_project.Inventory.Decorator.Asset": {
+ "Manufacturer": "$PRODUCT_MANUFACTURER",
+ "Model": "$PRODUCT_PRODUCT_NAME",
+ "PartNumber": "$PRODUCT_PART_NUMBER",
+ "SerialNumber": "$PRODUCT_SERIAL_NUMBER"
+ }
+}
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json
new file mode 100644
index 000000000..65f36ccab
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/WC-Baseboard.json
@@ -0,0 +1,1736 @@
+{
+ "Exposes": [
+ {
+ "Name": "System Fan connector 1",
+ "Pwm": 0,
+ "Tachs": [
+ 0,
+ 1
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 2",
+ "Pwm": 1,
+ "Tachs": [
+ 2,
+ 3
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 3",
+ "Pwm": 2,
+ "Tachs": [
+ 4,
+ 5
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 4",
+ "Pwm": 3,
+ "Tachs": [
+ 6,
+ 7
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 5",
+ "Pwm": 4,
+ "Tachs": [
+ 8,
+ 9
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 6",
+ "Pwm": 5,
+ "Tachs": [
+ 10,
+ 11
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 7",
+ "Pwm": 6,
+ "Tachs": [
+ 12,
+ 13
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 8",
+ "Pwm": 7,
+ "Tachs": [
+ 14,
+ 15
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Address": "0x4A",
+ "Bus": 6,
+ "Name": "BMC Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Index": 0,
+ "Name": "A_P12V_PSU_SCALED",
+ "PowerState": "On",
+ "ScaleFactor": 0.1124,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 13.494
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 13.101
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 10.945
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 10.616
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 4,
+ "Name": "P0V83_LAN_AUX",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 0.901
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 0.875
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.786
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.763
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 3,
+ "Name": "P105_PCH_AUX",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.139
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.106
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.995
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.966
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 5,
+ "Name": "P12V_AUX",
+ "ScaleFactor": 0.1124,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 13.494
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 13.101
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 10.945
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 10.616
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 6,
+ "Name": "P1V8_PCH",
+ "ScaleFactor": 0.7505,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.961
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.904
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.699
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.648
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 1,
+ "Name": "P3V3",
+ "PowerState": "On",
+ "ScaleFactor": 0.4107,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 3.647
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 3.541
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 3.066
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 2.974
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 7,
+ "Name": "P3VBAT",
+ "ScaleFactor": 0.3333,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 3.296
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 3.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 2.457
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 2.138
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 8,
+ "Name": "PVCCIN_CPU0",
+ "PowerState": "On",
+ "ScaleFactor": 0.7505,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 2.151
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 2.088
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.418
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.376
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 9,
+ "Name": "PVCCIN_CPU1",
+ "PowerState": "On",
+ "ScaleFactor": 0.7505,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 2.151
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 2.088
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.418
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.376
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 14,
+ "Name": "PVCCIO_CPU0",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.19
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.155
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.752
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.729
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 15,
+ "Name": "PVCCIO_CPU1",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.19
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.155
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.752
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.729
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 10,
+ "Name": "PVDQ_ABC_CPU0",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.301
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.138
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.104
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 12,
+ "Name": "PVDQ_ABC_CPU1",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.301
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.138
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.104
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 11,
+ "Name": "PVDQ_DEF_CPU0",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.301
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.138
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.104
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 13,
+ "Name": "PVDQ_DEF_CPU1",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.301
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.138
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.104
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 2,
+ "Name": "PVNN_PCH_AUX",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.081
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.049
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.807
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.783
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Address": "0x4B",
+ "Bus": 6,
+ "Name": "Right Rear Board Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x49",
+ "Bus": 6,
+ "Name": "Left Rear Board Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x48",
+ "Bus": 6,
+ "Name": "PCH M.2 Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x4f",
+ "Bus": 6,
+ "Name": "Inlet BRD Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x30",
+ "Bus": 0,
+ "CpuID": 0,
+ "Name": "Skylake CPU 0",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 99,
+ "label": "DIMM"
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 89,
+ "label": "DIMM"
+ }
+ ],
+ "Type": "SkylakeCPU"
+ },
+ {
+ "Address": "0x31",
+ "Bus": 0,
+ "CpuID": 1,
+ "Name": "Skylake CPU 1",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 99,
+ "label": "DIMM"
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 89,
+ "label": "DIMM"
+ }
+ ],
+ "Type": "SkylakeCPU"
+ },
+ {
+ "BindConnector": "System Fan connector 1",
+ "Index": 0,
+ "Name": "Fan 1a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 1",
+ "Index": 1,
+ "Name": "Fan 1b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 2",
+ "Index": 2,
+ "Name": "Fan 2a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 2",
+ "Index": 3,
+ "Name": "Fan 2b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 3",
+ "Index": 4,
+ "Name": "Fan 3a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 3",
+ "Index": 5,
+ "Name": "Fan 3b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 4",
+ "Index": 6,
+ "Name": "Fan 4a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 4",
+ "Index": 7,
+ "Name": "Fan 4b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 5",
+ "Index": 8,
+ "Name": "Fan 5a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 5",
+ "Index": 9,
+ "Name": "Fan 5b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 6",
+ "Index": 10,
+ "Name": "Fan 6a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 6",
+ "Index": 11,
+ "Name": "Fan 6b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 7",
+ "Index": 12,
+ "Name": "Fan 7a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 7",
+ "Index": 13,
+ "Name": "Fan 7b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 8",
+ "Index": 14,
+ "Name": "Fan 8a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 8",
+ "Index": 15,
+ "Name": "Fan 8b",
+ "Type": "AspeedFan"
+ },
+ {
+ "AlphaF": 4.352,
+ "AlphaS": 0.512,
+ "Name": "Exit Air Temp",
+ "PowerFactorMax": 10,
+ "PowerFactorMin": 4,
+ "QMax": 88,
+ "QMin": 15,
+ "Type": "ExitAirTempSensor"
+ },
+ {
+ "C1": 92.16,
+ "C2": 107.52,
+ "MaxCFM": 17.5,
+ "Name": "System Airflow",
+ "TachMaxPercent": 100,
+ "TachMinPercent": 20,
+ "Tachs": [
+ "Fan 1a",
+ "Fan 1b",
+ "Fan 2a",
+ "Fan 2b",
+ "Fan 3a",
+ "Fan 3b",
+ "Fan 4a",
+ "Fan 4b",
+ "Fan 5a",
+ "Fan 5b",
+ "Fan 6a",
+ "Fan 6b",
+ "Fan 7a",
+ "Fan 7b",
+ "Fan 8a",
+ "Fan 8b"
+ ],
+ "Type": "CFMSensor"
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 1a",
+ "Fan 1b"
+ ],
+ "Name": "Fan 1",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 1"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Left"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 2a",
+ "Fan 2b"
+ ],
+ "Name": "Fan 2",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 2"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Left"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 3a",
+ "Fan 3b"
+ ],
+ "Name": "Fan 3",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 3"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Left"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 4a",
+ "Fan 4b"
+ ],
+ "Name": "Fan 4",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 4"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Left"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 5a",
+ "Fan 5b"
+ ],
+ "Name": "Fan 5",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 5"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Right"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 6a",
+ "Fan 6b"
+ ],
+ "Name": "Fan 6",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 6"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Right"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 7a",
+ "Fan 7b"
+ ],
+ "Name": "Fan 7",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 7"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Right"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 8a",
+ "Fan 8b"
+ ],
+ "Name": "Fan 8",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 8"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Right"
+ ]
+ },
+ {
+ "FailSafePercent": 100,
+ "MinThermalRpm": 3000,
+ "Name": "Left",
+ "Type": "Pid.Zone"
+ },
+ {
+ "FailSafePercent": 100,
+ "MinThermalRpm": 3000,
+ "Name": "Right",
+ "Type": "Pid.Zone"
+ },
+ {
+ "AllowedFailures": 1,
+ "Name": "FanRedundancy",
+ "Type": "FanRedundancy"
+ },
+ {
+ "Class": "temp",
+ "FFGainCoefficient": 0.0,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": -0.2,
+ "ILimitMax": 100,
+ "ILimitMin": 30,
+ "Inputs": [
+ "Core \\d+ CPU0"
+ ],
+ "Name": "CPU0",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100,
+ "OutLimitMin": 30,
+ "Outputs": [],
+ "PCoefficient": -3.0,
+ "PositiveHysteresis": 0.0,
+ "SetPoint": 45.0,
+ "SlewNeg": -1,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Left"
+ ]
+ },
+ {
+ "Class": "temp",
+ "FFGainCoefficient": 0.0,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": -0.2,
+ "ILimitMax": 100,
+ "ILimitMin": 30,
+ "Inputs": [
+ "Core \\d+ CPU1"
+ ],
+ "Name": "CPU1",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100,
+ "OutLimitMin": 30,
+ "Outputs": [],
+ "PCoefficient": -3.0,
+ "PositiveHysteresis": 0.0,
+ "SetPoint": 45.0,
+ "SlewNeg": -1,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Right"
+ ]
+ },
+ {
+ "Direction": "In",
+ "Index": 48,
+ "Name": "CPU ERR2",
+ "Polarity": "High",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 49,
+ "Name": "CPU CATERR",
+ "Polarity": "High",
+ "Type": "Gpio"
+ },
+ {
+ "Class": "Floor",
+ "Inputs": [
+ "Front Panel Temp"
+ ],
+ "Name": "Front Panel LCC",
+ "NegativeHysteresis": 2,
+ "Output": [
+ 50.0,
+ 60.0
+ ],
+ "PositiveHysteresis": 0,
+ "Reading": [
+ 20.0,
+ 30.0
+ ],
+ "Type": "Stepwise",
+ "Zones": [
+ "Left",
+ "Right"
+ ]
+ },
+ {
+ "Address": "0x8",
+ "Class": "METemp",
+ "Name": "SSB Temp",
+ "PowerState": "BiosPost",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 103
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 98
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xC4",
+ "Class": "MpsBridgeTemp",
+ "Name": "CPU1 P12V PVCCIN VR Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xB4",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU1 P12V PVCCIO VR Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xDC",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU1 VR Mem ABCD Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xDC",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU1 VR Mem EFGH Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x4A",
+ "Class": "IRBridgeTemp",
+ "Name": "CPU1 VR P1V8",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xCC",
+ "Class": "MpsBridgeTemp",
+ "Name": "CPU2 P12V PVCCIN VR Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xD4",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU2 P12V PVCCIO VR Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xB0",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU2 VR Mem ABCD Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xEC",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU2 VR Mem EFGH Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x4C",
+ "Class": "IRBridgeTemp",
+ "Name": "CPU2 VR P1V8",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x4D",
+ "Bus": "0x1",
+ "Name": "Front Panel Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 55
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 50
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x71",
+ "Bus": 2,
+ "ChannelNames": [
+ "M2Slot1",
+ "M2Slot2"
+ ],
+ "Name": "M2 Mux",
+ "Type": "PCA9543Mux"
+ },
+ {
+ "Address": "0x72",
+ "Bus": 2,
+ "ChannelNames": [
+ "PcieSlot1",
+ "PcieSlot2",
+ "",
+ "FruChannel"
+ ],
+ "Name": "Riser 1 Mux",
+ "Type": "PCA9545Mux"
+ },
+ {
+ "Address": "0x73",
+ "Bus": 2,
+ "ChannelNames": [
+ "PcieSlot1",
+ "PcieSlot2",
+ "",
+ "FruChannel"
+ ],
+ "Name": "Riser 2 Mux",
+ "Type": "PCA9545Mux"
+ },
+ {
+ "Address": "0x74",
+ "Bus": 2,
+ "ChannelNames": [
+ "PcieSlot1",
+ "PcieSlot2",
+ "PcieSlot3",
+ "PcieSlot4"
+ ],
+ "Name": "PCIE Mux",
+ "Type": "PCA9546Mux"
+ },
+ {
+ "Address": "0x73",
+ "Bus": 9,
+ "ChannelNames": [
+ "MemoryChannel1",
+ "MemoryChannel2",
+ "MemoryChannel3",
+ "MemoryChannel4"
+ ],
+ "Name": "Memory Mux",
+ "Type": "PCA9545Mux"
+ },
+ {
+ "Class": "Ceiling",
+ "Inputs": [
+ "Front Panel Temp"
+ ],
+ "Name": "Front Panel UCC",
+ "NegativeHysteresis": 2,
+ "Output": [
+ 70.0,
+ 80.0
+ ],
+ "PositiveHysteresis": 0,
+ "Reading": [
+ 22.0,
+ 32.0
+ ],
+ "Type": "Stepwise",
+ "Zones": [
+ "Left",
+ "Right"
+ ]
+ },
+ {
+ "Controllers": [
+ ".*"
+ ],
+ "Name": "Acoustic",
+ "Type": "FanProfile"
+ },
+ {
+ "Controllers": [
+ "Front Panel LCC",
+ "CPU\\d"
+ ],
+ "Name": "Performance",
+ "Type": "FanProfile"
+ }
+ ],
+ "Name": "WC Baseboard",
+ "Probe": "xyz.openbmc_project.FruDevice({'PRODUCT_PRODUCT_NAME': '.*WC'})",
+ "Type": "Board",
+ "xyz.openbmc_project.Inventory.Decorator.Asset": {
+ "Manufacturer": "$PRODUCT_MANUFACTURER",
+ "Model": "$PRODUCT_PRODUCT_NAME",
+ "PartNumber": "$PRODUCT_PART_NUMBER",
+ "SerialNumber": "$PRODUCT_SERIAL_NUMBER"
+ }
+} \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/WP-Baseboard.json b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/WP-Baseboard.json
new file mode 100644
index 000000000..bd32ae60d
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager/WP-Baseboard.json
@@ -0,0 +1,1734 @@
+{
+ "Exposes": [
+ {
+ "Name": "System Fan connector 1",
+ "Pwm": 0,
+ "Tachs": [
+ 0,
+ 1
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 2",
+ "Pwm": 1,
+ "Tachs": [
+ 2,
+ 3
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 3",
+ "Pwm": 2,
+ "Tachs": [
+ 4,
+ 5
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 4",
+ "Pwm": 3,
+ "Tachs": [
+ 6,
+ 7
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 5",
+ "Pwm": 4,
+ "Tachs": [
+ 8,
+ 9
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 6",
+ "Pwm": 5,
+ "Tachs": [
+ 10,
+ 11
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 7",
+ "Pwm": 6,
+ "Tachs": [
+ 12,
+ 13
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Name": "System Fan connector 8",
+ "Pwm": 7,
+ "Tachs": [
+ 14,
+ 15
+ ],
+ "Type": "IntelFanConnector"
+ },
+ {
+ "Address": "0x4A",
+ "Bus": 6,
+ "Name": "BMC Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Index": 0,
+ "Name": "A_P12V_PSU_SCALED",
+ "PowerState": "On",
+ "ScaleFactor": 0.1124,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 13.494
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 13.101
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 10.945
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 10.616
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 4,
+ "Name": "P0V83_LAN_AUX",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 0.901
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 0.875
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.786
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.763
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 3,
+ "Name": "P105_PCH_AUX",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.139
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.106
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.995
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.966
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 5,
+ "Name": "P12V_AUX",
+ "ScaleFactor": 0.1124,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 13.494
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 13.101
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 10.945
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 10.616
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 6,
+ "Name": "P1V8_PCH",
+ "ScaleFactor": 0.7505,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.961
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.904
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.699
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.648
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 1,
+ "Name": "P3V3",
+ "PowerState": "On",
+ "ScaleFactor": 0.4107,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 3.647
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 3.541
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 3.066
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 2.974
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 7,
+ "Name": "P3VBAT",
+ "ScaleFactor": 0.3333,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 3.296
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 3.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 2.457
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 2.138
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 8,
+ "Name": "PVCCIN_CPU0",
+ "PowerState": "On",
+ "ScaleFactor": 0.7505,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 2.151
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 2.088
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.418
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.376
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 9,
+ "Name": "PVCCIN_CPU1",
+ "PowerState": "On",
+ "ScaleFactor": 0.7505,
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 2.151
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 2.088
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.418
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.376
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 14,
+ "Name": "PVCCIO_CPU0",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.19
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.155
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.752
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.729
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 15,
+ "Name": "PVCCIO_CPU1",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.19
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.155
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.752
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.729
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 10,
+ "Name": "PVDQ_ABC_CPU0",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.301
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.138
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.104
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 12,
+ "Name": "PVDQ_ABC_CPU1",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.301
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.138
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.104
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 11,
+ "Name": "PVDQ_DEF_CPU0",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.301
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.138
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.104
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 13,
+ "Name": "PVDQ_DEF_CPU1",
+ "PowerState": "On",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.301
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.263
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 1.138
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 1.104
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Index": 2,
+ "Name": "PVNN_PCH_AUX",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 1.081
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 1.049
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 0.807
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0.783
+ }
+ ],
+ "Type": "ADC"
+ },
+ {
+ "Address": "0x4B",
+ "Bus": 6,
+ "Name": "Right Rear Board Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x49",
+ "Bus": 6,
+ "Name": "Left Rear Board Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x48",
+ "Bus": 6,
+ "Name": "PCH M.2 Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x4f",
+ "Bus": 6,
+ "Name": "Inlet BRD Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x30",
+ "Bus": 0,
+ "CpuID": 0,
+ "Name": "Skylake CPU 0",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 99,
+ "label": "DIMM"
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 89,
+ "label": "DIMM"
+ }
+ ],
+ "Type": "SkylakeCPU"
+ },
+ {
+ "Address": "0x31",
+ "Bus": 0,
+ "CpuID": 1,
+ "Name": "Skylake CPU 1",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 99,
+ "label": "DIMM"
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 89,
+ "label": "DIMM"
+ }
+ ],
+ "Type": "SkylakeCPU"
+ },
+ {
+ "BindConnector": "System Fan connector 1",
+ "Index": 0,
+ "Name": "Fan 1a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 1",
+ "Index": 1,
+ "Name": "Fan 1b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 2",
+ "Index": 2,
+ "Name": "Fan 2a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 2",
+ "Index": 3,
+ "Name": "Fan 2b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 3",
+ "Index": 4,
+ "Name": "Fan 3a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 3",
+ "Index": 5,
+ "Name": "Fan 3b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 4",
+ "Index": 6,
+ "Name": "Fan 4a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 4",
+ "Index": 7,
+ "Name": "Fan 4b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 5",
+ "Index": 8,
+ "Name": "Fan 5a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 5",
+ "Index": 9,
+ "Name": "Fan 5b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 6",
+ "Index": 10,
+ "Name": "Fan 6a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 6",
+ "Index": 11,
+ "Name": "Fan 6b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 7",
+ "Index": 12,
+ "Name": "Fan 7a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 7",
+ "Index": 13,
+ "Name": "Fan 7b",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 8",
+ "Index": 14,
+ "Name": "Fan 8a",
+ "Type": "AspeedFan"
+ },
+ {
+ "BindConnector": "System Fan connector 8",
+ "Index": 15,
+ "Name": "Fan 8b",
+ "Type": "AspeedFan"
+ },
+ {
+ "AlphaF": 4.352,
+ "AlphaS": 0.512,
+ "Name": "Exit Air Temp",
+ "PowerFactorMax": 10,
+ "PowerFactorMin": 4,
+ "QMax": 88,
+ "QMin": 15,
+ "Type": "ExitAirTempSensor"
+ },
+ {
+ "C1": 92.16,
+ "C2": 107.52,
+ "MaxCFM": 17.5,
+ "Name": "System Airflow",
+ "TachMaxPercent": 100,
+ "TachMinPercent": 20,
+ "Tachs": [
+ "Fan 1a",
+ "Fan 1b",
+ "Fan 2a",
+ "Fan 2b",
+ "Fan 3a",
+ "Fan 3b",
+ "Fan 4a",
+ "Fan 4b",
+ "Fan 5a",
+ "Fan 5b",
+ "Fan 6a",
+ "Fan 6b",
+ "Fan 7a",
+ "Fan 7b",
+ "Fan 8a",
+ "Fan 8b"
+ ],
+ "Type": "CFMSensor"
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 1a",
+ "Fan 1b"
+ ],
+ "Name": "Fan 1",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 1"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Left"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 2a",
+ "Fan 2b"
+ ],
+ "Name": "Fan 2",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 2"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Left"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 3a",
+ "Fan 3b"
+ ],
+ "Name": "Fan 3",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 3"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Left"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 4a",
+ "Fan 4b"
+ ],
+ "Name": "Fan 4",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 4"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Left"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 5a",
+ "Fan 5b"
+ ],
+ "Name": "Fan 5",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 5"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Right"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 6a",
+ "Fan 6b"
+ ],
+ "Name": "Fan 6",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 6"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Right"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 7a",
+ "Fan 7b"
+ ],
+ "Name": "Fan 7",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 7"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Right"
+ ]
+ },
+ {
+ "Class": "fan",
+ "FFGainCoefficient": 0.01,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": 0.0,
+ "ILimitMax": 0.0,
+ "ILimitMin": 0.0,
+ "Inputs": [
+ "Fan 8a",
+ "Fan 8b"
+ ],
+ "Name": "Fan 8",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100.0,
+ "OutLimitMin": 30.0,
+ "Outputs": [
+ "Pwm 8"
+ ],
+ "PCoefficient": 0.0,
+ "PositiveHysteresis": 0.0,
+ "SlewNeg": 0.0,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Right"
+ ]
+ },
+ {
+ "FailSafePercent": 100,
+ "MinThermalRpm": 3000,
+ "Name": "Left",
+ "Type": "Pid.Zone"
+ },
+ {
+ "FailSafePercent": 100,
+ "MinThermalRpm": 3000,
+ "Name": "Right",
+ "Type": "Pid.Zone"
+ },
+ {
+ "AllowedFailures": 1,
+ "Name": "FanRedundancy",
+ "Type": "FanRedundancy"
+ },
+ {
+ "Class": "temp",
+ "FFGainCoefficient": 0.0,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": -0.2,
+ "ILimitMax": 100,
+ "ILimitMin": 30,
+ "Inputs": [
+ "Core \\d+ CPU0"
+ ],
+ "Name": "CPU0",
+ "NegativeHysteresis": 2.0,
+ "OutLimitMax": 100,
+ "OutLimitMin": 30,
+ "Outputs": [],
+ "PCoefficient": -3.0,
+ "PositiveHysteresis": 0.0,
+ "SetPoint": 45.0,
+ "SlewNeg": -1,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Left"
+ ]
+ },
+ {
+ "Class": "temp",
+ "FFGainCoefficient": 0.0,
+ "FFOffCoefficient": 0.0,
+ "ICoefficient": -0.2,
+ "ILimitMax": 100,
+ "ILimitMin": 30,
+ "Inputs": [
+ "Core \\d+ CPU1"
+ ],
+ "Name": "CPU1",
+ "OutLimitMax": 100,
+ "OutLimitMin": 30,
+ "Outputs": [],
+ "PCoefficient": -3.0,
+ "SetPoint": 45.0,
+ "SlewNeg": -1,
+ "SlewPos": 0.0,
+ "Type": "Pid",
+ "Zones": [
+ "Right"
+ ]
+ },
+ {
+ "Direction": "In",
+ "Index": 48,
+ "Name": "CPU ERR2",
+ "Polarity": "High",
+ "Type": "Gpio"
+ },
+ {
+ "Direction": "Input",
+ "Index": 49,
+ "Name": "CPU CATERR",
+ "Polarity": "High",
+ "Type": "Gpio"
+ },
+ {
+ "Class": "Floor",
+ "Inputs": [
+ "Front Panel Temp"
+ ],
+ "Name": "Front Panel LCC",
+ "NegativeHysteresis": 2,
+ "Output": [
+ 50.0,
+ 60.0
+ ],
+ "PositiveHysteresis": 0,
+ "Reading": [
+ 20.0,
+ 30.0
+ ],
+ "Type": "Stepwise",
+ "Zones": [
+ "Left",
+ "Right"
+ ]
+ },
+ {
+ "Address": "0x8",
+ "Class": "METemp",
+ "Name": "SSB Temp",
+ "PowerState": "BiosPost",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 103
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 98
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xC4",
+ "Class": "MpsBridgeTemp",
+ "Name": "CPU1 P12V PVCCIN VR Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xB4",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU1 P12V PVCCIO VR Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xDC",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU1 VR Mem ABCD Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xDC",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU1 VR Mem EFGH Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x4A",
+ "Class": "IRBridgeTemp",
+ "Name": "CPU1 VR P1V8",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xCC",
+ "Class": "MpsBridgeTemp",
+ "Name": "CPU2 P12V PVCCIN VR Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xD4",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU2 P12V PVCCIO VR Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xB0",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU2 VR Mem ABCD Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0xEC",
+ "Class": "PxeBridgeTemp",
+ "Name": "CPU2 VR Mem EFGH Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x4C",
+ "Class": "IRBridgeTemp",
+ "Name": "CPU2 VR P1V8",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 115
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 110
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "IpmbSensor"
+ },
+ {
+ "Address": "0x4D",
+ "Bus": "0x1",
+ "Name": "Front Panel Temp",
+ "Thresholds": [
+ {
+ "Direction": "greater than",
+ "Name": "upper critical",
+ "Severity": 1,
+ "Value": 55
+ },
+ {
+ "Direction": "greater than",
+ "Name": "upper non critical",
+ "Severity": 0,
+ "Value": 50
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower non critical",
+ "Severity": 0,
+ "Value": 5
+ },
+ {
+ "Direction": "less than",
+ "Name": "lower critical",
+ "Severity": 1,
+ "Value": 0
+ }
+ ],
+ "Type": "TMP75"
+ },
+ {
+ "Address": "0x71",
+ "Bus": 2,
+ "ChannelNames": [
+ "M2Slot1",
+ "M2Slot2"
+ ],
+ "Name": "M2 Mux",
+ "Type": "PCA9543Mux"
+ },
+ {
+ "Address": "0x72",
+ "Bus": 2,
+ "ChannelNames": [
+ "PcieSlot1",
+ "PcieSlot2",
+ "",
+ "FruChannel"
+ ],
+ "Name": "Riser 1 Mux",
+ "Type": "PCA9545Mux"
+ },
+ {
+ "Address": "0x73",
+ "Bus": 2,
+ "ChannelNames": [
+ "PcieSlot1",
+ "PcieSlot2",
+ "",
+ "FruChannel"
+ ],
+ "Name": "Riser 2 Mux",
+ "Type": "PCA9545Mux"
+ },
+ {
+ "Address": "0x74",
+ "Bus": 2,
+ "ChannelNames": [
+ "PcieSlot1",
+ "PcieSlot2",
+ "PcieSlot3",
+ "PcieSlot4"
+ ],
+ "Name": "PCIE Mux",
+ "Type": "PCA9546Mux"
+ },
+ {
+ "Address": "0x73",
+ "Bus": 9,
+ "ChannelNames": [
+ "MemoryChannel1",
+ "MemoryChannel2",
+ "MemoryChannel3",
+ "MemoryChannel4"
+ ],
+ "Name": "Memory Mux",
+ "Type": "PCA9545Mux"
+ },
+ {
+ "Class": "Ceiling",
+ "Inputs": [
+ "Front Panel Temp"
+ ],
+ "Name": "Front Panel UCC",
+ "NegativeHysteresis": 2,
+ "Output": [
+ 70.0,
+ 80.0
+ ],
+ "PositiveHysteresis": 0,
+ "Reading": [
+ 22.0,
+ 32.0
+ ],
+ "Type": "Stepwise",
+ "Zones": [
+ "Left",
+ "Right"
+ ]
+ },
+ {
+ "Controllers": [
+ ".*"
+ ],
+ "Name": "Acoustic",
+ "Type": "FanProfile"
+ },
+ {
+ "Controllers": [
+ "Front Panel LCC",
+ "CPU\\d"
+ ],
+ "Name": "Performance",
+ "Type": "FanProfile"
+ }
+ ],
+ "Name": "WP Baseboard",
+ "Probe": "xyz.openbmc_project.FruDevice({'PRODUCT_PRODUCT_NAME': '.*WP'})",
+ "Type": "Board",
+ "xyz.openbmc_project.Inventory.Decorator.Asset": {
+ "Manufacturer": "$PRODUCT_MANUFACTURER",
+ "Model": "$PRODUCT_PRODUCT_NAME",
+ "PartNumber": "$PRODUCT_PART_NUMBER",
+ "SerialNumber": "$PRODUCT_SERIAL_NUMBER"
+ }
+} \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager_%.bbappend b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager_%.bbappend
new file mode 100644
index 000000000..a2861c4ca
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager_%.bbappend
@@ -0,0 +1,13 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+SRC_URI_append = " file://WC-Baseboard.json \
+ file://WP-Baseboard.json \
+ file://TNP-baseboard.json \
+ file://FCXXPDBASSMBL_PDB.json \
+ file://OPB2RH-Chassis.json"
+
+RDEPENDS_${PN} += " default-fru"
+
+do_install_append(){
+ install -d ${D}/usr/share/entity-manager/configurations
+ install -m 0444 ${WORKDIR}/*.json ${D}/usr/share/entity-manager/configurations
+}
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console/obmc-console.conf b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console/obmc-console.conf
new file mode 100644
index 000000000..1d332e2a2
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console/obmc-console.conf
@@ -0,0 +1,3 @@
+baud = 921600
+local-tty = ttyS3
+local-tty-baud = 921600
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console/obmc-console@.service b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console/obmc-console@.service
new file mode 100644
index 000000000..7fb8f79d3
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console/obmc-console@.service
@@ -0,0 +1,21 @@
+[Unit]
+Description=Phosphor Console Muxer listening on device /dev/%I
+BindsTo=dev-%i.device
+After=dev-%i.device
+
+[Service]
+ExecStartPre=/usr/bin/sol-option-check.sh
+ExecStartPre=/bin/sh -c 'echo -n "uart3" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/uart1'
+ExecStartPre=/bin/sh -c 'echo -n "uart1" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/uart3'
+ExecStartPre=/bin/sh -c 'echo -n "io1" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/uart4'
+ExecStartPre=/bin/sh -c 'echo -n "uart4" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/io1'
+ExecStart=/usr/bin/env obmc-console-server --config {sysconfdir}/obmc-console.conf %i
+ExecStopPost=/bin/sh -c 'echo -n "io1" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/uart1'
+ExecStopPost=/bin/sh -c 'echo -n "io3" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/uart3'
+ExecStopPost=/bin/sh -c 'echo -n "io4" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/uart4'
+ExecStopPost=/bin/sh -c 'echo -n "uart1" > /sys/bus/platform/drivers/aspeed-uart-routing/1e78909c.uart_routing/io1'
+SyslogIdentifier=obmc-console-server
+Restart=always
+
+[Install]
+WantedBy={SYSTEMD_DEFAULT_TARGET}
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console/sol-option-check.sh b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console/sol-option-check.sh
new file mode 100755
index 000000000..ef32fcb9a
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console/sol-option-check.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# Copyright 2017 Intel Corporation
+#
+# 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.
+#
+#
+
+if [ $(grep 192000000 /sys/class/tty/ttyS0/uartclk | wc -l) != 0 ]; then
+ echo "hs-uart"
+ sed -i -e 's/115200/921600/g' /etc/obmc-console.conf
+else
+ echo "normal uart"
+ sed -i -e 's/921600/115200/g' /etc/obmc-console.conf
+fi
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console_%.bbappend b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console_%.bbappend
new file mode 100644
index 000000000..c2aad5e50
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/console/obmc-console_%.bbappend
@@ -0,0 +1,8 @@
+FILESEXTRAPATHS_prepend_wolfpass := "${THISDIR}/${PN}:"
+OBMC_CONSOLE_HOST_TTY = "ttyS2"
+SRC_URI += "file://sol-option-check.sh"
+
+do_install_append() {
+ install -d ${D}${bindir}
+ install -m 0755 ${WORKDIR}/sol-option-check.sh ${D}${bindir}
+}
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fans/fan-default-speed.bb b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fans/fan-default-speed.bb
new file mode 100644
index 000000000..9c10c5b3d
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fans/fan-default-speed.bb
@@ -0,0 +1,20 @@
+SUMMARY = "Set Wolfpass fan default speeds"
+DESCRIPTION = "Sets all fans to a single speed"
+
+inherit allarch
+inherit obmc-phosphor-systemd
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+RDEPENDS_${PN} += "python"
+
+S = "${WORKDIR}"
+SRC_URI += "file://set_fan_speeds.py"
+
+SYSTEMD_SERVICE_${PN} += "fan-default-speed.service"
+
+do_install() {
+ install -d ${D}/${bindir}
+ install -m 0755 ${WORKDIR}/set_fan_speeds.py ${D}/${bindir}/set_fan_speeds.py
+}
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fans/fan-default-speed/fan-default-speed.service b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fans/fan-default-speed/fan-default-speed.service
new file mode 100644
index 000000000..267fdee43
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fans/fan-default-speed/fan-default-speed.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Set fans to a default speed
+ConditionFileNotEmpty={bindir}/set_fan_speeds.py
+
+[Service]
+ExecStart={bindir}/set_fan_speeds.py 150
+Type=oneshot
+
+[Install]
+WantedBy=default.target
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fans/fan-default-speed/set_fan_speeds.py b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fans/fan-default-speed/set_fan_speeds.py
new file mode 100644
index 000000000..70ba64799
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fans/fan-default-speed/set_fan_speeds.py
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+import os
+import glob
+import time
+import sys
+
+HWMON_DIR = "/sys/class/hwmon/hwmon0"
+
+count = 0
+inputs = None
+while not inputs:
+ count += 1
+ if count > 20:
+ print("pwm missing!")
+ sys.exit(0)
+
+ inputs = glob.glob(os.path.join(HWMON_DIR, "pwm*"))
+ time.sleep(5)
+
+inputs = glob.glob(os.path.join(HWMON_DIR, "pwm*"))
+for pwm in inputs:
+ with open(pwm, 'w') as f:
+ f.write(sys.argv[1])
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru.bb b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru.bb
new file mode 100644
index 000000000..af0505d1f
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru.bb
@@ -0,0 +1,27 @@
+SUMMARY = "Default Fru"
+DESCRIPTION = "Installs a default fru file to image"
+
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} = "SetBaseboardFru.service"
+
+S = "${WORKDIR}"
+SRC_URI = "file://checkFru.sh \
+ file://SetBaseboardFru.service \
+ file://*.fru.bin"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENCE;md5=a6a4edad4aed50f39a66d098d74b265b"
+
+RDEPENDS_${PN} = "bash"
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/checkFru.sh ${D}/${bindir}/checkFru.sh
+
+ install -d ${D}${sysconfdir}/fru
+ cp ${S}/*.fru.bin ${D}/${sysconfdir}/fru
+
+ install -d ${D}${base_libdir}/systemd/system
+ install -m 0644 ${S}/SetBaseboardFru.service ${D}${base_libdir}/systemd/system
+}
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/LICENCE b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/LICENCE
new file mode 100644
index 000000000..dd0408376
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/LICENCE
@@ -0,0 +1,13 @@
+Copyright 2018 Intel Corporation
+
+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. \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600CYP.fru.bin b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600CYP.fru.bin
new file mode 100644
index 000000000..ba5b96392
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600CYP.fru.bin
Binary files differ
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600TNP.fru.bin b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600TNP.fru.bin
new file mode 100644
index 000000000..afd58e6b9
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600TNP.fru.bin
Binary files differ
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600WC.fru.bin b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600WC.fru.bin
new file mode 100644
index 000000000..76c4b8d4b
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600WC.fru.bin
Binary files differ
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600WFT.fru.bin b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600WFT.fru.bin
new file mode 100644
index 000000000..1b9f97ff4
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600WFT.fru.bin
Binary files differ
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600WP.fru.bin b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600WP.fru.bin
new file mode 100644
index 000000000..fb219c0ce
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/S2600WP.fru.bin
Binary files differ
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/SetBaseboardFru.service b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/SetBaseboardFru.service
new file mode 100644
index 000000000..dec53725e
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/SetBaseboardFru.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Reads GPIO and Loads the FRU
+
+[Service]
+ExecStart=/usr/bin/checkFru.sh
+Type=oneshot
+
+[Install]
+WantedBy=basic.target
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/checkFru.sh b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/checkFru.sh
new file mode 100755
index 000000000..1eb79b299
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/checkFru.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# this script checks the gpio id and loads the correct baseboard fru
+fruFile="/etc/fru/baseboard.fru.bin"
+idGpio=( 8 9 10 11 12 53)
+result=0
+idx=0
+
+if [ -f $fruFile ]; then
+ exit 0
+fi
+
+cd /etc/fru
+for gpio in "${idGpio[@]}"
+do
+ echo $gpio > /sys/class/gpio/export
+ typeset -i value=$(cat /sys/class/gpio/gpio$gpio/value)
+ value=$((value << idx))
+ result=$((result | value))
+ idx=$((idx+1))
+done
+
+# wp
+if (($result == 62)); then
+ cat S2600WP.fru.bin > $fruFile
+# wc
+elif (($result == 45)); then
+ cat S2600WC.fru.bin > $fruFile
+# cyp
+elif (($result == 60)); then
+ cat S2600CYP.fru.bin > $fruFile
+# tnp
+elif (($result == 12)); then
+ cat S2600TNP.fru.bin > $fruFile
+# default to wft
+else
+ cat S2600WFT.fru.bin > $fruFile
+fi
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/workbook/wolfpass-config.bb b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/workbook/wolfpass-config.bb
new file mode 100644
index 000000000..c91053536
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/workbook/wolfpass-config.bb
@@ -0,0 +1,10 @@
+SUMMARY = "Wolfpass board wiring"
+DESCRIPTION = "Board wiring information for the Wolfpass system."
+PR = "r1"
+
+inherit config-in-skeleton
+
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SRCREV = "946064239016e38cd1cc346047b1d26960c06cdb"
+SKELETON_URI = "git://git@github.com/Intel-BMC/skeleton.git;protocol=ssh;branch=intel"
diff --git a/meta-openbmc-mods/meta-wolfpass/recipes.txt b/meta-openbmc-mods/meta-wolfpass/recipes.txt
new file mode 100644
index 000000000..3ec3f4a42
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes.txt
@@ -0,0 +1,2 @@
+recipes-kernel - The kernel and generic applications/libraries with strong kernel dependencies
+recipes-phosphor - Phosphor OpenBMC applications and configuration