summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods
diff options
context:
space:
mode:
authorEd Tanous <ed.tanous@intel.com>2019-02-14 03:51:50 +0300
committerEd Tanous <ed.tanous@intel.com>2019-03-13 00:58:57 +0300
commita7715486507e75e4a7cee843a48067b15595defa (patch)
tree9fd209d468c42cfb6553a50e2523c1d7e1fb120a /meta-openbmc-mods
parent9b44ea7e2de71224bce792654cab12b7a5ceaa7d (diff)
downloadopenbmc-a7715486507e75e4a7cee843a48067b15595defa.tar.xz
Initial commit of intel repository
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
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.inc21
-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.bbclass36
-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/fstab8
-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/bmcweb/bmcweb/0001-Refine-KVM-websock-proxy.patch119
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/bmcweb/bmcweb_%.bbappend16
-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/intel-fw-update.bb18
-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/nv-overlay/files/nv-overlay.service15
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-core/nv-overlay/files/nv-overlay.sh141
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/nv-overlay/nv-overlay.bb19
-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/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/.clang-format98
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/LICENSE201
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/MAINTAINERS45
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/Makefile.am31
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/README.md18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/bootstrap.sh18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/configure.ac29
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/create_usbhid.sh135
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_args.cpp57
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_args.hpp123
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_input.cpp380
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_input.hpp111
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_manager.cpp100
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_manager.hpp75
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_server.cpp218
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_server.hpp167
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_video.cpp478
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_video.hpp150
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/obmc-ikvm.cpp12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/scancodes.hpp82
-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.bb43
-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.patch276
-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.patch565
-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/0025-dts-add-AST2500-LPC-SIO-tree-node.patch32
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch392
-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.patch1982
-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/intel.cfg1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend31
-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_%.bbappend16
-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/0001-image_verify-Add-support-for-OpenSSL-1.1.0.patch130
-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_%.bbappend1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-channel-inventory%.bbappend4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-channel-inventory%/channel.yaml8
-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/phosphor-ipmi-host.service26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend29
-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_%.bbappend13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-node-manager-proxy_git.bb19
-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.yaml36
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/logging/phosphor-logging_%.bbappend2
-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_%.bbappend8
-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.patch192
-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_%.bbappend8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/system/obmc-mgr-system%.bbappend2
-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_%.bbappend5
-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/obmc-enable-host-watchdog@.service14
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend4
-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.patch242
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend3
-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/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.cfg60
-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/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_%.bbappend10
-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/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.sh35
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes-phosphor/workbook/wolfpass-config.bb10
-rw-r--r--meta-openbmc-mods/meta-wolfpass/recipes.txt2
312 files changed, 35347 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..8fcab4a0a
--- /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 = "sumo"
+
+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..7fe8bf50f
--- /dev/null
+++ b/meta-openbmc-mods/conf/machine/include/intel.inc
@@ -0,0 +1,21 @@
+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"
+
+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..7deca9c05
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass
@@ -0,0 +1,36 @@
+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 \
+ nv-overlay \
+ 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 \
+ "
+
+# 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..8d4a67ec5
--- /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 = "de77d02aefa3c9df62365e7f07224c5cf9b0eb96"
+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..8d65eb990
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab
@@ -0,0 +1,8 @@
+/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
+
+# 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/bmcweb/bmcweb/0001-Refine-KVM-websock-proxy.patch b/meta-openbmc-mods/meta-common/recipes-core/bmcweb/bmcweb/0001-Refine-KVM-websock-proxy.patch
new file mode 100644
index 000000000..acbfebdee
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/bmcweb/bmcweb/0001-Refine-KVM-websock-proxy.patch
@@ -0,0 +1,119 @@
+From 430bfc33ee396e4aced0514b66703e5c58a7503d Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 26 Feb 2019 15:46:07 -0800
+Subject: [PATCH] Refine KVM websock proxy
+
+This commit simplifies input buffer delivering logic by removing
+a doWrite() call from readDone(). Input events can be delivered
+through websocket's onmessage handler only and it's enough.
+
+Also, it fixes a suspicious weak point of commit/consume pair on
+outputBuffer.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ include/kvm_websocket.hpp | 57 +++++++++++++++++++++--------------------------
+ 1 file changed, 26 insertions(+), 31 deletions(-)
+
+diff --git a/include/kvm_websocket.hpp b/include/kvm_websocket.hpp
+index aa2eaecc3205..447171b9981a 100644
+--- a/include/kvm_websocket.hpp
++++ b/include/kvm_websocket.hpp
+@@ -20,53 +20,48 @@ static boost::beast::flat_static_buffer<1024U> inputBuffer;
+
+ static crow::websocket::Connection* session = nullptr;
+
+-static bool doingWrite = false;
++inline void doWrite();
+
+-inline void doWrite()
++inline void WriteDone(const boost::system::error_code& ec,
++ std::size_t bytesWritten)
+ {
+- if (doingWrite)
++ BMCWEB_LOG_DEBUG << "Wrote " << bytesWritten << "bytes";
++ inputBuffer.consume(bytesWritten);
++
++ if (session == nullptr)
++ {
++ return;
++ }
++ if (ec == boost::asio::error::eof)
++ {
++ session->close("KVM socket port closed");
++ return;
++ }
++ if (ec)
+ {
+- BMCWEB_LOG_DEBUG << "Already writing. Bailing out";
++ session->close("Error in reading to host port");
++ BMCWEB_LOG_ERROR << "Error in KVM socket write " << ec;
+ return;
+ }
++
++ doWrite();
++}
++
++inline void doWrite()
++{
+ if (inputBuffer.size() == 0)
+ {
+ BMCWEB_LOG_DEBUG << "inputBuffer empty. Bailing out";
+ return;
+ }
+
+- doingWrite = true;
+- hostSocket->async_write_some(
+- inputBuffer.data(),
+- [](boost::beast::error_code ec, std::size_t bytes_written) {
+- BMCWEB_LOG_DEBUG << "Wrote " << bytes_written << "bytes";
+- doingWrite = false;
+- inputBuffer.consume(bytes_written);
+-
+- if (session == nullptr)
+- {
+- return;
+- }
+- if (ec == boost::asio::error::eof)
+- {
+- session->close("KVM socket port closed");
+- return;
+- }
+- if (ec)
+- {
+- session->close("Error in reading to host port");
+- BMCWEB_LOG_ERROR << "Error in KVM socket write " << ec;
+- return;
+- }
+- doWrite();
+- });
++ hostSocket->async_write_some(inputBuffer.data(), WriteDone);
+ }
+
+ inline void doRead();
+
+ inline void readDone(const boost::system::error_code& ec, std::size_t bytesRead)
+ {
+- outputBuffer.commit(bytesRead);
+ BMCWEB_LOG_DEBUG << "read done. Read " << bytesRead << " bytes";
+ if (ec)
+ {
+@@ -82,6 +77,7 @@ inline void readDone(const boost::system::error_code& ec, std::size_t bytesRead)
+ return;
+ }
+
++ outputBuffer.commit(bytesRead);
+ boost::beast::string_view payload(
+ static_cast<const char*>(outputBuffer.data().data()), bytesRead);
+ BMCWEB_LOG_DEBUG << "Sending payload size " << payload.size();
+@@ -112,7 +108,6 @@ inline void connectHandler(const boost::system::error_code& ec)
+ return;
+ }
+
+- doWrite();
+ doRead();
+ }
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/bmcweb/bmcweb_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/bmcweb/bmcweb_%.bbappend
new file mode 100644
index 000000000..8d5a43c51
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/bmcweb/bmcweb_%.bbappend
@@ -0,0 +1,16 @@
+# 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 "
+
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+
+SRC_URI += "file://0001-Refine-KVM-websock-proxy.patch"
+
+# 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-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..10793689b
--- /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 = "de77d02aefa3c9df62365e7f07224c5cf9b0eb96"
+
+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/intel-fw-update.bb b/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb
new file mode 100644
index 000000000..ea39e62be
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb
@@ -0,0 +1,18 @@
+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"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SRC_URI += "file://fwupd.sh"
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 ${WORKDIR}/fwupd.sh ${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..a7c19f708
--- /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 = "fcce83df799d9580f48b7f793989c9c96bc882e0"
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..9e620a19c
--- /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 = "3573b25576d14b3334f93bd988c6e2003fab8f90"
+
+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/nv-overlay/files/nv-overlay.service b/meta-openbmc-mods/meta-common/recipes-core/nv-overlay/files/nv-overlay.service
new file mode 100644
index 000000000..95957591f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/nv-overlay/files/nv-overlay.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Non-volatile overlay
+
+Before=sysinit.target systemd-sysctl.service systemd-modules-load.service swap.target systemd-tmpfiles-setup.service
+DefaultDependencies=no
+Conflicts=shutdown.target
+ConditionFileNotEmpty={bindir}/nv-overlay.sh
+
+[Service]
+Type=oneshot
+ExecStart={bindir}/nv-overlay.sh
+
+[Install]
+RequiredBy=paths.target
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/nv-overlay/files/nv-overlay.sh b/meta-openbmc-mods/meta-common/recipes-core/nv-overlay/files/nv-overlay.sh
new file mode 100755
index 000000000..cde082013
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/nv-overlay/files/nv-overlay.sh
@@ -0,0 +1,141 @@
+#!/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.
+#
+#
+# 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
+
+# list of things that need to be rw at boot
+NV_OVERLAYS="/etc /var /home"
+TMP_FS="/var/log /var/lib/systemd/coredump /media"
+
+# place to mount the real jffs2 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"
+}
+
+mtdblock_by_name() {
+ local name="$1"
+ local mtdblock="$(mtd_by_name "$name" | sed 's,mtd,mtdblock,')"
+ echo "$mtdblock"
+}
+
+NV_MTD=rwfs
+NV_MTD_DEV="$(mtd_by_name ${NV_MTD})"
+NV_MTD_BLOCKDEV="$(mtdblock_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, flash_eraseall $NV_MTD_DEV
+bootflags="0x$(sed 's/^.*bootflags=\([0-9a-f]*\).*$/\1/' /proc/cmdline)"
+let "restore_op = $bootflags & 0x3"
+if [ $restore_op -eq 3 ]; then
+ flash_eraseall "$NV_MTD_DEV"
+fi
+
+mount -t jffs2 "$NV_MTD_BLOCKDEV" "$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
+
+for FS in $TMP_FS; do
+ mount -t tmpfs tmpfs "$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_BLOCKDEV="$(mtdblock_by_name ${SOFS_MTD})"
+ mount -t jffs2 "$SOFS_MTD_BLOCKDEV" /var/sofs
+fi
+
+echo "Finished mounting non-volatile overlays"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/nv-overlay/nv-overlay.bb b/meta-openbmc-mods/meta-common/recipes-core/nv-overlay/nv-overlay.bb
new file mode 100644
index 000000000..78b0f80ca
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/nv-overlay/nv-overlay.bb
@@ -0,0 +1,19 @@
+SUMMARY = "Limited NV overlay init script"
+DESCRIPTION = "At runtime, overlay a few directories with an NV COW"
+PR = "r1"
+
+inherit obmc-phosphor-systemd
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SRC_URI += "file://nv-overlay.sh"
+SRC_URI += "file://nv-overlay.service"
+
+do_install_append() {
+ install -d ${D}${bindir}
+ install -m 0755 ${WORKDIR}/nv-overlay.sh ${D}${bindir}
+}
+
+TMPL = "nv-overlay.service"
+SYSTEMD_SERVICE_${PN} += "${TMPL}"
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..91eed5a82
--- /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 = "3cc86d6c536b4c5ee7afb5447837b83ce8b3d149"
+
+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/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..ddbb2d7ae
--- /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"
+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/.clang-format b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/.clang-format
new file mode 100644
index 000000000..8c5278e6f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/.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: 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
+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: Left
+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-graphics/obmc-ikvm/obmc-ikvm/LICENSE b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/LICENSE
new file mode 100644
index 000000000..8dada3eda
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/LICENSE
@@ -0,0 +1,201 @@
+ 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.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ 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.
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/MAINTAINERS b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/MAINTAINERS
new file mode 100644
index 000000000..a5ab97e02
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/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: Eddie James <eajames@linux.ibm.com> <eajames!>
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/Makefile.am b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/Makefile.am
new file mode 100644
index 000000000..1022b2e59
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/Makefile.am
@@ -0,0 +1,31 @@
+bin_PROGRAMS = obmc-ikvm
+dist_bin_SCRIPTS = create_usbhid.sh
+
+noinst_HEADERS = \
+ ikvm_args.hpp \
+ ikvm_input.hpp \
+ ikvm_manager.hpp \
+ ikvm_server.hpp \
+ ikvm_video.hpp
+
+obmc_ikvm_SOURCES = \
+ ikvm_args.cpp \
+ ikvm_input.cpp \
+ ikvm_manager.cpp \
+ ikvm_server.cpp \
+ ikvm_video.cpp \
+ obmc-ikvm.cpp
+
+obmc_ikvm_CXXFLAGS = \
+ $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \
+ $(PHOSPHOR_LOGGING_CFLAGS) \
+ $(PTHREAD_CFLAGS) \
+ $(SDBUSPLUS_CFLAGS) \
+ $(LIBVNCSERVER_CFLAGS)
+
+obmc_ikvm_LDFLAGS = \
+ $(PHOSPHOR_DBUS_INTERFACES_LIBS) \
+ $(PHOSPHOR_LOGGING_LIBS) \
+ $(PTHREAD_LIBS) \
+ $(SDBUSPLUS_LIBS) \
+ $(LIBVNCSERVER_LIBS)
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/README.md b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/README.md
new file mode 100644
index 000000000..70d6e1373
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/README.md
@@ -0,0 +1,18 @@
+# OpenBMC IpKVM Server
+
+The obmc-ikvm application is a VNC server that provides access to the host
+graphics output. The application interfaces with the video device on the BMC
+that captures the host graphics, and then serves that video data on the RFB
+(remote framebuffer, also known as VNC) protocol. The application also
+interfaces with the BMC USB gadget device to pass HID events from the BMC to
+the host, allowing the user to interact with the host system.
+
+## Usage
+
+Once the host is running and an appropriate HID gadget device is instantiated
+on the BMC, the application can be started with the following command:
+``` obmc-ikvm -v <video device path> -i <HID gadget device path> ```
+
+For example:
+
+``` obmc-ikvm -v /dev/video0 -i /dev/hidg0 ```
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/bootstrap.sh b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/bootstrap.sh
new file mode 100644
index 000000000..50b75b7ee
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/bootstrap.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+AUTOCONF_FILES="Makefile.in aclocal.m4 ar-lib autom4te.cache compile \
+ config.guess config.h.in config.sub configure depcomp install-sh \
+ ltmain.sh missing *libtool test-driver"
+
+case $1 in
+ clean)
+ test -f Makefile && make maintainer-clean
+ for file in ${AUTOCONF_FILES}; do
+ find -name "$file" | xargs -r rm -rf
+ done
+ exit 0
+ ;;
+esac
+
+autoreconf -i
+echo 'Run "./configure ${CONFIGURE_FLAGS} && make"'
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/configure.ac b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/configure.ac
new file mode 100644
index 000000000..671316022
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/configure.ac
@@ -0,0 +1,29 @@
+# Initialization
+AC_PREREQ([2.69])
+AC_INIT([obmc-ikvm], [1.0], [https://github.com/openbmc/obmc-ikvm/issues])
+AC_LANG([C++])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([subdir-objects -Wall -Werror foreign dist-xz])
+AM_SILENT_RULES([yes])
+
+# Checks for programs.
+AC_PROG_CXX
+AM_PROG_AR
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+# Checks for typedefs, structures, and compiler characteristics.
+AX_CXX_COMPILE_STDCXX_17([noext])
+AX_APPEND_COMPILE_FLAGS([-Wall -Werror], [CXXFLAGS])
+
+# Checks for libraries.
+AC_CHECK_LIB([pthread], [pthread_create])
+PKG_CHECK_MODULES([LIBVNCSERVER], [libvncserver], , AC_MSG_ERROR(["Requires libvncserver package."]))
+PKG_CHECK_MODULES([SDBUSPLUS], [sdbusplus], , AC_MSG_ERROR(["Requires sdbusplus package."]))
+PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging], , AC_MSG_ERROR(["Requires phosphor-logging package."]))
+PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces], , AC_MSG_ERROR(["Requires phosphor-dbus-interfaces package."]))
+
+LT_INIT
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/create_usbhid.sh b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/create_usbhid.sh
new file mode 100644
index 000000000..955f18b61
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/create_usbhid.sh
@@ -0,0 +1,135 @@
+#!/bin/sh
+
+new_directory="/sys/kernel/config/usb_gadget/obmc_input"
+
+if [ -e "${new_directory}" ]; then
+ exit 0
+fi
+
+# create gadget
+original_directory="$(pwd)"
+mkdir "${new_directory}"
+cd "${new_directory}"
+
+# add basic information
+echo 0x0100 > bcdDevice
+echo 0x0200 > bcdUSB
+echo 0x0104 > idProduct # Multifunction Composite Gadget
+echo 0x1d6b > idVendor # Linux Foundation
+
+# create English locale
+mkdir strings/0x409
+
+echo "OpenBMC" > strings/0x409/manufacturer
+echo "virtual_input" > strings/0x409/product
+echo "OBMC0001" > strings/0x409/serialnumber
+
+# Create HID keyboard function
+mkdir functions/hid.0
+
+echo 1 > functions/hid.0/protocol # 1: keyboard
+echo 8 > functions/hid.0/report_length
+echo 1 > functions/hid.0/subclass
+
+# Binary HID keyboard descriptor
+# 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+# 0x09, 0x06, // USAGE (Keyboard)
+# 0xa1, 0x01, // COLLECTION (Application)
+# 0x05, 0x07, // USAGE_PAGE (Keyboard)
+# 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
+# 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
+# 0x15, 0x00, // LOGICAL_MINIMUM (0)
+# 0x25, 0x01, // LOGICAL_MAXIMUM (1)
+# 0x75, 0x01, // REPORT_SIZE (1)
+# 0x95, 0x08, // REPORT_COUNT (8)
+# 0x81, 0x02, // INPUT (Data,Var,Abs)
+# 0x95, 0x01, // REPORT_COUNT (1)
+# 0x75, 0x08, // REPORT_SIZE (8)
+# 0x81, 0x03, // INPUT (Data,Var,Abs)
+# 0x95, 0x05, // REPORT_COUNT (5)
+# 0x75, 0x01, // REPORT_SIZE (1)
+# 0x05, 0x08, // USAGE_PAGE (LEDs)
+# 0x19, 0x01, // USAGE_MINIMUM (Num Lock)
+# 0x29, 0x05, // USAGE_MAXIMUM (Kana)
+# 0x91, 0x02, // OUTPUT (Data,Var,Abs)
+# 0x95, 0x01, // REPORT_COUNT (1)
+# 0x75, 0x03, // REPORT_SIZE (3)
+# 0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
+# 0x95, 0x06, // REPORT_COUNT (6)
+# 0x75, 0x08, // REPORT_SIZE (8)
+# 0x15, 0x00, // LOGICAL_MINIMUM (0)
+# 0x25, 0x65, // LOGICAL_MAXIMUM (101)
+# 0x05, 0x07, // USAGE_PAGE (Keyboard)
+# 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
+# 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
+# 0x81, 0x00, // INPUT (Data,Ary,Abs)
+# 0xc0 // END_COLLECTION
+echo -ne '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x03\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x03\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' > functions/hid.0/report_desc
+
+# Create HID mouse function
+mkdir functions/hid.1
+
+echo 2 > functions/hid.1/protocol # 2: mouse
+echo 5 > functions/hid.1/report_length
+echo 1 > functions/hid.1/subclass
+
+# Binary HID mouse descriptor (absolute coordinate)
+# 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+# 0x09, 0x02, // USAGE (Mouse)
+# 0xa1, 0x01, // COLLECTION (Application)
+# 0x09, 0x01, // USAGE (Pointer)
+# 0xa1, 0x00, // COLLECTION (Physical)
+# 0x05, 0x09, // USAGE_PAGE (Button)
+# 0x19, 0x01, // USAGE_MINIMUM (Button 1)
+# 0x29, 0x03, // USAGE_MAXIMUM (Button 3)
+# 0x15, 0x00, // LOGICAL_MINIMUM (0)
+# 0x25, 0x01, // LOGICAL_MAXIMUM (1)
+# 0x95, 0x03, // REPORT_COUNT (3)
+# 0x75, 0x01, // REPORT_SIZE (1)
+# 0x81, 0x02, // INPUT (Data,Var,Abs)
+# 0x95, 0x01, // REPORT_COUNT (1)
+# 0x75, 0x05, // REPORT_SIZE (5)
+# 0x81, 0x03, // INPUT (Cnst,Var,Abs)
+# 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+# 0x09, 0x30, // USAGE (X)
+# 0x09, 0x31, // USAGE (Y)
+# 0x35, 0x00, // PHYSICAL_MINIMUM (0)
+# 0x46, 0xff, 0x7f, // PHYSICAL_MAXIMUM (32767)
+# 0x15, 0x00, // LOGICAL_MINIMUM (0)
+# 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767)
+# 0x65, 0x11, // UNIT (SI Lin:Distance)
+# 0x55, 0x00, // UNIT_EXPONENT (0)
+# 0x75, 0x10, // REPORT_SIZE (16)
+# 0x95, 0x02, // REPORT_COUNT (2)
+# 0x81, 0x02, // INPUT (Data,Var,Abs)
+# 0xc0, // END_COLLECTION
+# 0xc0 // END_COLLECTION
+echo -ne '\x05\x01\x09\x02\xa1\x01\x09\x01\xa1\x00\x05\x09\x19\x01\x29\x03\x15\x00\x25\x01\x95\x03\x75\x01\x81\x02\x95\x01\x75\x05\x81\x03\x05\x01\x09\x30\x09\x31\x35\x00\x46\xff\x7f\x15\x00\x26\xff\x7f\x65\x11\x55\x00\x75\x10\x95\x02\x81\x02\xc0\xc0' > functions/hid.1/report_desc
+
+# Create configuration
+mkdir configs/c.1
+mkdir configs/c.1/strings/0x409
+
+echo 0x80 > configs/c.1/bmAttributes
+echo 200 > configs/c.1/MaxPower
+echo "" > configs/c.1/strings/0x409/configuration
+
+# Link HID functions to configuration
+ln -s functions/hid.0 configs/c.1
+ln -s functions/hid.1 configs/c.1
+
+# Enable gadget
+dev_name="1e6a0000.usb-vhub"
+i=0
+num_ports=5
+base_usb_dir="/sys/bus/platform/devices/${dev_name}/${dev_name}:p"
+while [ $i -lt $num_ports ]; do
+ port=$(($i + 1))
+ i=$port
+ if [ ! -e "${base_usb_dir}${port}/gadget/suspended" ]; then
+ break
+ fi
+done
+echo "${dev_name}:p${port}" > UDC
+
+cd "${original_directory}"
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_args.cpp b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_args.cpp
new file mode 100644
index 000000000..2723187dd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_args.cpp
@@ -0,0 +1,57 @@
+#include "ikvm_args.hpp"
+
+#include <getopt.h>
+#include <rfb/rfb.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+namespace ikvm
+{
+
+Args::Args(int argc, char* argv[]) : frameRate(30), commandLine(argc, argv)
+{
+ int option;
+ const char* opts = "f:h:k:p:v:";
+ struct option lopts[] = {{"frameRate", 1, 0, 'f'}, {"help", 0, 0, 'h'},
+ {"keyboard", 1, 0, 'k'}, {"mouse", 1, 0, 'p'},
+ {"videoDevice", 1, 0, 'v'}, {0, 0, 0, 0}};
+
+ while ((option = getopt_long(argc, argv, opts, lopts, NULL)) != -1)
+ {
+ switch (option)
+ {
+ case 'f':
+ frameRate = (int)strtol(optarg, NULL, 0);
+ if (frameRate < 0 || frameRate > 60)
+ frameRate = 30;
+ break;
+ case 'h':
+ printUsage();
+ exit(0);
+ case 'k':
+ keyboardPath = std::string(optarg);
+ break;
+ case 'p':
+ pointerPath = std::string(optarg);
+ break;
+ case 'v':
+ videoPath = std::string(optarg);
+ break;
+ }
+ }
+}
+
+void Args::printUsage()
+{
+ // use fprintf(stderr to match rfbUsage()
+ fprintf(stderr, "OpenBMC IKVM daemon\n");
+ fprintf(stderr, "Usage: obmc-ikvm [options]\n");
+ fprintf(stderr, "-f frame rate try this frame rate\n");
+ fprintf(stderr, "-h, --help show this message and exit\n");
+ fprintf(stderr, "-k device HID keyboard gadget device\n");
+ fprintf(stderr, "-p device HID mouse gadget device\n");
+ fprintf(stderr, "-v device V4L2 device\n");
+ rfbUsage();
+}
+
+} // namespace ikvm
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_args.hpp b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_args.hpp
new file mode 100644
index 000000000..f877d32e9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_args.hpp
@@ -0,0 +1,123 @@
+#pragma once
+
+#include <string>
+
+namespace ikvm
+{
+
+/*
+ * @class Args
+ * @brief Command line argument parser and storage
+ */
+class Args
+{
+ public:
+ /*
+ * @struct CommandLine
+ * @brief Stores the original command line arguments for later use
+ */
+ struct CommandLine
+ {
+ /*
+ * @brief Constructs CommandLine object
+ *
+ * @param[in] c - Number of arguments
+ * @param[in] v - Array of arguments
+ */
+ CommandLine(int c, char** v) : argc(c), argv(v)
+ {
+ }
+ ~CommandLine() = default;
+ CommandLine(const CommandLine&) = default;
+ CommandLine& operator=(const CommandLine&) = default;
+ CommandLine(CommandLine&&) = default;
+ CommandLine& operator=(CommandLine&&) = default;
+
+ int argc;
+ char** argv;
+ };
+
+ /*
+ * @brief Constructs Args object
+ *
+ * @param[in] argc - The number of arguments in the command line call
+ * @param[in] argv - The array of arguments from the command line
+ */
+ Args(int argc, char* argv[]);
+ ~Args() = default;
+ Args(const Args&) = default;
+ Args& operator=(const Args&) = default;
+ Args(Args&&) = default;
+ Args& operator=(Args&&) = default;
+
+ /*
+ * @brief Get the original command line arguments
+ *
+ * @return Reference to the CommandLine structure storing the original
+ * command line arguments
+ */
+ inline const CommandLine& getCommandLine() const
+ {
+ return commandLine;
+ }
+
+ /*
+ * @brief Get the desired video frame rate
+ *
+ * @return Value of the desired frame rate in frames per second
+ */
+ inline int getFrameRate() const
+ {
+ return frameRate;
+ }
+
+ /*
+ * @brief Get the path to the USB keyboard device
+ *
+ * @return Reference to the string storing the path to the keyboard device
+ */
+ inline const std::string& getKeyboardPath() const
+ {
+ return keyboardPath;
+ }
+
+ /*
+ * @brief Get the path to the USB mouse device
+ *
+ * @return Reference to the string storing the path to the mouse device
+ */
+ inline const std::string& getPointerPath() const
+ {
+ return pointerPath;
+ }
+
+ /*
+ * @brief Get the path to the V4L2 video device
+ *
+ * @return Reference to the string storing the path to the video device
+ */
+ inline const std::string& getVideoPath() const
+ {
+ return videoPath;
+ }
+
+ private:
+ /* @brief Prints the application usage to stderr */
+ void printUsage();
+
+ /*
+ * @brief Desired frame rate (in frames per second) of the video
+ * stream
+ */
+ int frameRate;
+ /* @brief Path to the USB keyboard device */
+ std::string keyboardPath;
+ /* @brief Path to the USB mouse device */
+ std::string pointerPath;
+ /* @brief Path to the V4L2 video device */
+ std::string videoPath;
+ /* @brief Original command line arguments passed to the application */
+ CommandLine commandLine;
+};
+
+} // namespace ikvm
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_input.cpp b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_input.cpp
new file mode 100644
index 000000000..f161f7327
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_input.cpp
@@ -0,0 +1,380 @@
+#include "ikvm_input.hpp"
+
+#include "ikvm_server.hpp"
+#include "scancodes.hpp"
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <rfb/keysym.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/elog.hpp>
+#include <phosphor-logging/log.hpp>
+#include <xyz/openbmc_project/Common/File/error.hpp>
+
+namespace ikvm
+{
+
+using namespace phosphor::logging;
+using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
+
+Input::Input(const std::string& kbdPath, const std::string& ptrPath) :
+ keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0},
+ keyboardPath(kbdPath), pointerPath(ptrPath)
+{
+ if (!keyboardPath.empty())
+ {
+ keyboardFd = open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC);
+ if (keyboardFd < 0)
+ {
+ log<level::ERR>("Failed to open input device",
+ entry("PATH=%s", keyboardPath.c_str()),
+ entry("ERROR=%s", strerror(errno)));
+ elog<Open>(xyz::openbmc_project::Common::File::Open::ERRNO(errno),
+ xyz::openbmc_project::Common::File::Open::PATH(
+ keyboardPath.c_str()));
+ }
+ }
+
+ if (!pointerPath.empty())
+ {
+ pointerFd = open(pointerPath.c_str(), O_RDWR | O_CLOEXEC);
+ if (pointerFd < 0)
+ {
+ log<level::ERR>("Failed to open input device",
+ entry("PATH=%s", pointerPath.c_str()),
+ entry("ERROR=%s", strerror(errno)));
+ elog<Open>(xyz::openbmc_project::Common::File::Open::ERRNO(errno),
+ xyz::openbmc_project::Common::File::Open::PATH(
+ pointerPath.c_str()));
+ }
+ }
+}
+
+Input::~Input()
+{
+ if (keyboardFd >= 0)
+ {
+ close(keyboardFd);
+ }
+
+ if (pointerFd >= 0)
+ {
+ close(pointerFd);
+ }
+}
+
+void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl)
+{
+ Server::ClientData* cd = (Server::ClientData*)cl->clientData;
+ Input* input = cd->input;
+
+ if (down)
+ {
+ uint8_t sc = keyToScancode(key);
+
+ if (sc)
+ {
+ if (input->keysDown.find(key) == input->keysDown.end())
+ {
+ for (unsigned int i = 2; i < KEY_REPORT_LENGTH; ++i)
+ {
+ if (!input->keyboardReport[i])
+ {
+ input->keyboardReport[i] = sc;
+ input->keysDown.insert(std::make_pair(key, i));
+ input->sendKeyboard = true;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ uint8_t mod = keyToMod(key);
+
+ if (mod)
+ {
+ input->keyboardReport[0] |= mod;
+ input->sendKeyboard = true;
+ }
+ }
+ }
+ else
+ {
+ auto it = input->keysDown.find(key);
+
+ if (it != input->keysDown.end())
+ {
+ input->keyboardReport[it->second] = 0;
+ input->keysDown.erase(it);
+ input->sendKeyboard = true;
+ }
+ else
+ {
+ uint8_t mod = keyToMod(key);
+
+ if (mod)
+ {
+ input->keyboardReport[0] &= ~mod;
+ input->sendKeyboard = true;
+ }
+ }
+ }
+}
+
+void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl)
+{
+ Server::ClientData* cd = (Server::ClientData*)cl->clientData;
+ Input* input = cd->input;
+ Server* server = (Server*)cl->screen->screenData;
+ const Video& video = server->getVideo();
+
+ input->pointerReport[0] = buttonMask & 0xFF;
+
+ if (x >= 0 && (unsigned int)x < video.getWidth())
+ {
+ uint16_t xx = x * ((SHRT_MAX + 1) / video.getWidth());
+
+ memcpy(&input->pointerReport[1], &xx, 2);
+ }
+
+ if (y >= 0 && (unsigned int)y < video.getHeight())
+ {
+ uint16_t yy = y * ((SHRT_MAX + 1) / video.getHeight());
+
+ memcpy(&input->pointerReport[3], &yy, 2);
+ }
+
+ input->sendPointer = true;
+ rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
+}
+
+void Input::sendWakeupPacket()
+{
+ uint8_t wakeupReport[PTR_REPORT_LENGTH] = {0};
+ uint16_t xy = SHRT_MAX / 2;
+
+ if (pointerFd < 0)
+ {
+ return;
+ }
+
+ memcpy(&wakeupReport[1], &xy, 2);
+ memcpy(&wakeupReport[3], &xy, 2);
+
+ if (write(pointerFd, wakeupReport, PTR_REPORT_LENGTH) != PTR_REPORT_LENGTH)
+ {
+ log<level::ERR>("Failed to write report",
+ entry("ERROR=%s", strerror(errno)));
+ }
+}
+
+void Input::sendReport()
+{
+ if (sendKeyboard && keyboardFd >= 0)
+ {
+ if (write(keyboardFd, keyboardReport, KEY_REPORT_LENGTH) !=
+ KEY_REPORT_LENGTH)
+ {
+ log<level::ERR>("Failed to write keyboard report",
+ entry("ERROR=%s", strerror(errno)));
+ }
+
+ sendKeyboard = false;
+ }
+
+ if (sendPointer && pointerFd >= 0)
+ {
+ if (write(pointerFd, pointerReport, PTR_REPORT_LENGTH) !=
+ PTR_REPORT_LENGTH)
+ {
+ log<level::ERR>("Failed to write pointer report",
+ entry("ERROR=%s", strerror(errno)));
+ }
+
+ sendPointer = false;
+ }
+}
+
+uint8_t Input::keyToMod(rfbKeySym key)
+{
+ uint8_t mod = 0;
+
+ if (key >= XK_Shift_L && key <= XK_Control_R)
+ {
+ mod = shiftCtrlMap[key - XK_Shift_L];
+ }
+ else if (key >= XK_Meta_L && key <= XK_Alt_R)
+ {
+ mod = metaAltMap[key - XK_Meta_L];
+ }
+
+ return mod;
+}
+
+uint8_t Input::keyToScancode(rfbKeySym key)
+{
+ uint8_t scancode = 0;
+
+ if ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'))
+ {
+ scancode = USBHID_KEY_A + ((key & 0x5F) - 'A');
+ }
+ else if (key >= '1' && key <= '9')
+ {
+ scancode = USBHID_KEY_1 + (key - '1');
+ }
+ else if (key >= XK_F1 && key <= XK_F12)
+ {
+ scancode = USBHID_KEY_F1 + (key - XK_F1);
+ }
+ else
+ {
+ switch (key)
+ {
+ case XK_exclam:
+ scancode = USBHID_KEY_1;
+ break;
+ case XK_at:
+ scancode = USBHID_KEY_2;
+ break;
+ case XK_numbersign:
+ scancode = USBHID_KEY_3;
+ break;
+ case XK_dollar:
+ scancode = USBHID_KEY_4;
+ break;
+ case XK_percent:
+ scancode = USBHID_KEY_5;
+ break;
+ case XK_asciicircum:
+ scancode = USBHID_KEY_6;
+ break;
+ case XK_ampersand:
+ scancode = USBHID_KEY_7;
+ break;
+ case XK_asterisk:
+ scancode = USBHID_KEY_8;
+ break;
+ case XK_parenleft:
+ scancode = USBHID_KEY_9;
+ break;
+ case XK_0:
+ case XK_parenright:
+ scancode = USBHID_KEY_0;
+ break;
+ case XK_Return:
+ scancode = USBHID_KEY_RETURN;
+ break;
+ case XK_Escape:
+ scancode = USBHID_KEY_ESC;
+ break;
+ case XK_BackSpace:
+ scancode = USBHID_KEY_BACKSPACE;
+ break;
+ case XK_Tab:
+ scancode = USBHID_KEY_TAB;
+ break;
+ case XK_space:
+ scancode = USBHID_KEY_SPACE;
+ break;
+ case XK_minus:
+ case XK_underscore:
+ scancode = USBHID_KEY_MINUS;
+ break;
+ case XK_plus:
+ case XK_equal:
+ scancode = USBHID_KEY_EQUAL;
+ break;
+ case XK_bracketleft:
+ case XK_braceleft:
+ scancode = USBHID_KEY_LEFTBRACE;
+ break;
+ case XK_bracketright:
+ case XK_braceright:
+ scancode = USBHID_KEY_RIGHTBRACE;
+ break;
+ case XK_backslash:
+ case XK_bar:
+ scancode = USBHID_KEY_BACKSLASH;
+ break;
+ case XK_colon:
+ case XK_semicolon:
+ scancode = USBHID_KEY_SEMICOLON;
+ break;
+ case XK_quotedbl:
+ case XK_apostrophe:
+ scancode = USBHID_KEY_APOSTROPHE;
+ break;
+ case XK_grave:
+ case XK_asciitilde:
+ scancode = USBHID_KEY_GRAVE;
+ break;
+ case XK_comma:
+ case XK_less:
+ scancode = USBHID_KEY_COMMA;
+ break;
+ case XK_period:
+ case XK_greater:
+ scancode = USBHID_KEY_DOT;
+ break;
+ case XK_slash:
+ case XK_question:
+ scancode = USBHID_KEY_SLASH;
+ break;
+ case XK_Caps_Lock:
+ scancode = USBHID_KEY_CAPSLOCK;
+ break;
+ case XK_Print:
+ scancode = USBHID_KEY_PRINT;
+ break;
+ case XK_Scroll_Lock:
+ scancode = USBHID_KEY_SCROLLLOCK;
+ break;
+ case XK_Pause:
+ scancode = USBHID_KEY_PAUSE;
+ break;
+ case XK_Insert:
+ scancode = USBHID_KEY_INSERT;
+ break;
+ case XK_Home:
+ scancode = USBHID_KEY_HOME;
+ break;
+ case XK_Page_Up:
+ scancode = USBHID_KEY_PAGEUP;
+ break;
+ case XK_Delete:
+ scancode = USBHID_KEY_DELETE;
+ break;
+ case XK_End:
+ scancode = USBHID_KEY_END;
+ break;
+ case XK_Page_Down:
+ scancode = USBHID_KEY_PAGEDOWN;
+ break;
+ case XK_Right:
+ scancode = USBHID_KEY_RIGHT;
+ break;
+ case XK_Left:
+ scancode = USBHID_KEY_LEFT;
+ break;
+ case XK_Down:
+ scancode = USBHID_KEY_DOWN;
+ break;
+ case XK_Up:
+ scancode = USBHID_KEY_UP;
+ break;
+ case XK_Num_Lock:
+ scancode = USBHID_KEY_NUMLOCK;
+ break;
+ }
+ }
+
+ return scancode;
+}
+
+} // namespace ikvm
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_input.hpp b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_input.hpp
new file mode 100644
index 000000000..f7413a4cd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_input.hpp
@@ -0,0 +1,111 @@
+#pragma once
+
+#include <rfb/rfb.h>
+
+#include <map>
+#include <string>
+
+namespace ikvm
+{
+
+/*
+ * @class Input
+ * @brief Receives events from RFB clients and sends reports to the USB input
+ * device
+ */
+class Input
+{
+ public:
+ /*
+ * @brief Constructs Input object
+ *
+ * @param[in] kbdPath - Path to the USB keyboard device
+ * @param[in] ptrPath - Path to the USB mouse device
+ */
+ Input(const std::string& kbdPath, const std::string& ptrPath);
+ ~Input();
+ Input(const Input&) = default;
+ Input& operator=(const Input&) = default;
+ Input(Input&&) = default;
+ Input& operator=(Input&&) = default;
+
+ /*
+ * @brief RFB client key event handler
+ *
+ * @param[in] down - Boolean indicating whether key is pressed or not
+ * @param[in] key - Key code
+ * @param[in] cl - Handle to the RFB client
+ */
+ static void keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl);
+ /*
+ * @brief RFB client pointer event handler
+ *
+ * @param[in] buttonMask - Bitmask indicating which buttons have been
+ * pressed
+ * @param[in] x - Pointer x-coordinate
+ * @param[in] y - Pointer y-coordinate
+ * @param[in] cl - Handle to the RFB client
+ */
+ static void pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl);
+
+ /* @brief Sends a wakeup data packet to the USB input device */
+ void sendWakeupPacket();
+ /* @brief Sends an HID report to the USB input device */
+ void sendReport();
+
+ private:
+ static constexpr int NUM_MODIFIER_BITS = 4;
+ static constexpr int KEY_REPORT_LENGTH = 8;
+ static constexpr int PTR_REPORT_LENGTH = 5;
+
+ /* @brief HID modifier bits mapped to shift and control key codes */
+ static constexpr uint8_t shiftCtrlMap[NUM_MODIFIER_BITS] = {
+ 0x02, // left shift
+ 0x20, // right shift
+ 0x01, // left control
+ 0x10 // right control
+ };
+ /* @brief HID modifier bits mapped to meta and alt key codes */
+ static constexpr uint8_t metaAltMap[NUM_MODIFIER_BITS] = {
+ 0x08, // left meta
+ 0x80, // right meta
+ 0x04, // left alt
+ 0x40 // right alt
+ };
+ /*
+ * @brief Translates a RFB-specific key code to HID modifier bit
+ *
+ * @param[in] key - key code
+ */
+ static uint8_t keyToMod(rfbKeySym key);
+ /*
+ * @brief Translates a RFB-specific key code to HID scancode
+ *
+ * @param[in] key - key code
+ */
+ static uint8_t keyToScancode(rfbKeySym key);
+
+ /* @brief Indicates whether or not to send a keyboard report */
+ bool sendKeyboard;
+ /* @brief Indicates whether or not to send a pointer report */
+ bool sendPointer;
+ /* @brief File descriptor for the USB keyboard device */
+ int keyboardFd;
+ /* @brief File descriptor for the USB mouse device */
+ int pointerFd;
+ /* @brief Data for keyboard report */
+ uint8_t keyboardReport[KEY_REPORT_LENGTH];
+ /* @brief Data for pointer report */
+ uint8_t pointerReport[PTR_REPORT_LENGTH];
+ /* @brief Path to the USB keyboard device */
+ std::string keyboardPath;
+ /* @brief Path to the USB mouse device */
+ std::string pointerPath;
+ /*
+ * @brief Mapping of RFB key code to report data index to keep track
+ * of which keys are down
+ */
+ std::map<int, int> keysDown;
+};
+
+} // namespace ikvm
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_manager.cpp b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_manager.cpp
new file mode 100644
index 000000000..5e014d057
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_manager.cpp
@@ -0,0 +1,100 @@
+#include "ikvm_manager.hpp"
+
+#include <thread>
+
+namespace ikvm
+{
+
+Manager::Manager(const Args& args) :
+ continueExecuting(true), serverDone(false), videoDone(true),
+ input(args.getKeyboardPath(), args.getPointerPath()),
+ video(args.getVideoPath(), input, args.getFrameRate()),
+ server(args, input, video)
+{
+}
+
+void Manager::run()
+{
+ std::thread run(serverThread, this);
+
+ while (continueExecuting)
+ {
+ if (server.wantsFrame())
+ {
+ video.getFrame();
+ server.sendFrame();
+ }
+ else
+ {
+ video.stop();
+ }
+
+ if (video.needsResize())
+ {
+ videoDone = false;
+ waitServer();
+ video.resize();
+ server.resize();
+ setVideoDone();
+ }
+ else
+ {
+ setVideoDone();
+ waitServer();
+ }
+ }
+
+ run.join();
+}
+
+void Manager::serverThread(Manager* manager)
+{
+ while (manager->continueExecuting)
+ {
+ manager->server.run();
+ manager->setServerDone();
+ manager->waitVideo();
+ }
+}
+
+void Manager::setServerDone()
+{
+ std::unique_lock<std::mutex> ulock(lock);
+
+ serverDone = true;
+ sync.notify_all();
+}
+
+void Manager::setVideoDone()
+{
+ std::unique_lock<std::mutex> ulock(lock);
+
+ videoDone = true;
+ sync.notify_all();
+}
+
+void Manager::waitServer()
+{
+ std::unique_lock<std::mutex> ulock(lock);
+
+ while (!serverDone)
+ {
+ sync.wait(ulock);
+ }
+
+ serverDone = false;
+}
+
+void Manager::waitVideo()
+{
+ std::unique_lock<std::mutex> ulock(lock);
+
+ while (!videoDone)
+ {
+ sync.wait(ulock);
+ }
+
+ // don't reset videoDone
+}
+
+} // namespace ikvm
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_manager.hpp b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_manager.hpp
new file mode 100644
index 000000000..67d5a681e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_manager.hpp
@@ -0,0 +1,75 @@
+#pragma once
+
+#include "ikvm_args.hpp"
+#include "ikvm_input.hpp"
+#include "ikvm_server.hpp"
+#include "ikvm_video.hpp"
+
+#include <condition_variable>
+#include <mutex>
+
+namespace ikvm
+{
+
+/*
+ * @class Manager
+ * @brief Manages the VNC server by executing threaded loops of RFB operations
+ * and video device operations.
+ */
+class Manager
+{
+ public:
+ /*
+ * @brief Constructs the Manager object
+ *
+ * @param[in] args - Reference to Args object
+ */
+ Manager(const Args& args);
+ ~Manager() = default;
+ Manager(const Manager&) = default;
+ Manager& operator=(const Manager&) = default;
+ Manager(Manager&&) = default;
+ Manager& operator=(Manager&&) = default;
+
+ /* @brief Begins operation of the VNC server */
+ void run();
+
+ private:
+ /*
+ * @brief Thread function to loop the RFB update operations
+ *
+ * @param[in] manager - Pointer to the Manager object
+ */
+ static void serverThread(Manager* manager);
+
+ /* @brief Notifies thread waiters that RFB operations are complete */
+ void setServerDone();
+ /* @brief Notifies thread waiters that video operations are complete */
+ void setVideoDone();
+ /* @brief Blocks until RFB operations complete */
+ void waitServer();
+ /* @brief Blocks until video operations are complete */
+ void waitVideo();
+
+ /*
+ * @brief Boolean to indicate whether the application should continue
+ * running
+ */
+ bool continueExecuting;
+ /* @brief Boolean to indicate that RFB operations are complete */
+ bool serverDone;
+ /* @brief Boolean to indicate that video operations are complete */
+ bool videoDone;
+ /* @brief Input object */
+ Input input;
+ /* @brief Video object */
+ Video video;
+ /* @brief RFB server object */
+ Server server;
+ /* @brief Condition variable to enable waiting for thread completion */
+ std::condition_variable sync;
+ /* @brief Mutex for waiting on condition variable safely */
+ std::mutex lock;
+};
+
+} // namespace ikvm
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_server.cpp b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_server.cpp
new file mode 100644
index 000000000..47737587e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_server.cpp
@@ -0,0 +1,218 @@
+#include "ikvm_server.hpp"
+
+#include <rfb/rfbproto.h>
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/elog.hpp>
+#include <phosphor-logging/log.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+
+namespace ikvm
+{
+
+using namespace phosphor::logging;
+using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+
+Server::Server(const Args& args, Input& i, Video& v) :
+ pendingResize(false), frameCounter(0), numClients(0), input(i), video(v)
+{
+ std::string ip("localhost");
+ const Args::CommandLine& commandLine = args.getCommandLine();
+ int argc = commandLine.argc;
+
+ server = rfbGetScreen(&argc, commandLine.argv, video.getWidth(),
+ video.getHeight(), Video::bitsPerSample,
+ Video::samplesPerPixel, Video::bytesPerPixel);
+
+ if (!server)
+ {
+ log<level::ERR>("Failed to get VNC screen due to invalid arguments");
+ elog<InvalidArgument>(
+ xyz::openbmc_project::Common::InvalidArgument::ARGUMENT_NAME(""),
+ xyz::openbmc_project::Common::InvalidArgument::ARGUMENT_VALUE(""));
+ }
+
+ framebuffer.resize(
+ video.getHeight() * video.getWidth() * Video::bytesPerPixel, 0);
+
+ server->screenData = this;
+ server->desktopName = "OpenBMC IKVM";
+ server->alwaysShared = true;
+ server->frameBuffer = framebuffer.data();
+ server->newClientHook = newClient;
+ server->cursor = rfbMakeXCursor(cursorWidth, cursorHeight, (char*)cursor,
+ (char*)cursorMask);
+ server->cursor->xhot = 1;
+ server->cursor->yhot = 1;
+ // char httpDir[] = "../webclients";
+ // server->httpDir = httpDir;
+ // server->httpEnableProxyConnect = true;
+
+ // commented it out to allow OOB connection
+ // rfbStringToAddr(&ip[0], &server->listenInterface);
+
+ rfbInitServer(server);
+
+ rfbMarkRectAsModified(server, 0, 0, video.getWidth(), video.getHeight());
+
+ server->kbdAddEvent = Input::keyEvent;
+ server->ptrAddEvent = Input::pointerEvent;
+
+ processTime = (1000000 / video.getFrameRate()) - 100;
+}
+
+Server::~Server()
+{
+ rfbScreenCleanup(server);
+}
+
+void Server::resize()
+{
+ if (frameCounter > video.getFrameRate())
+ {
+ doResize();
+ }
+ else
+ {
+ pendingResize = true;
+ }
+}
+
+void Server::run()
+{
+ rfbProcessEvents(server, processTime);
+
+ if (server->clientHead)
+ {
+ input.sendReport();
+
+ frameCounter++;
+ if (pendingResize && frameCounter > video.getFrameRate())
+ {
+ doResize();
+ pendingResize = false;
+ }
+ }
+}
+
+void Server::sendFrame()
+{
+ char* data = video.getData();
+ rfbClientIteratorPtr it;
+ rfbClientPtr cl;
+
+ if (!data || pendingResize)
+ {
+ return;
+ }
+
+ it = rfbGetClientIterator(server);
+
+ while ((cl = rfbClientIteratorNext(it)))
+ {
+ ClientData* cd = (ClientData*)cl->clientData;
+ rfbFramebufferUpdateMsg* fu = (rfbFramebufferUpdateMsg*)cl->updateBuf;
+
+ if (!cd)
+ {
+ continue;
+ }
+
+ if (cd->skipFrame)
+ {
+ cd->skipFrame--;
+ continue;
+ }
+
+ if (cl->enableLastRectEncoding)
+ {
+ fu->nRects = 0xFFFF;
+ }
+ else
+ {
+ fu->nRects = Swap16IfLE(1);
+ }
+
+ fu->type = rfbFramebufferUpdate;
+ cl->ublen = sz_rfbFramebufferUpdateMsg;
+ rfbSendUpdateBuf(cl);
+
+ cl->tightEncoding = rfbEncodingTight;
+ rfbSendTightHeader(cl, 0, 0, video.getWidth(), video.getHeight());
+
+ cl->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4);
+ rfbSendCompressedDataTight(cl, data, video.getFrameSize());
+
+ if (cl->enableLastRectEncoding)
+ {
+ rfbSendLastRectMarker(cl);
+ }
+
+ rfbSendUpdateBuf(cl);
+ }
+
+ rfbReleaseClientIterator(it);
+}
+
+void Server::clientGone(rfbClientPtr cl)
+{
+ Server* server = (Server*)cl->screen->screenData;
+
+ delete (ClientData*)cl->clientData;
+
+ if (server->numClients-- == 1)
+ {
+ rfbMarkRectAsModified(server->server, 0, 0, server->video.getWidth(),
+ server->video.getHeight());
+ }
+}
+
+enum rfbNewClientAction Server::newClient(rfbClientPtr cl)
+{
+ Server* server = (Server*)cl->screen->screenData;
+
+ cl->clientData =
+ new ClientData(server->video.getFrameRate(), &server->input);
+ cl->clientGoneHook = clientGone;
+ if (!server->numClients++)
+ {
+ server->pendingResize = false;
+ server->frameCounter = 0;
+ server->video.start();
+ }
+
+ return RFB_CLIENT_ACCEPT;
+}
+
+void Server::doResize()
+{
+ rfbClientIteratorPtr it;
+ rfbClientPtr cl;
+
+ framebuffer.resize(
+ video.getHeight() * video.getWidth() * Video::bytesPerPixel, 0);
+
+ rfbNewFramebuffer(server, framebuffer.data(), video.getWidth(),
+ video.getHeight(), Video::bitsPerSample,
+ Video::samplesPerPixel, Video::bytesPerPixel);
+ rfbMarkRectAsModified(server, 0, 0, video.getWidth(), video.getHeight());
+
+ it = rfbGetClientIterator(server);
+
+ while ((cl = rfbClientIteratorNext(it)))
+ {
+ ClientData* cd = (ClientData*)cl->clientData;
+
+ if (!cd)
+ {
+ continue;
+ }
+
+ // delay video updates to give the client time to resize
+ cd->skipFrame = video.getFrameRate();
+ }
+
+ rfbReleaseClientIterator(it);
+}
+
+} // namespace ikvm
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_server.hpp b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_server.hpp
new file mode 100644
index 000000000..b8062017b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_server.hpp
@@ -0,0 +1,167 @@
+#pragma once
+
+#include "ikvm_args.hpp"
+#include "ikvm_input.hpp"
+#include "ikvm_video.hpp"
+
+#include <rfb/rfb.h>
+
+#include <vector>
+
+namespace ikvm
+{
+
+/*
+ * @class Server
+ * @brief Manages the RFB server connection and updates
+ */
+class Server
+{
+ public:
+ /*
+ * @struct ClientData
+ * @brief Store necessary data for each connected RFB client
+ */
+ struct ClientData
+ {
+ /*
+ * @brief Constructs ClientData object
+ *
+ * @param[in] s - Number of frames to skip when client connects
+ * @param[in] i - Pointer to Input object
+ */
+ ClientData(int s, Input* i) : skipFrame(s), input(i)
+ {
+ }
+ ~ClientData() = default;
+ ClientData(const ClientData&) = default;
+ ClientData& operator=(const ClientData&) = default;
+ ClientData(ClientData&&) = default;
+ ClientData& operator=(ClientData&&) = default;
+
+ int skipFrame;
+ Input* input;
+ };
+
+ /*
+ * @brief Constructs Server object
+ *
+ * @param[in] args - Reference to Args object
+ * @param[in] i - Reference to Input object
+ * @param[in] v - Reference to Video object
+ */
+ Server(const Args& args, Input& i, Video& v);
+ ~Server();
+ Server(const Server&) = default;
+ Server& operator=(const Server&) = default;
+ Server(Server&&) = default;
+ Server& operator=(Server&&) = default;
+
+ /* @brief Resizes the RFB framebuffer */
+ void resize();
+ /* @brief Executes any pending RFB updates and client input */
+ void run();
+ /* @brief Sends pending video frame to clients */
+ void sendFrame();
+
+ /*
+ * @brief Indicates whether or not video data is desired
+ *
+ * @return Boolean to indicate whether any clients need a video frame
+ */
+ inline bool wantsFrame() const
+ {
+ return server->clientHead;
+ }
+ /*
+ * @brief Get the Video object
+ *
+ * @return Reference to the Video object
+ */
+ inline const Video& getVideo() const
+ {
+ return video;
+ }
+
+ private:
+ /*
+ * @brief Handler for a client disconnecting
+ *
+ * @param[in] cl - Handle to the client object
+ */
+ static void clientGone(rfbClientPtr cl);
+ /*
+ * @brief Handler for client connecting
+ *
+ * @param[in] cl - Handle to the client object
+ */
+ static enum rfbNewClientAction newClient(rfbClientPtr cl);
+
+ /* @brief Performs the resize operation on the framebuffer */
+ void doResize();
+
+ /* @brief Boolean to indicate if a resize operation is on-going */
+ bool pendingResize;
+ /* @brief Number of frames handled since a client connected */
+ int frameCounter;
+ /* @brief Number of connected clients */
+ unsigned int numClients;
+ /* @brief Microseconds to process RFB events every frame */
+ long int processTime;
+ /* @brief Handle to the RFB server object */
+ rfbScreenInfoPtr server;
+ /* @brief Reference to the Input object */
+ Input& input;
+ /* @brief Reference to the Video object */
+ Video& video;
+ /* @brief Default framebuffer storage */
+ std::vector<char> framebuffer;
+ /* @brief Cursor bitmap width */
+ static constexpr int cursorWidth = 20;
+ /* @brief Cursor bitmap height */
+ static constexpr int cursorHeight = 20;
+ /* @brief Cursor bitmap */
+ static constexpr char cursor[] = " "
+ " x "
+ " xx "
+ " xxx "
+ " xxxx "
+ " xxxxx "
+ " xxxxxx "
+ " xxxxxxx "
+ " xxxxxxxx "
+ " xxxxxxxxx "
+ " xxxxxxxxxx "
+ " xxxxxxxxxxx "
+ " xxxxxxx "
+ " xxxxxxx "
+ " xxx xxx "
+ " xx xxx "
+ " x xxx "
+ " xxx "
+ " x "
+ " ";
+ /* @brief Cursor bitmap mask */
+ static constexpr char cursorMask[] = " o "
+ "oxo "
+ "oxxo "
+ "oxxxo "
+ "oxxxxo "
+ "oxxxxxo "
+ "oxxxxxxo "
+ "oxxxxxxxo "
+ "oxxxxxxxxo "
+ "oxxxxxxxxxo "
+ "oxxxxxxxxxxo "
+ "oxxxxxxxxxxxo "
+ "oxxxxxxxoooo "
+ "oxxxxxxxo "
+ "oxxxooxxxo "
+ "oxxo oxxxo "
+ "oxo oxxxo "
+ " o oxxxo "
+ " oxo "
+ " o ";
+};
+
+} // namespace ikvm
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_video.cpp b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_video.cpp
new file mode 100644
index 000000000..13de54da1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_video.cpp
@@ -0,0 +1,478 @@
+#include "ikvm_video.hpp"
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/videodev2.h>
+#include <poll.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/elog.hpp>
+#include <phosphor-logging/log.hpp>
+#include <xyz/openbmc_project/Common/Device/error.hpp>
+#include <xyz/openbmc_project/Common/File/error.hpp>
+
+namespace ikvm
+{
+
+const int Video::bitsPerSample(8);
+const int Video::bytesPerPixel(4);
+const int Video::samplesPerPixel(3);
+
+using namespace phosphor::logging;
+using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
+using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
+
+Video::Video(const std::string& p, Input& input, int fr) :
+ resizeAfterOpen(false), fd(-1), frameRate(fr), lastFrameIndex(-1),
+ height(600), width(800), input(input), path(p)
+{
+}
+
+Video::~Video()
+{
+ stop();
+}
+
+char* Video::getData()
+{
+ if (lastFrameIndex >= 0)
+ {
+ return (char*)buffers[lastFrameIndex].data;
+ }
+
+ return nullptr;
+}
+
+void Video::getFrame()
+{
+ bool queue(false);
+ int rc(0);
+ v4l2_buffer buf;
+
+ if (fd < 0)
+ {
+ return;
+ }
+
+ memset(&buf, 0, sizeof(v4l2_buffer));
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+
+ while (rc >= 0)
+ {
+ rc = ioctl(fd, VIDIOC_DQBUF, &buf);
+ if (rc >= 0)
+ {
+ buffers[buf.index].queued = false;
+
+ if (!(buf.flags & V4L2_BUF_FLAG_ERROR))
+ {
+ lastFrameIndex = buf.index;
+ buffers[lastFrameIndex].payload = buf.bytesused;
+ queue = true;
+ break;
+ }
+ else
+ {
+ buffers[buf.index].payload = 0;
+ }
+ }
+ else
+ {
+ restart();
+ return;
+ }
+ }
+
+ if (queue)
+ {
+ for (unsigned int i = 0; i < buffers.size(); ++i)
+ {
+ if (i == (unsigned int)lastFrameIndex)
+ {
+ continue;
+ }
+
+ if (!buffers[i].queued)
+ {
+ memset(&buf, 0, sizeof(v4l2_buffer));
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = i;
+
+ rc = ioctl(fd, VIDIOC_QBUF, &buf);
+ if (rc)
+ {
+ log<level::ERR>("Failed to queue buffer",
+ entry("ERROR=%s", strerror(errno)));
+ elog<ReadFailure>(
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_ERRNO(errno),
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_DEVICE_PATH(path.c_str()));
+ }
+
+ buffers[i].queued = true;
+ }
+ }
+ }
+}
+
+bool Video::needsResize()
+{
+ int rc;
+ v4l2_dv_timings timings;
+
+ if (fd < 0)
+ {
+ return false;
+ }
+
+ if (resizeAfterOpen)
+ {
+ return true;
+ }
+
+ memset(&timings, 0, sizeof(v4l2_dv_timings));
+ rc = ioctl(fd, VIDIOC_QUERY_DV_TIMINGS, &timings);
+ if (rc < 0)
+ {
+ log<level::ERR>("Failed to query timings",
+ entry("ERROR=%s", strerror(errno)));
+ return false;
+ }
+
+ if (timings.bt.width != width || timings.bt.height != height)
+ {
+ width = timings.bt.width;
+ height = timings.bt.height;
+
+ if (!width || !height)
+ {
+ log<level::ERR>("Failed to get new resolution",
+ entry("WIDTH=%d", width),
+ entry("HEIGHT=%d", height));
+ elog<Open>(
+ xyz::openbmc_project::Common::File::Open::ERRNO(-EPROTO),
+ xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
+ }
+
+ lastFrameIndex = -1;
+ return true;
+ }
+
+ return false;
+}
+
+void Video::resize()
+{
+ int rc;
+ unsigned int i;
+ bool needsResizeCall(false);
+ v4l2_buf_type type(V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ v4l2_requestbuffers req;
+
+ if (fd < 0)
+ {
+ return;
+ }
+
+ if (resizeAfterOpen)
+ {
+ resizeAfterOpen = false;
+ return;
+ }
+
+ for (i = 0; i < buffers.size(); ++i)
+ {
+ if (buffers[i].data)
+ {
+ needsResizeCall = true;
+ break;
+ }
+ }
+
+ if (needsResizeCall)
+ {
+ rc = ioctl(fd, VIDIOC_STREAMOFF, &type);
+ if (rc)
+ {
+ log<level::ERR>("Failed to stop streaming",
+ entry("ERROR=%s", strerror(errno)));
+ elog<ReadFailure>(
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_ERRNO(errno),
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_DEVICE_PATH(path.c_str()));
+ }
+ }
+
+ for (i = 0; i < buffers.size(); ++i)
+ {
+ if (buffers[i].data)
+ {
+ munmap(buffers[i].data, buffers[i].size);
+ buffers[i].data = nullptr;
+ buffers[i].queued = false;
+ }
+ }
+
+ if (needsResizeCall)
+ {
+ v4l2_dv_timings timings;
+
+ memset(&req, 0, sizeof(v4l2_requestbuffers));
+ req.count = 0;
+ req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req.memory = V4L2_MEMORY_MMAP;
+ rc = ioctl(fd, VIDIOC_REQBUFS, &req);
+ if (rc < 0)
+ {
+ log<level::ERR>("Failed to zero streaming buffers",
+ entry("ERROR=%s", strerror(errno)));
+ elog<ReadFailure>(
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_ERRNO(errno),
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_DEVICE_PATH(path.c_str()));
+ }
+
+ memset(&timings, 0, sizeof(v4l2_dv_timings));
+ rc = ioctl(fd, VIDIOC_QUERY_DV_TIMINGS, &timings);
+ if (rc < 0)
+ {
+ log<level::ERR>("Failed to query timings",
+ entry("ERROR=%s", strerror(errno)));
+ elog<ReadFailure>(
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_ERRNO(errno),
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_DEVICE_PATH(path.c_str()));
+ }
+
+ rc = ioctl(fd, VIDIOC_S_DV_TIMINGS, &timings);
+ if (rc < 0)
+ {
+ log<level::ERR>("Failed to set timings",
+ entry("ERROR=%s", strerror(errno)));
+ elog<ReadFailure>(
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_ERRNO(errno),
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_DEVICE_PATH(path.c_str()));
+ }
+
+ buffers.clear();
+ }
+
+ memset(&req, 0, sizeof(v4l2_requestbuffers));
+ req.count = 3;
+ req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req.memory = V4L2_MEMORY_MMAP;
+ rc = ioctl(fd, VIDIOC_REQBUFS, &req);
+ if (rc < 0 || req.count < 2)
+ {
+ log<level::ERR>("Failed to request streaming buffers",
+ entry("ERROR=%s", strerror(errno)));
+ elog<ReadFailure>(
+ xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
+ errno),
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_DEVICE_PATH(path.c_str()));
+ }
+
+ buffers.resize(req.count);
+
+ for (i = 0; i < buffers.size(); ++i)
+ {
+ v4l2_buffer buf;
+
+ memset(&buf, 0, sizeof(v4l2_buffer));
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = i;
+
+ rc = ioctl(fd, VIDIOC_QUERYBUF, &buf);
+ if (rc < 0)
+ {
+ log<level::ERR>("Failed to query buffer",
+ entry("ERROR=%s", strerror(errno)));
+ elog<ReadFailure>(
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_ERRNO(errno),
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_DEVICE_PATH(path.c_str()));
+ }
+
+ buffers[i].data = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, buf.m.offset);
+ if (buffers[i].data == MAP_FAILED)
+ {
+ log<level::ERR>("Failed to mmap buffer",
+ entry("ERROR=%s", strerror(errno)));
+ elog<ReadFailure>(
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_ERRNO(errno),
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_DEVICE_PATH(path.c_str()));
+ }
+
+ buffers[i].size = buf.length;
+
+ rc = ioctl(fd, VIDIOC_QBUF, &buf);
+ if (rc < 0)
+ {
+ log<level::ERR>("Failed to queue buffer",
+ entry("ERROR=%s", strerror(errno)));
+ elog<ReadFailure>(
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_ERRNO(errno),
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_DEVICE_PATH(path.c_str()));
+ }
+
+ buffers[i].queued = true;
+ }
+
+ rc = ioctl(fd, VIDIOC_STREAMON, &type);
+ if (rc)
+ {
+ log<level::ERR>("Failed to start streaming",
+ entry("ERROR=%s", strerror(errno)));
+ elog<ReadFailure>(
+ xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
+ errno),
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_DEVICE_PATH(path.c_str()));
+ }
+}
+
+void Video::start()
+{
+ int rc;
+ size_t oldHeight = height;
+ size_t oldWidth = width;
+ v4l2_capability cap;
+ v4l2_format fmt;
+ v4l2_streamparm sparm;
+
+ if (fd >= 0)
+ {
+ return;
+ }
+
+ fd = open(path.c_str(), O_RDWR);
+ if (fd < 0)
+ {
+ input.sendWakeupPacket();
+
+ fd = open(path.c_str(), O_RDWR);
+ if (fd < 0)
+ {
+ log<level::ERR>("Failed to open video device",
+ entry("PATH=%s", path.c_str()),
+ entry("ERROR=%s", strerror(errno)));
+ elog<Open>(
+ xyz::openbmc_project::Common::File::Open::ERRNO(errno),
+ xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
+ }
+ }
+
+ memset(&cap, 0, sizeof(v4l2_capability));
+ rc = ioctl(fd, VIDIOC_QUERYCAP, &cap);
+ if (rc < 0)
+ {
+ log<level::ERR>("Failed to query video device capabilities",
+ entry("ERROR=%s", strerror(errno)));
+ elog<ReadFailure>(
+ xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
+ errno),
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_DEVICE_PATH(path.c_str()));
+ }
+
+ if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||
+ !(cap.capabilities & V4L2_CAP_STREAMING))
+ {
+ log<level::ERR>("Video device doesn't support this application");
+ elog<Open>(
+ xyz::openbmc_project::Common::File::Open::ERRNO(errno),
+ xyz::openbmc_project::Common::File::Open::PATH(path.c_str()));
+ }
+
+ memset(&fmt, 0, sizeof(v4l2_format));
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rc = ioctl(fd, VIDIOC_G_FMT, &fmt);
+ if (rc < 0)
+ {
+ log<level::ERR>("Failed to query video device format",
+ entry("ERROR=%s", strerror(errno)));
+ elog<ReadFailure>(
+ xyz::openbmc_project::Common::Device::ReadFailure::CALLOUT_ERRNO(
+ errno),
+ xyz::openbmc_project::Common::Device::ReadFailure::
+ CALLOUT_DEVICE_PATH(path.c_str()));
+ }
+
+ memset(&sparm, 0, sizeof(v4l2_streamparm));
+ sparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ sparm.parm.capture.timeperframe.numerator = 1;
+ sparm.parm.capture.timeperframe.denominator = frameRate;
+ rc = ioctl(fd, VIDIOC_S_PARM, &sparm);
+ if (rc < 0)
+ {
+ log<level::WARNING>("Failed to set video device frame rate",
+ entry("ERROR=%s", strerror(errno)));
+ }
+
+ height = fmt.fmt.pix.height;
+ width = fmt.fmt.pix.width;
+
+ resize();
+
+ if (oldHeight != height || oldWidth != width)
+ {
+ resizeAfterOpen = true;
+ }
+}
+
+void Video::stop()
+{
+ int rc;
+ unsigned int i;
+ v4l2_buf_type type(V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+ if (fd < 0)
+ {
+ return;
+ }
+
+ lastFrameIndex = -1;
+
+ rc = ioctl(fd, VIDIOC_STREAMOFF, &type);
+ if (rc)
+ {
+ log<level::ERR>("Failed to stop streaming",
+ entry("ERROR=%s", strerror(errno)));
+ }
+
+ for (i = 0; i < buffers.size(); ++i)
+ {
+ if (buffers[i].data)
+ {
+ munmap(buffers[i].data, buffers[i].size);
+ buffers[i].data = nullptr;
+ buffers[i].queued = false;
+ }
+ }
+
+ close(fd);
+ fd = -1;
+}
+
+} // namespace ikvm
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_video.hpp b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_video.hpp
new file mode 100644
index 000000000..8ce5319f5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/ikvm_video.hpp
@@ -0,0 +1,150 @@
+#pragma once
+
+#include "ikvm_input.hpp"
+
+#include <mutex>
+#include <string>
+#include <vector>
+
+namespace ikvm
+{
+
+/*
+ * @class Video
+ * @brief Sets up the V4L2 video device and performs read operations
+ */
+class Video
+{
+ public:
+ /*
+ * @brief Constructs Video object
+ *
+ * @param[in] p - Path to the V4L2 video device
+ * @param[in] input - Reference to the Input object
+ * @param[in] fr - desired frame rate of the video
+ */
+ Video(const std::string& p, Input& input, int fr = 30);
+ ~Video();
+ Video(const Video&) = default;
+ Video& operator=(const Video&) = default;
+ Video(Video&&) = default;
+ Video& operator=(Video&&) = default;
+
+ /*
+ * @brief Gets the video frame data
+ *
+ * @return Pointer to the video frame data
+ */
+ char* getData();
+ /* @brief Performs read to grab latest video frame */
+ void getFrame();
+ /*
+ * @brief Gets whether or not the video frame needs to be resized
+ *
+ * @return Boolean indicating if the frame needs to be resized
+ */
+ bool needsResize();
+ /* @brief Performs the resize and re-allocates framebuffer */
+ void resize();
+ /* @brief Starts streaming from the video device */
+ void start();
+ /* @brief Stops streaming from the video device */
+ void stop();
+
+ /* @brief Restart streaming from the video device */
+ inline void restart()
+ {
+ stop();
+ start();
+ }
+ /*
+ * @brief Gets the desired video frame rate in frames per second
+ *
+ * @return Value of the desired frame rate
+ */
+ inline int getFrameRate() const
+ {
+ return frameRate;
+ }
+ /*
+ * @brief Gets the size of the video frame data
+ *
+ * @return Value of the size of the video frame data in bytes
+ */
+ inline size_t getFrameSize() const
+ {
+ return buffers[lastFrameIndex].payload;
+ }
+ /*
+ * @brief Gets the height of the video frame
+ *
+ * @return Value of the height of video frame in pixels
+ */
+ inline size_t getHeight() const
+ {
+ return height;
+ }
+ /*
+ * @brief Gets the width of the video frame
+ *
+ * @return Value of the width of video frame in pixels
+ */
+ inline size_t getWidth() const
+ {
+ return width;
+ }
+
+ /* @brief Number of bits per component of a pixel */
+ static const int bitsPerSample;
+ /* @brief Number of bytes of storage for a pixel */
+ static const int bytesPerPixel;
+ /* @brief Number of components in a pixel (i.e. 3 for RGB pixel) */
+ static const int samplesPerPixel;
+
+ private:
+ /*
+ * @struct Buffer
+ * @brief Store the address and size of frame data from streaming
+ * operations
+ */
+ struct Buffer
+ {
+ Buffer() : data(nullptr), queued(false), payload(0), size(0)
+ {
+ }
+ ~Buffer() = default;
+ Buffer(const Buffer&) = default;
+ Buffer& operator=(const Buffer&) = default;
+ Buffer(Buffer&&) = default;
+ Buffer& operator=(Buffer&&) = default;
+
+ void* data;
+ bool queued;
+ size_t payload;
+ size_t size;
+ };
+
+ /*
+ * @brief Boolean to indicate whether the resize was triggered during
+ * the open operation
+ */
+ bool resizeAfterOpen;
+ /* @brief File descriptor for the V4L2 video device */
+ int fd;
+ /* @brief Desired frame rate of video stream in frames per second */
+ int frameRate;
+ /* @brief Buffer index for the last video frame */
+ int lastFrameIndex;
+ /* @brief Height in pixels of the video frame */
+ size_t height;
+ /* @brief Width in pixels of the video frame */
+ size_t width;
+ /* @brief Reference to the Input object */
+ Input& input;
+ /* @brief Path to the V4L2 video device */
+ const std::string path;
+ /* @brief Streaming buffer storage */
+ std::vector<Buffer> buffers;
+};
+
+} // namespace ikvm
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/obmc-ikvm.cpp b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/obmc-ikvm.cpp
new file mode 100644
index 000000000..271857b72
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/obmc-ikvm.cpp
@@ -0,0 +1,12 @@
+#include "ikvm_args.hpp"
+#include "ikvm_manager.hpp"
+
+int main(int argc, char* argv[])
+{
+ ikvm::Args args(argc, argv);
+ ikvm::Manager manager(args);
+
+ manager.run();
+
+ return 0;
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/scancodes.hpp b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/scancodes.hpp
new file mode 100644
index 000000000..db79231a2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/scancodes.hpp
@@ -0,0 +1,82 @@
+#pragma once
+
+#define USBHID_KEY_A 0x04
+#define USBHID_KEY_B 0x05
+#define USBHID_KEY_C 0x06
+#define USBHID_KEY_D 0x07
+#define USBHID_KEY_E 0x08
+#define USBHID_KEY_F 0x09
+#define USBHID_KEY_G 0x0a
+#define USBHID_KEY_H 0x0b
+#define USBHID_KEY_I 0x0c
+#define USBHID_KEY_J 0x0d
+#define USBHID_KEY_K 0x0e
+#define USBHID_KEY_L 0x0f
+#define USBHID_KEY_M 0x10
+#define USBHID_KEY_N 0x11
+#define USBHID_KEY_O 0x12
+#define USBHID_KEY_P 0x13
+#define USBHID_KEY_Q 0x14
+#define USBHID_KEY_R 0x15
+#define USBHID_KEY_S 0x16
+#define USBHID_KEY_T 0x17
+#define USBHID_KEY_U 0x18
+#define USBHID_KEY_V 0x19
+#define USBHID_KEY_W 0x1a
+#define USBHID_KEY_X 0x1b
+#define USBHID_KEY_Y 0x1c
+#define USBHID_KEY_Z 0x1d
+#define USBHID_KEY_1 0x1e
+#define USBHID_KEY_2 0x1f
+#define USBHID_KEY_3 0x20
+#define USBHID_KEY_4 0x21
+#define USBHID_KEY_5 0x22
+#define USBHID_KEY_6 0x23
+#define USBHID_KEY_7 0x24
+#define USBHID_KEY_8 0x25
+#define USBHID_KEY_9 0x26
+#define USBHID_KEY_0 0x27
+#define USBHID_KEY_RETURN 0x28
+#define USBHID_KEY_ESC 0x29
+#define USBHID_KEY_BACKSPACE 0x2a
+#define USBHID_KEY_TAB 0x2b
+#define USBHID_KEY_SPACE 0x2c
+#define USBHID_KEY_MINUS 0x2d
+#define USBHID_KEY_EQUAL 0x2e
+#define USBHID_KEY_LEFTBRACE 0x2f
+#define USBHID_KEY_RIGHTBRACE 0x30
+#define USBHID_KEY_BACKSLASH 0x31
+#define USBHID_KEY_HASH 0x32
+#define USBHID_KEY_SEMICOLON 0x33
+#define USBHID_KEY_APOSTROPHE 0x34
+#define USBHID_KEY_GRAVE 0x35
+#define USBHID_KEY_COMMA 0x36
+#define USBHID_KEY_DOT 0x37
+#define USBHID_KEY_SLASH 0x38
+#define USBHID_KEY_CAPSLOCK 0x39
+#define USBHID_KEY_F1 0x3a
+#define USBHID_KEY_F2 0x3b
+#define USBHID_KEY_F3 0x3c
+#define USBHID_KEY_F4 0x3d
+#define USBHID_KEY_F5 0x3e
+#define USBHID_KEY_F6 0x3f
+#define USBHID_KEY_F7 0x40
+#define USBHID_KEY_F8 0x41
+#define USBHID_KEY_F9 0x42
+#define USBHID_KEY_F10 0x43
+#define USBHID_KEY_F11 0x44
+#define USBHID_KEY_F12 0x45
+#define USBHID_KEY_PRINT 0x46
+#define USBHID_KEY_SCROLLLOCK 0x47
+#define USBHID_KEY_PAUSE 0x48
+#define USBHID_KEY_INSERT 0x49
+#define USBHID_KEY_HOME 0x4a
+#define USBHID_KEY_PAGEUP 0x4b
+#define USBHID_KEY_DELETE 0x4c
+#define USBHID_KEY_END 0x4d
+#define USBHID_KEY_PAGEDOWN 0x4e
+#define USBHID_KEY_RIGHT 0x4f
+#define USBHID_KEY_LEFT 0x50
+#define USBHID_KEY_DOWN 0x51
+#define USBHID_KEY_UP 0x52
+#define USBHID_KEY_NUMLOCK 0x53
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..f08b29ce7
--- /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 = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+DEPENDS = " libvncserver sdbusplus sdbusplus-native phosphor-logging phosphor-dbus-interfaces autoconf-archive-native"
+
+SRC_URI = "git://github.com/openbmc/obmc-ikvm"
+SRCREV = "2bc661d34abd1fda92a9d2b256ed88ca0e90d09a"
+
+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..c34578b7f
--- /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 = "371617ab2dbdf003e373876fa7d5a9ca83b1529d"
+
+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..923133be7
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb
@@ -0,0 +1,43 @@
+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 \
+ 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..21299e5b6
--- /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 = "3cc86d6c536b4c5ee7afb5447837b83ce8b3d149"
+
+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..074f580e9
--- /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 = "3cc86d6c536b4c5ee7afb5447837b83ce8b3d149"
+
+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..232903f2c
--- /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,276 @@
+From 3b9ab062d0eb781fc767bd15ce58dc7b7990e65b 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
+
+This commit updates PECI drivers to with linux community
+upstreaming version.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/hwmon/peci-cputemp.c | 2 +-
+ drivers/hwmon/peci-dimmtemp.c | 2 +-
+ drivers/hwmon/peci-hwmon.h | 2 +-
+ drivers/mfd/intel-peci-client.c | 43 +++++++++++++++--------------------
+ drivers/peci/peci-aspeed.c | 2 +-
+ drivers/peci/peci-core.c | 10 ++++----
+ include/linux/mfd/intel-peci-client.h | 4 +---
+ include/linux/peci.h | 2 +-
+ 8 files changed, 29 insertions(+), 38 deletions(-)
+
+diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c
+index 11880c86a854..63796d883c82 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>
+diff --git a/drivers/hwmon/peci-dimmtemp.c b/drivers/hwmon/peci-dimmtemp.c
+index 86a45a90805b..6e90d9bfeb45 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>
+diff --git a/drivers/hwmon/peci-hwmon.h b/drivers/hwmon/peci-hwmon.h
+index 6ca1855a86bb..16e3c195094c 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
+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/peci-aspeed.c b/drivers/peci/peci-aspeed.c
+index 51cb2563ceb6..2293d4e56e63 100644
+--- a/drivers/peci/peci-aspeed.c
++++ b/drivers/peci/peci-aspeed.c
+@@ -1,6 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0
+ // Copyright (C) 2012-2017 ASPEED Technology Inc.
+-// Copyright (c) 2018 Intel Corporation
++// Copyright (c) 2018-2019 Intel Corporation
+
+ #include <linux/bitfield.h>
+ #include <linux/clk.h>
+diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c
+index fac8c72dcda8..7ae05ded94bf 100644
+--- a/drivers/peci/peci-core.c
++++ b/drivers/peci/peci-core.c
+@@ -1,5 +1,5 @@
+ // 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>
+@@ -666,9 +666,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 *
+@@ -1119,7 +1119,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 */
+
+@@ -1216,7 +1216,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 */
+
+diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h
+index 8f6d823a59cd..dd5eb36cca75 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
+@@ -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..4b8be939585c 100644
+--- a/include/linux/peci.h
++++ b/include/linux/peci.h
+@@ -1,5 +1,5 @@
+ /* 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
+--
+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..fe50c0aea
--- /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,565 @@
+From 4084484a57d9a81b6581455ff144fc4f9c603075 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>
+---
+ .../devicetree/bindings/misc/aspeed-sio.txt | 14 +
+ drivers/misc/Kconfig | 9 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/aspeed-lpc-sio.c | 435 +++++++++++++++++++++
+ include/uapi/linux/aspeed-lpc-sio.h | 44 +++
+ 5 files changed, 503 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..7953cd3367df
+--- /dev/null
++++ b/Documentation/devicetree/bindings/misc/aspeed-sio.txt
+@@ -0,0 +1,14 @@
++* Aspeed LPC SIO driver.
++
++Required properties:
++- compatible: "aspeed,ast2500-lpc-sio"
++ - aspeed,ast2500-lpc-sio: Aspeed AST2500 family
++- reg: Should contain lpc-sio registers location and length
++
++Example:
++lpc_sio: lpc-sio@100 {
++ compatible = "aspeed,ast2500-lpc-sio";
++ reg = <0x100 0x20>;
++ status = "disabled";
++};
++
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 689d07ea7ded..fe1e2a4072a8 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 e4170f62ab98..a2b85ec21d09 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..fd9a83bd66d7
+--- /dev/null
++++ b/drivers/misc/aspeed-lpc-sio.c
+@@ -0,0 +1,435 @@
++/*
++ * 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.
++ *
++ */
++
++#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 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->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");
++ else
++ dev_info(dev, "Loaded at %pap (0x%08x)\n",
++ &lpc_sio->regmap, lpc_sio->reg_base);
++
++ 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);
++
++ return 0;
++}
++
++static const struct of_device_id aspeed_lpc_sio_match[] = {
++ { .compatible = "aspeed,ast2500-lpc-sio" },
++ { },
++};
++
++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_DEVICE_TABLE(of, aspeed_lpc_sio_match);
++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/0025-dts-add-AST2500-LPC-SIO-tree-node.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0025-dts-add-AST2500-LPC-SIO-tree-node.patch
new file mode 100644
index 000000000..73bd68f21
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0025-dts-add-AST2500-LPC-SIO-tree-node.patch
@@ -0,0 +1,32 @@
+From ba357b37e1041b6fe0e5012cf09571381207aa9b Mon Sep 17 00:00:00 2001
+From: Haiyue Wang <haiyue.wang@linux.intel.com>
+Date: Sat, 24 Feb 2018 11:23:46 +0800
+Subject: [PATCH] dts: add AST2500 LPC SIO tree node
+
+Add the AST2500 LPC SIO tree node.
+
+Signed-off-by: Haiyue Wang <haiyue.wang@linux.intel.com>
+---
+ arch/arm/boot/dts/aspeed-g5.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index baf230034480..f7e812d36641 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -464,6 +464,12 @@
+ compatible = "aspeed,bmc-misc";
+ };
+
++ lpc_sio: lpc-sio@100 {
++ compatible = "aspeed,ast2500-lpc-sio";
++ reg = <0x100 0x20>;
++ status = "disabled";
++ };
++
+ mbox: mbox@180 {
+ compatible = "aspeed,ast2500-mbox";
+ reg = <0x180 0x5c>;
+--
+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..3ba6fd56e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch
@@ -0,0 +1,392 @@
+From e734cd91f288838a491a75e16f3a09d353079139 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 | 200 ++++++++++++++++++++++++++++++++++++++++
+ include/uapi/linux/peci-ioctl.h | 109 ++++++++++++++++++++++
+ 2 files changed, 309 insertions(+)
+
+diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c
+index fac8c72dcda8..62dada99afee 100644
+--- a/drivers/peci/peci-core.c
++++ b/drivers/peci/peci-core.c
+@@ -242,6 +242,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);
+
+ return rc;
+ }
+@@ -515,6 +518,197 @@ static int peci_ioctl_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
+ return rc;
+ }
+
++static int peci_ioctl_rd_end_pt_cfg(struct peci_adapter *adapter, void *vmsg)
++{
++ struct peci_rd_end_pt_cfg_msg *umsg = vmsg;
++ struct peci_xfer_msg msg;
++ u32 address;
++ int rc = 0;
++
++ switch (umsg->msg_type) {
++ case RDENDPTCFG_TYPE_LOCAL_PCI:
++ case 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;
++ }
++
++ 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_len = RDENDPTCFG_PCI_WRITE_LEN;
++ msg.rx_len = RDENDPTCFG_READ_LEN_BASE + umsg->rx_len;
++ msg.tx_buf[0] = RDENDPTCFG_PECI_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] = RDENDPTCFG_ADDR_TYPE_PCI; /* Address 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 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 !=
++ RDENDPTCFG_ADDR_TYPE_MMIO_D &&
++ umsg->params.mmio.addr_type !=
++ RDENDPTCFG_ADDR_TYPE_MMIO_Q) {
++ dev_dbg(&adapter->dev,
++ "Invalid address type, addr_type: %d\n",
++ umsg->params.mmio.addr_type);
++ return -EINVAL;
++ }
++
++ address = umsg->params.mmio.function; /* [2:0] - Function */
++ address |= (u32)umsg->params.mmio.device
++ << 3; /* [7:3] - Device */
++
++ msg.addr = umsg->addr;
++ msg.tx_len = RDENDPTCFG_MMIO_D_WRITE_LEN;
++ msg.rx_len = RDENDPTCFG_READ_LEN_BASE + umsg->rx_len;
++ msg.tx_buf[0] = RDENDPTCFG_PECI_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
++ == RDENDPTCFG_ADDR_TYPE_MMIO_Q) {
++ msg.tx_len = 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;
++ }
++
++ rc = peci_xfer_with_retries(adapter, &msg, false);
++ if (!rc)
++ memcpy(umsg->data, &msg.rx_buf[1], umsg->rx_len);
++
++ return rc;
++}
++
++static int peci_ioctl_crashdump_disc(struct peci_adapter *adapter, void *vmsg)
++{
++ struct peci_crashdump_disc_msg *umsg = vmsg;
++ struct peci_xfer_msg msg;
++ int rc = 0;
++
++ /* 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.addr = umsg->addr;
++ msg.tx_len = CRASHDUMP_DISC_WRITE_LEN;
++ msg.rx_len = CRASHDUMP_DISC_READ_LEN_BASE + umsg->rx_len;
++ msg.tx_buf[0] = 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] = CRASHDUMP_DISC_VERSION;
++ msg.tx_buf[3] = 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;
++
++ rc = peci_xfer_with_retries(adapter, &msg, false);
++ if (!rc)
++ memcpy(umsg->data, &msg.rx_buf[1], umsg->rx_len);
++
++ return rc;
++}
++
++static int peci_ioctl_crashdump_get_frame(struct peci_adapter *adapter,
++ void *vmsg)
++{
++ struct peci_crashdump_get_frame_msg *umsg = vmsg;
++ struct peci_xfer_msg msg;
++ int rc = 0;
++
++ /* 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.addr = umsg->addr;
++ msg.tx_len = CRASHDUMP_GET_FRAME_WRITE_LEN;
++ msg.rx_len = CRASHDUMP_GET_FRAME_READ_LEN_BASE + umsg->rx_len;
++ msg.tx_buf[0] = 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] = CRASHDUMP_GET_FRAME_VERSION;
++ msg.tx_buf[3] = 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);
++
++ rc = peci_xfer_with_retries(adapter, &msg, false);
++ if (!rc)
++ memcpy(umsg->data, &msg.rx_buf[1], umsg->rx_len);
++
++ return rc;
++}
++
+ typedef int (*peci_ioctl_fn_type)(struct peci_adapter *, void *);
+
+ static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = {
+@@ -530,6 +724,9 @@ static const peci_ioctl_fn_type peci_ioctl_fn[PECI_CMD_MAX] = {
+ NULL, /* Reserved */
+ peci_ioctl_rd_pci_cfg_local,
+ peci_ioctl_wr_pci_cfg_local,
++ peci_ioctl_rd_end_pt_cfg,
++ peci_ioctl_crashdump_disc,
++ peci_ioctl_crashdump_get_frame,
+ };
+
+ /**
+@@ -592,6 +789,9 @@ static long peci_ioctl(struct file *file, unsigned int iocmd, unsigned long arg)
+ case PECI_IOC_RD_PCI_CFG:
+ case PECI_IOC_RD_PCI_CFG_LOCAL:
+ case PECI_IOC_WR_PCI_CFG_LOCAL:
++ case PECI_IOC_RD_END_PT_CFG:
++ case PECI_IOC_CRASHDUMP_DISC:
++ case PECI_IOC_CRASHDUMP_GET_FRAME:
+ cmd = _IOC_NR(iocmd);
+ msg_len = _IOC_SIZE(iocmd);
+ break;
+diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h
+index a6dae71cbff5..5040d1cb4a3d 100644
+--- a/include/uapi/linux/peci-ioctl.h
++++ b/include/uapi/linux/peci-ioctl.h
+@@ -31,6 +31,40 @@
+ #define PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */
+ #define PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */
+
++/* RdEndPointCfg Parameters */
++enum rdendptcfg_msg_type {
++ RDENDPTCFG_TYPE_LOCAL_PCI = 0x03,
++ RDENDPTCFG_TYPE_PCI = 0x04,
++ RDENDPTCFG_TYPE_MMIO = 0x05,
++};
++
++enum rdendptcfg_addr_type {
++ RDENDPTCFG_ADDR_TYPE_PCI = 0x04,
++ RDENDPTCFG_ADDR_TYPE_MMIO_D = 0x05,
++ RDENDPTCFG_ADDR_TYPE_MMIO_Q = 0x06,
++};
++
++/* Crashdump Parameters */
++enum crashdump_agent {
++ CRASHDUMP_CORE = 0x00,
++ CRASHDUMP_TOR = 0x01,
++};
++
++enum crashdump_discovery_sub_opcode {
++ CRASHDUMP_ENABLED = 0x00,
++ CRASHDUMP_NUM_AGENTS = 0x01,
++ CRASHDUMP_AGENT_DATA = 0x02,
++};
++
++enum crashdump_agent_data_param {
++ CRASHDUMP_AGENT_ID = 0x00,
++ CRASHDUMP_AGENT_PARAM = 0x01,
++};
++
++enum crashdump_agent_param {
++ CRASHDUMP_PAYLOAD_SIZE = 0x00,
++};
++
+ /* RdPkgConfig Index */
+ #define MBX_INDEX_CPU_ID 0 /* Package Identifier Read */
+ #define MBX_INDEX_VR_DEBUG 1 /* VR Debug */
+@@ -136,6 +170,22 @@
+ #define WRPCICFGLOCAL_READ_LEN 1
+ #define WRPCICFGLOCAL_PECI_CMD 0xe5
+
++#define RDENDPTCFG_PCI_WRITE_LEN 0x0C
++#define RDENDPTCFG_MMIO_D_WRITE_LEN 0x0E
++#define RDENDPTCFG_MMIO_Q_WRITE_LEN 0x12
++#define RDENDPTCFG_READ_LEN_BASE 1
++#define RDENDPTCFG_PECI_CMD 0xC1
++
++#define CRASHDUMP_DISC_WRITE_LEN 9
++#define CRASHDUMP_DISC_READ_LEN_BASE 1
++#define CRASHDUMP_DISC_VERSION 1
++#define CRASHDUMP_DISC_OPCODE 1
++#define CRASHDUMP_GET_FRAME_WRITE_LEN 10
++#define CRASHDUMP_GET_FRAME_READ_LEN_BASE 1
++#define CRASHDUMP_GET_FRAME_VERSION 3
++#define CRASHDUMP_GET_FRAME_OPCODE 3
++#define CRASHDUMP_CMD 0x71
++
+ #define PECI_BUFFER_SIZE 32
+
+ /**
+@@ -172,6 +222,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
+ };
+
+@@ -366,6 +419,50 @@ struct peci_wr_pci_cfg_local_msg {
+ __u32 value;
+ } __attribute__((__packed__));
+
++struct peci_rd_end_pt_cfg_msg {
++ __u8 addr;
++ __u8 msg_type;
++ 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;
++ __u64 offset;
++ } mmio;
++ } params;
++ __u8 rx_len;
++ __u8 data[8];
++} __attribute__((__packed__));
++
++struct peci_crashdump_disc_msg {
++ __u8 addr;
++ __u8 subopcode;
++ __u8 param0;
++ __u16 param1;
++ __u8 param2;
++ __u8 rx_len;
++ __u8 data[8];
++} __attribute__((__packed__));
++
++struct peci_crashdump_get_frame_msg {
++ __u8 addr;
++ __u16 param0;
++ __u16 param1;
++ __u16 param2;
++ __u8 rx_len;
++ __u8 data[16];
++} __attribute__((__packed__));
++
+ #define PECI_IOC_BASE 0xb7
+
+ #define PECI_IOC_XFER \
+@@ -400,4 +497,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..b618c49da
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0038-media-aspeed-backport-ikvm-patches.patch
@@ -0,0 +1,1982 @@
+From ba52b9e7f76879f888afce1f8e7e5ff180b7849b 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.
+
+Signed-off-by: Eddie James <eajames@linux.ibm.com>
+Reviewed-by: Rob Herring <robh@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 | 1729 ++++++++++++++++++++
+ include/dt-bindings/clock/aspeed-clock.h | 1 +
+ 8 files changed, 1824 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 9e9b19ecf6f7..fd4fdb3e6474 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -2350,6 +2350,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 0144d8bfa3fb..e55da933a70b 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 61d41645e4fe..2429a2464556 100644
+--- a/drivers/clk/clk-aspeed.c
++++ b/drivers/clk/clk-aspeed.c
+@@ -96,7 +96,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 */
+@@ -122,6 +122,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 },
+@@ -201,18 +219,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,
+ };
+@@ -326,6 +347,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
+@@ -548,6 +570,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:
+@@ -557,7 +595,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
+ */
+
+ for (i = 0; i < ARRAY_SIZE(aspeed_gates); i++) {
+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..dfec813f50a9
+--- /dev/null
++++ b/drivers/media/platform/aspeed-video.c
+@@ -0,0 +1,1729 @@
++// 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;
++ 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 f43738607d77..15a9059d0303 100644
+--- a/include/dt-bindings/clock/aspeed-clock.h
++++ b/include/dt-bindings/clock/aspeed-clock.h
+@@ -50,5 +50,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/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..cdf4325d9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend
@@ -0,0 +1,31 @@
+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://0025-dts-add-AST2500-LPC-SIO-tree-node.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 \
+ "
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..2ae5eeb64
--- /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 = "9945ddffc67a9e564a92a3c0bddf2a2d7dc70b97"
+
+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_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend
new file mode 100644
index 000000000..2449d9225
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend
@@ -0,0 +1,16 @@
+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 \
+ "
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..3ea7b96b1
--- /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 = "f42741197ec807e0436a5e519ccff18519c67248"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0001-image_verify-Add-support-for-OpenSSL-1.1.0.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0001-image_verify-Add-support-for-OpenSSL-1.1.0.patch
new file mode 100644
index 000000000..c5850473c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0001-image_verify-Add-support-for-OpenSSL-1.1.0.patch
@@ -0,0 +1,130 @@
+From fa124c7944088624d40d6b265bac0651bd8235bb Mon Sep 17 00:00:00 2001
+From: Adriana Kobylak <anoo@us.ibm.com>
+Date: Thu, 6 Sep 2018 13:15:34 -0500
+Subject: [PATCH] image_verify: Add support for OpenSSL 1.1.0
+
+With OpenSSL 1.1.0, some of the functions were renamed, for
+example EVP_MD_CTX_create() and EVP_MD_CTX_destroy() were
+renamed to EVP_MD_CTX_new() and EVP_MD_CTX_free().
+Reference: https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
+Abstract them to support old and new APIs.
+
+Resolves openbmc/openbmc#3136
+
+Tested: Verified the signature verification was successful.
+
+Change-Id: I2297243fdd652055fe9ea88f26eb2dcf473d24e6
+Signed-off-by: Adriana Kobylak <anoo@us.ibm.com>
+
+%% original patch: 0001-image_verify-Add-support-for-OpenSSL-1.1.0.patch
+---
+ Makefile.am | 8 ++++++--
+ image_verify.cpp | 2 +-
+ image_verify.hpp | 1 +
+ utils.cpp | 29 +++++++++++++++++++++++++++++
+ utils.hpp | 15 +++++++++++++++
+ 5 files changed, 52 insertions(+), 3 deletions(-)
+ create mode 100644 utils.cpp
+ create mode 100644 utils.hpp
+
+diff --git a/Makefile.am b/Makefile.am
+index adba0e4..21b556f 100755
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -42,8 +42,12 @@ phosphor_image_updater_SOURCES = \
+ include ubi/Makefile.am.include
+
+ if WANT_SIGNATURE_VERIFY_BUILD
+-noinst_HEADERS += image_verify.hpp
+-phosphor_image_updater_SOURCES += image_verify.cpp
++noinst_HEADERS += \
++ image_verify.hpp \
++ utils.hpp
++phosphor_image_updater_SOURCES += \
++ image_verify.cpp \
++ utils.cpp
+ endif
+
+ if WANT_SYNC
+diff --git a/image_verify.cpp b/image_verify.cpp
+index 7d59910..ba6b24d 100644
+--- a/image_verify.cpp
++++ b/image_verify.cpp
+@@ -216,7 +216,7 @@ bool Signature::verifyFile(const fs::path& file, const fs::path& sigFile,
+ EVP_PKEY_assign_RSA(pKeyPtr.get(), publicRSA);
+
+ // Initializes a digest context.
+- EVP_MD_CTX_Ptr rsaVerifyCtx(EVP_MD_CTX_create(), ::EVP_MD_CTX_destroy);
++ EVP_MD_CTX_Ptr rsaVerifyCtx(EVP_MD_CTX_new(), ::EVP_MD_CTX_free);
+
+ // Adds all digest algorithms to the internal table
+ OpenSSL_add_all_digests();
+diff --git a/image_verify.hpp b/image_verify.hpp
+index cbd0e39..22ee5f9 100644
+--- a/image_verify.hpp
++++ b/image_verify.hpp
+@@ -1,4 +1,5 @@
+ #pragma once
++#include "utils.hpp"
+ #include <openssl/rsa.h>
+ #include <openssl/evp.h>
+ #include <openssl/pem.h>
+diff --git a/utils.cpp b/utils.cpp
+new file mode 100644
+index 0000000..95fc2e0
+--- /dev/null
++++ b/utils.cpp
+@@ -0,0 +1,29 @@
++#include "utils.hpp"
++
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++
++#include <string.h>
++
++static void* OPENSSL_zalloc(size_t num)
++{
++ void* ret = OPENSSL_malloc(num);
++
++ if (ret != NULL)
++ {
++ memset(ret, 0, num);
++ }
++ return ret;
++}
++
++EVP_MD_CTX* EVP_MD_CTX_new(void)
++{
++ return (EVP_MD_CTX*)OPENSSL_zalloc(sizeof(EVP_MD_CTX));
++}
++
++void EVP_MD_CTX_free(EVP_MD_CTX* ctx)
++{
++ EVP_MD_CTX_cleanup(ctx);
++ OPENSSL_free(ctx);
++}
++
++#endif // OPENSSL_VERSION_NUMBER < 0x10100000L
+diff --git a/utils.hpp b/utils.hpp
+new file mode 100644
+index 0000000..90569bf
+--- /dev/null
++++ b/utils.hpp
+@@ -0,0 +1,15 @@
++#pragma once
++
++// With OpenSSL 1.1.0, some functions were deprecated. Need to abstract them
++// to make the code backward compatible with older OpenSSL veresions.
++// Reference: https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++
++#include <openssl/evp.h>
++
++extern "C" {
++EVP_MD_CTX* EVP_MD_CTX_new(void);
++void EVP_MD_CTX_free(EVP_MD_CTX* ctx);
++}
++
++#endif // OPENSSL_VERSION_NUMBER < 0x10100000L
+--
+2.7.4
+
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..9c3c3ee37
--- /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-amr-2.devtools.intel.com:29418/openbmc-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..6d6762fc9
--- /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 = "3cc86d6c536b4c5ee7afb5447837b83ce8b3d149"
+
+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..72d991c7e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend
@@ -0,0 +1 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-channel-inventory%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-channel-inventory%.bbappend
new file mode 100644
index 000000000..d79704ec6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-channel-inventory%.bbappend
@@ -0,0 +1,4 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += " file://channel.yaml \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-channel-inventory%/channel.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-channel-inventory%/channel.yaml
new file mode 100644
index 000000000..032e05127
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-channel-inventory%/channel.yaml
@@ -0,0 +1,8 @@
+# Channel Number (must be unique) is the key
+1:
+ # ifName the ethernet device name (used in the dbus path)
+ ifName: eth0
+2:
+ ifName: eth1
+3:
+ ifName: eth1
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/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..a92fc833b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend
@@ -0,0 +1,29 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+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 \
+ "
+
+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_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend
new file mode 100644
index 000000000..19fa4c06b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend
@@ -0,0 +1,13 @@
+inherit useradd
+
+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 \
+ "
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-node-manager-proxy_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-node-manager-proxy_git.bb
new file mode 100644
index 000000000..24b1dd2a0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-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/openbmc-intel/node-manager;protocol=ssh"
+SRCREV = "596cd421d4749c8b6d672fb410eccf9f2da08b3a"
+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/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..808cee1ed
--- /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-amr-2.devtools.intel.com:29418/openbmc-node-manager;protocol=ssh"
+SRCREV = "e5a5f6189ce357438f40116717b995bab82c50ae"
+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..813ffbfd4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml
@@ -0,0 +1,36 @@
+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'
+
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/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..56fb8531d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend
@@ -0,0 +1,8 @@
+SRCREV = "46342ec359c8e0ed543ebb352cfba8f26ce85afe"
+SRC_URI = "git://github.com/openbmc/dbus-sensors.git"
+
+DEPENDS_append = " i2c-tools"
+
+# turn this back on when we have a need, but disable it now
+# as no shipping platforms use it and it will take cpu cycles
+EXTRA_OECMAKE_append = " -DDISABLE_INTRUSION=ON"
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..184b539a9
--- /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 = "3cc86d6c536b4c5ee7afb5447837b83ce8b3d149"
+
+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..7c6f684ca
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager/0002-Capture-host-restart-cause.patch
@@ -0,0 +1,192 @@
+From 8dea573181c4455e144335e14cac9f54ebbf7208 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.
+Save the restart cause into file system.
+And restort it when BMC boot up.
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ configure.ac | 4 +--
+ host_state_manager.cpp | 16 ++++++++++++
+ host_state_manager.hpp | 56 +++++++++++++++++++++++++++++++++++++++---
+ 3 files changed, 71 insertions(+), 5 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 838aaf2..5879e2f 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -54,9 +54,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/host_state_manager.cpp b/host_state_manager.cpp
+index ec1f95f..8573d00 100644
+--- a/host_state_manager.cpp
++++ b/host_state_manager.cpp
+@@ -304,6 +304,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",
+@@ -349,6 +358,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
+ } // namepsace 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.17.0
+
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..92f5e530c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend
@@ -0,0 +1,8 @@
+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 \
+ "
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..d0fdce645
--- /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-amr-2.devtools.intel.com:29418/openbmc-provingground;protocol=ssh"
+
+inherit cmake systemd
+DEPENDS = "boost sdbusplus"
+
+PV = "0.1+git${SRCPV}"
+SRCREV = "3cc86d6c536b4c5ee7afb5447837b83ce8b3d149"
+
+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/system/obmc-mgr-system%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/system/obmc-mgr-system%.bbappend
new file mode 100644
index 000000000..37bb8f961
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/system/obmc-mgr-system%.bbappend
@@ -0,0 +1,2 @@
+SYSTEMD_AUTO_ENABLE = "enable"
+
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..332933a28
--- /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 4762913cfbd45234ddb363a5ec130eb56a8c7af0 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 | 295 +++------------------
+ user_mgr.hpp | 9 +-
+ user_service.cpp | 781 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ user_service.hpp | 233 +++++++++++++++++
+ 6 files changed, 1141 insertions(+), 271 deletions(-)
+ create mode 100644 user_service.cpp
+ create mode 100644 user_service.hpp
+
+diff --git a/Makefile.am b/Makefile.am
+index 4413b84..e4310d4 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,12 +1,13 @@
+ sbin_PROGRAMS = phosphor-user-manager
+
+-noinst_HEADERS = user.hpp user_mgr.hpp users.hpp
++noinst_HEADERS = user.hpp user_mgr.hpp users.hpp user_service.hpp
+
+ phosphor_user_manager_SOURCES = \
+ user.cpp \
+ 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 786a8fd..51193cc 100644
+--- a/user_mgr.cpp
++++ b/user_mgr.cpp
+@@ -14,26 +14,18 @@
+ // 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 +35,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;
+@@ -83,79 +73,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())
+@@ -282,39 +199,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);
++ // Tell the User Service to create a new user with the info provided.
++ userSrvc->createUser(userName, groupNames, priv, enabled);
+
+- // 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>();
+- }
+-
+- // 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(
+@@ -328,19 +220,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);
+
+@@ -351,24 +235,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();
+@@ -392,8 +265,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();
+@@ -409,29 +280,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()));
+@@ -627,19 +477,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()),
+@@ -730,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()
+@@ -783,60 +582,23 @@ 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));
+ }
+
+ 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())
+ {
+@@ -891,8 +653,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());
+@@ -1000,6 +764,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 c1673f1..169f121 100644
+--- a/user_mgr.hpp
++++ b/user_mgr.hpp
+@@ -20,6 +20,7 @@
+ #include <xyz/openbmc_project/User/AccountPolicy/server.hpp>
+ #include <unordered_map>
+ #include "users.hpp"
++#include "user_service.hpp"
+
+ namespace phosphor
+ {
+@@ -27,8 +28,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;
+
+@@ -49,8 +48,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
+@@ -148,6 +149,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..4a8952235
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend
@@ -0,0 +1,5 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+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/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_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend
new file mode 100644
index 000000000..d1888e86f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend
@@ -0,0 +1,4 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+
+# 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..a584c473c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/0001-Implement-KVM-in-webui.patch
@@ -0,0 +1,242 @@
+From a129c4e92eebd03772e5f68a2fcf855e00874f19 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 | 5 +-
+ webpack.config.js | 6 ++-
+ 10 files changed, 98 insertions(+), 8 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 2f3ded76cad2..f8b5db742acc 100644
+--- a/app/common/directives/app-navigation.html
++++ b/app/common/directives/app-navigation.html
+@@ -85,19 +85,21 @@
+ <a href="#/server-control/bmc-reboot" tabindex="12" ng-click="closeSubnav()">Reboot BMC</a></li>
+ <li ng-class="{'active': (path == '/server-control/remote-console')}">
+ <a href="#/server-control/remote-console" tabindex="13" ng-click="closeSubnav()">Serial over LAN console</a></li>
++ <li ng-class="{'active': (path == '/server-control/kvm')}">
++ <a href="#/server-control/kvm" tabindex="14" 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="14" ng-click="closeSubnav()">Network settings</a></li>
++ <a href="#/configuration/network" tabindex="15" ng-click="closeSubnav()">Network settings</a></li>
+ <li ng-class="{'active': (path == '/configuration' || path == '/configuration/snmp')}">
+- <a href="#/configuration/snmp" tabindex="15" ng-click="closeSubnav()">SNMP settings</a></li>
++ <a href="#/configuration/snmp" tabindex="16" ng-click="closeSubnav()">SNMP settings</a></li>
+ <li ng-class="{'active': (path == '/configuration' || path == '/configuration/firmware')}">
+- <a href="#/configuration/firmware" tabindex="16" ng-click="closeSubnav()">Firmware</a></li>
++ <a href="#/configuration/firmware" tabindex="17" ng-click="closeSubnav()">Firmware</a></li>
+ <li ng-class="{'active': (path == '/configuration' || path == '/configuration/date-time')}">
+- <a href="#/configuration/date-time" tabindex="17" ng-click="closeSubnav()">Date and time settings</a></li>
++ <a href="#/configuration/date-time" tabindex="18" 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="18" ng-click="closeSubnav()">Manage user accounts</a></li>
++ <a href="#/users/manage-accounts" tabindex="19" ng-click="closeSubnav()">Manage user account</a></li>
+ </ul>
+ </nav>
+diff --git a/app/index.js b/app/index.js
+index c9fed83fe4a9..d6b4a08fa5c6 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..c0125a0b72fd 100644
+--- a/package.json
++++ b/package.json
+@@ -28,8 +28,9 @@
+ "node"
+ ],
+ "dependencies": {
+- "angular": "^1.7.5",
+- "angular-animate": "^1.7.5",
++ "@novnc/novnc": "^1.0.0",
++ "angular": "^1.7.3",
++ "angular-animate": "^1.7.3",
+ "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_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend
new file mode 100644
index 000000000..e40b5ed8e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend
@@ -0,0 +1,3 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+
+SRC_URI += "file://0001-Implement-KVM-in-webui.patch"
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/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..dc3f9846d
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/0001-Create-intel-purley-dts.patch
@@ -0,0 +1,389 @@
+From 939070905b0d6d70b2e39d424e0797451efdedf8 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
+
+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 | 347 ++++++++++++++++++++++++++
+ 1 file changed, 347 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..8a18645e6316
+--- /dev/null
++++ b/arch/arm/boot/dts/aspeed-bmc-intel-purley.dts
+@@ -0,0 +1,347 @@
++/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>;
++ };
++
++ safs_memory: region@30000000 {
++ no-map;
++ reg = <0x30000000 0x08000000>; /* 128M */
++ };
++
++ 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 {
++ gpios = <&gpio ASPEED_GPIO(S, 6) GPIO_ACTIVE_LOW>;
++ };
++
++ status_amber {
++ gpios = <&gpio ASPEED_GPIO(S, 5) GPIO_ACTIVE_LOW>;
++ };
++
++ status_green {
++ gpios = <&gpio ASPEED_GPIO(S, 4) GPIO_ACTIVE_LOW>;
++ };
++ };
++
++ 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";
++ * };
++ *};
++ */
++
++&lpc_ctrl {
++ status = "okay";
++ memory-region = <&safs_memory>;
++ flash = <&spi1>;
++};
++
++&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 {
++ status = "okay";
++};
++
++&i2c2 {
++ 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 {
++ status = "okay";
++};
++
++&i2c7 {
++ multi-master;
++ status = "okay";
++
++ smlink1-pmbus1@10 {
++ compatible = "slave-mqueue";
++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>;
++ };
++};
++
++&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..9549d4d7b
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-kernel/linux/linux-aspeed/wolfpass.cfg
@@ -0,0 +1,60 @@
+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_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
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/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..d9fe8e10f
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/configuration/entity-manager_%.bbappend
@@ -0,0 +1,10 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+SRC_URI_append = " file://WC-Baseboard.json \
+ file://WP-Baseboard.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/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..b619dac8b
--- /dev/null
+++ b/meta-openbmc-mods/meta-wolfpass/recipes-phosphor/fru/default-fru/checkFru.sh
@@ -0,0 +1,35 @@
+#!/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)
+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 == 30)); then
+ cat S2600WP.fru.bin > $fruFile
+# wc
+elif (($result == 13)); then
+ cat S2600WC.fru.bin > $fruFile
+# cyp
+elif (($result == 28)); then
+ cat S2600CYP.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..ead62f47e
--- /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-amr-1.devtools.intel.com:29418/openbmc-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