summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common')
-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_intel_pfr.bbclass125
-rw-r--r--meta-openbmc-mods/meta-common/classes/image_types_phosphor_auto.bbclass79
-rw-r--r--meta-openbmc-mods/meta-common/classes/obmc-phosphor-full-fitimage.bbclass532
-rw-r--r--meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass56
-rw-r--r--meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-dev.bbclass7
-rw-r--r--meta-openbmc-mods/meta-common/classes/systemd-watchdog.bbclass35
-rw-r--r--meta-openbmc-mods/meta-common/conf/layer.conf11
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/fw_env.config25
-rw-r--r--meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-%.bbappend5
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.service10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.sh8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check_git.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug_git.bb33
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/crashdump/files/com.intel.crashdump.service10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/dropbear/dropbear_%.bbappend22
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-core/dropbear/files/enable-ssh.sh15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh366
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl136
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb30
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_%.bbappend3
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/.clang-format21
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0001-Smbus-changes-for-libmctp.patch119
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/CMakeLists.txt27
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.c93
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.h16
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/libmctp-smbus.h31
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/smbus.c467
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb42
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend5
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check.bb26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.service9
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.sh16
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/libpeci/libpeci_%.bbappend3
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/libxcrypt/libxcrypt_%.bbappend5
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd.inc43
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/avoid_parallel_tests.patch20
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/configure-sbindir.patch23
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/display_testname_for_subtest.patch25
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/ptest.patch23
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/run-ptest43
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser-l.pamd3
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser.pamd4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd_2.34.bb12
-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-sync/nv-sync/nv-sync.service11
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync_git.bb20
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend34
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/os-release/version-vars.inc78
-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/safec/safec_%.bbappend11
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/safec/safec_3.4.bb15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check.bb26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.service10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.sh42
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/obmc-targets.bbappend10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf42
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf_%.bbappend11
-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/0002-Disable-LLMNR-port-5355.patch26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/systemd-time-wait-sync.service36
-rw-r--r--meta-openbmc-mods/meta-common/recipes-core/systemd/systemd_%.bbappend16
-rw-r--r--meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb21
-rw-r--r--meta-openbmc-mods/meta-common/recipes-devtools/python/python_%.bbappend7
-rw-r--r--meta-openbmc-mods/meta-common/recipes-devtools/template-recipe/template-recipe.bb18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/pam/pam-ipmi_%.bbappend7
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow/pam.d/login90
-rw-r--r--meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow_%.bbappend4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend5
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch162
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/host-misc-comm-manager/host-misc-comm-manager_git.bb19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb21
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/images/intel-platforms.bb18
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py385
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/bmc_config.xml48
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/csk_prv.pem8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/csk_pub.pem4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/pfm_config.xml48
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/pfr_manifest.json196
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/rk_prv.pem8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/rk_pub.pem4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-blocksign-native.bb20
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-pfr-manager_git.bb22
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/obmc-intel-pfr-image-native.bb37
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.service11
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.sh14
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb38
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-intel/psu-manager/psu-manager.bb26
-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.bb28
-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/0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch500
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2600-platforms.patch537
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-base-aspeed-g6-dtsi-fixups.patch212
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Add-Aspeed-fmc-spi-driver.patch645
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch173
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch70
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch30
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch123
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-aspeed-pwm-tacho-change-default-fan-speed.patch28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0014-arm-dts-aspeed-g5-add-espi.patch31
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0015-New-flash-map-for-intel.patch117
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0016-Add-ASPEED-SGPIO-driver.patch760
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0017-SGPIO-DT-and-pinctrl-fixup.patch227
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0019-Add-I2C-IPMB-support.patch425
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0020-misc-aspeed-add-lpc-mbox-driver.patch491
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch580
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch762
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch95
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0030-Add-dump-debug-code-into-I2C-drivers.patch145
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0031-Add-high-speed-baud-rate-support-for-UART.patch135
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0032-misc-aspeed-Add-Aspeed-UART-routing-control-driver.patch559
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-aspeed-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.patch245
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch514
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0040-i2c-Add-mux-hold-unhold-msg-types.patch488
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch105
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch154
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch139
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch273
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch43
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0049-Suppress-excessive-HID-gadget-error-logs.patch52
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch67
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch920
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch1466
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0054-Documentation-jtag-Add-bindings-for-Aspeed-SoC.patch107
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch310
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch57
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch50
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-i2c-aspeed-add-buffer-mode-transfer-support.patch1148
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-i2c-aspeed-add-DMA-mode-transfer-support.patch491
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch180
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0064-set-idle-disconnect-to-true-in-all-cases.patch34
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch191
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch50
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0072-pmbus-add-fault-and-beep-attributes.patch88
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch155
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0075-Refine-initialization-flow-in-I2C-driver.patch64
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0076-arm-ast2600-add-pwm_tacho-driver-from-aspeed.patch1107
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0077-soc-aspeed-Add-read-only-property-support.patch47
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0078-Fix-NCSI-driver-issue-caused-by-host-shutdown.patch70
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0080-i2c-aspeed-filter-garbage-interrupts-out.patch56
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0084-ARM-dts-aspeed-g6-add-GFX-node.patch35
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0085-drm-add-AST2600-GFX-support.patch105
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch271
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ARM-dts-aspeed-g6-add-video-node.patch36
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0087-media-aspeed-add-aspeed-ast2600-video-engine-compati.patch63
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0088-clk-ast2600-enable-ESPICLK-always.patch30
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0089-ast2600-enable-high-speed-uart-in-kernel.patch97
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0090-peci-cpupower-driver-1.patch405
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0092-SPI-Quad-IO-driver-support-AST2600.patch136
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0093-ipmi-ipmb_dev_int-add-quick-fix-for-raw-I2C-type-reg.patch37
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0094-Return-link-speed-and-duplex-settings-for-the-NCSI-c.patch57
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0095-pwm-and-tach-driver-changes-for-ast2600.patch783
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0096-Fix-truncated-WrEndPointConfig-MMIO-command.patch40
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0100-Mailbox-Enabling-interrupt-based-mailbox.patch237
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0101-Add-poll-fops-in-eSPI-driver.patch151
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0102-Fix-for-dirty-node-in-jffs2-summary-entry.patch94
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0103-Refine-clock-settings.patch191
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0104-Add-chip-unique-id-reading-interface.patch213
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/debug.cfg2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg89
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend81
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch412
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch504
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0011-Added-enable-disable-control-of-the-Network-Interfac.patch189
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check79
-rw-r--r--meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service11
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb25
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format98
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt39
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp325
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend6
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format98
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt40
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp265
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/datetime/phosphor-time-manager_git.bbappend2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0001-Reapply-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-e.patch47
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch65
-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/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/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch57
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch39
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch55
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend15
-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.service14
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch41
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch188
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch76
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch438
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch408
-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_%.bbappend19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb30
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt7
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service9
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh76
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp219
-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/0001-Firmware-update-support-for-StandBySpare.patch462
-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_%.bbappend27
-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.json76
-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/.clang-format99
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Modify-Get-Lan-Configuration-IP-Address-Source-to-us.patch231
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0010-fix-get-system-GUID-ipmi-command.patch41
-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/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch105
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch356
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch259
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch291
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch140
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp147
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend44
-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/99-ipmi-kcs.rules2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend21
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch40
-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/0009-Add-dbus-interface-for-sol-commands.patch319
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch336
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend26
-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/id-led-off/id-led-off.service11
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config-native.bb21
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml48
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-manager/multi-node-manager.bb17
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb27
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service9
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh23
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb16
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb32
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend3
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init258
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb18
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend4
-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_%.bbappend9
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb20
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb31
-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_%.bbappend5
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb34
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/system/callback-manager.bb19
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch1655
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch76
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend11
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb24
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog.bb35
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format98
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt52
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json12
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp258
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch336
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service16
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend9
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb24
-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/watchdog/system-watchdog/watchdog-clear-failures.service10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.timer8
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.service7
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.sh13
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json9
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend4
-rw-r--r--meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf16
-rw-r--r--meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service15
-rw-r--r--meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-support/boost/boost/0001-Fix-Issue-62.patch28
-rw-r--r--meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend3
-rw-r--r--meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/default1
-rw-r--r--meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/init42
-rw-r--r--meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/rngd.service10
-rw-r--r--meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools_6.7.bb52
-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.c696
-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.c528
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h79
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/lpc-cmds.bb16
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit/0001-Force-nbdkit-to-send-PATCH-as-upload-method.patch71
-rw-r--r--meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit_git.bb35
-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
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend3
342 files changed, 36946 insertions, 0 deletions
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_intel_pfr.bbclass b/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass
new file mode 100644
index 000000000..505391669
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/classes/image_types_intel_pfr.bbclass
@@ -0,0 +1,125 @@
+
+
+inherit obmc-phosphor-full-fitimage
+inherit image_types_phosphor_auto
+DEPENDS += "obmc-intel-pfr-image-native python3-native intel-blocksign-native"
+
+require recipes-core/os-release/version-vars.inc
+
+IMAGE_TYPES += "intel-pfr"
+
+IMAGE_TYPEDEP_intel-pfr = "mtd-auto"
+IMAGE_TYPES_MASKED += "intel-pfr"
+
+# PFR images directory
+PFR_IMAGES_DIR = "${DEPLOY_DIR_IMAGE}/pfr_images"
+
+# PFR image generation script directory
+PFR_SCRIPT_DIR = "${STAGING_DIR_NATIVE}${bindir}"
+
+# PFR image config directory
+PFR_CFG_DIR = "${STAGING_DIR_NATIVE}${datadir}/pfrconfig"
+
+# Refer flash map in manifest.json for the addresses offset
+PFM_OFFSET = "0x80000"
+
+# 0x80000/1024 = 0x200 or 512, 1K Page size.
+PFM_OFFSET_PAGE = "512"
+
+# RC_IMAGE
+RC_IMAGE_OFFSET = "0x02a00000"
+
+# RC_IMAGE_PAGE= 0x02a00000/1024 = 0xA800 or 43008
+RC_IMAGE_PAGE = "43008"
+
+do_image_pfr () {
+ bbplain "Generating Intel PFR compliant BMC image"
+
+ bbplain "Build Version = ${build_version}"
+ bbplain "Build Number = ${build_number}"
+ bbplain "Build Hash = ${build_hash}"
+
+ mkdir -p "${PFR_IMAGES_DIR}"
+ cd "${PFR_IMAGES_DIR}"
+
+ # python script that does the creating PFM, BMC compressed and unsigned images from BMC 128MB raw binary file.
+ ${PFR_SCRIPT_DIR}/pfr_image.py ${PFR_CFG_DIR}/pfr_manifest.json ${DEPLOY_DIR_IMAGE}/image-mtd ${build_version} ${build_number} ${build_hash} ${SHA}
+
+ # sign the PFM region
+ ${PFR_SCRIPT_DIR}/blocksign -c ${PFR_CFG_DIR}/pfm_config.xml -o ${PFR_IMAGES_DIR}/pfm_signed.bin ${PFR_IMAGES_DIR}/pfm.bin -v
+
+ # Add the signed PFM to rom image
+ dd bs=1k conv=notrunc seek=${PFM_OFFSET_PAGE} if=${PFR_IMAGES_DIR}/pfm_signed.bin of=${PFR_IMAGES_DIR}/image-mtd-pfr
+
+ # Create unsigned BMC update capsule - append with 1. pfm_signed, 2. pbc, 3. bmc compressed
+ dd if=${PFR_IMAGES_DIR}/pfm_signed.bin bs=1k >> ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin
+
+ dd if=${PFR_IMAGES_DIR}/pbc.bin bs=1k >> ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin
+
+ dd if=${PFR_IMAGES_DIR}/bmc_compressed.bin bs=1k >> ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin
+
+ # Sign the BMC update capsule
+ ${PFR_SCRIPT_DIR}/blocksign -c ${PFR_CFG_DIR}/bmc_config.xml -o ${PFR_IMAGES_DIR}/bmc_signed_cap.bin ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin -v
+
+ # Add the signed bmc update capsule to full rom image @ 0x2a00000
+ dd bs=1k conv=notrunc seek=${RC_IMAGE_PAGE} if=${PFR_IMAGES_DIR}/bmc_signed_cap.bin of=${PFR_IMAGES_DIR}/image-mtd-pfr
+
+ # Append date and time to all the PFR images
+ mv ${PFR_IMAGES_DIR}/pfm_signed.bin ${PFR_IMAGES_DIR}/pfm_signed-${DATETIME}.bin
+ mv ${PFR_IMAGES_DIR}/pfm.bin ${PFR_IMAGES_DIR}/pfm-${DATETIME}.bin
+ mv ${PFR_IMAGES_DIR}/pbc.bin ${PFR_IMAGES_DIR}/pbc-${DATETIME}.bin
+ mv ${PFR_IMAGES_DIR}/bmc_compressed.bin ${PFR_IMAGES_DIR}/bmc_compressed-${DATETIME}.bin
+ mv ${PFR_IMAGES_DIR}/bmc_unsigned_cap.bin ${PFR_IMAGES_DIR}/bmc_unsigned_cap-${DATETIME}.bin
+ mv ${PFR_IMAGES_DIR}/bmc_signed_cap.bin ${PFR_IMAGES_DIR}/bmc_signed_cap-${DATETIME}.bin
+ mv ${PFR_IMAGES_DIR}/image-mtd-pfr ${PFR_IMAGES_DIR}/image-mtd-pfr-${DATETIME}.bin
+}
+
+do_image_pfr[vardepsexclude] += "DATE DATETIME"
+do_image_pfr[vardeps] += "IPMI_MAJOR IPMI_MINOR IPMI_AUX13 IPMI_AUX14 IPMI_AUX15 IPMI_AUX16"
+do_image_pfr[depends] += " \
+ obmc-intel-pfr-image-native:do_populate_sysroot \
+ intel-blocksign-native:do_populate_sysroot \
+ "
+
+python() {
+ product_gen = d.getVar('PRODUCT_GENERATION', True)
+ if product_gen == "wht":
+ d.setVar('SHA', "1")# 1- SHA256
+
+ types = d.getVar('IMAGE_FSTYPES', True).split()
+
+ if 'intel-pfr' in types:
+
+ bld_ver1 = d.getVar('IPMI_MAJOR', True)
+ bld_ver1 = int(bld_ver1) << 8
+
+ bld_ver2 = d.getVar('IPMI_MINOR', True)
+ bld_ver2 = int(bld_ver2)
+
+ bld_ver = bld_ver1 | bld_ver2
+ d.setVar('build_version', str(bld_ver))
+
+ bld_num = d.getVar('IPMI_AUX13', True)
+
+ d.setVar('build_number', bld_num)
+
+ bld_hash1 = d.getVar('IPMI_AUX14', True)
+ bld_hash2 = d.getVar('IPMI_AUX15', True)
+ bld_hash3 = d.getVar('IPMI_AUX16', True)
+
+ bld_hash1 = int(bld_hash1, 16)
+ bld_hash2 = int(bld_hash2, 16)
+ bld_hash3 = int(bld_hash3, 16)
+
+ bld_hash = bld_hash3 << 16
+ bld_hash |= bld_hash2 << 8
+ bld_hash |= bld_hash1
+
+ d.setVar('build_hash', str(bld_hash))
+
+ bb.build.addtask(# task, depends_on_task, task_depends_on, d )
+ 'do_image_pfr',
+ 'do_build',
+ 'do_generate_auto', d)
+}
+
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..f90a19c4b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/classes/image_types_phosphor_auto.bbclass
@@ -0,0 +1,79 @@
+# 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() {
+ types = d.getVar('IMAGE_FSTYPES', True).split()
+
+ # TODO: find partition list in DTS
+ d.setVar('FLASH_UBOOT_OFFSET', str(0))
+ if 'intel-pfr' in types:
+ d.setVar('FLASH_SIZE', str(128*1024))
+ DTB_FULL_FIT_IMAGE_OFFSETS = [0xb00000]
+ else:
+ d.setVar('FLASH_SIZE', str(64*1024))
+ DTB_FULL_FIT_IMAGE_OFFSETS = [0x80000, 0x2480000]
+
+ 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_TYPES=${IMAGE_TYPES} 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..26c895951
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-full-fitimage.bbclass
@@ -0,0 +1,532 @@
+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 "
+
+# 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')
+}
+
+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
+
+ tar -h -cvf "${DEPLOY_DIR_IMAGE}/${PN}-image-update-${MACHINE}-${DATETIME}.tar" MANIFEST image-u-boot image-runtime image-kernel image-rofs image-rwfs
+ # 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..ceee7f0fc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/classes/obmc-phosphor-image-common.bbclass
@@ -0,0 +1,56 @@
+inherit obmc-phosphor-image
+inherit systemd-watchdog
+
+IMAGE_INSTALL_append = " \
+ bmcweb \
+ dbus-broker \
+ entity-manager \
+ ipmitool \
+ intel-ipmi-oem \
+ phosphor-ipmi-ipmb \
+ phosphor-node-manager-proxy \
+ dbus-sensors \
+ phosphor-webui \
+ at-scale-debug \
+ phosphor-pid-control \
+ phosphor-host-postd \
+ phosphor-certificate-manager \
+ phosphor-sel-logger \
+ smbios-mdrv2 \
+ obmc-ikvm \
+ system-watchdog \
+ frb2-watchdog \
+ srvcfg-manager \
+ callback-manager \
+ post-code-manager \
+ preinit-mounts \
+ mtd-utils-ubifs \
+ special-mode-mgr \
+ rsyslog \
+ static-mac-addr \
+ phosphor-u-boot-mgr \
+ prov-mode-mgr \
+ ac-boot-check \
+ host-error-monitor \
+ beepcode-mgr \
+ psu-manager \
+ kernel-panic-check \
+ id-led-off \
+ hsbp-manager \
+ security-registers-check \
+ pch-time-sync \
+ nv-sync \
+ security-manager \
+ multi-node-nl \
+ mctpd \
+ virtual-media \
+ enable-nics \
+ host-misc-comm-manager \
+ "
+
+IMAGE_INSTALL_append = "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'intel-pfr-manager', '', d)}"
+
+# this package was flagged as a security risk
+IMAGE_INSTALL_remove += " lrzsz"
+
+BAD_RECOMMENDATIONS += "phosphor-settings-manager"
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/classes/systemd-watchdog.bbclass b/meta-openbmc-mods/meta-common/classes/systemd-watchdog.bbclass
new file mode 100644
index 000000000..66fecb8a9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/classes/systemd-watchdog.bbclass
@@ -0,0 +1,35 @@
+add_watchdog_confs() {
+
+ interval=10 # minutes
+ count=5 # allowed reboots
+
+ for service in $(ls $D/lib/systemd/system | grep -o ".*service"); do
+ if [[ "$service" == *"mapper-wait"* ]]; then
+ continue
+ fi
+
+ if [ "$service" = "system-watchdog.service" ]; then
+ continue
+ fi
+
+ if [ "$service" = "systemd-coredump@.service" ]; then
+ continue
+ fi
+
+ if cat $D/lib/systemd/system/${service} | grep oneshot > /dev/null; then
+ continue
+ fi
+
+ folder="$D/etc/systemd/system/${service}.d"
+ mkdir -p "${folder}"
+ fname="${folder}/watchdog.conf"
+ echo "[Unit]" > ${fname}
+ echo "OnFailure=watchdog-reset.service" >> ${fname}
+ echo "[Service]" >> "${fname}"
+ echo "StartLimitInterval=${interval}min" >> "${fname}"
+ echo "StartLimitBurst=${count}" >> "${fname}"
+ done
+
+}
+
+ROOTFS_POSTINSTALL_COMMAND += "add_watchdog_confs"
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..4c640e868
--- /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 = "warrior zeus"
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/fw_env.config b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/fw_env.config
new file mode 100644
index 000000000..19ace4b88
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/fw_env.config
@@ -0,0 +1,25 @@
+# Configuration file for fw_(printenv/setenv) utility.
+# Up to two entries are valid, in this case the redundant
+# environment sector is assumed present.
+# Notice, that the "Number of sectors" is ignored on NOR and SPI-dataflash.
+# Furthermore, if the Flash sector size is omitted, this value is assumed to
+# be the same as the Environment size, which is valid for NOR and SPI-dataflash
+
+# NOR example
+# MTD device name Device offset Env. size Flash sector size Number of sectors
+#/dev/mtd1 0x0000 0x20000 0x20000
+#/dev/mtd2 0x0000 0x4000 0x4000
+
+# MTD SPI-dataflash example
+# MTD device name Device offset Env. size Flash sector size Number of sectors
+#/dev/mtd2 0x00000 0x20000
+/dev/mtd/u-boot-env 0x00000 0x10000
+/dev/mtd/u-boot-env 0x10000 0x10000
+#/dev/mtd5 0x4200 0x4200
+#/dev/mtd6 0x4200 0x4200
+
+# NAND example
+#/dev/mtd0 0x4000 0x4000 0x20000 2
+
+# Block device example
+#/dev/mmcblk0 0xc0000 0x20000
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-%.bbappend b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-%.bbappend
new file mode 100644
index 000000000..eee5194fb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/u-boot-%.bbappend
@@ -0,0 +1,5 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
+
+SRC_URI += " \
+ file://fw_env.config \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.service b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.service
new file mode 100644
index 000000000..e8b563850
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Check for AC boot
+After=xyz.openbmc_project.Settings.service
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/ac-boot-check.sh
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.sh b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.sh
new file mode 100644
index 000000000..38728b512
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check/ac-boot-check.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if [[ `cat /proc/cmdline` =~ "resetreason=0x11" ]]
+then
+ busctl set-property xyz.openbmc_project.Settings /xyz/openbmc_project/control/host0/ac_boot xyz.openbmc_project.Common.ACBoot ACBoot s "True"
+else
+ busctl set-property xyz.openbmc_project.Settings /xyz/openbmc_project/control/host0/ac_boot xyz.openbmc_project.Common.ACBoot ACBoot s "False"
+fi
diff --git a/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check_git.bb b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check_git.bb
new file mode 100644
index 000000000..2a30696dc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/ac-boot-check/ac-boot-check_git.bb
@@ -0,0 +1,24 @@
+SUMMARY = "AC Boot Check"
+DESCRIPTION = "Script to check the resetreason for AC boot"
+
+S = "${WORKDIR}"
+SRC_URI = "file://ac-boot-check.sh \
+ file://ac-boot-check.service \
+"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+RDEPENDS_${PN} += "bash"
+
+inherit systemd
+
+FILES_${PN} += "${systemd_system_unitdir}/ac-boot-check.service"
+
+do_install() {
+ install -d ${D}${systemd_system_unitdir}
+ install -m 0644 ${WORKDIR}/ac-boot-check.service ${D}${systemd_system_unitdir}
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/ac-boot-check.sh ${D}/${bindir}/ac-boot-check.sh
+}
+
+SYSTEMD_SERVICE_${PN} += " ac-boot-check.service"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug_git.bb b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug_git.bb
new file mode 100644
index 000000000..6e3e0c4de
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/at-scale-debug_git.bb
@@ -0,0 +1,33 @@
+inherit obmc-phosphor-systemd
+
+SUMMARY = "At Scale Debug Service"
+DESCRIPTION = "At Scale Debug Service exposes remote JTAG target debug capabilities"
+
+LICENSE = "BSD"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=0d1c657b2ba1e8877940a8d1614ec560"
+
+
+inherit cmake
+DEPENDS = "sdbusplus openssl libpam libgpiod safec"
+
+do_configure[depends] += "virtual/kernel:do_shared_workdir"
+
+SRC_URI = "git://github.com/Intel-BMC/asd;protocol=git"
+SRCREV = "1.4.3"
+
+inherit useradd
+
+USERADD_PACKAGES = "${PN}"
+
+# add a special user asdbg
+USERADD_PARAM_${PN} = "-u 999 asdbg"
+
+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/uapi"
+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..4411de11c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebug.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Intel BMC At Scale Debug
+Requires=network-online.target
+
+[Service]
+Restart=always
+RestartSec=30
+ExecStart={bindir}/asd
+Type=simple
+SyslogIdentifier=asd
+
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service
new file mode 100644
index 000000000..281d1a993
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/at-scale-debug/files/com.intel.AtScaleDebugJtagTest.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Intel BMC At Scale Debug JTAG test to check if remote debug setting is enabled
+
+[Service]
+Type=oneshot
+ExecStartPre=/bin/sleep 10
+ExecStart={bindir}/jtag_test
+SyslogIdentifier=jtag_test
+RemainAfterExit=true
+
+[Install]
+WantedBy=obmc-host-start@0.target
diff --git a/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab
new file mode 100644
index 000000000..0b53093ae
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files/fstab
@@ -0,0 +1,10 @@
+/dev/root / auto defaults 1 1
+proc /proc proc defaults 0 0
+devpts /dev/pts devpts mode=0620,gid=5 0 0
+tmpfs /run tmpfs mode=0755,nodev,nosuid,strictatime 0 0
+tmpfs /var/lib/systemd/coredump tmpfs rw,nosuid,nodev,size=67108864 0 0
+tmpfs /media tmpfs rw 0 0
+
+# uncomment this if your device has a SD/MMC/Transflash slot
+#/dev/mmcblk0p1 /media/card auto defaults,sync,noauto 0 0
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend
new file mode 100644
index 000000000..79e529179
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/base-files/base-files_%.bbappend
@@ -0,0 +1,2 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+SRC_URI_append = " file://fstab"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb b/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb
new file mode 100644
index 000000000..b80282743
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/crashdump/crashdump_git.bb
@@ -0,0 +1,28 @@
+inherit obmc-phosphor-dbus-service
+inherit obmc-phosphor-systemd
+
+SUMMARY = "CPU Crashdump"
+DESCRIPTION = "CPU utilities for dumping CPU Crashdump and registers over PECI"
+
+DEPENDS = "boost cjson sdbusplus safec gtest libpeci"
+inherit cmake
+
+EXTRA_OECMAKE = "-DCRASHDUMP_BUILD_UT=ON"
+
+LICENSE = "Proprietary"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=43c09494f6b77f344027eea0a1c22830"
+
+SRC_URI = "git://github.com/Intel-BMC/crashdump;protocol=git"
+SRCREV = "0.5"
+
+S = "${WORKDIR}/git"
+
+SYSTEMD_SERVICE_${PN} += "com.intel.crashdump.service"
+DBUS_SERVICE_${PN} += "com.intel.crashdump.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/crashdump/files/com.intel.crashdump.service b/meta-openbmc-mods/meta-common/recipes-core/crashdump/files/com.intel.crashdump.service
new file mode 100644
index 000000000..6f79573f0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/crashdump/files/com.intel.crashdump.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Intel BMC CPU Crashdump
+
+[Service]
+Restart=always
+ExecStart={bindir}/crashdump
+Type=simple
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-core/dropbear/dropbear_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/dropbear/dropbear_%.bbappend
new file mode 100644
index 000000000..cfa1d0711
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/dropbear/dropbear_%.bbappend
@@ -0,0 +1,22 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
+
+SRC_URI += "file://enable-ssh.sh"
+
+add_manual_ssh_enable() {
+ install -d ${D}/usr/share/misc
+ install -m 0755 ${D}/${systemd_unitdir}/system/dropbear@.service ${D}/usr/share/misc/dropbear@.service
+ install -m 0755 ${D}/${systemd_unitdir}/system/dropbear.socket ${D}/usr/share/misc/dropbear.socket
+ install -m 0755 ${WORKDIR}/enable-ssh.sh ${D}${bindir}/enable-ssh.sh
+ # Remove dropbear service and socket by default, if debug-tweaks is disabled
+ rm ${D}/${systemd_unitdir}/system/dropbear@.service
+ rm ${D}/${systemd_unitdir}/system/dropbear.socket
+}
+
+do_install_append() {
+ # Add manual ssh enable script if debug-tweaks is disabled
+ ${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '', 'add_manual_ssh_enable', d)}
+}
+
+FILES_${PN} += "/usr/share/misc"
+SYSTEMD_SERVICE_${PN} += "dropbearkey.service"
+SYSTEMD_SERVICE_${PN}_remove += " ${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '', 'dropbear.socket', d)}"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/dropbear/files/enable-ssh.sh b/meta-openbmc-mods/meta-common/recipes-core/dropbear/files/enable-ssh.sh
new file mode 100755
index 000000000..e97995cc1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/dropbear/files/enable-ssh.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+if [ -e /etc/systemd/system/dropbear@.service ] && \
+ [ -e /etc/systemd/system/sockets.target.wants/dropbear.socket ]
+then
+ echo "SSH is already enabled"
+else
+ cp /usr/share/misc/dropbear@.service /etc/systemd/system/dropbear@.service
+ cp /usr/share/misc/dropbear.socket /etc/systemd/system/dropbear.socket
+ ln -s /etc/systemd/system/dropbear.socket /etc/systemd/system/sockets.target.wants/dropbear.socket
+ groupmems -g priv-admin -a root
+ systemctl daemon-reload
+ systemctl restart dropbear.socket
+ echo "Enabled SSH service for root user successful"
+fi
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..917e7ab09
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/fwupd.sh
@@ -0,0 +1,366 @@
+#!/bin/sh
+
+log() {
+ echo "$@"
+}
+
+FWTYPE=""
+FWVER=""
+redfish_log_fw_evt() {
+ local evt=$1
+ local sev=""
+ local msg=""
+ [ -z "$FWTYPE" ] && return
+ [ -z "$FWVER" ] && return
+ case "$evt" in
+ start)
+ evt=OpenBMC.0.1.FirmwareUpdateStarted
+ msg="${FWTYPE} firmware update to version ${FWVER} started."
+ sev=OK
+ ;;
+ success)
+ evt=OpenBMC.0.1.FirmwareUpdateCompleted
+ msg="${FWTYPE} firmware update to version ${FWVER} completed successfully."
+ sev=OK
+ ;;
+ abort)
+ evt=OpenBMC.0.1.FirmwareUpdateFailed
+ msg="${FWTYPE} firmware update to version ${FWVER} failed."
+ sev=Warning
+ ;;
+ *) return ;;
+ esac
+ logger-systemd --journald <<-EOF
+ MESSAGE=$msg
+ PRIORITY=2
+ SEVERITY=${sev}
+ REDFISH_MESSAGE_ID=${evt}
+ REDFISH_MESSAGE_ARGS=${FWTYPE},${FWVER}
+ EOF
+}
+
+wait_for_log_sync()
+{
+ sync
+ sleep 5
+}
+
+PFR_BUS=4
+PFR_ADDR=0x38
+PFR_ID_REG=0x00
+PFR_STATE_REG=0x03
+PFR_PROV_REG=0x0a
+PFR_INTENT_REG=0x13
+pfr_read() {
+ [ $# -ne 1 ] && return 1
+ local reg=$1
+ i2cget -y $PFR_BUS $PFR_ADDR $reg 2>/dev/null
+}
+
+pfr_write() {
+ [ $# -ne 2 ] && return 1
+ local reg=$1
+ local val=$2
+ i2cset -y $PFR_BUS $PFR_ADDR $reg $val >&/dev/null
+}
+
+pfr_active_update() {
+ local factory_reset=""
+ local recovery_offset=0x2a00000
+ systemctl stop nv-sync.service || \
+ log "BMC NV sync failed to stop"
+ # transition from non-PFR to PFR image requires factory reset
+ if [ ! -e /usr/share/pfr ]; then
+ factory_reset="-r"
+ mtd-util pfr stage $LOCAL_PATH $recovery_offset
+ fi
+ mtd-util $factory_reset pfr write $LOCAL_PATH
+ redfish_log_fw_evt success
+ # only wait for logging if not transitioning from non-PFR to PFR
+ if [ -e /usr/share/pfr ]; then
+ # exit bmc no nv mode
+ systemctl start nv-sync.service || log "failed to start nv-sync"
+ wait_for_log_sync
+ fi
+ reboot
+}
+
+pfr_staging_update() {
+ log "Updating $(basename $TGT)"
+ flash_erase $TGT $erase_offset $blk_cnt
+ log "Writing $(stat -c "%s" "$LOCAL_PATH") bytes"
+ # cat "$LOCAL_PATH" > "$TGT"
+ dd bs=4k seek=$(($erase_offset / 0x1000)) if=$LOCAL_PATH of=$TGT 2>/dev/null
+
+ # remove the updated image from /tmp
+ rm -f $LOCAL_PATH
+ redfish_log_fw_evt success
+ log "Setting update intent in PFR CPLD"
+ wait_for_log_sync
+
+ # write to PFRCPLD about BMC update intent.
+ pfr_write 0x13 $upd_intent_val
+}
+
+pfr_active_mode() {
+ # check for 0xde in register file 0
+ local id=$(pfr_read $PFR_ID_REG) || return 1
+ [ "$id" == "0xde" ] || return 1
+ local state=$(pfr_read $PFR_STATE_REG) || return 1
+ local prov=$(pfr_read $PFR_PROV_REG) || return 1
+ prov=$((prov & 0x20))
+ [ "$prov" == "32" ] && return 0
+ return 1
+}
+
+blk0blk1_update() {
+ # PFR-style image update section
+ # read the image type from the uploaded image
+ # Byte at location 0x8 gives image type
+ TGT="/dev/mtd/image-stg"
+ img_type=$(hexdump -s 8 -n 1 -e '/1 "%02x\n"' $LOCAL_PATH)
+ log "image-type=$img_type"
+
+ if [ $local_file -eq 0 ]; then
+ img_type_str=$(busctl get-property xyz.openbmc_project.Software.BMC.Updater /xyz/openbmc_project/software/$img_obj xyz.openbmc_project.Software.Version Purpose | cut -d " " -f 2 | cut -d "." -f 6 | sed 's/.\{1\}$//')
+ img_target=$(busctl get-property xyz.openbmc_project.Software.BMC.Updater /xyz/openbmc_project/software/$img_obj xyz.openbmc_project.Software.Activation RequestedActivation | cut -d " " -f 2| cut -d "." -f 6 | sed 's/.\{1\}$//')
+ else
+ img_type_str='BMC'
+ img_target='Active'
+ fi
+
+ apply_time=$(busctl get-property xyz.openbmc_project.Settings /xyz/openbmc_project/software/apply_time xyz.openbmc_project.Software.ApplyTime RequestedApplyTime | cut -d " " -f 2 | cut -d "." -f 6 | sed 's/.\{1\}$//')
+ log "image-name=$img_type_str"
+ log "image-target=$img_target"
+ log "apply_time=$apply_time"
+
+ case "$img_type" in
+ 04)
+ if [ "$img_type_str" == 'BMC' ]; then
+ # BMC image - max size 32MB
+ log "BMC firmware image"
+ img_size=33554432
+ if [ "$img_target" == 'StandbySpare' ]; then
+ upd_intent_val=0x10
+ else
+ upd_intent_val=0x08
+ fi
+ erase_offset=0
+ FWTYPE="BMC"
+ FWVER="${RANDOM}-fixme"
+ else
+ # log error the image selected for update is not same as downloaded.
+ log "Mismatch: image selected for update and image parsed are different"
+ redfish_log_fw_evt abort
+ return 1
+ fi
+ ;;
+ 00)
+ if [ "$img_type_str" == 'Other' ]; then
+ log "CPLD firmware image"
+ # CPLD image- max size 1MB
+ img_size=1048576
+ if [ "$img_target" == 'StandbySpare' ]; then
+ upd_intent_val=0x20
+ else
+ upd_intent_val=0x04
+ fi
+ erase_offset=0x3000000
+ FWTYPE="CPLD"
+ FWVER="${RANDOM}-fixme"
+ else
+ # log error the image selected for update is not same as downloaded.
+ log "Mismatch: image selected for update and image parsed are different"
+ redfish_log_fw_evt abort
+ return 1
+ fi
+ ;;
+ 02)
+ if [ "$img_type_str" = 'Host' ]; then
+ # BIOS image- max size 16MB
+ log "BIOS firmware image"
+ img_size=16777216
+ if [ "$img_target" == 'StandbySpare' ]; then
+ upd_intent_val=0x02
+ else
+ upd_intent_val=0x41
+ fi
+ erase_offset=0x2000000
+ # TODO: parse out the fwtype and fwver once that is specified
+ FWTYPE="BIOS"
+ FWVER="${RANDOM}-fixme"
+ else
+ # log error the image selected for update is not same as downloaded.
+ log "Mismatch: image selected for update and image parsed are different"
+ redfish_log_fw_evt abort
+ return 1
+ fi
+ ;;
+ *)
+ log "Unknown image type ${img_type}"
+ return 1
+ ;;
+ esac
+
+ # For deferred updates
+ if [ "$apply_time" == 'OnReset' ]; then
+ upd_intent_val=$(( "$upd_intent_val"|0x80 ))
+ fi
+
+ # do a quick sanity check on the image
+ if [ $(stat -c "%s" "$LOCAL_PATH") -gt $img_size ]; then
+ log "Update file "$LOCAL_PATH" is bigger than the supported image size"
+ redfish_log_fw_evt abort
+ return 1
+ fi
+ blk_cnt=$((img_size / 0x10000))
+
+ if pfr_active_mode; then
+ # pfr enforcing mode; any b0b1 image type
+ pfr_staging_update
+ elif [ "$img_type" == '04' ]; then
+ # legacy mode; pfr is not present but we got a pfr image
+ log "Updating BMC active firmware- PFR unprovisioned mode"
+ pfr_active_update
+ else
+ # error; pfr is not present but we got a pfr image,
+ # an invalid image, or nonBMC image
+ log "PFR inactive or invalid image type:${img_type}, cowardly refusing to process image"
+ redfish_log_fw_evt abort
+ return 1
+ fi
+}
+
+ping_pong_update() {
+ # if some one tries to update with non-PFR on PFR image
+ # just exit
+ if [ -e /usr/share/pfr ]; then
+ log "Update exited as non-PFR image is tried onto PFR image"
+ redfish_log_fw_evt abort
+ return 1
+ fi
+ # do a quick sanity check on the image
+ if [ $(stat -c "%s" "$LOCAL_PATH") -lt 10000000 ]; then
+ log "Update file "$LOCAL_PATH" seems to be too small"
+ redfish_log_fw_evt abort
+ return 1
+ fi
+ dtc -I dtb -O dtb "$LOCAL_PATH" > /dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ log "Update file $LOCAL_PATH doesn't seem to be in the proper format"
+ redfish_log_fw_evt abort
+ return 1
+ fi
+
+ # guess based on fw_env which partition we booted from
+ local BOOTADDR=$(fw_printenv bootcmd | awk '{print $2}')
+ local 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
+ log "Updating $(basename $TGT) (use bootm $BOOTADDR)"
+ flash_erase $TGT 0 0
+ log "Writing $(stat -c "%s" "$LOCAL_PATH") bytes"
+ cat "$LOCAL_PATH" > "$TGT"
+ fw_setenv "bootcmd" "bootm ${BOOTADDR}"
+ redfish_log_fw_evt success
+ wait_for_log_sync
+ # reboot
+ reboot
+}
+
+fetch_fw() {
+ 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)"
+ log "PROTO=$PROTO"
+ log "REMOTE=$REMOTE"
+ log "REMOTE_HOST=$REMOTE_HOST"
+ log "REMOTE_PATH=$REMOTE_PATH"
+ if [ ! -e $LOCAL_PATH ] || [ $(stat -c %s $LOCAL_PATH) -eq 0 ]; then
+ log "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
+ log "scp $REMOTE $LOCAL_PATH failed!"
+ return 1
+ fi
+ ;;
+ tftp)
+ cd /tmp
+ tftp -g -r "$REMOTE_PATH" "$REMOTE_HOST"
+ if [ $? -ne 0 ]; then
+ log "tftp -g -r \"$REMOTE_PATH\" \"$REMOTE_HOST\" failed!"
+ return 1
+ fi
+ ;;
+ http|https|ftp)
+ wget --no-check-certificate "$URI" -O "$LOCAL_PATH"
+ if [ $? -ne 0 ]; then
+ log "wget $URI failed!"
+ return 1
+ fi
+ ;;
+ file)
+ LOCAL_PATH=$(echo $URI | sed 's,^file://,,')
+ ;;
+ *)
+ log "Invalid URI $URI"
+ return 1
+ ;;
+ esac
+ fi
+}
+
+update_fw() {
+ redfish_log_fw_evt start
+ # determine firmware file type
+ local magic=$(hexdump -n 4 -v -e '/1 "%02x"' "$LOCAL_PATH")
+ case "$magic" in
+ d00dfeed) ping_pong_update ;;
+ 19fdeab6) blk0blk1_update ;;
+ *) log "Uknown file type ${magic}"
+ esac
+}
+
+# if this script was sourced, just return without executing anything
+[ "$_" != "$0" ] && return 0 >&/dev/null
+
+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
+ if [[ "$1" == *"/"* ]]; then
+ URI=$1 # local file
+ local_file=1 ;
+ else
+ URI="file:////tmp/images/$1/image-runtime"
+ img_obj=$1
+ local_file=0 ;
+ fi
+fi
+fetch_fw && update_fw
diff --git a/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl
new file mode 100644
index 000000000..ae9f54263
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/files/usb-ctrl
@@ -0,0 +1,136 @@
+#!/bin/sh
+
+setup_image()
+{
+ set -x
+ local storage="$1"
+ local sz_mb="$2"
+ # create the backing store
+ dd if=/dev/zero of=$storage bs=1M seek=$sz_mb count=0 2>/dev/null
+ # this shows up as 23FC-F676 in /dev/disk/by-uuid
+ local diskid=0x23FCF676
+ mkdosfs -n 'OPENBMC-FW' -i $diskid -I $storage >/dev/null 2>&1
+}
+
+mount_image()
+{
+ set -x
+ local storage="$1"
+ local stormnt="$2"
+ mkdir -p $stormnt || exit 1
+ mount -o loop -t vfat $storage $stormnt
+}
+
+cleanup_image()
+{
+ set -x
+ local storage="$1"
+ local stormnt="$2"
+ umount -f "$stormnt"
+ rm -f "$storage"
+ rmdir "$stormnt"
+}
+
+GADGET_BASE=/sys/kernel/config/usb_gadget
+
+which_dev()
+{
+ local in_use=$(cat $GADGET_BASE/*/UDC)
+ cd /sys/class/udc
+ for D in *; do
+ case "$in_use" in
+ *"$D"*) ;;
+ *) echo "$D"; return 0;;
+ esac
+ done
+ return 1
+}
+
+usb_ms_insert()
+{
+ local name="$1"
+ local storage="$2"
+
+ if [ -d $GADGET_BASE/$name ]; then
+ echo "device $name already exists" >&2
+ return 1
+ fi
+ mkdir $GADGET_BASE/$name
+ cd $GADGET_BASE/$name
+
+ echo 0x1d6b > idVendor # Linux Foundation
+ echo 0x0105 > idProduct # FunctionFS Gadget
+ mkdir strings/0x409
+ local machineid=$(cat /etc/machine-id)
+ local data="OpenBMC USB mass storage gadget device serial number"
+ local serial=$( echo -n "${machineid}${data}${machineid}" | \
+ sha256sum | cut -b 0-12 )
+ echo $serial > strings/0x409/serialnumber
+ echo OpenBMC > strings/0x409/manufacturer
+ echo "OpenBMC Mass Storage" > strings/0x409/product
+
+ mkdir configs/c.1
+ mkdir functions/mass_storage.$name
+ echo $storage > functions/mass_storage.$name/lun.0/file
+ echo 0 > functions/mass_storage.$name/lun.0/removable
+ mkdir configs/c.1/strings/0x409
+
+ echo "Conf 1" > configs/c.1/strings/0x409/configuration
+ echo 120 > configs/c.1/MaxPower
+ ln -s functions/mass_storage.$name configs/c.1
+ local dev=$(which_dev)
+ echo $dev > UDC
+}
+
+usb_ms_eject()
+{
+ local name="$1"
+
+ echo '' > $GADGET_BASE/$name/UDC
+
+ rm -f $GADGET_BASE/$name/configs/c.1/mass_storage.$name
+ rmdir $GADGET_BASE/$name/configs/c.1/strings/0x409
+ rmdir $GADGET_BASE/$name/configs/c.1
+ rmdir $GADGET_BASE/$name/functions/mass_storage.$name
+ rmdir $GADGET_BASE/$name/strings/0x409
+ rmdir $GADGET_BASE/$name
+}
+
+usage()
+{
+ echo "Usage: $0 <action> ..."
+ echo " $0 setup <file> <sizeMB>"
+ echo " $0 insert <name> <file>"
+ echo " $0 eject <name>"
+ echo " $0 mount <file> <mnt>"
+ echo " $0 cleanup <file> <mnt>"
+ exit 1
+}
+
+echo "$#: $0 $@"
+case "$1" in
+ insert)
+ shift
+ usb_ms_insert "$@"
+ ;;
+ eject)
+ shift
+ usb_ms_eject "$@"
+ ;;
+ setup)
+ shift
+ setup_image "$@"
+ ;;
+ mount)
+ shift
+ mount_image "$@"
+ ;;
+ cleanup)
+ shift
+ cleanup_image "$@"
+ ;;
+ *)
+ usage
+ ;;
+esac
+exit $?
diff --git a/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb b/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb
new file mode 100644
index 000000000..007a4aece
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/fw-update/intel-fw-update.bb
@@ -0,0 +1,30 @@
+SUMMARY = "Temporary intel-fw-update script"
+DESCRIPTION = "At runtime, perform a firmware update and reboot"
+PR = "r1"
+
+# flash_eraseall
+RDEPENDS_intel-fw-update += "mtd-utils"
+# wget tftp scp
+RDEPENDS_intel-fw-update += "busybox dropbear"
+# mkfs.vfat, parted
+RDEPENDS_intel-fw-update += "dosfstools dtc"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+PFR_EN = "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'pfr', '', d)}"
+
+SRC_URI += "file://fwupd.sh"
+SRC_URI += "file://usb-ctrl"
+
+FILES_${PN} += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '${datadir}/pfr', '', d)}"
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 ${WORKDIR}/fwupd.sh ${D}${bindir}
+ install -m 0755 ${WORKDIR}/usb-ctrl ${D}${bindir}
+
+ if [ "${PFR_EN}" = "pfr" ]; then
+ install -d ${D}${datadir}
+ touch ${D}${datadir}/pfr
+ fi
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_%.bbappend
new file mode 100644
index 000000000..81462b2d3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/host-error-monitor/host-error-monitor_%.bbappend
@@ -0,0 +1,3 @@
+# Enable downstream autobump
+SRC_URI = "git://github.com/openbmc/host-error-monitor"
+SRCREV = "53099c49b89c22cfe09c7217679ae1fb20e019eb"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/.clang-format b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/.clang-format
new file mode 100644
index 000000000..86a2a9d63
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/.clang-format
@@ -0,0 +1,21 @@
+---
+BasedOnStyle: LLVM
+Language: Cpp
+IndentWidth: 8
+UseTab: Always
+BreakBeforeBraces: Linux
+AlwaysBreakBeforeMultilineStrings: true
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+IndentCaseLabels: false
+AlignEscapedNewlinesLeft: false
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: false
+AlignAfterOpenBracket: true
+SpaceAfterCStyleCast: false
+MaxEmptyLinesToKeep: 2
+BreakBeforeBinaryOperators: NonAssignment
+BreakStringLiterals: false
+SortIncludes: true
+ContinuationIndentWidth: 8
diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0001-Smbus-changes-for-libmctp.patch b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0001-Smbus-changes-for-libmctp.patch
new file mode 100644
index 000000000..05bd4c055
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/0001-Smbus-changes-for-libmctp.patch
@@ -0,0 +1,119 @@
+From 1f14ea50ece39c59d23690690dc7c8b1059a35f6 Mon Sep 17 00:00:00 2001
+From: Nikhil Potade <nikhil.potade@linux.intel.com>
+Date: Tue, 19 Feb 2019 14:16:20 +0800
+Subject: [PATCH 1/1] Smbus changes for libmctp
+
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+---
+ core.c | 2 ++
+ libmctp.h | 40 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 42 insertions(+)
+
+diff --git a/core.c b/core.c
+index e7f5689..3732e8a 100644
+--- a/core.c
++++ b/core.c
+@@ -17,6 +17,7 @@
+
+ /* Internal data structures */
+
++/* clang-format off */
+ struct mctp_bus {
+ mctp_eid_t eid;
+ struct mctp_binding *binding;
+@@ -56,6 +57,7 @@ struct mctp {
+ ROUTE_BRIDGE,
+ } route_policy;
+ };
++/* clang-format on */
+
+ #ifndef BUILD_ASSERT
+ #define BUILD_ASSERT(x) \
+diff --git a/libmctp.h b/libmctp.h
+index 69ec46a..b7212be 100644
+--- a/libmctp.h
++++ b/libmctp.h
+@@ -15,6 +15,7 @@ extern "C" {
+ typedef uint8_t mctp_eid_t;
+
+ /* MCTP packet definitions */
++/* clang-format off */
+ struct mctp_hdr {
+ uint8_t ver;
+ uint8_t dest;
+@@ -30,19 +31,56 @@ struct mctp_hdr {
+ #define MCTP_HDR_SEQ_MASK (0x3)
+ #define MCTP_HDR_TAG_SHIFT (0)
+ #define MCTP_HDR_TAG_MASK (0x7)
++/* clang-format on */
+
+ /* Baseline Transmission Unit and packet size */
+ #define MCTP_BTU 64
+ #define MCTP_PACKET_SIZE(unit) ((unit) + sizeof(struct mctp_hdr))
+
++#define MCTP_CONTROL_MESSAGE_TYPE 0x00
++
++enum MCTP_COMMAND_CODE {
++ MCTP_COMMAND_CODE_SET_EID = 0x01,
++ MCTP_COMMAND_CODE_GET_EID = 0x02,
++ MCTP_COMMAND_CODE_GET_ENDPOINT_UUID = 0x03,
++ MCTP_COMMAND_CODE_GET_MCTP_VERSION_SUPPORT = 0x04,
++ MCTP_COMMAND_CODE_GET_MESSAGE_TYPE_SUPPORT = 0x05,
++ MCTP_COMMAND_CODE_GET_VENDOR_DEFINED_MSG_SUPPORT= 0x06,
++ MCTP_COMMAND_CODE_RESOLVE_ENDPOINT_ID = 0x07,
++ MCTP_COMMAND_CODE_ALLOCATE_ENDPOINT_IDS = 0x08,
++ MCTP_COMMAND_CODE_ROUTING_INFORMATION_UPDATE = 0x09,
++ MCTP_COMMAND_CODE_GET_ROUTING_TABLE_ENTRIES = 0x0A,
++ MCTP_COMMAND_CODE_PREPARE_FOR_ENDPOINT_DISCOVERY= 0x0B,
++ MCTP_COMMAND_CODE_ENDPOINT_DISCOVERY = 0x0C,
++ MCTP_COMMAND_CODE_DISCOVERY_NOTIFY = 0x0D,
++ MCTP_COMMAND_CODE_GET_NETWORK_ID = 0x0E,
++ MCTP_COMMAND_CODE_QUERY_HOP = 0x0F,
++ MCTP_COMMAND_CODE_RESOLVE_UUID = 0x10,
++ MCTP_COMMAND_CODE_QUERY_RATE_LIMIT = 0x11,
++ MCTP_COMMAND_CODE_REQUEST_TX_RATE_LIMIT = 0x12,
++ MCTP_COMMAND_CODE_UPDATE_RATE_LIMIT = 0x13,
++ MCTP_COMMAND_CODE_QUERY_SUPPORTED_INTERFACES = 0x14
++};
++
++enum MCTP_CONTROL_MSG_COMPLETION_CODE {
++ MCTP_CONTROL_MSG_STATUS_SUCCESS = 0x00,
++ MCTP_CONTROL_MSG_STATUS_ERROR = 0x01,
++ MCTP_CONTROL_MSG_STATUS_ERROR_INVALID_DATA = 0x02,
++ MCTP_CONTROL_MSG_STATUS_ERROR_INVALID_LENGTH = 0x03,
++ MCTP_CONTROL_MSG_STATUS_ERROR_NOT_READY = 0x04,
++ MCTP_CONTROL_MSG_STATUS_ERROR_UNSUPPORTED_CMD = 0x05
++};
++
+ /* packet buffers */
+
++/* clang-format off */
+ struct mctp_pktbuf {
+ size_t start, end, size;
+ size_t mctp_hdr_off;
+ struct mctp_pktbuf *next;
+ unsigned char data[];
+ };
++/* clang-format on */
+
+ struct mctp_binding;
+
+@@ -90,6 +128,7 @@ int mctp_message_tx(struct mctp *mctp, mctp_eid_t eid,
+ void *msg, size_t msg_len);
+
+ /* hardware bindings */
++/* clang-format off */
+ struct mctp_binding {
+ const char *name;
+ uint8_t version;
+@@ -101,6 +140,7 @@ struct mctp_binding {
+ int (*tx)(struct mctp_binding *binding,
+ struct mctp_pktbuf *pkt);
+ };
++/* clang-format on */
+
+ void mctp_binding_set_tx_enabled(struct mctp_binding *binding, bool enable);
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/CMakeLists.txt
new file mode 100644
index 000000000..28354123e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/CMakeLists.txt
@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+add_definitions(-DMCTP_LOG_STDERR)
+add_definitions(-DMCTP_HAVE_FILEIO)
+add_definitions(-DMCTP_HAVE_STDIO)
+add_definitions(-DMCTP_DEFAULT_ALLOC)
+
+add_library(
+ libmctp STATIC alloc.c core.c log.c libmctp.h serial.c smbus.c crc32c.c)
+
+target_include_directories(libmctp
+ PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<INSTALL_INTERFACE:include/libmctp)
+
+enable_testing()
+
+add_executable(test_eid tests/test_eid.c tests/test-utils.c)
+target_link_libraries(test_eid libmctp)
+
+add_executable(test_seq tests/test_seq.c tests/test-utils.c)
+target_link_libraries(test_seq libmctp)
+
+install(TARGETS libmctp DESTINATION lib)
+install(
+ FILES libmctp.h libmctp-smbus.h libmctp-serial.h crc32c.h DESTINATION include)
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.c b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.c
new file mode 100644
index 000000000..0d5090e2c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.c
@@ -0,0 +1,93 @@
+#include "crc32c.h"
+/*****************************************************************/
+/* */
+/* CRC LOOKUP TABLE */
+/* ================ */
+/* The following CRC lookup table was generated automagically */
+/* by the Rocksoft^tm Model CRC Algorithm Table Generation */
+/* Program V1.0 using the following model parameters: */
+/* */
+/* Width : 4 bytes. */
+/* Poly : 0x1EDC6F41L */
+/* Reverse : TRUE. */
+/* */
+/* For more information on the Rocksoft^tm Model CRC Algorithm, */
+/* see the document titled "A Painless Guide to CRC Error */
+/* Detection Algorithms" by Ross Williams */
+/* (ross@guest.adelaide.edu.au.). This document is likely to be */
+/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
+/* */
+/*****************************************************************/
+
+unsigned long crctable[256] = {
+ 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL,
+ 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL,
+ 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L,
+ 0x5E133C24L, 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
+ 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L,
+ 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL,
+ 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L,
+ 0x33ED7D2AL, 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
+ 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL,
+ 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L,
+ 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, 0x1642AE59L,
+ 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
+ 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 0x417B1DBCL,
+ 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L,
+ 0x67DAFA54L, 0x95B17957L, 0xCBA24573L, 0x39C9C670L, 0x2A993584L,
+ 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
+ 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL,
+ 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL,
+ 0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L,
+ 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
+ 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL,
+ 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 0x2C855CB2L, 0xDEEEDFB1L,
+ 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL,
+ 0x62C8A7F9L, 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
+ 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL,
+ 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL,
+ 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L,
+ 0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
+ 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 0x92A8FC17L,
+ 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL,
+ 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL,
+ 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
+ 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 0x65D122B9L,
+ 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL,
+ 0xC9A99D9EL, 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L,
+ 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
+ 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L,
+ 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, 0x0D3D3E1AL,
+ 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L,
+ 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
+ 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L,
+ 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L,
+ 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L,
+ 0x07198540L, 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
+ 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL,
+ 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L,
+ 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L,
+ 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
+ 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 0x34F4F86AL,
+ 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L,
+ 0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L,
+ 0xAD7D5351L};
+
+/*****************************************************************/
+/* End of CRC Lookup Table */
+/*****************************************************************/
+
+uint32_t crc32c(uint8_t *data, int length)
+{
+ const uint32_t CRC_INIT = 0xffffffffL;
+ const uint32_t XO_ROT = 0xffffffffL;
+
+ uint32_t crc = CRC_INIT;
+
+ while (length--) {
+ crc = crctable[(crc ^ *data++) & 0xFFL] ^ (crc >> 8);
+ }
+ crc = crc ^ XO_ROT;
+
+ return crc;
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.h b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.h
new file mode 100644
index 000000000..4586547e6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/crc32c.h
@@ -0,0 +1,16 @@
+#ifndef CRC32C_H
+#define CRC32C_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+uint32_t crc32c(uint8_t *buf, int len);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* CRC32C_H */
diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/libmctp-smbus.h b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/libmctp-smbus.h
new file mode 100644
index 000000000..67690bcb3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/libmctp-smbus.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#ifndef _LIBMCTP_SMBUS_H
+#define _LIBMCTP_SMBUS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "libmctp.h"
+
+struct mctp_binding_smbus;
+
+struct mctp_binding_smbus *mctp_smbus_init(void);
+int mctp_smbus_get_out_fd(struct mctp_binding_smbus *smbus);
+int mctp_smbus_get_in_fd(struct mctp_binding_smbus *smbus);
+void mctp_smbus_register_bus(struct mctp_binding_smbus *smbus,
+ struct mctp *mctp, mctp_eid_t eid);
+int mctp_smbus_read(struct mctp_binding_smbus *smbus);
+int mctp_smbus_open_bus(struct mctp_binding_smbus *smbus, int out_bus_num,
+ int root_bus_num);
+void mctp_smbus_free(struct mctp_binding_smbus *smbus);
+int mctp_smbus_open_in_bus(struct mctp_binding_smbus *smbus, int in_bus);
+int mctp_smbus_open_out_bus(struct mctp_binding_smbus *smbus, int out_bus);
+int mctp_smbus_set_in_fd(struct mctp_binding_smbus *smbus, int fd);
+int mctp_smbus_set_out_fd(struct mctp_binding_smbus *smbus, int fd);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LIBMCTP_SMBUS_H */
diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/smbus.c b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/smbus.c
new file mode 100644
index 000000000..2f099a7e5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp/smbus.c
@@ -0,0 +1,467 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef MCTP_HAVE_FILEIO
+#include <fcntl.h>
+#endif
+
+#define pr_fmt(x) "smbus: " x
+
+#include <i2c/smbus.h>
+#include <linux/i2c-dev.h>
+#include <linux/i2c.h>
+#include <sys/ioctl.h>
+
+#include "libmctp-alloc.h"
+#include "libmctp-log.h"
+#include "libmctp-smbus.h"
+#include "libmctp.h"
+
+struct mctp_binding_smbus {
+ struct mctp_binding binding;
+ int out_fd;
+ int in_fd;
+
+ unsigned long bus_id;
+
+ /* receive buffer */
+ uint8_t rxbuf[1024];
+ struct mctp_pktbuf *rx_pkt;
+
+ /* temporary transmit buffer */
+ uint8_t txbuf[256];
+};
+
+#ifndef container_of
+#define container_of(ptr, type, member) \
+ (type *)((char *)(ptr) - (char *)&((type *)0)->member)
+#endif
+
+#define binding_to_smbus(b) container_of(b, struct mctp_binding_smbus, binding)
+
+#define MCTP_COMMAND_CODE 0x0F
+#define MCTP_SLAVE_ADDRESS 0x1d
+#define MCTP_SOURCE_SLAVE_ADDRESS 0x21
+
+#define SMBUS_PEC_BYTE_SIZE 1
+#define SMBUS_COMMAND_CODE_SIZE 1
+#define SMBUS_LENGTH_FIELD_SIZE 1
+#define SMBUS_ADDR_OFFSET_SLAVE 0x1000
+
+struct mctp_smbus_header_tx {
+ uint8_t source_slave_address;
+};
+
+struct mctp_smbus_header_rx {
+ uint8_t destination_slave_address;
+ uint8_t command_code;
+ uint8_t byte_count;
+ uint8_t source_slave_address;
+};
+
+#define POLYCHECK (0x1070U << 3)
+static uint8_t crc8_calculate(uint16_t d)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if (d & 0x8000) {
+ d = d ^ POLYCHECK;
+ }
+ d = d << 1;
+ }
+
+ return (uint8_t)(d >> 8);
+}
+
+/* Incremental CRC8 over count bytes in the array pointed to by p */
+static uint8_t pec_calculate(uint8_t crc, uint8_t *p, size_t count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ crc = crc8_calculate((crc ^ p[i]) << 8);
+ }
+
+ return crc;
+}
+
+static uint8_t calculate_pec_byte(uint8_t *buf, size_t len, uint8_t address,
+ uint16_t flags)
+{
+ uint8_t addr = (address << 1) | (flags & I2C_M_RD ? 1 : 0);
+ uint8_t pec = pec_calculate(0, &addr, 1);
+ pec = pec_calculate(pec, buf, len);
+
+ return pec;
+}
+
+static int mctp_smbus_tx(struct mctp_binding_smbus *smbus, uint8_t len)
+{
+
+#ifdef I2C_M_HOLD
+ /* Hold message */
+ static uint16_t holdtimeout = 1000; // timeout in ms.
+ struct i2c_msg msg[2] =
+#else // !I2C_M_HOLD
+ struct i2c_msg msg[1] =
+#endif // I2C_M_HOLD
+ {{.addr = MCTP_SLAVE_ADDRESS,
+ .flags = 0,
+ .len = len,
+ .buf = (__uint8_t *)smbus->txbuf}
+#ifdef I2C_M_HOLD
+ ,
+ {.addr = 0,
+ .flags = I2C_M_HOLD,
+ .len = sizeof(holdtimeout),
+ .buf = (__uint8_t *)&holdtimeout}
+#endif // I2C_M_HOLD
+ };
+
+#ifdef I2C_M_HOLD
+ struct i2c_rdwr_ioctl_data msgrdwr = {&msg, 2};
+#else // !I2C_M_HOLD
+ struct i2c_rdwr_ioctl_data msgrdwr = {&msg, 1};
+#endif // I2C_M_HOLD
+
+ return ioctl(smbus->out_fd, I2C_RDWR, &msgrdwr);
+}
+
+#ifdef I2C_M_HOLD
+static int mctp_smbus_unhold_bus(struct mctp_binding_smbus *smbus)
+{
+ /* Unhold message */
+ static uint16_t holdtimeout = 0; // unhold
+ struct i2c_msg holdmsg = {0, I2C_M_HOLD, sizeof(holdtimeout),
+ (__uint8_t *)&holdtimeout};
+
+ struct i2c_rdwr_ioctl_data msgrdwr = {&holdmsg, 1};
+
+ return ioctl(smbus->out_fd, I2C_RDWR, &msgrdwr);
+}
+#endif // I2C_M_HOLD
+
+static int mctp_binding_smbus_tx(struct mctp_binding *b,
+ struct mctp_pktbuf *pkt)
+{
+ struct mctp_binding_smbus *smbus = binding_to_smbus(b);
+ struct mctp_smbus_header_tx *hdr;
+ size_t pkt_length;
+
+ uint8_t i2c_message_buf[256];
+ uint8_t *buf_ptr;
+ uint8_t i2c_message_len;
+
+ uint16_t timeout = 1000;
+
+ /* the length field in the header excludes smbus framing
+ * and escape sequences */
+ pkt_length = mctp_pktbuf_size(pkt);
+
+ buf_ptr = (void *)smbus->txbuf;
+ *buf_ptr = MCTP_COMMAND_CODE;
+ buf_ptr++;
+ *buf_ptr = pkt_length + sizeof(*hdr);
+ buf_ptr++;
+
+ hdr = (void *)buf_ptr;
+ hdr->source_slave_address = MCTP_SOURCE_SLAVE_ADDRESS;
+ buf_ptr = (buf_ptr + sizeof(*hdr));
+ memcpy(buf_ptr, &pkt->data[pkt->start], pkt_length);
+ buf_ptr = buf_ptr + pkt_length;
+
+ uint8_t pec_byte = calculate_pec_byte(
+ smbus->txbuf,
+ SMBUS_COMMAND_CODE_SIZE + SMBUS_LENGTH_FIELD_SIZE + sizeof(*hdr)
+ + pkt_length,
+ MCTP_SLAVE_ADDRESS, 0);
+
+ *buf_ptr = pec_byte;
+
+ i2c_message_len = SMBUS_COMMAND_CODE_SIZE + SMBUS_LENGTH_FIELD_SIZE
+ + sizeof(*hdr) + pkt_length
+ + SMBUS_PEC_BYTE_SIZE; // command code, length,
+ // header, data, pec byte
+
+ if (mctp_smbus_tx(smbus, i2c_message_len)) {
+ mctp_prerr("Can't hold mux");
+ return -1;
+ }
+
+ return 0;
+}
+
+#ifdef MCTP_HAVE_FILEIO
+int mctp_smbus_read(struct mctp_binding_smbus *smbus)
+{
+ ssize_t len = 0;
+ struct mctp_smbus_header_rx *hdr;
+ int ret = 0;
+
+ do {
+ ret = lseek(smbus->in_fd, 0, SEEK_SET);
+ if (ret < 0) {
+ mctp_prerr("Failed to seek");
+ ret = -1;
+ }
+
+ len = read(smbus->in_fd, smbus->rxbuf, sizeof(smbus->rxbuf));
+ if (len < sizeof(*hdr)) {
+ // This condition hits from from time to time, even with
+ // a properly written poll loop, although it's not clear
+ // why. Return an error so that the upper layer can
+ // retry.
+ ret = 0;
+ break;
+ }
+
+ hdr = (void *)smbus->rxbuf;
+ if (hdr->destination_slave_address
+ != (MCTP_SOURCE_SLAVE_ADDRESS & ~1)) {
+ mctp_prerr("Got bad slave address %d",
+ hdr->destination_slave_address);
+ ret = 0;
+ break;
+ }
+ if (hdr->command_code != MCTP_COMMAND_CODE) {
+ mctp_prerr("Got bad command code %d",
+ hdr->command_code);
+ // Not a payload intended for us
+ ret = 0;
+ break;
+ }
+
+ if (hdr->byte_count != (len - sizeof(*hdr))) {
+ // Got an incorrectly sized payload
+ mctp_prerr("Got smbus payload sized %d, expecting %d",
+ hdr->byte_count, len - sizeof(*hdr));
+ ret = 0;
+ break;
+ }
+
+ if (len < 0) {
+ mctp_prerr("can't read from smbus device: %m");
+ ret = -1;
+ break;
+ }
+
+ smbus->rx_pkt = mctp_pktbuf_alloc(&(smbus->binding), 0);
+ assert(smbus->rx_pkt);
+
+ if (mctp_pktbuf_push(smbus->rx_pkt, &smbus->rxbuf[sizeof(*hdr)],
+ len - sizeof(*hdr) - SMBUS_PEC_BYTE_SIZE)
+ != 0) {
+ mctp_prerr("Can't push tok pktbuf: %m");
+ ret = -1;
+ break;
+ }
+
+ mctp_bus_rx(&(smbus->binding), smbus->rx_pkt);
+
+ smbus->rx_pkt = NULL;
+
+ } while (0);
+
+#ifdef I2C_M_HOLD
+ if (mctp_smbus_unhold_bus(smbus)) {
+ mctp_prerr("Can't hold mux");
+ ret = -1;
+ }
+#endif // I2C_M_HOLD
+
+ return ret;
+}
+
+int mctp_smbus_get_in_fd(struct mctp_binding_smbus *smbus)
+{
+ return smbus->in_fd;
+}
+
+
+int mctp_smbus_set_in_fd(struct mctp_binding_smbus *smbus, int fd)
+{
+ smbus->in_fd = fd;
+}
+
+int mctp_smbus_set_out_fd(struct mctp_binding_smbus *smbus, int fd)
+{
+ smbus->out_fd = fd;
+}
+
+int mctp_smbus_get_out_fd(struct mctp_binding_smbus *smbus)
+{
+ return smbus->out_fd;
+}
+
+int mctp_smbus_open_in_bus(struct mctp_binding_smbus *smbus, int in_bus)
+{
+ char filename[60];
+ size_t filename_size = 0;
+ char slave_mqueue[20];
+ size_t mqueue_size = 0;
+ int fd = 0;
+ size_t size = sizeof(filename);
+ int address_7_bit = MCTP_SOURCE_SLAVE_ADDRESS >> 1;
+ int ret = -1;
+
+ snprintf(filename, size,
+ "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue", in_bus,
+ in_bus, SMBUS_ADDR_OFFSET_SLAVE | address_7_bit);
+
+ ret = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+ if (ret >= 0) {
+ return ret;
+ }
+
+ // Device doesn't exist. Create it.
+ filename_size = sizeof(filename);
+ snprintf(filename, filename_size,
+ "/sys/bus/i2c/devices/i2c-%d/new_device", in_bus);
+ filename[filename_size - 1] = '\0';
+
+ fd = open(filename, O_WRONLY);
+ if (fd < 0) {
+ mctp_prerr("can't open root device %s: %m", filename);
+ return -1;
+ }
+
+ mqueue_size = sizeof(slave_mqueue);
+ snprintf(slave_mqueue, mqueue_size, "slave-mqueue %#04x",
+ SMBUS_ADDR_OFFSET_SLAVE | address_7_bit);
+
+ size = write(fd, slave_mqueue, mqueue_size);
+ close(fd);
+ if (size != mqueue_size) {
+ mctp_prerr("can't create mqueue device on %s: %m", filename);
+ return -1;
+ }
+
+ size = sizeof(filename);
+ snprintf(filename, size,
+ "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue", in_bus,
+ in_bus, SMBUS_ADDR_OFFSET_SLAVE | address_7_bit);
+
+ return open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+}
+
+int mctp_smbus_open_out_bus(struct mctp_binding_smbus *smbus, int out_bus)
+{
+ char filename[60];
+ size_t size = sizeof(filename);
+ snprintf(filename, size, "/dev/i2c-%d", out_bus);
+ filename[size - 1] = '\0';
+
+ return open(filename, O_RDWR | O_NONBLOCK);
+}
+
+/*
+int mctp_smbus_open_bus(struct mctp_binding_smbus *smbus, int out_bus_num,
+ int root_bus_num)
+{
+ char filename[60];
+ size_t filename_size = 0;
+ char slave_mqueue[20];
+ size_t mqueue_size = 0;
+ int fd = 0;
+ size_t size = sizeof(filename);
+ int address_7_bit = MCTP_SOURCE_SLAVE_ADDRESS >> 1;
+
+ snprintf(filename, size,
+ "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue",
+ root_bus_num, root_bus_num,
+ SMBUS_ADDR_OFFSET_SLAVE | address_7_bit);
+
+ smbus->in_fd = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+ if (smbus->in_fd < 0) {
+ // Device doesn't exist. Create it.
+ filename_size = sizeof(filename);
+ snprintf(filename, filename_size,
+ "/sys/bus/i2c/devices/i2c-%d/new_device",
+ root_bus_num);
+ filename[filename_size - 1] = '\0';
+
+ fd = open(filename, O_WRONLY);
+ if (fd < 0) {
+ mctp_prerr("can't open root device %s: %m", filename);
+ return -1;
+ }
+
+ mqueue_size = sizeof(slave_mqueue);
+ snprintf(slave_mqueue, mqueue_size, "slave-mqueue %#04x",
+ SMBUS_ADDR_OFFSET_SLAVE | address_7_bit);
+
+ size = write(fd, slave_mqueue, mqueue_size);
+ close(fd);
+ if (size != mqueue_size) {
+ mctp_prerr("can't create mqueue device on %s: %m",
+ filename);
+ return -1;
+ }
+
+ size = sizeof(filename);
+ snprintf(filename, size,
+ "/sys/bus/i2c/devices/i2c-%d/%d-%04x/slave-mqueue",
+ root_bus_num, root_bus_num,
+ SMBUS_ADDR_OFFSET_SLAVE | address_7_bit);
+
+ smbus->in_fd =
+ open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+ if (smbus->in_fd < 0) {
+ mctp_prerr("can't open mqueue device on %s: %m",
+ filename);
+ return -2;
+ }
+ }
+
+ size = sizeof(filename);
+ snprintf(filename, size, "/dev/i2c-%d", out_bus_num);
+ filename[size - 1] = '\0';
+
+ smbus->out_fd = open(filename, O_RDWR | O_NONBLOCK);
+ if (smbus->out_fd < 0) {
+ close(smbus->in_fd);
+ mctp_prerr("can't open device %s: %m", filename);
+ }
+
+ return 0;
+}
+*/
+#endif
+
+void mctp_smbus_register_bus(struct mctp_binding_smbus *smbus,
+ struct mctp *mctp, mctp_eid_t eid)
+{
+ smbus->bus_id = mctp_register_bus(mctp, &smbus->binding, eid);
+ mctp_binding_set_tx_enabled(&smbus->binding, true);
+}
+
+struct mctp_binding_smbus *mctp_smbus_init(void)
+{
+ struct mctp_binding_smbus *smbus;
+
+ smbus = __mctp_alloc(sizeof(*smbus));
+ memset(&(smbus->binding), 0, sizeof(smbus->binding));
+
+ smbus->in_fd = -1;
+ smbus->out_fd = -1;
+
+ smbus->rx_pkt = NULL;
+ smbus->binding.name = "smbus";
+ smbus->binding.version = 1;
+ smbus->binding.pkt_size = sizeof(smbus->rxbuf);
+
+ smbus->binding.tx = mctp_binding_smbus_tx;
+ return smbus;
+}
+
+void mctp_smbus_free(struct mctp_binding_smbus *smbus)
+{
+ __mctp_free(smbus);
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb
new file mode 100644
index 000000000..edbcce6f3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/interfaces/libmctp_git.bb
@@ -0,0 +1,42 @@
+SUMMARY = "libmctp"
+DESCRIPTION = "Implementation of MCTP (DTMF DSP0236)"
+
+SRC_URI = "git://github.com/openbmc/libmctp.git"
+SRCREV = "6a18582ba2f47f677846dc68f608effc60bbb9e7"
+
+PV = "0.1+git${SRCPV}"
+
+LICENSE = "Apache-2.0 | GPLv2"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=0d30807bb7a4f16d36e96b78f9ed8fae"
+
+inherit cmake
+
+S = "${WORKDIR}/git"
+
+DEPENDS += "i2c-tools"
+
+CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include/uapi"
+CFLAGS_append = " -I ${STAGING_KERNEL_DIR}/include"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://0001-Smbus-changes-for-libmctp.patch \
+ file://CMakeLists.txt \
+ file://crc32c.c \
+ file://crc32c.h \
+ file://libmctp-smbus.h \
+ file://smbus.c"
+
+do_configure_prepend() {
+ cp -f ${WORKDIR}/*.c ${S}
+ cp -f ${WORKDIR}/*.h ${S}
+ cp -f ${WORKDIR}/CMakeLists.txt ${S}
+}
+
+# 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/ipmi/intel-ipmi-oem_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend
new file mode 100644
index 000000000..16ee0b625
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/ipmi/intel-ipmi-oem_%.bbappend
@@ -0,0 +1,5 @@
+EXTRA_OECMAKE += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '-DINTEL_PFR_ENABLED=ON', '', d)}"
+EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-DBMC_VALIDATION_UNSECURE_FEATURE=ON', '', d)}"
+EXTRA_OECMAKE += "-DUSING_ENTITY_MANAGER_DECORATORS=OFF"
+SRC_URI = "git://github.com/openbmc/intel-ipmi-oem.git"
+SRCREV = "2b664d5a185247f0448c763ba7d0e42cfc245024"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check.bb b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check.bb
new file mode 100644
index 000000000..955ed1921
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check.bb
@@ -0,0 +1,26 @@
+SUMMARY = "Kernel panic Check"
+DESCRIPTION = "script tool to check if the reboot is caused by kernel panic \
+ log the kernel panic to systemd journal, and also log to redfish \
+ "
+
+S = "${WORKDIR}"
+SRC_URI = "file://kernel-panic-check.sh \
+ file://kernel-panic-check.service \
+"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+RDEPENDS_${PN} += "bash logger-systemd"
+
+inherit systemd
+
+FILES_${PN} += "${systemd_system_unitdir}/kernel-panic-check.service"
+
+do_install() {
+ install -d ${D}${systemd_system_unitdir}
+ install -m 0644 ${WORKDIR}/kernel-panic-check.service ${D}${systemd_system_unitdir}
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/kernel-panic-check.sh ${D}/${bindir}/kernel-panic-check.sh
+}
+
+SYSTEMD_SERVICE_${PN} += " kernel-panic-check.service"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.service b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.service
new file mode 100644
index 000000000..afe017baf
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Check for kernel panic
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/kernel-panic-check.sh
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.sh b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.sh
new file mode 100755
index 000000000..815f50b71
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/kernel-panic-check/kernel-panic-check/kernel-panic-check.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+panicFile="/sys/fs/pstore/dmesg-ramoops-0"
+if [ -f $panicFile ]
+then
+ # log the detailed last kernel panic messages
+ logger -t kernel-panic-check "Reboot from kernel panic! Log as following:"
+ cat $panicFile | logger
+ # Also log it to redfish
+ cat <<EOF | logger-systemd --journald
+REDFISH_MESSAGE_ID=OpenBMC.0.1.BMCKernelPanic
+PRIORITY=4
+MESSAGE=BMC rebooted due to kernel panic
+EOF
+
+ rm -rf $panicFile
+fi
diff --git a/meta-openbmc-mods/meta-common/recipes-core/libpeci/libpeci_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/libpeci/libpeci_%.bbappend
new file mode 100644
index 000000000..fd56781d7
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/libpeci/libpeci_%.bbappend
@@ -0,0 +1,3 @@
+# Enable downstream autobump
+SRC_URI = "git://github.com/openbmc/libpeci"
+SRCREV = "7ef5a55777bb4d0c403a4eca98c487fa4e9c7bd1"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/libxcrypt/libxcrypt_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/libxcrypt/libxcrypt_%.bbappend
new file mode 100644
index 000000000..ee414efb8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/libxcrypt/libxcrypt_%.bbappend
@@ -0,0 +1,5 @@
+# libxcrypt fails to compile under gcc with the -Os flag. Because we want to
+# be able to compile the rest of the system with -Os, override the global
+# setting here to fall back to -O3
+CFLAGS_append = "--param max-inline-insns-single=1000"
+FULL_OPTIMIZATION = "-O3 -pipe ${DEBUG_FLAGS}"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd.inc b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd.inc
new file mode 100644
index 000000000..abad9d12d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd.inc
@@ -0,0 +1,43 @@
+SUMMARY = "logger tool in util-linux with systemd support"
+HOMEPAGE = "http://userweb.kernel.org/~kzak/util-linux/"
+DESCRIPTION = "logger tool with systemd support, used to add log to systemd journald."
+
+SECTION = "base"
+
+LICENSE = "GPLv2+ & LGPLv2.1+ & BSD-3-Clause & BSD-4-Clause"
+
+LIC_FILES_CHKSUM = "file://README.licensing;md5=972a134f1e14b2b060e365df2fab0099 \
+ file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263 \
+ file://Documentation/licenses/COPYING.GPL-2.0-or-later;md5=b234ee4d69f5fce4486a80fdaf4a4263 \
+ file://Documentation/licenses/COPYING.LGPL-2.1-or-later;md5=4fbd65380cdd255951079008b364516c \
+ file://Documentation/licenses/COPYING.BSD-3-Clause;md5=58dcd8452651fc8b07d1f65ce07ca8af \
+ file://Documentation/licenses/COPYING.BSD-4-Clause-UC;md5=263860f8968d8bafa5392cab74285262 \
+ file://libuuid/COPYING;md5=6d2cafc999feb2c2de84d4d24b23290c \
+ file://libmount/COPYING;md5=7c7e39fb7d70ffe5d693a643e29987c2 \
+ file://libblkid/COPYING;md5=693bcbbe16d3a4a4b37bc906bc01cc04"
+
+inherit autotools gettext pkgconfig
+DEPENDS = "libcap-ng ncurses virtual/crypt zlib systemd "
+#DEPENDS_intel-ast2500 += " systemd "
+#RDEPENDS_${PN} += " libsystemd"
+
+MAJOR_VERSION = "${@'.'.join(d.getVar('PV').split('.')[0:2])}"
+SRC_URI = "${KERNELORG_MIRROR}/linux/utils/util-linux/v${MAJOR_VERSION}/util-linux-${MAJOR_VERSION}.tar.xz \
+ "
+
+S = "${WORKDIR}/util-linux-${MAJOR_VERSION}"
+
+EXTRA_OECONF = " --disable-nls --disable-all-programs \
+ --disable-libuuid --disable-libblkid --disable-libmount \
+ --disable-libsmartcols --disable-libfdisk --disable-pylibmount \
+ --with-systemd \
+ --enable-logger \
+ "
+
+do_install_append () {
+ mv ${D}${bindir}/logger ${D}${bindir}/logger-systemd
+ rm -rf ${D}${sbindir}
+ rm -rf ${D}${base_libdir}
+ rm -rf ${D}${libdir}
+ rm -rf ${D}${datadir}
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/avoid_parallel_tests.patch b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/avoid_parallel_tests.patch
new file mode 100644
index 000000000..748b6ef09
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/avoid_parallel_tests.patch
@@ -0,0 +1,20 @@
+Ptest needs buildtest-TESTS and runtest-TESTS targets.
+serial-tests is required to generate those targets.
+Revert run.sh script accordingly to serialize running tests
+
+Signed-off-by: Tudor Florea <tudor.florea@enea.com>
+Upstream-Status: Inappropriate
+
+Index: util-linux-2.32/configure.ac
+===================================================================
+--- util-linux-2.32.orig/configure.ac
++++ util-linux-2.32/configure.ac
+@@ -11,7 +11,7 @@ AC_CONFIG_MACRO_DIR([m4])
+ dnl AC_USE_SYSTEM_EXTENSIONS must be called before any macros that run
+ dnl the compiler (like AC_PROG_LIBTOOL) to avoid autoconf errors.
+ AC_USE_SYSTEM_EXTENSIONS
+-AM_INIT_AUTOMAKE([-Wall foreign 1.10 tar-pax no-dist-gzip dist-xz subdir-objects])
++AM_INIT_AUTOMAKE([-Wall foreign 1.10 tar-pax no-dist-gzip dist-xz subdir-objects serial-tests])
+
+ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])],
+ [AC_SUBST([AM_DEFAULT_VERBOSITY], [1])])
diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/configure-sbindir.patch b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/configure-sbindir.patch
new file mode 100644
index 000000000..e475289f6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/configure-sbindir.patch
@@ -0,0 +1,23 @@
+util-linux: take ${sbindir} from the environment if it is set there
+fix the test, the [ ] syntax was getting eaten by autoconf
+
+Signed-off-by: Phil Blundell <pb@pbcl.net>
+Signed-off-by: Saul Wold <sgw@linux.intel.com
+Upstream-Status: Inappropriate [configuration]
+
+Index: util-linux-2.31/configure.ac
+===================================================================
+--- util-linux-2.31.orig/configure.ac
++++ util-linux-2.31/configure.ac
+@@ -89,7 +89,10 @@ AC_SUBST([runstatedir])
+ usrbin_execdir='${exec_prefix}/bin'
+ AC_SUBST([usrbin_execdir])
+
+-usrsbin_execdir='${exec_prefix}/sbin'
++if test -z "$usrsbin_execdir" ;
++then
++ usrsbin_execdir='${exec_prefix}/sbin'
++fi
+ AC_SUBST([usrsbin_execdir])
+
+ AS_CASE([$libdir],
diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/display_testname_for_subtest.patch b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/display_testname_for_subtest.patch
new file mode 100644
index 000000000..417ca1d98
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/display_testname_for_subtest.patch
@@ -0,0 +1,25 @@
+Display testname for subtest
+
+Signed-off-by: Tudor Florea <tudor.florea@enea.com>
+Upstream-Status: Pending
+
+---
+ tests/functions.sh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tests/functions.sh b/tests/functions.sh
+index 5246605..b24dc15 100644
+--- a/tests/functions.sh
++++ b/tests/functions.sh
+@@ -320,7 +320,7 @@ function ts_init_subtest {
+
+ if [ "$TS_PARSABLE" != "yes" ]; then
+ [ $TS_NSUBTESTS -eq 1 ] && echo
+- printf "%16s: %-27s ..." "" "$TS_SUBNAME"
++ printf "%13s: %-30s ..." "$TS_COMPONENT" "$TS_SUBNAME"
+ fi
+ }
+
+--
+2.8.3
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/ptest.patch b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/ptest.patch
new file mode 100644
index 000000000..0537f7d85
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/ptest.patch
@@ -0,0 +1,23 @@
+Define TESTS variable
+
+Signed-off-by: Tudor Florea <tudor.florea@enea.com>
+Upstream-Status: Pending
+---
+ Makefile.am | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/Makefile.am b/Makefile.am
+index bbaccb1..7d5a6bb 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -48,6 +48,7 @@ systemdsystemunit_DATA =
+ dist_bashcompletion_DATA =
+ check_PROGRAMS =
+ dist_check_SCRIPTS =
++TESTS = $(check_PROGRAMS)
+
+ PATHFILES =
+
+--
+2.8.3
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/run-ptest b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/run-ptest
new file mode 100644
index 000000000..e135ee583
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/run-ptest
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+
+# When udevd (from eudev) is running most eject/mount tests will fail because
+# of automount. We need to stop udevd before executing util-linux's tests.
+# The systemd-udevd daemon doesn't change the outcome of util-linux's tests.
+UDEV_PID="`pidof "@base_sbindir@/udevd"`"
+if [ "x$UDEV_PID" != "x" ]; then
+ /etc/init.d/udev stop
+fi
+
+current_path=$(readlink -f $0)
+export bindir=$(dirname $current_path)
+export PATH=$bindir/bin:$PATH
+
+cd tests || exit 1
+
+comps=$(find ts/ -type f -perm -111 -regex ".*/[^\.~]*" | sort)
+
+
+echo
+echo "-------------------- util-linux regression tests --------------------"
+echo
+echo " For development purpose only. "
+echo " Don't execute on production system! "
+echo
+
+res=0
+count=0
+for ts in $comps;
+do
+ $ts | sed -u '{
+ s/^\(.*\):\(.*\) \.\.\. OK$/PASS: \1:\2/
+ s/^\(.*\):\(.*\) \.\.\. FAILED \(.*\)$/FAIL: \1:\2 \3/
+ s/^\(.*\):\(.*\) \.\.\. SKIPPED \(.*\)$/SKIP: \1:\2 \3/
+ }'
+done
+
+
+if [ "x$UDEV_PID" != "x" ]; then
+ /etc/init.d/udev start
+fi
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser-l.pamd b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser-l.pamd
new file mode 100644
index 000000000..4b368ccf5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser-l.pamd
@@ -0,0 +1,3 @@
+auth include runuser
+session optional pam_keyinit.so force revoke
+session include runuser
diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser.pamd b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser.pamd
new file mode 100644
index 000000000..48d133b9e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd/runuser.pamd
@@ -0,0 +1,4 @@
+auth sufficient pam_rootok.so
+session optional pam_keyinit.so revoke
+session required pam_limits.so
+session required pam_unix.so
diff --git a/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd_2.34.bb b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd_2.34.bb
new file mode 100644
index 000000000..b58628667
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/logger-systemd/logger-systemd_2.34.bb
@@ -0,0 +1,12 @@
+require logger-systemd.inc
+
+SRC_URI += "file://configure-sbindir.patch \
+ file://runuser.pamd \
+ file://runuser-l.pamd \
+ file://ptest.patch \
+ file://run-ptest \
+ file://display_testname_for_subtest.patch \
+ file://avoid_parallel_tests.patch \
+"
+SRC_URI[md5sum] = "a78cbeaed9c39094b96a48ba8f891d50"
+SRC_URI[sha256sum] = "743f9d0c7252b6db246b659c1e1ce0bd45d8d4508b4dfa427bbb4a3e9b9f62b5" \ No newline at end of file
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..f8e5505ef
--- /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;nobranch=1"
+
+# 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-sync/nv-sync/nv-sync.service b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync.service
new file mode 100644
index 000000000..f5210dd5b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync/nv-sync.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Overlay sync to NV storage
+
+[Service]
+# Run rsync periodically to sync the overlay to NV storage
+ExecStart=bash -c 'while true; do rsync -a --delete /tmp/.overlay/ /tmp/.rwfs/.overlay; sync /tmp/.rwfs/.overlay; sleep 10; done'
+# On shutdown, archive the bash history so we don't lose it and run one last sync
+ExecStop=bash -c 'history -a; rsync -a --delete /tmp/.overlay/ /tmp/.rwfs/.overlay; sync /tmp/.rwfs/.overlay; sleep 5'
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync_git.bb b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync_git.bb
new file mode 100644
index 000000000..0ee70e880
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/nv-sync/nv-sync_git.bb
@@ -0,0 +1,20 @@
+SUMMARY = "NV Overlay Sync"
+DESCRIPTION = "Script to periodically sync the overlay to NV storage"
+
+S = "${WORKDIR}"
+SRC_URI = "file://nv-sync.service \
+"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+inherit systemd
+
+FILES_${PN} += "${systemd_system_unitdir}/nv-sync.service"
+
+do_install() {
+ install -d ${D}${systemd_system_unitdir}
+ install -m 0644 ${WORKDIR}/nv-sync.service ${D}${systemd_system_unitdir}
+}
+
+SYSTEMD_SERVICE_${PN} += " nv-sync.service"
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..a47d923f8
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/os-release/os-release.bbappend
@@ -0,0 +1,34 @@
+# 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!
+
+require version-vars.inc
+
+OS_RELEASE_FIELDS_append = " OPENBMC_VERSION IPMI_MAJOR IPMI_MINOR IPMI_AUX13 IPMI_AUX14 IPMI_AUX15 IPMI_AUX16"
+
+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/os-release/version-vars.inc b/meta-openbmc-mods/meta-common/recipes-core/os-release/version-vars.inc
new file mode 100644
index 000000000..0c8f3be56
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/os-release/version-vars.inc
@@ -0,0 +1,78 @@
+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() {
+ import re
+
+ gen = d.getVar('PRODUCT_GENERATION', True)
+ if gen is None:
+ gen = 'unknown'
+
+ corebase = d.getVar('COREBASE', True)
+ mibase = os.path.join(corebase, 'meta-openbmc-mods')
+ obmc_vers = irun_git(d, corebase, 'describe --dirty --long')
+ if obmc_vers is None:
+ raise bb.build.FuncFailed("Missing version tag for openbmc-openbmc")
+ d.setVar('OPENBMC_VERSION', obmc_vers)
+
+ obmc_hash = irun_git(d, corebase, 'rev-parse HEAD')
+ meta_vers = irun_git(d, mibase,
+ 'describe --long --abbrev=6 ' +
+ '--match \'{}-[0-9]*\.[0-9]*\''.format(gen))
+
+ # Until tags in meta-openbmc-mods, interim measure keep builds working.
+ if meta_vers.startswith('fatal:'):
+ meta_vers = '{}-0.0-0'.format(gen)
+
+ meta_hash = irun_git(d, mibase, 'rev-parse HEAD')
+ version_id = '{}-{}'.format(meta_vers, obmc_hash[0:7])
+ if version_id:
+ d.setVar('VERSION_ID', version_id)
+ versionList = version_id.split('-')
+ versionList = re.split('-|\.', version_id)
+ version = '{}.{}-{}'.format(versionList[0], versionList[1], versionList[2])
+ d.setVar('VERSION', version)
+ d.setVar('IPMI_MAJOR', versionList[1])
+ d.setVar('IPMI_MINOR', versionList[2])
+ d.setVar('IPMI_AUX13', hex(min(int(versionList[3]), 0xff)))
+ d.setVar('IPMI_AUX14', '0x{}'.format(meta_hash[0:2]))
+ d.setVar('IPMI_AUX15', '0x{}'.format(meta_hash[2:4]))
+ d.setVar('IPMI_AUX16', '0x{}'.format(meta_hash[4:6]))
+
+ build_id = irun_git(d, mibase, 'describe --abbrev=0')
+ if build_id:
+ d.setVar('BUILD_ID', build_id)
+}
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..4bf1c9548
--- /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://github.com/Intel-BMC/at-scale-debug;protocol=ssh"
+
+DEPENDS = "boost sdbusplus libpeci"
+
+PV = "0.1+git${SRCPV}"
+SRCREV = "98c33cdb7d704a387edee4ac8f0ef98ea771b222"
+
+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/safec/safec_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/safec/safec_%.bbappend
new file mode 100644
index 000000000..4ce29534d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/safec/safec_%.bbappend
@@ -0,0 +1,11 @@
+RDEPENDS_${PN} = ""
+do_install_append() {
+ F=$(find ${D} -name check_for_unsafe_apis)
+ if [ -n "${F}" ]; then
+ # remove the unused perl script
+ rm -f "${F}"
+ # remove the script's destination directory, only if it is empty
+ rmdir "$(dirname ${F})" 2>/dev/null || :
+ fi
+}
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/safec/safec_3.4.bb b/meta-openbmc-mods/meta-common/recipes-core/safec/safec_3.4.bb
new file mode 100644
index 000000000..449dcf04d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/safec/safec_3.4.bb
@@ -0,0 +1,15 @@
+SUMMARY = "Safe C Library"
+
+LICENSE = "safec"
+LIC_FILES_CHKSUM = "file://COPYING;md5=6d0eb7dfc57806a006fcbc4e389cf164"
+SECTION = "lib"
+
+inherit autotools pkgconfig
+
+S = "${WORKDIR}/git"
+SRCREV = "a7da29dadadde04feec174f595b59d67a64f3956"
+SRC_URI = "git://github.com/rurban/safeclib.git"
+
+COMPATIBLE_HOST = '(x86_64|i.86|powerpc|powerpc64|arm|aarch64).*-linux'
+
+RDEPENDS_${PN} = "perl"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check.bb b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check.bb
new file mode 100644
index 000000000..cfea1a910
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check.bb
@@ -0,0 +1,26 @@
+SUMMARY = "Security registers check"
+DESCRIPTION = "script tool to check if registers value are security \
+ log the security event to systemd journal, and also log to redfish \
+ "
+
+S = "${WORKDIR}"
+SRC_URI = "file://security-registers-check.sh \
+ file://security-registers-check.service \
+"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+RDEPENDS_${PN} += "bash logger-systemd"
+
+inherit systemd
+
+FILES_${PN} += "${systemd_system_unitdir}/security-registers-check.service"
+
+do_install() {
+ install -d ${D}${systemd_system_unitdir}
+ install -m 0644 ${WORKDIR}/security-registers-check.service ${D}${systemd_system_unitdir}
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/security-registers-check.sh ${D}/${bindir}/security-registers-check.sh
+}
+
+SYSTEMD_SERVICE_${PN} += " security-registers-check.service"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.service b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.service
new file mode 100644
index 000000000..b824dbe3e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Check for security registers
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/security-registers-check.sh
+Nice=5
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.sh b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.sh
new file mode 100644
index 000000000..211120c78
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/security-registers-check/security-registers-check/security-registers-check.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+value=`cat /sys/devices/platform/ahb/ahb:apb/1e6e2000.syscon/1e6e2000.syscon:misc_control/uart_port_debug`
+if [ $value == 0 ]
+ then
+ # log the detailed last security registers check messages
+ logger -t security-registers-check "Uart port debug is enabled! Log as following:"
+ echo "Uart port debug is enabled." | logger
+ # Also log it to redfish
+ cat <<EOF | logger-systemd --journald
+REDFISH_MESSAGE_ID=OpenBMC.0.1.SecurityUartPortDebugEnabled
+PRIORITY=4
+MESSAGE=BMC Uart port debug is enabled
+EOF
+fi
+
+value=`cat /sys/devices/platform/ahb/ahb:apb/1e6e2000.syscon/1e6e2000.syscon:misc_control/p2a-bridge`
+if [ $value == 1 ]
+ then
+ # log the detailed last security registers check messages
+ logger -t security-registers-check "P2A(PCIe to AHB) bridge is enabled! Log as following:"
+ echo "P2A(PCIe to AHB) bridge is enabled." | logger
+ # Also log it to redfish
+ cat <<EOF | logger-systemd --journald
+REDFISH_MESSAGE_ID=OpenBMC.0.1.SecurityP2aBridgeEnabled
+PRIORITY=4
+MESSAGE=BMC P2A(PCIe to AHB) bridge is enabled
+EOF
+fi
+
+value=`cat /sys/devices/platform/ahb/ahb:apb/1e6e2000.syscon/1e6e2000.syscon:misc_control/boot-2nd-flash`
+if [ $value == 1 ]
+ then
+ # log the detailed last security registers check messages
+ logger -t security-registers-check "BMC 2nd boot flash is enabled! Log as following:"
+ echo "BMC 2nd boot flash is enabled." | logger
+ # Also log it to redfish
+ cat <<EOF | logger-systemd --journald
+REDFISH_MESSAGE_ID=OpenBMC.0.1.SecurityBoot2ndFlashEnabled
+PRIORITY=4
+MESSAGE=BMC 2nd boot flash is enabled
+EOF
+fi
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..3d4e594a4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/obmc-targets.bbappend
@@ -0,0 +1,10 @@
+# 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-shutdown@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-host-reboot@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-host-startmin@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-poweron@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-poweroff@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-hard-poweroff@.target"
+SYSTEMD_SERVICE_${PN}_remove += " obmc-chassis-powerreset@.target"
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf
new file mode 100644
index 000000000..48c60d36b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/journald.conf
@@ -0,0 +1,42 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
+#
+# See journald.conf(5) for details.
+
+[Journal]
+Storage=volatile
+#Compress=yes
+#Seal=yes
+#SplitMode=uid
+#SyncIntervalSec=5m
+#RateLimitIntervalSec=30s
+#RateLimitBurst=10000
+#SystemMaxUse=6M
+#SystemKeepFree=
+#SystemMaxFileSize=512K
+#SystemMaxFiles=32
+RuntimeMaxUse=32M
+#RuntimeKeepFree=
+#RuntimeMaxFileSize=
+#RuntimeMaxFiles=4
+#MaxRetentionSec=
+#MaxFileSec=1month
+#ForwardToSyslog=no
+#ForwardToKMsg=no
+#ForwardToConsole=no
+#ForwardToWall=yes
+#TTYPath=/dev/console
+#MaxLevelStore=notice
+#MaxLevelSyslog=debug
+#MaxLevelKMsg=notice
+#MaxLevelConsole=info
+#MaxLevelWall=emerg
+#LineMax=48K
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf
new file mode 100644
index 000000000..aa455cbcb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf/systemd-timesyncd-save-time.conf
@@ -0,0 +1,2 @@
+[Service]
+ExecStop=touch /var/lib/systemd/timesync/clock \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf_%.bbappend b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf_%.bbappend
new file mode 100644
index 000000000..b3c318e15
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd-conf_%.bbappend
@@ -0,0 +1,11 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://journald.conf \
+ file://systemd-timesyncd-save-time.conf \
+ "
+
+FILES_${PN} += " ${systemd_system_unitdir}/systemd-timesyncd.service.d/systemd-timesyncd-save-time.conf"
+
+do_install_append() {
+ install -m 644 -D ${WORKDIR}/systemd-timesyncd-save-time.conf ${D}${systemd_system_unitdir}/systemd-timesyncd.service.d/systemd-timesyncd-save-time.conf
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/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..5b9f17006
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch
@@ -0,0 +1,28 @@
+From e02932693f92d6230b5520f431e127f7b6e2183e 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.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/core/system.conf.in b/src/core/system.conf.in
+index 8112125468..f7a35a56bb 100644
+--- a/src/core/system.conf.in
++++ b/src/core/system.conf.in
+@@ -39,7 +39,7 @@
+ #DefaultStandardOutput=journal
+ #DefaultStandardError=inherit
+ #DefaultTimeoutStartSec=90s
+-#DefaultTimeoutStopSec=90s
++DefaultTimeoutStopSec=10s
+ #DefaultTimeoutAbortSec=
+ #DefaultRestartSec=100ms
+ #DefaultStartLimitIntervalSec=10s
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0002-Disable-LLMNR-port-5355.patch b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0002-Disable-LLMNR-port-5355.patch
new file mode 100644
index 000000000..8b978e4fb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/0002-Disable-LLMNR-port-5355.patch
@@ -0,0 +1,26 @@
+From 9fb05323291ccdfbf19ac0d9428e366d6023b408 Mon Sep 17 00:00:00 2001
+From: Karthick Sundarrajan <karthick.sundarrajan@intel.com>
+Date: Fri, 3 Apr 2020 10:23:41 -0700
+Subject: [PATCH] Disable LLMNR (port 5355)
+
+As part of OS hardening process, the port has to be
+disabled.
+
+Signed-off-by: Karthick Sundarrajan <karthick.sundarrajan@intel.com>
+---
+ src/resolve/resolved.conf.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in
+index 6898c78..a9125fd 100644
+--- a/src/resolve/resolved.conf.in
++++ b/src/resolve/resolved.conf.in
+@@ -15,7 +15,7 @@
+ #DNS=
+ #FallbackDNS=@DNS_SERVERS@
+ #Domains=
+-#LLMNR=yes
++LLMNR=no
+ #MulticastDNS=yes
+ #DNSSEC=@DEFAULT_DNSSEC_MODE@
+ #DNSOverTLS=@DEFAULT_DNS_OVER_TLS_MODE@
diff --git a/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/systemd-time-wait-sync.service b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/systemd-time-wait-sync.service
new file mode 100644
index 000000000..f71aea39d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd/systemd-time-wait-sync.service
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Wait Until Kernel Time Synchronized
+Documentation=man:systemd-time-wait-sync.service(8)
+
+# Note that this tool doesn't need CAP_SYS_TIME itself, but it's primary
+# usecase is to run in conjunction with a local NTP service such as
+# systemd-timesyncd.service, which is conditioned this way. There might be
+# niche usecases where running this service independently is desired, but let's
+# make this all "just work" for the general case, and leave it to local
+# modifications to make it work in the remaining cases.
+
+ConditionCapability=CAP_SYS_TIME
+ConditionVirtualization=!container
+
+DefaultDependencies=no
+Before=time-sync.target shutdown.target
+Wants=time-sync.target
+Conflicts=shutdown.target
+
+[Service]
+Type=oneshot
+ExecStart=/lib/systemd/systemd-time-wait-sync
+TimeoutStartSec=10
+RemainAfterExit=yes
+
+[Install]
+WantedBy=sysinit.target
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..17f423dc3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-core/systemd/systemd_%.bbappend
@@ -0,0 +1,16 @@
+# add some configuration overrides for systemd default /usr/lib/tmpfiles.d/
+
+LICENSE = "GPL-2.0"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://0001-Modfiy-system.conf-DefaultTimeoutStopSec.patch \
+ file://0002-Disable-LLMNR-port-5355.patch \
+ file://systemd-time-wait-sync.service \
+ "
+
+USERADD_PACKAGES_remove = "${PN}-journal-gateway ${PN}-journal-upload ${PN}-journal-remote"
+
+do_install_append(){
+ cp -f ${WORKDIR}/systemd-time-wait-sync.service ${D}/lib/systemd/system/
+}
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..7e9d2f195
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-devtools/mtd-util/mtd-util.bb
@@ -0,0 +1,21 @@
+DESCRIPTION = "OpenBMC mtd-util"
+
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://COPYING;md5=b77c43ae4eaf67bd73fb6452b2f113a3"
+
+SRC_URI = "git://github.com/Intel-BMC/mtd-util;protocol=ssh"
+
+PV = "1.0+git${SRCPV}"
+SRCREV = "69016601a521a95732cc49a3f4c8c7fe4b0ee058"
+
+
+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 = ""
+
+EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '-DDEVELOPER_OPTIONS=ON', '', d)}"
diff --git a/meta-openbmc-mods/meta-common/recipes-devtools/python/python_%.bbappend b/meta-openbmc-mods/meta-common/recipes-devtools/python/python_%.bbappend
new file mode 100644
index 000000000..00815c173
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-devtools/python/python_%.bbappend
@@ -0,0 +1,7 @@
+# This commit pulls in the python world, and adds a very large chunk to our
+# image size. I suspect we can make most of our things rely on python-core
+# instead of full python, but this is a temporary fix.
+# https://git.yoctoproject.org/cgit/cgit.cgi/poky/commit/?id=f384e39ad1ca1514fb7b5d7fa0d63e0c863761ca
+
+RPROVIDES_${PN}-core = "${PN}"
+RPROVIDES_${PN}-modules = ""
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..50476715e
--- /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://github.com/Intel-BMC/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-extended/pam/pam-ipmi_%.bbappend b/meta-openbmc-mods/meta-common/recipes-extended/pam/pam-ipmi_%.bbappend
new file mode 100644
index 000000000..08f8c58b0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/pam/pam-ipmi_%.bbappend
@@ -0,0 +1,7 @@
+do_install_append () {
+# Remove ipmi_pass from image, if debug-tweaks is not enabled
+ ${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', '', 'rm ${D}/${sysconfdir}/ipmi_pass', d)}
+}
+
+# latest upstream HEAD until meta-phosphor autobumps
+SRCREV = "c2ef3319b42d86862b479e08e652ab36a26a14db"
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow/pam.d/login b/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow/pam.d/login
new file mode 100644
index 000000000..51dd3a83b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow/pam.d/login
@@ -0,0 +1,90 @@
+#
+# The PAM configuration file for the Shadow `login' service
+#
+
+# Enforce a minimal delay in case of failure (in microseconds).
+# (Replaces the `FAIL_DELAY' setting from login.defs)
+# Note that other modules may require another minimal delay. (for example,
+# to disable any delay, you should add the nodelay option to pam_unix)
+auth optional pam_faildelay.so delay=3000000
+
+# Outputs an issue file prior to each login prompt (Replaces the
+# ISSUE_FILE option from login.defs). Uncomment for use
+# auth required pam_issue.so issue=/etc/issue
+
+# Disallows root logins except on tty's listed in /etc/securetty
+# (Replaces the `CONSOLE' setting from login.defs)
+# Note that it is included as a "requisite" module. No password prompts will
+# be displayed if this module fails to avoid having the root password
+# transmitted on unsecure ttys.
+# You can change it to a "required" module if you think it permits to
+# guess valid user names of your system (invalid user names are considered
+# as possibly being root).
+auth [success=ok ignore=ignore user_unknown=ignore default=die] pam_securetty.so
+
+# Disallows other than root logins when /etc/nologin exists
+# (Replaces the `NOLOGINS_FILE' option from login.defs)
+auth requisite pam_nologin.so
+
+# This module parses environment configuration file(s)
+# and also allows you to use an extended config
+# file /etc/security/pam_env.conf.
+#
+# parsing /etc/environment needs "readenv=1"
+session required pam_env.so readenv=1
+
+# Allow only uid 0 for login prompt authentication
+auth required pam_succeed_if.so uid eq 0
+
+# Do regular pam unix based authentication. Allow null password.
+auth [success=2 default=ignore] pam_unix.so quiet nullok_secure
+# here's the fallback if no module succeeds
+auth requisite pam_deny.so
+# prime the stack with a positive return value if there isn't one already;
+# this avoids us returning an error just because nothing sets a success code
+# since the modules above will each just jump around
+auth required pam_permit.so
+
+# This allows certain extra groups to be granted to a user
+# based on things like time of day, tty, service, and user.
+# Please edit /etc/security/group.conf to fit your needs
+# (Replaces the `CONSOLE_GROUPS' option in login.defs)
+auth optional pam_group.so
+
+# Uncomment and edit /etc/security/time.conf if you need to set
+# time restrainst on logins.
+# (Replaces the `PORTTIME_CHECKS_ENAB' option from login.defs
+# as well as /etc/porttime)
+# account requisite pam_time.so
+
+# Uncomment and edit /etc/security/access.conf if you need to
+# set access limits.
+# (Replaces /etc/login.access file)
+# account required pam_access.so
+
+# Sets up user limits according to /etc/security/limits.conf
+# (Replaces the use of /etc/limits in old login)
+session required pam_limits.so
+
+# Prints the last login info upon succesful login
+# (Replaces the `LASTLOG_ENAB' option from login.defs)
+session optional pam_lastlog.so
+
+# Prints the motd upon succesful login
+# (Replaces the `MOTD_FILE' option in login.defs)
+session optional pam_motd.so
+
+# Prints the status of the user's mailbox upon succesful login
+# (Replaces the `MAIL_CHECK_ENAB' option from login.defs).
+#
+# This also defines the MAIL environment variable
+# However, userdel also needs MAIL_DIR and MAIL_FILE variables
+# in /etc/login.defs to make sure that removing a user
+# also removes the user's mail spool file.
+# See comments in /etc/login.defs
+session optional pam_mail.so standard
+
+# Standard Un*x account and session
+account include common-account
+password include common-password
+session include common-session
diff --git a/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow_%.bbappend b/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow_%.bbappend
new file mode 100644
index 000000000..283d787e5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-extended/shadow/shadow_%.bbappend
@@ -0,0 +1,4 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+PAM_SRC_URI += "file://pam.d/login \
+ "
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..741ac3715
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend
@@ -0,0 +1,5 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+
+# Use the latest to support obmc-ikvm properly
+#SRC_URI = "git://github.com/LibVNC/libvncserver"
+SRCREV = "9409a6e6aaeaff9dc36f71c21ba5b81b10d44ace"
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch
new file mode 100644
index 000000000..43600ac8a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch
@@ -0,0 +1,162 @@
+From 0c0b7b5da551c99161bda98820a529ba29cbaac1 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+Date: Wed, 21 Aug 2019 16:52:30 -0700
+Subject: [PATCH] Fix keyboard and mouse input events dropping issue
+
+Restarting of HID input devices causes input events dropping issue
+which is critical for BMC KVM uses. For an example, user can't enter
+to BIOS by doing keep pressing 'F2' or 'Del' key because of this issue.
+
+To fix the issue, this commit removes the input device restarting
+logic and refines error log journaling logic using errno checking.
+
+Tested:
+ 1. Open BMCweb -> Server control -> KVM.
+ 2. Make a host reset and keep pressing 'F2' key.
+ 3. Was able to enter to BIOS using the key press.
+
+Change-Id: Iec1bfad1d9e5825858844cab658bbfa3e6bc24f6
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+---
+ ikvm_input.cpp | 58 +++++++---------------------------------------------------
+ ikvm_input.hpp | 4 ----
+ ikvm_video.cpp | 3 +--
+ 3 files changed, 8 insertions(+), 57 deletions(-)
+
+diff --git a/ikvm_input.cpp b/ikvm_input.cpp
+index d95e6313f62c..df12f2715585 100644
+--- a/ikvm_input.cpp
++++ b/ikvm_input.cpp
+@@ -23,9 +23,9 @@ using namespace phosphor::logging;
+ using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
+
+ Input::Input(const std::string& kbdPath, const std::string& ptrPath) :
+- pointerError(false), sendKeyboard(false), sendPointer(false),
+- keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0},
+- keyboardPath(kbdPath), pointerPath(ptrPath)
++ sendKeyboard(false), sendPointer(false), keyboardFd(-1), pointerFd(-1),
++ keyboardReport{0}, pointerReport{0}, keyboardPath(kbdPath),
++ pointerPath(ptrPath)
+ {
+ if (!keyboardPath.empty())
+ {
+@@ -156,36 +156,6 @@ void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl)
+ rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
+ }
+
+-void Input::restart()
+-{
+- if (!keyboardPath.empty() && keyboardFd < 0)
+- {
+- 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)));
+- }
+-
+- sendKeyboard = false;
+- }
+-
+- if (!pointerPath.empty() && pointerFd < 0)
+- {
+- pointerFd = open(pointerPath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
+- if (pointerFd < 0)
+- {
+- log<level::ERR>("Failed to open input device",
+- entry("PATH=%s", pointerPath.c_str()),
+- entry("ERROR=%s", strerror(errno)));
+- }
+-
+- pointerError = false;
+- sendPointer = false;
+- }
+-}
+-
+ void Input::sendWakeupPacket()
+ {
+ uint8_t wakeupReport[KEY_REPORT_LENGTH] = {0};
+@@ -459,13 +429,10 @@ bool Input::writeKeyboard(const uint8_t *report)
+ {
+ if (write(keyboardFd, report, KEY_REPORT_LENGTH) != KEY_REPORT_LENGTH)
+ {
+- log<level::ERR>("Failed to write keyboard report",
+- entry("ERROR=%s", strerror(errno)));
+-
+- if (errno == ESHUTDOWN)
++ if (errno != ESHUTDOWN && errno != EAGAIN)
+ {
+- close(keyboardFd);
+- keyboardFd = -1;
++ log<level::ERR>("Failed to write keyboard report",
++ entry("ERROR=%s", strerror(errno)));
+ }
+
+ return false;
+@@ -478,23 +445,12 @@ void Input::writePointer(const uint8_t *report)
+ {
+ if (write(pointerFd, report, PTR_REPORT_LENGTH) != PTR_REPORT_LENGTH)
+ {
+- if (!pointerError)
++ if (errno != ESHUTDOWN && errno != EAGAIN)
+ {
+ log<level::ERR>("Failed to write pointer report",
+ entry("ERROR=%s", strerror(errno)));
+- pointerError = true;
+- }
+-
+- if (errno == ESHUTDOWN)
+- {
+- close(pointerFd);
+- pointerFd = -1;
+ }
+ }
+- else
+- {
+- pointerError = false;
+- }
+ }
+
+ } // namespace ikvm
+diff --git a/ikvm_input.hpp b/ikvm_input.hpp
+index 953333263e2d..2adc7c106755 100644
+--- a/ikvm_input.hpp
++++ b/ikvm_input.hpp
+@@ -48,8 +48,6 @@ class Input
+ */
+ static void pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl);
+
+- /* @brief Re-opens USB device in case the endpoint shutdown */
+- void restart();
+ /* @brief Sends a wakeup data packet to the USB input device */
+ void sendWakeupPacket();
+ /* @brief Sends an HID report to the USB input device */
+@@ -90,8 +88,6 @@ class Input
+ bool writeKeyboard(const uint8_t *report);
+ void writePointer(const uint8_t *report);
+
+- /* @brief Indicates whether or not a pointer report error has occurred */
+- bool pointerError;
+ /* @brief Indicates whether or not to send a keyboard report */
+ bool sendKeyboard;
+ /* @brief Indicates whether or not to send a pointer report */
+diff --git a/ikvm_video.cpp b/ikvm_video.cpp
+index 6a5aa6c10927..7bd4b4eb6c98 100644
+--- a/ikvm_video.cpp
++++ b/ikvm_video.cpp
+@@ -163,10 +163,9 @@ bool Video::needsResize()
+ restart();
+ return false;
+ }
+- else if (timingsError)
++ else
+ {
+ timingsError = false;
+- input.restart();
+ }
+
+ if (timings.bt.width != width || timings.bt.height != height)
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend
new file mode 100644
index 000000000..8de421d18
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend
@@ -0,0 +1,8 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+
+#SRC_URI = "git://github.com/openbmc/obmc-ikvm"
+SRCREV = "861337e8ec92767c4c88237ec5db494a2a67fa8d"
+
+SRC_URI += " \
+ file://0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/host-misc-comm-manager/host-misc-comm-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-intel/host-misc-comm-manager/host-misc-comm-manager_git.bb
new file mode 100644
index 000000000..604ee8068
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/host-misc-comm-manager/host-misc-comm-manager_git.bb
@@ -0,0 +1,19 @@
+SUMMARY = "Miscellaneous host interface communication manager"
+DESCRIPTION = "Daemon exposes Miscellaneous host interface communications like \
+ platform reset, mail box & scratch pad"
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SRC_URI = "git://github.com/Intel-BMC/host-misc-comm-manager.git;protocol=ssh"
+
+SRCREV = "2f7be710dea914b975bfb20a9d7a466da85f88cc"
+
+inherit cmake systemd
+SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.Host.Misc.Manager.service"
+
+DEPENDS = "boost sdbusplus phosphor-logging"
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb
new file mode 100644
index 000000000..b6fa1c9ea
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/hsbp/hsbp-manager_git.bb
@@ -0,0 +1,21 @@
+SUMMARY = "HSBP Manager"
+DESCRIPTION = "HSBP Manager monitors HSBPs through SMBUS"
+
+SRC_URI = "git://github.com/openbmc/s2600wf-misc.git"
+SRCREV = "da0c35fce8b53c1fba05b253c2e24effbbd97197"
+PV = "0.1+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
+
+SYSTEMD_SERVICE_${PN} = "hsbp-manager.service"
+
+DEPENDS = "boost \
+ i2c-tools \
+ sdbusplus"
+
+S = "${WORKDIR}/git/hsbp-manager"
+inherit cmake systemd
+
+EXTRA_OECMAKE = "-DYOCTO=1"
+
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..71245ac50
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/images/intel-platforms.bb
@@ -0,0 +1,18 @@
+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
+inherit ${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'image_types_intel_pfr', '', d)}
+
+DEPENDS += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'obmc-intel-pfr-image-native', '', d)}"
+DEPENDS += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'intel-pfr-manager', '', d)}"
+
+FEATURE_PACKAGES_obmc-sensors = ""
+FEATURE_PACKAGES_obmc-debug-collector = ""
+
+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/intel-pfr/files/pfr_image.py b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py
new file mode 100755
index 000000000..438a3b91f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/pfr_image.py
@@ -0,0 +1,385 @@
+#!/usr/bin/env python3
+# coding: utf-8
+# our image is contained as parts, including the hash
+# then it gets zipped up and signed again
+
+# this internal signature is for boot and recovery, but
+# will be checked prior to writing to flash as well.
+
+# the internal signature format is a PFR-specific block
+# including a hash bitmap, certificates (public keys),
+# and the actual signature data as well, for both active
+# and recovery images
+
+# TODO: figure out if active and recovery actually have different sigs
+# TODO: build hashmap from payload manifest
+# TODO: figure out exact struct layout for PFR metadata
+import os, hashlib, struct, json, sys, subprocess, mmap, io, array, binascii, copy, shutil, re
+from array import array
+from binascii import unhexlify
+from hashlib import sha1, sha256, sha384, sha512
+from shutil import copyfile
+# Flash Map
+# -----------------------------------------------
+# Start addr Contents
+# 0x00000000 S U-Boot
+# 0x00080000 S+ PFM
+# 0x000a0000 U U-boot Env
+# 0x000C0000 U SOFS
+# 0x002c0000 U RWFS
+# 0x00b00000 S fit-image
+# 0x02a00000 S+ rc-image
+# 0x04a00000 U staging-image
+# * partially signed (not full 64k page)
+# + unsigned, owned by pfr
+
+# TODO: The below defines should go to manifest files.
+# Keeping it here hard coded for now.
+# The pages to be skipped for HASH and PBC
+# Pages: 0x80 to 0x9f - starting PFM region until end of pfm
+# Pages: 0x2a00 to 0x7FFF - starting RC-image until end of flash
+EXCLUDE_PAGES =[[0x80, 0x9f],[0x2a00,0x7fff]]
+
+# SPI PFM globals
+PFM_OFFSET = 0x80000
+PFM_SPI = 0x1
+PFM_I2C = 0x2
+SHA = 0x1
+PFM_DEF_SIZE = 32 # 32 bytes of PFM header
+PFM_SPI_SIZE_DEF = 16 # 16 bytes of SPI PFM
+PFM_SPI_SIZE_HASH = 32 # 32 bytes of SPI region HASH
+PFM_I2C_SIZE = 40 # 40 bytes of i2c rules region in PFM
+
+PAGE_SIZE = 0x1000 # 4KB size of page
+
+def load_manifest(fname):
+ manifest = {}
+ with open(fname, 'r') as fd:
+ manifest = json.load(fd)
+ return manifest
+
+class pfm_spi(object):
+
+ def __init__(self, prot_mask, start_addr, end_addr, hash, hash_pres):
+ self.spi_pfm = PFM_SPI
+ self.spi_prot_mask = prot_mask
+ self.spi_hash_pres = hash_pres
+ if hash_pres != 0:
+ self.spi_hash = hash
+ self.spi_pfm_rsvd = 0xffffffff # b'\xff'*4
+ self.spi_start_addr = start_addr
+ self.spi_end_addr = end_addr
+
+class pfm_i2c(object):
+
+ def __init__(self, bus_id, rule_id, address, cmd_map):
+ self.i2c_pfm = PFM_I2C
+ self.i2c_pfm_rsvd = 0xffffffff # b'\xff'*4
+ self.i2c_bus_id = bus_id
+ self.i2c_rule_id = rule_id
+ self.i2c_address = address
+ self.i2c_cmd_whitelist = cmd_map
+
+class pfr_bmc_image(object):
+
+# json_file, firmware_file
+ def __init__(self, manifest, firmware_file, build_ver, build_num, build_hash, sha):
+
+ self.manifest = load_manifest(manifest)
+ self.firmware_file = firmware_file
+ self.build_version = build_ver
+ self.build_number = build_num
+ self.build_hash = build_hash
+ self.sha = sha
+ if self.sha == "2":
+ SHA = 0x2
+ PFM_SPI_SIZE_HASH = 48
+ if self.sha == "1":
+ PFM_SPI_SIZE_HASH = 32
+ SHA = 0x1
+ self.pfr_rom_file = 'image-mtd-pfr'
+ open(self.pfr_rom_file, 'a').close()
+
+ self.page_size = PAGE_SIZE
+ self.empty = b'\xff' * self.page_size
+
+ self.image_parts = []
+ for p in self.manifest['image-parts']:
+ # the json should have in the order- filename, index, offset, size and protection byte
+ self.image_parts.append((p['name'], p['index'], p['offset'], p['size'], p['prot_mask'], p['pfm'], p['hash'], p['compress']))
+ if self.sha == "1":
+ self.act_dgst = hashlib.sha256()
+ if self.sha == "2":
+ self.act_dgst = hashlib.sha384()
+ # SPI regions PFM array
+ self.pfm_spi_regions = []
+ self.pfm_bytes = PFM_DEF_SIZE # PFM definition bytes (SPI regions + SMBUS)
+
+ # hash, erase and compression bit maps for 128MB
+ self.pbc_erase_bitmap = bytearray(4096)
+ self.pbc_comp_bitmap = bytearray(4096)
+
+ self.pbc_comp_payload = 0
+ self.sec_rev = 1
+
+ # fill in the calculated data
+ self.hash_and_map()
+
+ self.i2c_rules = []
+ for i in self.manifest['i2c-rules']:
+ # the json should have in the order- bus-id, rule-id, address, size and cmd-whitelist
+ self.i2c_rules.append((i['bus-id'], i['rule-id'], i['address'], i['cmd-whitelist']))
+
+ # I2C rules PFM array
+ self.pfm_i2c_rules = []
+
+ # Generate the i2c rules
+ self.build_i2c_rules()
+
+ # Generate PFM region binary - pfm.bin
+ self.build_pfm()
+ print("PFM build done")
+
+ # Generate PBC region - pbc.bin
+ self.pbc_hdr()
+ print("PBC build done")
+
+ def hash_compress_regions(self, p, upd):
+
+ # JSON format as below
+ # 0. "name": <image region name>
+ # 1. "index": 1,
+ # 2. "offset": <start addr>,
+ # 3. "size": <size of the region>,
+ # 4. "prot_mask": <PFR protection mask>,
+ # 5. "pfm": <1|0 -add in PFM or not>,
+ # 6. "hash": <hashing of the region needed>,
+ # 7. "compress": <region to be compressed>
+
+ image_name = p[0]
+ start_addr = int(p[2],16) #image part start address
+ size = int(p[3],16) #size of the image part
+ pfm_prot_mask = p[4] # pfm protection mask
+ pfm_flag = p[5] # pfm needed?
+ hash_flag = p[6] #to be hashed?
+ compress = p[7] #compress flag
+ index = p[1] # image part index
+ # 1 page is 4KB
+ page = start_addr >> 12
+
+ with open(self.firmware_file, "rb") as f:
+ f.seek(start_addr)
+ skip = False
+
+ if hash_flag == 1:
+ if self.sha == "1":
+ hash_dgst = hashlib.sha256()
+ if self.sha == "2":
+ hash_dgst = hashlib.sha384()
+ for chunk in iter(lambda: f.read(self.page_size), b''):
+ chunk_len = len(chunk)
+ if chunk_len != self.page_size:
+ chunk = b''.join([chunk, b'\xff' * (self.page_size - chunk_len)])
+
+ for p in EXCLUDE_PAGES:
+ if (page >= p[0]) and (page <= p[1]):
+ #print("Exclude page={}".format(page))
+ skip = True
+ break
+
+ if not skip:
+ # add to the hash
+ if hash_flag == 1:
+ # HASH for the region
+ self.act_dgst.update(chunk)
+ hash_dgst.update(chunk)
+
+ if compress == 1:
+ self.pbc_erase_bitmap[page >> 3] |= 1 << (7- (page % 8)) # Big endian bit map
+ # add to the pbc map
+ if chunk != self.empty:
+ #print("compressed page ={}".format(page))
+ upd.write(chunk)
+ self.pbc_comp_bitmap[page >> 3] |= 1 << (7- (page % 8)) # Big Endian bit map
+ self.pbc_comp_payload += chunk_len # compressed payload bytes
+
+ page += 1
+
+ if (page * self.page_size) >= (size + start_addr):
+ break
+
+ if pfm_flag == 1:
+ self.pfm_bytes += PFM_SPI_SIZE_DEF
+
+ hash = bytearray(PFM_SPI_SIZE_HASH)
+ hash_pres = 0
+
+ if hash_flag == 1:
+ # region's hash
+ hash = hash_dgst.hexdigest()
+ hash_pres = SHA
+ self.pfm_bytes += PFM_SPI_SIZE_HASH
+
+ # append to SPI regions in PFM
+ self.pfm_spi_regions.append(pfm_spi(pfm_prot_mask, start_addr, (start_addr+size), hash, hash_pres))
+
+ def add_i2c_rules(self, i):
+ bus_id = i[0] # I2C Bus number
+ rule_id = i[1] # I2C rule number
+ addr = i[2] # I2C device address
+ cmds = i[3] # I2C white listed commands for which i2c write to be allowed
+ whitelist_map = bytearray(32)
+
+ self.pfm_bytes += PFM_I2C_SIZE # add upto PFM size
+
+ for c in cmds:
+ if c == "all":
+ for i in range(32):
+ whitelist_map[i] = 0xff
+ break
+ else:
+ idx = int(c,16) // 8 # index in the 32 bytes of white list i2c cmds
+ bit = int(c,16) % 8 # bit position to set
+ whitelist_map[idx] |= (1 << bit)
+
+ # append to I2C rules in PFM
+ self.pfm_i2c_rules.append(pfm_i2c(bus_id, rule_id, addr, whitelist_map))
+
+ def build_i2c_rules(self):
+ for i in self.i2c_rules:
+ self.add_i2c_rules(i)
+
+ def hash_and_map(self):
+
+ # have copy of the update file for appending with PFR meta and compression
+ copyfile(self.firmware_file, self.pfr_rom_file)
+ with open("bmc_compressed.bin", "wb+") as upd:
+ for p in self.image_parts:
+ #filename, index, offset, size, protection.
+ print(p[0], p[1], p[2], p[3], p[4])
+ self.hash_compress_regions(p, upd)
+
+ def pbc_hdr(self):
+ '''
+ typedef struct {
+ uint8_t tag[4]; /* PBC tag */
+ uint32_t version; /* PBC Version- 0x0000_0002 */
+ uint32_t page_size; /* NOR Flash page size = 0x0000_1000 */
+ uint32_t pattern_size; /* 0xFF as pattern 1byte = 0x0000_0001 */
+ uint32_t pattern; /* 0xFF pattern = 0x0000_00FF */
+ uint32_t bitmap_size; /* 32768 pages for 128MB- 0x0000_8000 */
+ uint32_t payload_length /* payload */
+ uint8_t reserved[100]; /* Reserved 100bytes */
+ uint8_t erase_bitmap[4096]; /* erase bit map for 32768 pages */
+ uint8_t comp_bitmap[4096]; /* compression bit map for 32768 pages */
+ uint8_t comp_payload; /* compressed payload */
+ '''
+ names = [
+ 'tag', 'pbc_ver', 'page_sz', 'pattern_sz', 'pattern', 'bitmap_sz',
+ 'payload_size', 'resvd0', 'erase_bitmap', 'comp_bitmap',
+ ]
+ parts = {
+ 'tag': b'CBP_',
+ 'pbc_ver': struct.pack('<i',0x00000002),
+ 'page_sz': struct.pack('<i',0x00001000),
+ 'pattern_sz': struct.pack('<i',0x00000001),
+ 'pattern': struct.pack('<i',0x000000FF),
+ 'bitmap_sz': struct.pack('<i',0x00008000),
+ 'payload_size': struct.pack('<i',self.pbc_comp_payload),
+ 'resvd0' : b'\x00'*100,
+ 'erase_bitmap': bytes(self.pbc_erase_bitmap),
+ 'comp_bitmap': bytes(self.pbc_comp_bitmap),
+ }
+
+ with open("pbc.bin", "wb+") as pbf:
+ pbf.write(b''.join([parts[n] for n in names]))
+ pbf.seek(0) # rewind to beginning of PBC file
+ self.act_dgst.update(pbf.read()) # add up PBC data for hashing
+
+ def build_pfm(self):
+ '''
+ typedef struct {
+ uint32_t tag; /* PFM_HDR_TAG above, no terminating null */
+ uint8_t SVN; /* SVN- security revision of associated image data */
+ uint8_t bkc; /* bkc */
+ uint8_t pfm_ver_major; /* PFM revision */
+ uint8_t pfm_ver_minor;
+ uint8_t reserved0[4];
+ uint8_t build_num;
+ uint8_t build_hash[3];
+ uint8_t reserved1[12]; /* reserved */
+ uint32_t pfm_length; /* PFM size in bytes */
+ pfm_spi pfm_spi[2]; /* PFM SPI regions - u-boot & fit-image */
+ pfm_smbus pfm_smbus[4]; /* defined smbus rules for PSUs and HSBP */
+ } __attribute__((packed)) pfm_hdr;
+ '''
+ names = [
+ 'tag', 'sec_rev', 'bkc', 'pfm_ver_major', 'pfm_ver_minor', 'resvd0', 'build_num', 'build_hash1', 'build_hash2', 'build_hash3', 'resvd1', 'pfm_len',
+ ]
+ parts = {
+ 'tag': struct.pack("<I", 0x02b3ce1d),
+ 'sec_rev': struct.pack('<B', self.sec_rev),
+ 'bkc': struct.pack('<B', 0x01),
+ 'pfm_ver_major': struct.pack('<B', ((int(self.build_version) >> 8) & 0xff)),
+ 'pfm_ver_minor': struct.pack('<B', (int(self.build_version) & 0x00ff)),
+ 'resvd0': b'\xff'* 4,
+ 'build_num': struct.pack('<B', int(self.build_number,16)),
+ 'build_hash1': struct.pack('<B', (int(self.build_hash) & 0xff)),
+ 'build_hash2': struct.pack('<B', ((int(self.build_hash) >> 8) & 0xff)),
+ 'build_hash3': struct.pack('<B', ((int(self.build_hash) >> 16) & 0xff)),
+ 'resvd1': b'\xff'* 12,
+ 'pfm_len': ''
+ }
+
+ # PFM should be 128bytes aligned, find the padding bytes
+ padding_bytes = 0
+ if (self.pfm_bytes % 128) != 0:
+ padding_bytes = 128 - (self.pfm_bytes % 128)
+
+ print("padding={}".format(padding_bytes))
+ print("PFM size1={}".format(self.pfm_bytes))
+ self.pfm_bytes += padding_bytes
+ parts['pfm_len'] = struct.pack('<I', self.pfm_bytes)
+ print("PFM size2={}".format(self.pfm_bytes))
+
+ with open("pfm.bin", "wb+") as f:
+ f.write(b''.join([parts[n] for n in names]))
+ for i in self.pfm_spi_regions:
+ f.write(struct.pack('<B', int(i.spi_pfm)))
+ f.write(struct.pack('<B', int(i.spi_prot_mask)))
+ f.write(struct.pack('<h', int(i.spi_hash_pres)))
+ f.write(struct.pack('<I', int(i.spi_pfm_rsvd)))
+ f.write(struct.pack('<I', int(i.spi_start_addr)))
+ f.write(struct.pack('<I', int(i.spi_end_addr)))
+
+ if i.spi_hash_pres != 0:
+ f.write(bytearray.fromhex(i.spi_hash))
+
+ for r in self.pfm_i2c_rules:
+ f.write(struct.pack('<B', int(r.i2c_pfm)))
+ f.write(struct.pack('<I', int(r.i2c_pfm_rsvd)))
+ f.write(struct.pack('<B', int(r.i2c_bus_id)))
+ f.write(struct.pack('<B', int(r.i2c_rule_id)))
+ f.write(struct.pack('<B', int(r.i2c_address, 16)))
+ f.write(r.i2c_cmd_whitelist)
+
+ # write the padding bytes at the end
+ f.write(b'\xff' * padding_bytes)
+
+def main():
+ if len(sys.argv) != 7: #< pfr_image.py manifest.json> <update.bin> <build_version> <build_number> <build_hash> <sha>
+ print('usage: {} <manifest.json> <firmware.bin> <build_version> <build_number> <build_hash> <sha>'.format(sys.argv[0]))
+ return
+
+ json_file = sys.argv[1]
+ firmware_file = sys.argv[2]
+ build_ver = sys.argv[3]
+ build_num = sys.argv[4]
+ build_hash = sys.argv[5]
+ sha = sys.argv[6]
+
+ # function to generate BMC PFM, PBC header and BMC compressed image
+ pfr_bmc_image(json_file, firmware_file, build_ver, build_num, build_hash, sha)
+
+if __name__ == '__main__':
+ main()
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/bmc_config.xml b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/bmc_config.xml
new file mode 100644
index 000000000..9e7d3f82d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/bmc_config.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- XML file for Block Sign Tool -->
+<blocksign>
+ <version>1</version>
+ <!-- Block 0 -->
+ <block0>
+ <magic>0xB6EAFD19</magic>
+ <pctype>4</pctype>
+ </block0>
+ <!-- Block 1 -->
+ <block1>
+ <magic>0xF27F28D7</magic>
+ <!-- Root key -->
+ <rkey>
+ <magic>0xA757A046</magic>
+ <curvemagic>0xC7B88C74</curvemagic>
+ <permissions>-1</permissions>
+ <keyid>-1</keyid>
+ <pubkey>rk_pub.pem</pubkey>
+ </rkey>
+ <!-- Code signing key -->
+ <cskey>
+ <magic>0x14711C2F</magic>
+ <curvemagic>0xC7B88C74</curvemagic>
+ <permissions>8</permissions>
+ <keyid>1</keyid>
+ <pubkey>csk_pub.pem</pubkey>
+ <sigmagic>0xDE64437D</sigmagic>
+ <hashalg>sha256</hashalg>
+ <signkey>rk_prv.pem</signkey>
+ <!--<script>./sign_external.sh</script>-->
+ </cskey>
+ <!-- Signature over Block 0 -->
+ <b0_sig>
+ <magic>0x15364367</magic>
+ <sigmagic>0xDE64437D</sigmagic>
+ <hashalg>sha256</hashalg>
+ <signkey>csk_prv.pem</signkey>
+ </b0_sig>
+ </block1>
+ <!-- CPLD Bitstream Specific -->
+ <padding>
+ <!-- Pad block1 such that combined block length is 1024b -->
+ <blockpad>1024</blockpad>
+ <!-- Align total package to 128 bytes -->
+ <align>128</align>
+ </padding>
+</blocksign>
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/csk_prv.pem b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/csk_prv.pem
new file mode 100644
index 000000000..a46fa2a2b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/csk_prv.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIFjPqxcb6tfFWyFVaQCVjeN9MtcISpYIbNlkQoODrHTUoAoGCCqGSM49
+AwEHoUQDQgAERGJveRnhIp7I5cvmjO74MJLbUJjTfvTDKlzK0hJB0WRBEFScpb9d
+xWLrwj9TNcO+EexnNcjEkF1RYNs6lHavRQ==
+-----END EC PRIVATE KEY-----
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/csk_pub.pem b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/csk_pub.pem
new file mode 100644
index 000000000..cc70d6e28
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/csk_pub.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERGJveRnhIp7I5cvmjO74MJLbUJjT
+fvTDKlzK0hJB0WRBEFScpb9dxWLrwj9TNcO+EexnNcjEkF1RYNs6lHavRQ==
+-----END PUBLIC KEY-----
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/pfm_config.xml b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/pfm_config.xml
new file mode 100644
index 000000000..19378d1b9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/pfm_config.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- XML file for Block Sign Tool -->
+<blocksign>
+ <version>1</version>
+ <!-- Block 0 -->
+ <block0>
+ <magic>0xB6EAFD19</magic>
+ <pctype>3</pctype>
+ </block0>
+ <!-- Block 1 -->
+ <block1>
+ <magic>0xF27F28D7</magic>
+ <!-- Root key -->
+ <rkey>
+ <magic>0xA757A046</magic>
+ <curvemagic>0xC7B88C74</curvemagic>
+ <permissions>-1</permissions>
+ <keyid>-1</keyid>
+ <pubkey>rk_pub.pem</pubkey>
+ </rkey>
+ <!-- Code signing key -->
+ <cskey>
+ <magic>0x14711C2F</magic>
+ <curvemagic>0xC7B88C74</curvemagic>
+ <permissions>4</permissions>
+ <keyid>1</keyid>
+ <pubkey>csk_pub.pem</pubkey>
+ <sigmagic>0xDE64437D</sigmagic>
+ <hashalg>sha256</hashalg>
+ <signkey>rk_prv.pem</signkey>
+ <!--<script>./sign_external.sh</script>-->
+ </cskey>
+ <!-- Signature over Block 0 -->
+ <b0_sig>
+ <magic>0x15364367</magic>
+ <sigmagic>0xDE64437D</sigmagic>
+ <hashalg>sha256</hashalg>
+ <signkey>csk_prv.pem</signkey>
+ </b0_sig>
+ </block1>
+ <!-- CPLD Bitstream Specific -->
+ <padding>
+ <!-- Pad block1 such that combined block length is 1024b -->
+ <blockpad>1024</blockpad>
+ <!-- Align total package to 128 bytes -->
+ <align>128</align>
+ </padding>
+</blocksign>
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/pfr_manifest.json b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/pfr_manifest.json
new file mode 100644
index 000000000..c79b7f343
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/pfr_manifest.json
@@ -0,0 +1,196 @@
+{
+ "image-parts": [{
+ "name": "u-boot",
+ "index": 0,
+ "offset": "0",
+ "size": "0x80000",
+ "prot_mask": 29,
+ "pfm": 1,
+ "hash": 1,
+ "compress": 1
+ },
+ {
+ "name": "pfm",
+ "index": 1,
+ "offset": "0x80000",
+ "size": "0x20000",
+ "prot_mask": 0,
+ "pfm": 1,
+ "hash": 0,
+ "compress": 0
+ },
+ {
+ "name": "u-boot-env",
+ "index": 2,
+ "offset": "0xa0000",
+ "size": "0x20000",
+ "prot_mask": 31,
+ "pfm": 1,
+ "hash": 0,
+ "compress": 1
+ },
+ {
+ "name": "sofs",
+ "index": 3,
+ "offset": "0xc0000",
+ "size": "0x200000",
+ "prot_mask": 31,
+ "pfm": 1,
+ "hash": 0,
+ "compress": 1
+ },
+ {
+ "name": "rwfs",
+ "index": 4,
+ "offset": "0x2c0000",
+ "size": "0x840000",
+ "prot_mask": 31,
+ "pfm": 1,
+ "hash": 0,
+ "compress": 1
+ },
+ {
+ "name": "fit-image-a",
+ "index": 5,
+ "offset": "0xb00000",
+ "size": "0x1f00000",
+ "prot_mask": 29,
+ "pfm": 1,
+ "hash": 1,
+ "compress": 1
+ },
+ {
+ "name": "rc-image",
+ "index": 6,
+ "offset": "0x2a00000",
+ "size": "0x2000000",
+ "prot_mask": 0,
+ "pfm": 1,
+ "hash": 0,
+ "compress": 0
+ },
+ {
+ "name": "image-stg",
+ "index": 7,
+ "offset": "0x4a00000",
+ "size": "0x3500000",
+ "prot_mask": 3,
+ "pfm": 1,
+ "hash": 0,
+ "compress": 0
+ },
+ {
+ "name": "cpld-rc",
+ "index": 8,
+ "offset": "0x7f00000",
+ "size": "0x100000",
+ "prot_mask": 0,
+ "pfm": 1,
+ "hash": 0,
+ "compress": 0
+ }
+ ],
+ "i2c-rules": [{
+ "bus-id": 3,
+ "rule-id": 3,
+ "address": "0xD0",
+ "cmd-whitelist": ["0x00", "0x01", "0x02", "0x03", "0x04", "0x09", "0x0A", "0x0B", "0x0C", "0x0D", "0x0E", "0x0F",
+ "0x10", "0x13", "0x17", "0x1B", "0x1C", "0x1D", "0x02", "0x021", "0x22", "0x23", "0x25", "0x30",
+ "0x31", "0x32", "0x33", "0x035", "0x36", "0x37", "0x38", "0x39", "0x3A", "0x3B", "0x3C", "0x3D"]
+ },
+ {
+ "bus-id": 3,
+ "rule-id": 4,
+ "address": "0xD8",
+ "cmd-whitelist": ["0x00", "0x01", "0x02", "0x03", "0x04", "0x09", "0x0A", "0x0B", "0x0C", "0x0D", "0x0E", "0x0F",
+ "0x10", "0x13", "0x17", "0x1B", "0x1C", "0x1D", "0x02", "0x021", "0x22", "0x23", "0x25", "0x30",
+ "0x31", "0x32", "0x33", "0x035", "0x36", "0x37", "0x38", "0x39", "0x3A", "0x3B", "0x3C", "0x3D"]
+ },
+ {
+ "bus-id": 1,
+ "rule-id": 6,
+ "address": "0xB0",
+ "cmd-whitelist": ["0x00", "0x03", "0x05", "0x06", "0x19", "0x1A", "0x30", "0x3A", "0x3B", "0x3C", "0x3D", "0x3E", "0x3F",
+ "0x79", "0x7A", "0x7B", "0x7C", "0x7D", "0x7E", "0x7F", "0x81", "0x82", "0x86", "0x87", "0x88",
+ "0x89", "0x8C", "0x8D", "0x8E", "0x8F", "0x90", "0x91", "0x92", "0x93", "0x94", "0x95", "0x96",
+ "0x97", "0x98", "0x9A", "0xA6", "0xA7", "0xD0", "0xD3", "0xD4", "0xD5", "0xD6", "0xD7", "0xD8",
+ "0xD9", "0xDC", "0xDD", "0xDE", "0xDE"]
+ },
+ {
+ "bus-id": 1,
+ "rule-id": 4,
+ "address": "0xB2",
+ "cmd-whitelist": ["0x00", "0x03", "0x05", "0x06", "0x19", "0x1A", "0x30", "0x3A", "0x3B", "0x3C", "0x3D", "0x3E", "0x3F",
+ "0x79", "0x7A", "0x7B", "0x7C", "0x7D", "0x7E", "0x7F", "0x81", "0x82", "0x86", "0x87", "0x88",
+ "0x89", "0x8C", "0x8D", "0x8E", "0x8F", "0x90", "0x91", "0x92", "0x93", "0x94", "0x95", "0x96",
+ "0x97", "0x98", "0x9A", "0xA6", "0xA7", "0xD0", "0xD3", "0xD4", "0xD5", "0xD6", "0xD7", "0xD8",
+ "0xD9", "0xDC", "0xDD", "0xDE", "0xDE"]
+ },
+ {
+ "bus-id": 2,
+ "rule-id": 1,
+ "address": "0xB4",
+ "cmd-whitelist": ["0x00"]
+ },
+ {
+ "bus-id": 2,
+ "rule-id": 2,
+ "address": "0xD4",
+ "cmd-whitelist": ["0x00"]
+ },
+ {
+ "bus-id": 2,
+ "rule-id": 3,
+ "address": "0x4A",
+ "cmd-whitelist": ["0x00"]
+ },
+ {
+ "bus-id": 2,
+ "rule-id": 4,
+ "address": "0x4C",
+ "cmd-whitelist": ["0x00"]
+ },
+ {
+ "bus-id": 2,
+ "rule-id": 5,
+ "address": "0xDC",
+ "cmd-whitelist": ["0x00"]
+ },
+ {
+ "bus-id": 2,
+ "rule-id": 6,
+ "address": "0xEC",
+ "cmd-whitelist": ["0x00"]
+ },
+ {
+ "bus-id": 2,
+ "rule-id": 7,
+ "address": "0xE0",
+ "cmd-whitelist": ["0x00"]
+ },
+ {
+ "bus-id": 2,
+ "rule-id": 8,
+ "address": "0xB0",
+ "cmd-whitelist": ["0x00"]
+ },
+ {
+ "bus-id": 2,
+ "rule-id": 9,
+ "address": "0xC4",
+ "cmd-whitelist": ["0x00"]
+ },
+ {
+ "bus-id": 2,
+ "rule-id": 10,
+ "address": "0xCC",
+ "cmd-whitelist": ["0x00"]
+ },
+ {
+ "bus-id": 2,
+ "rule-id": 11,
+ "address": "0xE4",
+ "cmd-whitelist": ["0x00"]
+ }
+ ]
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/rk_prv.pem b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/rk_prv.pem
new file mode 100644
index 000000000..9e8616795
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/rk_prv.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIHVbq5CmT4Vr4Jb0eJK0+KhUxDOWy1kh9QYAClV5MH1GoAoGCCqGSM49
+AwEHoUQDQgAEZUL6ZcF0YN590Pq/bKPYjfa3F4E44XiKcqvS6+l2GfSdCLRhXWHw
+iV803vFkTsZ1CfpzFdZGwfbwg7nvG5UpSQ==
+-----END EC PRIVATE KEY-----
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/rk_pub.pem b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/rk_pub.pem
new file mode 100644
index 000000000..117e08bae
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/files/wht/rk_pub.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZUL6ZcF0YN590Pq/bKPYjfa3F4E4
+4XiKcqvS6+l2GfSdCLRhXWHwiV803vFkTsZ1CfpzFdZGwfbwg7nvG5UpSQ==
+-----END PUBLIC KEY-----
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-blocksign-native.bb b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-blocksign-native.bb
new file mode 100644
index 000000000..9f8100dc2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-blocksign-native.bb
@@ -0,0 +1,20 @@
+SUMMARY = "Intel Blocksign tool for PFR image"
+DESCRIPTION = "Image signing tool for BMC PFR image"
+
+inherit native cmake
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+DEPENDS = "openssl-native libxml2-native "
+
+SRC_URI = "git://github.com/Intel-BMC/blocksign;protocol=ssh"
+
+SRCREV = "852d88a1cbf4dc5856ff88e823a38d2872a86ffe"
+
+S = "${WORKDIR}/git/"
+
+do_install_append() {
+ install -d ${D}/${bindir}
+ install -m 775 ${B}/blocksign ${D}/${bindir}
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-pfr-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-pfr-manager_git.bb
new file mode 100644
index 000000000..d48ffb1a5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/intel-pfr-manager_git.bb
@@ -0,0 +1,22 @@
+SUMMARY = "Intel PFR Manager Service"
+DESCRIPTION = "Daemon to handle all PFR functionalities"
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git/intel-pfr-manager"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh"
+SRCREV = "bee56d62b209088454d166d1efae4825a2b175df"
+
+inherit cmake systemd
+SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.PFR.Manager.service"
+
+DEPENDS += " \
+ sdbusplus \
+ phosphor-logging \
+ boost \
+ i2c-tools \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/obmc-intel-pfr-image-native.bb b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/obmc-intel-pfr-image-native.bb
new file mode 100644
index 000000000..bb8684ac2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/intel-pfr/obmc-intel-pfr-image-native.bb
@@ -0,0 +1,37 @@
+SUMMARY = "Intel PFR image manifest and image signing keys"
+DESCRIPTION = "This copies PFR image generation scripts and image signing keys to staging area"
+
+PR = "r1"
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+inherit native
+
+DEPENDS += " intel-blocksign-native"
+
+SRC_URI = " \
+ file://pfr_image.py \
+ file://${PRODUCT_GENERATION}/pfr_manifest.json \
+ file://${PRODUCT_GENERATION}/pfm_config.xml \
+ file://${PRODUCT_GENERATION}/bmc_config.xml \
+ file://${PRODUCT_GENERATION}/csk_prv.pem \
+ file://${PRODUCT_GENERATION}/csk_pub.pem \
+ file://${PRODUCT_GENERATION}/rk_pub.pem \
+ file://${PRODUCT_GENERATION}/rk_prv.pem \
+ "
+
+do_install () {
+ bbplain "Copying intel pfr image generation scripts and image signing keys"
+
+ install -d ${D}${bindir}
+ install -d ${D}/${datadir}/pfrconfig
+ install -m 775 ${WORKDIR}/pfr_image.py ${D}${bindir}/pfr_image.py
+ install -m 400 ${WORKDIR}/${PRODUCT_GENERATION}/pfr_manifest.json ${D}/${datadir}/pfrconfig
+ install -m 400 ${WORKDIR}/${PRODUCT_GENERATION}/pfm_config.xml ${D}/${datadir}/pfrconfig/pfm_config.xml
+ install -m 400 ${WORKDIR}/${PRODUCT_GENERATION}/bmc_config.xml ${D}/${datadir}/pfrconfig/bmc_config.xml
+ install -m 400 ${WORKDIR}/${PRODUCT_GENERATION}/csk_prv.pem ${D}/${datadir}/pfrconfig/csk_prv.pem
+ install -m 400 ${WORKDIR}/${PRODUCT_GENERATION}/csk_pub.pem ${D}/${datadir}/pfrconfig/csk_pub.pem
+ install -m 400 ${WORKDIR}/${PRODUCT_GENERATION}/rk_pub.pem ${D}/${datadir}/pfrconfig/rk_pub.pem
+ install -m 400 ${WORKDIR}/${PRODUCT_GENERATION}/rk_prv.pem ${D}/${datadir}/pfrconfig/rk_prv.pem
+}
+
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics.bb b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics.bb
new file mode 100644
index 000000000..50c8bd63e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics.bb
@@ -0,0 +1,24 @@
+SUMMARY = "One time automatically enable every NIC"
+DESCRIPTION = "Re-enable NIC accidentally disabled by earlier BMC firmware."
+
+S = "${WORKDIR}"
+SRC_URI = "file://enable-nics.sh \
+ file://enable-nics.service \
+ "
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+RDEPENDS_${PN} += "bash"
+
+inherit systemd
+
+FILES_${PN} += "${systemd_system_unitdir}/enable-nics.service"
+
+do_install() {
+ install -d ${D}${systemd_system_unitdir}
+ install -m 0644 ${WORKDIR}/enable-nics.service ${D}${systemd_system_unitdir}
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/enable-nics.sh ${D}/${bindir}/enable-nics.sh
+}
+
+SYSTEMD_SERVICE_${PN} += " enable-nics.service"
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.service b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.service
new file mode 100644
index 000000000..531b5d86e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Re-enable NICs mistakenly disabled by earlier BMC firmware
+Wants=multi-user.target
+After=multi-user.target
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/enable-nics.sh
+
+[Install]
+WantedBy=network.target
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.sh b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.sh
new file mode 100755
index 000000000..ce1473be1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/nic/enable-nics/enable-nics.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+SEMAPHORE_FILE=/var/cache/private/nic_fixup_complete
+
+if [ -a $SEMAPHORE_FILE ]; then
+ exit 0
+fi
+
+for nicFile in /etc/systemd/network/*.network
+do
+ sed -i -e"/Unmanaged/d" $nicFile
+done
+
+touch $SEMAPHORE_FILE
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..4d91ac673
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-intel-apps.bb
@@ -0,0 +1,38 @@
+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 = " \
+ x86-power-control \
+ "
+
+SUMMARY_${PN}-fans = "Intel Fans"
+RDEPENDS_${PN}-fans = " \
+ phosphor-pid-control \
+ "
+
+SUMMARY_${PN}-flash = "Intel Flash"
+RDEPENDS_${PN}-flash = ""
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..1921d8e3a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/packagegroups/packagegroup-obmc-apps.bbappend
@@ -0,0 +1,4 @@
+RDEPENDS_${PN}-extrasdevtools = "libgpiod-tools"
+RDEPENDS_${PN}-chassis-state-mgmt_remove = "obmc-phosphor-power"
+
+RDEPENDS_${PN}-settings = "settings"
diff --git a/meta-openbmc-mods/meta-common/recipes-intel/psu-manager/psu-manager.bb b/meta-openbmc-mods/meta-common/recipes-intel/psu-manager/psu-manager.bb
new file mode 100644
index 000000000..daeced419
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/psu-manager/psu-manager.bb
@@ -0,0 +1,26 @@
+SUMMARY = "Power supply manager for Intel based platform"
+DESCRIPTION = "Power supply manager which include PSU Cold Redundancy service"
+
+SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh"
+SRCREV = "bee56d62b209088454d166d1efae4825a2b175df"
+
+S = "${WORKDIR}/git/psu-manager/"
+
+PV = "1.0+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+inherit cmake
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.coldredundancy.service"
+
+DEPENDS += " \
+ systemd \
+ sdbusplus \
+ phosphor-dbus-interfaces \
+ phosphor-logging \
+ boost \
+ i2c-tools \
+ "
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..97866ba4e
--- /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://github.com/Intel-BMC/provingground.git;protocol=ssh;nobranch=1"
+SRCREV = "6aab8bcc8fd0550753c87265036b1b7c4c8a9f71"
+
+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..7a5cc7d3e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-intel/smbios/smbios-mdrv2.bb
@@ -0,0 +1,28 @@
+SUMMARY = "SMBIOS MDR version 2 service for Intel based platform"
+DESCRIPTION = "SMBIOS MDR version 2 service for Intel based platfrom"
+
+SRC_URI = "git://github.com/Intel-BMC/mdrv2.git;protocol=ssh"
+SRCREV = "e1d574504a16282fe86a0ca02a821ebdcd220774"
+
+S = "${WORKDIR}/git"
+
+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 \
+ boost \
+ systemd \
+ sdbusplus \
+ sdbusplus-native \
+ phosphor-dbus-interfaces \
+ phosphor-dbus-interfaces-native \
+ 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/0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch
new file mode 100644
index 000000000..5a01aaeed
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch
@@ -0,0 +1,500 @@
+From c2019bbf210e0e750478a3e6c0c9bfa557c5bc0f 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: add DTS for Intel ast2500 platforms
+
+Add the DTS file for Intel ast2500-based systems.
+
+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>
+Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
+Signed-off-by: Zhu, Yunge <yunge.zhu@linux.intel.com>
+Signed-off-by: Qiang XU <qiang.xu@linux.intel.com>
+Signed-off-by: Chen Yugang <yugang.chen@linux.intel.com>
+Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
+Signed-off-by: jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+---
+ arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts | 474 +++++++++++++++++++++++++
+ 1 file changed, 474 insertions(+)
+ create mode 100644 arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts
+
+diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts
+new file mode 100644
+index 000000000000..18fa1f804874
+--- /dev/null
++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts
+@@ -0,0 +1,468 @@
++/dts-v1/;
++
++#include "aspeed-g5.dtsi"
++#include <dt-bindings/gpio/aspeed-gpio.h>
++#include <dt-bindings/i2c/i2c.h>
++
++/ {
++ model = "Intel AST2500 BMC";
++ compatible = "intel,ast2500-bmc", "aspeed,ast2500";
++
++ aliases {
++ serial4 = &uart5;
++ };
++
++ chosen {
++ stdout-path = &uart5;
++ bootargs = "console=ttyS4,115200 earlyprintk";
++ };
++
++ memory@80000000 {
++ reg = <0x80000000 0x20000000>;
++ };
++
++ reserved-memory {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ vga_memory: framebuffer@7f000000 {
++ no-map;
++ reg = <0x7f000000 0x01000000>;
++ };
++
++ gfx_memory: framebuffer {
++ size = <0x01000000>;
++ alignment = <0x01000000>;
++ compatible = "shared-dma-pool";
++ reusable;
++ };
++
++ video_engine_memory: jpegbuffer {
++ size = <0x02000000>; /* 32M */
++ alignment = <0x01000000>;
++ compatible = "shared-dma-pool";
++ reusable;
++ };
++
++ ramoops@9eff0000{
++ compatible = "ramoops";
++ reg = <0x9eff0000 0x10000>;
++ record-size = <0x2000>;
++ console-size = <0x2000>;
++ };
++ };
++
++ vga-shared-memory {
++ compatible = "aspeed,ast2500-vga-sharedmem";
++ reg = <0x9ff00000 0x100000>;
++ };
++
++ iio-hwmon {
++ compatible = "iio-hwmon";
++ io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
++ <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>,
++ <&adc 8>, <&adc 9>, <&adc 10>, <&adc 11>,
++ <&adc 12>, <&adc 13>, <&adc 14>, <&adc 15>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ identify {
++ default-state = "on";
++ gpios = <&gpio ASPEED_GPIO(S, 6) GPIO_ACTIVE_LOW>;
++ };
++
++ status_amber {
++ default-state = "off";
++ gpios = <&gpio ASPEED_GPIO(S, 5) GPIO_ACTIVE_LOW>;
++ };
++
++ status_green {
++ default-state = "keep";
++ gpios = <&gpio ASPEED_GPIO(S, 4) GPIO_ACTIVE_LOW>;
++ };
++ };
++
++ beeper {
++ compatible = "pwm-beeper";
++ pwms = <&timer 6 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";
++ gpios = <&gpio ASPEED_GPIO(F, 6) 0>;
++};
++
++&syscon {
++ uart-clock-high-speed;
++ status = "okay";
++
++ misc_control {
++ compatible = "aspeed,bmc-misc";
++ uart_port_debug {
++ offset = <0x2c>;
++ bit-mask = <0x1>;
++ bit-shift = <10>;
++ read-only;
++ };
++ p2a-bridge {
++ offset = <0x180>;
++ bit-mask = <0x1>;
++ bit-shift = <1>;
++ read-only;
++ };
++ boot-2nd-flash {
++ offset = <0x70>;
++ bit-mask = <0x1>;
++ bit-shift = <17>;
++ read-only;
++ };
++ chip_id {
++ offset = <0x150>;
++ bit-mask = <0x0fffffff 0xffffffff>;
++ bit-shift = <0>;
++ read-only;
++ reg-width = <64>;
++ hash-data = "d44f9b804976fa23c2e25d62f16154d26520a7e24c5555095fd1b55c027804f1570dcd16189739c640cd7d9a6ce14944a2c4eaf1dc429eed6940e8a83498a474";
++ };
++ };
++};
++
++&adc {
++ status = "okay";
++};
++
++&gpio {
++ status = "okay";
++ gpio-line-names =
++ /*A0-A7*/ "","","","","","","","",
++ /*B0-B7*/ "FM_BMC_BOARD_SKU_ID0_N","FM_BMC_BOARD_SKU_ID1_N","FM_BMC_BOARD_SKU_ID2_N","FM_BMC_BOARD_SKU_ID3_N","FM_BMC_BOARD_SKU_ID4_N","","","",
++ /*C0-C7*/ "","","","","","","","",
++ /*D0-D7*/ "","","","","","","","",
++ /*E0-E7*/ "RESET_BUTTON","RESET_OUT","POWER_BUTTON","POWER_OUT","","DEBUG_EN_N","","",
++ /*F0-F7*/ "NMI_OUT","","","","CPU_ERR0","CPU_ERR1","PLTRST_N","PRDY_N",
++ /*G0-G7*/ "CPU_ERR2","CPU_CATERR","PCH_BMC_THERMTRIP","LCP_ENTER_BUTTON","LCP_LEFT_BUTTON","FM_BMC_BOARD_SKU_ID5_N","","",
++ /*H0-H7*/ "","","","FM_NODE_ID_1","FM_NODE_ID_2","FM_NODE_ID_3","FM_NODE_ID_4","FM_240VA_STATUS",
++ /*I0-I7*/ "FM_SYS_FAN0_PRSNT_D_N","FM_SYS_FAN1_PRSNT_D_N","FM_SYS_FAN2_PRSNT_D_N","FM_SYS_FAN3_PRSNT_D_N","FM_SYS_FAN4_PRSNT_D_N","FM_SYS_FAN5_PRSNT_D_N","","",
++ /*J0-J7*/ "","","","","","","","",
++ /*K0-K7*/ "","","","","","","","",
++ /*L0-L7*/ "","","","","","","","",
++ /*M0-M7*/ "","","","","","","","",
++ /*N0-N7*/ "","","","","","","","",
++ /*O0-O7*/ "","","","","","","","",
++ /*P0-P7*/ "","","","","","","","",
++ /*Q0-Q7*/ "","","","","","","","PWR_DEBUG_N",
++ /*R0-R7*/ "","XDP_PRST_N","","","","","","CHASSIS_INTRUSION",
++ /*S0-S7*/ "REMOTE_DEBUG_ENABLE","SYSPWROK","RSMRST_N","","","","","",
++ /*T0-T7*/ "","","","","","","","",
++ /*U0-U7*/ "","","","","","","","",
++ /*V0-V7*/ "","","","","","","","",
++ /*W0-W7*/ "","","","","","","","",
++ /*X0-X7*/ "","","","","","","","",
++ /*Y0-Y7*/ "SIO_S3","SIO_S5","","SIO_ONCONTROL","","","","",
++ /*Z0-Z7*/ "","SIO_POWER_GOOD","","","","","","",
++ /*AA0-AA7*/ "P3VBAT_BRIDGE_EN","","","","PREQ_N","TCK_MUX_SEL","SMI","POST_COMPLETE",
++ /*AB0-AB7*/ "","NMI_BUTTON","ID_BUTTON","PS_PWROK","","","","",
++ /*AC0-AC7*/ "","","","","","","","";
++};
++
++&sgpio {
++ status = "okay";
++ gpio-line-names =
++ /* SGPIO output lines */
++ /*OA0-OA7*/ "","","","","","","","",
++ /*OB0-OB7*/ "LED_CPU1_CH1_DIMM1_FAULT","LED_CPU1_CH1_DIMM2_FAULT","LED_CPU1_CH2_DIMM1_FAULT","LED_CPU1_CH2_DIMM2_FAULT","LED_CPU1_CH3_DIMM1_FAULT","LED_CPU1_CH3_DIMM2_FAULT","LED_CPU1_CH4_DIMM1_FAULT","LED_CPU1_CH4_DIMM2_FAULT",
++ /*OC0-OC7*/ "LED_CPU1_CH5_DIMM1_FAULT","LED_CPU1_CH5_DIMM2_FAULT","LED_CPU1_CH6_DIMM1_FAULT","LED_CPU1_CH6_DIMM2_FAULT","LED_FAN1_FAULT","LED_FAN2_FAULT","LED_FAN3_FAULT","LED_FAN4_FAULT",
++ /*OD0-OD7*/ "LED_FAN5_FAULT","LED_FAN6_FAULT","LED_FAN7_FAULT","LED_FAN8_FAULT","LED_CPU2_CH1_DIMM1_FAULT","LED_CPU1_CH1_DIMM2_FAULT","LED_CPU2_CH2_DIMM1_FAULT","LED_CPU2_CH2_DIMM2_FAULT",
++ /*OE0-OE7*/ "LED_CPU2_CH3_DIMM1_FAULT","LED_CPU2_CH3_DIMM2_FAULT","LED_CPU2_CH4_DIMM1_FAULT","LED_CPU2_CH4_DIMM2_FAULT","LED_CPU2_CH5_DIMM1_FAULT","LED_CPU2_CH5_DIMM2_FAULT","LED_CPU2_CH6_DIMM1_FAULT","LED_CPU2_CH6_DIMM2_FAULT",
++ /*OF0-OF7*/ "LED_CPU3_CH1_DIMM1_FAULT","LED_CPU3_CH1_DIMM2_FAULT","LED_CPU3_CH2_DIMM1_FAULT","LED_CPU3_CH2_DIMM2_FAULT","LED_CPU3_CH3_DIMM1_FAULT","LED_CPU3_CH3_DIMM2_FAULT","LED_CPU3_CH4_DIMM1_FAULT","LED_CPU3_CH4_DIMM2_FAULT",
++ /*OG0-OG7*/ "LED_CPU3_CH5_DIMM1_FAULT","LED_CPU3_CH5_DIMM2_FAULT","LED_CPU3_CH6_DIMM1_FAULT","LED_CPU3_CH6_DIMM2_FAULT","LED_CPU4_CH1_DIMM1_FAULT","LED_CPU4_CH1_DIMM2_FAULT","LED_CPU4_CH2_DIMM1_FAULT","LED_CPU4_CH2_DIMM2_FAULT",
++ /*OH0-OH7*/ "LED_CPU4_CH3_DIMM1_FAULT","LED_CPU4_CH3_DIMM2_FAULT","LED_CPU4_CH4_DIMM1_FAULT","LED_CPU4_CH4_DIMM2_FAULT","LED_CPU4_CH5_DIMM1_FAULT","LED_CPU4_CH5_DIMM2_FAULT","LED_CPU4_CH6_DIMM1_FAULT","LED_CPU4_CH6_DIMM2_FAULT",
++ /*OI0-OI7*/ "","","","","","","","",
++ /*OJ0-OJ7*/ "","","","","","","","",
++ /*DUMMY*/ "","","","","","","","",
++ /*DUMMY*/ "","","","","","","","",
++
++ /* SGPIO input lines */
++ /*IA0-IA7*/ "CPU1_PRESENCE","CPU1_THERMTRIP","CPU1_VRHOT","CPU1_FIVR_FAULT","CPU1_MEM_ABCD_VRHOT","CPU1_MEM_EFGH_VRHOT","","",
++ /*IB0-IB7*/ "CPU1_MISMATCH","CPU1_MEM_THERM_EVENT","CPU2_PRESENCE","CPU2_THERMTRIP","CPU2_VRHOT","CPU2_FIVR_FAULT","CPU2_MEM_ABCD_VRHOT","CPU2_MEM_EFGH_VRHOT",
++ /*IC0-IC7*/ "","","CPU2_MISMATCH","CPU2_MEM_THERM_EVENT","","","","",
++ /*ID0-ID7*/ "","","","","","","","",
++ /*IE0-IE7*/ "","","","","","","","",
++ /*IF0-IF7*/ "","","","","","","","",
++ /*IG0-IG7*/ "","","","","","","","",
++ /*IH0-IH7*/ "","","","","","","","",
++ /*II0-II7*/ "","","","","","","","",
++ /*IJ0-IJ7*/ "","","","","","","","";
++};
++
++&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";
++};
++
++&uart_routing {
++ 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";
++ * };
++ *};
++ */
++
++&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";
++ pinctrl-names = "default";
++ pinctrl-0 = <>;
++};
++
++&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;
++ general-call;
++ aspeed,dma-buf-size = <4095>;
++ aspeed,hw-timeout-ms = <300>;
++ status = "okay";
++};
++
++&i2c1 {
++ multi-master;
++ aspeed,dma-buf-size = <4095>;
++ aspeed,hw-timeout-ms = <300>;
++ status = "okay";
++};
++
++&i2c2 {
++ multi-master;
++ aspeed,dma-buf-size = <4095>;
++ aspeed,hw-timeout-ms = <300>;
++ status = "okay";
++};
++
++&i2c3 {
++ multi-master;
++ aspeed,dma-buf-size = <4095>;
++ aspeed,hw-timeout-ms = <300>;
++ status = "okay";
++};
++
++&i2c4 {
++ multi-master;
++ aspeed,dma-buf-size = <4095>;
++ aspeed,hw-timeout-ms = <300>;
++ status = "okay";
++};
++
++&i2c5 {
++ bus-frequency = <1000000>;
++ multi-master;
++ aspeed,dma-buf-size = <4095>;
++ aspeed,hw-timeout-ms = <300>;
++ status = "okay";
++};
++
++&i2c6 {
++ multi-master;
++ aspeed,dma-buf-size = <4095>;
++ aspeed,hw-timeout-ms = <300>;
++ status = "okay";
++};
++
++&i2c7 {
++ multi-master;
++ #retries = <3>;
++ aspeed,dma-buf-size = <4095>;
++ aspeed,hw-timeout-ms = <300>;
++ status = "okay";
++};
++
++&i2c9 {
++ multi-master;
++ aspeed,dma-buf-size = <4095>;
++ aspeed,hw-timeout-ms = <300>;
++ status = "okay";
++};
++
++&i2c11 {
++ multi-master;
++ aspeed,dma-buf-size = <4095>;
++ aspeed,hw-timeout-ms = <300>;
++ status = "okay";
++};
++
++&i2c13 {
++ multi-master;
++ aspeed,dma-buf-size = <4095>;
++ aspeed,hw-timeout-ms = <300>;
++ status = "okay";
++};
++
++&gfx {
++ status = "okay";
++ memory-region = <&gfx_memory>;
++};
++
++&vuart {
++ status = "okay";
++};
++
++&pwm_tacho {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default
++ &pinctrl_pwm2_default &pinctrl_pwm3_default
++ &pinctrl_pwm4_default &pinctrl_pwm5_default
++ &pinctrl_pwm6_default &pinctrl_pwm7_default>;
++
++ fan@0 {
++ reg = <0x00>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x00 0x01>;
++ };
++ fan@1 {
++ reg = <0x01>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x02 0x03>;
++ };
++ fan@2 {
++ reg = <0x02>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x04 0x05>;
++ };
++ fan@3 {
++ reg = <0x03>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x06 0x07>;
++ };
++ fan@4 {
++ reg = <0x04>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x08 0x09>;
++ };
++ fan@5 {
++ reg = <0x05>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x0A 0x0B>;
++ };
++ fan@6 {
++ reg = <0x06>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x0C 0x0D>;
++ };
++ fan@7 {
++ reg = <0x07>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x0E 0x0F>;
++ };
++
++};
++
++&timer {
++/*
++ * Available settings:
++ * fttmr010,pwm-outputs = <5>, <6>, <7>, <8>;
++ * pinctrl-0 = <&pinctrl_timer5_default &pinctrl_timer6_default
++ * &pinctrl_timer7_default &pinctrl_timer8_default>;
++ */
++ fttmr010,pwm-outputs = <6>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_timer6_default>;
++ #pwm-cells = <3>;
++ status = "okay";
++};
++
++&video {
++ status = "okay";
++ memory-region = <&video_engine_memory>;
++};
++
++&vhub {
++ status = "okay";
++};
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2600-platforms.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2600-platforms.patch
new file mode 100644
index 000000000..b3e7342c5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2600-platforms.patch
@@ -0,0 +1,537 @@
+From 0fca4f924e45f1968f610ad8903f18d638188784 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Tue, 19 Sep 2017 15:55:39 +0800
+Subject: [PATCH] arm: dts: add DTS for Intel ast2600 platforms
+
+Add the DTS file for Intel ast2600-based systems.
+
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+Signed-off-by: Chen Yugang <yugang.chen@linux.intel.com>
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+Signed-off-by: arun-pm <arun.p.m@linux.intel.com>
+Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com>
+---
+ arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts | 516 +++++++++++++++++++++++++
+ 1 file changed, 516 insertions(+)
+ create mode 100644 arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts
+
+diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts
+new file mode 100644
+index 000000000000..6d626338232e
+--- /dev/null
++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts
+@@ -0,0 +1,510 @@
++// SPDX-License-Identifier: GPL-2.0+
++/dts-v1/;
++
++#include "aspeed-g6.dtsi"
++#include <dt-bindings/gpio/aspeed-gpio.h>
++#include <dt-bindings/i2c/i2c.h>
++
++/ {
++ model = "AST2600 EVB";
++ compatible = "aspeed,ast2600";
++
++ chosen {
++ stdout-path = &uart5;
++ bootargs = "console=tty0 console=ttyS4,115200n8 root=/dev/ram rw init=/linuxrc";
++ };
++
++ memory@80000000 {
++ device_type = "memory";
++ reg = <0x80000000 0x40000000>;
++ };
++
++ reserved-memory {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ gfx_memory: framebuffer {
++ size = <0x01000000>;
++ alignment = <0x01000000>;
++ compatible = "shared-dma-pool";
++ reusable;
++ };
++
++ video_engine_memory: jpegbuffer {
++ size = <0x02000000>; /* 32M */
++ alignment = <0x01000000>;
++ compatible = "shared-dma-pool";
++ reusable;
++ };
++ };
++
++ reserved-memory {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++ video_memory: video {
++ size = <0x04000000>;
++ alignment = <0x01000000>;
++ compatible = "shared-dma-pool";
++ no-map;
++ };
++ };
++
++ iio-hwmon {
++ compatible = "iio-hwmon";
++ io-channels = <&adc0 0>, <&adc0 1>, <&adc0 2>, <&adc0 3>,
++ <&adc0 4>, <&adc0 5>, <&adc0 6>, <&adc0 7>,
++ <&adc1 0>, <&adc1 1>, <&adc1 2>, <&adc1 3>,
++ <&adc1 4>, <&adc1 5>, <&adc1 6>, <&adc1 7>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ identify {
++ default-state = "off";
++ gpios = <&gpio1 ASPEED_GPIO(B, 7) GPIO_ACTIVE_LOW>;
++ };
++
++ status_amber {
++ default-state = "off";
++ gpios = <&gpio1 ASPEED_GPIO(G, 3) GPIO_ACTIVE_LOW>;
++ };
++
++ status_green {
++ default-state = "keep";
++ gpios = <&gpio1 ASPEED_GPIO(G, 2) GPIO_ACTIVE_LOW>;
++ };
++ };
++/*
++ beeper {
++ compatible = "pwm-beeper";
++ pwms = <&timer 7 1000000 0>;
++ }; */
++};
++
++&fmc {
++ status = "okay";
++ flash: m25p80@0 {
++ compatible = "m25p80", "jedec,spi-nor";
++ reg = <0x0>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ spi-max-frequency = <40000000>;
++ spi-tx-bus-width = <4>;
++ m25p,fast-read;
++#include "openbmc-flash-layout-intel-64MB.dtsi"
++ };
++};
++
++&espi {
++ status = "okay";
++};
++
++&peci0 {
++ status = "okay";
++ gpios = <&gpio0 ASPEED_GPIO(F, 6) 0>;
++};
++
++&syscon {
++ uart-clock-high-speed;
++ status = "okay";
++
++ misc_control {
++ compatible = "aspeed,bmc-misc";
++ chip_id {
++ offset = <0x5b0>;
++ bit-mask = <0xffffffff 0xffffffff>;
++ bit-shift = <0>;
++ read-only;
++ reg-width = <64>;
++ hash-data = "d44f9b804976fa23c2e25d62f16154d26520a7e24c5555095fd1b55c027804f1570dcd16189739c640cd7d9a6ce14944a2c4eaf1dc429eed6940e8a83498a474";
++ };
++ };
++};
++
++#if 0
++ GPIO Alias: (runtime alias -> schematic name)
++ ID_BUTTON -> FP_ID_BTN_N
++ CPU_CATERR -> FM_PLT_BMC_THERMTRIP_N
++ PCH_BMC_THERMTRIP -> FM_PLT_BMC_THERMTRIP_N
++ RESET_BUTTON -> FP_BMC_RST_BTN_N
++ RESET_OUT -> RST_BMC_RSTBTN_OUT_R_N
++ POWER_BUTTON -> FP_BMC_PWR_BTN_R_N
++ POWER_OUT -> FM_BMC_PWR_BTN_N
++ PREQ_N -> DBP_ASD_BMC_PREQ_R_N
++ POST_COMPLETE -> FM_BIOS_POST_CMPLT_BMC_N
++ CPU_ERR0 -> FM_CPU_ERR0_LVT3_N
++ CPU_ERR1 -> FM_CPU_ERR1_LVT3_N
++ CPU_ERR2 -> FM_CPU_ERR2_LVT3_N
++ DEBUG_EN_N -> FM_JTAG_TCK_MUX_SEL_R
++ NMI_OUT -> IRQ_BMC_CPU_NMI_R
++ PLTRST_N -> RST_PLTRST_BMC_N
++ PRDY_N -> DBP_ASD_BMC_PRDY_R_N
++ PWR_DEBUG_N ->
++ XDP_PRST_N ->
++ SYSPWROK ->
++ RSMRST_N ->
++ SIO_S3 -> FM_SLPS3_R_N
++ SIO_S5 -> FM_SLPS4_R_N
++ SIO_ONCONTROL -> FM_BMC_ONCTL_R_N
++ SIO_POWER_GOOD -> PWRGD_CPU0_LVC3_R
++ PS_PWROK -> PWRGD_BMC_PS_PWROK_R
++ P3VBAT_BRIDGE_EN ->
++ TCK_MUX_SEL ->
++ SMI -> IRQ_SMI_ACTIVE_BMC_N
++ NMI_BUTTON -> FP_NMI_BTN_N
++#endif
++&gpio0 {
++ status = "okay";
++ /* Enable GPIOP0 and GPIOP2 pass-through by default */
++ /* pinctrl-names = "pass-through";
++ pinctrl-0 = <&pinctrl_thru0_default
++ &pinctrl_thru1_default>; */
++ gpio-line-names =
++ /*A0-A7*/ "","","","","SMB_CPU_PIROM_SCL","SMB_CPU_PIROM_SDA","SMB_IPMB_STBY_LVC3_R_SCL","SMB_IPMB_STBY_LVC3_R_SDA",
++ /*B0-B7*/ "FM_1200VA_OC","NMI_OUT","IRQ_SMB3_M2_ALERT_N","","RGMII_BMC_RMM4_LVC3_R_MDC","RGMII_BMC_RMM4_LVC3_R_MDIO","FM_BMC_BMCINIT_R","FP_ID_LED_N",
++ /*C0-C7*/ "FM_FORCE_BMC_UPDATE_N","RST_RGMII_PHYRST_N","FM_TPM_EN_PULSE","FM_BMC_CRASHLOG_TRIG_N","IRQ_BMC_PCH_NMI_R","FM_CPU1_DISABLE_COD_N","FM_4S_8S_N_MODE","FM_STANDALONE_MODE_N",
++ /*D0-D7*/ "CPU_ERR0","CPU_ERR1","CPU_ERR2","PRDY_N","FM_SPD_SWITCH_CTRL_N","","","",
++ /*E0-E7*/ "FM_SKT1_FAULT_LED","FM_SKT0_FAULT_LED","CLK_50M_CKMNG_BMCB","FM_BMC_BOARD_REV_ID2_N","","","","",
++ /*F0-F7*/ "FM_BMC_BOARD_SKU_ID0_N","FM_BMC_BOARD_SKU_ID1_N","FM_BMC_BOARD_SKU_ID2_N","FM_BMC_BOARD_SKU_ID3_N","FM_BMC_BOARD_SKU_ID4_N","FM_BMC_BOARD_SKU_ID5_N","ID_BUTTON","PS_PWROK",
++ /*G0-G7*/ "FM_SMB_BMC_NVME_LVC3_ALERT_N","RST_BMC_I2C_M2_R_N","FP_LED_STATUS_GREEN_N","FP_LED_STATUS_AMBER_N","FM_BMC_BOARD_REV_ID0_N","FM_BMC_BOARD_REV_ID1_N","FM_BMC_CPU_FBRK_OUT_R_N","DBP_PRESENT_IN_R2_N",
++ /*H0-H7*/ "SGPIO_BMC_CLK_R","SGPIO_BMC_LD_R","SGPIO_BMC_DOUT_R","SGPIO_BMC_DIN","PLTRST_N","CPU_CATERR","PCH_BMC_THERMTRIP","",
++ /*I0-I7*/ "JTAG_ASD_NTRST_R_N","JTAG_ASD_TDI_R","JTAG_ASD_TCK_R","JTAG_ASD_TMS_R","JTAG_ASD_TDO","FM_BMC_PWRBTN_OUT_R_N","FM_BMC_PWR_BTN_N","",
++ /*J0-J7*/ "SMB_CHASSENSOR_STBY_LVC3_SCL","SMB_CHASSENSOR_STBY_LVC3_SDA","FM_NODE_ID0","FM_NODE_ID1","","","","",
++ /*K0-K7*/ "SMB_HSBP_STBY_LVC3_R_SCL","SMB_HSBP_STBY_LVC3_R_SDA","SMB_SMLINK0_STBY_LVC3_R2_SCL","SMB_SMLINK0_STBY_LVC3_R2_SDA","SMB_TEMPSENSOR_STBY_LVC3_R_SCL","SMB_TEMPSENSOR_STBY_LVC3_R_SDA","SMB_PMBUS_SML1_STBY_LVC3_R_SCL","SMB_PMBUS_SML1_STBY_LVC3_R_SDA",
++ /*L0-L7*/ "SMB_PCIE_STBY_LVC3_R_SCL","SMB_PCIE_STBY_LVC3_R_SDA","SMB_HOST_STBY_BMC_LVC3_R_SCL","SMB_HOST_STBY_BMC_LVC3_R_SDA","PREQ_N","TCK_MUX_SEL","V_BMC_GFX_HSYNC_R","V_BMC_GFX_VSYNC_R",
++ /*M0-M7*/ "SPA_CTS_N","SPA_DCD_N","SPA_DSR_N","PU_SPA_RI_N","SPA_DTR_N","SPA_RTS_N","SPA_SOUT","SPA_SIN",
++ /*N0-N7*/ "SPB_CTS_N","SPB_DCD_N","SPB_DSR_N","PU_SPB_RI_N","SPB_DTR_N","SPB_RTS_N","SPB_SOUT","SPB_SIN",
++ /*O0-O7*/ "FAN_BMC_PWM0","FAN_BMC_PWM1","FAN_BMC_PWM2","FAN_BMC_PWM3","FAN_BMC_PWM4","FAN_BMC_PWM5","NMI_BUTTON","SPEAKER_BMC_R",
++ /*P0-P7*/ "RESET_BUTTON","RESET_OUT","POWER_BUTTON","POWER_OUT","FAN_BMC_PWM6","FAN_BMC_PWM7","FAN_BMC_PWM8","FAN_BMC_PWM9",
++ /*Q0-Q7*/ "FAN_BMC_TACH0","FAN_BMC_TACH1","FAN_BMC_TACH2","FAN_BMC_TACH3","FAN_BMC_TACH4","FAN_BMC_TACH5","FAN_BMC_TACH6","FAN_BMC_TACH7",
++ /*R0-R7*/ "FAN_BMC_TACH8","FAN_BMC_TACH9","","","","","","",
++ /*S0-S7*/ "RST_BMC_PCIE_MUX_N","FM_BMC_EUP_LOT6_N","","","","A_P3V_BAT_SCALED_EN","REMOTE_DEBUG_ENABLE","FM_PCHHOT_N",
++ /*T0-T7*/ "A_P12V_PSU_SCALED","A_P12V_AUX_SCALED","A_P3V3_SCALED","A_P5V_SCALED","A_PVNN_PCH_AUX_SENSOR","A_P1V05_PCH_AUX_SENSOR","A_P1V8_AUX_SENSOR","A_P3V_BAT_SCALED",
++ /*U0-U7*/ "A_PVCCIN_CPU0_SENSOR","A_PVCCIN_CPU1_SENSOR","A_PVCCINFAON_CPU0_SENSOR","A_PVCCINFAON_CPU1_SENSOR","A_PVCCFA_EHV_FIVRA_CPU0_SENSOR","A_PVCCFA_EHV_FIVRA_CPU1_SENSOR","A_PVCCD_HV_CPU0_SENSOR","A_PVCCD_HV_CPU1_SENSOR",
++ /*V0-V7*/ "SIO_S3","SIO_S5","TP_BMC_SIO_PWREQ_N","SIO_ONCONTROL","SIO_POWER_GOOD","LED_BMC_HB_LED_N","FM_BMC_SUSACK_N","",
++ /*W0-W7*/ "LPC_LAD0_ESPI_R_IO0","LPC_LAD1_ESPI_R_IO1","LPC_LAD2_ESPI_R_IO2","LPC_LAD3_ESPI_R_IO3","CLK_24M_66M_LPC0_ESPI_BMC","LPC_LFRAME_N_ESPI_CS0_BMC_N","IRQ_LPC_SERIRQ_ESPI_ALERT_N","RST_LPC_LRST_ESPI_RST_BMC_R_N",
++ /*X0-X7*/ "","SMI","POST_COMPLETE","","","","","",
++ /*Y0-Y7*/ "","IRQ_SML0_ALERT_BMC_R2_N","","IRQ_SML1_PMBUS_BMC_ALERT_N","SPI_BMC_BOOT_R_IO2","SPI_BMC_BOOT_R_IO3","PU_SPI_BMC_BOOT_ABR","PU_SPI_BMC_BOOT_WP_N",
++ /*Z0-Z7*/ "PWRGD_P3V3_RISER1","PWRGD_P3V3_RISER2","","HW_STRAP_5","HW_STRAP_6","HW_STRAP_7","HW_STRAP_2","HW_STRAP_3";
++};
++
++&gpio1 {
++ status = "disabled";
++ gpio-line-names = /* GPIO18 A-E */
++ /*A0-A7*/ "","","RST_EMMC_BMC_R_N","FM_SYS_FAN6_PRSNT_D_N","FM_SYS_FAN0_PRSNT_D_N","FM_SYS_FAN1_PRSNT_D_N","FM_SYS_FAN2_PRSNT_D_N","FM_SYS_FAN3_PRSNT_D_N",
++ /*B0-B7*/ "FM_SYS_FAN4_PRSNT_D_N","FM_SYS_FAN5_PRSNT_D_N","","FM_SYS_FAN7_PRSNT_D_N","RGMII_BMC_RMM4_TX_R_CLK","RGMII_BMC_RMM4_TX_R_CTRL","RGMII_BMC_RMM4_R_TXD0","RGMII_BMC_RMM4_R_TXD1",
++ /*C0-C7*/ "RGMII_BMC_RMM4_R_TXD2","RGMII_BMC_RMM4_R_TXD3","RGMII_BMC_RMM4_RX_CLK","RGMII_BMC_RMM4_RX_CTRL","RGMII_BMC_RMM4_RXD0","RGMII_BMC_RMM4_RXD1","RGMII_BMC_RMM4_RXD2","RGMII_BMC_RMM4_RXD3",
++ /*D0-D7*/ "EMMC_BMC_R_CLK","EMMC_BMC_R_CMD","EMMC_BMC_R_DATA0","EMMC_BMC_R_DATA1","EMMC_BMC_R_DATA2","EMMC_BMC_R_DATA3","EMMC_BMC_CD_N","EMMC_BMC_WP_N",
++ /*E0-E3*/ "EMMC_BMC_R_DATA4","EMMC_BMC_R_DATA5","EMMC_BMC_R_DATA6","EMMC_BMC_R_DATA7";
++};
++
++&sgpio {
++ status = "okay";
++ gpio-line-names =
++ /* SGPIO output lines */
++ /*OA0-OA7*/ "","","","","","","","",
++ /*OB0-OB7*/ "LED_CPU1_CH1_DIMM1_FAULT","LED_CPU1_CH1_DIMM2_FAULT","LED_CPU1_CH2_DIMM1_FAULT","LED_CPU1_CH2_DIMM2_FAULT","LED_CPU1_CH3_DIMM1_FAULT","LED_CPU1_CH3_DIMM2_FAULT","LED_CPU1_CH4_DIMM1_FAULT","LED_CPU1_CH4_DIMM2_FAULT",
++ /*OC0-OC7*/ "LED_CPU1_CH5_DIMM1_FAULT","LED_CPU1_CH5_DIMM2_FAULT","LED_CPU1_CH6_DIMM1_FAULT","LED_CPU1_CH6_DIMM2_FAULT","LED_FAN1_FAULT","LED_FAN2_FAULT","LED_FAN3_FAULT","LED_FAN4_FAULT",
++ /*OD0-OD7*/ "LED_FAN5_FAULT","LED_FAN6_FAULT","LED_FAN7_FAULT","LED_FAN8_FAULT","LED_CPU2_CH1_DIMM1_FAULT","LED_CPU1_CH1_DIMM2_FAULT","LED_CPU2_CH2_DIMM1_FAULT","LED_CPU2_CH2_DIMM2_FAULT",
++ /*OE0-OE7*/ "LED_CPU2_CH3_DIMM1_FAULT","LED_CPU2_CH3_DIMM2_FAULT","LED_CPU2_CH4_DIMM1_FAULT","LED_CPU2_CH4_DIMM2_FAULT","LED_CPU2_CH5_DIMM1_FAULT","LED_CPU2_CH5_DIMM2_FAULT","LED_CPU2_CH6_DIMM1_FAULT","LED_CPU2_CH6_DIMM2_FAULT",
++ /*OF0-OF7*/ "LED_CPU3_CH1_DIMM1_FAULT","LED_CPU3_CH1_DIMM2_FAULT","LED_CPU3_CH2_DIMM1_FAULT","LED_CPU3_CH2_DIMM2_FAULT","LED_CPU3_CH3_DIMM1_FAULT","LED_CPU3_CH3_DIMM2_FAULT","LED_CPU3_CH4_DIMM1_FAULT","LED_CPU3_CH4_DIMM2_FAULT",
++ /*OG0-OG7*/ "LED_CPU3_CH5_DIMM1_FAULT","LED_CPU3_CH5_DIMM2_FAULT","LED_CPU3_CH6_DIMM1_FAULT","LED_CPU3_CH6_DIMM2_FAULT","LED_CPU4_CH1_DIMM1_FAULT","LED_CPU4_CH1_DIMM2_FAULT","LED_CPU4_CH2_DIMM1_FAULT","LED_CPU4_CH2_DIMM2_FAULT",
++ /*OH0-OH7*/ "LED_CPU4_CH3_DIMM1_FAULT","LED_CPU4_CH3_DIMM2_FAULT","LED_CPU4_CH4_DIMM1_FAULT","LED_CPU4_CH4_DIMM2_FAULT","LED_CPU4_CH5_DIMM1_FAULT","LED_CPU4_CH5_DIMM2_FAULT","LED_CPU4_CH6_DIMM1_FAULT","LED_CPU4_CH6_DIMM2_FAULT",
++ /*OI0-OI7*/ "","","","","","","","",
++ /*OJ0-OJ7*/ "","","","","","","","",
++ /*DUMMY*/ "","","","","","","","",
++ /*DUMMY*/ "","","","","","","","",
++
++ /* SGPIO input lines */
++ /* Some lines have been renamed from the net names:
++ CPU1_PRESENCE -> FM_CPU0_SKTOCC_LVT3_N
++ CPU1_THERMTRIP -> H_CPU0_THERMTRIP_LVC1_N
++ CPU1_VRHOT -> IRQ_CPU0_VRHOT_N
++ CPU1_FIVR_FAULT -> H_CPU0_MON_FAIL_PLD_LVC1_N
++ CPU1_MEM_ABCD_VRHOT -> ??
++ CPU1_MEM_EFGH_VRHOT -> ??
++ CPU2_PRESENCE -> FM_CPU1_SKTOCC_LVT3_N
++ CPU2_THERMTRIP -> H_CPU1_THERMTRIP_LVC1_N
++ CPU2_VRHOT -> IRQ_CPU1_VRHOT_N
++ CPU2_FIVR_FAULT -> H_CPU1_MON_FAIL_PLD_LVC1_N
++ CPU2_MEM_ABCD_VRHOT -> ??
++ CPU2_MEM_EFGH_VRHOT -> ??
++
++ /*IA0-IA7*/ "CPU1_PRESENCE","CPU1_THERMTRIP","CPU1_VRHOT","CPU1_FIVR_FAULT","IRQ_CPU0_MEM_VRHOT_N","H_CPU0_MEMHOT_OUT_LVC1_N","FM_CPU0_PROC_ID0","FM_CPU0_PROC_ID1",
++ /*IB0-IB7*/ "WCPU_MISMATCH","IRQ_PSYS_CRIT_N","CPU2_PRESENCE","CPU2_THERMTRIP","CPU2_VRHOT","CPU2_FIVR_FAULT","IRQ_CPU1_MEM_VRHOT_N","H_CPU1_MEMHOT_OUT_LVC1_N",
++ /*IC0-IC7*/ "FM_CPU1_PROC_ID0","FM_CPU1_PROC_ID1","","","","","","",
++ /*ID0-ID7*/ "","","","","","","","",
++ /*IE0-IE7*/ "","","","","","","","",
++ /*IF0-IF7*/ "FPGA_REV_TEST_0","FPGA_REV_TEST_1","FPGA_REV_TEST_2","FPGA_REV_TEST_3","FPGA_REV_TEST_4","FPGA_REV_TEST_5","FPGA_REV_TEST_6","FPGA_REV_TEST_7",
++ /*IG0-IG7*/ "FPGA_REV_0","FPGA_REV_1","FPGA_REV_2","FPGA_REV_3","FPGA_REV_4","FPGA_REV_5","FPGA_REV_6","FPGA_REV_7",
++ /*IH0-IH7*/ "","WMEMX_PWR_FLT","WCPUX_MEM_PWR_FLT","PWRGD_P3V3_FF","WPSU_PWR_FLT","","","WPCH_PWR_FLT",
++ /*II0-II7*/ "FM_CPU0_PKGID0","FM_CPU0_PKGID1","FM_CPU0_PKGID2","H_CPU0_MEMTRIP_LVC1_N","FM_CPU1_PKGID0","FM_CPU1_PKGID1","FM_CPU1_PKGID2","H_CPU1_MEMTRIP_LVC1_N",
++ /*IJ0-IJ7*/ "","","","","","","","";
++};
++
++&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";
++};
++
++&mdio1 {
++ status = "okay";
++
++ ethphy1: ethernet-phy@0 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <0>;
++ };
++};
++
++&mac1 {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_rgmii2_default>;
++ clocks = <&syscon ASPEED_CLK_GATE_MAC2CLK>,
++ <&syscon ASPEED_CLK_MAC2RCLK>;
++ clock-names = "MACCLK", "RCLK";
++ phy-mode = "rgmii";
++ phy-handle = <&ethphy1>;
++};
++
++&mdio2 {
++ status = "okay";
++
++ ethphy2: ethernet-phy@1 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <0>;
++ };
++};
++
++&adc0 {
++ status = "okay";
++};
++
++&adc1 {
++ status = "okay";
++};
++
++&uart1 {
++ status = "okay";
++ 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-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";
++ pinctrl-0 = <>;
++};
++
++&uart4 {
++ status = "okay";
++ pinctrl-0 = <>;
++};
++
++&uart5 {
++ status = "okay";
++ // Workaround for A0
++ compatible = "snps,dw-apb-uart";
++};
++
++&uart_routing {
++ status = "okay";
++};
++
++&emmc_controller{
++ status = "okay";
++};
++
++&emmc {
++ non-removable;
++ bus-width = <4>;
++ max-frequency = <52000000>;
++};
++
++&i2c0 {
++ /* SMB_CHASSENSOR_STBY_LVC3 */
++ multi-master;
++ status = "okay";
++};
++
++&i2c4 {
++ /* SMB_HSBP_STBY_LVC3_R */
++ multi-master;
++ status = "okay";
++};
++
++&i2c5 {
++ /* SMB_SMLINK0_STBY_LVC3_R2 */
++ bus-frequency = <1000000>;
++ multi-master;
++ status = "okay";
++};
++
++&i2c6 {
++ /* SMB_TEMPSENSOR_STBY_LVC3_R */
++ multi-master;
++ status = "okay";
++};
++
++&i2c7 {
++ /* SMB_PMBUS_SML1_STBY_LVC3_R */
++ multi-master;
++ #retries = <3>;
++ status = "okay";
++};
++
++&i2c8 {
++ /* SMB_PCIE_STBY_LVC3_R */
++ multi-master;
++ status = "okay";
++};
++
++&i2c9 {
++ /* SMB_HOST_STBY_BMC_LVC3_R */
++ multi-master;
++ status = "okay";
++};
++
++&i2c12 {
++ /* SMB_CPU_PIROM */
++ multi-master;
++ status = "okay";
++};
++
++&i2c13 {
++ /* SMB_IPMB_STBY_LVC3_R */
++ multi-master;
++ status = "okay";
++};
++
++&i3c0 {
++ /* I3C_SPD_DDRABCD_CPU0_BMC ; FIXME: i3c driver hangs kernel on probe...*/
++ status = "disabled";
++};
++
++&i3c1 {
++ /* I3C_SPD_DDREFGH_CPU0_BMC */
++ status = "disabled";
++};
++
++&i3c2 {
++ /* I3C_SPD_DDRABCD_CPU1_BMC */
++ status = "disabled";
++};
++
++&i3c3 {
++ /* I3C_SPD_DDREFGH_CPU1_BMC */
++ status = "disabled";
++};
++
++&gfx {
++ status = "okay";
++ memory-region = <&gfx_memory>;
++};
++
++&pwm_tacho {
++ status = "disabled";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_tach0_default
++ &pinctrl_pwm1_default &pinctrl_tach1_default
++ &pinctrl_pwm2_default &pinctrl_tach2_default
++ &pinctrl_pwm3_default &pinctrl_tach3_default
++ &pinctrl_pwm4_default &pinctrl_tach4_default
++ &pinctrl_pwm5_default &pinctrl_tach5_default
++ &pinctrl_pwm12g1_default &pinctrl_tach6_default
++ &pinctrl_pwm13g1_default &pinctrl_tach7_default
++ &pinctrl_pwm14g1_default &pinctrl_tach8_default
++ &pinctrl_pwm15g1_default &pinctrl_tach9_default>; /*pwm 6-11 used for some other functionality*/
++
++ fan@0 {
++ reg = <0x00>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x00>;
++ };
++ fan@1 {
++ reg = <0x01>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x01>;
++ };
++ fan@2 {
++ reg = <0x02>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x02>;
++ };
++ fan@3 {
++ reg = <0x03>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x03>;
++ };
++ fan@4 {
++ reg = <0x04>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x04>;
++ };
++ fan@5 {
++ reg = <0x05>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x05>;
++ };
++ fan@6 {
++ reg = <0x06>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x06>;
++ };
++ fan@7 {
++ reg = <0x07>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x07>;
++ };
++ fan@8 {
++ reg = <0x08>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x08>;
++ };
++ fan@9 {
++ reg = <0x09>;
++ aspeed,fan-tach-ch = /bits/ 8 <0x09>;
++ };
++};
++
++&video {
++ status = "okay";
++ memory-region = <&video_engine_memory>;
++};
++
++&vhub {
++ status = "okay";
++};
++
++&jtag1 {
++ status = "okay";
++};
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-base-aspeed-g6-dtsi-fixups.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-base-aspeed-g6-dtsi-fixups.patch
new file mode 100644
index 000000000..d75229a15
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-base-aspeed-g6-dtsi-fixups.patch
@@ -0,0 +1,212 @@
+From 5e5758fe5929766a9b4677b86f9343a777526fe8 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Thu, 12 Sep 2019 15:55:39 +0800
+Subject: [PATCH] arm: dts: base aspeed g6 dtsi fixups
+
+Additions to the base g6 dtsi file for Aspeed ast2600 systems.
+This mostly includes entries for the drivers that are not upstream.
+
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ arch/arm/boot/dts/aspeed-g6.dtsi | 129 +++++++++++++++++++++++++++++-
+ include/dt-bindings/clock/ast2600-clock.h | 8 ++
+ 2 files changed, 135 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index 2af9efa1faa1..54add29d8217 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -28,6 +28,12 @@
+ i2c13 = &i2c13;
+ i2c14 = &i2c14;
+ i2c15 = &i2c15;
++ i3c0 = &i3c0;
++ i3c1 = &i3c1;
++ i3c2 = &i3c2;
++ i3c3 = &i3c3;
++ i3c4 = &i3c4;
++ i3c5 = &i3c5;
+ serial0 = &uart1;
+ serial1 = &uart2;
+ serial2 = &uart3;
+@@ -297,11 +303,21 @@
+ quality = <100>;
+ };
+
++ adc: adc@1e6e9000 {
++ compatible = "aspeed,ast2500-adc";
++ reg = <0x1e6e9000 0x100>;
++ clocks = <&syscon ASPEED_CLK_APB2>;
++ interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
++ resets = <&syscon ASPEED_RESET_ADC>;
++ #io-channel-cells = <1>;
++ status = "disabled";
++ };
++
+ gpio0: gpio@1e780000 {
+ #gpio-cells = <2>;
+ gpio-controller;
+ compatible = "aspeed,ast2600-gpio";
+- reg = <0x1e780000 0x800>;
++ reg = <0x1e780000 0x200>;
+ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 0 208>;
+ ngpios = <208>;
+@@ -314,7 +330,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ compatible = "aspeed,ast2600-gpio";
+- reg = <0x1e780800 0x800>;
++ reg = <0x1e780800 0x200>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 208 36>;
+ ngpios = <36>;
+@@ -398,6 +414,13 @@
+ ranges = <0x0 0x1e78b000 0x100>;
+ };
+
++ i3c: bus@1e7a0000 {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges = <0 0x1e7a0000 0x8000>;
++ };
++
+ lpc: lpc@1e789000 {
+ compatible = "aspeed,ast2600-lpc", "simple-mfd";
+ reg = <0x1e789000 0x1000>;
+@@ -486,6 +509,20 @@
+ sio_regs: regs {
+ compatible = "aspeed,bmc-misc";
+ };
++
++ lpc_sio: lpc-sio@100 {
++ compatible = "aspeed,ast2500-lpc-sio";
++ reg = <0x100 0x20>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
++
++ mbox: mbox@180 {
++ compatible = "aspeed,ast2600-mbox";
++ reg = <0x180 0x5c>;
++ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
++ #mbox-cells = <1>;
++ };
+ };
+ };
+
+@@ -871,3 +908,91 @@
+ status = "disabled";
+ };
+ };
++
++&i3c {
++ i3c0: i3c0@2000 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ #interrupt-cells = <1>;
++ reg = <0x2000 0x1000>;
++ compatible = "snps,dw-i3c-master-1.00a";
++ clocks = <&syscon ASPEED_CLK_APB2>;
++ resets = <&syscon ASPEED_RESET_I3C0>;
++ bus-frequency = <100000>;
++ interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++ };
++
++ i3c1: i3c1@3000 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ #interrupt-cells = <1>;
++ reg = <0x3000 0x1000>;
++ compatible = "snps,dw-i3c-master-1.00a";
++ clocks = <&syscon ASPEED_CLK_APB2>;
++ resets = <&syscon ASPEED_RESET_I3C1>;
++ bus-frequency = <100000>;
++ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++ };
++
++ i3c2: i3c2@4000 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ #interrupt-cells = <1>;
++ reg = <0x4000 0x1000>;
++ compatible = "snps,dw-i3c-master-1.00a";
++ clocks = <&syscon ASPEED_CLK_APB2>;
++ resets = <&syscon ASPEED_RESET_I3C2>;
++ bus-frequency = <100000>;
++ interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i3c3_default>;
++ status = "disabled";
++ };
++
++ i3c3: i3c3@5000 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ #interrupt-cells = <1>;
++ reg = <0x5000 0x1000>;
++ compatible = "snps,dw-i3c-master-1.00a";
++ clocks = <&syscon ASPEED_CLK_APB2>;
++ resets = <&syscon ASPEED_RESET_I3C3>;
++ bus-frequency = <100000>;
++ interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i3c4_default>;
++ status = "disabled";
++ };
++
++ i3c4: i3c4@6000 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ #interrupt-cells = <1>;
++ reg = <0x6000 0x1000>;
++ compatible = "snps,dw-i3c-master-1.00a";
++ clocks = <&syscon ASPEED_CLK_APB2>;
++ resets = <&syscon ASPEED_RESET_I3C4>;
++ bus-frequency = <100000>;
++ interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i3c5_default>;
++ status = "disabled";
++ };
++
++ i3c5: i3c5@7000 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ #interrupt-cells = <1>;
++ reg = <0x7000 0x1000>;
++ compatible = "snps,dw-i3c-master-1.00a";
++ clocks = <&syscon ASPEED_CLK_APB2>;
++ resets = <&syscon ASPEED_RESET_I3C5>;
++ bus-frequency = <100000>;
++ interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_i3c6_default>;
++ status = "disabled";
++ };
++};
+diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h
+index 62b9520a00fd..3d90582a813f 100644
+--- a/include/dt-bindings/clock/ast2600-clock.h
++++ b/include/dt-bindings/clock/ast2600-clock.h
+@@ -91,6 +91,14 @@
+ /* Only list resets here that are not part of a gate */
+ #define ASPEED_RESET_ADC 55
+ #define ASPEED_RESET_JTAG_MASTER2 54
++#define ASPEED_RESET_I3C7 47
++#define ASPEED_RESET_I3C6 46
++#define ASPEED_RESET_I3C5 45
++#define ASPEED_RESET_I3C4 44
++#define ASPEED_RESET_I3C3 43
++#define ASPEED_RESET_I3C2 42
++#define ASPEED_RESET_I3C1 41
++#define ASPEED_RESET_I3C0 40
+ #define ASPEED_RESET_I3C_DMA 39
+ #define ASPEED_RESET_PWM 37
+ #define ASPEED_RESET_PECI 36
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Add-Aspeed-fmc-spi-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Add-Aspeed-fmc-spi-driver.patch
new file mode 100644
index 000000000..08e350c15
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Add-Aspeed-fmc-spi-driver.patch
@@ -0,0 +1,645 @@
+From 1365492683b47f63d470d0666fee258a5c7ca3c3 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@intel.com>
+Date: Thu, 12 Sep 2019 15:26:08 -0700
+Subject: [PATCH 04/52] Add Aspeed fmc-spi driver
+
+Add the Aspeed fmc-spi driver from the Apeed SDK v5.02
+
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ arch/arm/boot/dts/aspeed-g6.dtsi | 43 ++-
+ drivers/spi/Kconfig | 6 +
+ drivers/spi/Makefile | 1 +
+ drivers/spi/fmc_spi.c | 530 +++++++++++++++++++++++++++++++
+ 4 files changed, 579 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/spi/fmc_spi.c
+
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index 42f644ac8111..1aab48fbf49e 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -90,7 +90,7 @@
+ <0x40464000 0x2000>,
+ <0x40466000 0x2000>;
+ };
+-
++#if 1
+ fmc: spi@1e620000 {
+ reg = < 0x1e620000 0xc4
+ 0x20000000 0x10000000 >;
+@@ -169,6 +169,47 @@
+ status = "disabled";
+ };
+ };
++#else
++ spi0: spi@1e620000 {
++ /* reg : cs0 : cs1 : cs2 */
++ reg = <0x1e620000 0x100
++ 0x20000000 0x40
++ 0x28000000 0x40>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "aspeed,fmc-spi";
++ clocks = <&syscon ASPEED_CLK_AHB>;
++ status = "disable";
++ number_of_chip_select = /bits/ 16 <2>;
++ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
++ spi1: spi1@1e630000 {
++ /* reg : cs0 : cs1 */
++ reg = <0x1e630000 0x100
++ 0x30000000 0x20
++ 0x32000000 0x20>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "aspeed,fmc-spi";
++ clocks = <&syscon ASPEED_CLK_AHB>;
++ status = "disable";
++ number_of_chip_select = /bits/ 16 <2>;
++ };
++
++ spi2: spi2@1e631000 {
++ /* reg : cs0 : cs1 */
++ reg = <0x1e631000 0x100
++ 0x38000000 0x20
++ 0x3A000000 0x20>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "aspeed,fmc-spi";
++ clocks = <&syscon ASPEED_CLK_AHB>;
++ status = "disable";
++ number_of_chip_select = /bits/ 16 <2>;
++ };
++#endif
+
+ mdio0: mdio@1e650000 {
+ compatible = "aspeed,ast2600-mdio";
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 6ee514fd0920..9f32c31ffa3c 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -57,6 +57,12 @@ config SPI_MEM
+
+ comment "SPI Master Controller Drivers"
+
++config SPI_FMC
++ tristate "Aspeed FMC SPI Controller"
++ depends on ARCH_ASPEED
++ help
++ This selects a driver for the AST FMC SPI Controller
++
+ config SPI_ALTERA
+ tristate "Altera SPI Controller"
+ help
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index adbebee93a75..224b9b71e29c 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -13,6 +13,7 @@ obj-$(CONFIG_SPI_SPIDEV) += spidev.o
+ obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o
+
+ # SPI master controller drivers (bus)
++obj-$(CONFIG_SPI_FMC) += fmc_spi.o
+ obj-$(CONFIG_SPI_ALTERA) += spi-altera.o
+ obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o
+ obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
+diff --git a/drivers/spi/fmc_spi.c b/drivers/spi/fmc_spi.c
+new file mode 100644
+index 000000000000..f21f7a00496e
+--- /dev/null
++++ b/drivers/spi/fmc_spi.c
+@@ -0,0 +1,530 @@
++/*
++ * fmc_spi.c - FMC SPI driver for the Aspeed SoC
++ *
++ * Copyright (C) ASPEED Technology Inc.
++ * Ryan Chen <ryan_chen@aspeedtech.com>
++ *
++ * 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/module.h>
++#include <linux/init.h>
++#include <linux/clk.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/errno.h>
++#include <linux/wait.h>
++#include <linux/delay.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/of_platform.h>
++
++/******************************************************************************/
++/* AST_SPI_CONFIG 0x00 : SPI00 CE Type Setting Register */
++#define AST_G5_SPI_CONF_CE1_WEN (0x1 << 17)
++#define AST_G5_SPI_CONF_CE0_WEN (0x1 << 16)
++
++#define SPI_CONF_CE0_WEN (0x1)
++
++/* Register offsets */
++#define FMC_SPI_CONFIG 0x00
++#define FMC_SPI_CTRL 0x04
++#define FMC_SPI_DMA_STS 0x08
++
++#define FMC_SPI_CE0_CTRL 0x10
++#define FMC_SPI_CE1_CTRL 0x14
++
++#define AST_SPI_DMA_CTRL 0x80
++#define AST_SPI_DMA_FLASH_BASE 0x84
++#define AST_SPI_DMA_DRAM_BASE 0x88
++#define AST_SPI_DMA_LENGTH 0x8c
++
++/* AST_FMC_CONFIG 0x00 : FMC00 CE Type Setting Register */
++#define FMC_CONF_LAGACY_DIS (0x1 << 31)
++#define FMC_CONF_CE1_WEN (0x1 << 17)
++#define FMC_CONF_CE0_WEN (0x1 << 16)
++#define FMC_CONF_CE1_SPI (0x2 << 2)
++#define FMC_CONF_CE0_SPI (0x2)
++
++/* FMC_SPI_CTRL : 0x04 : FMC04 CE Control Register */
++#define FMC_CTRL_CE1_4BYTE_MODE (0x1 << 1)
++#define FMC_CTRL_CE0_4BYTE_MODE (0x1)
++
++/* FMC_SPI_DMA_STS : 0x08 : FMC08 Interrupt Control and Status Register */
++#define FMC_STS_DMA_READY 0x0800
++#define FMC_STS_DMA_CLEAR 0x0800
++
++/* FMC_CE0_CTRL for SPI 0x10, 0x14, 0x18, 0x1c, 0x20 */
++#define SPI_IO_MODE_MASK (3 << 28)
++#define SPI_SINGLE_BIT (0 << 28)
++#define SPI_DUAL_MODE (0x2 << 28)
++#define SPI_DUAL_IO_MODE (0x3 << 28)
++#define SPI_QUAD_MODE (0x4 << 28)
++#define SPI_QUAD_IO_MODE (0x5 << 28)
++
++#define SPI_CE_WIDTH(x) (x << 24)
++#define SPI_CMD_DATA_MASK (0xff << 16)
++#define SPI_CMD_DATA(x) (x << 16)
++#define SPI_DUMMY_CMD (1 << 15)
++#define SPI_DUMMY_HIGH (1 << 14)
++//#define SPI_CLK_DIV (1 << 13) ?? TODO ask....
++//#define SPI_ADDR_CYCLE (1 << 13) ?? TODO ask....
++#define SPI_CMD_MERGE_DIS (1 << 12)
++#define SPI_CLK_DIV(x) (x << 8)
++#define SPI_CLK_DIV_MASK (0xf << 8)
++
++#define SPI_DUMMY_LOW_MASK (0x3 << 6)
++#define SPI_DUMMY_LOW(x) ((x) << 6)
++#define SPI_LSB_FIRST_CTRL (1 << 5)
++#define SPI_CPOL_1 (1 << 4)
++#define SPI_DUAL_DATA (1 << 3)
++#define SPI_CE_INACTIVE (1 << 2)
++#define SPI_CMD_MODE_MASK (0x3)
++#define SPI_CMD_NORMAL_READ_MODE 0
++#define SPI_CMD_READ_CMD_MODE 1
++#define SPI_CMD_WRITE_CMD_MODE 2
++#define SPI_CMD_USER_MODE 3
++
++/* AST_SPI_DMA_CTRL 0x80 */
++#define FMC_DMA_ENABLE (0x1)
++
++/******************************************************************************/
++struct fmc_spi_host {
++ void __iomem *base;
++ void __iomem *ctrl_reg;
++ u32 buff[5];
++ struct spi_master *master;
++ struct spi_device *spi_dev;
++ struct device *dev;
++ u32 ahb_clk;
++ spinlock_t lock;
++};
++
++static u32 ast_spi_calculate_divisor(struct fmc_spi_host *host,
++ u32 max_speed_hz)
++{
++ // [0] ->15 : HCLK , HCLK/16
++ u8 SPI_DIV[16] = {
++ 16, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0
++ };
++ u32 i, spi_cdvr = 0;
++
++ for (i = 1; i < 17; i++) {
++ if (max_speed_hz >= (host->ahb_clk / i)) {
++ spi_cdvr = SPI_DIV[i - 1];
++ break;
++ }
++ }
++
++ // printk("hclk is %d, divisor is %d, target :%d , cal speed %d\n", host->ahb_clk, spi_cdvr, spi->max_speed_hz, hclk/i);
++ return spi_cdvr;
++}
++
++/* the spi->mode bits understood by this driver: */
++#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
++
++static int fmc_spi_setup(struct spi_device *spi)
++{
++ struct fmc_spi_host *host =
++ (struct fmc_spi_host *)spi_master_get_devdata(spi->master);
++ unsigned int bits = spi->bits_per_word;
++ u32 fmc_config = 0;
++ u32 spi_ctrl = 0;
++ u32 divisor;
++
++ // dev_dbg(host->dev, "fmc_spi_setup() cs: %d, spi->mode %d \n", spi->chip_select, spi->mode);
++ // printk("fmc_spi_setup() cs: %d, spi->mode %d spi->max_speed_hz %d , spi->bits_per_word %d \n", spi->chip_select, spi->mode, spi->max_speed_hz, spi->bits_per_word);
++
++ switch (spi->chip_select) {
++ case 0:
++ fmc_config |= FMC_CONF_CE0_WEN | FMC_CONF_CE0_SPI;
++ host->ctrl_reg = host->base + FMC_SPI_CE0_CTRL;
++ break;
++ case 1:
++ fmc_config |= FMC_CONF_CE1_WEN | FMC_CONF_CE1_SPI;
++ host->ctrl_reg = host->base + FMC_SPI_CE0_CTRL;
++ break;
++ default:
++ dev_dbg(&spi->dev,
++ "setup: invalid chipselect %u (%u defined)\n",
++ spi->chip_select, spi->master->num_chipselect);
++ return -EINVAL;
++ break;
++ }
++ writel(fmc_config, host->base);
++
++ if (bits == 0)
++ bits = 8;
++
++ if (bits < 8 || bits > 16) {
++ dev_dbg(&spi->dev,
++ "setup: invalid bits_per_word %u (8 to 16)\n", bits);
++ return -EINVAL;
++ }
++
++ if (spi->mode & ~MODEBITS) {
++ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
++ spi->mode & ~MODEBITS);
++ return -EINVAL;
++ }
++
++ /* see notes above re chipselect */
++ if ((spi->chip_select == 0) && (spi->mode & SPI_CS_HIGH)) {
++ dev_dbg(&spi->dev, "setup: can't be active-high\n");
++ return -EINVAL;
++ }
++
++ /*
++ * Pre-new_1 chips start out at half the peripheral
++ * bus speed.
++ */
++
++ if (spi->max_speed_hz) {
++ /* Set the SPI slaves select and characteristic control register */
++ divisor = ast_spi_calculate_divisor(host, spi->max_speed_hz);
++ } else {
++ /* speed zero means "as slow as possible" */
++ divisor = 15;
++ }
++
++ spi_ctrl &= ~SPI_CLK_DIV_MASK;
++ // printk("set div %x \n",divisor);
++ //TODO MASK first
++ spi_ctrl |= SPI_CLK_DIV(divisor);
++
++ /* only support mode 0 (CPOL=0, CPHA=0) and cannot support mode 1 ~ mode 3 */
++
++#if 0
++ if (SPI_CPHA & spi->mode)
++ cpha = SPI_CPHA_1;
++ else
++ cpha = SPI_CPHA_0;
++#endif
++
++ // if (SPI_CPOL & spi->mode)
++ // spi_ctrl |= SPI_CPOL_1;
++ // else
++ // spi_ctrl &= ~SPI_CPOL_1;
++
++ //ISSUE : ast spi ctrl couldn't use mode 3, so fix mode 0
++ spi_ctrl &= ~SPI_CPOL_1;
++
++ if (SPI_LSB_FIRST & spi->mode)
++ spi_ctrl |= SPI_LSB_FIRST_CTRL;
++ else
++ spi_ctrl &= ~SPI_LSB_FIRST_CTRL;
++
++ /* Configure SPI controller */
++ writel(spi_ctrl, host->ctrl_reg);
++
++ // printk("ctrl %x, ", spi_ctrl);
++ return 0;
++}
++
++static int fmc_spi_transfer(struct spi_device *spi, struct spi_message *msg)
++{
++ struct fmc_spi_host *host =
++ (struct fmc_spi_host *)spi_master_get_devdata(spi->master);
++ struct spi_transfer *xfer;
++ const u8 *tx_buf;
++ u8 *rx_buf;
++ unsigned long flags;
++
++ int i = 0, j = 0;
++
++ // dev_dbg(host->dev, "xfer %s \n", dev_name(&spi->dev));
++ // printk("xfer spi->chip_select %d \n", spi->chip_select);
++
++ host->spi_dev = spi;
++ spin_lock_irqsave(&host->lock, flags);
++
++ writel(readl(host->ctrl_reg) | SPI_CMD_USER_MODE, host->ctrl_reg);
++ msg->actual_length = 0;
++ msg->status = 0;
++
++ list_for_each_entry (xfer, &msg->transfers, transfer_list) {
++ dev_dbg(host->dev,
++ "xfer[%d] %p: width %d, len %u, tx %p/%08x, rx %p/%08x\n",
++ j, xfer, xfer->bits_per_word, xfer->len, xfer->tx_buf,
++ xfer->tx_dma, xfer->rx_buf, xfer->rx_dma);
++
++ tx_buf = xfer->tx_buf;
++ rx_buf = xfer->rx_buf;
++
++ if (tx_buf != 0) {
++#if 0
++ printk("tx : ");
++ if(xfer->len > 10) {
++ for(i=0;i<10;i++)
++ printk("%x ",tx_buf[i]);
++ } else {
++ for(i=0;i<xfer->len;i++)
++ printk("%x ",tx_buf[i]);
++ }
++ printk("\n");
++#endif
++ for (i = 0; i < xfer->len; i++) {
++ writeb(tx_buf[i],
++ (void *)host->buff
++ [host->spi_dev->chip_select]);
++ }
++ }
++ //Issue need clarify
++ udelay(1);
++ if (rx_buf != 0) {
++ for (i = 0; i < xfer->len; i++) {
++ rx_buf[i] = readb(
++ (void *)host->buff
++ [host->spi_dev->chip_select]);
++ }
++#if 0
++ printk("rx : ");
++ if(xfer->len > 10) {
++ for(i=0;i<10;i++)
++ printk(" %x",rx_buf[i]);
++ } else {
++ for(i=0;i<xfer->len;i++)
++ printk(" %x",rx_buf[i]);
++ }
++ printk("\n");
++#endif
++ }
++ dev_dbg(host->dev, "old msg->actual_length %d , +len %d \n",
++ msg->actual_length, xfer->len);
++ msg->actual_length += xfer->len;
++ dev_dbg(host->dev, "new msg->actual_length %d \n",
++ msg->actual_length);
++ // j++;
++ }
++
++ // writel( SPI_CE_INACTIVE | readl(host->spi_data->ctrl_reg),host->spi_data->ctrl_reg);
++ writel(readl(host->ctrl_reg) & ~SPI_CMD_USER_MODE, host->ctrl_reg);
++ msg->status = 0;
++
++ msg->complete(msg->context);
++
++ // spin_unlock(&host->lock);
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ return 0;
++}
++
++static void fmc_spi_cleanup(struct spi_device *spi)
++{
++ struct fmc_spi_host *host = spi_master_get_devdata(spi->master);
++ unsigned long flags;
++ dev_dbg(host->dev, "fmc_spi_cleanup() \n");
++
++ spin_lock_irqsave(&host->lock, flags);
++ // if (host->stay == spi) {
++ // host->stay = NULL;
++ // cs_deactivate(host, spi);
++ // }
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++#if 0
++static int fmc_spi_flash_read(struct spi_device *spi,
++ struct spi_flash_read_message *msg)
++{
++// struct fmc_spi_host *host = spi_master_get_devdata(spi->master);
++ int ret = 0;
++
++// printk("read msg->from %x, msg->len %x , msg->buf %x , msg->addr_width %d , msg->dummy_bytes %x , msg->read_opcode %x \n", msg->from, msg->len, msg->buf, msg->addr_width, msg->dummy_bytes, msg->read_opcode);
++
++// memcpy_fromio(msg->buf, b53spi->mmio_base + msg->from, msg->len);
++ msg->retlen = msg->len;
++
++ return ret;
++}
++#endif
++
++static int fmc_spi_probe(struct platform_device *pdev)
++{
++ struct resource *res;
++ struct fmc_spi_host *host;
++ struct spi_master *master;
++ struct clk *clk;
++ int cs_num = 0;
++ int err = 0;
++
++ dev_dbg(&pdev->dev, "fmc_spi_probe() \n");
++
++ master = spi_alloc_master(&pdev->dev, sizeof(struct fmc_spi_host));
++ if (NULL == master) {
++ dev_err(&pdev->dev, "No memory for spi_master\n");
++ err = -ENOMEM;
++ goto err_nomem;
++ }
++
++ /* the spi->mode bits understood by this driver: */
++ master->mode_bits =
++ SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_RX_DUAL | SPI_TX_DUAL;
++ master->bits_per_word_mask = SPI_BPW_MASK(8);
++
++ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_RX_DUAL;
++ // master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
++ master->dev.of_node = pdev->dev.of_node;
++ master->bus_num = pdev->id;
++ // master->num_chipselect = master->dev.of_node ? 0 : 4;
++ platform_set_drvdata(pdev, master);
++
++ host = spi_master_get_devdata(master);
++ memset(host, 0, sizeof(struct fmc_spi_host));
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev, "cannot get IORESOURCE_MEM 0\n");
++ err = -ENXIO;
++ goto err_no_io_res;
++ }
++
++ host->base = devm_ioremap_resource(&pdev->dev, res);
++ if (!host->base) {
++ dev_err(&pdev->dev, "cannot remap register\n");
++ err = -EIO;
++ goto err_no_io_res;
++ }
++
++ clk = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(clk)) {
++ dev_err(&pdev->dev, "no clock defined\n");
++ return -ENODEV;
++ }
++ host->ahb_clk = clk_get_rate(clk);
++
++ dev_dbg(&pdev->dev, "remap phy %x, virt %x \n", (u32)res->start,
++ (u32)host->base);
++
++ host->master = spi_master_get(master);
++
++ if (of_property_read_u16(pdev->dev.of_node, "number_of_chip_select",
++ &host->master->num_chipselect))
++ goto err_register;
++
++ for (cs_num = 0; cs_num < host->master->num_chipselect; cs_num++) {
++ res = platform_get_resource(pdev, IORESOURCE_MEM, cs_num + 1);
++ if (!res) {
++ dev_err(&pdev->dev, "cannot get IORESOURCE_IO 0\n");
++ return -ENXIO;
++ }
++
++ host->buff[cs_num] =
++ (u32)devm_ioremap_resource(&pdev->dev, res);
++ if (!host->buff[cs_num]) {
++ dev_err(&pdev->dev, "cannot remap buffer \n");
++ err = -EIO;
++ goto err_no_io_res;
++ }
++
++ dev_dbg(&pdev->dev, "remap io phy %x, virt %x \n",
++ (u32)res->start, (u32)host->buff[cs_num]);
++ }
++
++ host->master->bus_num = pdev->id;
++ host->dev = &pdev->dev;
++
++ /* Setup the state for bitbang driver */
++ host->master->setup = fmc_spi_setup;
++ host->master->transfer = fmc_spi_transfer;
++ host->master->cleanup = fmc_spi_cleanup;
++ // host->master->spi_flash_read = fmc_spi_flash_read;
++
++ platform_set_drvdata(pdev, host);
++
++ /* Register our spi controller */
++ err = devm_spi_register_master(&pdev->dev, host->master);
++ if (err) {
++ dev_err(&pdev->dev, "failed to register SPI master\n");
++ goto err_register;
++ }
++
++ dev_dbg(&pdev->dev, "fmc_spi : driver load \n");
++
++ return 0;
++
++err_register:
++ spi_master_put(host->master);
++ iounmap(host->base);
++ for (cs_num = 0; cs_num < host->master->num_chipselect; cs_num++) {
++ iounmap((void *)host->buff[cs_num]);
++ }
++
++err_no_io_res:
++ kfree(master);
++ kfree(host);
++
++err_nomem:
++ return err;
++}
++
++static int fmc_spi_remove(struct platform_device *pdev)
++{
++ struct resource *res0;
++ struct fmc_spi_host *host = platform_get_drvdata(pdev);
++
++ dev_dbg(host->dev, "fmc_spi_remove()\n");
++
++ if (!host)
++ return -1;
++
++ res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ release_mem_region(res0->start, res0->end - res0->start + 1);
++ iounmap(host->base);
++ iounmap(host->buff);
++
++ platform_set_drvdata(pdev, NULL);
++ spi_unregister_master(host->master);
++ spi_master_put(host->master);
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int fmc_spi_suspend(struct platform_device *pdev, pm_message_t msg)
++{
++ return 0;
++}
++
++static int fmc_spi_resume(struct platform_device *pdev)
++{
++ return 0;
++}
++#else
++#define fmc_spi_suspend NULL
++#define fmc_spi_resume NULL
++#endif
++
++static const struct of_device_id fmc_spi_of_match[] = {
++ { .compatible = "aspeed,fmc-spi" },
++ {},
++};
++
++static struct platform_driver fmc_spi_driver = {
++ .probe = fmc_spi_probe,
++ .remove = fmc_spi_remove,
++#ifdef CONFIG_PM
++ .suspend = fmc_spi_suspend,
++ .resume = fmc_spi_resume,
++#endif
++ .driver = {
++ .name = KBUILD_MODNAME,
++ .of_match_table = fmc_spi_of_match,
++ },
++};
++
++module_platform_driver(fmc_spi_driver);
++
++MODULE_DESCRIPTION("FMC SPI Driver");
++MODULE_AUTHOR("Ryan Chen");
++MODULE_LICENSE("GPL");
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch
new file mode 100644
index 000000000..6123b8701
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch
@@ -0,0 +1,173 @@
+From 12ef9a4189cd44212a5a5bd2e1c6fce0756ace9f Mon Sep 17 00:00:00 2001
+From: "Jason M. Bills" <jason.m.bills@linux.intel.com>
+Date: Fri, 3 May 2019 16:12:39 -0700
+Subject: [PATCH] Enable pass-through on GPIOE1 and GPIOE3 free
+
+This change adds a gpio_disable_free() implementation that checks
+if the GPIO being freed is GPIOE1 (33) or GPIOE3 (35) and will
+re-enable the pass-through mux.
+
+Tested:
+Requested GPIOs 33 and 35 and used devmem to check that pass-through
+was disabled. Then freed them and checked that pass-through was
+enabled again.
+
+Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
+---
+ drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 17 ++++++++++
+ drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c | 17 ++++++++++
+ drivers/pinctrl/aspeed/pinctrl-aspeed.c | 53 ++++++++++++++++++++++++++++++
+ drivers/pinctrl/aspeed/pinctrl-aspeed.h | 3 ++
+ 4 files changed, 90 insertions(+)
+
+diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+index 0cab4c2576e2..c5406e2da320 100644
+--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+@@ -2780,6 +2780,22 @@ static int aspeed_g5_sig_expr_set(struct aspeed_pinmux_data *ctx,
+ return 0;
+ }
+
++#define GPIOE1 33
++#define GPIOE3 35
++static void aspeed_g5_gpio_disable_free(struct pinctrl_dev *pctldev,
++ struct pinctrl_gpio_range *range,
++ unsigned int offset)
++{
++ /*
++ * If we're freeing GPIOE1 (33) or GPIOE3 (35) then re-enable the
++ * pass-through mux setting; otherwise, do nothing.
++ */
++ if (offset != GPIOE1 && offset != GPIOE3)
++ return;
++
++ aspeed_gpio_disable_free(pctldev, range, offset);
++}
++
+ static const struct aspeed_pin_config_map aspeed_g5_pin_config_map[] = {
+ { PIN_CONFIG_BIAS_PULL_DOWN, 0, 1, BIT_MASK(0)},
+ { PIN_CONFIG_BIAS_PULL_DOWN, -1, 0, BIT_MASK(0)},
+@@ -2815,6 +2831,7 @@ static const struct pinmux_ops aspeed_g5_pinmux_ops = {
+ .get_function_groups = aspeed_pinmux_get_fn_groups,
+ .set_mux = aspeed_pinmux_set_mux,
+ .gpio_request_enable = aspeed_gpio_request_enable,
++ .gpio_disable_free = aspeed_g5_gpio_disable_free,
+ .strict = true,
+ };
+
+diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
+index fb96e8d2e6c8..bcd8c5656265 100644
+--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
+@@ -2655,6 +2655,22 @@ static int aspeed_g6_sig_expr_set(struct aspeed_pinmux_data *ctx,
+ return 0;
+ }
+
++#define GPIOP1 121
++#define GPIOP3 123
++static void aspeed_g6_gpio_disable_free(struct pinctrl_dev *pctldev,
++ struct pinctrl_gpio_range *range,
++ unsigned int offset)
++{
++ /*
++ * If we're freeing GPIOP1 (121) or GPIOP3 (123) then re-enable the
++ * pass-through mux setting; otherwise, do nothing.
++ */
++ if (offset != GPIOP1 && offset != GPIOP3)
++ return;
++
++ aspeed_gpio_disable_free(pctldev, range, offset);
++}
++
+ static const struct aspeed_pin_config_map aspeed_g6_pin_config_map[] = {
+ { PIN_CONFIG_BIAS_PULL_DOWN, 0, 1, BIT_MASK(0)},
+ { PIN_CONFIG_BIAS_PULL_DOWN, -1, 0, BIT_MASK(0)},
+@@ -2695,6 +2711,7 @@ static const struct pinmux_ops aspeed_g6_pinmux_ops = {
+ .get_function_groups = aspeed_pinmux_get_fn_groups,
+ .set_mux = aspeed_pinmux_set_mux,
+ .gpio_request_enable = aspeed_gpio_request_enable,
++ .gpio_disable_free = aspeed_g6_gpio_disable_free,
+ .strict = true,
+ };
+
+diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c
+index 53f3f8aec695..ca53f3743d16 100644
+--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c
++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c
+@@ -375,6 +375,59 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
+ return 0;
+ }
+
++void aspeed_gpio_disable_free(struct pinctrl_dev *pctldev,
++ struct pinctrl_gpio_range *range,
++ unsigned int offset)
++{
++ struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
++ const struct aspeed_pin_desc *pdesc = pdata->pins[offset].drv_data;
++ const struct aspeed_sig_expr ***prios, **funcs, *expr;
++ int ret;
++
++ if (!pdesc)
++ return;
++
++ dev_dbg(pctldev->dev,
++ "Freeing pass-through pin %s (%d). Re-enabling pass-through.\n",
++ pdesc->name, offset);
++
++ prios = pdesc->prios;
++
++ if (!prios)
++ return;
++
++ /* Disable any functions of higher priority than GPIO just in case */
++ while ((funcs = *prios)) {
++ if (aspeed_gpio_in_exprs(funcs))
++ break;
++
++ ret = aspeed_disable_sig(&pdata->pinmux, funcs);
++ if (ret)
++ return;
++
++ prios++;
++ }
++
++ if (!funcs) {
++ char *signals = get_defined_signals(pdesc);
++
++ pr_warn("No GPIO signal type found on pin %s (%d). Found: %s\n",
++ pdesc->name, offset, signals);
++ kfree(signals);
++
++ return;
++ }
++
++ /*
++ * Pass-through should be one priority higher than the GPIO function,
++ * so decrement our prios and enable that function
++ */
++ prios--;
++ funcs = *prios;
++ expr = *funcs;
++ aspeed_sig_expr_enable(&pdata->pinmux, expr);
++}
++
+ int aspeed_pinctrl_probe(struct platform_device *pdev,
+ struct pinctrl_desc *pdesc,
+ struct aspeed_pinctrl_data *pdata)
+diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.h b/drivers/pinctrl/aspeed/pinctrl-aspeed.h
+index 4dcde3bc29c8..bd497c20a15f 100644
+--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h
++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h
+@@ -101,6 +101,9 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
+ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset);
++void aspeed_gpio_disable_free(struct pinctrl_dev *pctldev,
++ struct pinctrl_gpio_range *range,
++ unsigned int offset);
+ int aspeed_pinctrl_probe(struct platform_device *pdev,
+ struct pinctrl_desc *pdesc,
+ struct aspeed_pinctrl_data *pdata);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch
new file mode 100644
index 000000000..1ee1c68de
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch
@@ -0,0 +1,70 @@
+From b34fdedc21c98db698150d5014e12927a017b07f Mon Sep 17 00:00:00 2001
+From: "Jason M. Bills" <jason.m.bills@linux.intel.com>
+Date: Mon, 6 May 2019 14:18:27 -0700
+Subject: [PATCH] Enable GPIOE0 and GPIOE2 pass-through by default
+
+This change sets the gpio DT pinctrl default configuration to
+enable GPIOE0 and GPIOE2 pass-through. Since this causes
+pinctrl_get_select_default() to be called automatically for
+the gpio driver to claim the GPIO pins in those groups, we
+also need to call pinctrl_put() to release claim on the
+pass-through GPIOs so they can be requested at runtime.
+
+Tested:
+Disabled pass-through in uboot and confirmed that after booting
+Linux, pass-through is enabled and 'cat /sys/kernel/debug/pinctrl/
+1e6e2000.syscon\:pinctrl-aspeed-g5-pinctrl/pinmux-pins' shows that
+the pass-through GPIOs are UNCLAIMED.
+
+Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
+---
+ arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts | 4 ++++
+ drivers/gpio/gpio-aspeed.c | 10 ++++++++++
+ 2 files changed, 14 insertions(+)
+
+diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts
+index 72bb1b3..ea1d9cd3 100644
+--- a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts
++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts
+@@ -134,6 +134,10 @@
+
+ &gpio {
+ status = "okay";
++ /* Enable GPIOE0 and GPIOE2 pass-through by default */
++ pinctrl-names = "pass-through";
++ pinctrl-0 = <&pinctrl_gpie0_default
++ &pinctrl_gpie2_default>;
+ gpio-line-names =
+ /*A0-A7*/ "","","","","","","","",
+ /*B0-B7*/ "FM_BMC_BOARD_SKU_ID0_N","FM_BMC_BOARD_SKU_ID1_N","FM_BMC_BOARD_SKU_ID2_N","FM_BMC_BOARD_SKU_ID3_N","FM_BMC_BOARD_SKU_ID4_N","","","",
+diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
+index 09e53c5..6165b44 100644
+--- a/drivers/gpio/gpio-aspeed.c
++++ b/drivers/gpio/gpio-aspeed.c
+@@ -1140,6 +1140,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
+ {
+ const struct of_device_id *gpio_id;
+ struct aspeed_gpio *gpio;
++ struct pinctrl *pinctrl;
+ int rc, i, banks, err;
+ u32 ngpio;
+
+@@ -1190,6 +1191,15 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
+ return -ENOMEM;
+
+ /*
++ * Select the pass-through pinctrl config to enable the pass-through
++ * mux for GPIOs marked as pass-through. Then call pinctrl_put() to
++ * release claim of the GPIO pins, so they can be requested at runtime.
++ */
++ pinctrl = pinctrl_get_select(&pdev->dev, "pass-through");
++ if (!IS_ERR(pinctrl))
++ pinctrl_put(pinctrl);
++
++ /*
+ * Populate it with initial values read from the HW and switch
+ * all command sources to the ARM by default
+ */
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch
new file mode 100644
index 000000000..ca54df9ee
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0005-128MB-flashmap-for-PFR.patch
@@ -0,0 +1,30 @@
+From 9a71adc7aecbfdf066ba54c763c2ecd8fb09d3cd 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.
+
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+---
+ arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts
+index 4815104459f1..df02bb1aaf36 100644
+--- a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts
++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts
+@@ -89,7 +89,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-common/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch
new file mode 100644
index 000000000..b9c14c1ac
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0006-Allow-monitoring-of-power-control-input-GPIOs.patch
@@ -0,0 +1,123 @@
+From 5f984831a3f451e299ecaf42d65dee36ff0ffeee Mon Sep 17 00:00:00 2001
+From: "Jason M. Bills" <jason.m.bills@linux.intel.com>
+Date: Fri, 24 May 2019 12:42:59 -0700
+Subject: [PATCH] Allow monitoring of power control input GPIOs
+
+The pass-through input GPIOs cannot be monitored because when
+requested, pass-through is disabled which causes a change on the
+pass-through output.
+
+The SIO GPIOs cannot be monitored because when requested, the
+request is rejected based on the value of the ACPI strap.
+
+This change removes the register check condition from the pass-
+through and desired SIO GPIOs so they can be requsted and
+monitored from power control.
+
+Tested:
+For pass-through, I used gpioset to hold a request on the input
+GPIOs and confirmed that pass-through remained enabled.
+
+For SIO, I used gpioget to confirm that I can successfully request
+and read the GPIO value.
+
+Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
+---
+ drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 10 +++++-----
+ drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c | 10 +++++-----
+ 2 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+index c5406e2da320..fde74c23ca7f 100644
+--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+@@ -279,7 +279,7 @@ FUNC_GROUP_DECL(SD2, F19, E21, F20, D20, D21, E20, G18, C21);
+
+ #define B20 32
+ SIG_EXPR_LIST_DECL_SINGLE(B20, NCTS3, NCTS3, SIG_DESC_SET(SCU80, 16));
+-SIG_EXPR_DECL_SINGLE(GPIE0IN, GPIE0, GPIE0_DESC);
++SIG_EXPR_DECL_SINGLE(GPIE0IN, GPIE0);
+ SIG_EXPR_DECL_SINGLE(GPIE0IN, GPIE, GPIE_DESC);
+ SIG_EXPR_LIST_DECL_DUAL(B20, GPIE0IN, GPIE0, GPIE);
+ PIN_DECL_2(B20, GPIOE0, NCTS3, GPIE0IN);
+@@ -299,7 +299,7 @@ FUNC_GROUP_DECL(GPIE0, B20, C20);
+
+ #define F18 34
+ SIG_EXPR_LIST_DECL_SINGLE(F18, NDSR3, NDSR3, SIG_DESC_SET(SCU80, 18));
+-SIG_EXPR_DECL_SINGLE(GPIE2IN, GPIE2, GPIE2_DESC);
++SIG_EXPR_DECL_SINGLE(GPIE2IN, GPIE2);
+ SIG_EXPR_DECL_SINGLE(GPIE2IN, GPIE, GPIE_DESC);
+ SIG_EXPR_LIST_DECL_DUAL(F18, GPIE2IN, GPIE2, GPIE);
+ PIN_DECL_2(F18, GPIOE2, NDSR3, GPIE2IN);
+@@ -1412,7 +1412,7 @@ FUNC_GROUP_DECL(ADC15, H4);
+
+ #define R22 192
+ SIG_EXPR_DECL_SINGLE(SIOS3, SIOS3, SIG_DESC_SET(SCUA4, 8));
+-SIG_EXPR_DECL_SINGLE(SIOS3, ACPI, ACPI_DESC);
++SIG_EXPR_DECL_SINGLE(SIOS3, ACPI);
+ SIG_EXPR_LIST_DECL_DUAL(R22, SIOS3, SIOS3, ACPI);
+ SIG_EXPR_LIST_DECL_SINGLE(R22, DASHR22, DASHR22, SIG_DESC_SET(SCU94, 10));
+ PIN_DECL_2(R22, GPIOY0, SIOS3, DASHR22);
+@@ -1420,7 +1420,7 @@ FUNC_GROUP_DECL(SIOS3, R22);
+
+ #define R21 193
+ SIG_EXPR_DECL_SINGLE(SIOS5, SIOS5, SIG_DESC_SET(SCUA4, 9));
+-SIG_EXPR_DECL_SINGLE(SIOS5, ACPI, ACPI_DESC);
++SIG_EXPR_DECL_SINGLE(SIOS5, ACPI);
+ SIG_EXPR_LIST_DECL_DUAL(R21, SIOS5, SIOS5, ACPI);
+ SIG_EXPR_LIST_DECL_SINGLE(R21, DASHR21, DASHR21, SIG_DESC_SET(SCU94, 10));
+ PIN_DECL_2(R21, GPIOY1, SIOS5, DASHR21);
+@@ -1436,7 +1436,7 @@ FUNC_GROUP_DECL(SIOPWREQ, P22);
+
+ #define P21 195
+ SIG_EXPR_DECL_SINGLE(SIOONCTRL, SIOONCTRL, SIG_DESC_SET(SCUA4, 11));
+-SIG_EXPR_DECL_SINGLE(SIOONCTRL, ACPI, ACPI_DESC);
++SIG_EXPR_DECL_SINGLE(SIOONCTRL, ACPI);
+ SIG_EXPR_LIST_DECL_DUAL(P21, SIOONCTRL, SIOONCTRL, ACPI);
+ SIG_EXPR_LIST_DECL_SINGLE(P21, DASHP21, DASHP21, SIG_DESC_SET(SCU94, 11));
+ PIN_DECL_2(P21, GPIOY3, SIOONCTRL, DASHP21);
+diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
+index bcd8c5656265..c18ceb52c289 100644
+--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
+@@ -762,7 +762,7 @@ SSSF_PIN_DECL(AC23, GPIOO7, PWM7, SIG_DESC_SET(SCU41C, 23));
+
+ #define AB22 120
+ SIG_EXPR_LIST_DECL_SEMG(AB22, PWM8, PWM8G1, PWM8, SIG_DESC_SET(SCU41C, 24));
+-SIG_EXPR_LIST_DECL_SESG(AB22, THRUIN0, THRU0, SIG_DESC_SET(SCU4BC, 24));
++SIG_EXPR_LIST_DECL_SESG(AB22, THRUIN0, THRU0);
+ PIN_DECL_2(AB22, GPIOP0, PWM8, THRUIN0);
+ GROUP_DECL(PWM8G1, AB22);
+ FUNC_DECL_2(PWM8, PWM8G0, PWM8G1);
+@@ -779,7 +779,7 @@ FUNC_DECL_2(PWM9, PWM9G0, PWM9G1);
+
+ #define AA23 122
+ SIG_EXPR_LIST_DECL_SEMG(AA23, PWM10, PWM10G1, PWM10, SIG_DESC_SET(SCU41C, 26));
+-SIG_EXPR_LIST_DECL_SESG(AA23, THRUIN1, THRU1, SIG_DESC_SET(SCU4BC, 26));
++SIG_EXPR_LIST_DECL_SESG(AA23, THRUIN1, THRU1);
+ PIN_DECL_2(AA23, GPIOP2, PWM10, THRUIN1);
+ GROUP_DECL(PWM10G1, AA23);
+ FUNC_DECL_2(PWM10, PWM10G0, PWM10G1);
+@@ -1070,16 +1070,16 @@ FUNC_GROUP_DECL(GPIU7, AC17);
+ FUNC_GROUP_DECL(ADC15, AC17);
+
+ #define AB15 168
+-SSSF_PIN_DECL(AB15, GPIOV0, SIOS3, SIG_DESC_SET(SCU434, 8));
++SSSF_PIN_DECL(AB15, GPIOV0, SIOS3);
+
+ #define AF14 169
+-SSSF_PIN_DECL(AF14, GPIOV1, SIOS5, SIG_DESC_SET(SCU434, 9));
++SSSF_PIN_DECL(AF14, GPIOV1, SIOS5);
+
+ #define AD14 170
+ SSSF_PIN_DECL(AD14, GPIOV2, SIOPWREQ, SIG_DESC_SET(SCU434, 10));
+
+ #define AC15 171
+-SSSF_PIN_DECL(AC15, GPIOV3, SIOONCTRL, SIG_DESC_SET(SCU434, 11));
++SSSF_PIN_DECL(AC15, GPIOV3, SIOONCTRL);
+
+ #define AE15 172
+ SSSF_PIN_DECL(AE15, GPIOV4, SIOPWRGD, SIG_DESC_SET(SCU434, 12));
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-aspeed-pwm-tacho-change-default-fan-speed.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-aspeed-pwm-tacho-change-default-fan-speed.patch
new file mode 100644
index 000000000..476a07043
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0007-aspeed-pwm-tacho-change-default-fan-speed.patch
@@ -0,0 +1,28 @@
+From b7e8941cf3b1c1c42330207600c91fb23781a77b Mon Sep 17 00:00:00 2001
+From: James Feist <james.feist@linux.intel.com>
+Date: Tue, 2 Jul 2019 10:14:59 -0700
+Subject: [PATCH] aspeed-pwm-tacho: change default fan speed
+
+Change it from max to 58%
+
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+---
+ drivers/hwmon/aspeed-pwm-tacho.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c
+index 40c489be62ea..ae5771f881b5 100644
+--- a/drivers/hwmon/aspeed-pwm-tacho.c
++++ b/drivers/hwmon/aspeed-pwm-tacho.c
+@@ -160,7 +160,7 @@
+ */
+ #define M_TACH_MODE 0x02 /* 10b */
+ #define M_TACH_UNIT 0x0210
+-#define INIT_FAN_CTRL 0xFF
++#define INIT_FAN_CTRL 150 /* 58% */
+
+ /* How long we sleep in us while waiting for an RPM result. */
+ #define ASPEED_RPM_STATUS_SLEEP_USEC 500
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0014-arm-dts-aspeed-g5-add-espi.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0014-arm-dts-aspeed-g5-add-espi.patch
new file mode 100644
index 000000000..993beb9ec
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0014-arm-dts-aspeed-g5-add-espi.patch
@@ -0,0 +1,31 @@
+From ea37c85db4d2a593d4f3392e21ec2cc108b111e5 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
+
+Signed-off-by: Juston Li <juston.li@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g5.dtsi | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index 6580b232771e..452ec323534f 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -408,6 +408,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/0015-New-flash-map-for-intel.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0015-New-flash-map-for-intel.patch
new file mode 100644
index 000000000..b9de9f5a9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0015-New-flash-map-for-intel.patch
@@ -0,0 +1,117 @@
+From f57d473a30f208754457bdb63512c307f7499ac8 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
+
+Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+---
+ .../boot/dts/openbmc-flash-layout-intel-128MB.dtsi | 50 ++++++++++++++++++++++
+ .../boot/dts/openbmc-flash-layout-intel-64MB.dtsi | 38 ++++++++++++++++
+ 2 files changed, 88 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 000000000000..0d3794423aed
+--- /dev/null
++++ b/arch/arm/boot/dts/openbmc-flash-layout-intel-128MB.dtsi
+@@ -0,0 +1,50 @@
++// 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";
++ };
++
++ pfm@80000 {
++ reg = <0x80000 0x20000>;
++ label = "pfm";
++ };
++
++ u-boot-env@a0000 {
++ reg = <0xa0000 0x20000>;
++ label = "u-boot-env";
++ };
++
++ sofs@c0000 {
++ reg = <0xc0000 0x200000>;
++ label = "sofs";
++ };
++
++ rwfs@2c0000 {
++ reg = <0x2c0000 0x840000>;
++ label = "rwfs";
++ };
++
++ fit-image-a@b00000 {
++ reg = <0xb00000 0x1f00000>;
++ label = "image-a";
++ };
++
++ rc-image@2a00000 {
++ reg = <0x2a00000 0x2000000>;
++ label = "rc-image";
++ };
++
++ image-staging@4a00000 {
++ reg = <0x4a00000 0x3600000>;
++ label = "image-stg";
++ };
++
++};
+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 000000000000..092708f5021f
+--- /dev/null
++++ b/arch/arm/boot/dts/openbmc-flash-layout-intel-64MB.dtsi
+@@ -0,0 +1,38 @@
++// 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/0016-Add-ASPEED-SGPIO-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0016-Add-ASPEED-SGPIO-driver.patch
new file mode 100644
index 000000000..950272e1b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0016-Add-ASPEED-SGPIO-driver.patch
@@ -0,0 +1,760 @@
+From a49e262cca260d15dc245fdd1870c89068042063 Mon Sep 17 00:00:00 2001
+From: "Feist, James" <james.feist@intel.com>
+Date: Tue, 4 Jun 2019 14:00:39 -0700
+Subject: [PATCH] Add ASPEED SGPIO driver
+
+Add SGPIO driver support for Aspeed SoCs.
+
+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 | 704 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 713 insertions(+)
+ create mode 100644 drivers/gpio/sgpio-aspeed.c
+
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index 7138290cdd36..0235b20a95f6 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -128,6 +128,14 @@ config GPIO_ASPEED_SGPIO
+ help
+ Say Y here to support Aspeed AST2500 SGPIO functionality.
+
++config SGPIO_ASPEED
++ tristate "ASPEED SGPIO support"
++ depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO
++ 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 e4599f90f702..0e80c8cd5ae7 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -33,6 +33,7 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
+ obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
+ obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
+ obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio-aspeed-sgpio.o
++obj-$(CONFIG_SGPIO_ASPEED) += sgpio-aspeed.o
+ obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
+ obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
+ obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o
+diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c
+new file mode 100644
+index 000000000000..5028e9144a75
+--- /dev/null
++++ b/drivers/gpio/sgpio-aspeed.c
+@@ -0,0 +1,704 @@
++// SPDX-License-Identifier: GPL-2.0+
++// Copyright (c) 2019 Intel Corporation
++
++#include <linux/bitfield.h>
++#include <linux/clk.h>
++#include <linux/gpio/driver.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/spinlock.h>
++
++#define ASPEED_SGPIO_CTRL 0x54
++#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16)
++#define ASPEED_SGPIO_CLK_DIV_MIN 1
++#define ASPEED_SGPIO_CLK_DIV_MAX 65535
++#define ASPEED_SGPIO_PINBYTES_MASK GENMASK(9, 6)
++#define ASPEED_SGPIO_PINBYTES_MIN 1
++#define ASPEED_SGPIO_PINBYTES_MAX 10
++#define ASPEED_SGPIO_ENABLE BIT(0)
++
++#define ASPEED_SGPIO_BUS_FREQ_DEFAULT 1000000
++
++struct aspeed_bank_props {
++ unsigned int bank;
++ u32 input;
++ u32 output;
++};
++
++struct aspeed_sgpio_config {
++ unsigned int nr_pgpios;
++ unsigned int nr_gpios;
++ const struct aspeed_bank_props *props;
++};
++
++struct aspeed_sgpio {
++ struct gpio_chip chip;
++ struct irq_chip irqc;
++ spinlock_t lock;
++ void __iomem *base;
++ int irq;
++ const struct aspeed_sgpio_config *config;
++};
++
++struct aspeed_sgpio_bank {
++ uint16_t val_reg;
++ uint16_t rdata_reg;
++ uint16_t tolerance_reg;
++ uint16_t irq_regs;
++ bool support_irq;
++ const char names[4][3];
++};
++
++/*
++ * Note: The "val" register returns the input value sampled on the line.
++ * Or, it can be used for writing a value on the line.
++ *
++ * The "rdata" register returns the content of the write latch and thus
++ * can be used to read back what was last written reliably.
++ */
++
++static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
++ {
++ .val_reg = 0x0000,
++ .rdata_reg = 0x0070,
++ .tolerance_reg = 0x0018,
++ .irq_regs = 0x0004,
++ .support_irq = false,
++ .names = { "OA", "OB", "OC", "OD" },
++ },
++ {
++ .val_reg = 0x001C,
++ .rdata_reg = 0x0074,
++ .tolerance_reg = 0x0034,
++ .irq_regs = 0x0020,
++ .support_irq = false,
++ .names = { "OE", "OF", "OG", "OH" },
++ },
++ {
++ .val_reg = 0x0038,
++ .rdata_reg = 0x0078,
++ .tolerance_reg = 0x0050,
++ .irq_regs = 0x003C,
++ .support_irq = false,
++ .names = { "OI", "OJ" },
++ },
++ {
++ .val_reg = 0x0000,
++ .rdata_reg = 0x0070,
++ .tolerance_reg = 0x0018,
++ .irq_regs = 0x0004,
++ .support_irq = true,
++ .names = { "IA", "IB", "IC", "ID" },
++ },
++ {
++ .val_reg = 0x001C,
++ .rdata_reg = 0x0074,
++ .tolerance_reg = 0x0034,
++ .irq_regs = 0x0020,
++ .support_irq = true,
++ .names = { "IE", "IF", "IG", "IH" },
++ },
++ {
++ .val_reg = 0x0038,
++ .rdata_reg = 0x0078,
++ .tolerance_reg = 0x0050,
++ .irq_regs = 0x003C,
++ .support_irq = true,
++ .names = { "II", "IJ" },
++ },
++};
++
++enum aspeed_sgpio_reg {
++ reg_val,
++ reg_rdata,
++ reg_irq_enable,
++ reg_irq_type0,
++ reg_irq_type1,
++ reg_irq_type2,
++ reg_irq_status,
++ reg_tolerance,
++};
++
++#define GPIO_IRQ_ENABLE 0x00
++#define GPIO_IRQ_TYPE0 0x04
++#define GPIO_IRQ_TYPE1 0x08
++#define GPIO_IRQ_TYPE2 0x0c
++#define GPIO_IRQ_STATUS 0x10
++
++/* This will be resolved at compile time */
++static inline void __iomem *bank_reg(struct aspeed_sgpio *gpio,
++ const struct aspeed_sgpio_bank *bank,
++ const enum aspeed_sgpio_reg reg)
++{
++ switch (reg) {
++ case reg_val:
++ return gpio->base + bank->val_reg;
++ case reg_rdata:
++ return gpio->base + bank->rdata_reg;
++ case reg_irq_enable:
++ return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
++ case reg_irq_type0:
++ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
++ case reg_irq_type1:
++ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
++ case reg_irq_type2:
++ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
++ case reg_irq_status:
++ return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
++ case reg_tolerance:
++ return gpio->base + bank->tolerance_reg;
++ default:
++ WARN_ON(1);
++ }
++
++ return NULL;
++}
++
++#define GPIO_BANK(x) ((x) >> 5)
++#define GPIO_OFFSET(x) ((x) & 0x1f)
++#define GPIO_BIT(x) BIT(GPIO_OFFSET(x))
++
++static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
++{
++ unsigned int bank = GPIO_BANK(offset);
++
++ WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
++ return &aspeed_sgpio_banks[bank];
++}
++
++static inline bool is_bank_props_sentinel(const struct aspeed_bank_props *props)
++{
++ return !(props->input || props->output);
++}
++
++static inline const struct aspeed_bank_props *find_bank_props(
++ struct aspeed_sgpio *gpio, unsigned int offset)
++{
++ const struct aspeed_bank_props *props = gpio->config->props;
++
++ while (!is_bank_props_sentinel(props)) {
++ if (props->bank == GPIO_BANK(offset))
++ return props;
++ props++;
++ }
++
++ return NULL;
++}
++
++static inline bool have_input(struct aspeed_sgpio *gpio, unsigned int offset)
++{
++ const struct aspeed_bank_props *props = find_bank_props(gpio, offset);
++
++ return !props || (props->input & GPIO_BIT(offset));
++}
++
++static inline bool have_output(struct aspeed_sgpio *gpio, unsigned int offset)
++{
++ const struct aspeed_bank_props *props = find_bank_props(gpio, offset);
++
++ return !props || (props->output & GPIO_BIT(offset));
++}
++
++static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
++{
++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
++ const struct aspeed_sgpio_bank *bank = to_bank(offset);
++ enum aspeed_sgpio_reg reg;
++
++ if (have_output(gpio, offset))
++ reg = reg_rdata;
++ else
++ reg = reg_val;
++
++ return !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
++}
++
++static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
++{
++ const struct aspeed_sgpio_bank *bank = to_bank(offset);
++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
++ unsigned long flags;
++ u32 reg;
++
++ if (!have_output(gpio, offset))
++ return;
++
++ spin_lock_irqsave(&gpio->lock, flags);
++
++ reg = ioread32(bank_reg(gpio, bank, reg_rdata));
++
++ if (val)
++ reg |= GPIO_BIT(offset);
++ else
++ reg &= ~GPIO_BIT(offset);
++
++ iowrite32(reg, bank_reg(gpio, bank, reg_val));
++
++ spin_unlock_irqrestore(&gpio->lock, flags);
++}
++
++static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
++{
++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
++
++ if (!have_input(gpio, offset))
++ return -ENOTSUPP;
++
++ return 0;
++}
++
++static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset,
++ int val)
++{
++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
++
++ if (!have_output(gpio, offset))
++ return -ENOTSUPP;
++
++ aspeed_sgpio_set(gc, offset, val);
++
++ return 0;
++}
++
++static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
++{
++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
++
++ if (have_output(gpio, offset))
++ return 0;
++ else if (have_input(gpio, offset))
++ return 1;
++
++ return -ENOTSUPP;
++}
++
++static inline int
++irqd_to_aspeed_sgpio_data(struct irq_data *d, struct aspeed_sgpio **gpio,
++ const struct aspeed_sgpio_bank **bank,
++ u32 *bit, int *offset)
++{
++ struct aspeed_sgpio *internal;
++
++ *offset = irqd_to_hwirq(d);
++
++ internal = irq_data_get_irq_chip_data(d);
++
++ *gpio = internal;
++ *bank = to_bank(*offset);
++ *bit = GPIO_BIT(*offset);
++
++ return 0;
++}
++
++static void aspeed_sgpio_irq_ack(struct irq_data *d)
++{
++ const struct aspeed_sgpio_bank *bank;
++ struct aspeed_sgpio *gpio;
++ void __iomem *status_addr;
++ unsigned long flags;
++ int rc, offset;
++ u32 bit;
++
++ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
++ if (rc)
++ return;
++
++ status_addr = bank_reg(gpio, bank, reg_irq_status);
++
++ spin_lock_irqsave(&gpio->lock, flags);
++
++ iowrite32(bit, status_addr);
++
++ spin_unlock_irqrestore(&gpio->lock, flags);
++}
++
++static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
++{
++ const struct aspeed_sgpio_bank *bank;
++ struct aspeed_sgpio *gpio;
++ unsigned long flags;
++ u32 reg, bit;
++ void __iomem *addr;
++ int rc, offset;
++
++ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
++ if (rc)
++ return;
++
++ if (!bank->support_irq)
++ return;
++
++ addr = bank_reg(gpio, bank, reg_irq_enable);
++
++ spin_lock_irqsave(&gpio->lock, flags);
++
++ reg = ioread32(addr);
++ if (set)
++ reg |= bit;
++ else
++ reg &= ~bit;
++
++ iowrite32(reg, addr);
++
++ spin_unlock_irqrestore(&gpio->lock, flags);
++}
++
++static void aspeed_sgpio_irq_mask(struct irq_data *d)
++{
++ aspeed_sgpio_irq_set_mask(d, false);
++}
++
++static void aspeed_sgpio_irq_unmask(struct irq_data *d)
++{
++ aspeed_sgpio_irq_set_mask(d, true);
++}
++
++static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
++{
++ u32 type0 = 0;
++ u32 type1 = 0;
++ u32 type2 = 0;
++ u32 bit, reg;
++ const struct aspeed_sgpio_bank *bank;
++ irq_flow_handler_t handler;
++ struct aspeed_sgpio *gpio;
++ unsigned long flags;
++ void __iomem *addr;
++ int rc, offset;
++
++ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
++ if (rc)
++ return -EINVAL;
++
++ if (!bank->support_irq)
++ return -ENOTSUPP;
++
++ switch (type & IRQ_TYPE_SENSE_MASK) {
++ case IRQ_TYPE_EDGE_BOTH:
++ type2 |= bit;
++ /* fall through */
++ case IRQ_TYPE_EDGE_RISING:
++ type0 |= bit;
++ /* fall through */
++ case IRQ_TYPE_EDGE_FALLING:
++ handler = handle_edge_irq;
++ break;
++ case IRQ_TYPE_LEVEL_HIGH:
++ type0 |= bit;
++ /* fall through */
++ case IRQ_TYPE_LEVEL_LOW:
++ type1 |= bit;
++ handler = handle_level_irq;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&gpio->lock, flags);
++
++ addr = bank_reg(gpio, bank, reg_irq_type0);
++ reg = ioread32(addr);
++ reg = (reg & ~bit) | type0;
++ iowrite32(reg, addr);
++
++ addr = bank_reg(gpio, bank, reg_irq_type1);
++ reg = ioread32(addr);
++ reg = (reg & ~bit) | type1;
++ iowrite32(reg, addr);
++
++ addr = bank_reg(gpio, bank, reg_irq_type2);
++ reg = ioread32(addr);
++ reg = (reg & ~bit) | type2;
++ iowrite32(reg, addr);
++
++ spin_unlock_irqrestore(&gpio->lock, flags);
++
++ irq_set_handler_locked(d, handler);
++
++ return 0;
++}
++
++static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
++{
++ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
++ struct aspeed_sgpio *data = gpiochip_get_data(gc);
++ struct irq_chip *ic = irq_desc_get_chip(desc);
++ unsigned int i, p, girq;
++ unsigned long reg;
++
++ chained_irq_enter(ic, desc);
++
++ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
++ const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
++
++ if (!bank->support_irq)
++ continue;
++
++ reg = ioread32(bank_reg(data, bank, reg_irq_status));
++
++ for_each_set_bit(p, &reg, 32) {
++ girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
++ generic_handle_irq(girq);
++ }
++ }
++
++ chained_irq_exit(ic, desc);
++}
++
++static void aspeed_sgpio_init_irq_valid_mask(struct gpio_chip *gc,
++ unsigned long *valid_mask,
++ unsigned int ngpios)
++{
++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
++ const struct aspeed_bank_props *props = gpio->config->props;
++
++ while (!is_bank_props_sentinel(props)) {
++ unsigned int offset;
++ const unsigned long int input = props->input;
++
++ /* Pretty crummy approach, but similar to GPIO core */
++ for_each_clear_bit(offset, &input, 32) {
++ unsigned int i = props->bank * 32 + offset;
++
++ if (i >= gpio->chip.ngpio)
++ break;
++
++ clear_bit(i, valid_mask);
++ }
++
++ props++;
++ }
++}
++
++static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
++ struct platform_device *pdev)
++{
++ const struct aspeed_sgpio_bank *bank;
++ struct gpio_irq_chip *girq;
++ int rc, i;
++
++ /* Initialize IRQ and tolerant settings */
++ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
++ bank = &aspeed_sgpio_banks[i];
++
++ /* Value will be reset by WDT reset */
++ iowrite32(0x00000000, bank_reg(gpio, bank, reg_tolerance));
++
++ if (!bank->support_irq)
++ continue;
++
++ /* disable irq enable bits */
++ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
++ /* clear status bits */
++ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
++ /* set rising or level-high irq */
++ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type0));
++ /* trigger type is level */
++ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type1));
++ /* single trigger mode */
++ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2));
++ }
++
++ rc = platform_get_irq(pdev, 0);
++ if (rc < 0)
++ return rc;
++
++ gpio->irq = rc;
++ girq = &gpio->chip.irq;
++ girq->chip = &gpio->irqc;
++ girq->chip->name = dev_name(&pdev->dev);
++ girq->chip->irq_ack = aspeed_sgpio_irq_ack;
++ girq->chip->irq_mask = aspeed_sgpio_irq_mask;
++ girq->chip->irq_unmask = aspeed_sgpio_irq_unmask;
++ girq->chip->irq_set_type = aspeed_sgpio_set_type;
++ girq->parent_handler = aspeed_sgpio_irq_handler;
++ girq->num_parents = 1;
++ girq->parents = devm_kcalloc(&pdev->dev, 1,
++ sizeof(*girq->parents),
++ GFP_KERNEL);
++ if (!girq->parents)
++ return -ENOMEM;
++ girq->parents[0] = gpio->irq;
++ girq->default_type = IRQ_TYPE_NONE;
++ girq->handler = handle_bad_irq;
++ girq->init_valid_mask = aspeed_sgpio_init_irq_valid_mask;
++
++ return 0;
++}
++
++static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip,
++ unsigned int offset, bool enable)
++{
++ struct aspeed_sgpio *gpio = gpiochip_get_data(chip);
++ unsigned long flags;
++ void __iomem *treg;
++ u32 val;
++
++ treg = bank_reg(gpio, to_bank(offset), reg_tolerance);
++
++ spin_lock_irqsave(&gpio->lock, flags);
++
++ val = readl(treg);
++
++ if (enable)
++ val |= GPIO_BIT(offset);
++ else
++ val &= ~GPIO_BIT(offset);
++
++ writel(val, treg);
++
++ spin_unlock_irqrestore(&gpio->lock, flags);
++
++ return 0;
++}
++
++static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset,
++ unsigned long config)
++{
++ unsigned long param = pinconf_to_config_param(config);
++ u32 arg = pinconf_to_config_argument(config);
++
++ if (param == PIN_CONFIG_PERSIST_STATE)
++ return aspeed_sgpio_reset_tolerance(chip, offset, arg);
++
++ return -ENOTSUPP;
++}
++
++/*
++ * Any banks not specified in a struct aspeed_bank_props array are assumed to
++ * have the properties:
++ *
++ * { .input = 0xffffffff, .output = 0xffffffff }
++ */
++
++static const struct aspeed_bank_props ast_sgpio_bank_props[] = {
++ /* input output */
++ { 0, 0x00000000, 0xffffffff }, /* OA/OB/OC/OD */
++ { 1, 0x00000000, 0xffffffff }, /* OE/OF/OG/OH */
++ { 2, 0x00000000, 0x0000ffff }, /* OI/OJ */
++ { 3, 0xffffffff, 0x00000000 }, /* IA/IB/IC/ID */
++ { 4, 0xffffffff, 0x00000000 }, /* IE/IF/IG/IH */
++ { 5, 0x0000ffff, 0x00000000 }, /* II/IJ */
++ { }
++};
++
++/*
++ * This H/W has 80 bidirectional lines so this driver provides total 160 lines
++ * for 80 outputs and 80 inputs. To simplify bank register manipulation, it
++ * uses 96 lines per each input and output set so total 192 lines it has.
++ */
++static const struct aspeed_sgpio_config ast2400_config =
++ { .nr_pgpios = 224, .nr_gpios = 192, .props = ast_sgpio_bank_props };
++
++static const struct aspeed_sgpio_config ast2500_config =
++ { .nr_pgpios = 232, .nr_gpios = 192, .props = ast_sgpio_bank_props };
++
++static const struct of_device_id aspeed_sgpio_of_table[] = {
++ { .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_config },
++ { .compatible = "aspeed,ast2500-sgpio", .data = &ast2500_config },
++ { .compatible = "aspeed,ast2600-sgpio", .data = &ast2500_config },
++ { }
++};
++MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
++
++static int __init aspeed_sgpio_probe(struct platform_device *pdev)
++{
++ const struct of_device_id *gpio_id;
++ u32 sgpio_freq, clk_div, nb_gpios;
++ struct aspeed_sgpio *gpio;
++ unsigned long src_freq;
++ struct clk *clk;
++ int rc;
++
++ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
++ if (!gpio)
++ return -ENOMEM;
++
++ gpio->base = devm_platform_ioremap_resource(pdev, 0);
++ if (IS_ERR(gpio->base))
++ return PTR_ERR(gpio->base);
++
++ spin_lock_init(&gpio->lock);
++
++ gpio_id = of_match_node(aspeed_sgpio_of_table, pdev->dev.of_node);
++ if (!gpio_id)
++ return -EINVAL;
++
++ gpio->config = gpio_id->data;
++
++ rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq);
++ if (rc < 0) {
++ dev_warn(&pdev->dev, "Could not read bus-frequency property. Use default.\n");
++ sgpio_freq = ASPEED_SGPIO_BUS_FREQ_DEFAULT;
++ }
++
++ clk = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(clk)) {
++ rc = PTR_ERR(clk);
++ if (rc != -EPROBE_DEFER)
++ dev_err(&pdev->dev, "Failed to get clk source.\n");
++ return rc;
++ }
++
++ /*
++ * There is a limitation that SGPIO clock division has to be larger or
++ * equal to 1. And a read back value of clock division is 1-bit left
++ * shifted from the 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 an example, SGPIO clock is 1MHz and number of SGPIO is 80. Each
++ * SGPIO will be updated every 80us.
++ */
++ src_freq = clk_get_rate(clk);
++ clk_div = src_freq / (2 * sgpio_freq) - 1;
++ if (clk_div < ASPEED_SGPIO_CLK_DIV_MIN)
++ clk_div = ASPEED_SGPIO_CLK_DIV_MIN;
++ else if (clk_div > ASPEED_SGPIO_CLK_DIV_MAX)
++ clk_div = ASPEED_SGPIO_CLK_DIV_MAX;
++
++ nb_gpios = gpio->config->nr_gpios / 16;
++ if (nb_gpios < ASPEED_SGPIO_PINBYTES_MIN)
++ nb_gpios = ASPEED_SGPIO_PINBYTES_MIN;
++ else if (nb_gpios > ASPEED_SGPIO_PINBYTES_MAX)
++ nb_gpios = ASPEED_SGPIO_PINBYTES_MAX;
++
++ iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, clk_div) |
++ FIELD_PREP(ASPEED_SGPIO_PINBYTES_MASK, nb_gpios) |
++ ASPEED_SGPIO_ENABLE,
++ gpio->base + ASPEED_SGPIO_CTRL);
++
++ gpio->chip.parent = &pdev->dev;
++ gpio->chip.ngpio = gpio->config->nr_gpios;
++
++ gpio->chip.direction_input = aspeed_sgpio_dir_in;
++ gpio->chip.direction_output = aspeed_sgpio_dir_out;
++ gpio->chip.get_direction = aspeed_sgpio_get_direction;
++ gpio->chip.get = aspeed_sgpio_get;
++ gpio->chip.set = aspeed_sgpio_set;
++ gpio->chip.set_config = aspeed_sgpio_set_config;
++ gpio->chip.label = dev_name(&pdev->dev);
++ gpio->chip.base = -1;
++
++ rc = aspeed_sgpio_setup_irqs(gpio, pdev);
++ if (rc < 0)
++ return rc;
++
++ return devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
++}
++
++static struct platform_driver aspeed_sgpio_driver = {
++ .driver = {
++ .name = KBUILD_MODNAME,
++ .of_match_table = aspeed_sgpio_of_table,
++ },
++};
++
++module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
++
++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
++MODULE_DESCRIPTION("Aspeed SGPIO Master Driver");
++MODULE_LICENSE("GPL v2");
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0017-SGPIO-DT-and-pinctrl-fixup.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0017-SGPIO-DT-and-pinctrl-fixup.patch
new file mode 100644
index 000000000..50c31f625
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0017-SGPIO-DT-and-pinctrl-fixup.patch
@@ -0,0 +1,227 @@
+From 89b5ebd26fc44b4bf820aa507bc88eec028ba218 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 | 56 +++++++++++-------------------
+ arch/arm/boot/dts/aspeed-g5.dtsi | 3 +-
+ arch/arm/boot/dts/aspeed-g6.dtsi | 15 ++++++++
+ drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c | 48 ++++++++++++-------------
+ 4 files changed, 60 insertions(+), 62 deletions(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index b875c0785833..e9fd66ab3099 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -254,6 +254,20 @@
+ #interrupt-cells = <2>;
+ };
+
++ sgpio: sgpio@1e780200 {
++ #gpio-cells = <2>;
++ gpio-controller;
++ compatible = "aspeed,ast2400-sgpio";
++ reg = <0x1e780200 0x0100>;
++ interrupts = <40>;
++ interrupt-controller;
++ clocks = <&syscon ASPEED_CLK_APB>;
++ bus-frequency = <1000000>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_sgpm_default>;
++ status = "disabled";
++ };
++
+ timer: timer@1e782000 {
+ /* This timer is a Faraday FTTMR010 derivative */
+ compatible = "aspeed,ast2400-timer";
+@@ -1227,44 +1241,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 452ec323534f..20b2eb8052b7 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -326,8 +326,7 @@
+ reg = <0x1e780200 0x0100>;
+ clocks = <&syscon ASPEED_CLK_APB>;
+ interrupt-controller;
+- ngpios = <8>;
+- bus-frequency = <12000000>;
++ bus-frequency = <1000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sgpm_default>;
+ status = "disabled";
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index 54add29d8217..459070693aba 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -339,6 +339,21 @@
+ #interrupt-cells = <2>;
+ };
+
++ sgpio: sgpio@1e780500 {
++ #gpio-cells = <2>;
++ gpio-controller;
++ compatible = "aspeed,ast2600-sgpio";
++ reg = <0x1e780500 0x0100>;
++ #interrupt-cells = <2>;
++ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
++ interrupt-controller;
++ bus-frequency = <1000000>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_sgpm1_default>;
++ clocks = <&syscon ASPEED_CLK_APB1>;
++ status = "disabled";
++ };
++
+ rtc: rtc@1e781000 {
+ compatible = "aspeed,ast2600-rtc";
+ reg = <0x1e781000 0x18>;
+diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
+index bfed0e274643..10dadfd0e6e1 100644
+--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
++++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
+@@ -430,16 +430,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(A14, SGPSCK, SGPS, SIG_DESC_SET(SCU84, 0));
++PIN_DECL_1(A14, GPIOG0, SGPSCK);
+
+ #define E13 49
+-SSSF_PIN_DECL(E13, GPIOG1, SGPSLD, SIG_DESC_SET(SCU84, 1));
++SIG_EXPR_LIST_DECL_SINGLE(E13, SGPSLD, SGPS, SIG_DESC_SET(SCU84, 1));
++PIN_DECL_1(E13, GPIOG1, SGPSLD);
+
+ #define D13 50
+-SSSF_PIN_DECL(D13, GPIOG2, SGPSI0, SIG_DESC_SET(SCU84, 2));
++SIG_EXPR_LIST_DECL_SINGLE(D13, SGPSIO, SGPS, SIG_DESC_SET(SCU84, 2));
++PIN_DECL_1(D13, GPIOG2, SGPSIO);
+
+ #define C13 51
+-SSSF_PIN_DECL(C13, GPIOG3, SGPSI1, SIG_DESC_SET(SCU84, 3));
++SIG_EXPR_LIST_DECL_SINGLE(C13, SGPSI1, SGPS, SIG_DESC_SET(SCU84, 3));
++PIN_DECL_1(C13, GPIOG3, SGPSI1);
++
++FUNC_GROUP_DECL(SGPS, A14, E13, D13, C13);
+
+ #define B13 52
+ SIG_EXPR_LIST_DECL_SINGLE(B13, OSCCLK, OSCCLK, SIG_DESC_SET(SCU2C, 1));
+@@ -613,16 +619,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(J5, SGPMCK, SGPM, SIG_DESC_SET(SCU84, 8));
++PIN_DECL_1(J5, GPIOJ0, SGPMCK);
+
+ #define J4 73
+-SSSF_PIN_DECL(J4, GPIOJ1, SGPMLD, SIG_DESC_SET(SCU84, 9));
++SIG_EXPR_LIST_DECL_SINGLE(J4, SGPMLD, SGPM, SIG_DESC_SET(SCU84, 9));
++PIN_DECL_1(J4, GPIOJ1, SGPMLD);
+
+ #define K5 74
+-SSSF_PIN_DECL(K5, GPIOJ2, SGPMO, SIG_DESC_SET(SCU84, 10));
++SIG_EXPR_LIST_DECL_SINGLE(K5, SGPMO, SGPM, SIG_DESC_SET(SCU84, 10));
++PIN_DECL_1(K5, GPIOJ2, SGPMO);
+
+ #define J3 75
+-SSSF_PIN_DECL(J3, GPIOJ3, SGPMI, SIG_DESC_SET(SCU84, 11));
++SIG_EXPR_LIST_DECL_SINGLE(J3, SGPMI, SGPM, SIG_DESC_SET(SCU84, 11));
++PIN_DECL_1(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));
+@@ -2234,14 +2246,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),
+@@ -2389,14 +2395,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),
+--
+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..128b11ecf
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0019-Add-I2C-IPMB-support.patch
@@ -0,0 +1,425 @@
+From f588865f8180a6370ac639bdfc186ffc5b926246 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] Add I2C IPMB support
+
+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 | 124 +++++++++++++++++
+ drivers/i2c/Kconfig | 23 +++
+ drivers/i2c/Makefile | 1 +
+ drivers/i2c/i2c-slave-mqueue.c | 217 +++++++++++++++++++++++++++++
+ 4 files changed, 365 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..2d0d06d8df9d
+--- /dev/null
++++ b/Documentation/i2c/slave-mqueue-backend.rst
+@@ -0,0 +1,124 @@
++.. 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 abedd55a1264..49a2379876c6 100644
+--- a/drivers/i2c/Kconfig
++++ b/drivers/i2c/Kconfig
+@@ -119,6 +119,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/0020-misc-aspeed-add-lpc-mbox-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0020-misc-aspeed-add-lpc-mbox-driver.patch
new file mode 100644
index 000000000..c5add2dd5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0020-misc-aspeed-add-lpc-mbox-driver.patch
@@ -0,0 +1,491 @@
+From 42326dfecd45c52918272cf6b65e6eb5b8499c46 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 10 Jul 2019 16:19:33 -0700
+Subject: [PATCH] misc: aspeed: add lpc mbox driver
+
+This commit adds back the lpc mbox driver which was removed from
+the openbmc linux dev-5.2 tree.
+
+This driver should be rewritten later.
+
+Signed-off-by: Cyril Bur <cyrilbur@gmail.com>"
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com>
+---
+ arch/arm/boot/dts/aspeed-g4.dtsi | 9 +
+ arch/arm/boot/dts/aspeed-g5.dtsi | 9 +
+ arch/arm/boot/dts/aspeed-g6.dtsi | 1 +
+ drivers/soc/aspeed/Kconfig | 7 +
+ drivers/soc/aspeed/Makefile | 1 +
+ drivers/soc/aspeed/aspeed-lpc-mbox.c | 377 +++++++++++++++++++++++++++
+ 6 files changed, 404 insertions(+)
+ create mode 100644 drivers/soc/aspeed/aspeed-lpc-mbox.c
+
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index e9fd66ab3099..f3edda4ae477 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -393,6 +393,15 @@
+ sio_regs: regs {
+ compatible = "aspeed,bmc-misc";
+ };
++
++ mbox: mbox@180 {
++ compatible = "aspeed,ast2400-mbox";
++ reg = <0x180 0x5c>;
++ interrupts = <46>;
++ #mbox-cells = <1>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
+ };
+ };
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index b4ae3827ed1d..b69110b9eab9 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -522,6 +522,15 @@
+ sio_regs: regs {
+ compatible = "aspeed,bmc-misc";
+ };
++
++ mbox: mbox@180 {
++ compatible = "aspeed,ast2500-mbox";
++ reg = <0x180 0x5c>;
++ interrupts = <46>;
++ #mbox-cells = <1>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
+ };
+ };
+
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index 825e64ce317a..183869eaf79a 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -594,6 +594,7 @@
+ reg = <0x180 0x5c>;
+ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+ #mbox-cells = <1>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ };
+ };
+ };
+diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig
+index a4b3cac87ce2..464a55c7eb39 100644
+--- a/drivers/soc/aspeed/Kconfig
++++ b/drivers/soc/aspeed/Kconfig
+@@ -21,6 +21,13 @@ 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_MBOX
++ tristate "Aspeed LPC Mailbox Controller"
++ depends on SOC_ASPEED && REGMAP && MFD_SYSCON
++ ---help---
++ Expose the ASPEED LPC MBOX registers found on Aspeed SOCs (AST2400
++ and AST2500) to userspace.
++
+ config ASPEED_LPC_SNOOP
+ tristate "Aspeed ast2500 HOST LPC snoop support"
+ depends on SOC_ASPEED && REGMAP && MFD_SYSCON
+diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
+index 217d876fec25..26924c111af3 100644
+--- a/drivers/soc/aspeed/Makefile
++++ b/drivers/soc/aspeed/Makefile
+@@ -1,6 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ obj-$(CONFIG_ASPEED_BMC_MISC) += aspeed-bmc-misc.o
+ obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
++obj-$(CONFIG_ASPEED_LPC_MBOX) += aspeed-lpc-mbox.o
+ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
+ obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
+ obj-$(CONFIG_ASPEED_XDMA) += aspeed-xdma.o
+diff --git a/drivers/soc/aspeed/aspeed-lpc-mbox.c b/drivers/soc/aspeed/aspeed-lpc-mbox.c
+new file mode 100644
+index 000000000000..583feecc4f18
+--- /dev/null
++++ b/drivers/soc/aspeed/aspeed-lpc-mbox.c
+@@ -0,0 +1,377 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++// Copyright 2017 IBM Corporation
++// TODO: Rewrite this driver
++
++#include <linux/clk.h>
++#include <linux/interrupt.h>
++#include <linux/mfd/syscon.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/of_irq.h>
++#include <linux/platform_device.h>
++#include <linux/poll.h>
++#include <linux/regmap.h>
++#include <linux/slab.h>
++
++#define DEVICE_NAME "aspeed-mbox"
++
++#define MBX_USE_INTERRUPT 0
++
++#define ASPEED_MBOX_NUM_REGS 16
++
++#define ASPEED_MBOX_DATA_0 0x00
++#define ASPEED_MBOX_STATUS_0 0x40
++#define ASPEED_MBOX_STATUS_1 0x44
++#define ASPEED_MBOX_BMC_CTRL 0x48
++#define ASPEED_MBOX_CTRL_RECV BIT(7)
++#define ASPEED_MBOX_CTRL_MASK BIT(1)
++#define ASPEED_MBOX_CTRL_SEND BIT(0)
++#define ASPEED_MBOX_HOST_CTRL 0x4c
++#define ASPEED_MBOX_INTERRUPT_0 0x50
++#define ASPEED_MBOX_INTERRUPT_1 0x54
++
++struct aspeed_mbox {
++ struct miscdevice miscdev;
++ struct regmap *regmap;
++ struct clk *clk;
++ unsigned int base;
++ int irq;
++ wait_queue_head_t queue;
++ struct mutex mutex;
++};
++
++static atomic_t aspeed_mbox_open_count = ATOMIC_INIT(0);
++
++static u8 aspeed_mbox_inb(struct aspeed_mbox *mbox, int reg)
++{
++ /*
++ * The mbox registers are actually only one byte but are addressed
++ * four bytes apart. The other three bytes are marked 'reserved',
++ * they *should* be zero but lets not rely on it.
++ * I am going to rely on the fact we can casually read/write to them...
++ */
++ unsigned int val = 0xff; /* If regmap throws an error return 0xff */
++ int rc = regmap_read(mbox->regmap, mbox->base + reg, &val);
++
++ if (rc)
++ dev_err(mbox->miscdev.parent, "regmap_read() failed with "
++ "%d (reg: 0x%08x)\n", rc, reg);
++
++ return val & 0xff;
++}
++
++static void aspeed_mbox_outb(struct aspeed_mbox *mbox, u8 data, int reg)
++{
++ int rc = regmap_write(mbox->regmap, mbox->base + reg, data);
++
++ if (rc)
++ dev_err(mbox->miscdev.parent, "regmap_write() failed with "
++ "%d (data: %u reg: 0x%08x)\n", rc, data, reg);
++}
++
++static struct aspeed_mbox *file_mbox(struct file *file)
++{
++ return container_of(file->private_data, struct aspeed_mbox, miscdev);
++}
++
++static int aspeed_mbox_open(struct inode *inode, struct file *file)
++{
++#if MBX_USE_INTERRUPT
++ struct aspeed_mbox *mbox = file_mbox(file);
++#endif
++
++ 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;
++ }
++
++ atomic_dec(&aspeed_mbox_open_count);
++ return -EBUSY;
++}
++
++static ssize_t aspeed_mbox_read(struct file *file, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct aspeed_mbox *mbox = file_mbox(file);
++ char __user *p = buf;
++ ssize_t ret;
++ int i;
++
++ if (!access_ok(buf, count))
++ return -EFAULT;
++
++ 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))
++ return -EAGAIN;
++ } else if (wait_event_interruptible(mbox->queue,
++ aspeed_mbox_inb(mbox, ASPEED_MBOX_BMC_CTRL) &
++ ASPEED_MBOX_CTRL_RECV)) {
++ return -ERESTARTSYS;
++ }
++#endif
++
++ mutex_lock(&mbox->mutex);
++
++ for (i = *ppos; count > 0 && i < ASPEED_MBOX_NUM_REGS; i++) {
++ uint8_t reg = aspeed_mbox_inb(mbox, ASPEED_MBOX_DATA_0 + (i * 4));
++
++ ret = __put_user(reg, p);
++ if (ret)
++ goto out_unlock;
++
++ p++;
++ 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:
++ mutex_unlock(&mbox->mutex);
++ return ret;
++}
++
++static ssize_t aspeed_mbox_write(struct file *file, const char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct aspeed_mbox *mbox = file_mbox(file);
++ const char __user *p = buf;
++ ssize_t ret;
++ char c;
++ int i;
++
++ if (!access_ok(buf, count))
++ return -EFAULT;
++
++ if (count + *ppos > ASPEED_MBOX_NUM_REGS)
++ return -EINVAL;
++
++ mutex_lock(&mbox->mutex);
++
++ for (i = *ppos; count > 0 && i < ASPEED_MBOX_NUM_REGS; i++) {
++ ret = __get_user(c, p);
++ if (ret)
++ goto out_unlock;
++
++ aspeed_mbox_outb(mbox, c, ASPEED_MBOX_DATA_0 + (i * 4));
++ p++;
++ count--;
++ }
++
++ 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_CTRL_MASK | ASPEED_MBOX_CTRL_SEND, ASPEED_MBOX_BMC_CTRL);
++ ret = p - buf;
++
++out_unlock:
++ mutex_unlock(&mbox->mutex);
++ return ret;
++}
++
++static unsigned int aspeed_mbox_poll(struct file *file, poll_table *wait)
++{
++ struct aspeed_mbox *mbox = file_mbox(file);
++ unsigned int mask = 0;
++
++ 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;
++}
++
++static int aspeed_mbox_release(struct inode *inode, struct file *file)
++{
++ atomic_dec(&aspeed_mbox_open_count);
++ return 0;
++}
++
++static const struct file_operations aspeed_mbox_fops = {
++ .owner = THIS_MODULE,
++ .llseek = no_seek_end_llseek,
++ .read = aspeed_mbox_read,
++ .write = aspeed_mbox_write,
++ .open = aspeed_mbox_open,
++ .release = aspeed_mbox_release,
++ .poll = aspeed_mbox_poll,
++};
++
++static irqreturn_t aspeed_mbox_irq(int irq, void *arg)
++{
++ struct aspeed_mbox *mbox = arg;
++#if MBX_USE_INTERRUPT
++ int i;
++
++// if (!(aspeed_mbox_inb(mbox, ASPEED_MBOX_BMC_CTRL) & ASPEED_MBOX_CTRL_RECV))
++// return IRQ_NONE;
++
++ printk(KERN_ERR "BMC_CTRL: 0x%02x\n",
++ aspeed_mbox_inb(mbox, ASPEED_MBOX_BMC_CTRL));
++ printk(KERN_ERR "STATUS_0: 0x%02x\n",
++ aspeed_mbox_inb(mbox, ASPEED_MBOX_STATUS_0));
++ printk(KERN_ERR "STATUS_1: 0x%02x\n",
++ aspeed_mbox_inb(mbox, ASPEED_MBOX_STATUS_1));
++ for (i = 0; i < ASPEED_MBOX_NUM_REGS; i++) {
++ printk(KERN_ERR "DATA_%d: 0x%02x\n", i,
++ aspeed_mbox_inb(mbox, ASPEED_MBOX_DATA_0 + (i * 4)));
++ }
++#endif
++
++ /* Clear interrupt status */
++ 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);
++
++ wake_up(&mbox->queue);
++ return IRQ_HANDLED;
++}
++
++static int aspeed_mbox_config_irq(struct aspeed_mbox *mbox,
++ struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ int rc;
++
++ mbox->irq = platform_get_irq(pdev, 0);
++ if (!mbox->irq)
++ return -ENODEV;
++
++ rc = devm_request_irq(dev, mbox->irq, aspeed_mbox_irq,
++ IRQF_SHARED, DEVICE_NAME, mbox);
++ if (rc < 0) {
++ dev_err(dev, "Unable to request IRQ %d\n", mbox->irq);
++ return rc;
++ }
++
++ /* Disable all register based interrupts. */
++ aspeed_mbox_outb(mbox, 0xff, ASPEED_MBOX_INTERRUPT_0); /* regs 0 - 7 */
++ aspeed_mbox_outb(mbox, 0xff, ASPEED_MBOX_INTERRUPT_1); /* regs 8 - 15 */
++
++ /* These registers are write one to clear. Clear them. */
++ 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);
++ return 0;
++}
++
++static int aspeed_mbox_probe(struct platform_device *pdev)
++{
++ struct aspeed_mbox *mbox;
++ struct device *dev;
++ int rc;
++
++ dev = &pdev->dev;
++
++ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
++ if (!mbox)
++ return -ENOMEM;
++
++ dev_set_drvdata(&pdev->dev, mbox);
++
++ rc = of_property_read_u32(dev->of_node, "reg", &mbox->base);
++ if (rc) {
++ dev_err(dev, "Couldn't read reg device-tree property\n");
++ return rc;
++ }
++
++ mbox->regmap = syscon_node_to_regmap(
++ pdev->dev.parent->of_node);
++ if (IS_ERR(mbox->regmap)) {
++ dev_err(dev, "Couldn't get regmap\n");
++ return -ENODEV;
++ }
++
++ mutex_init(&mbox->mutex);
++ init_waitqueue_head(&mbox->queue);
++
++ mbox->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(mbox->clk)) {
++ rc = PTR_ERR(mbox->clk);
++ if (rc != -EPROBE_DEFER)
++ dev_err(dev, "couldn't get clock\n");
++ return rc;
++ }
++ rc = clk_prepare_enable(mbox->clk);
++ if (rc) {
++ dev_err(dev, "couldn't enable clock\n");
++ return rc;
++ }
++
++ mbox->miscdev.minor = MISC_DYNAMIC_MINOR;
++ mbox->miscdev.name = DEVICE_NAME;
++ mbox->miscdev.fops = &aspeed_mbox_fops;
++ mbox->miscdev.parent = dev;
++ rc = misc_register(&mbox->miscdev);
++ if (rc) {
++ dev_err(dev, "Unable to register device\n");
++ goto err;
++ }
++
++ rc = aspeed_mbox_config_irq(mbox, pdev);
++ if (rc) {
++ dev_err(dev, "Failed to configure IRQ\n");
++ misc_deregister(&mbox->miscdev);
++ goto err;
++ }
++
++ dev_info(&pdev->dev, "LPC mbox registered, irq %d\n", mbox->irq);
++
++ return 0;
++
++err:
++ clk_disable_unprepare(mbox->clk);
++
++ return rc;
++}
++
++static int aspeed_mbox_remove(struct platform_device *pdev)
++{
++ struct aspeed_mbox *mbox = dev_get_drvdata(&pdev->dev);
++
++ misc_deregister(&mbox->miscdev);
++ clk_disable_unprepare(mbox->clk);
++
++ return 0;
++}
++
++static const struct of_device_id aspeed_mbox_match[] = {
++ { .compatible = "aspeed,ast2400-mbox" },
++ { .compatible = "aspeed,ast2500-mbox" },
++ { .compatible = "aspeed,ast2600-mbox" },
++ { },
++};
++MODULE_DEVICE_TABLE(of, aspeed_mbox_match);
++
++static struct platform_driver aspeed_mbox_driver = {
++ .driver = {
++ .name = DEVICE_NAME,
++ .of_match_table = aspeed_mbox_match,
++ },
++ .probe = aspeed_mbox_probe,
++ .remove = aspeed_mbox_remove,
++};
++
++module_platform_driver(aspeed_mbox_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>");
++MODULE_DESCRIPTION("Aspeed mailbox device driver");
+--
+2.17.1
+
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..b4b1bcad8
--- /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,580 @@
+From 39f76bd49fd481999cf51fbdfbea3e820efc7227 Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@intel.com>
+Date: Mon, 13 Nov 2017 16:29:44 +0800
+Subject: [PATCH] Aspeed LPC SIO driver
+
+Add lpc sio device driver for AST2500/2400
+
+Signed-off-by: Yong Li <yong.b.li@intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ .../bindings/soc/aspeed/aspeed-lpc-sio.txt | 17 +
+ arch/arm/boot/dts/aspeed-g4.dtsi | 7 +
+ arch/arm/boot/dts/aspeed-g5.dtsi | 7 +
+ drivers/soc/aspeed/Kconfig | 7 +
+ drivers/soc/aspeed/Makefile | 1 +
+ drivers/soc/aspeed/aspeed-lpc-sio.c | 410 +++++++++++++++++++++
+ include/uapi/linux/aspeed-lpc-sio.h | 45 +++
+ 7 files changed, 494 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/soc/aspeed/aspeed-lpc-sio.txt
+ create mode 100644 drivers/soc/aspeed/aspeed-lpc-sio.c
+ create mode 100644 include/uapi/linux/aspeed-lpc-sio.h
+
+diff --git a/Documentation/devicetree/bindings/soc/aspeed/aspeed-lpc-sio.txt b/Documentation/devicetree/bindings/soc/aspeed/aspeed-lpc-sio.txt
+new file mode 100644
+index 000000000000..c74ea3a4e5ac
+--- /dev/null
++++ b/Documentation/devicetree/bindings/soc/aspeed/aspeed-lpc-sio.txt
+@@ -0,0 +1,17 @@
++* Aspeed LPC SIO driver.
++
++Required properties:
++- compatible : Should be one of:
++ "aspeed,ast2400-lpc-sio"
++ "aspeed,ast2500-lpc-sio"
++- reg : Should contain lpc-sio registers location and length
++- clocks: contains a phandle to the syscon node describing the clocks.
++ There should then be one cell representing the clock to use.
++
++Example:
++lpc_sio: lpc-sio@100 {
++ compatible = "aspeed,ast2500-lpc-sio";
++ reg = <0x100 0x20>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++};
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index f3edda4ae477..a70bee24d058 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -394,6 +394,13 @@
+ compatible = "aspeed,bmc-misc";
+ };
+
++ lpc_sio: lpc-sio@100 {
++ compatible = "aspeed,ast2400-lpc-sio";
++ reg = <0x100 0x20>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
++
+ mbox: mbox@180 {
+ compatible = "aspeed,ast2400-mbox";
+ reg = <0x180 0x5c>;
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index bd6d1461e4bd..c15be82c3a9d 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -503,6 +503,13 @@
+ compatible = "aspeed,bmc-misc";
+ };
+
++ lpc_sio: lpc-sio@100 {
++ compatible = "aspeed,ast2500-lpc-sio";
++ reg = <0x100 0x20>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
++
+ mbox: mbox@180 {
+ compatible = "aspeed,ast2500-mbox";
+ reg = <0x180 0x5c>;
+diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig
+index a4be8e566bc7..285c19042c65 100644
+--- a/drivers/soc/aspeed/Kconfig
++++ b/drivers/soc/aspeed/Kconfig
+@@ -28,6 +28,13 @@ config ASPEED_LPC_MBOX
+ Expose the ASPEED LPC MBOX registers found on Aspeed SOCs (AST2400
+ and AST2500) to userspace.
+
++config ASPEED_LPC_SIO
++ tristate "Aspeed ast2400/2500 HOST LPC SIO support"
++ depends on SOC_ASPEED && REGMAP && MFD_SYSCON
++ 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 SOC_ASPEED && REGMAP && MFD_SYSCON
+diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
+index f3ff29b874ed..2e547cc47e62 100644
+--- a/drivers/soc/aspeed/Makefile
++++ b/drivers/soc/aspeed/Makefile
+@@ -2,5 +2,6 @@
+ obj-$(CONFIG_ASPEED_BMC_MISC) += aspeed-bmc-misc.o
+ obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
+ obj-$(CONFIG_ASPEED_LPC_MBOX) += aspeed-lpc-mbox.o
++obj-$(CONFIG_ASPEED_LPC_SIO) += aspeed-lpc-sio.o
+ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
+ obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
+diff --git a/drivers/soc/aspeed/aspeed-lpc-sio.c b/drivers/soc/aspeed/aspeed-lpc-sio.c
+new file mode 100644
+index 000000000000..d4a4da112ff4
+--- /dev/null
++++ b/drivers/soc/aspeed/aspeed-lpc-sio.c
+@@ -0,0 +1,410 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (C) 2012-2017 ASPEED Technology Inc.
++// Copyright (c) 2017-2020 Intel Corporation
++
++#include <linux/aspeed-lpc-sio.h>
++#include <linux/clk.h>
++#include <linux/mfd/syscon.h>
++#include <linux/miscdevice.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/poll.h>
++#include <linux/regmap.h>
++
++#define SOC_NAME "aspeed"
++#define DEVICE_NAME "lpc-sio"
++
++#define AST_LPC_SWCR0300 0x00
++#define LPC_PWRGD_STS BIT(30)
++#define LPC_PWRGD_RISING_EVT_STS BIT(29)
++#define LPC_PWRGD_FALLING_EVT_STS BIT(28)
++#define LPC_PWRBTN_STS BIT(27)
++#define LPC_PWRBTN_RISING_EVT_STS BIT(26)
++#define LPC_PWRBTN_FALLING_EVT_STS BIT(25)
++#define LPC_S5N_STS BIT(21)
++#define LPC_S5N_RISING_EVT_STS BIT(20)
++#define LPC_S5N_FALLING_EVT_STS BIT(19)
++#define LPC_S3N_STS BIT(18)
++#define LPC_S3N_RISING_EVT_STS BIT(17)
++#define LPC_S3N_FALLING_EVT_STS BIT(16)
++#define LPC_PWBTO_RAW_STS BIT(15)
++#define LPC_LAST_ONCTL_STS BIT(14)
++#define LPC_WAS_PFAIL_STS BIT(13)
++#define LPC_POWER_UP_FAIL_STS BIT(12) /* Crowbar */
++#define LPC_PWRBTN_OVERRIDE_STS BIT(11)
++#define LPC_BMC_TRIG_WAKEUP_EVT_STS BIT(8)
++
++#define AST_LPC_SWCR0704 0x04
++#define LPC_BMC_TRIG_WAKEUP_EVT_EN BIT(8)
++
++#define AST_LPC_SWCR0B08 0x08
++#define LPC_PWREQ_OUTPUT_LEVEL BIT(25)
++#define LPC_PWBTO_OUTPUT_LEVEL BIT(24)
++#define LPC_ONCTL_STS BIT(15)
++#define LPC_ONCTL_GPIO_LEVEL BIT(14)
++#define LPC_ONCTL_EN_GPIO_OUTPUT BIT(13)
++#define LPC_ONCTL_EN_GPIO_MODE BIT(12)
++#define LPC_BMC_TRIG_WAKEUP_EVT BIT(6)
++
++#define AST_LPC_SWCR0F0C 0x0C
++#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 LPC_BMC_TRIG_SCI_EVT_STS BIT(8)
++
++#define AST_LPC_ACPIB7B4 0x2C
++#define LPC_BMC_TRIG_SCI_EVT_EN BIT(8)
++
++struct aspeed_lpc_sio {
++ struct miscdevice miscdev;
++ struct regmap *regmap;
++ struct clk *clk;
++ struct semaphore lock;
++ unsigned int reg_base;
++};
++
++static struct aspeed_lpc_sio *file_aspeed_lpc_sio(struct file *file)
++{
++ return container_of(file->private_data, struct aspeed_lpc_sio,
++ miscdev);
++}
++
++static int aspeed_lpc_sio_open(struct inode *inode, struct file *filp)
++{
++ return 0;
++}
++
++#define LPC_SLP3N5N_EVENT_STATUS (\
++ LPC_S5N_RISING_EVT_STS | \
++ LPC_S5N_FALLING_EVT_STS | \
++ LPC_S3N_RISING_EVT_STS | \
++ LPC_S3N_FALLING_EVT_STS)
++
++/*
++ * SLPS3n SLPS5n State
++ * ---------------------------------
++ * 1 1 S12
++ * 0 1 S3I
++ * x 0 S45
++ *************************************
++ */
++
++static void sio_get_acpi_state(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg, val;
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300;
++ regmap_read(lpc_sio->regmap, reg, &val);
++
++ /* update the ACPI state event status */
++ if (sio_data->param != 0) {
++ if (val & LPC_SLP3N5N_EVENT_STATUS) {
++ sio_data->param = 1;
++ regmap_write(lpc_sio->regmap, reg,
++ LPC_SLP3N5N_EVENT_STATUS);
++ } 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;
++}
++
++#define LPC_PWRGD_EVENT_STATUS ( \
++ LPC_PWRGD_RISING_EVT_STS | \
++ LPC_PWRGD_FALLING_EVT_STS)
++
++static void sio_get_pwrgd_status(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg, val;
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300;
++ regmap_read(lpc_sio->regmap, reg, &val);
++
++ /* update the PWRGD event status */
++ if (sio_data->param != 0) {
++ if (val & LPC_PWRGD_EVENT_STATUS) {
++ sio_data->param = 1;
++ regmap_write(lpc_sio->regmap, reg,
++ LPC_PWRGD_EVENT_STATUS);
++ } else {
++ sio_data->param = 0;
++ }
++ }
++
++ sio_data->data = (val & LPC_PWRGD_STS) != 0 ? 1 : 0;
++}
++
++static void sio_get_onctl_status(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg, val;
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0B08;
++ regmap_read(lpc_sio->regmap, reg, &val);
++
++ sio_data->data = (val & LPC_ONCTL_STS) != 0 ? 1 : 0;
++}
++
++static void sio_set_onctl_gpio(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg, val;
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0B08;
++ regmap_read(lpc_sio->regmap, reg, &val);
++
++ /* 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;
++
++ regmap_write(lpc_sio->regmap, reg, val);
++ } else {
++ val &= ~LPC_ONCTL_EN_GPIO_MODE;
++ regmap_write(lpc_sio->regmap, reg, val);
++ }
++}
++
++static void sio_get_pwrbtn_override(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg, val;
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300;
++ regmap_read(lpc_sio->regmap, reg, &val);
++
++ /* clear the PWRBTN OVERRIDE status */
++ if (sio_data->param != 0 && val & LPC_PWRBTN_OVERRIDE_STS)
++ regmap_write(lpc_sio->regmap, reg, LPC_PWRBTN_OVERRIDE_STS);
++
++ sio_data->data = (val & LPC_PWRBTN_OVERRIDE_STS) != 0 ? 1 : 0;
++}
++
++static void sio_get_pfail_status(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg, val;
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300;
++ regmap_read(lpc_sio->regmap, reg, &val);
++
++ /* [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) {
++ regmap_write(lpc_sio->regmap, reg, 0); /* W0C */
++ sio_data->data = 1;
++ } else {
++ sio_data->data = 0;
++ }
++}
++
++static void sio_set_bmc_sci_event(struct aspeed_lpc_sio *lpc_sio,
++ struct sio_ioctl_data *sio_data)
++{
++ u32 reg;
++
++ if (sio_data->param) {
++ reg = lpc_sio->reg_base + AST_LPC_ACPIB7B4;
++ regmap_write_bits(lpc_sio->regmap, reg,
++ LPC_BMC_TRIG_SCI_EVT_EN,
++ LPC_BMC_TRIG_SCI_EVT_EN);
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0704;
++ regmap_write_bits(lpc_sio->regmap, reg,
++ LPC_BMC_TRIG_WAKEUP_EVT_EN,
++ LPC_BMC_TRIG_WAKEUP_EVT_EN);
++
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0B08;
++ regmap_write_bits(lpc_sio->regmap, reg,
++ LPC_BMC_TRIG_WAKEUP_EVT,
++ LPC_BMC_TRIG_WAKEUP_EVT);
++ } else {
++ reg = lpc_sio->reg_base + AST_LPC_SWCR0300;
++ regmap_write_bits(lpc_sio->regmap, reg,
++ LPC_BMC_TRIG_WAKEUP_EVT_STS,
++ LPC_BMC_TRIG_WAKEUP_EVT_STS);
++
++ reg = lpc_sio->reg_base + AST_LPC_ACPIB3B0;
++ regmap_write_bits(lpc_sio->regmap, reg,
++ LPC_BMC_TRIG_SCI_EVT_STS,
++ LPC_BMC_TRIG_SCI_EVT_STS);
++ }
++
++ sio_data->data = sio_data->param;
++}
++
++typedef void (*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,
++ [SIO_SET_BMC_SCI_EVENT] = sio_set_bmc_sci_event,
++};
++
++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);
++ struct sio_ioctl_data sio_data;
++ sio_cmd_fn cmd_fn;
++ long ret;
++
++ 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)
++ return -EINVAL;
++
++ if (down_interruptible(&lpc_sio->lock) != 0)
++ return -ERESTARTSYS;
++
++ cmd_fn(lpc_sio, &sio_data);
++ ret = copy_to_user((void __user *)param, &sio_data, sizeof(sio_data));
++
++ 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;
++ u32 val;
++ int ret;
++
++ 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);
++
++ ret = of_property_read_u32(dev->of_node, "reg", &lpc_sio->reg_base);
++ if (ret) {
++ dev_err(dev, "Couldn't read reg device-tree property\n");
++ return ret;
++ }
++
++ 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;
++ }
++
++ /*
++ * We check that the regmap works on this very first access,
++ * but as this is an MMIO-backed regmap, subsequent regmap
++ * access is not going to fail and we skip error checks from
++ * this point.
++ */
++ ret = regmap_read(lpc_sio->regmap, AST_LPC_SWCR0300, &val);
++ if (ret) {
++ dev_err(dev, "failed to read regmap\n");
++ return ret;
++ }
++
++ sema_init(&lpc_sio->lock, 1);
++
++ lpc_sio->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(lpc_sio->clk)) {
++ ret = PTR_ERR(lpc_sio->clk);
++ if (ret != -EPROBE_DEFER)
++ dev_err(dev, "couldn't get clock\n");
++ return ret;
++ }
++ ret = clk_prepare_enable(lpc_sio->clk);
++ if (ret) {
++ dev_err(dev, "couldn't enable clock\n");
++ return ret;
++ }
++
++ 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;
++ ret = misc_register(&lpc_sio->miscdev);
++ if (ret) {
++ dev_err(dev, "Unable to register device\n");
++ goto err;
++ }
++
++ dev_info(dev, "Loaded at %pap (0x%08x)\n", &lpc_sio->regmap,
++ lpc_sio->reg_base);
++
++ return 0;
++
++err:
++ clk_disable_unprepare(lpc_sio->clk);
++
++ return ret;
++}
++
++static int aspeed_lpc_sio_remove(struct platform_device *pdev)
++{
++ struct aspeed_lpc_sio *lpc_sio = dev_get_drvdata(&pdev->dev);
++
++ misc_deregister(&lpc_sio->miscdev);
++ clk_disable_unprepare(lpc_sio->clk);
++
++ return 0;
++}
++
++static const struct of_device_id aspeed_lpc_sio_match[] = {
++ { .compatible = "aspeed,ast2500-lpc-sio" },
++ { },
++};
++MODULE_DEVICE_TABLE(of, aspeed_lpc_sio_match);
++
++static struct platform_driver aspeed_lpc_sio_driver = {
++ .driver = {
++ .name = SOC_NAME "-" DEVICE_NAME,
++ .of_match_table = of_match_ptr(aspeed_lpc_sio_match),
++ },
++ .probe = aspeed_lpc_sio_probe,
++ .remove = aspeed_lpc_sio_remove,
++};
++module_platform_driver(aspeed_lpc_sio_driver);
++
++MODULE_LICENSE("GPL v2");
++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..acf89a7d2b4a
+--- /dev/null
++++ b/include/uapi/linux/aspeed-lpc-sio.h
+@@ -0,0 +1,45 @@
++/*
++ * 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_SET_BMC_SCI_EVENT,
++
++ 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..c409dec50
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0022-Add-AST2500-eSPI-driver.patch
@@ -0,0 +1,762 @@
+From e6e186acacc16fd95251b2d0fb024993a66ffa0a 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] Add AST2500 eSPI driver
+
+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
+
+Also, it provides monitoring interface of PLTRST_N signal through
+/dev/espi-pltrstn
+
+Signed-off-by: Haiyue Wang <haiyue.wang@linux.intel.com>
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
+---
+ .../devicetree/bindings/misc/aspeed,espi-slave.txt | 20 +
+ Documentation/misc-devices/espi-slave.rst | 118 ++++++
+ arch/arm/boot/dts/aspeed-g5.dtsi | 4 +
+ arch/arm/boot/dts/aspeed-g6.dtsi | 14 +
+ drivers/misc/Kconfig | 8 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/aspeed-espi-slave.c | 468 +++++++++++++++++++++
+ include/dt-bindings/clock/ast2600-clock.h | 1 +
+ 8 files changed, 634 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..f72d9ae32f3e
+--- /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"
++ - "aspeed,ast2600-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..887a69a7130a
+--- /dev/null
++++ b/Documentation/misc-devices/espi-slave.rst
+@@ -0,0 +1,118 @@
++.. 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 26d885d2bd8a..7b798c49cb95 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -336,6 +336,7 @@
+ clocks = <&syscon ASPEED_CLK_APB>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
++ status = "disabled";
+ };
+
+ sgpio: sgpio@1e780200 {
+@@ -432,6 +433,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/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index 825e64ce317a..315d35c15208 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -4,6 +4,7 @@
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/ast2600-clock.h>
+ #include <dt-bindings/interrupt-controller/aspeed-scu-ic.h>
++#include <dt-bindings/gpio/aspeed-gpio.h>
+
+ / {
+ model = "Aspeed BMC";
+@@ -708,6 +709,19 @@
+ status = "disabled";
+ };
+
++ espi: espi@1e6ee000 {
++ compatible = "aspeed,ast2600-espi-slave";
++ reg = <0x1e6ee000 0x200>;
++ interrupts-extended = <&gic GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
++ <&gpio0 ASPEED_GPIO(W, 7) IRQ_TYPE_EDGE_FALLING>;
++ status = "disabled";
++ clocks = <&syscon ASPEED_CLK_GATE_ESPICLK>;
++ resets = <&syscon ASPEED_RESET_ESPI>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_espi_default>,
++ <&pinctrl_espialt_default>;
++ };
++
+ i2c: bus@1e78a000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 06a2b753cc7c..0f9b5a356c93 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -433,6 +433,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 PCI_ENDPOINT_TEST
+ depends on PCI
+ select CRC32
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index b9e6d4c3e906..53864687e8fd 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -51,6 +51,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_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
+ obj-$(CONFIG_OCXL) += ocxl/
+ obj-y += cardreader/
+diff --git a/drivers/misc/aspeed-espi-slave.c b/drivers/misc/aspeed-espi-slave.c
+new file mode 100644
+index 000000000000..87bc81948694
+--- /dev/null
++++ b/drivers/misc/aspeed-espi-slave.c
+@@ -0,0 +1,468 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2015-2019, Intel Corporation.
++
++#include <linux/clk.h>
++#include <linux/fs.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/regmap.h>
++#include <linux/reset.h>
++#include <linux/sched/signal.h>
++#include <linux/spinlock.h>
++#include <linux/uaccess.h>
++
++#define ASPEED_ESPI_CTRL 0x00
++#define ASPEED_ESPI_CTRL_SW_RESET GENMASK(31, 24)
++#define ASPEED_ESPI_CTRL_OOB_CHRDY BIT(4)
++#define ASPEED_ESPI_INT_STS 0x08
++#define ASPEED_ESPI_HW_RESET BIT(31)
++#define ASPEED_ESPI_VW_SYSEVT1 BIT(22)
++#define ASPEED_ESPI_VW_SYSEVT BIT(8)
++#define ASPEED_ESPI_INT_EN 0x0C
++#define ASPEED_ESPI_DATA_PORT 0x28
++#define ASPEED_ESPI_SYSEVT_INT_EN 0x94
++#define ASPEED_ESPI_SYSEVT 0x98
++#define ASPEED_ESPI_SYSEVT_HOST_RST_ACK BIT(27)
++#define ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS BIT(23)
++#define ASPEED_ESPI_SYSEVT_SLAVE_BOOT_DONE BIT(20)
++#define ASPEED_ESPI_SYSEVT_OOB_RST_ACK BIT(16)
++#define ASPEED_ESPI_SYSEVT_INT_T0 0x110
++#define ASPEED_ESPI_SYSEVT_INT_T1 0x114
++#define ASPEED_ESPI_SYSEVT_INT_T2 0x118
++#define ASPEED_ESPI_SYSEVT_INT_STS 0x11C
++#define ASPEED_ESPI_SYSEVT_HOST_RST_WARN BIT(8)
++#define ASPEED_ESPI_SYSEVT_OOB_RST_WARN BIT(6)
++#define ASPEED_ESPI_SYSEVT_PLTRSTN BIT(5)
++#define ASPEED_ESPI_SYSEVT1_INT_EN 0x100
++#define ASPEED_ESPI_SYSEVT1 0x104
++#define ASPEED_ESPI_SYSEVT1_SUS_ACK BIT(20)
++#define ASPEED_ESPI_SYSEVT1_INT_T0 0x120
++#define ASPEED_ESPI_SYSEVT1_INT_T1 0x124
++#define ASPEED_ESPI_SYSEVT1_INT_T2 0x128
++#define ASPEED_ESPI_SYSEVT1_INT_STS 0x12C
++#define ASPEED_ESPI_SYSEVT1_SUS_WARN BIT(0)
++
++#define ASPEED_ESPI_INT_MASK \
++ (ASPEED_ESPI_HW_RESET | \
++ ASPEED_ESPI_VW_SYSEVT1 | \
++ ASPEED_ESPI_VW_SYSEVT)
++
++/*
++ * 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) PLTRSTN : Dual Edge 1 0 0
++ */
++#define ASPEED_ESPI_SYSEVT_INT_T0_MASK 0
++#define ASPEED_ESPI_SYSEVT_INT_T1_MASK 0
++#define ASPEED_ESPI_SYSEVT_INT_T2_MASK \
++ (ASPEED_ESPI_SYSEVT_HOST_RST_WARN | \
++ ASPEED_ESPI_SYSEVT_OOB_RST_WARN | \
++ ASPEED_ESPI_SYSEVT_PLTRSTN)
++#define ASPEED_ESPI_SYSEVT_INT_MASK \
++ (ASPEED_ESPI_SYSEVT_INT_T0_MASK | \
++ ASPEED_ESPI_SYSEVT_INT_T1_MASK | \
++ ASPEED_ESPI_SYSEVT_INT_T2_MASK)
++
++/*
++ * Setup Interrupt Type / Enable of System Event 1 from Master
++ * T2 T1 T0
++ * 1) SUS_WARN : Rising Edge 0 0 1
++ */
++#define ASPEED_ESPI_SYSEVT1_INT_T0_MASK ASPEED_ESPI_SYSEVT1_SUS_WARN
++#define ASPEED_ESPI_SYSEVT1_INT_T1_MASK 0
++#define ASPEED_ESPI_SYSEVT1_INT_T2_MASK 0
++#define ASPEED_ESPI_SYSEVT1_INT_MASK \
++ (ASPEED_ESPI_SYSEVT1_INT_T0_MASK | \
++ ASPEED_ESPI_SYSEVT1_INT_T1_MASK | \
++ ASPEED_ESPI_SYSEVT1_INT_T2_MASK)
++
++struct aspeed_espi {
++ struct regmap *map;
++ struct clk *clk;
++ struct device *dev;
++ struct reset_control *reset;
++ int irq;
++ int rst_irq;
++
++ /* for PLTRST_N signal monitoring interface */
++ struct miscdevice pltrstn_miscdev;
++ spinlock_t pltrstn_lock; /* for PLTRST_N signal sampling */
++ wait_queue_head_t pltrstn_waitq;
++ char pltrstn;
++};
++
++static void aspeed_espi_sys_event(struct aspeed_espi *priv)
++{
++ u32 sts, evt;
++
++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT_INT_STS, &sts);
++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT, &evt);
++
++ dev_dbg(priv->dev, "sys: sts = %08x, evt = %08x\n", sts, evt);
++
++ if (!(evt & ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS)) {
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT,
++ evt | ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS |
++ ASPEED_ESPI_SYSEVT_SLAVE_BOOT_DONE);
++ dev_dbg(priv->dev, "Setting espi slave boot done\n");
++ }
++ if (sts & ASPEED_ESPI_SYSEVT_HOST_RST_WARN &&
++ evt & ASPEED_ESPI_SYSEVT_HOST_RST_WARN) {
++ regmap_write_bits(priv->map, ASPEED_ESPI_SYSEVT,
++ ASPEED_ESPI_SYSEVT_HOST_RST_ACK,
++ ASPEED_ESPI_SYSEVT_HOST_RST_ACK);
++ dev_dbg(priv->dev, "SYSEVT_HOST_RST_WARN: acked\n");
++ }
++ if (sts & ASPEED_ESPI_SYSEVT_OOB_RST_WARN &&
++ evt & ASPEED_ESPI_SYSEVT_OOB_RST_WARN) {
++ regmap_write_bits(priv->map, ASPEED_ESPI_SYSEVT,
++ ASPEED_ESPI_SYSEVT_OOB_RST_ACK,
++ ASPEED_ESPI_SYSEVT_OOB_RST_ACK);
++ dev_dbg(priv->dev, "SYSEVT_OOB_RST_WARN: acked\n");
++ }
++ if (sts & ASPEED_ESPI_SYSEVT_PLTRSTN || priv->pltrstn == 'U') {
++ priv->pltrstn = (evt & ASPEED_ESPI_SYSEVT_PLTRSTN) ? '1' : '0';
++ wake_up_interruptible(&priv->pltrstn_waitq);
++ dev_dbg(priv->dev, "SYSEVT_PLTRSTN: %c\n", priv->pltrstn);
++ }
++
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_STS, sts);
++}
++
++static void aspeed_espi_sys_event1(struct aspeed_espi *priv)
++{
++ u32 sts, evt;
++
++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT1_INT_STS, &sts);
++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT1, &evt);
++
++ dev_dbg(priv->dev, "sys event1: sts = %08x, evt = %08x\n", sts, evt);
++
++ if (sts & ASPEED_ESPI_SYSEVT1_SUS_WARN &&
++ evt & ASPEED_ESPI_SYSEVT1_SUS_WARN) {
++ regmap_write_bits(priv->map, ASPEED_ESPI_SYSEVT1,
++ ASPEED_ESPI_SYSEVT1_SUS_ACK,
++ ASPEED_ESPI_SYSEVT1_SUS_ACK);
++ dev_dbg(priv->dev, "SYSEVT1_SUS_WARN: acked\n");
++ }
++
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_STS, sts);
++}
++
++static void aspeed_espi_boot_ack(struct aspeed_espi *priv)
++{
++ u32 evt;
++
++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT, &evt);
++ if (!(evt & ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS)) {
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT,
++ evt | ASPEED_ESPI_SYSEVT_SLAVE_BOOT_STATUS |
++ ASPEED_ESPI_SYSEVT_SLAVE_BOOT_DONE);
++ dev_dbg(priv->dev, "Setting espi slave boot done\n");
++ }
++
++ regmap_read(priv->map, ASPEED_ESPI_SYSEVT1, &evt);
++ if (evt & ASPEED_ESPI_SYSEVT1_SUS_WARN &&
++ !(evt & ASPEED_ESPI_SYSEVT1_SUS_ACK)) {
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1,
++ evt | ASPEED_ESPI_SYSEVT1_SUS_ACK);
++ dev_dbg(priv->dev, "Boot SYSEVT1_SUS_WARN: acked\n");
++ }
++}
++
++static irqreturn_t aspeed_espi_irq(int irq, void *arg)
++{
++ struct aspeed_espi *priv = arg;
++ u32 sts, sts_handled = 0;
++
++ regmap_read(priv->map, ASPEED_ESPI_INT_STS, &sts);
++
++ dev_dbg(priv->dev, "INT_STS: 0x%08x\n", sts);
++
++ if (sts & ASPEED_ESPI_VW_SYSEVT) {
++ aspeed_espi_sys_event(priv);
++ sts_handled |= ASPEED_ESPI_VW_SYSEVT;
++ }
++
++ if (sts & ASPEED_ESPI_VW_SYSEVT1) {
++ aspeed_espi_sys_event1(priv);
++ sts_handled |= ASPEED_ESPI_VW_SYSEVT1;
++ }
++
++ if (sts & ASPEED_ESPI_HW_RESET) {
++ if (priv->rst_irq < 0) {
++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL,
++ ASPEED_ESPI_CTRL_SW_RESET, 0);
++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL,
++ ASPEED_ESPI_CTRL_SW_RESET,
++ ASPEED_ESPI_CTRL_SW_RESET);
++ }
++
++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL,
++ ASPEED_ESPI_CTRL_OOB_CHRDY,
++ ASPEED_ESPI_CTRL_OOB_CHRDY);
++ aspeed_espi_boot_ack(priv);
++ sts_handled |= ASPEED_ESPI_HW_RESET;
++ }
++
++ regmap_write(priv->map, ASPEED_ESPI_INT_STS, sts);
++
++ return sts != sts_handled ? IRQ_NONE : IRQ_HANDLED;
++}
++
++static void aspeed_espi_config_irq(struct aspeed_espi *priv)
++{
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_T0,
++ ASPEED_ESPI_SYSEVT_INT_T0_MASK);
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_T1,
++ ASPEED_ESPI_SYSEVT_INT_T1_MASK);
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_T2,
++ ASPEED_ESPI_SYSEVT_INT_T2_MASK);
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT_INT_EN,
++ ASPEED_ESPI_SYSEVT_INT_MASK);
++
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_T0,
++ ASPEED_ESPI_SYSEVT1_INT_T0_MASK);
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_T1,
++ ASPEED_ESPI_SYSEVT1_INT_T1_MASK);
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_T2,
++ ASPEED_ESPI_SYSEVT1_INT_T2_MASK);
++ regmap_write(priv->map, ASPEED_ESPI_SYSEVT1_INT_EN,
++ ASPEED_ESPI_SYSEVT1_INT_MASK);
++
++ regmap_write(priv->map, ASPEED_ESPI_INT_EN, ASPEED_ESPI_INT_MASK);
++}
++
++static irqreturn_t aspeed_espi_reset_isr(int irq, void *arg)
++{
++ struct aspeed_espi *priv = arg;
++
++ reset_control_assert(priv->reset);
++ reset_control_deassert(priv->reset);
++
++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL,
++ ASPEED_ESPI_CTRL_SW_RESET, 0);
++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL,
++ ASPEED_ESPI_CTRL_SW_RESET, ASPEED_ESPI_CTRL_SW_RESET);
++
++ regmap_write_bits(priv->map, ASPEED_ESPI_CTRL,
++ ASPEED_ESPI_CTRL_OOB_CHRDY, 0);
++
++ aspeed_espi_config_irq(priv);
++
++ return IRQ_HANDLED;
++}
++
++static inline struct aspeed_espi *to_aspeed_espi(struct file *filp)
++{
++ return container_of(filp->private_data, struct aspeed_espi,
++ pltrstn_miscdev);
++}
++
++static int aspeed_espi_pltrstn_open(struct inode *inode, struct file *filp)
++{
++ if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
++ return -EACCES;
++
++ return 0;
++}
++
++static ssize_t aspeed_espi_pltrstn_read(struct file *filp, char __user *buf,
++ size_t count, loff_t *offset)
++{
++ struct aspeed_espi *priv = to_aspeed_espi(filp);
++ DECLARE_WAITQUEUE(wait, current);
++ unsigned long flags;
++ char old_sample;
++ int ret = 0;
++
++ spin_lock_irqsave(&priv->pltrstn_lock, flags);
++
++ add_wait_queue(&priv->pltrstn_waitq, &wait);
++ set_current_state(TASK_INTERRUPTIBLE);
++
++ old_sample = priv->pltrstn;
++
++ do {
++ char new_sample = priv->pltrstn;
++
++ if (filp->f_flags & O_NONBLOCK || old_sample != new_sample) {
++ ret = put_user(new_sample, (unsigned long __user *)buf);
++ if (!ret)
++ ret = sizeof(new_sample);
++ } else if (signal_pending(current)) {
++ ret = -ERESTARTSYS;
++ }
++
++ if (!ret) {
++ spin_unlock_irqrestore(&priv->pltrstn_lock, flags);
++ schedule();
++ spin_lock_irqsave(&priv->pltrstn_lock, flags);
++ }
++ } while (!ret);
++
++ remove_wait_queue(&priv->pltrstn_waitq, &wait);
++ set_current_state(TASK_RUNNING);
++
++ spin_unlock_irqrestore(&priv->pltrstn_lock, flags);
++
++ return ret;
++}
++
++static const struct file_operations aspeed_espi_pltrstn_fops = {
++ .owner = THIS_MODULE,
++ .open = aspeed_espi_pltrstn_open,
++ .read = aspeed_espi_pltrstn_read,
++};
++
++static const struct regmap_config aspeed_espi_regmap_cfg = {
++ .reg_bits = 32,
++ .reg_stride = 4,
++ .val_bits = 32,
++ .max_register = ASPEED_ESPI_SYSEVT1_INT_STS,
++};
++
++static int aspeed_espi_probe(struct platform_device *pdev)
++{
++ struct aspeed_espi *priv;
++ struct resource *res;
++ void __iomem *regs;
++ u32 ctrl;
++ int ret;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ regs = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(regs))
++ return PTR_ERR(regs);
++
++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ dev_set_drvdata(&pdev->dev, priv);
++ priv->dev = &pdev->dev;
++
++ priv->map = devm_regmap_init_mmio(&pdev->dev, regs,
++ &aspeed_espi_regmap_cfg);
++ if (IS_ERR(priv->map))
++ return PTR_ERR(priv->map);
++
++ spin_lock_init(&priv->pltrstn_lock);
++ init_waitqueue_head(&priv->pltrstn_waitq);
++ priv->pltrstn = 'U'; /* means it's not reported yet from master */
++
++ priv->irq = platform_get_irq(pdev, 0);
++ if (priv->irq < 0)
++ return priv->irq;
++
++ ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_espi_irq, 0,
++ "aspeed-espi-irq", priv);
++ if (ret)
++ return ret;
++
++ if (of_device_is_compatible(pdev->dev.of_node,
++ "aspeed,ast2600-espi-slave")) {
++ priv->rst_irq = platform_get_irq(pdev, 1);
++ if (priv->rst_irq < 0)
++ return priv->rst_irq;
++
++ ret = devm_request_irq(&pdev->dev, priv->rst_irq,
++ aspeed_espi_reset_isr, 0,
++ "aspeed-espi-rst-irq", priv);
++ if (ret)
++ return ret;
++
++ priv->reset = devm_reset_control_get(&pdev->dev, NULL);
++ if (IS_ERR(priv->reset))
++ return PTR_ERR(priv->reset);
++ } else {
++ priv->rst_irq = -ENOTSUPP;
++ }
++
++ priv->clk = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(priv->clk)) {
++ ret = PTR_ERR(priv->clk);
++ if (ret != -EPROBE_DEFER)
++ dev_err(&pdev->dev, "couldn't get clock\n");
++ return ret;
++ }
++ ret = clk_prepare_enable(priv->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "couldn't enable clock\n");
++ return ret;
++ }
++
++ /*
++ * We check that the regmap works on this very first access, but as this
++ * is an MMIO-backed regmap, subsequent regmap access is not going to
++ * fail and we skip error checks from this point.
++ */
++ ret = regmap_read(priv->map, ASPEED_ESPI_CTRL, &ctrl);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to read ctrl register\n");
++ goto err_clk_disable_out;
++ }
++ regmap_write(priv->map, ASPEED_ESPI_CTRL,
++ ctrl | ASPEED_ESPI_CTRL_OOB_CHRDY);
++
++ priv->pltrstn_miscdev.minor = MISC_DYNAMIC_MINOR;
++ priv->pltrstn_miscdev.name = "espi-pltrstn";
++ priv->pltrstn_miscdev.fops = &aspeed_espi_pltrstn_fops;
++ priv->pltrstn_miscdev.parent = &pdev->dev;
++
++ ret = misc_register(&priv->pltrstn_miscdev);
++ if (ret) {
++ dev_err(&pdev->dev, "Unable to register device\n");
++ goto err_clk_disable_out;
++ }
++
++ aspeed_espi_config_irq(priv);
++ aspeed_espi_boot_ack(priv);
++
++ dev_info(&pdev->dev, "eSPI registered, irq %d\n", priv->irq);
++
++ return 0;
++
++err_clk_disable_out:
++ clk_disable_unprepare(priv->clk);
++
++ return ret;
++}
++
++static int aspeed_espi_remove(struct platform_device *pdev)
++{
++ struct aspeed_espi *priv = dev_get_drvdata(&pdev->dev);
++
++ misc_deregister(&priv->pltrstn_miscdev);
++ clk_disable_unprepare(priv->clk);
++
++ return 0;
++}
++
++static const struct of_device_id of_espi_match_table[] = {
++ { .compatible = "aspeed,ast2500-espi-slave" },
++ { .compatible = "aspeed,ast2600-espi-slave" },
++ { }
++};
++MODULE_DEVICE_TABLE(of, of_espi_match_table);
++
++static struct platform_driver aspeed_espi_driver = {
++ .driver = {
++ .name = KBUILD_MODNAME,
++ .of_match_table = of_match_ptr(of_espi_match_table),
++ },
++ .probe = aspeed_espi_probe,
++ .remove = aspeed_espi_remove,
++};
++module_platform_driver(aspeed_espi_driver);
++
++MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
++MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
++MODULE_DESCRIPTION("Aspeed eSPI driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h
+index 3d90582a813f..1e18364de03d 100644
+--- a/include/dt-bindings/clock/ast2600-clock.h
++++ b/include/dt-bindings/clock/ast2600-clock.h
+@@ -104,6 +104,7 @@
+ #define ASPEED_RESET_PECI 36
+ #define ASPEED_RESET_MII 35
+ #define ASPEED_RESET_I2C 34
++#define ASPEED_RESET_ESPI 32
+ #define ASPEED_RESET_H2X 31
+ #define ASPEED_RESET_GP_MCU 30
+ #define ASPEED_RESET_DP_MCU 29
+--
+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..45dec5b20
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0028-Add-AST2500-JTAG-driver.patch
@@ -0,0 +1,95 @@
+From a4413fe3ba94906243b632e0b9e0e9a91620dd22 Mon Sep 17 00:00:00 2001
+From: "Corona, Ernesto" <ernesto.corona@intel.com>
+Date: Fri, 1 Mar 2019 11:46:09 -0700
+Subject: [PATCH] Add AST2500 JTAG driver
+
+Update AST2500 JTAG driver. Remove Legacy driver but keep headers.
+
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+---
+ include/uapi/linux/jtag_drv.h | 73 +++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 73 insertions(+)
+ create mode 100644 include/uapi/linux/jtag_drv.h
+
+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/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..c9844e1bd
--- /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,145 @@
+From a57f401058e452f9abb6f3233e7f2776af1e6b8d 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 | 26 ++++++++++++++++++++++++++
+ drivers/i2c/i2c-slave-mqueue.c | 24 ++++++++++++++++++++++++
+ 2 files changed, 50 insertions(+)
+
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index a7be6f24450b..c113ffa8d5df 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -169,6 +169,21 @@ 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) \
++ do { \
++ if (dump_debug && (bus)->adap.nr == dump_debug_bus_id) { \
++ char dump_info[100] = {0,}; \
++ snprintf(dump_info, sizeof(dump_info), \
++ "bus_id:%d, addr:0x%02x, flags:0x%02x: ", \
++ (bus)->adap.nr, addr, flags); \
++ print_hex_dump(KERN_ERR, dump_info, DUMP_PREFIX_NONE, \
++ 16, 1, buf, len, true); \
++ } \
++ } while (0)
++
+ static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus);
+
+ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
+@@ -657,6 +672,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 i;
+
+ spin_lock_irqsave(&bus->lock, flags);
+ bus->cmd_err = 0;
+@@ -708,6 +724,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;
+ }
+
+@@ -1079,6 +1100,11 @@ static struct platform_driver aspeed_i2c_bus_driver = {
+ };
+ module_platform_driver(aspeed_i2c_bus_driver);
+
++module_param_named(dump_debug, dump_debug, bool, 0644);
++MODULE_PARM_DESC(dump_debug, "debug flag for dump printing");
++module_param_named(dump_debug_bus_id, dump_debug_bus_id, int, 0644);
++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..2c7a6038409c 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,21 @@ 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) \
++ do { \
++ if (dump_debug && \
++ (client)->adapter->nr == dump_debug_bus_id) { \
++ char dump_info[100] = {0,}; \
++ snprintf(dump_info, sizeof(dump_info), \
++ "bus_id:%d: ", (client)->adapter->nr); \
++ print_hex_dump(KERN_ERR, dump_info, DUMP_PREFIX_NONE, \
++ 16, 1, buf, len, true); \
++ } \
++ } while (0)
++
+ static int i2c_slave_mqueue_callback(struct i2c_client *client,
+ enum i2c_slave_event event, u8 *val)
+ {
+@@ -101,6 +117,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 +148,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 +231,11 @@ static struct i2c_driver i2c_slave_mqueue_driver = {
+ };
+ module_i2c_driver(i2c_slave_mqueue_driver);
+
++module_param_named(dump_debug, dump_debug, bool, 0644);
++MODULE_PARM_DESC(dump_debug, "debug flag for dump printing");
++module_param_named(dump_debug_bus_id, dump_debug_bus_id, int, 0644);
++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..5240a05f5
--- /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,135 @@
+From 0bc792097e73c07bc324e2c9b0172fb27b51a087 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 | 44 +++++++++++++++++++++++++++-----
+ include/dt-bindings/clock/aspeed-clock.h | 2 ++
+ 2 files changed, 39 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
+index 411ff5fb2c07..5e1c87bc8a99 100644
+--- a/drivers/clk/clk-aspeed.c
++++ b/drivers/clk/clk-aspeed.c
+@@ -14,7 +14,9 @@
+
+ #include "clk-aspeed.h"
+
+-#define ASPEED_NUM_CLKS 38
++#define ASPEED_NUM_CLKS ASPEED_CLK_MAX
++#define UART_HIGH_SPEED_CLK 192000000
++#define UART_LOW_SPEED_CLK 24000000
+
+ #define ASPEED_RESET2_OFFSET 32
+
+@@ -29,6 +31,12 @@
+ #define ASPEED_MISC_CTRL 0x2c
+ #define UART_DIV13_EN BIT(12)
+ #define ASPEED_MAC_CLK_DLY 0x48
++#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)
+@@ -386,7 +394,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, rate, rate_hi;
+ int i, ret;
+
+ map = syscon_node_to_regmap(dev->of_node);
+@@ -420,16 +428,25 @@ 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;
+- else
+- rate = 24000000;
++ if (val & UART_DIV13_EN) {
++ rate = UART_LOW_SPEED_CLK / 13;
++ rate_hi = UART_HIGH_SPEED_CLK / 13;
++ } else {
++ rate = UART_LOW_SPEED_CLK;
++ rate_hi = UART_HIGH_SPEED_CLK;
++ }
+ /* TODO: Find the parent data for the uart clock */
+ hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate);
+ 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,
++ rate_hi);
++ 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.
+@@ -539,9 +556,22 @@ static int aspeed_clk_probe(struct platform_device *pdev)
+ * UART[1..5] clock source mux
+ */
+
++ /* 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.
+@@ -549,7 +579,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 9ff4f6e4558c..41d531dd0b48 100644
+--- a/include/dt-bindings/clock/aspeed-clock.h
++++ b/include/dt-bindings/clock/aspeed-clock.h
+@@ -41,6 +41,8 @@
+ #define ASPEED_CLK_24M 35
+ #define ASPEED_CLK_MAC1RCLK 36
+ #define ASPEED_CLK_MAC2RCLK 37
++#define ASPEED_CLK_UART_HS 38
++#define ASPEED_CLK_MAX 39
+
+ #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..2ba9e5002
--- /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,559 @@
+From 09aa5d5af94823f100fb515d45b0a04fc8d7ee4f 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>
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ .../ABI/stable/sysfs-driver-aspeed-uart-routing | 14 +
+ Documentation/misc-devices/aspeed-uart-routing.txt | 49 +++
+ arch/arm/boot/dts/aspeed-g5.dtsi | 6 +
+ arch/arm/boot/dts/aspeed-g6.dtsi | 6 +
+ drivers/misc/Kconfig | 6 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/aspeed-uart-routing.c | 383 +++++++++++++++++++++
+ 7 files changed, 465 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..cf1c2a466875
+--- /dev/null
++++ b/Documentation/misc-devices/aspeed-uart-routing.txt
+@@ -0,0 +1,49 @@
++Kernel driver aspeed-uart-routing
++=================================
++
++Supported chips:
++ASPEED AST2500/AST2600
++
++Author:
++Google LLC
++
++Description
++-----------
++
++The Aspeed AST2500/AST2600 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-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index bd2037e52a94..797013debaa7 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -523,6 +523,12 @@
+ status = "disabled";
+ };
+ };
++
++ uart_routing: uart_routing@9c {
++ compatible = "aspeed,ast2500-uart-routing";
++ reg = <0x9c 0x4>;
++ status = "disabled";
++ };
+ };
+
+ peci: bus@1e78b000 {
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index e4c1ab3d274e..8cc978058f16 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -291,6 +291,12 @@
+ compatible = "aspeed,ast2600-pinctrl";
+ };
+
++ uart_routing: uart_routing@9c {
++ compatible = "aspeed,ast2500-uart-routing";
++ reg = <0x9c 0x4>;
++ status = "disabled";
++ };
++
+ smp-memram@180 {
+ compatible = "aspeed,ast2600-smpmem";
+ reg = <0x180 0x40>;
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 0f9b5a356c93..8af817694648 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -441,6 +441,12 @@ config ASPEED_ESPI_SLAVE
+ Control Aspeed ast2500 eSPI slave controller to handle event
+ which needs the firmware's processing.
+
++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.
++
+ config PCI_ENDPOINT_TEST
+ depends on PCI
+ select CRC32
+diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
+index 53864687e8fd..a4372208f4de 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -52,6 +52,7 @@ 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_UART_ROUTING) += aspeed-uart-routing.o
+ obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
+ obj-$(CONFIG_OCXL) += ocxl/
+ obj-y += cardreader/
+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-aspeed-Swap-the-mac-nodes-numbering.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-aspeed-Swap-the-mac-nodes-numbering.patch
new file mode 100644
index 000000000..2f0fd3a31
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0034-arm-dts-aspeed-Swap-the-mac-nodes-numbering.patch
@@ -0,0 +1,85 @@
+From 65c8090f2b418892aee9f239729fa417bd508a00 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: aspeed: 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 a70bee24d058..054d97229626 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -120,14 +120,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>;
+@@ -136,6 +128,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 797013debaa7..27ed188296a1 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -148,14 +148,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>;
+@@ -164,6 +156,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..741b44462
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0035-Implement-a-memory-driver-share-memory.patch
@@ -0,0 +1,245 @@
+From 9be0e8ccde0e096cc494aad6f15e7d7d3de3e46f Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <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: Cheng C Yang <cheng.c.yang@intel.com>
+---
+ .../bindings/soc/aspeed/aspeed-vga-sharedmem.txt | 20 +++
+ drivers/soc/aspeed/Kconfig | 9 ++
+ drivers/soc/aspeed/Makefile | 1 +
+ drivers/soc/aspeed/aspeed-vga-sharedmem.c | 163 +++++++++++++++++++++
+ 4 files changed, 193 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/soc/aspeed/aspeed-vga-sharedmem.txt
+ create mode 100644 drivers/soc/aspeed/aspeed-vga-sharedmem.c
+
+diff --git a/Documentation/devicetree/bindings/soc/aspeed/aspeed-vga-sharedmem.txt b/Documentation/devicetree/bindings/soc/aspeed/aspeed-vga-sharedmem.txt
+new file mode 100644
+index 000000000000..03f57c53e844
+--- /dev/null
++++ b/Documentation/devicetree/bindings/soc/aspeed/aspeed-vga-sharedmem.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/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig
+index cb85917b8c6f..13cd9fbabbf1 100644
+--- a/drivers/soc/aspeed/Kconfig
++++ b/drivers/soc/aspeed/Kconfig
+@@ -59,4 +59,13 @@ config ASPEED_XDMA
+ SOCs. The XDMA engine can perform automatic PCI DMA operations
+ between the AST2XXX (acting as a BMC) and a host processor.
+
++config ASPEED_VGA_SHAREDMEM
++ tristate "Aspeed VGA Shared memory"
++ depends on SOC_ASPEED
++ 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.
++
+ endmenu
+diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
+index 56c5de5eeabe..875f0d9e7866 100644
+--- a/drivers/soc/aspeed/Makefile
++++ b/drivers/soc/aspeed/Makefile
+@@ -6,3 +6,4 @@ obj-$(CONFIG_ASPEED_LPC_SIO) += aspeed-lpc-sio.o
+ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
+ obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
+ obj-$(CONFIG_ASPEED_XDMA) += aspeed-xdma.o
++obj-$(CONFIG_ASPEED_VGA_SHAREDMEM) += aspeed-vga-sharedmem.o
+diff --git a/drivers/soc/aspeed/aspeed-vga-sharedmem.c b/drivers/soc/aspeed/aspeed-vga-sharedmem.c
+new file mode 100644
+index 000000000000..cd1f5431378c
+--- /dev/null
++++ b/drivers/soc/aspeed/aspeed-vga-sharedmem.c
+@@ -0,0 +1,163 @@
++// 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)
++{
++ struct aspeed_vga_sharedmem *vga_sharedmem = file_sharemem(file);
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
++ 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;
++ 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.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..0fdd40d77
--- /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,514 @@
+From b20b1ce81f4451d9e906b84e7edcc22d4e70e7df 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/pwm/Kconfig | 9 +
+ drivers/pwm/Makefile | 1 +
+ drivers/pwm/pwm-fttmr010.c | 441 +++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 452 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/pwm/pwm-fttmr010.c
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index 27ed188296a1..45202bc3d60c 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -341,7 +341,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/pwm/Kconfig b/drivers/pwm/Kconfig
+index e3a2518503ed..21def8cd5af6 100644
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -171,6 +171,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 26326adf71d7..3a9e9840b5ae 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_IMX1) += pwm-imx1.o
+diff --git a/drivers/pwm/pwm-fttmr010.c b/drivers/pwm/pwm-fttmr010.c
+new file mode 100644
+index 000000000000..283ded6906f1
+--- /dev/null
++++ b/drivers/pwm/pwm-fttmr010.c
+@@ -0,0 +1,441 @@
++// 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>
++
++#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;
++};
++
++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);
++ u32 cr;
++
++ 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;
++ default:
++ return -ERANGE;
++ }
++
++ writel(cr, priv->base + TIMER_CR);
++ 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);
++ u32 cr;
++
++ 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;
++ default:
++ return;
++ }
++
++ writel(cr, priv->base + TIMER_CR);
++ 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;
++ default:
++ return -ERANGE;
++ }
++
++ 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 = priv->variant.chan_min; i < priv->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");
+--
+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..198beaa93
--- /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,488 @@
+From ee9cee93b96b791f52295d7763985fdb10903e2b 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 | 70 +++++++++++++++++++++++++--
+ drivers/i2c/i2c-core-smbus.c | 22 +++++++--
+ 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, 214 insertions(+), 16 deletions(-)
+
+diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
+index 5f6a4985f2bc..d1cd7afe4068 100644
+--- a/drivers/i2c/i2c-core-base.c
++++ b/drivers/i2c/i2c-core-base.c
+@@ -1297,6 +1297,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;
+@@ -1379,6 +1398,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:
+@@ -1599,6 +1621,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));
+@@ -1948,7 +1972,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 = I2C_HOLD_MSG_NONE;
+ unsigned long orig_jiffies;
++ unsigned long timeout;
+ int ret, try;
+
+ if (WARN_ON(!msgs || num < 1))
+@@ -1961,6 +1987,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
+@@ -1997,6 +2042,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);
+@@ -2015,6 +2063,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;
+
+ if (!adap->algo->master_xfer) {
+@@ -2038,12 +2087,25 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+ * one (discarding status on the second message) or errno
+ * (discarding status on the first one).
+ */
+- ret = __i2c_lock_bus_helper(adap);
+- if (ret)
+- return ret;
++ /*
++ * 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) {
++ ret = __i2c_lock_bus_helper(adap);
++ if (ret)
++ return ret;
++ }
+
+ 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;
+ }
+diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c
+index 3ac426a8ab5a..f7bf95101e34 100644
+--- a/drivers/i2c/i2c-core-smbus.c
++++ b/drivers/i2c/i2c-core-smbus.c
+@@ -526,15 +526,29 @@ 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;
+
+- res = __i2c_lock_bus_helper(adapter);
+- if (res)
+- return res;
++ /*
++ * 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) {
++ res = __i2c_lock_bus_helper(adapter);
++ if (res)
++ return res;
++ }
+
+ 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 774507b54b57..c6e433238b22 100644
+--- a/drivers/i2c/i2c-mux.c
++++ b/drivers/i2c/i2c-mux.c
+@@ -27,6 +27,7 @@
+ #include <linux/of.h>
+ #include <linux/slab.h>
+ #include <linux/sysfs.h>
++#include <linux/timer.h>
+
+ /* multiplexer per channel data */
+ struct i2c_mux_priv {
+@@ -36,21 +37,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;
+ }
+@@ -61,15 +98,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;
+ }
+@@ -82,16 +136,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;
+ }
+@@ -104,16 +175,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);
+@@ -441,6 +532,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 c5a977320f82..47f8763d6ed2 100644
+--- a/include/linux/i2c-mux.h
++++ b/include/linux/i2c-mux.h
+@@ -27,6 +27,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 1361637c369d..b4055d133338 100644
+--- a/include/linux/i2c.h
++++ b/include/linux/i2c.h
+@@ -711,6 +711,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)
+
+@@ -1005,4 +1012,22 @@ static inline struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle ha
+ }
+ #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/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch
new file mode 100644
index 000000000..5b9d4ef8b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch
@@ -0,0 +1,105 @@
+From 37e7896bf297edef4f2877998ca7a5c086015591 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 7 Mar 2019 15:17:40 -0800
+Subject: [PATCH] Add bus-timeout-ms and #retries device tree properties
+
+BMC uses I2C bus 7 as a PMBus channel to communicate with PSUs,
+also ME uses this bus as SMLink to control PSUs so this bus is
+managed by multi-masters. In this use case, some arbitration errors
+are expected so we need to add retry logic. And PMBus subsystem
+uses I2C bus in kernel internally so retry logic should be
+supported in kernel level.
+
+To support the use case, this commit adds 'bus-timeout-ms' and
+'#retries' device tree properties to set the bus specific
+parameters at kernel boot time without using any additional ioctls
+from user space.
+
+This patch would not be accepted by I2C maintainer in linux
+upstream because he doesn't like adding these legacy properties
+into device tree, so keep it only in downstream.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ Documentation/devicetree/bindings/i2c/i2c-aspeed.txt | 3 +++
+ Documentation/devicetree/bindings/i2c/i2c.txt | 6 ++++++
+ drivers/i2c/busses/i2c-aspeed.c | 1 -
+ drivers/i2c/i2c-core-base.c | 12 ++++++++++--
+ 4 files changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+index 8fbd8633a387..7da7e813b2b0 100644
+--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+@@ -16,6 +16,9 @@ Optional Properties:
+ - bus-frequency : frequency of the bus clock in Hz defaults to 100 kHz when not
+ specified
+ - multi-master : states that there is another master active on this bus.
++- bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not
++ specified.
++- #retries : Number of retries for master transfer.
+
+ Example:
+
+diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
+index 44efafdfd7f5..e382931cf3d6 100644
+--- a/Documentation/devicetree/bindings/i2c/i2c.txt
++++ b/Documentation/devicetree/bindings/i2c/i2c.txt
+@@ -80,6 +80,12 @@ wants to support one of the below features, it should adapt the bindings below.
+ Names of map programmable addresses.
+ It can contain any map needing another address than default one.
+
++- bus-timeout-ms
++ Bus timeout in milliseconds.
++
++- #retries
++ Number of retries for master transfer.
++
+ Binding may contain optional "interrupts" property, describing interrupts
+ used by the device. I2C core will assign "irq" interrupt (or the very first
+ interrupt if not using interrupt names) as primary interrupt for the slave.
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index c113ffa8d5df..7becfcd67142 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -1032,7 +1032,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+ spin_lock_init(&bus->lock);
+ init_completion(&bus->cmd_complete);
+ bus->adap.owner = THIS_MODULE;
+- bus->adap.retries = 0;
+ bus->adap.algo = &aspeed_i2c_algo;
+ bus->adap.dev.parent = &pdev->dev;
+ bus->adap.dev.of_node = pdev->dev.of_node;
+diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
+index d1cd7afe4068..1db991220fae 100644
+--- a/drivers/i2c/i2c-core-base.c
++++ b/drivers/i2c/i2c-core-base.c
+@@ -1318,6 +1318,7 @@ static void i2c_adapter_hold_timer_callback(struct timer_list *t)
+
+ static int i2c_register_adapter(struct i2c_adapter *adap)
+ {
++ u32 bus_timeout_ms = 0;
+ int res = -EINVAL;
+
+ /* Can't register until after driver model init */
+@@ -1345,8 +1346,15 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
+ INIT_LIST_HEAD(&adap->userspace_clients);
+
+ /* Set default timeout to 1 second if not already set */
+- if (adap->timeout == 0)
+- adap->timeout = HZ;
++ if (adap->timeout == 0) {
++ device_property_read_u32(&adap->dev, "bus-timeout-ms",
++ &bus_timeout_ms);
++ adap->timeout = bus_timeout_ms ?
++ msecs_to_jiffies(bus_timeout_ms) : HZ;
++ }
++
++ /* Set retries count if it has the property setting */
++ device_property_read_u32(&adap->dev, "#retries", &adap->retries);
+
+ /* register soft irqs for Host Notify */
+ res = i2c_setup_host_notify_irq_domain(adap);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch
new file mode 100644
index 000000000..6cc7d1138
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch
@@ -0,0 +1,154 @@
+From 301c1aaba9e59eb593406d878451e3ea4fe355bb Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 13 Mar 2019 15:04:16 -0700
+Subject: [PATCH] char: ipmi: Add clock control logic into Aspeed LPC BT driver
+
+If LPC BT driver is registered ahead of lpc-ctrl module, LPC BT
+block will be enabled without heart beating of LCLK until lpc-ctrl
+enables the LCLK. This issue causes improper handling on host
+interrupts when the host sends interrupt in that time frame. Then
+kernel eventually forcibly disables the interrupt with dumping
+stack and printing a 'nobody cared this irq' message out.
+
+To prevent this issue, all LPC sub-nodes should enable LCLK
+individually so this patch adds clock control logic into the LPC
+BT driver.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ .../bindings/ipmi/aspeed,ast2400-ibt-bmc.txt | 3 +++
+ arch/arm/boot/dts/aspeed-g4.dtsi | 1 +
+ arch/arm/boot/dts/aspeed-g5.dtsi | 1 +
+ arch/arm/boot/dts/aspeed-g6.dtsi | 1 +
+ drivers/char/ipmi/bt-bmc.c | 24 +++++++++++++++++++++-
+ 5 files changed, 29 insertions(+), 1 deletion(-)
+
+diff --git a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt
+index 028268fd99ee..d13887d60f19 100644
+--- a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt
++++ b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt
+@@ -10,6 +10,8 @@ Required properties:
+ "aspeed,ast2400-ibt-bmc"
+ "aspeed,ast2500-ibt-bmc"
+ - reg: physical address and size of the registers
++- clocks: contains a phandle to the syscon node describing the clocks.
++ There should then be one cell representing the clock to use.
+
+ Optional properties:
+
+@@ -22,4 +24,5 @@ Example:
+ compatible = "aspeed,ast2400-ibt-bmc";
+ reg = <0x1e789140 0x18>;
+ interrupts = <8>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ };
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index 054d97229626..db962ab435af 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -386,6 +386,7 @@
+ ibt: ibt@c0 {
+ compatible = "aspeed,ast2400-ibt-bmc";
+ reg = <0xc0 0x18>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ interrupts = <8>;
+ status = "disabled";
+ };
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index 45202bc3d60c..c4724ec27041 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -499,6 +499,7 @@
+ ibt: ibt@c0 {
+ compatible = "aspeed,ast2500-ibt-bmc";
+ reg = <0xc0 0x18>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ interrupts = <8>;
+ status = "disabled";
+ };
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index 8cc978058f16..a557a7e6fe8d 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -524,6 +524,7 @@
+ ibt: ibt@c0 {
+ compatible = "aspeed,ast2600-ibt-bmc";
+ reg = <0xc0 0x18>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
+index 0e600449931b..87bf3ff28542 100644
+--- a/drivers/char/ipmi/bt-bmc.c
++++ b/drivers/char/ipmi/bt-bmc.c
+@@ -5,6 +5,7 @@
+
+ #include <linux/atomic.h>
+ #include <linux/bt-bmc.h>
++#include <linux/clk.h>
+ #include <linux/errno.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+@@ -60,6 +61,7 @@ struct bt_bmc {
+ struct device dev;
+ struct miscdevice miscdev;
+ struct regmap *map;
++ struct clk *clk;
+ int offset;
+ int irq;
+ wait_queue_head_t queue;
+@@ -467,6 +469,19 @@ static int bt_bmc_probe(struct platform_device *pdev)
+ mutex_init(&bt_bmc->mutex);
+ init_waitqueue_head(&bt_bmc->queue);
+
++ bt_bmc->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(bt_bmc->clk)) {
++ rc = PTR_ERR(bt_bmc->clk);
++ if (rc != -EPROBE_DEFER)
++ dev_err(dev, "couldn't get clock\n");
++ return rc;
++ }
++ rc = clk_prepare_enable(bt_bmc->clk);
++ if (rc) {
++ dev_err(dev, "couldn't enable clock\n");
++ return rc;
++ }
++
+ bt_bmc->miscdev.minor = MISC_DYNAMIC_MINOR,
+ bt_bmc->miscdev.name = DEVICE_NAME,
+ bt_bmc->miscdev.fops = &bt_bmc_fops,
+@@ -474,7 +489,7 @@ static int bt_bmc_probe(struct platform_device *pdev)
+ rc = misc_register(&bt_bmc->miscdev);
+ if (rc) {
+ dev_err(dev, "Unable to register misc device\n");
+- return rc;
++ goto err;
+ }
+
+ bt_bmc_config_irq(bt_bmc, pdev);
+@@ -498,6 +513,11 @@ static int bt_bmc_probe(struct platform_device *pdev)
+ clr_b_busy(bt_bmc);
+
+ return 0;
++
++err:
++ clk_disable_unprepare(bt_bmc->clk);
++
++ return rc;
+ }
+
+ static int bt_bmc_remove(struct platform_device *pdev)
+@@ -507,6 +527,8 @@ static int bt_bmc_remove(struct platform_device *pdev)
+ misc_deregister(&bt_bmc->miscdev);
+ if (!bt_bmc->irq)
+ del_timer_sync(&bt_bmc->poll_timer);
++ clk_disable_unprepare(bt_bmc->clk);
++
+ return 0;
+ }
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch
new file mode 100644
index 000000000..b3ace73f6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch
@@ -0,0 +1,139 @@
+From 404f73827714e324a21250b1a855fdc10fcfaf51 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 13 Mar 2019 15:27:48 -0700
+Subject: [PATCH] misc: Add clock control logic into Aspeed LPC SNOOP driver
+
+If LPC SNOOP driver is registered ahead of lpc-ctrl module, LPC
+SNOOP block will be enabled without heart beating of LCLK until
+lpc-ctrl enables the LCLK. This issue causes improper handling on
+host interrupts when the host sends interrupt in that time frame.
+Then kernel eventually forcibly disables the interrupt with
+dumping stack and printing a 'nobody cared this irq' message out.
+
+To prevent this issue, all LPC sub-nodes should enable LCLK
+individually so this patch adds clock control logic into the LPC
+SNOOP driver.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ arch/arm/boot/dts/aspeed-g4.dtsi | 1 +
+ arch/arm/boot/dts/aspeed-g5.dtsi | 1 +
+ arch/arm/boot/dts/aspeed-g6.dtsi | 1 +
+ drivers/soc/aspeed/aspeed-lpc-snoop.c | 30 +++++++++++++++++++++++++++---
+ 4 files changed, 30 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index db962ab435af..24a20384b5e8 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -369,6 +369,7 @@
+ compatible = "aspeed,ast2400-lpc-snoop";
+ reg = <0x0 0x80>;
+ interrupts = <8>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index c4724ec27041..18d2a465c0ed 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -482,6 +482,7 @@
+ compatible = "aspeed,ast2500-lpc-snoop";
+ reg = <0x0 0x80>;
+ interrupts = <8>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index a557a7e6fe8d..4035d7bd647e 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -507,6 +507,7 @@
+ compatible = "aspeed,ast2600-lpc-snoop";
+ reg = <0x0 0x80>;
+ interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+
+diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c
+index c7b4ac066b40..ed272677fc82 100644
+--- a/drivers/soc/aspeed/aspeed-lpc-snoop.c
++++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c
+@@ -11,6 +11,7 @@
+ */
+
+ #include <linux/bitops.h>
++#include <linux/clk.h>
+ #include <linux/interrupt.h>
+ #include <linux/fs.h>
+ #include <linux/kfifo.h>
+@@ -67,6 +68,7 @@ struct aspeed_lpc_snoop_channel {
+ struct aspeed_lpc_snoop {
+ struct regmap *regmap;
+ int irq;
++ struct clk *clk;
+ struct aspeed_lpc_snoop_channel chan[NUM_SNOOP_CHANNELS];
+ };
+
+@@ -282,22 +284,42 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev)
+ return -ENODEV;
+ }
+
++ lpc_snoop->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(lpc_snoop->clk)) {
++ rc = PTR_ERR(lpc_snoop->clk);
++ if (rc != -EPROBE_DEFER)
++ dev_err(dev, "couldn't get clock\n");
++ return rc;
++ }
++ rc = clk_prepare_enable(lpc_snoop->clk);
++ if (rc) {
++ dev_err(dev, "couldn't enable clock\n");
++ return rc;
++ }
++
+ rc = aspeed_lpc_snoop_config_irq(lpc_snoop, pdev);
+ if (rc)
+- return rc;
++ goto err;
+
+ rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 0, port);
+ if (rc)
+- return rc;
++ goto err;
+
+ /* Configuration of 2nd snoop channel port is optional */
+ if (of_property_read_u32_index(dev->of_node, "snoop-ports",
+ 1, &port) == 0) {
+ rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 1, port);
+- if (rc)
++ if (rc) {
+ aspeed_lpc_disable_snoop(lpc_snoop, 0);
++ goto err;
++ }
+ }
+
++ return 0;
++
++err:
++ clk_disable_unprepare(lpc_snoop->clk);
++
+ return rc;
+ }
+
+@@ -309,6 +331,8 @@ static int aspeed_lpc_snoop_remove(struct platform_device *pdev)
+ aspeed_lpc_disable_snoop(lpc_snoop, 0);
+ aspeed_lpc_disable_snoop(lpc_snoop, 1);
+
++ clk_disable_unprepare(lpc_snoop->clk);
++
+ return 0;
+ }
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch
new file mode 100644
index 000000000..1c0903d71
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch
@@ -0,0 +1,273 @@
+From cd62ca008a771bd6b7aeb06526c37d8435f86648 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 13 Mar 2019 15:36:34 -0700
+Subject: [PATCH] char: ipmi: Add clock control logic into Aspeed LPC KCS
+ driver
+
+If LPC KCS driver is registered ahead of lpc-ctrl module, LPC KCS
+block will be enabled without heart beating of LCLK until lpc-ctrl
+enables the LCLK. This issue causes improper handling on host
+interrupts when the host sends interrupt in that time frame. Then
+kernel eventually forcibly disables the interrupt with dumping
+stack and printing a 'nobody cared this irq' message out.
+
+To prevent this issue, all LPC sub-nodes should enable LCLK
+individually so this patch adds clock control logic into the LPC
+KCS driver.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ .../devicetree/bindings/ipmi/aspeed-kcs-bmc.txt | 3 ++
+ arch/arm/boot/dts/aspeed-g4.dtsi | 35 ++++++++++++++++++++
+ arch/arm/boot/dts/aspeed-g5.dtsi | 6 +++-
+ arch/arm/boot/dts/aspeed-g6.dtsi | 6 ++++
+ drivers/char/ipmi/kcs_bmc_aspeed.c | 37 ++++++++++++++++++----
+ 5 files changed, 79 insertions(+), 8 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
+index d98a9bf45d6c..3453eb0bf8f2 100644
+--- a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
++++ b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
+@@ -9,6 +9,8 @@ Required properties:
+ "aspeed,ast2400-kcs-bmc"
+ "aspeed,ast2500-kcs-bmc"
+ - interrupts : interrupt generated by the controller
++- clocks: contains a phandle to the syscon node describing the clocks.
++ There should then be one cell representing the clock to use.
+ - kcs_chan : The LPC channel number in the controller
+ - kcs_addr : The host CPU IO map address
+
+@@ -19,6 +21,7 @@ Example:
+ compatible = "aspeed,ast2500-kcs-bmc";
+ reg = <0x0 0x80>;
+ interrupts = <8>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ kcs_chan = <3>;
+ kcs_addr = <0xCA2>;
+ status = "okay";
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index 24a20384b5e8..fc6f4e009db7 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -347,6 +347,33 @@
+ lpc_bmc: lpc-bmc@0 {
+ compatible = "aspeed,ast2400-lpc-bmc";
+ reg = <0x0 0x80>;
++ reg-io-width = <4>;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges = <0x0 0x0 0x80>;
++
++ kcs1: kcs1@0 {
++ compatible = "aspeed,ast2400-kcs-bmc";
++ interrupts = <8>;
++ kcs_chan = <1>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
++ kcs2: kcs2@0 {
++ compatible = "aspeed,ast2400-kcs-bmc";
++ interrupts = <8>;
++ kcs_chan = <2>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
++ kcs3: kcs3@0 {
++ compatible = "aspeed,ast2400-kcs-bmc";
++ interrupts = <8>;
++ kcs_chan = <3>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
+ };
+
+ lpc_host: lpc-host@80 {
+@@ -358,6 +385,14 @@
+ #size-cells = <1>;
+ ranges = <0x0 0x80 0x1e0>;
+
++ kcs4: kcs4@0 {
++ compatible = "aspeed,ast2400-kcs-bmc";
++ interrupts = <8>;
++ kcs_chan = <4>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
++ status = "disabled";
++ };
++
+ lpc_ctrl: lpc-ctrl@0 {
+ compatible = "aspeed,ast2400-lpc-ctrl";
+ reg = <0x0 0x80>;
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index 18d2a465c0ed..751a8f0316d6 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -134,7 +134,7 @@
+ };
+
+ vic: interrupt-controller@1e6c0080 {
+- compatible = "aspeed,ast2400-vic";
++ compatible = "aspeed,ast2500-vic";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ valid-sources = <0xfefff7ff 0x0807ffff>;
+@@ -439,18 +439,21 @@
+ compatible = "aspeed,ast2500-kcs-bmc";
+ interrupts = <8>;
+ kcs_chan = <1>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+ kcs2: kcs2@0 {
+ compatible = "aspeed,ast2500-kcs-bmc";
+ interrupts = <8>;
+ kcs_chan = <2>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+ kcs3: kcs3@0 {
+ compatible = "aspeed,ast2500-kcs-bmc";
+ interrupts = <8>;
+ kcs_chan = <3>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+ };
+@@ -468,6 +471,7 @@
+ compatible = "aspeed,ast2500-kcs-bmc";
+ interrupts = <8>;
+ kcs_chan = <4>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index 4035d7bd647e..0e35c4598df5 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -463,18 +463,23 @@
+ kcs1: kcs1@0 {
+ compatible = "aspeed,ast2600-kcs-bmc";
+ interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ kcs_chan = <1>;
+ status = "disabled";
+ };
++
+ kcs2: kcs2@0 {
+ compatible = "aspeed,ast2600-kcs-bmc";
+ interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ kcs_chan = <2>;
+ status = "disabled";
+ };
++
+ kcs3: kcs3@0 {
+ compatible = "aspeed,ast2600-kcs-bmc";
+ interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ kcs_chan = <3>;
+ status = "disabled";
+ };
+@@ -492,6 +497,7 @@
+ kcs4: kcs4@0 {
+ compatible = "aspeed,ast2600-kcs-bmc";
+ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ kcs_chan = <4>;
+ status = "disabled";
+ };
+diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c
+index a0a8bb89c9b3..94cfb879f520 100644
+--- a/drivers/char/ipmi/kcs_bmc_aspeed.c
++++ b/drivers/char/ipmi/kcs_bmc_aspeed.c
+@@ -1,11 +1,10 @@
+ // SPDX-License-Identifier: GPL-2.0
+-/*
+- * Copyright (c) 2015-2018, Intel Corporation.
+- */
++// Copyright (c) 2015-2019, Intel Corporation.
+
+ #define pr_fmt(fmt) "aspeed-kcs-bmc: " fmt
+
+ #include <linux/atomic.h>
++#include <linux/clk.h>
+ #include <linux/errno.h>
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+@@ -63,6 +62,7 @@
+
+ struct aspeed_kcs_bmc {
+ struct regmap *map;
++ struct clk *clk;
+ };
+
+
+@@ -264,36 +264,59 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
+ return -ENODEV;
+ }
+
++ priv->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(priv->clk)) {
++ rc = PTR_ERR(priv->clk);
++ if (rc != -EPROBE_DEFER)
++ dev_err(dev, "couldn't get clock\n");
++ return rc;
++ }
++ rc = clk_prepare_enable(priv->clk);
++ if (rc) {
++ dev_err(dev, "couldn't enable clock\n");
++ return rc;
++ }
++
+ kcs_bmc->ioreg = ast_kcs_bmc_ioregs[chan - 1];
+ kcs_bmc->io_inputb = aspeed_kcs_inb;
+ kcs_bmc->io_outputb = aspeed_kcs_outb;
+
+ dev_set_drvdata(dev, kcs_bmc);
+
+- aspeed_kcs_set_address(kcs_bmc, addr);
+- aspeed_kcs_enable_channel(kcs_bmc, true);
+ rc = aspeed_kcs_config_irq(kcs_bmc, pdev);
+ if (rc)
+- return rc;
++ goto err;
+
+ rc = misc_register(&kcs_bmc->miscdev);
+ if (rc) {
+ dev_err(dev, "Unable to register device\n");
+- return rc;
++ goto err;
+ }
+
++ aspeed_kcs_set_address(kcs_bmc, addr);
++ aspeed_kcs_enable_channel(kcs_bmc, true);
++
+ pr_info("channel=%u addr=0x%x idr=0x%x odr=0x%x str=0x%x\n",
+ chan, addr,
+ kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str);
+
+ return 0;
++
++err:
++ aspeed_kcs_enable_channel(kcs_bmc, false);
++ clk_disable_unprepare(priv->clk);
++
++ return rc;
+ }
+
+ static int aspeed_kcs_remove(struct platform_device *pdev)
+ {
+ struct kcs_bmc *kcs_bmc = dev_get_drvdata(&pdev->dev);
++ struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
+
+ misc_deregister(&kcs_bmc->miscdev);
++ aspeed_kcs_enable_channel(kcs_bmc, false);
++ clk_disable_unprepare(priv->clk);
+
+ return 0;
+ }
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch
new file mode 100644
index 000000000..8e9c793ba
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch
@@ -0,0 +1,43 @@
+From 5473931df3348b7284c16fac3e7d336c9d0c4294 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 13 Mar 2019 15:57:08 -0700
+Subject: [PATCH] misc: Block error printing on probe defer case in Aspeed LPC
+ ctrl
+
+This commit adds a checking code when it gets -EPROBE_DEFER while
+getting a clock resource. In this case it doesn't need to print
+out an error message because the probing will be re-visited.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/soc/aspeed/aspeed-lpc-ctrl.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c
+index f4ac14c40518..432128b8db87 100644
+--- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c
++++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c
+@@ -265,8 +265,10 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
+
+ lpc_ctrl->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(lpc_ctrl->clk)) {
+- dev_err(dev, "couldn't get clock\n");
+- return PTR_ERR(lpc_ctrl->clk);
++ rc = PTR_ERR(lpc_ctrl->clk);
++ if (rc != -EPROBE_DEFER)
++ dev_err(dev, "couldn't get clock\n");
++ return rc;
+ }
+ rc = clk_prepare_enable(lpc_ctrl->clk);
+ if (rc) {
+@@ -288,6 +290,7 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
+
+ err:
+ clk_disable_unprepare(lpc_ctrl->clk);
++
+ return rc;
+ }
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0049-Suppress-excessive-HID-gadget-error-logs.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0049-Suppress-excessive-HID-gadget-error-logs.patch
new file mode 100644
index 000000000..4a87f2d76
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0049-Suppress-excessive-HID-gadget-error-logs.patch
@@ -0,0 +1,52 @@
+From 5b9ec5081492b461710cb82e7ecc93fd3af8ad34 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Mon, 18 Mar 2019 14:06:36 -0700
+Subject: [PATCH] Suppress excessive HID gadget error logs
+
+HID events can be sent even when the host disconnects the HID
+device according to the current graphic mode. For an example, if
+KVM mouse events are sent when the host is in text mode, queueing
+of end point messages will be dropped with this message:
+
+configfs-gadget gadget: usb_ep_queue error on int endpoint -108
+
+This case is very usual case in BMC since BMC can control power
+status of the host, so this commit suppress the error printing outs
+with making HID gadget driver drop events quietly in the case.
+
+This should be a downstream only customization. Do not upstream it.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/usb/gadget/function/f_hid.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
+index f3816a5c861e..c96c0f6f1df0 100644
+--- a/drivers/usb/gadget/function/f_hid.c
++++ b/drivers/usb/gadget/function/f_hid.c
+@@ -320,7 +320,7 @@ static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req)
+ struct f_hidg *hidg = (struct f_hidg *)ep->driver_data;
+ unsigned long flags;
+
+- if (req->status != 0) {
++ if (req->status != 0 && req->status != -ESHUTDOWN) {
+ ERROR(hidg->func.config->cdev,
+ "End Point Request ERROR: %d\n", req->status);
+ }
+@@ -395,8 +395,10 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
+
+ status = usb_ep_queue(hidg->in_ep, req, GFP_ATOMIC);
+ if (status < 0) {
+- ERROR(hidg->func.config->cdev,
+- "usb_ep_queue error on int endpoint %zd\n", status);
++ if (status != -ESHUTDOWN)
++ ERROR(hidg->func.config->cdev,
++ "usb_ep_queue error on int endpoint %zd\n",
++ status);
+ goto release_write_pending;
+ } else {
+ status = count;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch
new file mode 100644
index 000000000..db94b13fd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0051-Add-AST2500-JTAG-device.patch
@@ -0,0 +1,67 @@
+From 79d407327558f27a7df9d04b1d66cbe63129b622 Mon Sep 17 00:00:00 2001
+From: "Hunt, Bryan" <bryan.hunt@intel.com>
+Date: Mon, 6 May 2019 10:02:14 -0700
+Subject: [PATCH] Add AST2500 JTAG device
+
+Adding aspeed jtag device
+
+Signed-off-by: Hunt, Bryan <bryan.hunt@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g5.dtsi | 9 +++++++++
+ arch/arm/boot/dts/aspeed-g6.dtsi | 20 ++++++++++++++++++++
+ 2 files changed, 29 insertions(+)
+
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index f5c25dab5337..5999cd5e0f2e 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -438,6 +438,15 @@
+ pinctrl-0 = <&pinctrl_espi_default>;
+ };
+
++ jtag: jtag@1e6e4000 {
++ compatible = "aspeed,ast2500-jtag";
++ reg = <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/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index 09f50afea11b..4d8b561fe582 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -367,6 +367,26 @@
+ status = "disabled";
+ };
+
++ jtag0: jtag@1e6e4000 {
++ compatible = "aspeed,ast2600-jtag";
++ reg = <0x1e6e4000 0x40>;
++ clocks = <&syscon ASPEED_CLK_APB1>;
++ resets = <&syscon ASPEED_RESET_JTAG_MASTER>;
++ interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++ };
++
++ jtag1: jtag@1e6e4100 {
++ compatible = "aspeed,ast2600-jtag";
++ reg = <0x1e6e4100 0x40>;
++ clocks = <&syscon ASPEED_CLK_APB1>;
++ resets = <&syscon ASPEED_RESET_JTAG_MASTER2>;
++ interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_jtagm_default>;
++ status = "disabled";
++ };
++
+ adc: adc@1e6e9000 {
+ compatible = "aspeed,ast2500-adc";
+ reg = <0x1e6e9000 0x100>;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch
new file mode 100644
index 000000000..484c576b9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0052-drivers-jtag-Add-JTAG-core-driver.patch
@@ -0,0 +1,920 @@
+From ea6fa8fd6e36c776d560b4f69d1ede4a3bbe5f6b Mon Sep 17 00:00:00 2001
+From: "Corona, Ernesto" <ernesto.corona@intel.com>
+Date: Fri, 7 Jun 2019 07:37:39 -0800
+Subject: [PATCH v29 1/6] drivers: jtag: Add JTAG core driver
+
+JTAG class driver provide infrastructure to support hardware/software
+JTAG platform drivers. It provide user layer API interface for flashing
+and debugging external devices which equipped with JTAG interface
+using standard transactions.
+
+Driver exposes set of IOCTL to user space for:
+- XFER:
+ SIR (Scan Instruction Register, IEEE 1149.1 Data Register scan);
+ SDR (Scan Data Register, IEEE 1149.1 Instruction Register scan);
+- GIOCSTATUS read the current TAPC state of the JTAG controller
+- SIOCSTATE Forces the JTAG TAPC to go into a particular state.
+- SIOCFREQ/GIOCFREQ for setting and reading JTAG frequency.
+- IOCBITBANG for low level control of JTAG signals.
+
+Driver core provides set of internal APIs for allocation and
+registration:
+- jtag_register;
+- jtag_unregister;
+- jtag_alloc;
+- jtag_free;
+
+Platform driver on registration with jtag-core creates the next
+entry in dev folder:
+/dev/jtagX
+
+Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
+Signed-off-by: Jiri Pirko <jiri@mellanox.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+Acked-by: Philippe Ombredanne <pombredanne@nexb.com>
+Cc: Vadim Pasternak <vadimp@mellanox.com>
+Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
+Cc: Paul Burton <paul.burton@mips.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Boris Brezillon <bbrezillon@kernel.org>
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Cc: Johan Hovold <johan@kernel.org>
+Cc: Jens Axboe <axboe@kernel.dk>
+Cc: Joel Stanley <joel@jms.id.au>
+Cc: Palmer Dabbelt <palmer@sifive.com>
+Cc: Kees Cook <keescook@chromium.org>
+Cc: Steven A Filary <steven.a.filary@intel.com>
+Cc: Bryan Hunt <bryan.hunt@intel.com>
+---
+v28->v29
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Expand bitbang function to accept multiples bitbang operations within a
+ single JTAG_IOCBITBANG call. It will receive a buffer with TDI and TMS
+ values and it is expected that driver fills TDO fields with its
+ corresponding output value for every transaction.
+- Always setup JTAG controller to master mode but disable JTAG output when
+ the driver is not in use to allow other HW to own the JTAG bus. Remove SCU
+ register accesses. This register controls the JTAG controller mode
+ (master/slave).
+- Fix static analysis issues
+- Add support for multichain. Set tap state and xfer operations now include
+ two tap state arguments: current state and end state.
+
+v27->v28
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Replace JTAG_IOCRUNTEST with JTAG_SIOCSTATE adding support for all TAPC
+ end states in SW mode using a lookup table to navigate across states.
+- Add support for simultaneous READ/WRITE transfers(JTAG_READ_WRITE_XFER).
+- Support for switching JTAG controller mode between slave and master
+ mode.
+- Setup JTAG controller mode to master only when the driver is opened,
+ letting
+ other HW to own the JTAG bus when it isn't in use.
+- Include JTAG bit bang IOCTL for low level JTAG control usage
+ (JTAG_IOCBITBANG).
+
+v24->v25
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- set values to enums in jtag.h
+
+v23->v24
+Notifications from kbuild test robot <lkp@intel.com>
+- Add include types.h header to jtag.h
+- remove unecessary jtag_release
+
+v22->v23
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- remove restriction of allocated JTAG devs-
+- add validation fo idle values
+- remove unnecessary blank line
+- change retcode for xfer
+- remove unecessary jtag_release callback
+- remove unecessary defined fron jtag.h
+- align in one line define JTAG_IOCRUNTEST
+
+v21->v22
+Comments pointed by Andy Shevchenko <andy.shevchenko@gmail.com>
+- Fix 0x0f -> 0x0F in ioctl-number.txt
+- Add description to #define MAX_JTAG_NAME_LEN
+- Remove unnecessary entry *dev from struct jtag
+- Remove redundant parens
+- Described mandatory callbacks and removed unnecessary
+- Set JTAG_MAX_XFER_DATA_LEN to power of 2
+- rework driver alloc/register to devm_ variant
+- increasing line length up to 84 in order to improve readability.
+
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- fix spell in ABI doccumentation
+
+v20->v21
+ Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+ - Fix JTAG dirver help in Kconfig
+
+v19->v20
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- Fix JTAG dirver help in Kconfig
+
+Notifications from kbuild test robot <lkp@intel.com>
+- fix incompatible type casts
+
+v18->v19
+Comments pointed by Julia Cartwright <juliac@eso.teric.us>
+- Fix memory leak on jtag_alloc exit
+
+v17->v18
+Comments pointed by Julia Cartwright <juliac@eso.teric.us>
+- Change to return -EOPNOTSUPP in case of error in JTAG_GIOCFREQ
+- Add ops callbacks check to jtag_alloc
+- Add err check for copy_to_user
+- Move the kfree() above the if (err) in JTAG_IOCXFER
+- remove unnecessary check for error after put_user
+- add padding to struct jtag_xfer
+
+v16->v17
+Comments pointed by Julia Cartwright <juliac@eso.teric.us>
+- Fix memory allocation on jtag alloc
+- Move out unnecessary form lock on jtag open
+- Rework jtag register behavior
+
+v15->v16
+Comments pointed by Florian Fainelli <f.fainelli@gmail.com>
+- move check jtag->ops->* in ioctl before get_user()
+- change error type -EINVAL --> -EBUSY on open already opened jtag
+- remove unnecessary ARCH_DMA_MINALIGN flag from kzalloc
+- remove define ARCH_DMA_MINALIGN
+
+v14->v15
+v13->v14
+Comments pointed by Philippe Ombredanne <pombredanne@nexb.com>
+- Change style of head block comment from /**/ to //
+
+v12->v13
+Comments pointed by Philippe Ombredanne <pombredanne@nexb.com>
+- Change jtag.c licence type to
+ SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ and reorder line with license in description
+
+v11->v12
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- Change jtag.h licence type to
+ SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ and reorder line with license in description
+
+Comments pointed by Chip Bilbrey <chip@bilbrey.org>
+- Remove Apeed reference from uapi jtag.h header
+- Remove access mode from xfer and idle transactions
+- Add new ioctl JTAG_SIOCMODE for set hw mode
+- Add single open per device blocking
+
+v10->v11
+Notifications from kbuild test robot <lkp@intel.com>
+- Add include types.h header to jtag.h
+- fix incompatible type of xfer callback
+- remove rdundant class defination
+- Fix return order in case of xfer error
+
+V9->v10
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- remove unnecessary alignment for pirv data
+- move jtag_copy_to_user and jtag_copy_from_user code just to ioctl
+- move int jtag_run_test_idle_op and jtag_xfer_op code
+ just to ioctl
+- change return error codes to more applicable
+- add missing error checks
+- fix error check order in ioctl
+- remove unnecessary blank lines
+- add param validation to ioctl
+- remove compat_ioctl
+- remove only one open per JTAG port blocking.
+ User will care about this.
+- Fix idr memory leak on jtag_exit
+- change cdev device type to misc
+
+V8->v9
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- use get_user() instead of __get_user().
+- change jtag->open type from int to atomic_t
+- remove spinlock on jtg_open
+- remove mutex on jtag_register
+- add unregister_chrdev_region on jtag_init err
+- add unregister_chrdev_region on jtag_exit
+- remove unnecessary pointer casts
+- add *data parameter to xfer function prototype
+
+v7->v8
+Comments pointed by Moritz Fischer <moritz.fischer@ettus.com>
+- Fix misspelling s/friver/driver
+
+v6->v7
+Notifications from kbuild test robot <lkp@intel.com>
+- Remove include asm/types.h from jtag.h
+- Add include <linux/types.h> to jtag.c
+
+v5->v6
+v4->v5
+
+v3->v4
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- change transaction pointer tdio type to __u64
+- change internal status type from enum to __u32
+- reorder jtag_xfer members to avoid the implied padding
+- add __packed attribute to jtag_xfer and jtag_run_test_idle
+
+v2->v3
+Notifications from kbuild test robot <lkp@intel.com>
+- Change include path to <linux/types.h> in jtag.h
+
+v1->v2
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- Change license type from GPLv2/BSD to GPLv2
+- Change type of variables which crossed user/kernel to __type
+- Remove "default n" from Kconfig
+
+Comments pointed by Andrew Lunn <andrew@lunn.ch>
+- Change list_add_tail in jtag_unregister to list_del
+
+Comments pointed by Neil Armstrong <narmstrong@baylibre.com>
+- Add SPDX-License-Identifier instead of license text
+
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- Change __copy_to_user to memdup_user
+- Change __put_user to put_user
+- Change type of variables to __type for compatible 32 and 64-bit systems
+- Add check for maximum xfer data size
+- Change lookup data mechanism to get jtag data from inode
+- Add .compat_ioctl to file ops
+- Add mem alignment for jtag priv data
+
+Comments pointed by Tobias Klauser <tklauser@distanz.ch>
+- Change function names to avoid match with variable types
+- Fix description for jtag_ru_test_idle in uapi jtag.h
+- Fix misprints IDEL/IDLE, trough/through
+---
+ drivers/Kconfig | 1 +
+ drivers/Makefile | 1 +
+ drivers/jtag/Kconfig | 17 +++
+ drivers/jtag/Makefile | 1 +
+ drivers/jtag/jtag.c | 321 ++++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/jtag.h | 47 +++++++
+ include/uapi/linux/jtag.h | 214 +++++++++++++++++++++++++++++++
+ 7 files changed, 602 insertions(+)
+ create mode 100644 drivers/jtag/Kconfig
+ create mode 100644 drivers/jtag/Makefile
+ create mode 100644 drivers/jtag/jtag.c
+ create mode 100644 include/linux/jtag.h
+ create mode 100644 include/uapi/linux/jtag.h
+
+diff --git a/drivers/Kconfig b/drivers/Kconfig
+index 4322efa37732..e5e4fe21b5d9 100644
+--- a/drivers/Kconfig
++++ b/drivers/Kconfig
+@@ -230,4 +230,5 @@ source "drivers/counter/Kconfig"
+
+ source "drivers/peci/Kconfig"
+
++source "drivers/jtag/Kconfig"
+ endmenu
+diff --git a/drivers/Makefile b/drivers/Makefile
+index 82f78cfedf69..297047d4ed9b 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -187,3 +187,4 @@ obj-$(CONFIG_GNSS) += gnss/
+ obj-$(CONFIG_INTERCONNECT) += interconnect/
+ obj-$(CONFIG_COUNTER) += counter/
+ 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..47771fcd3c5b
+--- /dev/null
++++ b/drivers/jtag/Kconfig
+@@ -0,0 +1,17 @@
++menuconfig JTAG
++ tristate "JTAG support"
++ help
++ This provides basic core functionality support for JTAG class devices.
++ Hardware that is equipped with a JTAG microcontroller can be
++ supported by using this driver's interfaces.
++ This driver exposes a set of IOCTLs to the user space for
++ the following commands:
++ SDR: Performs an IEEE 1149.1 Data Register scan
++ SIR: Performs an IEEE 1149.1 Instruction Register scan.
++ RUNTEST: Forces the IEEE 1149.1 bus to a run state for a specified
++ number of clocks or a specified time period.
++
++ 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.
+diff --git a/drivers/jtag/Makefile b/drivers/jtag/Makefile
+new file mode 100644
+index 000000000000..af374939a9e6
+--- /dev/null
++++ b/drivers/jtag/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_JTAG) += jtag.o
+diff --git a/drivers/jtag/jtag.c b/drivers/jtag/jtag.c
+new file mode 100644
+index 000000000000..39a4d88a9c21
+--- /dev/null
++++ b/drivers/jtag/jtag.c
+@@ -0,0 +1,321 @@
++// SPDX-License-Identifier: GPL-2.0-only
++// Copyright (c) 2018 Mellanox Technologies. All rights reserved.
++// Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com>
++// Copyright (c) 2019 Intel Corporation
++
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/jtag.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/rtnetlink.h>
++#include <linux/spinlock.h>
++#include <linux/types.h>
++#include <uapi/linux/jtag.h>
++
++struct jtag {
++ struct miscdevice miscdev;
++ const struct jtag_ops *ops;
++ int id;
++ unsigned long priv[0];
++};
++
++static DEFINE_IDA(jtag_ida);
++
++void *jtag_priv(struct jtag *jtag)
++{
++ return jtag->priv;
++}
++EXPORT_SYMBOL_GPL(jtag_priv);
++
++static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++ struct jtag *jtag = file->private_data;
++ struct jtag_tap_state tapstate;
++ struct jtag_xfer xfer;
++ struct bitbang_packet bitbang;
++ struct tck_bitbang *bitbang_data;
++ struct jtag_mode mode;
++ u8 *xfer_data;
++ u32 data_size;
++ u32 value;
++ int err;
++
++ if (!arg)
++ return -EINVAL;
++
++ switch (cmd) {
++ case JTAG_GIOCFREQ:
++ if (!jtag->ops->freq_get)
++ return -EOPNOTSUPP;
++
++ err = jtag->ops->freq_get(jtag, &value);
++ if (err)
++ break;
++
++ if (put_user(value, (__u32 __user *)arg))
++ err = -EFAULT;
++ break;
++
++ case JTAG_SIOCFREQ:
++ if (!jtag->ops->freq_set)
++ return -EOPNOTSUPP;
++
++ if (get_user(value, (__u32 __user *)arg))
++ return -EFAULT;
++ if (value == 0)
++ return -EINVAL;
++
++ err = jtag->ops->freq_set(jtag, value);
++ break;
++
++ case JTAG_SIOCSTATE:
++ if (copy_from_user(&tapstate, (const void __user *)arg,
++ sizeof(struct jtag_tap_state)))
++ return -EFAULT;
++
++ if (tapstate.from > JTAG_STATE_CURRENT)
++ return -EINVAL;
++
++ if (tapstate.endstate > JTAG_STATE_CURRENT)
++ return -EINVAL;
++
++ if (tapstate.reset > JTAG_FORCE_RESET)
++ return -EINVAL;
++
++ err = jtag->ops->status_set(jtag, &tapstate);
++ break;
++
++ case JTAG_IOCXFER:
++ if (copy_from_user(&xfer, (const void __user *)arg,
++ sizeof(struct jtag_xfer)))
++ return -EFAULT;
++
++ if (xfer.length >= JTAG_MAX_XFER_DATA_LEN)
++ return -EINVAL;
++
++ if (xfer.type > JTAG_SDR_XFER)
++ return -EINVAL;
++
++ if (xfer.direction > JTAG_READ_WRITE_XFER)
++ return -EINVAL;
++
++ if (xfer.from > JTAG_STATE_CURRENT)
++ return -EINVAL;
++
++ if (xfer.endstate > JTAG_STATE_CURRENT)
++ return -EINVAL;
++
++ data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE);
++ xfer_data = memdup_user(u64_to_user_ptr(xfer.tdio), data_size);
++ if (IS_ERR(xfer_data))
++ return -EFAULT;
++
++ err = jtag->ops->xfer(jtag, &xfer, xfer_data);
++ if (err) {
++ kfree(xfer_data);
++ return err;
++ }
++
++ err = copy_to_user(u64_to_user_ptr(xfer.tdio),
++ (void *)xfer_data, data_size);
++ kfree(xfer_data);
++ if (err)
++ return -EFAULT;
++
++ if (copy_to_user((void __user *)arg, (void *)&xfer,
++ sizeof(struct jtag_xfer)))
++ return -EFAULT;
++ break;
++
++ case JTAG_GIOCSTATUS:
++ err = jtag->ops->status_get(jtag, &value);
++ if (err)
++ break;
++
++ err = put_user(value, (__u32 __user *)arg);
++ break;
++ case JTAG_IOCBITBANG:
++ if (copy_from_user(&bitbang, (const void __user *)arg,
++ sizeof(struct bitbang_packet)))
++ return -EFAULT;
++
++ if (bitbang.length >= JTAG_MAX_XFER_DATA_LEN)
++ return -EINVAL;
++
++ data_size = bitbang.length * sizeof(struct tck_bitbang);
++ bitbang_data = memdup_user((void __user *)bitbang.data,
++ data_size);
++ if (IS_ERR(bitbang_data))
++ return -EFAULT;
++
++ err = jtag->ops->bitbang(jtag, &bitbang, bitbang_data);
++ if (err) {
++ kfree(bitbang_data);
++ return err;
++ }
++ err = copy_to_user((void __user *)bitbang.data,
++ (void *)bitbang_data, data_size);
++ kfree(bitbang_data);
++ if (err)
++ return -EFAULT;
++ break;
++ case JTAG_SIOCMODE:
++ if (!jtag->ops->mode_set)
++ return -EOPNOTSUPP;
++
++ if (copy_from_user(&mode, (const void __user *)arg,
++ sizeof(struct jtag_mode)))
++ return -EFAULT;
++
++ err = jtag->ops->mode_set(jtag, &mode);
++ break;
++
++ default:
++ return -EINVAL;
++ }
++ return err;
++}
++
++static int jtag_open(struct inode *inode, struct file *file)
++{
++ struct jtag *jtag = container_of(file->private_data,
++ struct jtag,
++ miscdev);
++
++ file->private_data = jtag;
++ if (jtag->ops->enable(jtag))
++ return -EBUSY;
++ return nonseekable_open(inode, file);
++}
++
++static int jtag_release(struct inode *inode, struct file *file)
++{
++ struct jtag *jtag = file->private_data;
++
++ if (jtag->ops->disable(jtag))
++ return -EBUSY;
++ return 0;
++}
++
++static const struct file_operations jtag_fops = {
++ .owner = THIS_MODULE,
++ .open = jtag_open,
++ .llseek = noop_llseek,
++ .unlocked_ioctl = jtag_ioctl,
++ .release = jtag_release,
++};
++
++struct jtag *jtag_alloc(struct device *host, size_t priv_size,
++ const struct jtag_ops *ops)
++{
++ struct jtag *jtag;
++
++ if (!host)
++ return NULL;
++
++ if (!ops)
++ return NULL;
++
++ if (!ops->status_set || !ops->status_get || !ops->xfer)
++ return NULL;
++
++ jtag = kzalloc(sizeof(*jtag) + priv_size, GFP_KERNEL);
++ if (!jtag)
++ return NULL;
++
++ jtag->ops = ops;
++ jtag->miscdev.parent = host;
++
++ return jtag;
++}
++EXPORT_SYMBOL_GPL(jtag_alloc);
++
++void jtag_free(struct jtag *jtag)
++{
++ kfree(jtag);
++}
++EXPORT_SYMBOL_GPL(jtag_free);
++
++static int jtag_register(struct jtag *jtag)
++{
++ struct device *dev = jtag->miscdev.parent;
++ int err;
++ int id;
++
++ if (!dev)
++ return -ENODEV;
++
++ id = ida_simple_get(&jtag_ida, 0, 0, GFP_KERNEL);
++ if (id < 0)
++ return id;
++
++ jtag->id = id;
++
++ jtag->miscdev.fops = &jtag_fops;
++ jtag->miscdev.minor = MISC_DYNAMIC_MINOR;
++ jtag->miscdev.name = kasprintf(GFP_KERNEL, "jtag%d", id);
++ if (!jtag->miscdev.name) {
++ err = -ENOMEM;
++ goto err_jtag_alloc;
++ }
++
++ err = misc_register(&jtag->miscdev);
++ if (err) {
++ dev_err(jtag->miscdev.parent, "Unable to register device\n");
++ goto err_jtag_name;
++ }
++ return 0;
++
++err_jtag_name:
++ kfree(jtag->miscdev.name);
++err_jtag_alloc:
++ ida_simple_remove(&jtag_ida, id);
++ return err;
++}
++
++static void jtag_unregister(struct jtag *jtag)
++{
++ misc_deregister(&jtag->miscdev);
++ kfree(jtag->miscdev.name);
++ ida_simple_remove(&jtag_ida, jtag->id);
++}
++
++static void devm_jtag_unregister(struct device *dev, void *res)
++{
++ jtag_unregister(*(struct jtag **)res);
++}
++
++int devm_jtag_register(struct device *dev, struct jtag *jtag)
++{
++ struct jtag **ptr;
++ int ret;
++
++ ptr = devres_alloc(devm_jtag_unregister, sizeof(struct jtag *),
++ GFP_KERNEL);
++ if (!ptr)
++ return -ENOMEM;
++
++ ret = jtag_register(jtag);
++ if (!ret) {
++ *ptr = jtag;
++ devres_add(dev, ptr);
++ } else {
++ devres_free(ptr);
++ }
++ return ret;
++}
++EXPORT_SYMBOL_GPL(devm_jtag_register);
++
++static void __exit jtag_exit(void)
++{
++ ida_destroy(&jtag_ida);
++}
++
++module_exit(jtag_exit);
++
++MODULE_AUTHOR("Oleksandr Shamray <oleksandrs@mellanox.com>");
++MODULE_DESCRIPTION("Generic jtag support");
++MODULE_LICENSE("GPL v2");
+diff --git a/include/linux/jtag.h b/include/linux/jtag.h
+new file mode 100644
+index 000000000000..fab12dc4fc5e
+--- /dev/null
++++ b/include/linux/jtag.h
+@@ -0,0 +1,47 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/* Copyright (c) 2018 Mellanox Technologies. All rights reserved. */
++/* Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com> */
++/* Copyright (c) 2019 Intel Corporation */
++
++#ifndef __LINUX_JTAG_H
++#define __LINUX_JTAG_H
++
++#include <linux/types.h>
++#include <uapi/linux/jtag.h>
++
++#define JTAG_MAX_XFER_DATA_LEN 65535
++
++struct jtag;
++/**
++ * struct jtag_ops - callbacks for JTAG control functions:
++ *
++ * @freq_get: get frequency function. Filled by dev driver
++ * @freq_set: set frequency function. Filled by dev driver
++ * @status_get: get JTAG TAPC state function. Mandatory, Filled by dev driver
++ * @status_set: set JTAG TAPC state function. Mandatory, Filled by dev driver
++ * @xfer: send JTAG xfer function. Mandatory func. Filled by dev driver
++ * @mode_set: set specific work mode for JTAG. Filled by dev driver
++ * @bitbang: set low level bitbang operations. Filled by dev driver
++ * @enable: enables JTAG interface in master mode. Filled by dev driver
++ * @disable: disables JTAG interface master mode. Filled by dev driver
++ */
++struct jtag_ops {
++ int (*freq_get)(struct jtag *jtag, u32 *freq);
++ int (*freq_set)(struct jtag *jtag, u32 freq);
++ int (*status_get)(struct jtag *jtag, u32 *state);
++ int (*status_set)(struct jtag *jtag, struct jtag_tap_state *endst);
++ int (*xfer)(struct jtag *jtag, struct jtag_xfer *xfer, u8 *xfer_data);
++ int (*mode_set)(struct jtag *jtag, struct jtag_mode *jtag_mode);
++ int (*bitbang)(struct jtag *jtag, struct bitbang_packet *bitbang,
++ struct tck_bitbang *bitbang_data);
++ int (*enable)(struct jtag *jtag);
++ int (*disable)(struct jtag *jtag);
++};
++
++void *jtag_priv(struct jtag *jtag);
++int devm_jtag_register(struct device *dev, struct jtag *jtag);
++struct jtag *jtag_alloc(struct device *host, size_t priv_size,
++ const struct jtag_ops *ops);
++void jtag_free(struct jtag *jtag);
++
++#endif /* __LINUX_JTAG_H */
+diff --git a/include/uapi/linux/jtag.h b/include/uapi/linux/jtag.h
+new file mode 100644
+index 000000000000..315e59577a17
+--- /dev/null
++++ b/include/uapi/linux/jtag.h
+@@ -0,0 +1,214 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/* Copyright (c) 2018 Mellanox Technologies. All rights reserved. */
++/* Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com> */
++/* Copyright (c) 2019 Intel Corporation */
++
++#ifndef __UAPI_LINUX_JTAG_H
++#define __UAPI_LINUX_JTAG_H
++
++/*
++ * JTAG_XFER_MODE: JTAG transfer mode. Used to set JTAG controller transfer mode
++ * This is bitmask for feature param in jtag_mode for ioctl JTAG_SIOCMODE
++ */
++#define JTAG_XFER_MODE 0
++/*
++ * JTAG_CONTROL_MODE: JTAG controller mode. Used to set JTAG controller mode
++ * This is bitmask for feature param in jtag_mode for ioctl JTAG_SIOCMODE
++ */
++#define JTAG_CONTROL_MODE 1
++/*
++ * JTAG_MASTER_OUTPUT_DISABLE: JTAG master mode output disable, it is used to
++ * enable other devices to own the JTAG bus.
++ * This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE
++ */
++#define JTAG_MASTER_OUTPUT_DISABLE 0
++/*
++ * JTAG_MASTER_MODE: JTAG master mode. Used to set JTAG controller master mode
++ * This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE
++ */
++#define JTAG_MASTER_MODE 1
++/*
++ * JTAG_XFER_HW_MODE: JTAG hardware mode. Used to set HW drived or bitbang
++ * mode. This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE
++ */
++#define JTAG_XFER_HW_MODE 1
++/*
++ * JTAG_XFER_SW_MODE: JTAG software mode. Used to set SW drived or bitbang
++ * mode. This is bitmask for mode param in jtag_mode for ioctl JTAG_SIOCMODE
++ */
++#define JTAG_XFER_SW_MODE 0
++
++/**
++ * enum jtag_tapstate:
++ *
++ * @JTAG_STATE_TLRESET: JTAG state machine Test Logic Reset state
++ * @JTAG_STATE_IDLE: JTAG state machine IDLE state
++ * @JTAG_STATE_SELECTDR: JTAG state machine SELECT_DR state
++ * @JTAG_STATE_CAPTUREDR: JTAG state machine CAPTURE_DR state
++ * @JTAG_STATE_SHIFTDR: JTAG state machine SHIFT_DR state
++ * @JTAG_STATE_EXIT1DR: JTAG state machine EXIT-1 DR state
++ * @JTAG_STATE_PAUSEDR: JTAG state machine PAUSE_DR state
++ * @JTAG_STATE_EXIT2DR: JTAG state machine EXIT-2 DR state
++ * @JTAG_STATE_UPDATEDR: JTAG state machine UPDATE DR state
++ * @JTAG_STATE_SELECTIR: JTAG state machine SELECT_IR state
++ * @JTAG_STATE_CAPTUREIR: JTAG state machine CAPTURE_IR state
++ * @JTAG_STATE_SHIFTIR: JTAG state machine SHIFT_IR state
++ * @JTAG_STATE_EXIT1IR: JTAG state machine EXIT-1 IR state
++ * @JTAG_STATE_PAUSEIR: JTAG state machine PAUSE_IR state
++ * @JTAG_STATE_EXIT2IR: JTAG state machine EXIT-2 IR state
++ * @JTAG_STATE_UPDATEIR: JTAG state machine UPDATE IR state
++ * @JTAG_STATE_CURRENT: JTAG current state, saved by driver
++ */
++enum jtag_tapstate {
++ JTAG_STATE_TLRESET,
++ JTAG_STATE_IDLE,
++ JTAG_STATE_SELECTDR,
++ JTAG_STATE_CAPTUREDR,
++ JTAG_STATE_SHIFTDR,
++ JTAG_STATE_EXIT1DR,
++ JTAG_STATE_PAUSEDR,
++ JTAG_STATE_EXIT2DR,
++ JTAG_STATE_UPDATEDR,
++ JTAG_STATE_SELECTIR,
++ JTAG_STATE_CAPTUREIR,
++ JTAG_STATE_SHIFTIR,
++ JTAG_STATE_EXIT1IR,
++ JTAG_STATE_PAUSEIR,
++ JTAG_STATE_EXIT2IR,
++ JTAG_STATE_UPDATEIR,
++ JTAG_STATE_CURRENT
++};
++
++/**
++ * enum jtag_reset:
++ *
++ * @JTAG_NO_RESET: JTAG run TAP from current state
++ * @JTAG_FORCE_RESET: JTAG force TAP to reset state
++ */
++enum jtag_reset {
++ JTAG_NO_RESET = 0,
++ JTAG_FORCE_RESET = 1,
++};
++
++/**
++ * enum jtag_xfer_type:
++ *
++ * @JTAG_SIR_XFER: SIR transfer
++ * @JTAG_SDR_XFER: SDR transfer
++ */
++enum jtag_xfer_type {
++ JTAG_SIR_XFER = 0,
++ JTAG_SDR_XFER = 1,
++};
++
++/**
++ * enum jtag_xfer_direction:
++ *
++ * @JTAG_READ_XFER: read transfer
++ * @JTAG_WRITE_XFER: write transfer
++ * @JTAG_READ_WRITE_XFER: read & write transfer
++ */
++enum jtag_xfer_direction {
++ JTAG_READ_XFER = 1,
++ JTAG_WRITE_XFER = 2,
++ JTAG_READ_WRITE_XFER = 3,
++};
++
++/**
++ * struct jtag_tap_state - forces JTAG state machine to go into a TAPC
++ * state
++ *
++ * @reset: 0 - run IDLE/PAUSE from current state
++ * 1 - go through TEST_LOGIC/RESET state before IDLE/PAUSE
++ * @end: completion flag
++ * @tck: clock counter
++ *
++ * Structure provide interface to JTAG device for JTAG set state execution.
++ */
++struct jtag_tap_state {
++ __u8 reset;
++ __u8 from;
++ __u8 endstate;
++ __u8 tck;
++};
++
++/**
++ * struct jtag_xfer - jtag xfer:
++ *
++ * @type: transfer type
++ * @direction: xfer direction
++ * @from: xfer current state
++ * @endstate: xfer end state
++ * @padding: xfer padding
++ * @length: xfer bits length
++ * @tdio : xfer data array
++ *
++ * Structure provide interface to JTAG device for JTAG SDR/SIR xfer execution.
++ */
++struct jtag_xfer {
++ __u8 type;
++ __u8 direction;
++ __u8 from;
++ __u8 endstate;
++ __u8 padding;
++ __u32 length;
++ __u64 tdio;
++};
++
++/**
++ * struct bitbang_packet - jtag bitbang array packet:
++ *
++ * @data: JTAG Bitbang struct array pointer(input/output)
++ * @length: array size (input)
++ *
++ * Structure provide interface to JTAG device for JTAG bitbang bundle execution
++ */
++struct bitbang_packet {
++ struct tck_bitbang *data;
++ __u32 length;
++} __attribute__((__packed__));
++
++/**
++ * struct jtag_bitbang - jtag bitbang:
++ *
++ * @tms: JTAG TMS
++ * @tdi: JTAG TDI (input)
++ * @tdo: JTAG TDO (output)
++ *
++ * Structure provide interface to JTAG device for JTAG bitbang execution.
++ */
++struct tck_bitbang {
++ __u8 tms;
++ __u8 tdi;
++ __u8 tdo;
++} __attribute__((__packed__));
++
++/**
++ * struct jtag_mode - jtag mode:
++ *
++ * @feature: 0 - JTAG feature setting selector for JTAG controller HW/SW
++ * 1 - JTAG feature setting selector for controller bus master
++ * mode output (enable / disable).
++ * @mode: (0 - SW / 1 - HW) for JTAG_XFER_MODE feature(0)
++ * (0 - output disable / 1 - output enable) for JTAG_CONTROL_MODE
++ * feature(1)
++ *
++ * Structure provide configuration modes to JTAG device.
++ */
++struct jtag_mode {
++ __u32 feature;
++ __u32 mode;
++};
++
++/* ioctl interface */
++#define __JTAG_IOCTL_MAGIC 0xb2
++
++#define JTAG_SIOCSTATE _IOW(__JTAG_IOCTL_MAGIC, 0, struct jtag_tap_state)
++#define JTAG_SIOCFREQ _IOW(__JTAG_IOCTL_MAGIC, 1, unsigned int)
++#define JTAG_GIOCFREQ _IOR(__JTAG_IOCTL_MAGIC, 2, unsigned int)
++#define JTAG_IOCXFER _IOWR(__JTAG_IOCTL_MAGIC, 3, struct jtag_xfer)
++#define JTAG_GIOCSTATUS _IOWR(__JTAG_IOCTL_MAGIC, 4, enum jtag_tapstate)
++#define JTAG_SIOCMODE _IOW(__JTAG_IOCTL_MAGIC, 5, unsigned int)
++#define JTAG_IOCBITBANG _IOW(__JTAG_IOCTL_MAGIC, 6, unsigned int)
++
++#endif /* __UAPI_LINUX_JTAG_H */
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch
new file mode 100644
index 000000000..b70629f18
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch
@@ -0,0 +1,1466 @@
+From e01c562db28797e3b6be9030f1f52507115c6765 Mon Sep 17 00:00:00 2001
+From: "Corona, Ernesto" <ernesto.corona@intel.com>
+Date: Mon, 6 Apr 2020 09:48:32 -0700
+Subject: [PATCH] Add Aspeed SoC 24xx and 25xx families JTAG
+
+Driver adds support of Aspeed 2400-2600 series SOC JTAG master controller.
+
+Driver implements the following jtag ops:
+- freq_get;
+- freq_set;
+- status_get;
+- status_set
+- xfer;
+- mode_set;
+- bitbang;
+- enable;
+- disable;
+
+It has been tested on Mellanox system with BMC equipped with
+Aspeed 2520 SoC for programming CPLD devices.
+
+It has also been tested on Intel system using Aspeed 25xx SoC
+for JTAG communication.
+
+Tested on Intel system using Aspeed 26xx SoC for JTAG communication.
+
+Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
+Signed-off-by: Jiri Pirko <jiri@mellanox.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Acked-by: Philippe Ombredanne <pombredanne@nexb.com>
+Acked-by: Joel Stanley <joel@jms.id.au>
+Cc: Vadim Pasternak <vadimp@mellanox.com>
+Cc: Andrew Jeffery <andrew@aj.id.au>
+Cc: Steven A Filary <steven.a.filary@intel.com>
+Cc: Bryan Hunt <bryan.hunt@intel.com>
+---
+v29->v30
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Add Suport for 26xx series
+
+v28->v29
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Expand bitbang function to accept multiples bitbang operations within a
+ single JTAG_IOCBITBANG call. It will receive a buffer with TDI and TMS
+ values and it is expected that driver fills TDO fields with its
+ corresponding output value for every transaction.
+- Always setup JTAG controller to master mode but disable JTAG output when
+ the driver is not in use to allow other HW to own the JTAG bus. Remove SCU
+ register accesses. This register controls the JTAG controller mode
+ (master/slave).
+- Encansulate dev_dgb message into DEBUG_JTAG macros to improve driver's JTAG
+ performace.
+- Add support for multichain. Set tap state and xfer operations now include
+ two tap state arguments: current state and end state.
+
+v27->v28
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Replace JTAG_IOCRUNTEST with JTAG_SIOCSTATE adding support for all TAPC
+ end states in SW mode using a lookup table to navigate across states.
+- Add support for simultaneous READ/WRITE transfers(JTAG_READ_WRITE_XFER).
+- Support for switching JTAG controller mode between slave and master
+ mode.
+- Setup JTAG controller mode to master only when the driver is opened,
+ letting other HW to own the JTAG bus when it isn't in use.
+- Include JTAG bit bang IOCTL for low level JTAG control usage
+ (JTAG_IOCBITBANG).
+- Add debug traces.
+- Add support for register polling (default) due it is 3 times faster than
+ interrupt mode. Define USE_INTERRUPTS macro to enable interrupt usage.
+- Remove unnecessary delays for aspeed_jtag_status_set function. It makes
+ SW mode 4 times faster.
+- Clean data buffer on aspeed_jtag_xfer_sw before tdo writes to avoid data
+ output corruption for read operations in SW mode.
+- Correct register settings for HW mode transfer operations.
+- Propagate ret codes all the way from low level functions up to
+ JTAG_IOCXFER call.
+- Support for partitioned transfers. Single JTAG transfer through
+ multiples JTAG_IOCXFER calls. Now end transmission(scan_end) also
+ evaluates transfer end state.
+
+v26->v27
+Changes made by Oleksandr Shamray <oleksandrs@mellamnox.com>
+- change aspeed_jtag_sw_delay to udelay function in bit-bang operation
+
+v25->v26
+v24->v25
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- reduced debug printouts
+
+v23->v24
+v22->v23
+v21->v22
+Comments pointed by Andy Shevchenko <andy.shevchenko@gmail.com>
+- rearrange ASPEED register defines
+- simplified JTAG divider calculation formula
+- change delay function in bit-bang operation
+- add helper functions for TAP states switching
+- remove unnecessary comments
+- remove redundant debug messages
+- make dines for repetative register bit sets
+- fixed indentation
+- change checks from negative to positive
+- add error check for clk_prepare_enable
+- rework driver alloc/register to devm_ variant
+- Increasing line length up to 85 in order to improve readability
+
+v20->v21
+v19->v20
+Notifications from kbuild test robot <lkp@intel.com>
+- add static declaration to 'aspeed_jtag_init' and
+ 'aspeed_jtag_deinit' functions
+
+v18->v19
+v17->v18
+v16->v17
+v15->v16
+Comments pointed by Joel Stanley <joel.stan@gmail.com>
+- Add reset_control on Jtag init/deinit
+
+v14->v15
+Comments pointed by Joel Stanley <joel.stan@gmail.com>
+- Add ARCH_ASPEED || COMPILE_TEST to Kconfig
+- remove unused offset variable
+- remove "aspeed_jtag" from dev_err and dev_dbg messages
+- change clk_prepare_enable initialisation order
+
+v13->v14
+Comments pointed by Philippe Ombredanne <pombredanne@nexb.com>
+- Change style of head block comment from /**/ to //
+
+v12->v13
+Comments pointed by Philippe Ombredanne <pombredanne@nexb.com>
+- Change jtag-aspeed.c licence type to
+ SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ and reorder line with license- add reset descriptions in bndings file
+ in description
+Comments pointed by Kun Yi <kunyi@google.com>
+- Changed capability check for aspeed,ast2400-jtag/ast200-jtag
+
+v11->v12
+Comments pointed by Chip Bilbrey <chip@bilbrey.org>
+- Remove access mode from xfer and idle transactions
+- Add new ioctl JTAG_SIOCMODE for set hw mode
+
+v10->v11
+v9->v10
+V8->v9
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- add *data parameter to xfer function prototype
+
+v7->v8
+Comments pointed by Joel Stanley <joel.stan@gmail.com>
+- aspeed_jtag_init replace goto to return;
+- change input variables type from __u32 to u32
+ in functios freq_get, freq_set, status_get
+- change sm_ variables type from char to u8
+- in jatg_init add disable clocks on error case
+- remove release_mem_region on error case
+- remove devm_free_irq on jtag_deinit
+- Fix misspelling Disabe/Disable
+- Change compatible string to ast2400 and ast2000
+
+v6->v7
+Notifications from kbuild test robot <lkp@intel.com>
+- Add include <linux/types.h> to jtag-asapeed.c
+
+v5->v6
+v4->v5
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- Added HAS_IOMEM dependence in Kconfig to avoid
+ "undefined reference to `devm_ioremap_resource'" error,
+ because in some arch this not supported
+
+v3->v4
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- change transaction pointer tdio type to __u64
+- change internal status type from enum to __u32
+
+v2->v3
+
+v1->v2
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- change license type from GPLv2/BSD to GPLv2
+
+Comments pointed by Neil Armstrong <narmstrong@baylibre.com>
+- Add clk_prepare_enable/clk_disable_unprepare in clock init/deinit
+- Change .compatible to soc-specific compatible names
+ aspeed,aspeed4000-jtag/aspeed5000-jtag
+- Added dt-bindings
+
+Comments pointed by Arnd Bergmann <arnd@arndb.de>
+- Reorder functions and removed the forward declarations
+- Add static const qualifier to state machine states transitions
+- Change .compatible to soc-specific compatible names
+ aspeed,aspeed4000-jtag/aspeed5000-jtag
+- Add dt-bindings
+
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- Change module name jtag-aspeed in description in Kconfig
+
+Comments pointed by kbuild test robot <lkp@intel.com>
+- Remove invalid include <asm/mach-types.h>
+- add resource_size instead of calculation
+---
+ drivers/jtag/Kconfig | 14 +
+ drivers/jtag/Makefile | 1 +
+ drivers/jtag/jtag-aspeed.c | 1217 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1232 insertions(+)
+ create mode 100644 drivers/jtag/jtag-aspeed.c
+
+diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig
+index 47771fc..0cc163f 100644
+--- a/drivers/jtag/Kconfig
++++ b/drivers/jtag/Kconfig
+@@ -15,3 +15,17 @@ menuconfig JTAG
+
+ To compile this driver as a module, choose M here: the module will
+ be called jtag.
++
++menuconfig JTAG_ASPEED
++ tristate "Aspeed SoC JTAG controller support"
++ depends on JTAG && 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
+index af37493..04a855e 100644
+--- a/drivers/jtag/Makefile
++++ b/drivers/jtag/Makefile
+@@ -1 +1,2 @@
+ obj-$(CONFIG_JTAG) += jtag.o
++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 0000000..1e6ace6
+--- /dev/null
++++ b/drivers/jtag/jtag-aspeed.c
+@@ -0,0 +1,1217 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2018 Mellanox Technologies. All rights reserved.
++// Copyright (c) 2018 Oleksandr Shamray <oleksandrs@mellanox.com>
++// Copyright (c) 2019 Intel Corporation
++
++#include <linux/clk.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/jtag.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <uapi/linux/jtag.h>
++
++#define ASPEED_SCU_RESET_JTAG BIT(22)
++
++#define ASPEED_JTAG_DATA 0x00
++#define ASPEED_JTAG_INST 0x04
++#define ASPEED_JTAG_CTRL 0x08
++#define ASPEED_JTAG_ISR 0x0C
++#define ASPEED_JTAG_SW 0x10
++#define ASPEED_JTAG_TCK 0x14
++#define ASPEED_JTAG_EC 0x18
++
++#define ASPEED_JTAG_DATA_MSB 0x01
++#define ASPEED_JTAG_DATA_CHUNK_SIZE 0x20
++
++/* ASPEED_JTAG_CTRL: Engine Control 24xx and 25xx series*/
++#define ASPEED_JTAG_CTL_ENG_EN BIT(31)
++#define ASPEED_JTAG_CTL_ENG_OUT_EN BIT(30)
++#define ASPEED_JTAG_CTL_FORCE_TMS BIT(29)
++#define ASPEED_JTAG_CTL_IR_UPDATE BIT(26)
++#define ASPEED_JTAG_CTL_INST_LEN(x) ((x) << 20)
++#define ASPEED_JTAG_CTL_LASPEED_INST BIT(17)
++#define ASPEED_JTAG_CTL_INST_EN BIT(16)
++#define ASPEED_JTAG_CTL_DR_UPDATE BIT(10)
++#define ASPEED_JTAG_CTL_DATA_LEN(x) ((x) << 4)
++#define ASPEED_JTAG_CTL_LASPEED_DATA BIT(1)
++#define ASPEED_JTAG_CTL_DATA_EN BIT(0)
++
++/* ASPEED_JTAG_CTRL: Engine Control 26xx series*/
++#define ASPEED_JTAG_CTL_26XX_RESET_FIFO BIT(21)
++#define ASPEED_JTAG_CTL_26XX_FIFO_MODE_CTRL BIT(20)
++#define ASPEED_JTAG_CTL_26XX_TRANS_LEN(x) ((x) << 8)
++#define ASPEED_JTAG_CTL_26XX_MSB_FIRST BIT(6)
++#define ASPEED_JTAG_CTL_26XX_TERM_TRANS BIT(5)
++#define ASPEED_JTAG_CTL_26XX_LASPEED_TRANS BIT(4)
++#define ASPEED_JTAG_CTL_26XX_INST_EN BIT(1)
++
++/* ASPEED_JTAG_ISR : Interrupt status and enable */
++#define ASPEED_JTAG_ISR_INST_PAUSE BIT(19)
++#define ASPEED_JTAG_ISR_INST_COMPLETE BIT(18)
++#define ASPEED_JTAG_ISR_DATA_PAUSE BIT(17)
++#define ASPEED_JTAG_ISR_DATA_COMPLETE BIT(16)
++#define ASPEED_JTAG_ISR_INST_PAUSE_EN BIT(3)
++#define ASPEED_JTAG_ISR_INST_COMPLETE_EN BIT(2)
++#define ASPEED_JTAG_ISR_DATA_PAUSE_EN BIT(1)
++#define ASPEED_JTAG_ISR_DATA_COMPLETE_EN BIT(0)
++#define ASPEED_JTAG_ISR_INT_EN_MASK GENMASK(3, 0)
++#define ASPEED_JTAG_ISR_INT_MASK GENMASK(19, 16)
++
++/* ASPEED_JTAG_SW : Software Mode and Status */
++#define ASPEED_JTAG_SW_MODE_EN BIT(19)
++#define ASPEED_JTAG_SW_MODE_TCK BIT(18)
++#define ASPEED_JTAG_SW_MODE_TMS BIT(17)
++#define ASPEED_JTAG_SW_MODE_TDIO BIT(16)
++
++/* ASPEED_JTAG_TCK : TCK Control */
++#define ASPEED_JTAG_TCK_DIVISOR_MASK GENMASK(10, 0)
++#define ASPEED_JTAG_TCK_GET_DIV(x) ((x) & ASPEED_JTAG_TCK_DIVISOR_MASK)
++
++/* ASPEED_JTAG_EC : Controller set for go to IDLE */
++#define ASPEED_JTAG_EC_GO_IDLE BIT(0)
++
++#define ASPEED_JTAG_IOUT_LEN(len) \
++ (ASPEED_JTAG_CTL_ENG_EN | \
++ ASPEED_JTAG_CTL_ENG_OUT_EN | \
++ ASPEED_JTAG_CTL_INST_LEN(len))
++
++#define ASPEED_JTAG_DOUT_LEN(len) \
++ (ASPEED_JTAG_CTL_ENG_EN | \
++ ASPEED_JTAG_CTL_ENG_OUT_EN | \
++ ASPEED_JTAG_CTL_DATA_LEN(len))
++
++#define ASPEED_JTAG_TRANS_LEN(len) \
++ (ASPEED_JTAG_CTL_ENG_EN | \
++ ASPEED_JTAG_CTL_ENG_OUT_EN | \
++ ASPEED_JTAG_CTL_26XX_TRANS_LEN(len))
++
++#define ASPEED_JTAG_SW_TDIO (ASPEED_JTAG_SW_MODE_EN | ASPEED_JTAG_SW_MODE_TDIO)
++
++#define ASPEED_JTAG_GET_TDI(direction, byte) \
++ (((direction) & JTAG_WRITE_XFER) ? byte : UINT_MAX)
++
++#define ASPEED_JTAG_TCK_WAIT 10
++#define ASPEED_JTAG_RESET_CNTR 10
++#define WAIT_ITERATIONS 75
++
++/* ASPEED JTAG HW MODE 2 (Only supported in AST26xx series) */
++#define ASPEED_JTAG_SHDATA0 0x20
++#define ASPEED_JTAG_SHDATA1 0x24
++#define ASPEED_JTAG_PADCTRL0 0x28
++#define ASPEED_JTAG_PADCTRL1 0x2C
++#define ASPEED_JTAG_SHCTRL 0x30
++#define ASPEED_JTAG_GBLCTRL 0x34
++#define ASPEED_JTAG_INTCTRL 0x38
++#define ASPEED_JTAG_STAT 0x3C
++
++/* ASPEED_JTAG_PADCTRLx : Padding control 0 and 1 */
++#define ASPEED_JTAG_PADCTRL_PAD_DATA BIT(24)
++#define ASPEED_JTAG_PADCTRL_POSTPAD(x) (((x) & GENMASK(8, 0)) << 12)
++#define ASPEED_JTAG_PADCTRL_PREPAD(x) (((x) & GENMASK(8, 0)) << 0)
++
++/* ASPEED_JTAG_SHCTRL: Shift Control */
++#define ASPEED_JTAG_SHCTRL_FRUN_TCK_EN BIT(31)
++#define ASPEED_JTAG_SHCTRL_STSHIFT_EN BIT(30)
++#define ASPEED_JTAG_SHCTRL_TMS(x) (((x) & GENMASK(13, 0)) << 16)
++#define ASPEED_JTAG_SHCTRL_POST_TMS(x) (((x) & GENMASK(3, 0)) << 13)
++#define ASPEED_JTAG_SHCTRL_PRE_TMS(x) (((x) & GENMASK(3, 0)) << 10)
++#define ASPEED_JTAG_SHCTRL_PAD_SEL0 (0)
++#define ASPEED_JTAG_SHCTRL_PAD_SEL1 BIT(9)
++#define ASPEED_JTAG_SHCTRL_END_SHIFT BIT(8)
++#define ASPEED_JTAG_SHCTRL_START_SHIFT BIT(7)
++#define ASPEED_JTAG_SHCTRL_LWRDT_SHIFT(x) ((x) & GENMASK(6, 0))
++
++/* ASPEED_JTAG_GBLCTRL : Global Control */
++#define ASPEED_JTAG_GBLCTRL_ENG_MODE_EN BIT(31)
++#define ASPEED_JTAG_GBLCTRL_ENG_OUT_EN BIT(30)
++#define ASPEED_JTAG_GBLCTRL_FORCE_TMS BIT(29)
++#define ASPEED_JTAG_GBLCTRL_SHIFT_COMPLETE BIT(28)
++#define ASPEED_JTAG_GBLCTRL_RESET_FIFO BIT(25)
++#define ASPEED_JTAG_GBLCTRL_FIFO_MODE BIT(24)
++#define ASPEED_JTAG_GBLCTRL_UPDT_SHIFT(x) (((x) & GENMASK(3, 0)) << 20)
++#define ASPEED_JTAG_GBLCTRL_STSHIFT(x) (((x) & GENMASK(0, 0)) << 16)
++#define ASPEED_JTAG_GBLCTRL_TRST BIT(15)
++#define ASPEED_JTAG_CLK_DIVISOR_MASK GENMASK(11, 0)
++#define ASPEED_JTAG_CLK_GET_DIV(x) ((x) & ASPEED_JTAG_CLK_DIVISOR_MASK)
++
++/* ASPEED_JTAG_INTCTRL: Interrupt Control */
++#define ASPEED_JTAG_INTCTRL_SHCPL_IRQ_EN BIT(16)
++#define ASPEED_JTAG_INTCTRL_SHCPL_IRQ_STAT BIT(0)
++
++/* ASPEED_JTAG_STAT: JTAG HW mode 2 status */
++#define ASPEED_JTAG_STAT_ENG_IDLE BIT(0)
++
++/*#define USE_INTERRUPTS*/
++#define DEBUG_JTAG
++
++static const char * const regnames[] = {
++ [ASPEED_JTAG_DATA] = "ASPEED_JTAG_DATA",
++ [ASPEED_JTAG_INST] = "ASPEED_JTAG_INST",
++ [ASPEED_JTAG_CTRL] = "ASPEED_JTAG_CTRL",
++ [ASPEED_JTAG_ISR] = "ASPEED_JTAG_ISR",
++ [ASPEED_JTAG_SW] = "ASPEED_JTAG_SW",
++ [ASPEED_JTAG_TCK] = "ASPEED_JTAG_TCK",
++ [ASPEED_JTAG_EC] = "ASPEED_JTAG_EC",
++ [ASPEED_JTAG_SHDATA0] = "ASPEED_JTAG_SHDATA0",
++ [ASPEED_JTAG_SHDATA1] = "ASPEED_JTAG_SHDATA1",
++ [ASPEED_JTAG_PADCTRL0] = "ASPEED_JTAG_PADCTRL0",
++ [ASPEED_JTAG_PADCTRL1] = "ASPEED_JTAG_PADCTRL1",
++ [ASPEED_JTAG_SHCTRL] = "ASPEED_JTAG_SHCTRL",
++ [ASPEED_JTAG_GBLCTRL] = "ASPEED_JTAG_GBLCTRL",
++ [ASPEED_JTAG_INTCTRL] = "ASPEED_JTAG_INTCTRL",
++ [ASPEED_JTAG_STAT] = "ASPEED_JTAG_STAT",
++};
++
++#define ASPEED_JTAG_NAME "jtag-aspeed"
++
++struct aspeed_jtag {
++ void __iomem *reg_base;
++ struct device *dev;
++ struct clk *pclk;
++ enum jtag_tapstate status;
++ int irq;
++ struct reset_control *rst;
++ u32 flag;
++ wait_queue_head_t jtag_wq;
++ u32 mode;
++ struct jtag_low_level_functions *llops;
++};
++
++/* Multi generation support is enabled by fops and low level assped function
++ * mapping using asped_jtag_functions struct as config mechanism.
++ */
++
++struct jtag_low_level_functions {
++ void (*output_disable)(struct aspeed_jtag *aspeed_jtag);
++ int (*xfer_push_data)(struct aspeed_jtag *aspeed_jtag,
++ enum jtag_xfer_type type, u32 bits_len);
++ int (*xfer_push_data_last)(struct aspeed_jtag *aspeed_jtag,
++ enum jtag_xfer_type type, u32 bits_len);
++};
++
++struct aspeed_jtag_functions {
++ struct jtag_ops *aspeed_jtag_ops;
++ struct jtag_low_level_functions *aspeed_jtag_llops;
++};
++
++/*
++ * 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;
++};
++
++/*
++ * 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*/
++/* TLR */{{0x00, 0}, {0x00, 1}, {0x02, 2}, {0x02, 3}, {0x02, 4}, {0x0a, 4},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x0a, 5}, {0x2a, 6}, {0x1a, 5}, {0x06, 3}, {0x06, 4}, {0x06, 5},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x16, 5}, {0x16, 6}, {0x56, 7}, {0x36, 6} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* RTI */{{0x07, 3}, {0x00, 0}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x05, 4}, {0x15, 5}, {0x0d, 4}, {0x03, 2}, {0x03, 3}, {0x03, 4},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* SelDR*/{{0x03, 2}, {0x03, 3}, {0x00, 0}, {0x00, 1}, {0x00, 2}, {0x02, 2},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x02, 3}, {0x0a, 4}, {0x06, 3}, {0x01, 1}, {0x01, 2}, {0x01, 3},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x0d, 4} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* CapDR*/{{0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x00, 0}, {0x00, 1}, {0x01, 1},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x01, 2}, {0x05, 3}, {0x03, 2}, {0x0f, 4}, {0x0f, 5}, {0x0f, 6},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, {0x6f, 7} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* SDR */{{0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x00, 0}, {0x01, 1},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x01, 2}, {0x05, 3}, {0x03, 2}, {0x0f, 4}, {0x0f, 5}, {0x0f, 6},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, {0x6f, 7} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* Ex1DR*/{{0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x02, 3}, {0x00, 0},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x00, 1}, {0x02, 2}, {0x01, 1}, {0x07, 3}, {0x07, 4}, {0x07, 5},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* PDR */{{0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x01, 2}, {0x05, 3},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x00, 0}, {0x01, 1}, {0x03, 2}, {0x0f, 4}, {0x0f, 5}, {0x0f, 6},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, {0x6f, 7} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* Ex2DR*/{{0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x00, 1}, {0x02, 2},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x02, 3}, {0x00, 0}, {0x01, 1}, {0x07, 3}, {0x07, 4}, {0x07, 5},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* UpdDR*/{{0x07, 3}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x05, 4}, {0x15, 5}, {0x00, 0}, {0x03, 2}, {0x03, 3}, {0x03, 4},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* SelIR*/{{0x01, 1}, {0x01, 2}, {0x05, 3}, {0x05, 4}, {0x05, 5}, {0x15, 5},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x15, 6}, {0x55, 7}, {0x35, 6}, {0x00, 0}, {0x00, 1}, {0x00, 2},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x02, 2}, {0x02, 3}, {0x0a, 4}, {0x06, 3} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* CapIR*/{{0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, {0x00, 0}, {0x00, 1},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* SIR */{{0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, {0x0f, 5}, {0x00, 0},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* Ex1IR*/{{0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x0b, 5}, {0x2b, 6}, {0x1b, 5}, {0x07, 3}, {0x07, 4}, {0x02, 3},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x00, 0}, {0x00, 1}, {0x02, 2}, {0x01, 1} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* PIR */{{0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, {0x17, 5},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, {0x0f, 5}, {0x01, 2},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x05, 3}, {0x00, 0}, {0x01, 1}, {0x03, 2} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* Ex2IR*/{{0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x03, 4}, {0x0b, 4},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x0b, 5}, {0x2b, 6}, {0x1b, 5}, {0x07, 3}, {0x07, 4}, {0x00, 1},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x02, 2}, {0x02, 3}, {0x00, 0}, {0x01, 1} },
++
++/* TLR RTI SelDR CapDR SDR Ex1DR*/
++/* UpdIR*/{{0x07, 3}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x01, 3}, {0x05, 3},
++/* PDR Ex2DR UpdDR SelIR CapIR SIR*/
++ {0x05, 4}, {0x15, 5}, {0x0d, 4}, {0x03, 2}, {0x03, 3}, {0x03, 4},
++/* Ex1IR PIR Ex2IR UpdIR*/
++ {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x00, 0} },
++};
++
++#ifdef DEBUG_JTAG
++static char *end_status_str[] = {
++ "tlr", "idle", "selDR", "capDR", "sDR", "ex1DR", "pDR", "ex2DR",
++ "updDR", "selIR", "capIR", "sIR", "ex1IR", "pIR", "ex2IR", "updIR"
++};
++#endif
++
++static u32 aspeed_jtag_read(struct aspeed_jtag *aspeed_jtag, u32 reg)
++{
++ u32 val = readl(aspeed_jtag->reg_base + reg);
++
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "read:%s val = 0x%08x\n", regnames[reg], val);
++#endif
++ return val;
++}
++
++static void
++aspeed_jtag_write(struct aspeed_jtag *aspeed_jtag, u32 val, u32 reg)
++{
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "write:%s val = 0x%08x\n",
++ regnames[reg], val);
++#endif
++ writel(val, aspeed_jtag->reg_base + reg);
++}
++
++static int aspeed_jtag_freq_set(struct jtag *jtag, u32 freq)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++ unsigned long apb_frq;
++ u32 tck_val;
++ u16 div;
++
++ apb_frq = clk_get_rate(aspeed_jtag->pclk);
++ if (!apb_frq)
++ return -ENOTSUPP;
++
++ div = (apb_frq - 1) / freq;
++ tck_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK);
++ aspeed_jtag_write(aspeed_jtag,
++ (tck_val & ~ASPEED_JTAG_TCK_DIVISOR_MASK) | div,
++ ASPEED_JTAG_TCK);
++ return 0;
++}
++
++static int aspeed_jtag_freq_get(struct jtag *jtag, u32 *frq)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++ u32 pclk;
++ u32 tck;
++
++ pclk = clk_get_rate(aspeed_jtag->pclk);
++ tck = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK);
++ *frq = pclk / (ASPEED_JTAG_TCK_GET_DIV(tck) + 1);
++
++ return 0;
++}
++
++static inline void aspeed_jtag_output_disable(struct aspeed_jtag *aspeed_jtag)
++{
++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL);
++}
++
++static inline void aspeed_jtag_master(struct aspeed_jtag *aspeed_jtag)
++{
++ aspeed_jtag_write(aspeed_jtag, (ASPEED_JTAG_CTL_ENG_EN |
++ ASPEED_JTAG_CTL_ENG_OUT_EN),
++ ASPEED_JTAG_CTRL);
++
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
++ ASPEED_JTAG_SW_MODE_TDIO,
++ ASPEED_JTAG_SW);
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_ISR_INST_PAUSE |
++ ASPEED_JTAG_ISR_INST_COMPLETE |
++ ASPEED_JTAG_ISR_DATA_PAUSE |
++ ASPEED_JTAG_ISR_DATA_COMPLETE |
++ ASPEED_JTAG_ISR_INST_PAUSE_EN |
++ ASPEED_JTAG_ISR_INST_COMPLETE_EN |
++ ASPEED_JTAG_ISR_DATA_PAUSE_EN |
++ ASPEED_JTAG_ISR_DATA_COMPLETE_EN,
++ ASPEED_JTAG_ISR); /* Enable Interrupt */
++}
++
++static int aspeed_jtag_mode_set(struct jtag *jtag, struct jtag_mode *jtag_mode)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++
++ switch (jtag_mode->feature) {
++ case JTAG_XFER_MODE:
++ aspeed_jtag->mode = jtag_mode->mode;
++ break;
++ case JTAG_CONTROL_MODE:
++ if (jtag_mode->mode == JTAG_MASTER_OUTPUT_DISABLE)
++ aspeed_jtag_output_disable(aspeed_jtag);
++ else if (jtag_mode->mode == JTAG_MASTER_MODE)
++ aspeed_jtag_master(aspeed_jtag);
++ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static char aspeed_jtag_tck_cycle(struct aspeed_jtag *aspeed_jtag,
++ u8 tms, u8 tdi)
++{
++ char tdo = 0;
++
++ /* TCK = 0 */
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
++ (tms * ASPEED_JTAG_SW_MODE_TMS) |
++ (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);
++
++ aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW);
++
++ /* TCK = 1 */
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |
++ ASPEED_JTAG_SW_MODE_TCK |
++ (tms * ASPEED_JTAG_SW_MODE_TMS) |
++ (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);
++
++ if (aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW) &
++ ASPEED_JTAG_SW_MODE_TDIO)
++ tdo = 1;
++
++ return tdo;
++}
++
++static int aspeed_jtag_bitbang(struct jtag *jtag,
++ struct bitbang_packet *bitbang,
++ struct tck_bitbang *bitbang_data)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++ int i = 0;
++
++ for (i = 0; i < bitbang->length; i++) {
++ bitbang_data[i].tdo =
++ aspeed_jtag_tck_cycle(aspeed_jtag, bitbang_data[i].tms,
++ bitbang_data[i].tdi);
++ }
++ return 0;
++}
++
++static int aspeed_jtag_wait_instruction_pause(struct aspeed_jtag *aspeed_jtag)
++{
++ int res = 0;
++#ifdef USE_INTERRUPTS
++ res = wait_event_interruptible(aspeed_jtag->jtag_wq,
++ aspeed_jtag->flag &
++ ASPEED_JTAG_ISR_INST_PAUSE);
++ aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_INST_PAUSE;
++#else
++ u32 status = 0;
++ u32 iterations = 0;
++
++ while ((status & ASPEED_JTAG_ISR_INST_PAUSE) == 0) {
++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "%s = 0x%08x\n", __func__, status);
++#endif
++ iterations++;
++ if (iterations > WAIT_ITERATIONS) {
++ dev_err(aspeed_jtag->dev,
++ "aspeed_jtag driver timed out waiting for instruction pause complete\n");
++ res = -EFAULT;
++ break;
++ }
++ if ((status & ASPEED_JTAG_ISR_DATA_COMPLETE) == 0) {
++ if (iterations % 25 == 0)
++ usleep_range(1, 5);
++ else
++ udelay(1);
++ }
++ }
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_ISR_INST_PAUSE |
++ (status & 0xf),
++ ASPEED_JTAG_ISR);
++#endif
++ return res;
++}
++
++static int
++aspeed_jtag_wait_instruction_complete(struct aspeed_jtag *aspeed_jtag)
++{
++ int res = 0;
++#ifdef USE_INTERRUPTS
++ res = wait_event_interruptible(aspeed_jtag->jtag_wq,
++ aspeed_jtag->flag &
++ ASPEED_JTAG_ISR_INST_COMPLETE);
++ aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_INST_COMPLETE;
++#else
++ u32 status = 0;
++ u32 iterations = 0;
++
++ while ((status & ASPEED_JTAG_ISR_INST_COMPLETE) == 0) {
++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "%s = 0x%08x\n", __func__, status);
++#endif
++ iterations++;
++ if (iterations > WAIT_ITERATIONS) {
++ dev_err(aspeed_jtag->dev,
++ "aspeed_jtag driver timed out waiting for instruction complete\n");
++ res = -EFAULT;
++ break;
++ }
++ if ((status & ASPEED_JTAG_ISR_DATA_COMPLETE) == 0) {
++ if (iterations % 25 == 0)
++ usleep_range(1, 5);
++ else
++ udelay(1);
++ }
++ }
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_ISR_INST_COMPLETE |
++ (status & 0xf),
++ ASPEED_JTAG_ISR);
++#endif
++ return res;
++}
++
++static int
++aspeed_jtag_wait_data_pause_complete(struct aspeed_jtag *aspeed_jtag)
++{
++ int res = 0;
++#ifdef USE_INTERRUPTS
++ res = wait_event_interruptible(aspeed_jtag->jtag_wq,
++ aspeed_jtag->flag &
++ ASPEED_JTAG_ISR_DATA_PAUSE);
++ aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_DATA_PAUSE;
++#else
++ u32 status = 0;
++ u32 iterations = 0;
++
++ while ((status & ASPEED_JTAG_ISR_DATA_PAUSE) == 0) {
++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "%s = 0x%08x\n", __func__, status);
++#endif
++ iterations++;
++ if (iterations > WAIT_ITERATIONS) {
++ dev_err(aspeed_jtag->dev,
++ "aspeed_jtag driver timed out waiting for data pause complete\n");
++ res = -EFAULT;
++ break;
++ }
++ if ((status & ASPEED_JTAG_ISR_DATA_COMPLETE) == 0) {
++ if (iterations % 25 == 0)
++ usleep_range(1, 5);
++ else
++ udelay(1);
++ }
++ }
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_ISR_DATA_PAUSE |
++ (status & 0xf), ASPEED_JTAG_ISR);
++#endif
++ return res;
++}
++
++static int aspeed_jtag_wait_data_complete(struct aspeed_jtag *aspeed_jtag)
++{
++ int res = 0;
++#ifdef USE_INTERRUPTS
++ res = wait_event_interruptible(aspeed_jtag->jtag_wq,
++ aspeed_jtag->flag &
++ ASPEED_JTAG_ISR_DATA_COMPLETE);
++ aspeed_jtag->flag &= ~ASPEED_JTAG_ISR_DATA_COMPLETE;
++#else
++ u32 status = 0;
++ u32 iterations = 0;
++
++ while ((status & ASPEED_JTAG_ISR_DATA_COMPLETE) == 0) {
++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "%s = 0x%08x\n", __func__, status);
++#endif
++ iterations++;
++ if (iterations > WAIT_ITERATIONS) {
++ dev_err(aspeed_jtag->dev,
++ "ast_jtag driver timed out waiting for data complete\n");
++ res = -EFAULT;
++ break;
++ }
++ if ((status & ASPEED_JTAG_ISR_DATA_COMPLETE) == 0) {
++ if (iterations % 25 == 0)
++ usleep_range(1, 5);
++ else
++ udelay(1);
++ }
++ }
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_ISR_DATA_COMPLETE | (status & 0xf),
++ ASPEED_JTAG_ISR);
++#endif
++ return res;
++}
++
++static void aspeed_jtag_set_tap_state(struct aspeed_jtag *aspeed_jtag,
++ enum jtag_tapstate from_state,
++ enum jtag_tapstate end_state)
++{
++ int i = 0;
++ enum jtag_tapstate from, to;
++
++ from = from_state;
++ to = end_state;
++
++ if (from == JTAG_STATE_CURRENT)
++ from = aspeed_jtag->status;
++
++ for (i = 0; i < _tms_cycle_lookup[from][to].count; i++)
++ aspeed_jtag_tck_cycle(aspeed_jtag,
++ ((_tms_cycle_lookup[from][to].tmsbits >> i) & 0x1), 0);
++ aspeed_jtag->status = end_state;
++}
++
++static void aspeed_jtag_set_tap_state_sw(struct aspeed_jtag *aspeed_jtag,
++ struct jtag_tap_state *tapstate)
++{
++ /* SW mode from curent tap state -> to end_state */
++ if (tapstate->reset) {
++ int i = 0;
++
++ for (i = 0; i < ASPEED_JTAG_RESET_CNTR; i++)
++ aspeed_jtag_tck_cycle(aspeed_jtag, 1, 0);
++ aspeed_jtag->status = JTAG_STATE_TLRESET;
++ }
++
++ aspeed_jtag_set_tap_state(aspeed_jtag, tapstate->from,
++ tapstate->endstate);
++}
++
++static int aspeed_jtag_status_set(struct jtag *jtag,
++ struct jtag_tap_state *tapstate)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "Set TAP state: %s\n",
++ end_status_str[tapstate->endstate]);
++#endif
++
++ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) {
++ aspeed_jtag_set_tap_state_sw(aspeed_jtag, tapstate);
++ return 0;
++ }
++
++ /* x TMS high + 1 TMS low */
++ if (tapstate->reset) {
++ /* Disable sw mode */
++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW);
++ mdelay(1);
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_CTL_ENG_EN |
++ ASPEED_JTAG_CTL_ENG_OUT_EN |
++ ASPEED_JTAG_CTL_FORCE_TMS, ASPEED_JTAG_CTRL);
++ mdelay(1);
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_SW_TDIO, ASPEED_JTAG_SW);
++ aspeed_jtag->status = JTAG_STATE_TLRESET;
++ }
++
++ return 0;
++}
++
++static void aspeed_jtag_xfer_sw(struct aspeed_jtag *aspeed_jtag,
++ struct jtag_xfer *xfer, u32 *data)
++{
++ unsigned long remain_xfer = xfer->length;
++ unsigned long shift_bits = 0;
++ unsigned long index = 0;
++ unsigned long tdi;
++ char tdo;
++
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "SW JTAG SHIFT %s, length = %d\n",
++ (xfer->type == JTAG_SIR_XFER) ? "IR" : "DR", xfer->length);
++#endif
++
++ if (xfer->type == JTAG_SIR_XFER)
++ aspeed_jtag_set_tap_state(aspeed_jtag, xfer->from,
++ JTAG_STATE_SHIFTIR);
++ else
++ aspeed_jtag_set_tap_state(aspeed_jtag, xfer->from,
++ JTAG_STATE_SHIFTDR);
++
++ tdi = ASPEED_JTAG_GET_TDI(xfer->direction, data[index]);
++ data[index] = 0;
++ while (remain_xfer > 1) {
++ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 0,
++ tdi & ASPEED_JTAG_DATA_MSB);
++ data[index] |= tdo << (shift_bits %
++ ASPEED_JTAG_DATA_CHUNK_SIZE);
++ tdi >>= 1;
++ shift_bits++;
++ remain_xfer--;
++
++ if (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE == 0) {
++ tdo = 0;
++ index++;
++ tdi = ASPEED_JTAG_GET_TDI(xfer->direction, data[index]);
++ data[index] = 0;
++ }
++ }
++
++ if ((xfer->endstate == (xfer->type == JTAG_SIR_XFER ?
++ JTAG_STATE_SHIFTIR : JTAG_STATE_SHIFTDR))) {
++ /* Stay in Shift IR/DR*/
++ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 0,
++ tdi & ASPEED_JTAG_DATA_MSB);
++ data[index] |= tdo << (shift_bits %
++ ASPEED_JTAG_DATA_CHUNK_SIZE);
++ } else {
++ /* Goto end state */
++ tdo = aspeed_jtag_tck_cycle(aspeed_jtag, 1,
++ tdi & ASPEED_JTAG_DATA_MSB);
++ data[index] |= tdo << (shift_bits %
++ ASPEED_JTAG_DATA_CHUNK_SIZE);
++ aspeed_jtag->status = (xfer->type == JTAG_SIR_XFER) ?
++ JTAG_STATE_EXIT1IR : JTAG_STATE_EXIT1DR;
++ aspeed_jtag_set_tap_state(aspeed_jtag, aspeed_jtag->status,
++ xfer->endstate);
++ }
++}
++
++static int aspeed_jtag_xfer_push_data_26xx(struct aspeed_jtag *aspeed_jtag,
++ enum jtag_xfer_type type, u32 bits_len)
++{
++ int res = 0;
++
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_TRANS_LEN(bits_len),
++ ASPEED_JTAG_CTRL);
++ if (type == JTAG_SIR_XFER) {
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_TRANS_LEN(bits_len) |
++ ASPEED_JTAG_CTL_26XX_INST_EN,
++ ASPEED_JTAG_CTRL);
++ res = aspeed_jtag_wait_instruction_pause(aspeed_jtag);
++ } else {
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_TRANS_LEN(bits_len) |
++ ASPEED_JTAG_CTL_DATA_EN, ASPEED_JTAG_CTRL);
++ res = aspeed_jtag_wait_data_pause_complete(aspeed_jtag);
++ }
++ return res;
++}
++
++static int aspeed_jtag_xfer_push_data(struct aspeed_jtag *aspeed_jtag,
++ enum jtag_xfer_type type, u32 bits_len)
++{
++ int res = 0;
++
++ if (type == JTAG_SIR_XFER) {
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_IOUT_LEN(bits_len),
++ ASPEED_JTAG_CTRL);
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_IOUT_LEN(bits_len) |
++ ASPEED_JTAG_CTL_INST_EN, ASPEED_JTAG_CTRL);
++ res = aspeed_jtag_wait_instruction_pause(aspeed_jtag);
++ } else {
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len),
++ ASPEED_JTAG_CTRL);
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len) |
++ ASPEED_JTAG_CTL_DATA_EN, ASPEED_JTAG_CTRL);
++ res = aspeed_jtag_wait_data_pause_complete(aspeed_jtag);
++ }
++ return res;
++}
++
++static int aspeed_jtag_xfer_push_data_last_26xx(struct aspeed_jtag *aspeed_jtag,
++ enum jtag_xfer_type type,
++ u32 shift_bits)
++{
++ int res = 0;
++
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_TRANS_LEN(shift_bits) |
++ ASPEED_JTAG_CTL_26XX_LASPEED_TRANS, ASPEED_JTAG_CTRL);
++ if (type == JTAG_SIR_XFER) {
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_TRANS_LEN(shift_bits) |
++ ASPEED_JTAG_CTL_26XX_LASPEED_TRANS |
++ ASPEED_JTAG_CTL_26XX_INST_EN,
++ ASPEED_JTAG_CTRL);
++ res = aspeed_jtag_wait_instruction_complete(aspeed_jtag);
++ } else {
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_TRANS_LEN(shift_bits) |
++ ASPEED_JTAG_CTL_26XX_LASPEED_TRANS |
++ ASPEED_JTAG_CTL_DATA_EN,
++ ASPEED_JTAG_CTRL);
++ res = aspeed_jtag_wait_data_complete(aspeed_jtag);
++ }
++ return res;
++}
++
++static int aspeed_jtag_xfer_push_data_last(struct aspeed_jtag *aspeed_jtag,
++ enum jtag_xfer_type type,
++ u32 shift_bits)
++{
++ int res = 0;
++
++ if (type == JTAG_SIR_XFER) {
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_IOUT_LEN(shift_bits) |
++ ASPEED_JTAG_CTL_LASPEED_INST,
++ ASPEED_JTAG_CTRL);
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_IOUT_LEN(shift_bits) |
++ ASPEED_JTAG_CTL_LASPEED_INST |
++ ASPEED_JTAG_CTL_INST_EN,
++ ASPEED_JTAG_CTRL);
++ res = aspeed_jtag_wait_instruction_complete(aspeed_jtag);
++ } else {
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_DOUT_LEN(shift_bits) |
++ ASPEED_JTAG_CTL_LASPEED_DATA,
++ ASPEED_JTAG_CTRL);
++ aspeed_jtag_write(aspeed_jtag,
++ ASPEED_JTAG_DOUT_LEN(shift_bits) |
++ ASPEED_JTAG_CTL_LASPEED_DATA |
++ ASPEED_JTAG_CTL_DATA_EN,
++ ASPEED_JTAG_CTRL);
++ res = aspeed_jtag_wait_data_complete(aspeed_jtag);
++ }
++ return res;
++}
++
++static int aspeed_jtag_xfer_hw(struct aspeed_jtag *aspeed_jtag,
++ struct jtag_xfer *xfer, u32 *data)
++{
++ unsigned long remain_xfer = xfer->length;
++ unsigned long index = 0;
++ char shift_bits;
++ u32 data_reg;
++ u32 scan_end;
++
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev, "HW JTAG SHIFT %s, length = %d\n",
++ (xfer->type == JTAG_SIR_XFER) ? "IR" : "DR", xfer->length);
++#endif
++ data_reg = xfer->type == JTAG_SIR_XFER ?
++ ASPEED_JTAG_INST : ASPEED_JTAG_DATA;
++ if (xfer->endstate == JTAG_STATE_SHIFTIR ||
++ xfer->endstate == JTAG_STATE_SHIFTDR ||
++ xfer->endstate == JTAG_STATE_PAUSEIR ||
++ xfer->endstate == JTAG_STATE_PAUSEDR) {
++ scan_end = 0;
++ } else {
++ scan_end = 1;
++ }
++
++ while (remain_xfer) {
++ if (xfer->direction & JTAG_WRITE_XFER)
++ aspeed_jtag_write(aspeed_jtag, data[index], data_reg);
++ else
++ aspeed_jtag_write(aspeed_jtag, 0, data_reg);
++
++ if (remain_xfer > ASPEED_JTAG_DATA_CHUNK_SIZE) {
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev,
++ "Chunk len=%d chunk_size=%d remain_xfer=%lu\n",
++ xfer->length, ASPEED_JTAG_DATA_CHUNK_SIZE,
++ remain_xfer);
++#endif
++ shift_bits = ASPEED_JTAG_DATA_CHUNK_SIZE;
++
++ /*
++ * Transmit bytes that were not equals to column length
++ * and after the transfer go to Pause IR/DR.
++ */
++ if (aspeed_jtag->llops->xfer_push_data(aspeed_jtag,
++ xfer->type, shift_bits) != 0) {
++ return -EFAULT;
++ }
++ } else {
++ /*
++ * Read bytes equals to column length
++ */
++ shift_bits = remain_xfer;
++ if (scan_end) {
++ /*
++ * If this data is the end of the transmission
++ * send remaining bits and go to endstate
++ */
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev,
++ "Last len=%d chunk_size=%d remain_xfer=%lu\n",
++ xfer->length,
++ ASPEED_JTAG_DATA_CHUNK_SIZE,
++ remain_xfer);
++#endif
++ if (aspeed_jtag->llops->xfer_push_data_last(
++ aspeed_jtag,
++ xfer->type,
++ shift_bits) != 0) {
++ return -EFAULT;
++ }
++ } else {
++ /*
++ * If transmission is waiting for additional
++ * data send remaining bits and then go to
++ * Pause IR/DR.
++ */
++#ifdef DEBUG_JTAG
++ dev_dbg(aspeed_jtag->dev,
++ "Tail len=%d chunk_size=%d remain_xfer=%lu\n",
++ xfer->length,
++ ASPEED_JTAG_DATA_CHUNK_SIZE,
++ remain_xfer);
++#endif
++ if (aspeed_jtag->llops->xfer_push_data(
++ aspeed_jtag,
++ xfer->type,
++ shift_bits)
++ != 0) {
++ return -EFAULT;
++ }
++ }
++ }
++
++ if (xfer->direction & JTAG_READ_XFER) {
++ if (shift_bits < ASPEED_JTAG_DATA_CHUNK_SIZE) {
++ data[index] = aspeed_jtag_read(aspeed_jtag,
++ data_reg);
++
++ data[index] >>= ASPEED_JTAG_DATA_CHUNK_SIZE -
++ shift_bits;
++ } else {
++ data[index] = aspeed_jtag_read(aspeed_jtag,
++ data_reg);
++ }
++ }
++
++ remain_xfer = remain_xfer - shift_bits;
++ index++;
++ }
++ return 0;
++}
++
++static int aspeed_jtag_xfer(struct jtag *jtag, struct jtag_xfer *xfer,
++ u8 *xfer_data)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++
++ if (!(aspeed_jtag->mode & JTAG_XFER_HW_MODE)) {
++ /* SW mode */
++ aspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_TDIO,
++ ASPEED_JTAG_SW);
++
++ aspeed_jtag_xfer_sw(aspeed_jtag, xfer, (u32 *)xfer_data);
++ } else {
++ /* HW mode */
++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW);
++ if (aspeed_jtag_xfer_hw(aspeed_jtag, xfer,
++ (u32 *)xfer_data) != 0)
++ return -EFAULT;
++ }
++
++ aspeed_jtag->status = xfer->endstate;
++ return 0;
++}
++
++static int aspeed_jtag_status_get(struct jtag *jtag, u32 *status)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++
++ *status = aspeed_jtag->status;
++ return 0;
++}
++
++#ifdef USE_INTERRUPTS
++static irqreturn_t aspeed_jtag_interrupt(s32 this_irq, void *dev_id)
++{
++ struct aspeed_jtag *aspeed_jtag = dev_id;
++ irqreturn_t ret = IRQ_HANDLED;
++ u32 status;
++
++ status = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);
++
++ if (status & ASPEED_JTAG_ISR_INT_MASK) {
++ aspeed_jtag_write(aspeed_jtag,
++ (status & ASPEED_JTAG_ISR_INT_MASK)
++ | (status & ASPEED_JTAG_ISR_INT_EN_MASK),
++ ASPEED_JTAG_ISR);
++ aspeed_jtag->flag |= status & ASPEED_JTAG_ISR_INT_MASK;
++ }
++
++ if (aspeed_jtag->flag) {
++ wake_up_interruptible(&aspeed_jtag->jtag_wq);
++ ret = IRQ_HANDLED;
++ } else {
++ dev_err(aspeed_jtag->dev, "irq status:%x\n",
++ status);
++ ret = IRQ_NONE;
++ }
++ return ret;
++}
++#endif
++
++static int aspeed_jtag_enable(struct jtag *jtag)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++
++ aspeed_jtag_master(aspeed_jtag);
++ return 0;
++}
++
++static int aspeed_jtag_disable(struct jtag *jtag)
++{
++ struct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);
++
++ aspeed_jtag_output_disable(aspeed_jtag);
++ return 0;
++}
++
++static int aspeed_jtag_init(struct platform_device *pdev,
++ struct aspeed_jtag *aspeed_jtag)
++{
++ struct resource *res;
++#ifdef USE_INTERRUPTS
++ int err;
++#endif
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ aspeed_jtag->reg_base = devm_ioremap_resource(aspeed_jtag->dev, res);
++ if (IS_ERR(aspeed_jtag->reg_base))
++ return -ENOMEM;
++
++ aspeed_jtag->pclk = devm_clk_get(aspeed_jtag->dev, NULL);
++ if (IS_ERR(aspeed_jtag->pclk)) {
++ dev_err(aspeed_jtag->dev, "devm_clk_get failed\n");
++ return PTR_ERR(aspeed_jtag->pclk);
++ }
++
++#ifdef USE_INTERRUPTS
++ aspeed_jtag->irq = platform_get_irq(pdev, 0);
++ if (aspeed_jtag->irq < 0) {
++ dev_err(aspeed_jtag->dev, "no irq specified\n");
++ return -ENOENT;
++ }
++#endif
++
++ if (clk_prepare_enable(aspeed_jtag->pclk)) {
++ dev_err(aspeed_jtag->dev, "no irq specified\n");
++ return -ENOENT;
++ }
++
++ aspeed_jtag->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
++ if (IS_ERR(aspeed_jtag->rst)) {
++ dev_err(aspeed_jtag->dev,
++ "missing or invalid reset controller device tree entry");
++ return PTR_ERR(aspeed_jtag->rst);
++ }
++ reset_control_deassert(aspeed_jtag->rst);
++
++#ifdef USE_INTERRUPTS
++ err = devm_request_irq(aspeed_jtag->dev, aspeed_jtag->irq,
++ aspeed_jtag_interrupt, 0,
++ "aspeed-jtag", aspeed_jtag);
++ if (err) {
++ dev_err(aspeed_jtag->dev, "unable to get IRQ");
++ clk_disable_unprepare(aspeed_jtag->pclk);
++ return err;
++ }
++#endif
++
++ aspeed_jtag_output_disable(aspeed_jtag);
++
++ aspeed_jtag->flag = 0;
++ aspeed_jtag->mode = 0;
++ init_waitqueue_head(&aspeed_jtag->jtag_wq);
++ return 0;
++}
++
++static int aspeed_jtag_deinit(struct platform_device *pdev,
++ struct aspeed_jtag *aspeed_jtag)
++{
++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_ISR);
++ /* Disable clock */
++ aspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL);
++ reset_control_assert(aspeed_jtag->rst);
++ clk_disable_unprepare(aspeed_jtag->pclk);
++ return 0;
++}
++
++static const struct jtag_ops aspeed_jtag_ops = {
++ .freq_get = aspeed_jtag_freq_get,
++ .freq_set = aspeed_jtag_freq_set,
++ .status_get = aspeed_jtag_status_get,
++ .status_set = aspeed_jtag_status_set,
++ .xfer = aspeed_jtag_xfer,
++ .mode_set = aspeed_jtag_mode_set,
++ .bitbang = aspeed_jtag_bitbang,
++ .enable = aspeed_jtag_enable,
++ .disable = aspeed_jtag_disable
++};
++
++static const struct jtag_low_level_functions ast25xx_llops = {
++ .output_disable = aspeed_jtag_output_disable,
++ .xfer_push_data = aspeed_jtag_xfer_push_data,
++ .xfer_push_data_last = aspeed_jtag_xfer_push_data_last
++};
++
++static struct aspeed_jtag_functions ast25xx_functions = {
++ .aspeed_jtag_ops = &aspeed_jtag_ops,
++ .aspeed_jtag_llops = &ast25xx_llops
++};
++
++static const struct jtag_low_level_functions ast26xx_llops = {
++ .output_disable = aspeed_jtag_output_disable,
++ .xfer_push_data = aspeed_jtag_xfer_push_data_26xx,
++ .xfer_push_data_last = aspeed_jtag_xfer_push_data_last_26xx
++};
++
++static struct aspeed_jtag_functions ast26xx_functions = {
++ .aspeed_jtag_ops = &aspeed_jtag_ops,
++ .aspeed_jtag_llops = &ast26xx_llops
++};
++
++static const struct of_device_id aspeed_jtag_of_match[] = {
++ { .compatible = "aspeed,ast2400-jtag", .data = &ast25xx_functions },
++ { .compatible = "aspeed,ast2500-jtag", .data = &ast25xx_functions },
++ { .compatible = "aspeed,ast2600-jtag", .data = &ast26xx_functions },
++ {}
++};
++
++static int aspeed_jtag_probe(struct platform_device *pdev)
++{
++ struct aspeed_jtag *aspeed_jtag;
++ struct jtag *jtag;
++ const struct of_device_id *match;
++ struct aspeed_jtag_functions *jtag_functions;
++ int err;
++
++ match = of_match_node(aspeed_jtag_of_match, pdev->dev.of_node);
++ if (!match)
++ return -ENODEV;
++ jtag_functions = match->data;
++
++ jtag = jtag_alloc(&pdev->dev, sizeof(*aspeed_jtag),
++ jtag_functions->aspeed_jtag_ops);
++ if (!jtag)
++ return -ENOMEM;
++
++ platform_set_drvdata(pdev, jtag);
++ aspeed_jtag = jtag_priv(jtag);
++ aspeed_jtag->dev = &pdev->dev;
++
++ aspeed_jtag->llops = jtag_functions->aspeed_jtag_llops;
++
++ /* Initialize device*/
++ err = aspeed_jtag_init(pdev, aspeed_jtag);
++ if (err)
++ goto err_jtag_init;
++
++ /* Initialize JTAG core structure*/
++ err = devm_jtag_register(aspeed_jtag->dev, jtag);
++ if (err)
++ goto err_jtag_register;
++
++ return 0;
++
++err_jtag_register:
++ aspeed_jtag_deinit(pdev, aspeed_jtag);
++err_jtag_init:
++ jtag_free(jtag);
++ return err;
++}
++
++static int aspeed_jtag_remove(struct platform_device *pdev)
++{
++ struct jtag *jtag = platform_get_drvdata(pdev);
++
++ aspeed_jtag_deinit(pdev, jtag_priv(jtag));
++ return 0;
++}
++
++static struct platform_driver aspeed_jtag_driver = {
++ .probe = aspeed_jtag_probe,
++ .remove = aspeed_jtag_remove,
++ .driver = {
++ .name = ASPEED_JTAG_NAME,
++ .of_match_table = aspeed_jtag_of_match,
++ },
++};
++module_platform_driver(aspeed_jtag_driver);
++
++MODULE_AUTHOR("Oleksandr Shamray <oleksandrs@mellanox.com>");
++MODULE_DESCRIPTION("ASPEED JTAG driver");
++MODULE_LICENSE("GPL v2");
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0054-Documentation-jtag-Add-bindings-for-Aspeed-SoC.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0054-Documentation-jtag-Add-bindings-for-Aspeed-SoC.patch
new file mode 100644
index 000000000..12073da02
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0054-Documentation-jtag-Add-bindings-for-Aspeed-SoC.patch
@@ -0,0 +1,107 @@
+From 2a22feac440070b7feaf0a6fe7e7e555d57ca19b Mon Sep 17 00:00:00 2001
+From: "Corona, Ernesto" <ernesto.corona@intel.com>
+Date: Wed, 10 Mar 2019 11:45:04 -0800
+Subject: [PATCH] Documentation: jtag: Add bindings for Aspeed SoC
+
+It has been tested on Mellanox system with BMC equipped with
+Aspeed 2520 SoC for programming CPLD devices.
+
+It also has been tested on Intel systems with BMC equipped with
+Aspeed 25x0 SoC for JTAG board communication.
+
+Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
+Signed-off-by: Jiri Pirko <jiri@mellanox.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Joel Stanley <joel@jms.id.au>
+Cc: Andrew Jeffery <andrew@aj.id.au>
+Cc: Steven A Filary <steven.a.filary@intel.com>
+Cc: Bryan Hunt <bryan.hunt@intel.com>
+---
+v28->v29
+v27->v28
+v26->v27
+v25->v26
+v24->v25
+v23->v24
+v22->v23
+v21->v22
+v20->v21
+v19->v20
+v18->v19
+
+v17->v18
+v16->v17
+v15->v16
+Comments pointed by Joel Stanley <joel.stan@gmail.com>
+- change clocks = <&clk_apb> to proper clocks = <&syscon ASPEED_CLK_APB>
+- add reset descriptions in bindings file
+
+v14->v15
+v13->v14
+v12->v13
+v11->v12
+v10->v11
+v9->v10
+v8->v9
+v7->v8
+Comments pointed by pointed by Joel Stanley <joel.stan@gmail.com>
+- Change compatible string to ast2400 and ast2000
+
+V6->v7
+Comments pointed by Tobias Klauser <tklauser@distanz.ch>
+ - Fix spell "Doccumentation" -> "Documentation"
+
+v5->v6
+Comments pointed by Tobias Klauser <tklauser@distanz.ch>
+- Small nit: s/documentation/Documentation/
+
+v4->v5
+
+V3->v4
+Comments pointed by Rob Herring <robh@kernel.org>
+- delete unnecessary "status" and "reg-shift" descriptions in
+ bindings file
+
+v2->v3
+Comments pointed by Rob Herring <robh@kernel.org>
+- split Aspeed jtag driver and binding to separate patches
+- delete unnecessary "status" and "reg-shift" descriptions in
+ bindings file
+---
+ .../devicetree/bindings/jtag/aspeed-jtag.txt | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/jtag/aspeed-jtag.txt
+
+diff --git a/Documentation/devicetree/bindings/jtag/aspeed-jtag.txt b/Documentation/devicetree/bindings/jtag/aspeed-jtag.txt
+new file mode 100644
+index 0000000..7c36eb6
+--- /dev/null
++++ b/Documentation/devicetree/bindings/jtag/aspeed-jtag.txt
+@@ -0,0 +1,22 @@
++Aspeed JTAG driver for ast2400 and ast2500 SoC
++
++Required properties:
++- compatible: Should be one of
++ - "aspeed,ast2400-jtag"
++ - "aspeed,ast2500-jtag"
++- reg contains the offset and length of the JTAG memory
++ region
++- clocks root clock of bus, should reference the APB
++ clock in the second cell
++- resets phandle to reset controller with the reset number in
++ the second cell
++- interrupts should contain JTAG controller interrupt
++
++Example:
++jtag: jtag@1e6e4000 {
++ compatible = "aspeed,ast2500-jtag";
++ reg = <0x1e6e4000 0x1c>;
++ clocks = <&syscon ASPEED_CLK_APB>;
++ resets = <&syscon ASPEED_RESET_JTAG_MASTER>;
++ interrupts = <43>;
++};
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch
new file mode 100644
index 000000000..1e4142035
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0055-Documentation-jtag-Add-ABI-documentation.patch
@@ -0,0 +1,310 @@
+From d4c55bd4eeb6d9290025fa353d1787f18bca6ade Mon Sep 17 00:00:00 2001
+From: "Corona, Ernesto" <ernesto.corona@intel.com>
+Date: Sun, 10 Mar 2019 11:47:40 -0800
+Subject: [PATCH v29 4/6] Documentation: jtag: Add ABI documentation
+
+Added document that describe the ABI for JTAG class driver
+
+Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Jonathan Corbet <corbet@lwn.net>
+Cc: Jiri Pirko <jiri@mellanox.com>
+Cc: Vadim Pasternak <vadimp@mellanox.com>
+Cc: Steven A Filary <steven.a.filary@intel.com>
+Cc: Bryan Hunt <bryan.hunt@intel.com>
+---
+v28->v29
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Expand bitbang function to accept multiples bitbang operations within a
+ single JTAG_IOCBITBANG call. It will receive a buffer with TDI and TMS
+ values and it is expected that driver fills TDO fields with its
+ corresponding output value for every transaction.
+
+v27->v28
+Comments pointed by Steven Filary <steven.a.filary@intel.com>
+- Replace JTAG_IOCRUNTEST with JTAG_SIOCSTATE adding support for all TAPC
+ end states in SW mode using a lookup table to navigate across states.
+- Add support for simultaneous READ/WRITE transfers(JTAG_READ_WRITE_XFER).
+- Support for switching JTAG controller mode between slave and master
+ mode.
+- Setup JTAG controller mode to master only when the driver is opened,
+ letting other HW to own the JTAG bus when it isn't in use.
+- Include JTAG bit bang IOCTL for low level JTAG control usage
+ (JTAG_IOCBITBANG).
+
+v26->v27
+v25->v26
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- fix spell in ABI documentation
+
+v24->v25
+Comments pointed by Greg KH <gregkh@linuxfoundation.org>
+- Fixed documentation according to new open() behavior
+
+v23->v24
+v22->v23
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- fix spell in ABI doccumentation
+
+v21->v22
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- fix spell in ABI doccumentation
+
+v20->v21
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- Fix JTAG dirver help in Kconfig
+
+v19->v20
+Comments pointed by Randy Dunlap <rdunlap@infradead.org>
+- Fix JTAG doccumentation
+
+v18->v19
+Pavel Machek <pavel@ucw.cz>
+- Added JTAG doccumentation to Documentation/jtag
+
+v17->v18
+v16->v17
+v15->v16
+v14->v15
+v13->v14
+v12->v13
+v11->v12 Tobias Klauser <tklauser@distanz.ch>
+Comments pointed by
+- rename /Documentation/ABI/testing/jatg-dev -> jtag-dev
+- Typo: s/interfase/interface
+v10->v11
+v9->v10
+Fixes added by Oleksandr:
+- change jtag-cdev to jtag-dev in documentation
+- update KernelVersion and Date in jtag-dev documentation;
+v8->v9
+v7->v8
+v6->v7
+Comments pointed by Pavel Machek <pavel@ucw.cz>
+- Added jtag-cdev documentation to Documentation/ABI/testing folder
+---
+ Documentation/ABI/testing/jtag-dev | 23 ++++++
+ Documentation/jtag/overview | 27 +++++++
+ Documentation/jtag/transactions | 145 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 195 insertions(+)
+ create mode 100644 Documentation/ABI/testing/jtag-dev
+ create mode 100644 Documentation/jtag/overview
+ create mode 100644 Documentation/jtag/transactions
+
+diff --git a/Documentation/ABI/testing/jtag-dev b/Documentation/ABI/testing/jtag-dev
+new file mode 100644
+index 000000000000..423baab18761
+--- /dev/null
++++ b/Documentation/ABI/testing/jtag-dev
+@@ -0,0 +1,23 @@
++What: /dev/jtag[0-9]+
++Date: July 2018
++KernelVersion: 4.20
++Contact: oleksandrs@mellanox.com
++Description:
++ The misc device files /dev/jtag* are the interface
++ between JTAG master interface and userspace.
++
++ The ioctl(2)-based ABI is defined and documented in
++ [include/uapi]<linux/jtag.h>.
++
++ The following file operations are supported:
++
++ open(2)
++ Opens and allocates file descriptor.
++
++ ioctl(2)
++ Initiate various actions.
++ See the inline documentation in [include/uapi]<linux/jtag.h>
++ for descriptions of all ioctls.
++
++Users:
++ userspace tools which wants to access to JTAG bus
+diff --git a/Documentation/jtag/overview b/Documentation/jtag/overview
+new file mode 100644
+index 000000000000..6a5ec335e313
+--- /dev/null
++++ b/Documentation/jtag/overview
+@@ -0,0 +1,27 @@
++Linux kernel JTAG support
++=========================
++
++JTAG is an industry standard for verifying hardware. JTAG provides access to
++many logic signals of a complex integrated circuit, including the device pins.
++
++A JTAG interface is a special interface added to a chip.
++Depending on the version of JTAG, two, four, or five pins are added.
++
++The connector pins are:
++ TDI (Test Data In)
++ TDO (Test Data Out)
++ TCK (Test Clock)
++ TMS (Test Mode Select)
++ TRST (Test Reset) optional
++
++JTAG interface is designed to have two parts - basic core driver and
++hardware specific driver. The basic driver introduces a general interface
++which is not dependent of specific hardware. It provides communication
++between user space and hardware specific driver.
++Each JTAG device is represented as a char device from (jtag0, jtag1, ...).
++Access to a JTAG device is performed through IOCTL calls.
++
++Call flow example:
++User: open -> /dev/jatgX -> JTAG core driver -> JTAG hardware specific driver
++User: ioctl -> /dev/jtagX -> JTAG core driver -> JTAG hardware specific driver
++User: close -> /dev/jatgX -> JTAG core driver -> JTAG hardware specific driver
+diff --git a/Documentation/jtag/transactions b/Documentation/jtag/transactions
+new file mode 100644
+index 000000000000..f5d4a1ded6cf
+--- /dev/null
++++ b/Documentation/jtag/transactions
+@@ -0,0 +1,145 @@
++The JTAG API
++=============
++
++JTAG master devices can be accessed through a character misc-device.
++Each JTAG master interface can be accessed by using /dev/jtagN.
++
++JTAG system calls set:
++- SIR (Scan Instruction Register, IEEE 1149.1 Instruction Register scan);
++- SDR (Scan Data Register, IEEE 1149.1 Data Register scan);
++- RUNTEST (Forces the IEEE 1149.1 bus to a run state for a specified
++number of clocks.
++
++open(), close()
++-------
++open() opens JTAG device.
++
++Open/Close device:
++- jtag_fd = open("/dev/jtag0", O_RDWR);
++- close(jtag_fd);
++
++ioctl()
++-------
++All access operations to JTAG devices are performed through ioctl interface.
++The IOCTL interface supports these requests:
++ JTAG_SIOCSTATE - Force JTAG state machine to go into a TAPC state
++ JTAG_SIOCFREQ - Set JTAG TCK frequency
++ JTAG_GIOCFREQ - Get JTAG TCK frequency
++ JTAG_IOCXFER - send/receive JTAG data Xfer
++ JTAG_GIOCSTATUS - get current JTAG TAP state
++ JTAG_SIOCMODE - set JTAG mode flags.
++ JTAG_IOCBITBANG - JTAG bitbang low level control.
++
++JTAG_SIOCFREQ, JTAG_GIOCFREQ
++------
++Set/Get JTAG clock speed:
++
++ unsigned int jtag_fd;
++ ioctl(jtag_fd, JTAG_SIOCFREQ, &frq);
++ ioctl(jtag_fd, JTAG_GIOCFREQ, &frq);
++
++JTAG_SIOCSTATE
++------
++Force JTAG state machine to go into a TAPC state
++
++struct jtag_tap_state {
++ __u8 reset;
++ __u8 from;
++ __u8 endstate;
++ __u8 tck;
++};
++
++reset:
++ JTAG_NO_RESET - go through selected endstate from current state
++ JTAG_FORCE_RESET - go through TEST_LOGIC/RESET state before selected endstate
++endstate: completion flag
++tck: clock counter
++
++Example:
++ struct jtag_tap_state tap_state;
++
++ tap_state.from = JTAG_STATE_TLRESET;
++ tap_state.endstate = JTAG_STATE_IDLE;
++ tap_state.reset = 0;
++ tap_state.tck = data_p->tck;
++ usleep(25 * 1000);
++ ioctl(jtag_fd, JTAG_SIOCSTATE, &tap_state);
++
++JTAG_GIOCSTATUS
++------
++Get JTAG TAPC machine state
++
++ unsigned int jtag_fd;
++ jtag_tapstate tapstate;
++ ioctl(jtag_fd, JTAG_GIOCSTATUS, &tapstate);
++
++JTAG_IOCXFER
++------
++Send SDR/SIR transaction
++
++struct jtag_xfer {
++ __u8 type;
++ __u8 direction;
++ __u8 from;
++ __u8 endstate;
++ __u8 padding;
++ __u32 length;
++ __u64 tdio;
++};
++
++type: transfer type - JTAG_SIR_XFER/JTAG_SDR_XFER
++direction: xfer direction - JTAG_READ_XFER/JTAG_WRITE_XFER/JTAG_READ_WRITE_XFER
++length: xfer data length in bits
++tdio : xfer data array
++from: xfer from state can be current JTAG tap state saved by the driver
++ JTAG_STATE_CURRENT or in a multichain environment any state listed in
++ jtag_tapstate struct saved by your multichain controller software.
++endstate: xfer end state after transaction finish
++ can be: any state listed in jtag_tapstate struct
++
++Example:
++ struct jtag_xfer xfer;
++ static char buf[64];
++ static unsigned int buf_len = 0;
++ [...]
++ xfer.type = JTAG_SDR_XFER;
++ xfer.tdio = (__u64)buf;
++ xfer.length = buf_len;
++ xfer.from = JTAG_STATE_TLRESET;
++ xfer.endstate = JTAG_STATE_IDLE;
++
++ if (is_read)
++ xfer.direction = JTAG_READ_XFER;
++ else if (is_write)
++ xfer.direction = JTAG_WRITE_XFER;
++ else
++ xfer.direction = JTAG_READ_WRITE_XFER;
++
++ ioctl(jtag_fd, JTAG_IOCXFER, &xfer);
++
++JTAG_SIOCMODE
++------
++If hardware driver can support different running modes you can change it.
++
++Example:
++ struct jtag_mode mode;
++ mode.feature = JTAG_XFER_MODE;
++ mode.mode = JTAG_XFER_HW_MODE;
++ ioctl(jtag_fd, JTAG_SIOCMODE, &mode);
++
++JTAG_IOCBITBANG
++------
++JTAG Bitbang low level operation.
++
++Example:
++ struct bitbang_packet bitbang;
++ struct tck_bitbang bitbang_data[2];
++ bitbang_data[0].tms = 0;
++ bitbang_data[0].tdi = 1;
++ bitbang_data[1].tms = 0;
++ bitbang_data[1].tdi = 1;
++ bitbang.data = bitbang_data;
++ bitbang.length = 2;
++ ioctl(jtag_fd, JTAG_IOCBITBANG, &bitbang);
++ tdo0 = bitbang_data[0].tdo;
++ tdo1 = bitbang_data[1].tdo;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch
new file mode 100644
index 000000000..99cc318ab
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch
@@ -0,0 +1,57 @@
+From 8618c2cd920d10681859bacf8af56c71f168b5a2 Mon Sep 17 00:00:00 2001
+From: "Corona, Ernesto" <ernesto.corona@intel.com>
+Date: Sun, 10 Mar 2019 11:48:18 -0800
+Subject: [PATCH] Documentation jtag: Add JTAG core driver ioctl number
+
+JTAG class driver provide infrastructure to support hardware/software
+JTAG platform drivers. It provide user layer API interface for flashing
+and debugging external devices which equipped with JTAG interface
+using standard transactions.
+
+Driver exposes set of IOCTL to user space for:
+- XFER:
+ SIR (Scan Instruction Register, IEEE 1149.1 Data Register scan);
+ SDR (Scan Data Register, IEEE 1149.1 Instruction Register scan);
+- GIOCSTATUS read the current TAPC state of the JTAG controller
+- SIOCSTATE Forces the JTAG TAPC to go into a particular state.
+- SIOCFREQ/GIOCFREQ for setting and reading JTAG frequency.
+- IOCBITBANG for low level control of JTAG signals.
+
+Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+Acked-by: Philippe Ombredanne <pombredanne@nexb.com>
+Cc: Jiri Pirko <jiri@mellanox.com>
+Cc: Vadim Pasternak <vadimp@mellanox.com>
+Cc: Jonathan Corbet <corbet@lwn.net>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Kishon Vijay Abraham I <kishon@ti.com>
+Cc: Darrick J. Wong <darrick.wong@oracle.com>
+Cc: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
+Cc: Eric Sandeen <sandeen@redhat.com>
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Cc: Tomohiro Kusumi <kusumi.tomohiro@gmail.com>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Steven A Filary <steven.a.filary@intel.com>
+Cc: Bryan Hunt <bryan.hunt@intel.com>
+---
+ Documentation/ioctl/ioctl-number.rst | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/Documentation/ioctl/ioctl-number.rst b/Documentation/ioctl/ioctl-number.rst
+index de23fc0f0fce..339d198c5adf 100644
+--- a/Documentation/ioctl/ioctl-number.rst
++++ b/Documentation/ioctl/ioctl-number.rst
+@@ -333,6 +333,8 @@ Code Seq# Include File Comments
+ <mailto:vgo@ratio.de>
+ 0xB1 00-1F PPPoX
+ <mailto:mostrows@styx.uwaterloo.ca>
++0xB2 00-0F linux/jtag.h JTAG driver
++ <mailto:oleksandrs@mellanox.com>
+ 0xB3 00 linux/mmc/ioctl.h
+ 0xB4 00-0F linux/gpio.h <mailto:linux-gpio@vger.kernel.org>
+ 0xB5 00-0F uapi/linux/rpmsg.h <mailto:linux-remoteproc@vger.kernel.org>
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch
new file mode 100644
index 000000000..9ff92d8ec
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch
@@ -0,0 +1,50 @@
+From fcf8f7fd3cb4e0b08cb1540f9ff9e5988cd285d1 Mon Sep 17 00:00:00 2001
+From: "Corona, Ernesto" <ernesto.corona@intel.com>
+Date: Sun, 10 Mar 2019 11:49:37 -0800
+Subject: [PATCH] drivers: jtag: Add JTAG core driver Maintainers
+
+JTAG class driver provide infrastructure to support hardware/software
+JTAG platform drivers. It provide user layer API interface for flashing
+and debugging external devices which equipped with JTAG interface
+using standard transactions.
+
+Signed-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>
+Signed-off-by: Corona, Ernesto <ernesto.corona@intel.com>
+Acked-by: Arnd Bergmann <arnd@arndb.de>
+Cc: Jiri Pirko <jiri@mellanox.com>
+Cc: Vadim Pasternak <vadimp@mellanox.com>
+Cc: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: David S. Miller <davem@davemloft.net>
+Cc: Nicolas Ferre <nicolas.ferre@microchip.com>
+Cc: Steven A Filary <steven.a.filary@intel.com>
+Cc: Bryan Hunt <bryan.hunt@intel.com>
+---
+ MAINTAINERS | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 3bbdae50eb7e..34ab3522801c 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -8819,6 +8819,17 @@ L: linux-serial@vger.kernel.org
+ S: Orphan
+ F: drivers/tty/serial/jsm/
+
++JTAG SUBSYSTEM
++M: Oleksandr Shamray <oleksandrs@mellanox.com>
++M: Vadim Pasternak <vadimp@mellanox.com>
++M Ernesto Corona <ernesto.corona@intel.com>
++S: Maintained
++F: include/linux/jtag.h
++F: include/uapi/linux/jtag.h
++F: drivers/jtag/
++F: Documentation/devicetree/bindings/jtag/
++F: Documentation/ABI/testing/jtag-dev
++
+ K10TEMP HARDWARE MONITORING DRIVER
+ M: Clemens Ladisch <clemens@ladisch.de>
+ L: linux-hwmon@vger.kernel.org
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-i2c-aspeed-add-buffer-mode-transfer-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-i2c-aspeed-add-buffer-mode-transfer-support.patch
new file mode 100644
index 000000000..fbf422a35
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0061-i2c-aspeed-add-buffer-mode-transfer-support.patch
@@ -0,0 +1,1148 @@
+From b8d7d0f3513abdf014345b240a79d23c63409c4c Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 11 Jun 2019 15:07:08 -0700
+Subject: [PATCH] i2c: aspeed: add buffer mode transfer support
+
+Byte mode currently this driver uses makes lots of interrupt call
+which isn't good for performance and it makes the driver very
+timing sensitive. To improve performance of the driver, this commit
+adds buffer mode transfer support which uses I2C SRAM buffer
+instead of using a single byte buffer.
+
+AST2400:
+It has 2 KBytes (256 Bytes x 8 pages) of I2C SRAM buffer pool from
+0x1e78a800 to 0x1e78afff that can be used for all busses with
+buffer pool manipulation. To simplify implementation for supporting
+both AST2400 and AST2500, it assigns each 128 Bytes per bus without
+using buffer pool manipulation so total 1792 Bytes of I2C SRAM
+buffer will be used.
+
+AST2500:
+It has 16 Bytes of individual I2C SRAM buffer per each bus and its
+range is from 0x1e78a200 to 0x1e78a2df, so it doesn't have 'buffer
+page selection' bit field in the Function control register, and
+neither 'base address pointer' bit field in the Pool buffer control
+register it has. To simplify implementation for supporting both
+AST2400 and AST2500, it writes zeros on those register bit fields
+but it's okay because it does nothing in AST2500.
+
+It provides buffer based master and slave data transfer.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ .../devicetree/bindings/i2c/i2c-aspeed.txt | 40 ++-
+ arch/arm/boot/dts/aspeed-g4.dtsi | 47 +--
+ arch/arm/boot/dts/aspeed-g5.dtsi | 47 +--
+ arch/arm/boot/dts/aspeed-g6.dtsi | 32 +-
+ drivers/i2c/busses/i2c-aspeed.c | 376 +++++++++++++++++++--
+ 5 files changed, 451 insertions(+), 91 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+index 7da7e813b2b0..0ff3539cee95 100644
+--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+@@ -3,7 +3,10 @@ Device tree configuration for the I2C busses on the AST24XX and AST25XX SoCs.
+ Required Properties:
+ - #address-cells : should be 1
+ - #size-cells : should be 0
+-- reg : address offset and range of bus
++- reg : Address offset and range of bus registers.
++ An additional SRAM buffer address offset and range is
++ optional in case of enabling I2C dedicated SRAM for
++ buffer mode transfer support.
+ - compatible : should be "aspeed,ast2400-i2c-bus"
+ or "aspeed,ast2500-i2c-bus"
+ - clocks : root clock of bus, should reference the APB
+@@ -28,12 +31,21 @@ i2c {
+ #size-cells = <1>;
+ ranges = <0 0x1e78a000 0x1000>;
+
+- i2c_ic: interrupt-controller@0 {
+- #interrupt-cells = <1>;
+- compatible = "aspeed,ast2400-i2c-ic";
++ i2c_gr: i2c-global-regs@0 {
++ compatible = "aspeed,ast2500-i2c-gr", "syscon";
+ reg = <0x0 0x40>;
+- interrupts = <12>;
+- interrupt-controller;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges = <0x0 0x0 0x40>;
++
++ i2c_ic: interrupt-controller@0 {
++ #interrupt-cells = <1>;
++ compatible = "aspeed,ast2500-i2c-ic";
++ reg = <0x0 0x4>;
++ interrupts = <12>;
++ interrupt-controller;
++ };
+ };
+
+ i2c0: i2c-bus@40 {
+@@ -41,11 +53,25 @@ i2c {
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x40 0x40>;
+- compatible = "aspeed,ast2400-i2c-bus";
++ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ bus-frequency = <100000>;
+ interrupts = <0>;
+ interrupt-parent = <&i2c_ic>;
+ };
++
++ /* buffer mode transfer enabled */
++ i2c1: i2c-bus@80 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ #interrupt-cells = <1>;
++ reg = <0x80 0x40>, <0x210 0x10>;
++ compatible = "aspeed,ast2500-i2c-bus";
++ clocks = <&syscon ASPEED_CLK_APB>;
++ resets = <&syscon ASPEED_RESET_I2C>;
++ bus-frequency = <100000>;
++ interrupts = <1>;
++ interrupt-parent = <&i2c_ic>;
++ };
+ };
+diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
+index fc6f4e009db7..0b30c8546e64 100644
+--- a/arch/arm/boot/dts/aspeed-g4.dtsi
++++ b/arch/arm/boot/dts/aspeed-g4.dtsi
+@@ -518,12 +518,21 @@
+ };
+
+ &i2c {
+- i2c_ic: interrupt-controller@0 {
+- #interrupt-cells = <1>;
+- compatible = "aspeed,ast2400-i2c-ic";
++ i2c_gr: i2c-global-regs@0 {
++ compatible = "aspeed,ast2400-i2c-gr", "syscon";
+ reg = <0x0 0x40>;
+- interrupts = <12>;
+- interrupt-controller;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges = <0x0 0x0 0x40>;
++
++ i2c_ic: interrupt-controller@0 {
++ #interrupt-cells = <1>;
++ compatible = "aspeed,ast2400-i2c-ic";
++ reg = <0x0 0x4>;
++ interrupts = <12>;
++ interrupt-controller;
++ };
+ };
+
+ i2c0: i2c-bus@40 {
+@@ -531,7 +540,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x40 0x40>;
++ reg = <0x40 0x40>, <0x800 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -547,7 +556,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x80 0x40>;
++ reg = <0x80 0x40>, <0x880 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -563,7 +572,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0xc0 0x40>;
++ reg = <0xc0 0x40>, <0x900 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -580,7 +589,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x100 0x40>;
++ reg = <0x100 0x40>, <0x980 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -597,7 +606,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x140 0x40>;
++ reg = <0x140 0x40>, <0xa00 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -614,7 +623,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x180 0x40>;
++ reg = <0x180 0x40>, <0xa80 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -631,7 +640,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x1c0 0x40>;
++ reg = <0x1c0 0x40>, <0xb00 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -648,7 +657,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x300 0x40>;
++ reg = <0x300 0x40>, <0xb80 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -665,7 +674,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x340 0x40>;
++ reg = <0x340 0x40>, <0xc00 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -682,7 +691,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x380 0x40>;
++ reg = <0x380 0x40>, <0xc80 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -699,7 +708,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x3c0 0x40>;
++ reg = <0x3c0 0x40>, <0xd00 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -716,7 +725,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x400 0x40>;
++ reg = <0x400 0x40>, <0xd80 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -733,7 +742,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x440 0x40>;
++ reg = <0x440 0x40>, <0xe00 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -750,7 +759,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x480 0x40>;
++ reg = <0x480 0x40>, <0xe80 0x80>;
+ compatible = "aspeed,ast2400-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
+index eb1f9c9d9cca..51593a0a8a23 100644
+--- a/arch/arm/boot/dts/aspeed-g5.dtsi
++++ b/arch/arm/boot/dts/aspeed-g5.dtsi
+@@ -615,12 +615,21 @@
+ };
+
+ &i2c {
+- i2c_ic: interrupt-controller@0 {
+- #interrupt-cells = <1>;
+- compatible = "aspeed,ast2500-i2c-ic";
++ i2c_gr: i2c-global-regs@0 {
++ compatible = "aspeed,ast2500-i2c-gr", "syscon";
+ reg = <0x0 0x40>;
+- interrupts = <12>;
+- interrupt-controller;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges = <0x0 0x0 0x40>;
++
++ i2c_ic: interrupt-controller@0 {
++ #interrupt-cells = <1>;
++ compatible = "aspeed,ast2500-i2c-ic";
++ reg = <0x0 0x4>;
++ interrupts = <12>;
++ interrupt-controller;
++ };
+ };
+
+ i2c0: i2c-bus@40 {
+@@ -628,7 +637,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x40 0x40>;
++ reg = <0x40 0x40>, <0x200 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -644,7 +653,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x80 0x40>;
++ reg = <0x80 0x40>, <0x210 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -660,7 +669,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0xc0 0x40>;
++ reg = <0xc0 0x40>, <0x220 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -677,7 +686,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x100 0x40>;
++ reg = <0x100 0x40>, <0x230 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -694,7 +703,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x140 0x40>;
++ reg = <0x140 0x40>, <0x240 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -711,7 +720,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x180 0x40>;
++ reg = <0x180 0x40>, <0x250 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -728,7 +737,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x1c0 0x40>;
++ reg = <0x1c0 0x40>, <0x260 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -745,7 +754,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x300 0x40>;
++ reg = <0x300 0x40>, <0x270 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -762,7 +771,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x340 0x40>;
++ reg = <0x340 0x40>, <0x280 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -779,7 +788,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x380 0x40>;
++ reg = <0x380 0x40>, <0x290 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -796,7 +805,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x3c0 0x40>;
++ reg = <0x3c0 0x40>, <0x2a0 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -813,7 +822,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x400 0x40>;
++ reg = <0x400 0x40>, <0x2b0 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -830,7 +839,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x440 0x40>;
++ reg = <0x440 0x40>, <0x2c0 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -847,7 +856,7 @@
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+
+- reg = <0x480 0x40>;
++ reg = <0x480 0x40>, <0x2d0 0x10>;
+ compatible = "aspeed,ast2500-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index f92a2aa999d1..3ef312543269 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -712,7 +712,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x80 0x80>;
++ reg = <0x80 0x80>, <0xc00 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -727,7 +727,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x100 0x80>;
++ reg = <0x100 0x80>, <0xc20 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -742,7 +742,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x180 0x80>;
++ reg = <0x180 0x80>, <0xc40 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -757,7 +757,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x200 0x80>;
++ reg = <0x200 0x80>, <0xc60 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -772,7 +772,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x280 0x80>;
++ reg = <0x280 0x80>, <0xc80 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -787,7 +787,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x300 0x80>;
++ reg = <0x300 0x80>, <0xca0 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -802,7 +802,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x380 0x80>;
++ reg = <0x380 0x80>, <0xcc0 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -817,7 +817,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x400 0x80>;
++ reg = <0x400 0x80>, <0xce0 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -832,7 +832,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x480 0x80>;
++ reg = <0x480 0x80>, <0xd00 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -847,7 +847,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x500 0x80>;
++ reg = <0x500 0x80>, <0xd20 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -862,7 +862,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x580 0x80>;
++ reg = <0x580 0x80>, <0xd40 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -877,7 +877,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x600 0x80>;
++ reg = <0x600 0x80>, <0xd60 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -892,7 +892,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x680 0x80>;
++ reg = <0x680 0x80>, <0xd80 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -907,7 +907,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x700 0x80>;
++ reg = <0x700 0x80>, <0xda0 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -922,7 +922,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x780 0x80>;
++ reg = <0x780 0x80>, <0xdc0 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+@@ -937,7 +937,7 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+- reg = <0x800 0x80>;
++ reg = <0x800 0x80>, <0xde0 0x20>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index 7becfcd67142..bf72e151d11f 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -7,6 +7,7 @@
+ * Copyright 2017 Google, Inc.
+ */
+
++#include <linux/bitfield.h>
+ #include <linux/clk.h>
+ #include <linux/completion.h>
+ #include <linux/err.h>
+@@ -19,15 +20,24 @@
+ #include <linux/irqchip/chained_irq.h>
+ #include <linux/irqdomain.h>
+ #include <linux/kernel.h>
++#include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/of_address.h>
+ #include <linux/of_irq.h>
+ #include <linux/of_platform.h>
+ #include <linux/platform_device.h>
++#include <linux/regmap.h>
+ #include <linux/reset.h>
+ #include <linux/slab.h>
+
+-/* I2C Register */
++/* I2C Global Registers */
++/* 0x00 : I2CG Interrupt Status Register */
++/* 0x08 : I2CG Interrupt Target Assignment */
++/* 0x0c : I2CG Global Control Register (AST2500) */
++#define ASPEED_I2CG_GLOBAL_CTRL_REG 0x0c
++#define ASPEED_I2CG_SRAM_BUFFER_EN BIT(0)
++
++/* I2C Bus Registers */
+ #define ASPEED_I2C_FUN_CTRL_REG 0x00
+ #define ASPEED_I2C_AC_TIMING_REG1 0x04
+ #define ASPEED_I2C_AC_TIMING_REG2 0x08
+@@ -35,14 +45,12 @@
+ #define ASPEED_I2C_INTR_STS_REG 0x10
+ #define ASPEED_I2C_CMD_REG 0x14
+ #define ASPEED_I2C_DEV_ADDR_REG 0x18
++#define ASPEED_I2C_BUF_CTRL_REG 0x1c
+ #define ASPEED_I2C_BYTE_BUF_REG 0x20
+
+-/* Global Register Definition */
+-/* 0x00 : I2C Interrupt Status Register */
+-/* 0x08 : I2C Interrupt Target Assignment */
+-
+ /* Device Register Definition */
+ /* 0x00 : I2CD Function Control Register */
++#define ASPEED_I2CD_BUFFER_PAGE_SEL_MASK GENMASK(22, 20)
+ #define ASPEED_I2CD_MULTI_MASTER_DIS BIT(15)
+ #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8)
+ #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7)
+@@ -102,6 +110,8 @@
+ #define ASPEED_I2CD_BUS_RECOVER_CMD BIT(11)
+
+ /* Command Bit */
++#define ASPEED_I2CD_RX_BUFF_ENABLE BIT(7)
++#define ASPEED_I2CD_TX_BUFF_ENABLE BIT(6)
+ #define ASPEED_I2CD_M_STOP_CMD BIT(5)
+ #define ASPEED_I2CD_M_S_RX_CMD_LAST BIT(4)
+ #define ASPEED_I2CD_M_RX_CMD BIT(3)
+@@ -118,6 +128,13 @@
+ /* 0x18 : I2CD Slave Device Address Register */
+ #define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0)
+
++/* 0x1c : I2CD Buffer Control Register */
++/* Use 8-bits or 6-bits wide bit fileds to support both AST2400 and AST2500 */
++#define ASPEED_I2CD_BUF_RX_COUNT_MASK GENMASK(31, 24)
++#define ASPEED_I2CD_BUF_RX_SIZE_MASK GENMASK(23, 16)
++#define ASPEED_I2CD_BUF_TX_COUNT_MASK GENMASK(15, 8)
++#define ASPEED_I2CD_BUF_OFFSET_MASK GENMASK(5, 0)
++
+ enum aspeed_i2c_master_state {
+ ASPEED_I2C_MASTER_INACTIVE,
+ ASPEED_I2C_MASTER_PENDING,
+@@ -163,6 +180,11 @@ struct aspeed_i2c_bus {
+ int master_xfer_result;
+ /* Multi-master */
+ bool multi_master;
++ /* Buffer mode */
++ void __iomem *buf_base;
++ u8 buf_offset;
++ u8 buf_page;
++ size_t buf_size;
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
+ struct i2c_client *slave;
+ enum aspeed_i2c_slave_state slave_state;
+@@ -255,6 +277,77 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
+ }
+
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
++static inline void
++aspeed_i2c_slave_handle_rx_done(struct aspeed_i2c_bus *bus, u32 irq_status,
++ u8 *value)
++{
++ if (bus->buf_base &&
++ bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED &&
++ !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))
++ *value = readb(bus->buf_base);
++ else
++ *value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
++}
++
++static inline void
++aspeed_i2c_slave_handle_normal_stop(struct aspeed_i2c_bus *bus, u32 irq_status,
++ u8 *value)
++{
++ int i, len;
++
++ if (bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED &&
++ irq_status & ASPEED_I2CD_INTR_RX_DONE) {
++ if (bus->buf_base) {
++ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK,
++ readl(bus->base +
++ ASPEED_I2C_BUF_CTRL_REG));
++ for (i = 0; i < len; i++) {
++ *value = readb(bus->buf_base + i);
++ i2c_slave_event(bus->slave,
++ I2C_SLAVE_WRITE_RECEIVED,
++ value);
++ }
++ }
++ }
++}
++
++static inline void
++aspeed_i2c_slave_handle_write_requested(struct aspeed_i2c_bus *bus, u8 *value)
++{
++ if (bus->buf_base) {
++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK,
++ bus->buf_size - 1) |
++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK,
++ bus->buf_offset),
++ bus->base + ASPEED_I2C_BUF_CTRL_REG);
++ writel(ASPEED_I2CD_RX_BUFF_ENABLE,
++ bus->base + ASPEED_I2C_CMD_REG);
++ }
++}
++
++static inline void
++aspeed_i2c_slave_handle_write_received(struct aspeed_i2c_bus *bus, u8 *value)
++{
++ int i, len;
++
++ if (bus->buf_base) {
++ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK,
++ readl(bus->base +
++ ASPEED_I2C_BUF_CTRL_REG));
++ for (i = 1; i < len; i++) {
++ *value = readb(bus->buf_base + i);
++ i2c_slave_event(bus->slave, I2C_SLAVE_WRITE_RECEIVED,
++ value);
++ }
++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK,
++ bus->buf_size - 1) |
++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, bus->buf_offset),
++ bus->base + ASPEED_I2C_BUF_CTRL_REG);
++ writel(ASPEED_I2CD_RX_BUFF_ENABLE,
++ bus->base + ASPEED_I2C_CMD_REG);
++ }
++}
++
+ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ {
+ u32 command, irq_handled = 0;
+@@ -281,7 +374,7 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+
+ /* Slave was sent something. */
+ if (irq_status & ASPEED_I2CD_INTR_RX_DONE) {
+- value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
++ aspeed_i2c_slave_handle_rx_done(bus, irq_status, &value);
+ /* Handle address frame. */
+ if (bus->slave_state == ASPEED_I2C_SLAVE_START) {
+ if (value & 0x1)
+@@ -296,9 +389,11 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+
+ /* Slave was asked to stop. */
+ if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
++ aspeed_i2c_slave_handle_normal_stop(bus, irq_status, &value);
+ irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP;
+ bus->slave_state = ASPEED_I2C_SLAVE_STOP;
+ }
++
+ if (irq_status & ASPEED_I2CD_INTR_TX_NAK &&
+ bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) {
+ irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
+@@ -328,9 +423,11 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ case ASPEED_I2C_SLAVE_WRITE_REQUESTED:
+ bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED;
+ i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value);
++ aspeed_i2c_slave_handle_write_requested(bus, &value);
+ break;
+ case ASPEED_I2C_SLAVE_WRITE_RECEIVED:
+ i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value);
++ aspeed_i2c_slave_handle_write_received(bus, &value);
+ break;
+ case ASPEED_I2C_SLAVE_STOP:
+ i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
+@@ -350,12 +447,76 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ }
+ #endif /* CONFIG_I2C_SLAVE */
+
++static inline u32
++aspeed_i2c_prepare_rx_buf(struct aspeed_i2c_bus *bus, struct i2c_msg *msg)
++{
++ u32 command = 0;
++ int len;
++
++ if (msg->len > bus->buf_size) {
++ len = bus->buf_size;
++ } else {
++ len = msg->len;
++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
++ }
++
++ if (bus->buf_base) {
++ command |= ASPEED_I2CD_RX_BUFF_ENABLE;
++
++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, len - 1) |
++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, bus->buf_offset),
++ bus->base + ASPEED_I2C_BUF_CTRL_REG);
++ }
++
++ return command;
++}
++
++static inline u32
++aspeed_i2c_prepare_tx_buf(struct aspeed_i2c_bus *bus, struct i2c_msg *msg)
++{
++ u8 slave_addr = i2c_8bit_addr_from_msg(msg);
++ u32 command = 0;
++ int len;
++
++ if (msg->len + 1 > bus->buf_size)
++ len = bus->buf_size;
++ else
++ len = msg->len + 1;
++
++ if (bus->buf_base) {
++ u8 wbuf[4];
++ int i;
++
++ command |= ASPEED_I2CD_TX_BUFF_ENABLE;
++
++ /*
++ * Yeah, it looks bad but byte writing on remapped I2C SRAM
++ * causes corruption so use this way to make dword writings.
++ */
++ wbuf[0] = slave_addr;
++ for (i = 1; i < len; i++) {
++ wbuf[i % 4] = msg->buf[i - 1];
++ if (i % 4 == 3)
++ writel(*(u32 *)wbuf, bus->buf_base + i - 3);
++ }
++ if (--i % 4 != 3)
++ writel(*(u32 *)wbuf, bus->buf_base + i - (i % 4));
++
++ writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, len - 1) |
++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, bus->buf_offset),
++ bus->base + ASPEED_I2C_BUF_CTRL_REG);
++ }
++
++ bus->buf_index = len - 1;
++
++ return command;
++}
++
+ /* precondition: bus.lock has been acquired. */
+ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus)
+ {
+ u32 command = ASPEED_I2CD_M_START_CMD | ASPEED_I2CD_M_TX_CMD;
+ struct i2c_msg *msg = &bus->msgs[bus->msgs_index];
+- u8 slave_addr = i2c_8bit_addr_from_msg(msg);
+
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
+ /*
+@@ -374,12 +535,21 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus)
+
+ if (msg->flags & I2C_M_RD) {
+ command |= ASPEED_I2CD_M_RX_CMD;
+- /* Need to let the hardware know to NACK after RX. */
+- if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN))
+- command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
++ if (!(msg->flags & I2C_M_RECV_LEN)) {
++ if (msg->len && bus->buf_base)
++ command |= aspeed_i2c_prepare_rx_buf(bus, msg);
++
++ /* Need to let the hardware know to NACK after RX. */
++ if (msg->len <= 1)
++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
++ }
++ } else if (msg->len && bus->buf_base) {
++ command |= aspeed_i2c_prepare_tx_buf(bus, msg);
+ }
+
+- writel(slave_addr, bus->base + ASPEED_I2C_BYTE_BUF_REG);
++ if (!(command & ASPEED_I2CD_TX_BUFF_ENABLE))
++ writel(i2c_8bit_addr_from_msg(msg),
++ bus->base + ASPEED_I2C_BYTE_BUF_REG);
+ writel(command, bus->base + ASPEED_I2C_CMD_REG);
+ }
+
+@@ -414,6 +584,104 @@ static int aspeed_i2c_is_irq_error(u32 irq_status)
+ return 0;
+ }
+
++static inline u32
++aspeed_i2c_master_handle_tx_first(struct aspeed_i2c_bus *bus,
++ struct i2c_msg *msg)
++{
++ u32 command = 0;
++
++ if (bus->buf_base) {
++ u8 wbuf[4];
++ int len;
++ int i;
++
++ if (msg->len - bus->buf_index > bus->buf_size)
++ len = bus->buf_size;
++ else
++ len = msg->len - bus->buf_index;
++
++
++ command |= ASPEED_I2CD_TX_BUFF_ENABLE;
++
++ if (msg->len - bus->buf_index > bus->buf_size)
++ len = bus->buf_size;
++ else
++ len = msg->len - bus->buf_index;
++
++ for (i = 0; i < len; i++) {
++ wbuf[i % 4] = msg->buf[bus->buf_index + i];
++ if (i % 4 == 3)
++ writel(*(u32 *)wbuf,
++ bus->buf_base + i - 3);
++ }
++ if (--i % 4 != 3)
++ writel(*(u32 *)wbuf,
++ bus->buf_base + i - (i % 4));
++
++ writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK,
++ len - 1) |
++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK,
++ bus->buf_offset),
++ bus->base + ASPEED_I2C_BUF_CTRL_REG);
++
++ bus->buf_index += len;
++ } else {
++ writel(msg->buf[bus->buf_index++],
++ bus->base + ASPEED_I2C_BYTE_BUF_REG);
++ }
++
++ return command;
++}
++
++static inline void
++aspeed_i2c_master_handle_rx(struct aspeed_i2c_bus *bus, struct i2c_msg *msg)
++{
++ u8 recv_byte;
++ int len;
++
++ if (bus->buf_base) {
++ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK,
++ readl(bus->base + ASPEED_I2C_BUF_CTRL_REG));
++ memcpy_fromio(msg->buf + bus->buf_index, bus->buf_base, len);
++ bus->buf_index += len;
++ } else {
++ recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
++ msg->buf[bus->buf_index++] = recv_byte;
++ }
++}
++
++static inline u32
++aspeed_i2c_master_handle_rx_next(struct aspeed_i2c_bus *bus,
++ struct i2c_msg *msg)
++{
++ u32 command = 0;
++
++ if (bus->buf_base) {
++ int len;
++
++ if (msg->len - bus->buf_index > bus->buf_size) {
++ len = bus->buf_size;
++ } else {
++ len = msg->len - bus->buf_index;
++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
++ }
++
++ command |= ASPEED_I2CD_RX_BUFF_ENABLE;
++
++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK,
++ len - 1) |
++ FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, 0) |
++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK,
++ bus->buf_offset),
++ bus->base + ASPEED_I2C_BUF_CTRL_REG);
++ } else {
++ if (bus->buf_index + 1 == msg->len)
++ command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
++ }
++
++ return command;
++}
++
+ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ {
+ u32 irq_handled = 0, command = 0;
+@@ -522,11 +790,10 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ /* fall through */
+ case ASPEED_I2C_MASTER_TX_FIRST:
+ if (bus->buf_index < msg->len) {
++ command = ASPEED_I2CD_M_TX_CMD;
++ command |= aspeed_i2c_master_handle_tx_first(bus, msg);
++ writel(command, bus->base + ASPEED_I2C_CMD_REG);
+ bus->master_state = ASPEED_I2C_MASTER_TX;
+- writel(msg->buf[bus->buf_index++],
+- bus->base + ASPEED_I2C_BYTE_BUF_REG);
+- writel(ASPEED_I2CD_M_TX_CMD,
+- bus->base + ASPEED_I2C_CMD_REG);
+ } else {
+ aspeed_i2c_next_msg_or_stop(bus);
+ }
+@@ -543,26 +810,26 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ }
+ irq_handled |= ASPEED_I2CD_INTR_RX_DONE;
+
+- recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
+- msg->buf[bus->buf_index++] = recv_byte;
+-
+ if (msg->flags & I2C_M_RECV_LEN) {
++ recv_byte = readl(bus->base +
++ ASPEED_I2C_BYTE_BUF_REG) >> 8;
+ if (unlikely(recv_byte > I2C_SMBUS_BLOCK_MAX)) {
+ bus->cmd_err = -EPROTO;
+ aspeed_i2c_do_stop(bus);
+ goto out_no_complete;
+ }
+- msg->len = recv_byte +
+- ((msg->flags & I2C_CLIENT_PEC) ? 2 : 1);
++ msg->len = recv_byte + ((msg->flags & I2C_CLIENT_PEC) ?
++ 2 : 1);
+ msg->flags &= ~I2C_M_RECV_LEN;
++ } else if (msg->len) {
++ aspeed_i2c_master_handle_rx(bus, msg);
+ }
+
+ if (bus->buf_index < msg->len) {
+- bus->master_state = ASPEED_I2C_MASTER_RX;
+ command = ASPEED_I2CD_M_RX_CMD;
+- if (bus->buf_index + 1 == msg->len)
+- command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
++ command |= aspeed_i2c_master_handle_rx_next(bus, msg);
+ writel(command, bus->base + ASPEED_I2C_CMD_REG);
++ bus->master_state = ASPEED_I2C_MASTER_RX;
+ } else {
+ aspeed_i2c_next_msg_or_stop(bus);
+ }
+@@ -924,6 +1191,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus,
+ if (ret < 0)
+ return ret;
+
++ fun_ctrl_reg |= FIELD_PREP(ASPEED_I2CD_BUFFER_PAGE_SEL_MASK,
++ bus->buf_page);
++
+ if (of_property_read_bool(pdev->dev.of_node, "multi-master"))
+ bus->multi_master = true;
+ else
+@@ -964,6 +1234,52 @@ static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus)
+ return ret;
+ }
+
++static void aspeed_i2c_set_xfer_mode(struct aspeed_i2c_bus *bus)
++{
++ struct platform_device *pdev = to_platform_device(bus->dev);
++ bool sram_enabled = true;
++ int ret;
++
++ /*
++ * Enable I2C SRAM in case of AST2500.
++ * SRAM is enabled by default in AST2400 and AST2600.
++ */
++ if (of_device_is_compatible(pdev->dev.of_node,
++ "aspeed,ast2500-i2c-bus")) {
++ struct regmap *gr_regmap = syscon_regmap_lookup_by_compatible("aspeed,ast2500-i2c-gr");
++
++ if (IS_ERR(gr_regmap))
++ ret = PTR_ERR(gr_regmap);
++ else
++ ret = regmap_update_bits(gr_regmap,
++ ASPEED_I2CG_GLOBAL_CTRL_REG,
++ ASPEED_I2CG_SRAM_BUFFER_EN,
++ ASPEED_I2CG_SRAM_BUFFER_EN);
++
++ if (ret)
++ sram_enabled = false;
++ }
++
++ if (sram_enabled) {
++ struct resource *res = platform_get_resource(pdev,
++ IORESOURCE_MEM, 1);
++
++ if (res && resource_size(res) >= 2)
++ bus->buf_base = devm_ioremap_resource(&pdev->dev, res);
++
++ if (!IS_ERR_OR_NULL(bus->buf_base)) {
++ bus->buf_size = resource_size(res);
++ if (of_device_is_compatible(pdev->dev.of_node,
++ "aspeed,ast2400-i2c-bus")) {
++ bus->buf_page = ((res->start >> 8) &
++ GENMASK(3, 0)) - 8;
++ bus->buf_offset = (res->start >> 2) &
++ ASPEED_I2CD_BUF_OFFSET_MASK;
++ }
++ }
++ }
++}
++
+ static const struct of_device_id aspeed_i2c_bus_of_table[] = {
+ {
+ .compatible = "aspeed,ast2400-i2c-bus",
+@@ -986,18 +1302,18 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+ const struct of_device_id *match;
+ struct aspeed_i2c_bus *bus;
+ struct clk *parent_clk;
+- struct resource *res;
+ int irq, ret;
+
+ bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ return -ENOMEM;
+
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- bus->base = devm_ioremap_resource(&pdev->dev, res);
++ bus->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(bus->base))
+ return PTR_ERR(bus->base);
+
++ bus->dev = &pdev->dev;
++
+ parent_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(parent_clk))
+ return PTR_ERR(parent_clk);
+@@ -1028,6 +1344,8 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+ bus->get_clk_reg_val = (u32 (*)(struct device *, u32))
+ match->data;
+
++ aspeed_i2c_set_xfer_mode(bus);
++
+ /* Initialize the I2C adapter */
+ spin_lock_init(&bus->lock);
+ init_completion(&bus->cmd_complete);
+@@ -1038,8 +1356,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+ strlcpy(bus->adap.name, pdev->name, sizeof(bus->adap.name));
+ i2c_set_adapdata(&bus->adap, bus);
+
+- bus->dev = &pdev->dev;
+-
+ /* Clean up any left over interrupt state. */
+ writel(0, bus->base + ASPEED_I2C_INTR_CTRL_REG);
+ writel(0xffffffff, bus->base + ASPEED_I2C_INTR_STS_REG);
+@@ -1063,8 +1379,8 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, bus);
+
+- dev_info(bus->dev, "i2c bus %d registered, irq %d\n",
+- bus->adap.nr, irq);
++ dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n",
++ bus->adap.nr, bus->buf_base ? "buffer" : "byte", irq);
+
+ return 0;
+ }
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-i2c-aspeed-add-DMA-mode-transfer-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-i2c-aspeed-add-DMA-mode-transfer-support.patch
new file mode 100644
index 000000000..994c20b18
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0062-i2c-aspeed-add-DMA-mode-transfer-support.patch
@@ -0,0 +1,491 @@
+From 5bf7a202eb0af455675a85a4f1bdad863fd8805d Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 18 Jun 2019 08:47:50 -0700
+Subject: [PATCH] i2c: aspeed: add DMA mode transfer support
+
+This commit adds DMA mode transfer support.
+
+Only AST2500 supports DMA mode under some limitations:
+I2C is sharing the DMA H/W with UHCI host controller and MCTP
+controller. Since those controllers operate with DMA mode only, I2C
+has to use buffer mode or byte mode instead if one of those
+controllers is enabled. Also make sure that if SD/eMMC or Port80
+snoop uses DMA mode instead of PIO or FIFO respectively, I2C can't
+use DMA mode.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ .../devicetree/bindings/i2c/i2c-aspeed.txt | 25 ++
+ drivers/i2c/busses/i2c-aspeed.c | 253 +++++++++++++++++----
+ 2 files changed, 234 insertions(+), 44 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+index 0ff3539cee95..d3f4a39f7ba6 100644
+--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+@@ -22,6 +22,16 @@ Optional Properties:
+ - bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not
+ specified.
+ - #retries : Number of retries for master transfer.
++- aspeed,dma-buf-size : size of DMA buffer (from 2 to 4095 in case of AST2500)
++ Only AST2500 supports DMA mode under some limitations:
++ I2C is sharing the DMA H/W with UHCI host controller
++ and MCTP controller. Since those controllers operate
++ with DMA mode only, I2C has to use buffer mode or byte
++ mode instead if one of those controllers is enabled.
++ Also make sure that if SD/eMMC or Port80 snoop uses
++ DMA mode instead of PIO or FIFO respectively, I2C
++ can't use DMA mode. IF both DMA and buffer modes are
++ enabled, DMA mode will be selected.
+
+ Example:
+
+@@ -74,4 +84,19 @@ i2c {
+ interrupts = <1>;
+ interrupt-parent = <&i2c_ic>;
+ };
++
++ /* DMA mode transfer enabled */
++ i2c2: i2c-bus@c0 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ #interrupt-cells = <1>;
++ reg = <0xc0 0x40>;
++ aspeed,dma-buf-size = <4095>;
++ compatible = "aspeed,ast2500-i2c-bus";
++ clocks = <&syscon ASPEED_CLK_APB>;
++ resets = <&syscon ASPEED_RESET_I2C>;
++ bus-frequency = <100000>;
++ interrupts = <2>;
++ interrupt-parent = <&i2c_ic>;
++ };
+ };
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index bf72e151d11f..3c9e491cbe4e 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -10,6 +10,8 @@
+ #include <linux/bitfield.h>
+ #include <linux/clk.h>
+ #include <linux/completion.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmapool.h>
+ #include <linux/err.h>
+ #include <linux/errno.h>
+ #include <linux/i2c.h>
+@@ -47,6 +49,8 @@
+ #define ASPEED_I2C_DEV_ADDR_REG 0x18
+ #define ASPEED_I2C_BUF_CTRL_REG 0x1c
+ #define ASPEED_I2C_BYTE_BUF_REG 0x20
++#define ASPEED_I2C_DMA_ADDR_REG 0x24
++#define ASPEED_I2C_DMA_LEN_REG 0x28
+
+ /* Device Register Definition */
+ /* 0x00 : I2CD Function Control Register */
+@@ -110,6 +114,8 @@
+ #define ASPEED_I2CD_BUS_RECOVER_CMD BIT(11)
+
+ /* Command Bit */
++#define ASPEED_I2CD_RX_DMA_ENABLE BIT(9)
++#define ASPEED_I2CD_TX_DMA_ENABLE BIT(8)
+ #define ASPEED_I2CD_RX_BUFF_ENABLE BIT(7)
+ #define ASPEED_I2CD_TX_BUFF_ENABLE BIT(6)
+ #define ASPEED_I2CD_M_STOP_CMD BIT(5)
+@@ -135,6 +141,14 @@
+ #define ASPEED_I2CD_BUF_TX_COUNT_MASK GENMASK(15, 8)
+ #define ASPEED_I2CD_BUF_OFFSET_MASK GENMASK(5, 0)
+
++/* 0x24 : I2CD DMA Mode Buffer Address Register */
++#define ASPEED_I2CD_DMA_ADDR_MASK GENMASK(31, 2)
++#define ASPEED_I2CD_DMA_ALIGN 4
++
++/* 0x28 : I2CD DMA Transfer Length Register */
++#define ASPEED_I2CD_DMA_LEN_SHIFT 0
++#define ASPEED_I2CD_DMA_LEN_MASK GENMASK(11, 0)
++
+ enum aspeed_i2c_master_state {
+ ASPEED_I2C_MASTER_INACTIVE,
+ ASPEED_I2C_MASTER_PENDING,
+@@ -184,6 +198,12 @@ struct aspeed_i2c_bus {
+ void __iomem *buf_base;
+ u8 buf_offset;
+ u8 buf_page;
++ /* DMA mode */
++ struct dma_pool *dma_pool;
++ dma_addr_t dma_handle;
++ u8 *dma_buf;
++ size_t dma_len;
++ /* Buffer/DMA mode */
+ size_t buf_size;
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
+ struct i2c_client *slave;
+@@ -281,7 +301,11 @@ static inline void
+ aspeed_i2c_slave_handle_rx_done(struct aspeed_i2c_bus *bus, u32 irq_status,
+ u8 *value)
+ {
+- if (bus->buf_base &&
++ if (bus->dma_buf &&
++ bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED &&
++ !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))
++ *value = bus->dma_buf[0];
++ else if (bus->buf_base &&
+ bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED &&
+ !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))
+ *value = readb(bus->buf_base);
+@@ -297,7 +321,18 @@ aspeed_i2c_slave_handle_normal_stop(struct aspeed_i2c_bus *bus, u32 irq_status,
+
+ if (bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED &&
+ irq_status & ASPEED_I2CD_INTR_RX_DONE) {
+- if (bus->buf_base) {
++ if (bus->dma_buf) {
++ len = bus->buf_size -
++ FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK,
++ readl(bus->base +
++ ASPEED_I2C_DMA_LEN_REG));
++ for (i = 0; i < len; i++) {
++ *value = bus->dma_buf[i];
++ i2c_slave_event(bus->slave,
++ I2C_SLAVE_WRITE_RECEIVED,
++ value);
++ }
++ } else if (bus->buf_base) {
+ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK,
+ readl(bus->base +
+ ASPEED_I2C_BUF_CTRL_REG));
+@@ -314,7 +349,14 @@ aspeed_i2c_slave_handle_normal_stop(struct aspeed_i2c_bus *bus, u32 irq_status,
+ static inline void
+ aspeed_i2c_slave_handle_write_requested(struct aspeed_i2c_bus *bus, u8 *value)
+ {
+- if (bus->buf_base) {
++ if (bus->dma_buf) {
++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK,
++ bus->base + ASPEED_I2C_DMA_ADDR_REG);
++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, bus->buf_size),
++ bus->base + ASPEED_I2C_DMA_LEN_REG);
++ writel(ASPEED_I2CD_RX_DMA_ENABLE,
++ bus->base + ASPEED_I2C_CMD_REG);
++ } else if (bus->buf_base) {
+ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK,
+ bus->buf_size - 1) |
+ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK,
+@@ -330,7 +372,23 @@ aspeed_i2c_slave_handle_write_received(struct aspeed_i2c_bus *bus, u8 *value)
+ {
+ int i, len;
+
+- if (bus->buf_base) {
++ if (bus->dma_buf) {
++ len = bus->buf_size -
++ FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK,
++ readl(bus->base +
++ ASPEED_I2C_DMA_LEN_REG));
++ for (i = 1; i < len; i++) {
++ *value = bus->dma_buf[i];
++ i2c_slave_event(bus->slave, I2C_SLAVE_WRITE_RECEIVED,
++ value);
++ }
++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK,
++ bus->base + ASPEED_I2C_DMA_ADDR_REG);
++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, bus->buf_size),
++ bus->base + ASPEED_I2C_DMA_LEN_REG);
++ writel(ASPEED_I2CD_RX_DMA_ENABLE,
++ bus->base + ASPEED_I2C_CMD_REG);
++ } else if (bus->buf_base) {
+ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK,
+ readl(bus->base +
+ ASPEED_I2C_BUF_CTRL_REG));
+@@ -460,7 +518,15 @@ aspeed_i2c_prepare_rx_buf(struct aspeed_i2c_bus *bus, struct i2c_msg *msg)
+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
+ }
+
+- if (bus->buf_base) {
++ if (bus->dma_buf) {
++ command |= ASPEED_I2CD_RX_DMA_ENABLE;
++
++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK,
++ bus->base + ASPEED_I2C_DMA_ADDR_REG);
++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, len),
++ bus->base + ASPEED_I2C_DMA_LEN_REG);
++ bus->dma_len = len;
++ } else {
+ command |= ASPEED_I2CD_RX_BUFF_ENABLE;
+
+ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, len - 1) |
+@@ -483,7 +549,18 @@ aspeed_i2c_prepare_tx_buf(struct aspeed_i2c_bus *bus, struct i2c_msg *msg)
+ else
+ len = msg->len + 1;
+
+- if (bus->buf_base) {
++ if (bus->dma_buf) {
++ command |= ASPEED_I2CD_TX_DMA_ENABLE;
++
++ bus->dma_buf[0] = slave_addr;
++ memcpy(bus->dma_buf + 1, msg->buf, len);
++
++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK,
++ bus->base + ASPEED_I2C_DMA_ADDR_REG);
++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, len),
++ bus->base + ASPEED_I2C_DMA_LEN_REG);
++ bus->dma_len = len;
++ } else {
+ u8 wbuf[4];
+ int i;
+
+@@ -536,18 +613,19 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus)
+ if (msg->flags & I2C_M_RD) {
+ command |= ASPEED_I2CD_M_RX_CMD;
+ if (!(msg->flags & I2C_M_RECV_LEN)) {
+- if (msg->len && bus->buf_base)
++ if (msg->len && (bus->dma_buf || bus->buf_base))
+ command |= aspeed_i2c_prepare_rx_buf(bus, msg);
+
+ /* Need to let the hardware know to NACK after RX. */
+ if (msg->len <= 1)
+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
+ }
+- } else if (msg->len && bus->buf_base) {
++ } else if (msg->len && (bus->dma_buf || bus->buf_base)) {
+ command |= aspeed_i2c_prepare_tx_buf(bus, msg);
+ }
+
+- if (!(command & ASPEED_I2CD_TX_BUFF_ENABLE))
++ if (!(command & (ASPEED_I2CD_TX_BUFF_ENABLE |
++ ASPEED_I2CD_TX_DMA_ENABLE)))
+ writel(i2c_8bit_addr_from_msg(msg),
+ bus->base + ASPEED_I2C_BYTE_BUF_REG);
+ writel(command, bus->base + ASPEED_I2C_CMD_REG);
+@@ -590,39 +668,52 @@ aspeed_i2c_master_handle_tx_first(struct aspeed_i2c_bus *bus,
+ {
+ u32 command = 0;
+
+- if (bus->buf_base) {
+- u8 wbuf[4];
++ if (bus->dma_buf || bus->buf_base) {
+ int len;
+- int i;
+
+ if (msg->len - bus->buf_index > bus->buf_size)
+ len = bus->buf_size;
+ else
+ len = msg->len - bus->buf_index;
+
++ if (bus->dma_buf) {
++ command |= ASPEED_I2CD_TX_DMA_ENABLE;
+
+- command |= ASPEED_I2CD_TX_BUFF_ENABLE;
++ memcpy(bus->dma_buf, msg->buf + bus->buf_index, len);
+
+- if (msg->len - bus->buf_index > bus->buf_size)
+- len = bus->buf_size;
+- else
+- len = msg->len - bus->buf_index;
+
+- for (i = 0; i < len; i++) {
+- wbuf[i % 4] = msg->buf[bus->buf_index + i];
+- if (i % 4 == 3)
++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK,
++ bus->base + ASPEED_I2C_DMA_ADDR_REG);
++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, len),
++ bus->base + ASPEED_I2C_DMA_LEN_REG);
++ bus->dma_len = len;
++ } else {
++ u8 wbuf[4];
++ int i;
++
++ command |= ASPEED_I2CD_TX_BUFF_ENABLE;
++
++ if (msg->len - bus->buf_index > bus->buf_size)
++ len = bus->buf_size;
++ else
++ len = msg->len - bus->buf_index;
++
++ for (i = 0; i < len; i++) {
++ wbuf[i % 4] = msg->buf[bus->buf_index + i];
++ if (i % 4 == 3)
++ writel(*(u32 *)wbuf,
++ bus->buf_base + i - 3);
++ }
++ if (--i % 4 != 3)
+ writel(*(u32 *)wbuf,
+- bus->buf_base + i - 3);
+- }
+- if (--i % 4 != 3)
+- writel(*(u32 *)wbuf,
+- bus->buf_base + i - (i % 4));
++ bus->buf_base + i - (i % 4));
+
+- writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK,
+- len - 1) |
+- FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK,
+- bus->buf_offset),
+- bus->base + ASPEED_I2C_BUF_CTRL_REG);
++ writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK,
++ len - 1) |
++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK,
++ bus->buf_offset),
++ bus->base + ASPEED_I2C_BUF_CTRL_REG);
++ }
+
+ bus->buf_index += len;
+ } else {
+@@ -639,7 +730,14 @@ aspeed_i2c_master_handle_rx(struct aspeed_i2c_bus *bus, struct i2c_msg *msg)
+ u8 recv_byte;
+ int len;
+
+- if (bus->buf_base) {
++ if (bus->dma_buf) {
++ len = bus->dma_len -
++ FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK,
++ readl(bus->base + ASPEED_I2C_DMA_LEN_REG));
++
++ memcpy(msg->buf + bus->buf_index, bus->dma_buf, len);
++ bus->buf_index += len;
++ } else if (bus->buf_base) {
+ len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK,
+ readl(bus->base + ASPEED_I2C_BUF_CTRL_REG));
+ memcpy_fromio(msg->buf + bus->buf_index, bus->buf_base, len);
+@@ -656,7 +754,7 @@ aspeed_i2c_master_handle_rx_next(struct aspeed_i2c_bus *bus,
+ {
+ u32 command = 0;
+
+- if (bus->buf_base) {
++ if (bus->dma_buf || bus->buf_base) {
+ int len;
+
+ if (msg->len - bus->buf_index > bus->buf_size) {
+@@ -666,14 +764,24 @@ aspeed_i2c_master_handle_rx_next(struct aspeed_i2c_bus *bus,
+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
+ }
+
+- command |= ASPEED_I2CD_RX_BUFF_ENABLE;
++ if (bus->dma_buf) {
++ command |= ASPEED_I2CD_RX_DMA_ENABLE;
+
+- writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK,
+- len - 1) |
+- FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, 0) |
+- FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK,
+- bus->buf_offset),
+- bus->base + ASPEED_I2C_BUF_CTRL_REG);
++ writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK,
++ bus->base + ASPEED_I2C_DMA_ADDR_REG);
++ writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, len),
++ bus->base + ASPEED_I2C_DMA_LEN_REG);
++ bus->dma_len = len;
++ } else {
++ command |= ASPEED_I2CD_RX_BUFF_ENABLE;
++
++ writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK,
++ len - 1) |
++ FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, 0) |
++ FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK,
++ bus->buf_offset),
++ bus->base + ASPEED_I2C_BUF_CTRL_REG);
++ }
+ } else {
+ if (bus->buf_index + 1 == msg->len)
+ command |= ASPEED_I2CD_M_S_RX_CMD_LAST;
+@@ -1260,7 +1368,51 @@ static void aspeed_i2c_set_xfer_mode(struct aspeed_i2c_bus *bus)
+ sram_enabled = false;
+ }
+
+- if (sram_enabled) {
++ /*
++ * Only AST2500 and AST2600 support DMA mode under some limitations:
++ * I2C is sharing the DMA H/W with UHCI host controller and MCTP
++ * controller. Since those controllers operate with DMA mode only, I2C
++ * has to use buffer mode or byte mode instead if one of those
++ * controllers is enabled. Also make sure that if SD/eMMC or Port80
++ * snoop uses DMA mode instead of PIO or FIFO respectively, I2C can't
++ * use DMA mode.
++ */
++ if (sram_enabled && !IS_ENABLED(CONFIG_USB_UHCI_ASPEED) &&
++ !of_device_is_compatible(pdev->dev.of_node,
++ "aspeed,ast2400-i2c-bus")) {
++ u32 dma_len_max = ASPEED_I2CD_DMA_LEN_MASK >>
++ ASPEED_I2CD_DMA_LEN_SHIFT;
++
++ ret = device_property_read_u32(&pdev->dev,
++ "aspeed,dma-buf-size",
++ &bus->buf_size);
++ if (!ret && bus->buf_size > dma_len_max)
++ bus->buf_size = dma_len_max;
++ }
++
++ if (bus->buf_size) {
++ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
++ dev_warn(&pdev->dev, "No suitable DMA available\n");
++ } else {
++ bus->dma_pool = dma_pool_create("i2c-aspeed",
++ &pdev->dev,
++ bus->buf_size,
++ ASPEED_I2CD_DMA_ALIGN,
++ 0);
++ if (bus->dma_pool)
++ bus->dma_buf = dma_pool_alloc(bus->dma_pool,
++ GFP_KERNEL,
++ &bus->dma_handle);
++
++ if (!bus->dma_buf) {
++ dev_warn(&pdev->dev,
++ "Cannot allocate DMA buffer\n");
++ dma_pool_destroy(bus->dma_pool);
++ }
++ }
++ }
++
++ if (!bus->dma_buf && sram_enabled) {
+ struct resource *res = platform_get_resource(pdev,
+ IORESOURCE_MEM, 1);
+
+@@ -1365,24 +1517,33 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+ */
+ ret = aspeed_i2c_init(bus, pdev);
+ if (ret < 0)
+- return ret;
++ goto out_free_dma_buf;
+
+ irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ ret = devm_request_irq(&pdev->dev, irq, aspeed_i2c_bus_irq,
+ 0, dev_name(&pdev->dev), bus);
+ if (ret < 0)
+- return ret;
++ goto out_free_dma_buf;
+
+ ret = i2c_add_adapter(&bus->adap);
+ if (ret < 0)
+- return ret;
++ goto out_free_dma_buf;
+
+ platform_set_drvdata(pdev, bus);
+
+ dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n",
+- bus->adap.nr, bus->buf_base ? "buffer" : "byte", irq);
++ bus->adap.nr, bus->dma_buf ? "dma" :
++ bus->buf_base ? "buffer" : "byte",
++ irq);
+
+ return 0;
++
++out_free_dma_buf:
++ if (bus->dma_buf)
++ dma_pool_free(bus->dma_pool, bus->dma_buf, bus->dma_handle);
++ dma_pool_destroy(bus->dma_pool);
++
++ return ret;
+ }
+
+ static int aspeed_i2c_remove_bus(struct platform_device *pdev)
+@@ -1400,6 +1561,10 @@ static int aspeed_i2c_remove_bus(struct platform_device *pdev)
+
+ reset_control_assert(bus->rst);
+
++ if (bus->dma_buf)
++ dma_pool_free(bus->dma_pool, bus->dma_buf, bus->dma_handle);
++ dma_pool_destroy(bus->dma_pool);
++
+ i2c_del_adapter(&bus->adap);
+
+ return 0;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch
new file mode 100644
index 000000000..899924f61
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0063-i2c-aspeed-add-general-call-support.patch
@@ -0,0 +1,180 @@
+From d731b53de05b8d69ea739f02275416126cf5fe4e Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 1 May 2019 13:27:34 -0700
+Subject: [PATCH] i2c: aspeed: add general call support
+
+This commit adds general call support into Aspeed I2C driver.
+This is downstream only customization so it should not go into
+upstream.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ .../devicetree/bindings/i2c/i2c-aspeed.txt | 1 +
+ drivers/i2c/busses/i2c-aspeed.c | 39 ++++++++++++++++++++++
+ drivers/i2c/i2c-slave-mqueue.c | 4 ++-
+ include/linux/i2c.h | 1 +
+ 4 files changed, 44 insertions(+), 1 deletion(-)
+
+diff --git a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+index d3f4a39f7ba6..c1ee99398517 100644
+--- a/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
++++ b/Documentation/devicetree/bindings/i2c/i2c-aspeed.txt
+@@ -19,6 +19,7 @@ Optional Properties:
+ - bus-frequency : frequency of the bus clock in Hz defaults to 100 kHz when not
+ specified
+ - multi-master : states that there is another master active on this bus.
++- general-call : enables general call receiving.
+ - bus-timeout-ms: bus timeout in milliseconds defaults to 1 second when not
+ specified.
+ - #retries : Number of retries for master transfer.
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index 3c9e491cbe4e..4420899e2c2d 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -59,6 +59,7 @@
+ #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8)
+ #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7)
+ #define ASPEED_I2CD_M_HIGH_SPEED_EN BIT(6)
++#define ASPEED_I2CD_GCALL_EN BIT(2)
+ #define ASPEED_I2CD_SLAVE_EN BIT(1)
+ #define ASPEED_I2CD_MASTER_EN BIT(0)
+
+@@ -83,6 +84,7 @@
+ */
+ #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14)
+ #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13)
++#define ASPEED_I2CD_INTR_GCALL_ADDR BIT(8)
+ #define ASPEED_I2CD_INTR_SLAVE_MATCH BIT(7)
+ #define ASPEED_I2CD_INTR_SCL_TIMEOUT BIT(6)
+ #define ASPEED_I2CD_INTR_ABNORMAL BIT(5)
+@@ -167,6 +169,8 @@ enum aspeed_i2c_slave_state {
+ ASPEED_I2C_SLAVE_READ_PROCESSED,
+ ASPEED_I2C_SLAVE_WRITE_REQUESTED,
+ ASPEED_I2C_SLAVE_WRITE_RECEIVED,
++ ASPEED_I2C_SLAVE_GCALL_START,
++ ASPEED_I2C_SLAVE_GCALL_REQUESTED,
+ ASPEED_I2C_SLAVE_STOP,
+ };
+
+@@ -208,6 +212,8 @@ struct aspeed_i2c_bus {
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
+ struct i2c_client *slave;
+ enum aspeed_i2c_slave_state slave_state;
++ /* General call */
++ bool general_call;
+ #endif /* CONFIG_I2C_SLAVE */
+ };
+
+@@ -423,6 +429,12 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ bus->slave_state = ASPEED_I2C_SLAVE_START;
+ }
+
++ /* General call was requested, restart state machine. */
++ if (irq_status & ASPEED_I2CD_INTR_GCALL_ADDR) {
++ irq_handled |= ASPEED_I2CD_INTR_GCALL_ADDR;
++ bus->slave_state = ASPEED_I2C_SLAVE_GCALL_START;
++ }
++
+ /* Slave is not currently active, irq was for someone else. */
+ if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE)
+ return irq_handled;
+@@ -441,6 +453,21 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ else
+ bus->slave_state =
+ ASPEED_I2C_SLAVE_WRITE_REQUESTED;
++ } else if (bus->slave_state == ASPEED_I2C_SLAVE_GCALL_START) {
++ /*
++ * I2C spec defines the second byte meaning like below.
++ * 0x06 : Reset and write programmable part of slave
++ * address by hardware.
++ * 0x04 : Write programmable part of slave address by
++ * hardware.
++ * 0x00 : No allowed.
++ *
++ * But in OpenBMC, we are going to use this
++ * 'General call' feature for IPMB message broadcasting
++ * so it delivers all data as is without any specific
++ * handling of the second byte.
++ */
++ bus->slave_state = ASPEED_I2C_SLAVE_GCALL_REQUESTED;
+ }
+ irq_handled |= ASPEED_I2CD_INTR_RX_DONE;
+ }
+@@ -487,11 +514,16 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value);
+ aspeed_i2c_slave_handle_write_received(bus, &value);
+ break;
++ case ASPEED_I2C_SLAVE_GCALL_REQUESTED:
++ bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED;
++ i2c_slave_event(slave, I2C_SLAVE_GCALL_REQUESTED, &value);
++ 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:
++ case ASPEED_I2C_SLAVE_GCALL_START:
+ /* Slave was just started. Waiting for the next event. */;
+ break;
+ default:
+@@ -1127,6 +1159,8 @@ static void __aspeed_i2c_reg_slave(struct aspeed_i2c_bus *bus, u16 slave_addr)
+ /* Turn on slave mode. */
+ func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG);
+ func_ctrl_reg_val |= ASPEED_I2CD_SLAVE_EN;
++ if (bus->general_call)
++ func_ctrl_reg_val |= ASPEED_I2CD_GCALL_EN;
+ writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG);
+ }
+
+@@ -1165,6 +1199,8 @@ static int aspeed_i2c_unreg_slave(struct i2c_client *client)
+ /* Turn off slave mode. */
+ func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG);
+ func_ctrl_reg_val &= ~ASPEED_I2CD_SLAVE_EN;
++ if (bus->general_call)
++ func_ctrl_reg_val &= ~ASPEED_I2CD_GCALL_EN;
+ writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG);
+
+ bus->slave = NULL;
+@@ -1312,6 +1348,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus,
+ bus->base + ASPEED_I2C_FUN_CTRL_REG);
+
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
++ if (of_property_read_bool(pdev->dev.of_node, "general-call"))
++ bus->general_call = true;
++
+ /* If slave has already been registered, re-enable it. */
+ if (bus->slave)
+ __aspeed_i2c_reg_slave(bus, bus->slave->addr);
+diff --git a/drivers/i2c/i2c-slave-mqueue.c b/drivers/i2c/i2c-slave-mqueue.c
+index 2c7a6038409c..1d4db584b393 100644
+--- a/drivers/i2c/i2c-slave-mqueue.c
++++ b/drivers/i2c/i2c-slave-mqueue.c
+@@ -56,10 +56,12 @@ static int i2c_slave_mqueue_callback(struct i2c_client *client,
+
+ switch (event) {
+ case I2C_SLAVE_WRITE_REQUESTED:
++ case I2C_SLAVE_GCALL_REQUESTED:
+ mq->truncated = 0;
+
+ msg->len = 1;
+- msg->buf[0] = client->addr << 1;
++ msg->buf[0] = event == I2C_SLAVE_GCALL_REQUESTED ?
++ 0 : client->addr << 1;
+ break;
+
+ case I2C_SLAVE_WRITE_RECEIVED:
+diff --git a/include/linux/i2c.h b/include/linux/i2c.h
+index b4055d133338..52369ea150b4 100644
+--- a/include/linux/i2c.h
++++ b/include/linux/i2c.h
+@@ -365,6 +365,7 @@ enum i2c_slave_event {
+ I2C_SLAVE_WRITE_REQUESTED,
+ I2C_SLAVE_READ_PROCESSED,
+ I2C_SLAVE_WRITE_RECEIVED,
++ I2C_SLAVE_GCALL_REQUESTED,
+ I2C_SLAVE_STOP,
+ };
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0064-set-idle-disconnect-to-true-in-all-cases.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0064-set-idle-disconnect-to-true-in-all-cases.patch
new file mode 100644
index 000000000..925880eff
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0064-set-idle-disconnect-to-true-in-all-cases.patch
@@ -0,0 +1,34 @@
+From 7854a5e094ac49bebf9b2bfdd44db2f8cdd37543 Mon Sep 17 00:00:00 2001
+From: James Feist <james.feist@linux.intel.com>
+Date: Fri, 31 May 2019 15:05:13 -0700
+Subject: [PATCH] set idle-disconnect to true in all cases
+
+From sysfs this parameter can't be set. We want the
+muxes to clean themselves up if possible. Set this to
+true.
+
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+---
+ drivers/i2c/muxes/i2c-mux-pca954x.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
+index 923aa3a5a3dc..084c10951890 100644
+--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
++++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
+@@ -474,8 +474,12 @@ static int pca954x_probe(struct i2c_client *client,
+ data->last_chan = 0; /* force the first selection */
+ data->idle_state = MUX_IDLE_AS_IS;
+
++#if 1 /* Forcibly set the self-disconnect flag */
++ idle_disconnect_dt = true;
++#else
+ idle_disconnect_dt = np &&
+ of_property_read_bool(np, "i2c-mux-idle-disconnect");
++#endif
+ if (idle_disconnect_dt)
+ data->idle_state = MUX_IDLE_DISCONNECT;
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch
new file mode 100644
index 000000000..0e8a2b101
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0068-i2c-aspeed-add-H-W-timeout-support.patch
@@ -0,0 +1,191 @@
+From b429cf11ecb2f6009dd9e062ea5e053718802d93 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 11 Jul 2019 13:53:34 -0700
+Subject: [PATCH] i2c: aspeed: add H/W timeout support
+
+This commit adds I2C H/W timeout support.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/i2c/busses/i2c-aspeed.c | 82 ++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 76 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index 4420899e2c2d..830b3d2cabad 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -55,6 +55,7 @@
+ /* Device Register Definition */
+ /* 0x00 : I2CD Function Control Register */
+ #define ASPEED_I2CD_BUFFER_PAGE_SEL_MASK GENMASK(22, 20)
++#define ASPEED_I2CD_BUS_AUTO_RECOVERY_EN BIT(17)
+ #define ASPEED_I2CD_MULTI_MASTER_DIS BIT(15)
+ #define ASPEED_I2CD_SDA_DRIVE_1T_EN BIT(8)
+ #define ASPEED_I2CD_M_SDA_DRIVE_1T_EN BIT(7)
+@@ -71,10 +72,14 @@
+ #define ASPEED_I2CD_TIME_SCL_HIGH_MASK GENMASK(19, 16)
+ #define ASPEED_I2CD_TIME_SCL_LOW_SHIFT 12
+ #define ASPEED_I2CD_TIME_SCL_LOW_MASK GENMASK(15, 12)
++#define ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_SHIFT 8
++#define ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_MASK GENMASK(9, 8)
+ #define ASPEED_I2CD_TIME_BASE_DIVISOR_MASK GENMASK(3, 0)
+ #define ASPEED_I2CD_TIME_SCL_REG_MAX GENMASK(3, 0)
++
+ /* 0x08 : I2CD Clock and AC Timing Control Register #2 */
+-#define ASPEED_NO_TIMEOUT_CTRL 0
++#define ASPEED_I2CD_TIMEOUT_CYCLES_SHIFT 0
++#define ASPEED_I2CD_TIMEOUT_CYCLES_MASK GENMASK(4, 0)
+
+ /* 0x0c : I2CD Interrupt Control Register &
+ * 0x10 : I2CD Interrupt Status Register
+@@ -82,6 +87,7 @@
+ * These share bit definitions, so use the same values for the enable &
+ * status bits.
+ */
++#define ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT BIT(15)
+ #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14)
+ #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13)
+ #define ASPEED_I2CD_INTR_GCALL_ADDR BIT(8)
+@@ -98,8 +104,11 @@
+ ASPEED_I2CD_INTR_SCL_TIMEOUT | \
+ ASPEED_I2CD_INTR_ABNORMAL | \
+ ASPEED_I2CD_INTR_ARBIT_LOSS)
++#define ASPEED_I2CD_INTR_SLAVE_ERRORS \
++ ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT
+ #define ASPEED_I2CD_INTR_ALL \
+- (ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
++ (ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT | \
++ ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
+ ASPEED_I2CD_INTR_BUS_RECOVER_DONE | \
+ ASPEED_I2CD_INTR_SCL_TIMEOUT | \
+ ASPEED_I2CD_INTR_ABNORMAL | \
+@@ -186,6 +195,7 @@ struct aspeed_i2c_bus {
+ u32 divisor);
+ unsigned long parent_clk_frequency;
+ u32 bus_frequency;
++ u32 hw_timeout_ms;
+ /* Transaction state. */
+ enum aspeed_i2c_master_state master_state;
+ struct i2c_msg *msgs;
+@@ -303,6 +313,14 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
+ }
+
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
++static int aspeed_i2c_check_slave_error(u32 irq_status)
++{
++ if (irq_status & ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT)
++ return -EIO;
++
++ return 0;
++}
++
+ static inline void
+ aspeed_i2c_slave_handle_rx_done(struct aspeed_i2c_bus *bus, u32 irq_status,
+ u8 *value)
+@@ -421,6 +439,14 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ if (!slave)
+ return 0;
+
++ if (aspeed_i2c_check_slave_error(irq_status)) {
++ dev_dbg(bus->dev, "received slave error interrupt: 0x%08x\n",
++ irq_status);
++ irq_handled |= (irq_status & ASPEED_I2CD_INTR_SLAVE_ERRORS);
++ bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
++ return irq_handled;
++ }
++
+ command = readl(bus->base + ASPEED_I2C_CMD_REG);
+
+ /* Slave was requested, restart state machine. */
+@@ -681,7 +707,7 @@ static void aspeed_i2c_next_msg_or_stop(struct aspeed_i2c_bus *bus)
+ }
+ }
+
+-static int aspeed_i2c_is_irq_error(u32 irq_status)
++static int aspeed_i2c_check_master_error(u32 irq_status)
+ {
+ if (irq_status & ASPEED_I2CD_INTR_ARBIT_LOSS)
+ return -EAGAIN;
+@@ -840,9 +866,9 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ * should clear the command queue effectively taking us back to the
+ * INACTIVE state.
+ */
+- ret = aspeed_i2c_is_irq_error(irq_status);
++ ret = aspeed_i2c_check_master_error(irq_status);
+ if (ret) {
+- dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
++ dev_dbg(bus->dev, "received master error interrupt: 0x%08x\n",
+ irq_status);
+ irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS);
+ if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
+@@ -1307,6 +1333,7 @@ static u32 aspeed_i2c_25xx_get_clk_reg_val(struct device *dev, u32 divisor)
+ /* precondition: bus.lock has been acquired. */
+ static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus)
+ {
++ u32 timeout_base_divisor, timeout_tick_us, timeout_cycles;
+ u32 divisor, clk_reg_val;
+
+ divisor = DIV_ROUND_UP(bus->parent_clk_frequency, bus->bus_frequency);
+@@ -1315,8 +1342,46 @@ static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus)
+ ASPEED_I2CD_TIME_THDSTA_MASK |
+ ASPEED_I2CD_TIME_TACST_MASK);
+ clk_reg_val |= bus->get_clk_reg_val(bus->dev, divisor);
++
++ if (bus->hw_timeout_ms) {
++ u8 div_max = ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_MASK >>
++ ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_SHIFT;
++ u8 cycles_max = ASPEED_I2CD_TIMEOUT_CYCLES_MASK >>
++ ASPEED_I2CD_TIMEOUT_CYCLES_SHIFT;
++
++ timeout_base_divisor = 0;
++
++ do {
++ timeout_tick_us = 1000 * (16384 <<
++ (timeout_base_divisor << 1)) /
++ (bus->parent_clk_frequency / 1000);
++
++ if (timeout_base_divisor == div_max ||
++ timeout_tick_us * ASPEED_I2CD_TIMEOUT_CYCLES_MASK >=
++ bus->hw_timeout_ms * 1000)
++ break;
++ } while (timeout_base_divisor++ < div_max);
++
++ if (timeout_tick_us) {
++ timeout_cycles = DIV_ROUND_UP(bus->hw_timeout_ms * 1000,
++ timeout_tick_us);
++ if (timeout_cycles == 0)
++ timeout_cycles = 1;
++ else if (timeout_cycles > cycles_max)
++ timeout_cycles = cycles_max;
++ } else {
++ timeout_cycles = 0;
++ }
++ } else {
++ timeout_base_divisor = 0;
++ timeout_cycles = 0;
++ }
++
++ clk_reg_val |= FIELD_PREP(ASPEED_I2CD_TIME_TIMEOUT_BASE_DIVISOR_MASK,
++ timeout_base_divisor);
++
+ writel(clk_reg_val, bus->base + ASPEED_I2C_AC_TIMING_REG1);
+- writel(ASPEED_NO_TIMEOUT_CTRL, bus->base + ASPEED_I2C_AC_TIMING_REG2);
++ writel(timeout_cycles, bus->base + ASPEED_I2C_AC_TIMING_REG2);
+
+ return 0;
+ }
+@@ -1331,6 +1396,11 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus,
+ /* Disable everything. */
+ writel(0, bus->base + ASPEED_I2C_FUN_CTRL_REG);
+
++ device_property_read_u32(&pdev->dev, "aspeed,hw-timeout-ms",
++ &bus->hw_timeout_ms);
++ if (bus->hw_timeout_ms)
++ fun_ctrl_reg |= ASPEED_I2CD_BUS_AUTO_RECOVERY_EN;
++
+ ret = aspeed_i2c_init_clk(bus);
+ if (ret < 0)
+ return ret;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch
new file mode 100644
index 000000000..104279ace
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch
@@ -0,0 +1,50 @@
+From b43bdeb5f3aa297549655e67f0e6a5db5f592e34 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 11 Jul 2019 14:04:39 -0700
+Subject: [PATCH] i2c: aspeed: add SLAVE_ADDR_RECEIVED_PENDING interrupt
+ handling
+
+If a peer master sends messages too quickly before it processes
+previous slave DMA data handling, this indicator will be set. It's
+just a indicator and driver can't recover this case so just ignore
+it.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/i2c/busses/i2c-aspeed.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index 830b3d2cabad..a308d5896632 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -87,6 +87,7 @@
+ * These share bit definitions, so use the same values for the enable &
+ * status bits.
+ */
++#define ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING BIT(30)
+ #define ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT BIT(15)
+ #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14)
+ #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13)
+@@ -468,6 +469,18 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
+ irq_status, command);
+
++ /*
++ * If a peer master sends messages too quickly before it processes
++ * previous slave DMA data handling, this indicator will be set. It's
++ * just a indicator and driver can't recover this case so just ignore
++ * it.
++ */
++ if (unlikely(irq_status &
++ ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING)) {
++ dev_dbg(bus->dev, "A slave addr match interrupt is pending.\n");
++ irq_handled |= ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING;
++ }
++
+ /* Slave was sent something. */
+ if (irq_status & ASPEED_I2CD_INTR_RX_DONE) {
+ aspeed_i2c_slave_handle_rx_done(bus, irq_status, &value);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch
new file mode 100644
index 000000000..5c3e35016
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch
@@ -0,0 +1,44 @@
+From 0bda96c5fe3064c71f190bc484e2ce59c51d5585 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Fri, 19 Jul 2019 12:54:38 -0700
+Subject: [PATCH] gpio: aspeed: temporary fix for gpiochip range setting
+
+Since we are still using fixed indices for gpio line numbers for sysfs
+interface, this commit set the gpiochip range as fixed temporariliy
+til we replace all index based gpio uses with name based uses.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/gpio/gpio-aspeed.c | 2 +-
+ drivers/gpio/sgpio-aspeed.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
+index 39c50c53dae3..05945470bd89 100644
+--- a/drivers/gpio/gpio-aspeed.c
++++ b/drivers/gpio/gpio-aspeed.c
+@@ -1181,7 +1181,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
+ gpio->chip.set = aspeed_gpio_set;
+ gpio->chip.set_config = aspeed_gpio_set_config;
+ gpio->chip.label = dev_name(&pdev->dev);
+- gpio->chip.base = -1;
++ gpio->chip.base = 0;
+
+ /* Allocate a cache of the output registers */
+ banks = DIV_ROUND_UP(gpio->chip.ngpio, 32);
+diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c
+index 5028e9144a75..850539da43f5 100644
+--- a/drivers/gpio/sgpio-aspeed.c
++++ b/drivers/gpio/sgpio-aspeed.c
+@@ -681,7 +681,7 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
+ gpio->chip.set = aspeed_sgpio_set;
+ gpio->chip.set_config = aspeed_sgpio_set_config;
+ gpio->chip.label = dev_name(&pdev->dev);
+- gpio->chip.base = -1;
++ gpio->chip.base = gpio->config->nr_pgpios;
+
+ rc = aspeed_sgpio_setup_irqs(gpio, pdev);
+ if (rc < 0)
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0072-pmbus-add-fault-and-beep-attributes.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0072-pmbus-add-fault-and-beep-attributes.patch
new file mode 100644
index 000000000..40a9272e0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0072-pmbus-add-fault-and-beep-attributes.patch
@@ -0,0 +1,88 @@
+From e360a6c2a3f15bfc8900c7262c56f9bcd5e0f16e Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 8 Aug 2019 10:38:00 -0700
+Subject: [PATCH] pmbus: add 'fault' and 'beep' attributes
+
+This commit adds two more attirbutes to reflect MFR_SPECIFIC bit in
+the STATUS_WORD and 'Unit Off For Insufficient Input Voltage' bit in
+the STATUS_INPUT into 'fault' and 'beep' attributes respectively.
+
+The attributes will be enumerated as 'inX_fault' and 'inX_beep' in
+a 'vin' group.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/hwmon/pmbus/pmbus.h | 1 +
+ drivers/hwmon/pmbus/pmbus_core.c | 30 ++++++++++++++++++++++++++++++
+ 2 files changed, 31 insertions(+)
+
+diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
+index d198af3a92b6..09e6fe01c304 100644
+--- a/drivers/hwmon/pmbus/pmbus.h
++++ b/drivers/hwmon/pmbus/pmbus.h
+@@ -303,6 +303,7 @@ enum pmbus_fan_mode { percent = 0, rpm };
+ #define PB_PIN_OP_WARNING BIT(0)
+ #define PB_IIN_OC_WARNING BIT(1)
+ #define PB_IIN_OC_FAULT BIT(2)
++#define PB_UNIT_OFF_FOR_INSUF_VIN BIT(3)
+
+ /*
+ * STATUS_TEMPERATURE
+diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
+index 898d7378f4f8..85295a45c3ba 100644
+--- a/drivers/hwmon/pmbus/pmbus_core.c
++++ b/drivers/hwmon/pmbus/pmbus_core.c
+@@ -1163,6 +1163,8 @@ struct pmbus_limit_attr {
+ struct pmbus_sensor_attr {
+ u16 reg; /* sensor register */
+ u16 gbit; /* generic status bit */
++ u16 gfbit; /* generic fault status bit */
++ u16 sbbit; /* beep status bit */
+ u8 nlimit; /* # of limit registers */
+ enum pmbus_sensor_classes class;/* sensor class */
+ const char *label; /* sensor label */
+@@ -1264,6 +1266,32 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
+ return ret;
+ }
+ }
++ /*
++ * Add fault attribute if there is a generic fault bit, and if
++ * the generic status register (word or byte, depending on which global
++ * bit is set) for this page is accessible.
++ */
++ if (attr->gfbit) {
++ upper = !!(attr->gfbit & 0xff00); /* need to check STATUS_WORD */
++ if ((!upper || (upper && data->has_status_word)) &&
++ pmbus_check_status_register(client, page)) {
++ ret = pmbus_add_boolean(data, name, "fault", index,
++ NULL, NULL,
++ PB_STATUS_BASE + page,
++ attr->gfbit);
++ if (ret)
++ return ret;
++ }
++ }
++ /* Add beep attribute if there is a beep status bit. */
++ if (attr->sbbit) {
++ ret = pmbus_add_boolean(data, name, "beep", index,
++ NULL, NULL,
++ attr->sbase + page,
++ attr->sbbit);
++ if (ret)
++ return ret;
++ }
+ return 0;
+ }
+
+@@ -1435,6 +1463,8 @@ static const struct pmbus_sensor_attr voltage_attributes[] = {
+ .gbit = PB_STATUS_VIN_UV,
+ .limit = vin_limit_attrs,
+ .nlimit = ARRAY_SIZE(vin_limit_attrs),
++ .gfbit = PB_STATUS_WORD_MFR,
++ .sbbit = PB_UNIT_OFF_FOR_INSUF_VIN,
+ }, {
+ .reg = PMBUS_VIRT_READ_VMON,
+ .class = PSC_VOLTAGE_IN,
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch
new file mode 100644
index 000000000..1056b3beb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch
@@ -0,0 +1,155 @@
+From 5c82e0b33f2a373d5e19569635f108cfa096f53e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Adrian=20Ambro=C5=BCewicz?= <adrian.ambrozewicz@intel.com>
+Date: Mon, 29 Jul 2019 10:19:00 +0200
+Subject: [PATCH] Add IO statistics to USB Mass storage gadget
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Introduces new attribute to Mass Storage Gadget ConfigFS : stats.
+It's read-only attribute which contains statistics of read/write operations
+based on LUN transaction counters (IO number and bytes transferred).
+
+Goal is to provide a way to observe whether simulated device is actually
+used by host. Statistics on hosted file / nbd level are not always viable
+due to page cache having severe impact on actual IO statistics.
+This attribute should provide information about host IO on USB Gadget as
+close to endpoint as possible.
+
+Attribute is tied completely to configFS implementation and it's lifecycle
+is managed by Kernel and user. Driver implements a handler which populates
+output buffer on read.
+
+Tests performed:
+- mounted USB Mass Storage gadget, new attribute showed up in gadget tree
+- attribute was monitored for changes during IO performed on host machine
+- removed device, attribute (along with other device attributes) was gone
+
+Signed-off-by: Adrian Ambrożewicz <adrian.ambrozewicz@intel.com>
+---
+ drivers/usb/gadget/function/f_mass_storage.c | 12 ++++++++++++
+ drivers/usb/gadget/function/storage_common.c | 9 +++++++++
+ drivers/usb/gadget/function/storage_common.h | 29 ++++++++++++++++++++++++++++
+ 3 files changed, 50 insertions(+)
+
+diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
+index 7c96c4665178..ecc3c68a7882 100644
+--- a/drivers/usb/gadget/function/f_mass_storage.c
++++ b/drivers/usb/gadget/function/f_mass_storage.c
+@@ -710,6 +710,8 @@ static int do_read(struct fsg_common *common)
+ amount_left -= nread;
+ common->residue -= nread;
+
++ fsg_stats_rd_attempt(&curlun->stats, nread);
++
+ /*
+ * Except at the end of the transfer, nread will be
+ * equal to the buffer size, which is divisible by the
+@@ -907,6 +909,8 @@ static int do_write(struct fsg_common *common)
+ amount_left_to_write -= nwritten;
+ common->residue -= nwritten;
+
++ fsg_stats_wr_attempt(&curlun->stats, nwritten);
++
+ /* If an error occurred, report it and its position */
+ if (nwritten < amount) {
+ curlun->sense_data = SS_WRITE_ERROR;
+@@ -3122,6 +3126,13 @@ static ssize_t fsg_lun_opts_inquiry_string_store(struct config_item *item,
+
+ CONFIGFS_ATTR(fsg_lun_opts_, inquiry_string);
+
++static ssize_t fsg_lun_opts_stats_show(struct config_item *item, char *page)
++{
++ return fsg_show_stats(to_fsg_lun_opts(item)->lun, page);
++}
++
++CONFIGFS_ATTR_RO(fsg_lun_opts_, stats);
++
+ static struct configfs_attribute *fsg_lun_attrs[] = {
+ &fsg_lun_opts_attr_file,
+ &fsg_lun_opts_attr_ro,
+@@ -3129,6 +3140,7 @@ static struct configfs_attribute *fsg_lun_attrs[] = {
+ &fsg_lun_opts_attr_cdrom,
+ &fsg_lun_opts_attr_nofua,
+ &fsg_lun_opts_attr_inquiry_string,
++ &fsg_lun_opts_attr_stats,
+ NULL,
+ };
+
+diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c
+index f7e6c42558eb..2325b97961df 100644
+--- a/drivers/usb/gadget/function/storage_common.c
++++ b/drivers/usb/gadget/function/storage_common.c
+@@ -371,6 +371,15 @@ ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf)
+ }
+ EXPORT_SYMBOL_GPL(fsg_show_inquiry_string);
+
++ssize_t fsg_show_stats(struct fsg_lun *curlun, char *buf)
++{
++ return sprintf(buf, "read cnt: %u\n" "read sum: %llu\n"
++ "write cnt: %u\n" "write sum: %llu\n",
++ curlun->stats.read.count, curlun->stats.read.bytes,
++ curlun->stats.write.count, curlun->stats.write.bytes);
++}
++EXPORT_SYMBOL_GPL(fsg_show_stats);
++
+ /*
+ * The caller must hold fsg->filesem for reading when calling this function.
+ */
+diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h
+index e5e3a2553aaa..447021ba821a 100644
+--- a/drivers/usb/gadget/function/storage_common.h
++++ b/drivers/usb/gadget/function/storage_common.h
+@@ -95,6 +95,32 @@ do { \
+ */
+ #define INQUIRY_STRING_LEN ((size_t) (8 + 16 + 4 + 1))
+
++struct fsg_stats_cnt {
++ u64 bytes;
++ u32 count;
++};
++
++struct fsg_stats {
++ struct fsg_stats_cnt read;
++ struct fsg_stats_cnt write;
++};
++
++static inline void fsg_stats_update(struct fsg_stats_cnt *cnt, u64 diff)
++{
++ cnt->count++;
++ cnt->bytes += diff;
++}
++
++static inline void fsg_stats_wr_attempt(struct fsg_stats *stats, u64 b_written)
++{
++ fsg_stats_update(&stats->write, b_written);
++}
++
++static inline void fsg_stats_rd_attempt(struct fsg_stats *stats, u64 b_read)
++{
++ fsg_stats_update(&stats->read, b_read);
++}
++
+ struct fsg_lun {
+ struct file *filp;
+ loff_t file_length;
+@@ -120,6 +146,8 @@ struct fsg_lun {
+ const char *name; /* "lun.name" */
+ const char **name_pfx; /* "function.name" */
+ char inquiry_string[INQUIRY_STRING_LEN];
++
++ struct fsg_stats stats;
+ };
+
+ static inline bool fsg_lun_is_open(struct fsg_lun *curlun)
+@@ -213,6 +241,7 @@ ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
+ ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf);
+ ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf);
+ ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf);
++ssize_t fsg_show_stats(struct fsg_lun *curlun, char *buf);
+ ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem,
+ const char *buf, size_t count);
+ ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0075-Refine-initialization-flow-in-I2C-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0075-Refine-initialization-flow-in-I2C-driver.patch
new file mode 100644
index 000000000..52c3617d6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0075-Refine-initialization-flow-in-I2C-driver.patch
@@ -0,0 +1,64 @@
+From 93ba2aeb9ad3899e2b72877daa47376a6bf192b6 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Mon, 23 Sep 2019 13:48:49 -0700
+Subject: [PATCH] Refine initialization flow in I2C driver
+
+Since we enabled I2C busses in u-boot, we need to disable the I2C
+bus and clear all garbage interrupts when kernel probes the bus.
+This commit refines the initialization flow by adding a bus reset
+at the beginning of probe function and by moving bus init function
+after interrupt handling setup.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/i2c/busses/i2c-aspeed.c | 20 +++++++++-----------
+ 1 file changed, 9 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index a308d5896632..b32611088c82 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -1588,6 +1588,11 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+
+ bus->dev = &pdev->dev;
+
++ /* Disable bus and clean up any left over interrupt state. */
++ writel(0, bus->base + ASPEED_I2C_FUN_CTRL_REG);
++ writel(0, bus->base + ASPEED_I2C_INTR_CTRL_REG);
++ writel(0xffffffff, bus->base + ASPEED_I2C_INTR_STS_REG);
++
+ parent_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(parent_clk))
+ return PTR_ERR(parent_clk);
+@@ -1630,17 +1635,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+ strlcpy(bus->adap.name, pdev->name, sizeof(bus->adap.name));
+ i2c_set_adapdata(&bus->adap, bus);
+
+- /* Clean up any left over interrupt state. */
+- writel(0, bus->base + ASPEED_I2C_INTR_CTRL_REG);
+- writel(0xffffffff, bus->base + ASPEED_I2C_INTR_STS_REG);
+- /*
+- * bus.lock does not need to be held because the interrupt handler has
+- * not been enabled yet.
+- */
+- ret = aspeed_i2c_init(bus, pdev);
+- if (ret < 0)
+- goto out_free_dma_buf;
+-
+ irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ ret = devm_request_irq(&pdev->dev, irq, aspeed_i2c_bus_irq,
+ 0, dev_name(&pdev->dev), bus);
+@@ -1653,6 +1647,10 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, bus);
+
++ ret = aspeed_i2c_init(bus, pdev);
++ if (ret < 0)
++ goto out_free_dma_buf;
++
+ dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n",
+ bus->adap.nr, bus->dma_buf ? "dma" :
+ bus->buf_base ? "buffer" : "byte",
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0076-arm-ast2600-add-pwm_tacho-driver-from-aspeed.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0076-arm-ast2600-add-pwm_tacho-driver-from-aspeed.patch
new file mode 100644
index 000000000..9515a1a89
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0076-arm-ast2600-add-pwm_tacho-driver-from-aspeed.patch
@@ -0,0 +1,1107 @@
+From a17a084c4889dcc7cb43ef5f93032997cfcee4f0 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@intel.com>
+Date: Fri, 27 Sep 2019 13:09:48 -0700
+Subject: [PATCH] arm: ast2600: add pwm_tacho driver from aspeed
+
+Add the pwm_tacho driver from Aspeed to get pwm working until an
+upstream PWM/Tacho driver is available. This was copied from the v5.02
+BSP from Aspeed.
+
+Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g6.dtsi | 10 +
+ drivers/hwmon/Kconfig | 11 +
+ drivers/hwmon/Makefile | 1 +
+ drivers/hwmon/aspeed-g6-pwm-tacho.c | 1025 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 1047 insertions(+)
+ create mode 100644 drivers/hwmon/aspeed-g6-pwm-tacho.c
+
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index eeace4b7b725..33fcd89db6b8 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -278,6 +278,16 @@
+ #size-cells = <1>;
+ ranges;
+
++ pwm_tacho: pwm-tacho-controller@1e610000 {
++ compatible = "aspeed,ast2600-pwm-tacho";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ reg = <0x1e610000 0x100>;
++ clocks = <&syscon ASPEED_CLK_AHB>;
++ resets = <&syscon ASPEED_RESET_PWM>;
++ status = "disabled";
++ };
++
+ syscon: syscon@1e6e2000 {
+ compatible = "aspeed,ast2600-scu", "syscon", "simple-mfd";
+ reg = <0x1e6e2000 0x1000>;
+diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
+index e244a7901392..8312b3798b82 100644
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -371,6 +371,17 @@ config SENSORS_ASPEED
+ This driver can also be built as a module. If so, the module
+ will be called aspeed_pwm_tacho.
+
++config SENSORS_ASPEED_G6
++ tristate "ASPEED AST2600 PWM and Fan tach driver"
++ depends on THERMAL || THERMAL=n
++ select REGMAP
++ help
++ This driver provides support for ASPEED AST2600 PWM
++ and Fan Tacho controllers.
++
++ This driver can also be built as a module. If so, the module
++ will be called aspeed_g6_pwm_tacho.
++
+ config SENSORS_ATXP1
+ tristate "Attansic ATXP1 VID controller"
+ depends on I2C
+diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
+index 1c7ab361adc7..e74ea925fb56 100644
+--- a/drivers/hwmon/Makefile
++++ b/drivers/hwmon/Makefile
+@@ -50,6 +50,7 @@ obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o
+ obj-$(CONFIG_SENSORS_AS370) += as370-hwmon.o
+ obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
+ obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o
++obj-$(CONFIG_SENSORS_ASPEED_G6) += aspeed-g6-pwm-tacho.o
+ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
+ obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
+ obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
+diff --git a/drivers/hwmon/aspeed-g6-pwm-tacho.c b/drivers/hwmon/aspeed-g6-pwm-tacho.c
+new file mode 100644
+index 000000000000..1894f6ad5edb
+--- /dev/null
++++ b/drivers/hwmon/aspeed-g6-pwm-tacho.c
+@@ -0,0 +1,1025 @@
++/*
++ * Copyright (C) ASPEED Technology Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 or later as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/clk.h>
++#include <linux/errno.h>
++#include <linux/gpio/consumer.h>
++#include <linux/delay.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/sysfs.h>
++#include <linux/reset.h>
++#include <linux/regmap.h>
++#include <linux/thermal.h>
++
++#define ASPEED_PWM_CTRL 0x00 //PWM0 General Register
++#define ASPEED_PWM_CTRL_CH(x) ((x * 0x10) + 0x00)
++#define PWM_LOAD_AS_WDT BIT(19) //load selection as WDT
++#define PWM_DUTY_LOAD_AS_WDT_EN BIT(18) //enable PWM duty load as WDT
++#define PWM_DUTY_SYNC_DIS BIT(17) //disable PWM duty sync
++#define PWM_CLK_ENABLE BIT(16) //enable PWM clock
++#define PWM_LEVEL_OUTPUT BIT(15) //output PWM level
++#define PWM_INVERSE BIT(14) //inverse PWM pin
++#define PWM_OPEN_DRAIN_EN BIT(13) //enable open-drain
++#define PWM_PIN_EN BIT(12) //enable PWM pin
++#define PWM_CLK_DIV_H_MASK (0xf << 8) //PWM clock division H bit [3:0]
++#define PWM_CLK_DIV_L_MASK (0xff) //PWM clock division H bit [3:0]
++
++/*
++\xregmid {11:8 }{RW}{PWM clock division H bit [3:0]}{
++ 0: divide 1 \n
++ 1: divide 2 \n
++ 2: divide 4 \n
++ 3: divide 8 \n
++ ... \n
++ F: divide 32768}
++\xregmid {7 :0 }{RW}{PWM clock division L bit [7:0]}{
++ 00: divide 1 \n
++ 01: divide 2 \n
++ 02: divide 3 \n
++ 03: divide 4 \n
++ ... \n
++ FF: divide 256}
++*/
++
++#define ASPEED_PWM_DUTY_CYCLE 0x04 //PWM0 Duty Cycle Register
++#define ASPEED_PWM_DUTY_CYCLE_CH(x) ((x * 0x10) + 0x04)
++#define PWM_LOOP_BIT_MASK (0xf << 24) //loop bit [7:0]
++#define PWM_PERIOD_BIT (24) //pwm period bit [7:0]
++#define PWM_PERIOD_BIT_MASK (0xff << 24) //pwm period bit [7:0]
++#define PWM_RISING_FALLING_AS_WDT_BIT (16)
++#define PWM_RISING_FALLING_AS_WDT_MASK (0xff << 16) //pwm rising/falling point bit [7:0] as WDT
++#define PWM_RISING_FALLING_MASK (0xffff)
++#define PWM_RISING_FALLING_BIT (8) //pwm falling point bit [7:0]
++#define PWM_RISING_RISING_BIT (0) //pwm rising point bit [7:0]
++
++#define ASPEED_TACHO_CTRL 0x08 //TACH0 General Register
++#define ASPEED_TACHO_CTRL_CH(x) ((x * 0x10) + 0x08)
++#define TACHO_IER BIT(31) //enable tacho interrupt
++#define TACHO_INVERS_LIMIT BIT(30) //inverse tacho limit comparison
++#define TACHO_LOOPBACK BIT(29) //tacho loopback
++#define TACHO_ENABLE BIT(28) //{enable tacho}
++#define TACHO_DEBOUNCE_BIT (26) //{tacho de-bounce}
++#define TACHO_DEBOUNCE_MASK (0x3 << 26) //{tacho de-bounce}
++#define TECHIO_EDGE_MASK (0x3 << 24) //tacho edge}
++#define TECHIO_EDGE_BIT (24) //tacho edge}
++#define TACHO_CLK_DIV_T_MASK (0xf << 20)
++#define TACHO_CLK_DIV_BIT (20)
++#define TACHO_THRESHOLD_MASK (0xfffff) //tacho threshold bit
++/*
++\xregmid {23:20}{RW}{tacho clock division T bit [3:0]}{
++ 0: divide 1 \n
++ 1: divide 4 \n
++ 2: divide 16 \n
++ 3: divide 64 \n
++ ... \n
++ B: divide 4194304 \n
++ others: reserved}
++\xregmidb{19 :0 }{RW}{tacho threshold bit [19:0]}
++*/
++
++#define ASPEED_TACHO_STS 0x0C //TACH0 Status Register
++#define ASPEED_TACHO_STS_CH(x) ((x * 0x10) + 0x0C)
++#define TACHO_ISR BIT(31) //interrupt status and clear
++#define PWM_OUT BIT(25) //{pwm_out}
++#define PWM_OEN BIT(24) //{pwm_oeN}
++#define TACHO_DEB_INPUT BIT(23) //tacho deB input
++#define TACHO_RAW_INPUT BIT(22) //tacho raw input}
++#define TACHO_VALUE_UPDATE BIT(21) //tacho value updated since the last read
++#define TACHO_FULL_MEASUREMENT BIT(20) //{tacho full measurement}
++#define TACHO_VALUE_MASK 0xfffff //tacho value bit [19:0]}
++
++#define MAX_CDEV_NAME_LEN 16
++
++struct aspeed_pwm_channel_params {
++ int load_wdt_rising_falling_pt;
++ int load_wdt_selection; //0: rising , 1: falling
++ int load_wdt_enable;
++ int duty_sync_enable;
++ int invert_pin;
++ u8 divide_h;
++ u8 divide_l;
++ u8 period;
++ u8 rising;
++ u8 falling;
++};
++
++static struct aspeed_pwm_channel_params default_pwm_params[] = {
++ [0] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 1,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [1] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [2] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [3] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [4] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [5] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [6] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [7] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [8] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [9] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [10] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [11] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [12] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [13] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [14] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++ [15] = {
++ .load_wdt_rising_falling_pt = 0x10,
++ .load_wdt_selection = 0,
++ .load_wdt_enable = 0,
++ .duty_sync_enable = 0,
++ .invert_pin = 0,
++ .divide_h = 0x5,
++ .divide_l = 0x6,
++ .period = 0x13, //5% ~~
++ .rising = 0x00,
++ .falling = 0x0a,
++ },
++};
++
++/*
++ * 5:4 fan tach edge mode selection bit:
++ * 00: falling
++ * 01: rising
++ * 10: both
++ * 11: reserved.
++ */
++
++struct aspeed_tacho_channel_params {
++ int limited_inverse;
++ u16 threshold;
++ u8 tacho_edge;
++ u8 tacho_debounce;
++ u8 divide;
++};
++
++
++static struct aspeed_tacho_channel_params default_tacho_params[] = {
++ [0] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [1] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [2] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [3] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [4] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [5] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [6] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [7] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [8] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [9] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [10] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [11] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [12] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [13] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [14] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++ [15] = {
++ .limited_inverse = 0,
++ .threshold = 0,
++ .tacho_edge = 0,
++ .tacho_debounce = 0,
++ .divide = 8,
++ },
++};
++
++struct aspeed_pwm_tachometer_data {
++ struct regmap *regmap;
++ unsigned long clk_freq;
++ struct reset_control *reset;
++ bool pwm_present[16];
++ bool fan_tach_present[16];
++ struct aspeed_pwm_channel_params *pwm_channel;
++ struct aspeed_tacho_channel_params *tacho_channel;
++ struct aspeed_cooling_device *cdev[8];
++ const struct attribute_group *groups[3];
++};
++
++struct aspeed_cooling_device {
++ char name[16];
++ struct aspeed_pwm_tachometer_data *priv;
++ struct thermal_cooling_device *tcdev;
++ int pwm_channel;
++ u8 *cooling_levels;
++ u8 max_state;
++ u8 cur_state;
++};
++
++static int regmap_aspeed_pwm_tachometer_reg_write(void *context, unsigned int reg,
++ unsigned int val)
++{
++ void __iomem *regs = (void __iomem *)context;
++
++ writel(val, regs + reg);
++ return 0;
++}
++
++static int regmap_aspeed_pwm_tachometer_reg_read(void *context, unsigned int reg,
++ unsigned int *val)
++{
++ void __iomem *regs = (void __iomem *)context;
++
++ *val = readl(regs + reg);
++ return 0;
++}
++
++static const struct regmap_config aspeed_pwm_tachometer_regmap_config = {
++ .reg_bits = 32,
++ .val_bits = 32,
++ .reg_stride = 4,
++ .max_register = 0x100,
++ .reg_write = regmap_aspeed_pwm_tachometer_reg_write,
++ .reg_read = regmap_aspeed_pwm_tachometer_reg_read,
++ .fast_io = true,
++};
++
++static void aspeed_set_pwm_channel_enable(struct regmap *regmap, u8 pwm_channel,
++ bool enable)
++{
++ regmap_update_bits(regmap, ASPEED_PWM_CTRL_CH(pwm_channel), (PWM_CLK_ENABLE | PWM_PIN_EN), enable ? (PWM_CLK_ENABLE | PWM_PIN_EN) : 0);
++}
++
++static void aspeed_set_fan_tach_ch_enable(struct aspeed_pwm_tachometer_data *priv, u8 fan_tach_ch,
++ bool enable)
++{
++ u32 i = 0, j;
++ u32 divide_val = 0;
++ u32 reg_value = 0;
++
++ if(enable) {
++ //4 ^ n
++ //check pwm clk and to change tacho devide 25KZ
++ for(i = 0; i < 12; i++) {
++ divide_val = 1;
++ for (j = 1; j <= i; j++)
++ divide_val *= 4;
++// printk("i : %d , priv->clk_freq/divide_val %d ",i, priv->clk_freq/divide_val);
++ if((priv->clk_freq/divide_val) < 250000)
++ break;
++ }
++ i--;
++ divide_val = ((1 << i) * (1 << i));
++// printk("tacho divide_val %d , i %x max tacho clk %d \n", divide_val, i, priv->clk_freq / divide_val);
++ priv->tacho_channel[fan_tach_ch].divide = i;
++
++ reg_value = TACHO_ENABLE |
++ (priv->tacho_channel[fan_tach_ch].tacho_edge << TECHIO_EDGE_BIT) |
++ (priv->tacho_channel[fan_tach_ch].divide << TACHO_CLK_DIV_BIT) |
++ (priv->tacho_channel[fan_tach_ch].tacho_debounce << TACHO_DEBOUNCE_BIT);
++
++ if(priv->tacho_channel[fan_tach_ch].limited_inverse)
++ reg_value |= TACHO_INVERS_LIMIT;
++
++ if(priv->tacho_channel[fan_tach_ch].threshold)
++ reg_value |= (TACHO_IER | priv->tacho_channel[fan_tach_ch].threshold);
++
++ regmap_write(priv->regmap, ASPEED_TACHO_CTRL_CH(fan_tach_ch), reg_value);
++ } else
++ regmap_update_bits(priv->regmap, ASPEED_TACHO_CTRL_CH(fan_tach_ch), TACHO_ENABLE, 0);
++}
++
++static void aspeed_set_pwm_channel_fan_ctrl(struct aspeed_pwm_tachometer_data *priv,
++ u8 index, u8 fan_ctrl)
++{
++ u32 duty_value, ctrl_value;
++
++ if (fan_ctrl == 0) {
++ aspeed_set_pwm_channel_enable(priv->regmap, index, false);
++ } else {
++ duty_value = (priv->pwm_channel[index].period << PWM_PERIOD_BIT) |
++ (0 << PWM_RISING_RISING_BIT) | (fan_ctrl << PWM_RISING_FALLING_BIT);
++
++ ctrl_value = (priv->pwm_channel[index].divide_h << 8) | priv->pwm_channel[index].divide_l;
++
++ if (priv->pwm_channel[index].load_wdt_enable) {
++ ctrl_value |= PWM_DUTY_LOAD_AS_WDT_EN;
++ if(priv->pwm_channel[index].load_wdt_selection) {
++ ctrl_value |= PWM_LOAD_AS_WDT;
++ duty_value |= (priv->pwm_channel[index].load_wdt_rising_falling_pt << PWM_RISING_FALLING_AS_WDT_BIT);
++ } else {
++ duty_value |= (priv->pwm_channel[index].load_wdt_rising_falling_pt << PWM_RISING_FALLING_AS_WDT_BIT);
++ }
++ }
++
++ regmap_write(priv->regmap, ASPEED_PWM_DUTY_CYCLE_CH(index), duty_value);
++
++ regmap_write(priv->regmap, ASPEED_PWM_CTRL_CH(index), ctrl_value);
++// printk("pwm clk is %d \n", priv->clk_freq / (priv->pwm_channel[index].period + 1));
++ aspeed_set_pwm_channel_enable(priv->regmap, index, true);
++ }
++}
++
++#define BOTH_EDGES 0x02 /* 10b */
++
++static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tachometer_data *priv,
++ u8 fan_tach_ch)
++{
++ u32 raw_data, tach_div, clk_source, val;
++ u8 mode, both;
++ int i, retries = 3;
++
++ for(i = 0; i < retries; i++) {
++ regmap_read(priv->regmap, ASPEED_TACHO_STS_CH(fan_tach_ch), &val);
++ if (TACHO_FULL_MEASUREMENT & val)
++ break;
++ }
++
++ raw_data = val & TACHO_VALUE_MASK;
++ if(raw_data == 0xfffff)
++ return 0;
++
++ tach_div = priv->tacho_channel[fan_tach_ch].divide;
++ /*
++ * We need the mode to determine if the raw_data is double (from
++ * counting both edges).
++ */
++ mode = priv->tacho_channel[fan_tach_ch].tacho_edge;
++ both = (mode & BOTH_EDGES) ? 1 : 0;
++// printk("clk %ld, raw_data %x , tach_div %x both %x \n", priv->clk_freq, raw_data, tach_div, both);
++
++ tach_div = (tach_div * 2) * (0x1 << both);
++ clk_source = priv->clk_freq;
++
++ if (raw_data == 0)
++ return 0;
++
++ return (clk_source * 60) / (2 * raw_data * tach_div);
++
++}
++
++static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int index = sensor_attr->index;
++ int ret;
++ struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev);
++ long fan_ctrl;
++
++ ret = kstrtol(buf, 10, &fan_ctrl);
++ if (ret != 0)
++ return ret;
++
++ if (fan_ctrl < 0 || fan_ctrl > priv->pwm_channel[index].period)
++ return -EINVAL;
++
++ if (priv->pwm_channel[index].falling == fan_ctrl)
++ return count;
++
++ priv->pwm_channel[index].falling = fan_ctrl;
++ aspeed_set_pwm_channel_fan_ctrl(priv, index, fan_ctrl);
++
++ return count;
++}
++
++static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int index = sensor_attr->index;
++ struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev);
++
++ return sprintf(buf, "%u\n", priv->pwm_channel[index].falling);
++}
++
++static ssize_t show_rpm(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
++ int index = sensor_attr->index;
++ int rpm;
++ struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev);
++
++ rpm = aspeed_get_fan_tach_ch_rpm(priv, index);
++ if (rpm < 0)
++ return rpm;
++
++ return sprintf(buf, "%d\n", rpm);
++}
++
++static umode_t pwm_is_visible(struct kobject *kobj,
++ struct attribute *a, int index)
++{
++ struct device *dev = container_of(kobj, struct device, kobj);
++ struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev);
++
++ if (!priv->pwm_present[index])
++ return 0;
++ return a->mode;
++}
++
++static umode_t fan_dev_is_visible(struct kobject *kobj,
++ struct attribute *a, int index)
++{
++ struct device *dev = container_of(kobj, struct device, kobj);
++ struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev);
++
++ if (!priv->fan_tach_present[index])
++ return 0;
++ return a->mode;
++}
++
++static SENSOR_DEVICE_ATTR(pwm0, 0644,
++ show_pwm, set_pwm, 0);
++static SENSOR_DEVICE_ATTR(pwm1, 0644,
++ show_pwm, set_pwm, 1);
++static SENSOR_DEVICE_ATTR(pwm2, 0644,
++ show_pwm, set_pwm, 2);
++static SENSOR_DEVICE_ATTR(pwm3, 0644,
++ show_pwm, set_pwm, 3);
++static SENSOR_DEVICE_ATTR(pwm4, 0644,
++ show_pwm, set_pwm, 4);
++static SENSOR_DEVICE_ATTR(pwm5, 0644,
++ show_pwm, set_pwm, 5);
++static SENSOR_DEVICE_ATTR(pwm6, 0644,
++ show_pwm, set_pwm, 6);
++static SENSOR_DEVICE_ATTR(pwm7, 0644,
++ show_pwm, set_pwm, 7);
++static SENSOR_DEVICE_ATTR(pwm8, 0644,
++ show_pwm, set_pwm, 8);
++static SENSOR_DEVICE_ATTR(pwm9, 0644,
++ show_pwm, set_pwm, 9);
++static SENSOR_DEVICE_ATTR(pwm10, 0644,
++ show_pwm, set_pwm, 10);
++static SENSOR_DEVICE_ATTR(pwm11, 0644,
++ show_pwm, set_pwm, 11);
++static SENSOR_DEVICE_ATTR(pwm12, 0644,
++ show_pwm, set_pwm, 12);
++static SENSOR_DEVICE_ATTR(pwm13, 0644,
++ show_pwm, set_pwm, 13);
++static SENSOR_DEVICE_ATTR(pwm14, 0644,
++ show_pwm, set_pwm, 14);
++static SENSOR_DEVICE_ATTR(pwm15, 0644,
++ show_pwm, set_pwm, 15);
++static struct attribute *pwm_dev_attrs[] = {
++ &sensor_dev_attr_pwm0.dev_attr.attr,
++ &sensor_dev_attr_pwm1.dev_attr.attr,
++ &sensor_dev_attr_pwm2.dev_attr.attr,
++ &sensor_dev_attr_pwm3.dev_attr.attr,
++ &sensor_dev_attr_pwm4.dev_attr.attr,
++ &sensor_dev_attr_pwm5.dev_attr.attr,
++ &sensor_dev_attr_pwm6.dev_attr.attr,
++ &sensor_dev_attr_pwm7.dev_attr.attr,
++ &sensor_dev_attr_pwm8.dev_attr.attr,
++ &sensor_dev_attr_pwm9.dev_attr.attr,
++ &sensor_dev_attr_pwm10.dev_attr.attr,
++ &sensor_dev_attr_pwm11.dev_attr.attr,
++ &sensor_dev_attr_pwm12.dev_attr.attr,
++ &sensor_dev_attr_pwm13.dev_attr.attr,
++ &sensor_dev_attr_pwm14.dev_attr.attr,
++ &sensor_dev_attr_pwm15.dev_attr.attr,
++ NULL,
++};
++
++static const struct attribute_group pwm_dev_group = {
++ .attrs = pwm_dev_attrs,
++ .is_visible = pwm_is_visible,
++};
++
++static SENSOR_DEVICE_ATTR(fan0_input, 0444,
++ show_rpm, NULL, 0);
++static SENSOR_DEVICE_ATTR(fan1_input, 0444,
++ show_rpm, NULL, 1);
++static SENSOR_DEVICE_ATTR(fan2_input, 0444,
++ show_rpm, NULL, 2);
++static SENSOR_DEVICE_ATTR(fan3_input, 0444,
++ show_rpm, NULL, 3);
++static SENSOR_DEVICE_ATTR(fan4_input, 0444,
++ show_rpm, NULL, 4);
++static SENSOR_DEVICE_ATTR(fan5_input, 0444,
++ show_rpm, NULL, 5);
++static SENSOR_DEVICE_ATTR(fan6_input, 0444,
++ show_rpm, NULL, 6);
++static SENSOR_DEVICE_ATTR(fan7_input, 0444,
++ show_rpm, NULL, 7);
++static SENSOR_DEVICE_ATTR(fan8_input, 0444,
++ show_rpm, NULL, 8);
++static SENSOR_DEVICE_ATTR(fan9_input, 0444,
++ show_rpm, NULL, 9);
++static SENSOR_DEVICE_ATTR(fan10_input, 0444,
++ show_rpm, NULL, 10);
++static SENSOR_DEVICE_ATTR(fan11_input, 0444,
++ show_rpm, NULL, 11);
++static SENSOR_DEVICE_ATTR(fan12_input, 0444,
++ show_rpm, NULL, 12);
++static SENSOR_DEVICE_ATTR(fan13_input, 0444,
++ show_rpm, NULL, 13);
++static SENSOR_DEVICE_ATTR(fan14_input, 0444,
++ show_rpm, NULL, 14);
++static SENSOR_DEVICE_ATTR(fan15_input, 0444,
++ show_rpm, NULL, 15);
++static struct attribute *fan_dev_attrs[] = {
++ &sensor_dev_attr_fan0_input.dev_attr.attr,
++ &sensor_dev_attr_fan1_input.dev_attr.attr,
++ &sensor_dev_attr_fan2_input.dev_attr.attr,
++ &sensor_dev_attr_fan3_input.dev_attr.attr,
++ &sensor_dev_attr_fan4_input.dev_attr.attr,
++ &sensor_dev_attr_fan5_input.dev_attr.attr,
++ &sensor_dev_attr_fan6_input.dev_attr.attr,
++ &sensor_dev_attr_fan7_input.dev_attr.attr,
++ &sensor_dev_attr_fan8_input.dev_attr.attr,
++ &sensor_dev_attr_fan9_input.dev_attr.attr,
++ &sensor_dev_attr_fan10_input.dev_attr.attr,
++ &sensor_dev_attr_fan11_input.dev_attr.attr,
++ &sensor_dev_attr_fan12_input.dev_attr.attr,
++ &sensor_dev_attr_fan13_input.dev_attr.attr,
++ &sensor_dev_attr_fan14_input.dev_attr.attr,
++ &sensor_dev_attr_fan15_input.dev_attr.attr,
++ NULL
++};
++
++static const struct attribute_group fan_dev_group = {
++ .attrs = fan_dev_attrs,
++ .is_visible = fan_dev_is_visible,
++};
++
++static void aspeed_create_pwm_channel(struct aspeed_pwm_tachometer_data *priv,
++ u8 pwm_channel)
++{
++ priv->pwm_present[pwm_channel] = true;
++
++ //use default
++ aspeed_set_pwm_channel_fan_ctrl(priv, pwm_channel, priv->pwm_channel[pwm_channel].falling);
++}
++
++static void aspeed_create_fan_tach_channel(struct aspeed_pwm_tachometer_data *priv,
++ u8 *fan_tach_ch,
++ int count)
++{
++ u8 val, index;
++
++ for (val = 0; val < count; val++) {
++ index = fan_tach_ch[val];
++ priv->fan_tach_present[index] = true;
++ aspeed_set_fan_tach_ch_enable(priv, index, true);
++ }
++}
++
++static int
++aspeed_pwm_cz_get_max_state(struct thermal_cooling_device *tcdev,
++ unsigned long *state)
++{
++ struct aspeed_cooling_device *cdev = tcdev->devdata;
++
++ *state = cdev->max_state;
++
++ return 0;
++}
++
++static int
++aspeed_pwm_cz_get_cur_state(struct thermal_cooling_device *tcdev,
++ unsigned long *state)
++{
++ struct aspeed_cooling_device *cdev = tcdev->devdata;
++
++ *state = cdev->cur_state;
++
++ return 0;
++}
++
++static int
++aspeed_pwm_cz_set_cur_state(struct thermal_cooling_device *tcdev,
++ unsigned long state)
++{
++ struct aspeed_cooling_device *cdev = tcdev->devdata;
++
++ if (state > cdev->max_state)
++ return -EINVAL;
++
++ cdev->cur_state = state;
++ cdev->priv->pwm_channel[cdev->pwm_channel].falling =
++ cdev->cooling_levels[cdev->cur_state];
++ aspeed_set_pwm_channel_fan_ctrl(cdev->priv, cdev->pwm_channel,
++ cdev->cooling_levels[cdev->cur_state]);
++
++ return 0;
++}
++
++static const struct thermal_cooling_device_ops aspeed_pwm_cool_ops = {
++ .get_max_state = aspeed_pwm_cz_get_max_state,
++ .get_cur_state = aspeed_pwm_cz_get_cur_state,
++ .set_cur_state = aspeed_pwm_cz_set_cur_state,
++};
++
++static int aspeed_create_pwm_cooling(struct device *dev,
++ struct device_node *child,
++ struct aspeed_pwm_tachometer_data *priv,
++ u32 pwm_channel, u8 num_levels)
++{
++ int ret;
++ struct aspeed_cooling_device *cdev;
++
++ cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL);
++ if (!cdev)
++ return -ENOMEM;
++
++ cdev->cooling_levels = devm_kzalloc(dev, num_levels, GFP_KERNEL);
++ if (!cdev->cooling_levels)
++ return -ENOMEM;
++
++ cdev->max_state = num_levels - 1;
++ ret = of_property_read_u8_array(child, "cooling-levels",
++ cdev->cooling_levels,
++ num_levels);
++ if (ret) {
++ dev_err(dev, "Property 'cooling-levels' cannot be read.\n");
++ return ret;
++ }
++ snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%s%d", child->name, pwm_channel);
++
++ cdev->tcdev = thermal_of_cooling_device_register(child,
++ cdev->name,
++ cdev,
++ &aspeed_pwm_cool_ops);
++ if (IS_ERR(cdev->tcdev))
++ return PTR_ERR(cdev->tcdev);
++
++ cdev->priv = priv;
++ cdev->pwm_channel = pwm_channel;
++
++ priv->cdev[pwm_channel] = cdev;
++
++ return 0;
++}
++
++static int aspeed_pwm_create_fan(struct device *dev,
++ struct device_node *child,
++ struct aspeed_pwm_tachometer_data *priv)
++{
++ u8 *fan_tach_ch;
++ u32 pwm_channel;
++ int ret, count;
++
++ ret = of_property_read_u32(child, "reg", &pwm_channel);
++ if (ret)
++ return ret;
++
++ aspeed_create_pwm_channel(priv, (u8)pwm_channel);
++
++ ret = of_property_count_u8_elems(child, "cooling-levels");
++ if (ret > 0) {
++ ret = aspeed_create_pwm_cooling(dev, child, priv, pwm_channel,
++ ret);
++ if (ret)
++ return ret;
++ }
++
++ count = of_property_count_u8_elems(child, "aspeed,fan-tach-ch");
++ if (count < 1)
++ return -EINVAL;
++
++ fan_tach_ch = devm_kzalloc(dev, sizeof(*fan_tach_ch) * count,
++ GFP_KERNEL);
++ if (!fan_tach_ch)
++ return -ENOMEM;
++ ret = of_property_read_u8_array(child, "aspeed,fan-tach-ch",
++ fan_tach_ch, count);
++ if (ret)
++ return ret;
++
++ aspeed_create_fan_tach_channel(priv, fan_tach_ch, count);
++
++ return 0;
++}
++
++static int aspeed_pwm_tachometer_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *np, *child;
++ struct aspeed_pwm_tachometer_data *priv;
++ void __iomem *regs;
++ struct resource *res;
++ struct device *hwmon;
++ struct clk *clk;
++ int ret;
++
++ np = dev->of_node;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res)
++ return -ENOENT;
++ 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->pwm_channel = default_pwm_params;
++ priv->tacho_channel = default_tacho_params;
++ priv->regmap = devm_regmap_init(dev, NULL, (__force void *)regs,
++ &aspeed_pwm_tachometer_regmap_config);
++ if (IS_ERR(priv->regmap))
++ return PTR_ERR(priv->regmap);
++
++ clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(clk))
++ return -ENODEV;
++ priv->clk_freq = clk_get_rate(clk);
++
++ priv->reset = devm_reset_control_get(&pdev->dev, NULL);
++ if (IS_ERR(priv->reset)) {
++ dev_err(&pdev->dev, "can't get aspeed_pwm_tacho reset\n");
++ return PTR_ERR(priv->reset);
++ }
++
++ //scu init
++ reset_control_assert(priv->reset);
++ reset_control_deassert(priv->reset);
++
++ for_each_child_of_node(np, child) {
++ ret = aspeed_pwm_create_fan(dev, child, priv);
++ if (ret) {
++ of_node_put(child);
++ return ret;
++ }
++ }
++
++ priv->groups[0] = &pwm_dev_group;
++ priv->groups[1] = &fan_dev_group;
++ priv->groups[2] = NULL;
++ hwmon = devm_hwmon_device_register_with_groups(dev,
++ "aspeed_g6_pwm_tacho",
++ priv, priv->groups);
++
++ return PTR_ERR_OR_ZERO(hwmon);
++}
++
++static const struct of_device_id of_pwm_tachometer_match_table[] = {
++ { .compatible = "aspeed,ast2600-pwm-tacho", },
++ {},
++};
++MODULE_DEVICE_TABLE(of, of_pwm_tachometer_match_table);
++
++static struct platform_driver aspeed_pwm_tachometer_driver = {
++ .probe = aspeed_pwm_tachometer_probe,
++ .driver = {
++ .name = "aspeed_g6_pwm_tacho",
++ .of_match_table = of_pwm_tachometer_match_table,
++ },
++};
++
++module_platform_driver(aspeed_pwm_tachometer_driver);
++
++MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
++MODULE_DESCRIPTION("ASPEED PWM and Fan Tachometer device driver");
++MODULE_LICENSE("GPL");
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0077-soc-aspeed-Add-read-only-property-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0077-soc-aspeed-Add-read-only-property-support.patch
new file mode 100644
index 000000000..7ea00a4a2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0077-soc-aspeed-Add-read-only-property-support.patch
@@ -0,0 +1,47 @@
+From f2d62c90f2ea05b1abf9a1887502122eefb5906d Mon Sep 17 00:00:00 2001
+From: Yong Li <yong.b.li@linux.intel.com>
+Date: Wed, 16 Oct 2019 15:11:06 +0800
+Subject: [PATCH] soc: aspeed: Add read-only property support
+
+Add a read-only property, to support export register bits as read-only.
+
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ drivers/soc/aspeed/aspeed-bmc-misc.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/soc/aspeed/aspeed-bmc-misc.c b/drivers/soc/aspeed/aspeed-bmc-misc.c
+index 314007b..bf88376 100644
+--- a/drivers/soc/aspeed/aspeed-bmc-misc.c
++++ b/drivers/soc/aspeed/aspeed-bmc-misc.c
+@@ -15,6 +15,7 @@ struct aspeed_bmc_ctrl {
+ u32 offset;
+ u32 mask;
+ u32 shift;
++ bool read_only;
+ struct regmap *map;
+ struct kobj_attribute attr;
+ };
+@@ -55,6 +56,8 @@ static int aspeed_bmc_misc_parse_dt_child(struct device_node *child,
+ if (rc < 0)
+ return rc;
+
++ ctrl->read_only = of_property_read_bool(child, "read-only");
++
+ ctrl->mask <<= ctrl->shift;
+
+ return 0;
+@@ -116,6 +119,10 @@ static ssize_t aspeed_bmc_misc_store(struct kobject *kobj,
+ return rc;
+
+ ctrl = container_of(attr, struct aspeed_bmc_ctrl, attr);
++
++ if (ctrl->read_only)
++ return -EROFS;
++
+ val <<= ctrl->shift;
+ rc = regmap_update_bits(ctrl->map, ctrl->offset, ctrl->mask, val);
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0078-Fix-NCSI-driver-issue-caused-by-host-shutdown.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0078-Fix-NCSI-driver-issue-caused-by-host-shutdown.patch
new file mode 100644
index 000000000..09a957860
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0078-Fix-NCSI-driver-issue-caused-by-host-shutdown.patch
@@ -0,0 +1,70 @@
+From 3eaf814c51f85aaad0d181d27ff686ce35b31d6a Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Tue, 29 Oct 2019 11:28:29 +0800
+Subject: [PATCH] Fix NCSI driver issue caused by host shutdown due to
+ overheated.
+
+NCSI device cannot be recovered when host shutdown due to overheated.
+
+Tested:
+Heat host till shutdown due to overheated and then
+run the ipmi command like power status
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ net/ncsi/ncsi-manage.c | 18 +++++++++++++-----
+ 1 file changed, 13 insertions(+), 5 deletions(-)
+
+diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
+index 70fe02697544..4e16a0015f26 100644
+--- a/net/ncsi/ncsi-manage.c
++++ b/net/ncsi/ncsi-manage.c
+@@ -132,18 +132,15 @@ static void ncsi_channel_monitor(struct timer_list *t)
+ netdev_err(ndp->ndev.dev, "NCSI Channel %d timed out!\n",
+ nc->id);
+ ncsi_report_link(ndp, true);
+- ndp->flags |= NCSI_DEV_RESHUFFLE;
+
+ ncsi_stop_channel_monitor(nc);
+
+- ncm = &nc->modes[NCSI_MODE_LINK];
+ spin_lock_irqsave(&nc->lock, flags);
+- nc->state = NCSI_CHANNEL_INVISIBLE;
+- ncm->data[2] &= ~0x1;
++ nc->state = NCSI_CHANNEL_INACTIVE;
+ spin_unlock_irqrestore(&nc->lock, flags);
+
+ spin_lock_irqsave(&ndp->lock, flags);
+- nc->state = NCSI_CHANNEL_ACTIVE;
++ ndp->flags |= NCSI_DEV_RESHUFFLE | NCSI_DEV_RESET;
+ list_add_tail_rcu(&nc->link, &ndp->channel_queue);
+ spin_unlock_irqrestore(&ndp->lock, flags);
+ ncsi_process_next_channel(ndp);
+@@ -424,6 +421,7 @@ static void ncsi_request_timeout(struct timer_list *t)
+ {
+ struct ncsi_request *nr = from_timer(nr, t, timer);
+ struct ncsi_dev_priv *ndp = nr->ndp;
++ struct ncsi_dev *nd = &ndp->ndev;
+ struct ncsi_cmd_pkt *cmd;
+ struct ncsi_package *np;
+ struct ncsi_channel *nc;
+@@ -438,6 +436,16 @@ static void ncsi_request_timeout(struct timer_list *t)
+ spin_unlock_irqrestore(&ndp->lock, flags);
+ return;
+ }
++ if (nd->state == ncsi_dev_state_suspend ||
++ nd->state == ncsi_dev_state_suspend_select ||
++ nd->state == ncsi_dev_state_suspend_gls ||
++ nd->state == ncsi_dev_state_suspend_dcnt ||
++ nd->state == ncsi_dev_state_suspend_dc ||
++ nd->state == ncsi_dev_state_suspend_deselect ||
++ nd->state == ncsi_dev_state_suspend_done) {
++ ndp->flags |= NCSI_DEV_RESET;
++ nd->state = ncsi_dev_state_suspend_done;
++ }
+ spin_unlock_irqrestore(&ndp->lock, flags);
+
+ if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0080-i2c-aspeed-filter-garbage-interrupts-out.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0080-i2c-aspeed-filter-garbage-interrupts-out.patch
new file mode 100644
index 000000000..89e7b894f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0080-i2c-aspeed-filter-garbage-interrupts-out.patch
@@ -0,0 +1,56 @@
+From a90b8f7dfcfcab2d40d1a575e3948ef3a34f643f Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Fri, 8 Nov 2019 15:57:27 -0800
+Subject: [PATCH] i2c: aspeed: filter garbage interrupts out
+
+AST2600 makes a garbage interrupt which is decribed as 'reserved'
+in datasheet so filter them out.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/i2c/busses/i2c-aspeed.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index 62b803e15ce2..c24cecdcfe89 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -87,7 +87,11 @@
+ * These share bit definitions, so use the same values for the enable &
+ * status bits.
+ */
++#if defined(CONFIG_MACH_ASPEED_G6)
++#define ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING BIT(29)
++#else
+ #define ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING BIT(30)
++#endif
+ #define ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT BIT(15)
+ #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14)
+ #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13)
+@@ -118,6 +122,11 @@
+ ASPEED_I2CD_INTR_RX_DONE | \
+ ASPEED_I2CD_INTR_TX_NAK | \
+ ASPEED_I2CD_INTR_TX_ACK)
++#define ASPEED_I2CD_INTR_STATUS_MASK \
++ (ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING | \
++ ASPEED_I2CD_INTR_GCALL_ADDR | \
++ ASPEED_I2CD_INTR_SLAVE_MATCH | \
++ ASPEED_I2CD_INTR_ALL)
+
+ /* 0x14 : I2CD Command/Status Register */
+ #define ASPEED_I2CD_SCL_LINE_STS BIT(18)
+@@ -1021,6 +1030,11 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
+ /* Ack all interrupts except for Rx done */
+ writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE,
+ bus->base + ASPEED_I2C_INTR_STS_REG);
++ /*
++ * AST2600 makes a garbage interrupt which is decribed as 'reserved'
++ * in datasheet so filter them out.
++ */
++ irq_received &= ASPEED_I2CD_INTR_STATUS_MASK;
+ irq_remaining = irq_received;
+
+ #if IS_ENABLED(CONFIG_I2C_SLAVE)
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0084-ARM-dts-aspeed-g6-add-GFX-node.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0084-ARM-dts-aspeed-g6-add-GFX-node.patch
new file mode 100644
index 000000000..f578d0f04
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0084-ARM-dts-aspeed-g6-add-GFX-node.patch
@@ -0,0 +1,35 @@
+From 523bbaaf9f9d064c9cf1f627d64dd7ba169d175d Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 20 Nov 2019 15:01:06 -0800
+Subject: [PATCH] ARM: dts: aspeed-g6: add GFX node
+
+This commit adds GFX node for AST2600 SoC.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g6.dtsi | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index b880e8e8f999..3e2153416e11 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -330,6 +330,15 @@
+ quality = <100>;
+ };
+
++ gfx: display@1e6e6000 {
++ compatible = "aspeed,ast2600-gfx", "syscon";
++ reg = <0x1e6e6000 0x1000>;
++ reg-io-width = <4>;
++ clocks = <&syscon ASPEED_CLK_GATE_D1CLK>;
++ status = "disabled";
++ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
+ adc: adc@1e6e9000 {
+ compatible = "aspeed,ast2500-adc";
+ reg = <0x1e6e9000 0x100>;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0085-drm-add-AST2600-GFX-support.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0085-drm-add-AST2600-GFX-support.patch
new file mode 100644
index 000000000..259720e87
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0085-drm-add-AST2600-GFX-support.patch
@@ -0,0 +1,105 @@
+From 195cd60ff2fe38b18ebdea90245b908548f4e985 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 20 Nov 2019 14:58:24 -0800
+Subject: [PATCH] drm: add AST2600 GFX support
+
+This commit adds support for AST2600 GFX.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/gpu/drm/aspeed/aspeed_gfx.h | 4 ++++
+ drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c | 6 +++---
+ drivers/gpu/drm/aspeed/aspeed_gfx_drv.c | 18 +++++++++++-------
+ 3 files changed, 18 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx.h b/drivers/gpu/drm/aspeed/aspeed_gfx.h
+index a10358bb61ec..eebd72eb1220 100644
+--- a/drivers/gpu/drm/aspeed/aspeed_gfx.h
++++ b/drivers/gpu/drm/aspeed/aspeed_gfx.h
+@@ -13,11 +13,15 @@ struct aspeed_gfx {
+ struct drm_simple_display_pipe pipe;
+ struct drm_connector connector;
+ struct drm_fbdev_cma *fbdev;
++ u32 scu_misc_offset;
+ };
+
+ int aspeed_gfx_create_pipe(struct drm_device *drm);
+ int aspeed_gfx_create_output(struct drm_device *drm);
+
++#define SCU_MISC_AST2500 0x2c /* SCU Misc of AST2500 */
++#define SCU_MISC_AST2600 0xc0 /* SCU Misc1 of AST2600 */
++
+ #define CRT_CTRL1 0x60 /* CRT Control I */
+ #define CRT_CTRL2 0x64 /* CRT Control II */
+ #define CRT_STATUS 0x68 /* CRT Status */
+diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c
+index 2184b8be6fd4..86359a0fe05f 100644
+--- a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c
++++ b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c
+@@ -59,8 +59,8 @@ static void aspeed_gfx_enable_controller(struct aspeed_gfx *priv)
+ u32 ctrl1 = readl(priv->base + CRT_CTRL1);
+ u32 ctrl2 = readl(priv->base + CRT_CTRL2);
+
+- /* SCU2C: set DAC source for display output to Graphics CRT (GFX) */
+- regmap_update_bits(priv->scu, 0x2c, BIT(16), BIT(16));
++ /* Set DAC source for display output to Graphics CRT (GFX) */
++ regmap_update_bits(priv->scu, priv->scu_misc_offset, BIT(16), BIT(16));
+
+ writel(ctrl1 | CRT_CTRL_EN, priv->base + CRT_CTRL1);
+ writel(ctrl2 | CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2);
+@@ -74,7 +74,7 @@ static void aspeed_gfx_disable_controller(struct aspeed_gfx *priv)
+ writel(ctrl1 & ~CRT_CTRL_EN, priv->base + CRT_CTRL1);
+ writel(ctrl2 & ~CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2);
+
+- regmap_update_bits(priv->scu, 0x2c, BIT(16), 0);
++ regmap_update_bits(priv->scu, priv->scu_misc_offset, BIT(16), 0);
+ }
+
+ static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv)
+diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
+index ada2f6aca906..92bc9b475e0f 100644
+--- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
++++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c
+@@ -112,8 +112,14 @@ static int aspeed_gfx_load(struct drm_device *drm)
+
+ priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu");
+ if (IS_ERR(priv->scu)) {
+- dev_err(&pdev->dev, "failed to find SCU regmap\n");
+- return PTR_ERR(priv->scu);
++ priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2600-scu");
++ if (IS_ERR(priv->scu)) {
++ dev_err(&pdev->dev, "failed to find SCU regmap\n");
++ return PTR_ERR(priv->scu);
++ }
++ priv->scu_misc_offset = SCU_MISC_AST2600;
++ } else {
++ priv->scu_misc_offset = SCU_MISC_AST2500;
+ }
+
+ ret = of_reserved_mem_device_init(drm->dev);
+@@ -130,12 +136,9 @@ static int aspeed_gfx_load(struct drm_device *drm)
+ }
+
+ priv->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+- if (IS_ERR(priv->rst)) {
+- dev_err(&pdev->dev,
+- "missing or invalid reset controller device tree entry");
+- return PTR_ERR(priv->rst);
++ if (!IS_ERR_OR_NULL(priv->rst)) {
++ reset_control_deassert(priv->rst);
+ }
+- reset_control_deassert(priv->rst);
+
+ priv->clk = devm_clk_get(drm->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+@@ -211,6 +214,7 @@ static struct drm_driver aspeed_gfx_driver = {
+
+ static const struct of_device_id aspeed_gfx_match[] = {
+ { .compatible = "aspeed,ast2500-gfx" },
++ { .compatible = "aspeed,ast2600-gfx" },
+ { }
+ };
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch
new file mode 100644
index 000000000..4dde9fb06
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch
@@ -0,0 +1,271 @@
+From 278db13a36f128b84f76fc0f0f13860b5bf62588 Mon Sep 17 00:00:00 2001
+From: Chen Yugang <yugang.chen@linux.intel.com>
+Date: Tue, 3 Dec 2019 13:41:37 +0800
+Subject: [PATCH] ADC linux driver for AST2600
+
+Tested:
+it's tested with DC input.
+
+Signed-off-by: Chen Yugang <yugang.chen@linux.intel.com>
+---
+ arch/arm/boot/dts/aspeed-g6.dtsi | 14 +++++-
+ drivers/iio/adc/aspeed_adc.c | 99 +++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 99 insertions(+), 14 deletions(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index 3e2153416e11..5acc1085526d 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -339,12 +339,22 @@
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+- adc: adc@1e6e9000 {
+- compatible = "aspeed,ast2500-adc";
++ adc0: adc@1e6e9000 {
++ compatible = "aspeed,ast2600-adc";
+ reg = <0x1e6e9000 0x100>;
+ clocks = <&syscon ASPEED_CLK_APB2>;
++ resets = <&syscon ASPEED_RESET_ADC>;
+ interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
++ #io-channel-cells = <1>;
++ status = "disabled";
++ };
++
++ adc1: adc@1e6e9100 {
++ compatible = "aspeed,ast2600-adc";
++ reg = <0x1e6e9100 0x100>;
++ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_ADC>;
++ interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+ #io-channel-cells = <1>;
+ status = "disabled";
+ };
+diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
+index d3fc39df535d..1dd5a97a16bc 100644
+--- a/drivers/iio/adc/aspeed_adc.c
++++ b/drivers/iio/adc/aspeed_adc.c
+@@ -1,8 +1,12 @@
+-// SPDX-License-Identifier: GPL-2.0-only
+ /*
+- * Aspeed AST2400/2500 ADC
++ * Aspeed AST2400/2500/2600 ADC
+ *
+ * Copyright (C) 2017 Google, Inc.
++ * Copyright (C) ASPEED Technology Inc.
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
+ */
+
+ #include <linux/clk.h>
+@@ -30,6 +34,14 @@
+ #define ASPEED_REG_CLOCK_CONTROL 0x0C
+ #define ASPEED_REG_MAX 0xC0
+
++/* ast2600 */
++#define REF_VLOTAGE_2500mV 0
++#define REF_VLOTAGE_1200mV GENMASK(6, 6)
++#define REF_VLOTAGE_1550mV GENMASK(7, 7)
++#define REF_VLOTAGE_900mV GENMASK(7, 6)
++
++#define ASPEED_AUTOPENSATING BIT(5)
++
+ #define ASPEED_OPERATION_MODE_POWER_DOWN (0x0 << 1)
+ #define ASPEED_OPERATION_MODE_STANDBY (0x1 << 1)
+ #define ASPEED_OPERATION_MODE_NORMAL (0x7 << 1)
+@@ -45,8 +57,10 @@ struct aspeed_adc_model_data {
+ const char *model_name;
+ unsigned int min_sampling_rate; // Hz
+ unsigned int max_sampling_rate; // Hz
+- unsigned int vref_voltage; // mV
++ u32 vref_voltage; // mV
+ bool wait_init_sequence;
++ struct iio_chan_spec const *channels;
++ int num_channels;
+ };
+
+ struct aspeed_adc_data {
+@@ -56,6 +70,7 @@ struct aspeed_adc_data {
+ struct clk_hw *clk_prescaler;
+ struct clk_hw *clk_scaler;
+ struct reset_control *rst;
++ int cv;
+ };
+
+ #define ASPEED_CHAN(_idx, _data_reg_addr) { \
+@@ -87,6 +102,17 @@ static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
+ ASPEED_CHAN(15, 0x2E),
+ };
+
++static const struct iio_chan_spec ast2600_adc_iio_channels[] = {
++ ASPEED_CHAN(0, 0x10),
++ ASPEED_CHAN(1, 0x12),
++ ASPEED_CHAN(2, 0x14),
++ ASPEED_CHAN(3, 0x16),
++ ASPEED_CHAN(4, 0x18),
++ ASPEED_CHAN(5, 0x1A),
++ ASPEED_CHAN(6, 0x1C),
++ ASPEED_CHAN(7, 0x1E),
++};
++
+ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+@@ -175,7 +201,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
+ const struct aspeed_adc_model_data *model_data;
+ struct resource *res;
+ const char *clk_parent_name;
++ char prescaler_clk_name[32];
++ char scaler_clk_name[32];
+ int ret;
++ u32 eng_ctrl = 0;
+ u32 adc_engine_control_reg_val;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
+@@ -194,19 +223,21 @@ static int aspeed_adc_probe(struct platform_device *pdev)
+ spin_lock_init(&data->clk_lock);
+ clk_parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
+
++ snprintf(prescaler_clk_name, sizeof(prescaler_clk_name), "prescaler-%s", pdev->name);
+ data->clk_prescaler = clk_hw_register_divider(
+- &pdev->dev, "prescaler", clk_parent_name, 0,
++ &pdev->dev, prescaler_clk_name, clk_parent_name, 0,
+ data->base + ASPEED_REG_CLOCK_CONTROL,
+ 17, 15, 0, &data->clk_lock);
+ if (IS_ERR(data->clk_prescaler))
+ return PTR_ERR(data->clk_prescaler);
+
++ snprintf(scaler_clk_name, sizeof(scaler_clk_name), "scaler-%s", pdev->name);
+ /*
+ * Register ADC clock scaler downstream from the prescaler. Allow rate
+ * setting to adjust the prescaler as well.
+ */
+ data->clk_scaler = clk_hw_register_divider(
+- &pdev->dev, "scaler", "prescaler",
++ &pdev->dev, scaler_clk_name, prescaler_clk_name,
+ CLK_SET_RATE_PARENT,
+ data->base + ASPEED_REG_CLOCK_CONTROL,
+ 0, 10, 0, &data->clk_lock);
+@@ -215,7 +246,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
+ goto scaler_error;
+ }
+
+- data->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
++ data->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
+ if (IS_ERR(data->rst)) {
+ dev_err(&pdev->dev,
+ "invalid or missing reset controller device tree entry");
+@@ -225,11 +256,26 @@ static int aspeed_adc_probe(struct platform_device *pdev)
+ reset_control_deassert(data->rst);
+
+ model_data = of_device_get_match_data(&pdev->dev);
++ if (!of_property_read_u32(pdev->dev.of_node, "ref_voltage", (u32 *)&model_data->vref_voltage)) {
++ if (model_data->vref_voltage == 2500)
++ eng_ctrl = REF_VLOTAGE_2500mV;
++ else if (model_data->vref_voltage == 1200)
++ eng_ctrl = REF_VLOTAGE_1200mV;
++ else if ((model_data->vref_voltage >= 1550) && (model_data->vref_voltage <= 2700))
++ eng_ctrl = REF_VLOTAGE_1550mV;
++ else if ((model_data->vref_voltage >= 900) && (model_data->vref_voltage <= 1650))
++ eng_ctrl = REF_VLOTAGE_900mV;
++ else {
++ printk("error ref voltage %d \n", model_data->vref_voltage);
++ eng_ctrl = 0;
++ }
++ } else
++ eng_ctrl = 0;
+
+ if (model_data->wait_init_sequence) {
+ /* Enable engine in normal mode. */
+- writel(ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE,
+- data->base + ASPEED_REG_ENGINE_CONTROL);
++ eng_ctrl |= ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE;
++ writel(eng_ctrl, data->base + ASPEED_REG_ENGINE_CONTROL);
+
+ /* Wait for initial sequence complete. */
+ ret = readl_poll_timeout(data->base + ASPEED_REG_ENGINE_CONTROL,
+@@ -242,12 +288,26 @@ static int aspeed_adc_probe(struct platform_device *pdev)
+ goto poll_timeout_error;
+ }
+
++ /* do compensating calculation use ch 0 */
++ writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL |
++ ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL);
++
++ writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL | BIT(16) |
++ ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL);
++ mdelay(1);
++
++ data->cv = 0x200 - (readl(data->base + 0x10) & GENMASK(9, 0));
++
++ writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL |
++ ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL);
++ printk(KERN_INFO "aspeed_adc: cv %d \n", data->cv);
++
+ /* Start all channels in normal mode. */
+ ret = clk_prepare_enable(data->clk_scaler->clk);
+ if (ret)
+ goto clk_enable_error;
+
+- adc_engine_control_reg_val = GENMASK(31, 16) |
++ adc_engine_control_reg_val = eng_ctrl | GENMASK(31, 16) |
+ ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE;
+ writel(adc_engine_control_reg_val,
+ data->base + ASPEED_REG_ENGINE_CONTROL);
+@@ -257,8 +317,8 @@ static int aspeed_adc_probe(struct platform_device *pdev)
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &aspeed_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+- indio_dev->channels = aspeed_adc_iio_channels;
+- indio_dev->num_channels = ARRAY_SIZE(aspeed_adc_iio_channels);
++ indio_dev->channels = model_data->channels;
++ indio_dev->num_channels = model_data->num_channels;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+@@ -301,6 +361,8 @@ static const struct aspeed_adc_model_data ast2400_model_data = {
+ .vref_voltage = 2500, // mV
+ .min_sampling_rate = 10000,
+ .max_sampling_rate = 500000,
++ .channels = aspeed_adc_iio_channels,
++ .num_channels = 16,
+ };
+
+ static const struct aspeed_adc_model_data ast2500_model_data = {
+@@ -309,11 +371,24 @@ static const struct aspeed_adc_model_data ast2500_model_data = {
+ .min_sampling_rate = 1,
+ .max_sampling_rate = 1000000,
+ .wait_init_sequence = true,
++ .channels = aspeed_adc_iio_channels,
++ .num_channels = 16,
++};
++
++static const struct aspeed_adc_model_data ast2600_model_data = {
++ .model_name = "ast2500-adc",
++ .vref_voltage = 1800, /* mV --> can be 1.2v or 2.5 or ext 1.55~2.7v, 0.9v ~1.65v */
++ .min_sampling_rate = 1,
++ .max_sampling_rate = 1000000,
++ .wait_init_sequence = true,
++ .channels = ast2600_adc_iio_channels,
++ .num_channels = 8,
+ };
+
+ static const struct of_device_id aspeed_adc_matches[] = {
+ { .compatible = "aspeed,ast2400-adc", .data = &ast2400_model_data },
+ { .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data },
++ { .compatible = "aspeed,ast2600-adc", .data = &ast2600_model_data },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, aspeed_adc_matches);
+@@ -330,5 +405,5 @@ static struct platform_driver aspeed_adc_driver = {
+ module_platform_driver(aspeed_adc_driver);
+
+ MODULE_AUTHOR("Rick Altherr <raltherr@google.com>");
+-MODULE_DESCRIPTION("Aspeed AST2400/2500 ADC Driver");
++MODULE_DESCRIPTION("Aspeed AST2400/2500/2600 ADC Driver");
+ MODULE_LICENSE("GPL");
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ARM-dts-aspeed-g6-add-video-node.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ARM-dts-aspeed-g6-add-video-node.patch
new file mode 100644
index 000000000..221800720
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ARM-dts-aspeed-g6-add-video-node.patch
@@ -0,0 +1,36 @@
+From 90c72bbe5f1ac2c8d62736c44492bd8bbc4fcab0 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 26 Nov 2019 16:37:36 -0800
+Subject: [PATCH] ARM: dts: aspeed-g6: add video node
+
+This commit adds video node.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ arch/arm/boot/dts/aspeed-g6.dtsi | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index 5acc1085526d..b0283e03e9ff 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -359,6 +359,16 @@
+ status = "disabled";
+ };
+
++ video: video@1e700000 {
++ compatible = "aspeed,ast2600-video-engine";
++ reg = <0x1e700000 0x1000>;
++ clocks = <&syscon ASPEED_CLK_GATE_VCLK>,
++ <&syscon ASPEED_CLK_GATE_ECLK>;
++ clock-names = "vclk", "eclk";
++ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++ };
++
+ gpio0: gpio@1e780000 {
+ #gpio-cells = <2>;
+ gpio-controller;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0087-media-aspeed-add-aspeed-ast2600-video-engine-compati.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0087-media-aspeed-add-aspeed-ast2600-video-engine-compati.patch
new file mode 100644
index 000000000..1d8b722de
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0087-media-aspeed-add-aspeed-ast2600-video-engine-compati.patch
@@ -0,0 +1,63 @@
+From 1765cb18bacff9d1f48b833f44da198a09f7d5cb Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 26 Nov 2019 16:39:16 -0800
+Subject: [PATCH] media: aspeed: add aspeed,ast2600-video-engine compatible
+ string
+
+This commit adds "aspeed,ast2600-video-engine" compatible string
+to support AST2600 video engine H/W. Also. it adds G6 specific
+register handling flow.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/media/platform/aspeed-video.c | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
+index db45502774b1..fe70ad408375 100644
+--- a/drivers/media/platform/aspeed-video.c
++++ b/drivers/media/platform/aspeed-video.c
+@@ -72,8 +72,8 @@
+ #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 */
++#if defined(CONFIG_MACH_ASPEED_G5) || defined(CONFIG_MACH_ASPEED_G6)
++#define VE_SEQ_CTRL_JPEG_MODE BIT(13) /* AST2500/2600 */
+ #else
+ #define VE_SEQ_CTRL_JPEG_MODE BIT(8) /* AST2400 */
+ #endif /* CONFIG_MACH_ASPEED_G5 */
+@@ -135,6 +135,12 @@
+
+ #define VE_OFFSET_COMP_STREAM 0x078
+
++#ifdef CONFIG_MACH_ASPEED_G6
++#define VE_JPEG_COMP_SIZE_READ_BACK 0x084 /* AST2600 */
++#else
++#define VE_JPEG_COMP_SIZE_READ_BACK VE_OFFSET_COMP_STREAM
++#endif
++
+ #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)
+@@ -572,7 +578,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
+ if (sts & VE_INTERRUPT_COMP_COMPLETE) {
+ struct aspeed_video_buffer *buf;
+ u32 frame_size = aspeed_video_read(video,
+- VE_OFFSET_COMP_STREAM);
++ VE_JPEG_COMP_SIZE_READ_BACK);
+
+ spin_lock(&video->lock);
+ clear_bit(VIDEO_FRAME_INPRG, &video->flags);
+@@ -1718,6 +1724,7 @@ static int aspeed_video_remove(struct platform_device *pdev)
+ static const struct of_device_id aspeed_video_of_match[] = {
+ { .compatible = "aspeed,ast2400-video-engine" },
+ { .compatible = "aspeed,ast2500-video-engine" },
++ { .compatible = "aspeed,ast2600-video-engine" },
+ {}
+ };
+ MODULE_DEVICE_TABLE(of, aspeed_video_of_match);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0088-clk-ast2600-enable-ESPICLK-always.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0088-clk-ast2600-enable-ESPICLK-always.patch
new file mode 100644
index 000000000..34df0882b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0088-clk-ast2600-enable-ESPICLK-always.patch
@@ -0,0 +1,30 @@
+From 37efef00064a228c3e723b0eece22d72f2632705 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Fri, 6 Dec 2019 13:51:37 -0800
+Subject: [PATCH] clk: ast2600: enable ESPICLK always
+
+To support continous eSPI H/W handshaking, this patch enables
+ESPICLK always so that there discontinuity of eSPI handshaking while
+boot BMC.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/clk/clk-ast2600.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c
+index 8201d65..21967bc 100644
+--- a/drivers/clk/clk-ast2600.c
++++ b/drivers/clk/clk-ast2600.c
+@@ -87,7 +87,7 @@ static const struct aspeed_gate_data aspeed_g6_gates[] = {
+ [ASPEED_CLK_GATE_EMMCCLK] = { 27, 16, "emmcclk-gate", NULL, 0 }, /* For card clk */
+ /* Reserved 28/29/30 */
+ [ASPEED_CLK_GATE_LCLK] = { 32, 32, "lclk-gate", NULL, 0 }, /* LPC */
+- [ASPEED_CLK_GATE_ESPICLK] = { 33, -1, "espiclk-gate", NULL, 0 }, /* eSPI */
++ [ASPEED_CLK_GATE_ESPICLK] = { 33, -1, "espiclk-gate", NULL, CLK_IS_CRITICAL }, /* eSPI */
+ [ASPEED_CLK_GATE_REF1CLK] = { 34, -1, "ref1clk-gate", "clkin", CLK_IS_CRITICAL },
+ /* Reserved 35 */
+ [ASPEED_CLK_GATE_SDCLK] = { 36, 56, "sdclk-gate", NULL, 0 }, /* SDIO/SD */
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0089-ast2600-enable-high-speed-uart-in-kernel.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0089-ast2600-enable-high-speed-uart-in-kernel.patch
new file mode 100644
index 000000000..962d42e6f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0089-ast2600-enable-high-speed-uart-in-kernel.patch
@@ -0,0 +1,97 @@
+From 054391014d04e5b97ae62e1bf5e6aed005f3c67a Mon Sep 17 00:00:00 2001
+From: Kuiying Wang <kuiying.wang@intel.com>
+Date: Fri, 13 Dec 2019 16:15:16 +0800
+Subject: [PATCH] ast2600: enable high speed uart in kernel.
+
+Tested:
+1. Config baud rate to 921600 in BIOS setup page
+2. BMC could change env variable "hostserialcfg" to 1.
+3. BMC is force to reboot and SPA baud rate is changed to 921600 successfully.
+4. It is same for back to 115200.
+
+Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
+---
+ drivers/clk/clk-ast2600.c | 26 +++++++++++++++++++-------
+ include/dt-bindings/clock/ast2600-clock.h | 2 ++
+ 2 files changed, 21 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c
+index c7236e39ef85..af908b2dbeb6 100644
+--- a/drivers/clk/clk-ast2600.c
++++ b/drivers/clk/clk-ast2600.c
+@@ -15,7 +15,7 @@
+
+ #include "clk-aspeed.h"
+
+-#define ASPEED_G6_NUM_CLKS 71
++#define ASPEED_G6_NUM_CLKS ASPEED_CLK_MAX
+
+ #define ASPEED_G6_SILICON_REV 0x004
+
+@@ -43,6 +43,9 @@
+ #define ASPEED_MAC12_CLK_DLY 0x340
+ #define ASPEED_MAC34_CLK_DLY 0x350
+
++#define ASPEED_G6_GEN_UART_REF 0x338
++#define UART_192MHZ_R_N_VALUE 0x3c38e
++
+ /* Globally visible clocks */
+ static DEFINE_SPINLOCK(aspeed_g6_clk_lock);
+
+@@ -76,7 +79,7 @@ static const struct aspeed_gate_data aspeed_g6_gates[] = {
+ /* Reserved 11/12 */
+ [ASPEED_CLK_GATE_YCLK] = { 13, 4, "yclk-gate", NULL, 0 }, /* HAC */
+ [ASPEED_CLK_GATE_USBPORT1CLK] = { 14, 14, "usb-port1-gate", NULL, 0 }, /* USB2 hub/USB2 host port 1/USB1.1 dev */
+- [ASPEED_CLK_GATE_UART5CLK] = { 15, -1, "uart5clk-gate", "uart", 0 }, /* UART5 */
++ [ASPEED_CLK_GATE_UART5CLK] = { 15, -1, "uart5clk-gate", "uart5", 0 }, /* UART5 */
+ /* Reserved 16/19 */
+ [ASPEED_CLK_GATE_MAC1CLK] = { 20, 11, "mac1clk-gate", "mac12", 0 }, /* MAC1 */
+ [ASPEED_CLK_GATE_MAC2CLK] = { 21, 12, "mac2clk-gate", "mac12", 0 }, /* MAC2 */
+@@ -437,17 +440,26 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev)
+ return ret;
+ }
+
+- /* UART clock div13 setting */
+- regmap_read(map, ASPEED_G6_MISC_CTRL, &val);
+- if (val & UART_DIV13_EN)
+- rate = 24000000 / 13;
++ /* UART clock setting */
++ regmap_read(map, ASPEED_G6_GEN_UART_REF, &val);
++ if (val == UART_192MHZ_R_N_VALUE){
++ rate = 192000000 / 13;
++ dev_err(dev, "192Mhz baud rate 921600\n");
++ }
+ else
+- rate = 24000000;
++ rate = 24000000 / 13;
+ hw = clk_hw_register_fixed_rate(dev, "uart", NULL, 0, rate);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_g6_clk_data->hws[ASPEED_CLK_UART] = hw;
+
++ /* UART5 clock setting */
++ rate = 24000000 / 13;
++ hw = clk_hw_register_fixed_rate(dev, "uart5", NULL, 0, rate);
++ if (IS_ERR(hw))
++ return PTR_ERR(hw);
++ aspeed_g6_clk_data->hws[ASPEED_CLK_UART5] = hw;
++
+ /* UART6~13 clock div13 setting */
+ regmap_read(map, 0x80, &val);
+ if (val & BIT(31))
+diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h
+index 3d90582a813f..4952f7683be7 100644
+--- a/include/dt-bindings/clock/ast2600-clock.h
++++ b/include/dt-bindings/clock/ast2600-clock.h
+@@ -87,6 +87,8 @@
+ #define ASPEED_CLK_MAC2RCLK 68
+ #define ASPEED_CLK_MAC3RCLK 69
+ #define ASPEED_CLK_MAC4RCLK 70
++#define ASPEED_CLK_UART5 71
++#define ASPEED_CLK_MAX 72
+
+ /* Only list resets here that are not part of a gate */
+ #define ASPEED_RESET_ADC 55
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0090-peci-cpupower-driver-1.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0090-peci-cpupower-driver-1.patch
new file mode 100644
index 000000000..475e9611f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0090-peci-cpupower-driver-1.patch
@@ -0,0 +1,405 @@
+From e40f7d10d5306c075e2fc7e538ce1efc70eeb448 Mon Sep 17 00:00:00 2001
+From: ZhikuiRen <zhikui.ren@intel.com>
+Date: Thu, 9 Jan 2020 10:48:00 -0800
+Subject: [PATCH] Add peci-cpupower driver
+
+peci-cpupower reads CPU energy counter through peci
+and computes average power in mW since last read.
+
+Signed-off-by: ZhikuiRen <zhikui.ren@intel.com>
+---
+ Documentation/hwmon/index.rst | 1 +
+ Documentation/hwmon/peci-cpupower.rst | 52 ++++++++
+ arch/arm/configs/aspeed_g5_defconfig | 1 +
+ drivers/hwmon/Kconfig | 14 +++
+ drivers/hwmon/Makefile | 1 +
+ drivers/hwmon/peci-cpupower.c | 231 ++++++++++++++++++++++++++++++++++
+ drivers/mfd/intel-peci-client.c | 1 +
+ include/uapi/linux/peci-ioctl.h | 1 +
+ 8 files changed, 302 insertions(+)
+ create mode 100644 Documentation/hwmon/peci-cpupower.rst
+ create mode 100644 drivers/hwmon/peci-cpupower.c
+
+diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
+index 7d894c9..0bde0ef 100644
+--- a/Documentation/hwmon/index.rst
++++ b/Documentation/hwmon/index.rst
+@@ -130,6 +130,7 @@ Hardware Monitoring Kernel Drivers
+ pcf8591
+ peci-cputemp
+ peci-dimmtemp
++ peci-cpupower
+ pmbus
+ powr1220
+ pxe1610
+diff --git a/Documentation/hwmon/peci-cpupower.rst b/Documentation/hwmon/peci-cpupower.rst
+new file mode 100644
+index 0000000..4d7bd61
+--- /dev/null
++++ b/Documentation/hwmon/peci-cpupower.rst
+@@ -0,0 +1,52 @@
++.. SPDX-License-Identifier: GPL-2.0
++
++Kernel driver peci-cpupower
++==========================
++
++:Copyright: |copy| 2018-2020 Intel Corporation
++
++Supported chips:
++ One of Intel server CPUs listed below which is connected to a PECI bus.
++ * Intel Xeon E5/E7 v3 server processors
++ Intel Xeon E5-14xx v3 family
++ Intel Xeon E5-24xx v3 family
++ Intel Xeon E5-16xx v3 family
++ Intel Xeon E5-26xx v3 family
++ Intel Xeon E5-46xx v3 family
++ Intel Xeon E7-48xx v3 family
++ Intel Xeon E7-88xx v3 family
++ * Intel Xeon E5/E7 v4 server processors
++ Intel Xeon E5-16xx v4 family
++ Intel Xeon E5-26xx v4 family
++ Intel Xeon E5-46xx v4 family
++ Intel Xeon E7-48xx v4 family
++ Intel Xeon E7-88xx v4 family
++ * Intel Xeon Scalable server processors
++ Intel Xeon D family
++ Intel Xeon Bronze family
++ Intel Xeon Silver family
++ Intel Xeon Gold family
++ Intel Xeon Platinum family
++
++ Addresses scanned: PECI client address 0x30 - 0x37
++ Datasheet: Available from http://www.intel.com/design/literature.htm
++
++Author:
++ Zhikui Ren <zhikui.ren@.intel.com>
++
++Description
++-----------
++
++This driver implements a generic PECI hwmon feature which provides
++average power consumption readings of the CPU package based on energy counter
++accessible using the PECI Client Command Suite via the processor PECI client.
++
++Power values are average power since last measure given in milli Watt and
++will be measurable only when the target CPU is powered on.
++
++``sysfs`` interface
++-------------------
++======================= =======================================================
++power1_average Provides average power since last read in milli Watt.
++power1_label Provides string "Average Power".
++======================= =======================================================
+diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig
+index 1e589a0..0e50040 100644
+--- a/arch/arm/configs/aspeed_g5_defconfig
++++ b/arch/arm/configs/aspeed_g5_defconfig
+@@ -177,6 +177,7 @@ CONFIG_SENSORS_OCC_P8_I2C=y
+ CONFIG_SENSORS_OCC_P9_SBE=y
+ CONFIG_SENSORS_PECI_CPUTEMP=y
+ CONFIG_SENSORS_PECI_DIMMTEMP=y
++CONFIG_SENSORS_PECI_CPUPOWER=y
+ CONFIG_PMBUS=y
+ CONFIG_SENSORS_ADM1275=y
+ CONFIG_SENSORS_IBM_CFFPS=y
+diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
+index 8312b37..07d8826 100644
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -1361,6 +1361,20 @@ config SENSORS_PECI_DIMMTEMP
+ This driver can also be built as a module. If so, the module
+ will be called peci-dimmtemp.
+
++config SENSORS_PECI_CPUPOWER
++ tristate "PECI CPU power monitoring support"
++ depends on PECI
++ select MFD_INTEL_PECI_CLIENT
++ help
++ If you say yes here you get support for the generic Intel PECI
++ cputemp driver which provides average engergy
++ readings of the CPU package using
++ the PECI Client Command Suite via the processor PECI client.
++ Check Documentation/hwmon/peci-cpupower for details.
++
++ This driver can also be built as a module. If so, the module
++ will be called peci-cpupower.
++
+ source "drivers/hwmon/pmbus/Kconfig"
+
+ config SENSORS_PWM_FAN
+diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
+index e74ea92..fab43fd 100644
+--- a/drivers/hwmon/Makefile
++++ b/drivers/hwmon/Makefile
+@@ -144,6 +144,7 @@ obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
+ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
+ obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o
+ obj-$(CONFIG_SENSORS_PECI_DIMMTEMP) += peci-dimmtemp.o
++obj-$(CONFIG_SENSORS_PECI_CPUPOWER) += peci-cpupower.o
+ obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
+ obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
+ obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
+diff --git a/drivers/hwmon/peci-cpupower.c b/drivers/hwmon/peci-cpupower.c
+new file mode 100644
+index 0000000..6907696
+--- /dev/null
++++ b/drivers/hwmon/peci-cpupower.c
+@@ -0,0 +1,231 @@
++// SPDX-License-Identifier: GPL-2.0
++// Copyright (c) 2018-2020 Intel Corporation
++
++#include <linux/hwmon.h>
++#include <linux/jiffies.h>
++#include <linux/mfd/intel-peci-client.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include "peci-hwmon.h"
++
++#define POWER_DEFAULT_CHANNEL_NUMS 1
++
++struct peci_cpupower {
++ struct peci_client_manager *mgr;
++ struct device *dev;
++ char name[PECI_NAME_SIZE];
++ const struct cpu_gen_info *gen_info;
++ struct peci_sensor_data energy;
++ long avg_power_val;
++ u64 core_mask;
++ u32 power_config[POWER_DEFAULT_CHANNEL_NUMS + 1];
++ uint config_idx;
++ struct hwmon_channel_info power_info;
++ const struct hwmon_channel_info *info[2];
++ struct hwmon_chip_info chip;
++};
++
++enum cpupower_channels {
++ average_power,
++};
++
++static const u32 config_table[POWER_DEFAULT_CHANNEL_NUMS] = {
++ /* average power */
++ HWMON_P_LABEL | HWMON_P_AVERAGE,
++};
++
++static const char *cpupower_label[POWER_DEFAULT_CHANNEL_NUMS] = {
++ "Average Power",
++};
++
++static int get_average_power(struct peci_cpupower *priv)
++{
++ u8 pkg_cfg[4];
++ int ret;
++
++ if (!peci_sensor_need_update(&priv->energy))
++ return 0;
++
++ ret = peci_client_read_package_config(priv->mgr,
++ PECI_MBX_INDEX_TDP_UNITS,
++ PECI_PKG_ID_PKG_ENERGY_STATUS,
++ pkg_cfg);
++
++ u32 power_unit = ((le32_to_cpup((__le32 *)pkg_cfg)) & 0x1f00) >> 8;
++
++ dev_dbg(priv->dev, "cpupower units %d (1J/pow(2, unit))\n",
++ power_unit);
++
++ ret = peci_client_read_package_config(priv->mgr,
++ PECI_MBX_INDEX_ENERGY_COUNTER,
++ PECI_PKG_ID_PKG_ENERGY_STATUS,
++ pkg_cfg);
++ if (!ret) {
++ u32 energy_cnt = le32_to_cpup((__le32 *)pkg_cfg);
++ ulong jif = jiffies;
++ ulong elapsed = (jif - priv->energy.last_updated);
++ long power_val = 0;
++ /*
++ * Don't calculate average power for first counter read or
++ * counter wrapped around or last counter read was more than
++ * 60 minutes ago (jiffies did not wrap and power calculation
++ * does not overflow or underflow
++ */
++ if (priv->energy.last_updated > 0 &&
++ energy_cnt > priv->energy.value &&
++ (elapsed < (HZ * 3600))) {
++ power_val = (long)(energy_cnt - priv->energy.value)
++ / elapsed * HZ;
++ dev_dbg(priv->dev, "countDiff %d, jiffes elapsed %d, raw powerValue %d scale to %d mW\n",
++ (long)(energy_cnt - priv->energy.value),
++ elapsed, power_val,
++ power_val >> (power_unit - 10));
++ } else {
++ dev_dbg(priv->dev, "countDiff %d, jiffes elapsed %d, skipping calculate power, try agin\n",
++ (long)(energy_cnt - priv->energy.value),
++ elapsed);
++ ret = -EAGAIN;
++ }
++
++ priv->energy.value = energy_cnt;
++ priv->avg_power_val = power_val >> ((power_unit - 10));
++ peci_sensor_mark_updated(&priv->energy);
++
++ dev_dbg(priv->dev, "energy counter 0x%8x, average power %dmW, jif %u, HZ is %d jiffies\n",
++ priv->energy.value, priv->avg_power_val,
++ jif, HZ);
++ }
++ return ret;
++}
++
++static int cpupower_read_string(struct device *dev,
++ enum hwmon_sensor_types type,
++ u32 attr, int channel, const char **str)
++{
++ if (attr != hwmon_power_label)
++ return -EOPNOTSUPP;
++ if (channel >= POWER_DEFAULT_CHANNEL_NUMS)
++ return -EOPNOTSUPP;
++ *str = cpupower_label[channel];
++
++ return 0;
++}
++
++static int cpupower_read(struct device *dev,
++ enum hwmon_sensor_types type,
++ u32 attr, int channel, long *val)
++{
++ struct peci_cpupower *priv = dev_get_drvdata(dev);
++ int ret;
++
++ if (channel >= POWER_DEFAULT_CHANNEL_NUMS ||
++ !(priv->power_config[channel] & BIT(attr)))
++ return -EOPNOTSUPP;
++
++ switch (attr) {
++ case hwmon_power_average:
++ switch (channel) {
++ case average_power:
++ ret = get_average_power(priv);
++ if (ret)
++ break;
++
++ *val = priv->avg_power_val;
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ ret = -EOPNOTSUPP;
++ break;
++ }
++
++ return ret;
++}
++
++static umode_t cpupower_is_visible(const void *data,
++ enum hwmon_sensor_types type,
++ u32 attr, int channel)
++{
++ const struct peci_cpupower *priv = data;
++
++ if (channel < POWER_DEFAULT_CHANNEL_NUMS ||
++ (priv->power_config[channel] & BIT(attr)))
++ return 0444;
++
++ return 0;
++}
++
++static const struct hwmon_ops cpupower_ops = {
++ .is_visible = cpupower_is_visible,
++ .read_string = cpupower_read_string,
++ .read = cpupower_read,
++};
++
++static int peci_cpupower_probe(struct platform_device *pdev)
++{
++ struct peci_client_manager *mgr = dev_get_drvdata(pdev->dev.parent);
++ struct device *dev = &pdev->dev;
++ struct peci_cpupower *priv;
++ struct device *hwmon_dev;
++
++ if ((mgr->client->adapter->cmd_mask &
++ (BIT(PECI_CMD_RD_PKG_CFG))) !=
++ (BIT(PECI_CMD_RD_PKG_CFG))) {
++ return -ENODEV;
++ }
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ dev_set_drvdata(dev, priv);
++ priv->mgr = mgr;
++ priv->dev = dev;
++ priv->gen_info = mgr->gen_info;
++
++ snprintf(priv->name, PECI_NAME_SIZE, "peci_cpupower.cpu%d",
++ mgr->client->addr - PECI_BASE_ADDR);
++
++ priv->power_config[priv->config_idx++] = config_table[average_power];
++
++ priv->chip.ops = &cpupower_ops;
++ priv->chip.info = priv->info;
++
++ priv->info[0] = &priv->power_info;
++
++ priv->power_info.type = hwmon_power;
++ priv->power_info.config = priv->power_config;
++
++ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev,
++ priv->name,
++ priv,
++ &priv->chip,
++ NULL);
++
++ if (IS_ERR(hwmon_dev))
++ return PTR_ERR(hwmon_dev);
++
++ dev_dbg(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), priv->name);
++
++ return 0;
++}
++
++static const struct platform_device_id peci_cpupower_ids[] = {
++ { .name = "peci-cpupower", .driver_data = 0 },
++ { }
++};
++MODULE_DEVICE_TABLE(platform, peci_cpupower_ids);
++
++static struct platform_driver peci_cpupower_driver = {
++ .probe = peci_cpupower_probe,
++ .id_table = peci_cpupower_ids,
++ .driver = { .name = KBUILD_MODNAME, },
++};
++module_platform_driver(peci_cpupower_driver);
++
++MODULE_AUTHOR("Zhikui Ren <zhikui.ren@intel.com>");
++MODULE_DESCRIPTION("PECI cpupower driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c
+index 9751b04..0c62ad6 100644
+--- a/drivers/mfd/intel-peci-client.c
++++ b/drivers/mfd/intel-peci-client.c
+@@ -21,6 +21,7 @@
+ static struct mfd_cell peci_functions[] = {
+ { .name = "peci-cputemp", },
+ { .name = "peci-dimmtemp", },
++ { .name = "peci-cpupower", },
+ };
+
+ static const struct cpu_gen_info cpu_gen_info_table[] = {
+diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h
+index 843930f..d16f7c9 100644
+--- a/include/uapi/linux/peci-ioctl.h
++++ b/include/uapi/linux/peci-ioctl.h
+@@ -231,6 +231,7 @@ struct peci_rd_pkg_cfg_msg {
+ #define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */
+ #define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */
+ #define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */
++#define PECI_PKG_ID_PKG_ENERGY_STATUS 0x00ff /* Average Energy */
+
+ __u8 rx_len;
+ __u8 cc;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0092-SPI-Quad-IO-driver-support-AST2600.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0092-SPI-Quad-IO-driver-support-AST2600.patch
new file mode 100644
index 000000000..2717d367f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0092-SPI-Quad-IO-driver-support-AST2600.patch
@@ -0,0 +1,136 @@
+From 9f1eea1fb639a0554195e29c488cefb36a04910e Mon Sep 17 00:00:00 2001
+From: arun-pm <arun.p.m@linux.intel.com>
+Date: Tue, 3 Dec 2019 17:22:28 +0530
+Subject: [PATCH] SPI Quad IO driver support AST2600
+
+This commit adds spi driver quad io support for AST2600
+
+Note:- Removed n25q00 Quad I/O support for the time being due to clock issue
+ with chip 'Micron 8UA15 - rw182 (128MB)' while enabling Quad I/O mode.
+
+Signed-off-by: arun-pm <arun.p.m@linux.intel.com>
+---
+ drivers/mtd/spi-nor/aspeed-smc.c | 49 ++++++++++++++++++++++++++++++++++------
+ drivers/mtd/spi-nor/spi-nor.c | 7 +++++-
+ 2 files changed, 48 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c
+index 0805dcab8cb1..305c1940e822 100644
+--- a/drivers/mtd/spi-nor/aspeed-smc.c
++++ b/drivers/mtd/spi-nor/aspeed-smc.c
+@@ -21,6 +21,11 @@
+ #include <linux/sysfs.h>
+
+ #define DEVICE_NAME "aspeed-smc"
++#define AST2600A0 0x05000303
++#define AST2600A0_MAX_FREQ 50000000
++#define AST2600A0_SAFE_FREQ 40000000
++#define AST_MAX_FREQ 100000000
++#define AST2600_REVISION_ID_SCU 0x1e6e2004
+
+ /*
+ * The driver only support SPI flash
+@@ -542,6 +547,10 @@ static int aspeed_smc_get_io_mode(struct aspeed_smc_chip *chip)
+ return CONTROL_IO_DUAL_DATA;
+ case SNOR_PROTO_1_2_2:
+ return CONTROL_IO_DUAL_ADDR_DATA;
++ case SNOR_PROTO_1_1_4:
++ return CONTROL_IO_QUAD_DATA;
++ case SNOR_PROTO_1_4_4:
++ return CONTROL_IO_QUAD_ADDR_DATA;
+ default:
+ dev_err(chip->nor.dev, "unsupported SPI read mode\n");
+ return -EINVAL;
+@@ -573,7 +582,7 @@ static ssize_t aspeed_smc_read_user(struct spi_nor *nor, loff_t from,
+ aspeed_smc_write_to_ahb(chip->ahb_base, &dummy, sizeof(dummy));
+
+ /* Set IO mode only for data */
+- if (io_mode == CONTROL_IO_DUAL_DATA)
++ if (io_mode == CONTROL_IO_DUAL_DATA || io_mode == CONTROL_IO_QUAD_DATA)
+ aspeed_smc_set_io_mode(chip, io_mode);
+
+ aspeed_smc_read_from_ahb(read_buf, chip->ahb_base, len);
+@@ -1222,20 +1231,35 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
+ return 0;
+ }
+
++static void aspeed_allowed_max_freq(struct aspeed_smc_chip *chip)
++{
++ void __iomem *scu_ast_revision_id = ioremap(AST2600_REVISION_ID_SCU, 4);
++ u32 rev_id = readl(scu_ast_revision_id);
++
++ /*Limit max spi frequency less than 50MHz on AST2600-A0 due
++ * to FWSPICLK signal quality issue.
++ */
++ if(rev_id == AST2600A0 && chip->clk_rate >= AST2600A0_MAX_FREQ)
++ chip->clk_rate = AST2600A0_SAFE_FREQ;
++}
++
++static u32 get_hwcaps(unsigned int tx_width){
++ if(tx_width == 4)
++ return SNOR_HWCAPS_READ_1_1_4;
++ else
++ return SNOR_HWCAPS_READ_1_1_2;
++}
++
+ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
+ struct device_node *np, struct resource *r)
+ {
+- const struct spi_nor_hwcaps hwcaps = {
+- .mask = SNOR_HWCAPS_READ |
+- SNOR_HWCAPS_READ_FAST |
+- SNOR_HWCAPS_READ_1_1_2 |
+- SNOR_HWCAPS_PP,
+- };
++ struct spi_nor_hwcaps hwcaps;
+ const struct aspeed_smc_info *info = controller->info;
+ struct device *dev = controller->dev;
+ struct device_node *child;
+ unsigned int cs;
+ int ret = -ENODEV;
++ unsigned int spi_tx_width;
+
+ for_each_available_child_of_node(np, child) {
+ struct aspeed_smc_chip *chip;
+@@ -1276,9 +1300,20 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
+ &chip->clk_rate)) {
+ chip->clk_rate = ASPEED_SPI_DEFAULT_FREQ;
+ }
++ aspeed_allowed_max_freq(chip);
+ dev_info(dev, "Using %d MHz SPI frequency\n",
+ chip->clk_rate / 1000000);
+
++ if (of_property_read_u32(child, "spi-tx-bus-width",
++ &spi_tx_width)) {
++ spi_tx_width = 2;
++ }
++ dev_info(dev, "tx width: %ld\n", spi_tx_width);
++
++ hwcaps.mask = SNOR_HWCAPS_READ |
++ SNOR_HWCAPS_READ_FAST |
++ get_hwcaps(spi_tx_width) |
++ SNOR_HWCAPS_PP;
+ chip->controller = controller;
+ chip->ctl = controller->regs + info->ctl0 + cs * 4;
+ chip->cs = cs;
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index 3668a862d37d..50904876cb09 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -2315,7 +2315,12 @@ static const struct flash_info spi_nor_ids[] = {
+ SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+ { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K |
+ SPI_NOR_QUAD_READ) },
+- { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
++ /* Removed n25q00 Quad I/O support for the time being due to clock issue with chip 'Micron 8UA15 - rw182 (128MB)'
++ * while enabling Quad I/O mode. As this chip is default shipped in platforms, marking it
++ * as Not supported for the time being. Once all chips are replaced with the new model, this can be enabled
++ * back(Note:- Certain other chips having same name(n25q00) but different part number has no issues).
++ */
++ { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | NO_CHIP_ERASE) },
+ { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
+ { "mt25ql02g", INFO(0x20ba22, 0, 64 * 1024, 4096,
+ SECT_4K | USE_FSR | SPI_NOR_QUAD_READ |
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0093-ipmi-ipmb_dev_int-add-quick-fix-for-raw-I2C-type-reg.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0093-ipmi-ipmb_dev_int-add-quick-fix-for-raw-I2C-type-reg.patch
new file mode 100644
index 000000000..4b3b6b838
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0093-ipmi-ipmb_dev_int-add-quick-fix-for-raw-I2C-type-reg.patch
@@ -0,0 +1,37 @@
+From 8be7c34e78bd09fa95ce9972332c8c2bb950ec03 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 28 Jan 2020 16:14:07 -0800
+Subject: [PATCH] ipmi: ipmb_dev_int: add quick fix for raw I2C type
+ registration
+
+This commit adds quick fix for cases of run time registration
+through sysfs. It should be fixed later by adding parsing code for
+ipmb_id instead.
+
+This is a temporary fix. Do not upstream it.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/char/ipmi/ipmb_dev_int.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/char/ipmi/ipmb_dev_int.c b/drivers/char/ipmi/ipmb_dev_int.c
+index 382e4a1df510..c5db37266724 100644
+--- a/drivers/char/ipmi/ipmb_dev_int.c
++++ b/drivers/char/ipmi/ipmb_dev_int.c
+@@ -328,8 +328,12 @@ static int ipmb_probe(struct i2c_client *client,
+ if (ret)
+ return ret;
+
++#if 1 /* FIXME: Quick fix. Need to add parsing code for ipmb_id instead */
++ ipmb_dev->is_i2c_protocol = true;
++#else
+ ipmb_dev->is_i2c_protocol
+ = device_property_read_bool(&client->dev, "i2c-protocol");
++#endif
+
+ ipmb_dev->client = client;
+ i2c_set_clientdata(client, ipmb_dev);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0094-Return-link-speed-and-duplex-settings-for-the-NCSI-c.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0094-Return-link-speed-and-duplex-settings-for-the-NCSI-c.patch
new file mode 100644
index 000000000..3e426edcd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0094-Return-link-speed-and-duplex-settings-for-the-NCSI-c.patch
@@ -0,0 +1,57 @@
+From f280c15c79e7d13e4a59d413a3091eb21b56dd92 Mon Sep 17 00:00:00 2001
+From: Johnathan Mantey <johnathanx.mantey@intel.com>
+Date: Mon, 27 Jan 2020 09:03:56 -0800
+Subject: [PATCH] Return link speed and duplex settings for the NCSI channel
+
+The ftgmac100_open function initializes state for the NCSI
+channel. The get link settings function does not return this
+data. This caused the link speed, and the duplex value to be returned
+incorrectly by the PHY driver (0 Mbps, and duplex off).
+
+Update the driver to return either the PHY settings when not using
+NCSI, or the NCSI values that were assigned when the driver is opened.
+
+Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
+---
+ drivers/net/ethernet/faraday/ftgmac100.c | 22 +++++++++++++++++++++-
+ 1 file changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
+index 8ed85037f021..a53878eecfc8 100644
+--- a/drivers/net/ethernet/faraday/ftgmac100.c
++++ b/drivers/net/ethernet/faraday/ftgmac100.c
+@@ -1218,10 +1218,30 @@ static int ftgmac100_set_pauseparam(struct net_device *netdev,
+ return 0;
+ }
+
++int ftgmac100_ethtool_get_link_ksettings(struct net_device *netdev,
++ struct ethtool_link_ksettings *cmd)
++{
++ struct phy_device *phydev = netdev->phydev;
++ struct ftgmac100 *priv = netdev_priv(netdev);
++ int retval = 0;
++
++ if (phydev) {
++ phy_ethtool_ksettings_get(phydev, cmd);
++ } else if (priv->use_ncsi) {
++ cmd->base.speed = priv->cur_speed;
++ cmd->base.duplex = priv->cur_duplex;
++ cmd->base.autoneg = 0;
++ } else {
++ retval = -ENODEV;
++ }
++
++ return retval;
++}
++
+ static const struct ethtool_ops ftgmac100_ethtool_ops = {
+ .get_drvinfo = ftgmac100_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+- .get_link_ksettings = phy_ethtool_get_link_ksettings,
++ .get_link_ksettings = ftgmac100_ethtool_get_link_ksettings,
+ .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .nway_reset = phy_ethtool_nway_reset,
+ .get_ringparam = ftgmac100_get_ringparam,
+--
+2.24.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0095-pwm-and-tach-driver-changes-for-ast2600.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0095-pwm-and-tach-driver-changes-for-ast2600.patch
new file mode 100644
index 000000000..377ec2b36
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0095-pwm-and-tach-driver-changes-for-ast2600.patch
@@ -0,0 +1,783 @@
+From 0301f9b2bc948069aaad2899e15e6c94a07ca818 Mon Sep 17 00:00:00 2001
+From: Ayushi Smriti <smriti.ayushi@intel.com>
+Date: Mon, 2 Mar 2020 22:51:46 +0530
+Subject: [PATCH] pwm and tach driver changes for ast2600
+
+This commit includes additions/changes in driver code
+to support 9 PWM outputs and 9 fan tachometer inputs for
+ast2600
+
+Signed-off-by: Ayushi Smriti <smriti.ayushi@intel.com>
+---
+ drivers/hwmon/aspeed-g6-pwm-tacho.c | 328 +++++++++++++++-------------
+ 1 file changed, 171 insertions(+), 157 deletions(-)
+
+diff --git a/drivers/hwmon/aspeed-g6-pwm-tacho.c b/drivers/hwmon/aspeed-g6-pwm-tacho.c
+index 1894f6ad5edb..1ff788bf1133 100644
+--- a/drivers/hwmon/aspeed-g6-pwm-tacho.c
++++ b/drivers/hwmon/aspeed-g6-pwm-tacho.c
+@@ -64,6 +64,8 @@
+ #define PWM_RISING_FALLING_BIT (8) //pwm falling point bit [7:0]
+ #define PWM_RISING_RISING_BIT (0) //pwm rising point bit [7:0]
+
++#define DEF_PWM_PERIOD 0xff
++
+ #define ASPEED_TACHO_CTRL 0x08 //TACH0 General Register
+ #define ASPEED_TACHO_CTRL_CH(x) ((x * 0x10) + 0x08)
+ #define TACHO_IER BIT(31) //enable tacho interrupt
+@@ -72,8 +74,7 @@
+ #define TACHO_ENABLE BIT(28) //{enable tacho}
+ #define TACHO_DEBOUNCE_BIT (26) //{tacho de-bounce}
+ #define TACHO_DEBOUNCE_MASK (0x3 << 26) //{tacho de-bounce}
+-#define TECHIO_EDGE_MASK (0x3 << 24) //tacho edge}
+-#define TECHIO_EDGE_BIT (24) //tacho edge}
++#define TACHIO_EDGE_BIT (24) /*tacho edge}*/
+ #define TACHO_CLK_DIV_T_MASK (0xf << 20)
+ #define TACHO_CLK_DIV_BIT (20)
+ #define TACHO_THRESHOLD_MASK (0xfffff) //tacho threshold bit
+@@ -102,211 +103,183 @@
+
+ #define MAX_CDEV_NAME_LEN 16
+
++#define DEFAULT_TARGET_PWM_FREQ 25000
++#define DEFAULT_MIN_RPM 2900
++
++#define PWM_FALLING_VALUE 0xff
++
+ struct aspeed_pwm_channel_params {
++ int target_freq;
++ int pwm_freq;
+ int load_wdt_rising_falling_pt;
+ int load_wdt_selection; //0: rising , 1: falling
+ int load_wdt_enable;
+ int duty_sync_enable;
+ int invert_pin;
+- u8 divide_h;
+- u8 divide_l;
+- u8 period;
+ u8 rising;
+ u8 falling;
+ };
+
+ static struct aspeed_pwm_channel_params default_pwm_params[] = {
+ [0] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 1,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [1] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [2] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [3] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [4] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [5] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [6] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [7] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [8] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [9] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [10] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [11] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [12] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [13] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [14] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ [15] = {
++ .target_freq = 25000,
+ .load_wdt_rising_falling_pt = 0x10,
+ .load_wdt_selection = 0,
+ .load_wdt_enable = 0,
+ .duty_sync_enable = 0,
+ .invert_pin = 0,
+- .divide_h = 0x5,
+- .divide_l = 0x6,
+- .period = 0x13, //5% ~~
+ .rising = 0x00,
+- .falling = 0x0a,
++ .falling = PWM_FALLING_VALUE,
+ },
+ };
+
+@@ -318,125 +291,146 @@ static struct aspeed_pwm_channel_params default_pwm_params[] = {
+ * 11: reserved.
+ */
+
++#define F2F_EDGES 0x00
++#define R2R_EDGES 0x01
++#define BOTH_EDGES 0x02
++
+ struct aspeed_tacho_channel_params {
++ u32 min_rpm;
+ int limited_inverse;
+ u16 threshold;
+ u8 tacho_edge;
+ u8 tacho_debounce;
+- u8 divide;
++ u32 divide;
+ };
+
+
+ static struct aspeed_tacho_channel_params default_tacho_params[] = {
+ [0] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [1] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [2] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [3] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [4] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [5] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [6] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [7] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [8] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [9] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [10] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [11] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [12] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [13] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [14] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+ [15] = {
++ .min_rpm = 2900,
+ .limited_inverse = 0,
+ .threshold = 0,
+- .tacho_edge = 0,
++ .tacho_edge = F2F_EDGES,
+ .tacho_debounce = 0,
+ .divide = 8,
+ },
+@@ -501,29 +495,28 @@ static void aspeed_set_pwm_channel_enable(struct regmap *regmap, u8 pwm_channel,
+ static void aspeed_set_fan_tach_ch_enable(struct aspeed_pwm_tachometer_data *priv, u8 fan_tach_ch,
+ bool enable)
+ {
+- u32 i = 0, j;
++ u32 i;
+ u32 divide_val = 0;
++ u32 target_div;
+ u32 reg_value = 0;
+
+ if(enable) {
+- //4 ^ n
+- //check pwm clk and to change tacho devide 25KZ
+- for(i = 0; i < 12; i++) {
++ /*RPM calculation as per ast2600 datasheet*/
++ target_div = (priv->clk_freq * 60 / priv->tacho_channel[fan_tach_ch].min_rpm * 2) / (0xfffff + 1);
++ if (target_div) {
++ for (i = 0; i < 12; i++) {
++ divide_val = BIT(i) * BIT(i);
++ if (divide_val > target_div)
++ break;
++ }
++ } else {
+ divide_val = 1;
+- for (j = 1; j <= i; j++)
+- divide_val *= 4;
+-// printk("i : %d , priv->clk_freq/divide_val %d ",i, priv->clk_freq/divide_val);
+- if((priv->clk_freq/divide_val) < 250000)
+- break;
+ }
+- i--;
+- divide_val = ((1 << i) * (1 << i));
+-// printk("tacho divide_val %d , i %x max tacho clk %d \n", divide_val, i, priv->clk_freq / divide_val);
+- priv->tacho_channel[fan_tach_ch].divide = i;
++ priv->tacho_channel[fan_tach_ch].divide = divide_val;
+
+ reg_value = TACHO_ENABLE |
+- (priv->tacho_channel[fan_tach_ch].tacho_edge << TECHIO_EDGE_BIT) |
+- (priv->tacho_channel[fan_tach_ch].divide << TACHO_CLK_DIV_BIT) |
++ (priv->tacho_channel[fan_tach_ch].tacho_edge << TACHIO_EDGE_BIT) |
++ (i << TACHO_CLK_DIV_BIT) |
+ (priv->tacho_channel[fan_tach_ch].tacho_debounce << TACHO_DEBOUNCE_BIT);
+
+ if(priv->tacho_channel[fan_tach_ch].limited_inverse)
+@@ -541,14 +534,28 @@ static void aspeed_set_pwm_channel_fan_ctrl(struct aspeed_pwm_tachometer_data *p
+ u8 index, u8 fan_ctrl)
+ {
+ u32 duty_value, ctrl_value;
++ u32 div_h, div_l, cal_freq;
+
+ if (fan_ctrl == 0) {
+ aspeed_set_pwm_channel_enable(priv->regmap, index, false);
+ } else {
+- duty_value = (priv->pwm_channel[index].period << PWM_PERIOD_BIT) |
+- (0 << PWM_RISING_RISING_BIT) | (fan_ctrl << PWM_RISING_FALLING_BIT);
++ cal_freq = priv->clk_freq / (DEF_PWM_PERIOD + 1);
++ /*calculate for target frequence*/
++ for (div_l = 0; div_l < 0x100; div_l++) {
++ for (div_h = 0; div_h < 0x10; div_h++) {
++ if ((cal_freq / (BIT(div_h) * (div_l + 1))) < priv->pwm_channel[index].target_freq)
++ break;
++ }
++ if ((cal_freq / (BIT(div_h) * (div_l + 1))) < priv->pwm_channel[index].target_freq)
++ break;
++ }
++
++ priv->pwm_channel[index].pwm_freq = cal_freq / (BIT(div_h) * (div_l + 1));
+
+- ctrl_value = (priv->pwm_channel[index].divide_h << 8) | priv->pwm_channel[index].divide_l;
++ ctrl_value = (div_h << 8) | div_l;
++
++ duty_value = (DEF_PWM_PERIOD << PWM_PERIOD_BIT) |
++ (0 << PWM_RISING_RISING_BIT) | (fan_ctrl << PWM_RISING_FALLING_BIT);
+
+ if (priv->pwm_channel[index].load_wdt_enable) {
+ ctrl_value |= PWM_DUTY_LOAD_AS_WDT_EN;
+@@ -568,13 +575,11 @@ static void aspeed_set_pwm_channel_fan_ctrl(struct aspeed_pwm_tachometer_data *p
+ }
+ }
+
+-#define BOTH_EDGES 0x02 /* 10b */
+-
+ static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tachometer_data *priv,
+ u8 fan_tach_ch)
+ {
+ u32 raw_data, tach_div, clk_source, val;
+- u8 mode, both;
++ u8 multiplier = 2;
+ int i, retries = 3;
+
+ for(i = 0; i < retries; i++) {
+@@ -587,22 +592,15 @@ static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tachometer_data *priv,
+ if(raw_data == 0xfffff)
+ return 0;
+
+- tach_div = priv->tacho_channel[fan_tach_ch].divide;
+- /*
+- * We need the mode to determine if the raw_data is double (from
+- * counting both edges).
+- */
+- mode = priv->tacho_channel[fan_tach_ch].tacho_edge;
+- both = (mode & BOTH_EDGES) ? 1 : 0;
+-// printk("clk %ld, raw_data %x , tach_div %x both %x \n", priv->clk_freq, raw_data, tach_div, both);
++ raw_data += 1;
++ tach_div = raw_data * (priv->tacho_channel[fan_tach_ch].divide) * (multiplier);
+
+- tach_div = (tach_div * 2) * (0x1 << both);
+ clk_source = priv->clk_freq;
+
+ if (raw_data == 0)
+ return 0;
+
+- return (clk_source * 60) / (2 * raw_data * tach_div);
++ return (clk_source / tach_div * 60);
+
+ }
+
+@@ -614,19 +612,27 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ int ret;
+ struct aspeed_pwm_tachometer_data *priv = dev_get_drvdata(dev);
+ long fan_ctrl;
++ u8 org_falling = priv->pwm_channel[index].falling;
+
+ ret = kstrtol(buf, 10, &fan_ctrl);
+ if (ret != 0)
+ return ret;
+
+- if (fan_ctrl < 0 || fan_ctrl > priv->pwm_channel[index].period)
++ if (fan_ctrl < 0 || fan_ctrl > DEF_PWM_PERIOD)
+ return -EINVAL;
+
+ if (priv->pwm_channel[index].falling == fan_ctrl)
+ return count;
+
+ priv->pwm_channel[index].falling = fan_ctrl;
+- aspeed_set_pwm_channel_fan_ctrl(priv, index, fan_ctrl);
++
++ if (fan_ctrl == 0)
++ aspeed_set_pwm_channel_enable(priv->regmap, index, false);
++ else
++ regmap_update_bits(priv->regmap, ASPEED_PWM_DUTY_CYCLE_CH(index), GENMASK(15, 8), (fan_ctrl << PWM_RISING_FALLING_BIT));
++
++ if (org_falling == 0)
++ aspeed_set_pwm_channel_enable(priv->regmap, index, true);
+
+ return count;
+ }
+@@ -678,40 +684,39 @@ static umode_t fan_dev_is_visible(struct kobject *kobj,
+ return a->mode;
+ }
+
+-static SENSOR_DEVICE_ATTR(pwm0, 0644,
+- show_pwm, set_pwm, 0);
+ static SENSOR_DEVICE_ATTR(pwm1, 0644,
+- show_pwm, set_pwm, 1);
++ show_pwm, set_pwm, 0);
+ static SENSOR_DEVICE_ATTR(pwm2, 0644,
+- show_pwm, set_pwm, 2);
++ show_pwm, set_pwm, 1);
+ static SENSOR_DEVICE_ATTR(pwm3, 0644,
+- show_pwm, set_pwm, 3);
++ show_pwm, set_pwm, 2);
+ static SENSOR_DEVICE_ATTR(pwm4, 0644,
+- show_pwm, set_pwm, 4);
++ show_pwm, set_pwm, 3);
+ static SENSOR_DEVICE_ATTR(pwm5, 0644,
+- show_pwm, set_pwm, 5);
++ show_pwm, set_pwm, 4);
+ static SENSOR_DEVICE_ATTR(pwm6, 0644,
+- show_pwm, set_pwm, 6);
++ show_pwm, set_pwm, 5);
+ static SENSOR_DEVICE_ATTR(pwm7, 0644,
+- show_pwm, set_pwm, 7);
++ show_pwm, set_pwm, 6);
+ static SENSOR_DEVICE_ATTR(pwm8, 0644,
+- show_pwm, set_pwm, 8);
++ show_pwm, set_pwm, 7);
+ static SENSOR_DEVICE_ATTR(pwm9, 0644,
+- show_pwm, set_pwm, 9);
++ show_pwm, set_pwm, 8);
+ static SENSOR_DEVICE_ATTR(pwm10, 0644,
+- show_pwm, set_pwm, 10);
++ show_pwm, set_pwm, 9);
+ static SENSOR_DEVICE_ATTR(pwm11, 0644,
+- show_pwm, set_pwm, 11);
++ show_pwm, set_pwm, 10);
+ static SENSOR_DEVICE_ATTR(pwm12, 0644,
+- show_pwm, set_pwm, 12);
++ show_pwm, set_pwm, 11);
+ static SENSOR_DEVICE_ATTR(pwm13, 0644,
+- show_pwm, set_pwm, 13);
++ show_pwm, set_pwm, 12);
+ static SENSOR_DEVICE_ATTR(pwm14, 0644,
+- show_pwm, set_pwm, 14);
++ show_pwm, set_pwm, 13);
+ static SENSOR_DEVICE_ATTR(pwm15, 0644,
++ show_pwm, set_pwm, 14);
++static SENSOR_DEVICE_ATTR(pwm16, 0644,
+ show_pwm, set_pwm, 15);
+ static struct attribute *pwm_dev_attrs[] = {
+- &sensor_dev_attr_pwm0.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+@@ -727,6 +732,7 @@ static struct attribute *pwm_dev_attrs[] = {
+ &sensor_dev_attr_pwm13.dev_attr.attr,
+ &sensor_dev_attr_pwm14.dev_attr.attr,
+ &sensor_dev_attr_pwm15.dev_attr.attr,
++ &sensor_dev_attr_pwm16.dev_attr.attr,
+ NULL,
+ };
+
+@@ -735,40 +741,39 @@ static const struct attribute_group pwm_dev_group = {
+ .is_visible = pwm_is_visible,
+ };
+
+-static SENSOR_DEVICE_ATTR(fan0_input, 0444,
+- show_rpm, NULL, 0);
+ static SENSOR_DEVICE_ATTR(fan1_input, 0444,
+- show_rpm, NULL, 1);
++ show_rpm, NULL, 0);
+ static SENSOR_DEVICE_ATTR(fan2_input, 0444,
+- show_rpm, NULL, 2);
++ show_rpm, NULL, 1);
+ static SENSOR_DEVICE_ATTR(fan3_input, 0444,
+- show_rpm, NULL, 3);
++ show_rpm, NULL, 2);
+ static SENSOR_DEVICE_ATTR(fan4_input, 0444,
+- show_rpm, NULL, 4);
++ show_rpm, NULL, 3);
+ static SENSOR_DEVICE_ATTR(fan5_input, 0444,
+- show_rpm, NULL, 5);
++ show_rpm, NULL, 4);
+ static SENSOR_DEVICE_ATTR(fan6_input, 0444,
+- show_rpm, NULL, 6);
++ show_rpm, NULL, 5);
+ static SENSOR_DEVICE_ATTR(fan7_input, 0444,
+- show_rpm, NULL, 7);
++ show_rpm, NULL, 6);
+ static SENSOR_DEVICE_ATTR(fan8_input, 0444,
+- show_rpm, NULL, 8);
++ show_rpm, NULL, 7);
+ static SENSOR_DEVICE_ATTR(fan9_input, 0444,
+- show_rpm, NULL, 9);
++ show_rpm, NULL, 8);
+ static SENSOR_DEVICE_ATTR(fan10_input, 0444,
+- show_rpm, NULL, 10);
++ show_rpm, NULL, 9);
+ static SENSOR_DEVICE_ATTR(fan11_input, 0444,
+- show_rpm, NULL, 11);
++ show_rpm, NULL, 10);
+ static SENSOR_DEVICE_ATTR(fan12_input, 0444,
+- show_rpm, NULL, 12);
++ show_rpm, NULL, 11);
+ static SENSOR_DEVICE_ATTR(fan13_input, 0444,
+- show_rpm, NULL, 13);
++ show_rpm, NULL, 12);
+ static SENSOR_DEVICE_ATTR(fan14_input, 0444,
+- show_rpm, NULL, 14);
++ show_rpm, NULL, 13);
+ static SENSOR_DEVICE_ATTR(fan15_input, 0444,
++ show_rpm, NULL, 14);
++static SENSOR_DEVICE_ATTR(fan16_input, 0444,
+ show_rpm, NULL, 15);
+ static struct attribute *fan_dev_attrs[] = {
+- &sensor_dev_attr_fan0_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+@@ -784,6 +789,7 @@ static struct attribute *fan_dev_attrs[] = {
+ &sensor_dev_attr_fan13_input.dev_attr.attr,
+ &sensor_dev_attr_fan14_input.dev_attr.attr,
+ &sensor_dev_attr_fan15_input.dev_attr.attr,
++ &sensor_dev_attr_fan16_input.dev_attr.attr,
+ NULL
+ };
+
+@@ -802,14 +808,14 @@ static void aspeed_create_pwm_channel(struct aspeed_pwm_tachometer_data *priv,
+ }
+
+ static void aspeed_create_fan_tach_channel(struct aspeed_pwm_tachometer_data *priv,
+- u8 *fan_tach_ch,
+- int count)
++ u8 *fan_tach_ch, int count, u32 min_rpm)
+ {
+ u8 val, index;
+
+ for (val = 0; val < count; val++) {
+ index = fan_tach_ch[val];
+ priv->fan_tach_present[index] = true;
++ priv->tacho_channel[index].min_rpm = min_rpm;
+ aspeed_set_fan_tach_ch_enable(priv, index, true);
+ }
+ }
+@@ -906,13 +912,19 @@ static int aspeed_pwm_create_fan(struct device *dev,
+ struct aspeed_pwm_tachometer_data *priv)
+ {
+ u8 *fan_tach_ch;
++ u32 fan_min_rpm;
+ u32 pwm_channel;
++ u32 target_pwm_freq;
+ int ret, count;
+
+ ret = of_property_read_u32(child, "reg", &pwm_channel);
+ if (ret)
+ return ret;
+
++ ret = of_property_read_u32(child, "aspeed,target_pwm", &target_pwm_freq);
++ if (ret)
++ target_pwm_freq = DEFAULT_TARGET_PWM_FREQ;
++
+ aspeed_create_pwm_channel(priv, (u8)pwm_channel);
+
+ ret = of_property_count_u8_elems(child, "cooling-levels");
+@@ -935,9 +947,11 @@ static int aspeed_pwm_create_fan(struct device *dev,
+ fan_tach_ch, count);
+ if (ret)
+ return ret;
++ ret = of_property_read_u32(child, "aspeed,min_rpm", &fan_min_rpm);
++ if (ret)
++ fan_min_rpm = DEFAULT_MIN_RPM;
+
+- aspeed_create_fan_tach_channel(priv, fan_tach_ch, count);
+-
++ aspeed_create_fan_tach_channel(priv, fan_tach_ch, count, fan_min_rpm);
+ return 0;
+ }
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0096-Fix-truncated-WrEndPointConfig-MMIO-command.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0096-Fix-truncated-WrEndPointConfig-MMIO-command.patch
new file mode 100644
index 000000000..e2196c629
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0096-Fix-truncated-WrEndPointConfig-MMIO-command.patch
@@ -0,0 +1,40 @@
+From 7555448ab0676ea974ef67ef0c8ebe5d68b73d25 Mon Sep 17 00:00:00 2001
+From: "Jason M. Bills" <jason.m.bills@linux.intel.com>
+Date: Tue, 18 Feb 2020 14:17:22 -0800
+Subject: [PATCH] Fix truncated WrEndPointConfig MMIO command
+
+When address type is 6, the driver is reducing the msg buffer to
+the base size and truncating the additional command data.
+
+This removes the line that sets the msg buffer size to the base
+size. The correct buffer size is already set.
+
+Tested:
+Ran this command:
+peci_cmds WrEndpointConfigMMIO 6 0 0 0x7e 0x1a 0x0 0x224e0 0x5f5a56
+
+and got the full buffer in the driver log:
+[ 795.207278] peci_aspeed 1e78b000.peci-bus: HEAD : 0x00011730
+[ 795.212980] TX : c5 00 05 00 00 00 06 00 d0 7e e0 24 02 00 00 00 .........~.$....
+[ 795.220556] TX : 00 00 56 5a 5f 00 a8 ..VZ_..
+
+Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
+---
+ drivers/peci/peci-core.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c
+index 9aedb74..efb73b0 100644
+--- a/drivers/peci/peci-core.c
++++ b/drivers/peci/peci-core.c
+@@ -1040,7 +1040,6 @@ static int peci_cmd_wr_end_pt_cfg(struct peci_adapter *adapter, void *vmsg)
+ >> 24); /* MSB - DWORD Register Offset */
+ if (umsg->params.mmio.addr_type ==
+ PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q) {
+- msg->tx_len = PECI_WRENDPTCFG_MMIO_Q_WRITE_LEN_BASE;
+ msg->tx_buf[14] = (u8)(umsg->params.mmio.offset
+ >> 32); /* Register Offset */
+ msg->tx_buf[15] = (u8)(umsg->params.mmio.offset
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0100-Mailbox-Enabling-interrupt-based-mailbox.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0100-Mailbox-Enabling-interrupt-based-mailbox.patch
new file mode 100644
index 000000000..cb06f9def
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0100-Mailbox-Enabling-interrupt-based-mailbox.patch
@@ -0,0 +1,237 @@
+From d5bc758cee51d92c48f2835ca2b4ebb146f0f0b4 Mon Sep 17 00:00:00 2001
+From: "Arun P. Mohanan" <arun.p.m@linux.intel.com>
+Date: Wed, 11 Mar 2020 17:23:49 +0530
+Subject: [PATCH] [Mailbox] Enabling interrupt based mailbox
+
+Modifying the mailbox driver to use FIFO queue while using interrupt.
+
+Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com>
+---
+ drivers/soc/aspeed/aspeed-lpc-mbox.c | 102 ++++++++++++++++++---------
+ 1 file changed, 69 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/soc/aspeed/aspeed-lpc-mbox.c b/drivers/soc/aspeed/aspeed-lpc-mbox.c
+index 795107206022..1ca68bb3534c 100644
+--- a/drivers/soc/aspeed/aspeed-lpc-mbox.c
++++ b/drivers/soc/aspeed/aspeed-lpc-mbox.c
+@@ -12,10 +12,11 @@
+ #include <linux/poll.h>
+ #include <linux/regmap.h>
+ #include <linux/slab.h>
++#include <linux/kfifo.h>
+
+ #define DEVICE_NAME "aspeed-mbox"
+
+-#define MBX_USE_INTERRUPT 0
++#define MBX_USE_INTERRUPT 1
+
+ #define ASPEED_MBOX_NUM_REGS 16
+
+@@ -29,6 +30,7 @@
+ #define ASPEED_MBOX_HOST_CTRL 0x4c
+ #define ASPEED_MBOX_INTERRUPT_0 0x50
+ #define ASPEED_MBOX_INTERRUPT_1 0x54
++#define MBOX_FIFO_SIZE 64
+
+ struct aspeed_mbox {
+ struct miscdevice miscdev;
+@@ -38,6 +40,8 @@ struct aspeed_mbox {
+ int irq;
+ wait_queue_head_t queue;
+ struct mutex mutex;
++ struct kfifo fifo;
++ spinlock_t lock;
+ };
+
+ static atomic_t aspeed_mbox_open_count = ATOMIC_INIT(0);
+@@ -74,20 +78,37 @@ static struct aspeed_mbox *file_mbox(struct file *file)
+ return container_of(file->private_data, struct aspeed_mbox, miscdev);
+ }
+
++/* Save a byte to a FIFO and discard the oldest byte if FIFO is full */
++static void put_fifo_with_discard(struct aspeed_mbox *mbox, u8 val)
++{
++ if (!kfifo_initialized(&mbox->fifo))
++ return;
++ if (kfifo_is_full(&mbox->fifo))
++ kfifo_skip(&mbox->fifo);
++ kfifo_put(&mbox->fifo, val);
++}
++
+ static int aspeed_mbox_open(struct inode *inode, struct file *file)
+ {
+ #if MBX_USE_INTERRUPT
+ struct aspeed_mbox *mbox = file_mbox(file);
++ int i;
+ #endif
+
+ 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
++ * Reset the FIFO while opening to clear the old cached data
++ * and load the FIFO with latest mailbox register values.
+ */
+- aspeed_mbox_outb(mbox, ASPEED_MBOX_CTRL_RECV, ASPEED_MBOX_BMC_CTRL);
++ kfifo_reset(&mbox->fifo);
++ spin_lock_irq(&mbox->lock);
++ for (i = 0; i < ASPEED_MBOX_NUM_REGS; i++) {
++ put_fifo_with_discard(mbox,
++ aspeed_mbox_inb(mbox, ASPEED_MBOX_DATA_0 + (i * 4)));
++ }
++ spin_unlock_irq(&mbox->lock);
++
+ #endif
+ return 0;
+ }
+@@ -102,6 +123,8 @@ static ssize_t aspeed_mbox_read(struct file *file, char __user *buf,
+ struct aspeed_mbox *mbox = file_mbox(file);
+ char __user *p = buf;
+ ssize_t ret;
++ unsigned int copied;
++ unsigned long flags;
+ int i;
+
+ if (!access_ok(buf, count))
+@@ -111,17 +134,32 @@ static ssize_t aspeed_mbox_read(struct file *file, char __user *buf,
+ 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))
++ /*
++ * Restrict count as per the number of mailbox registers
++ * to use kfifo.
++ */
++ if (count != ASPEED_MBOX_NUM_REGS)
++ goto reg_read;
++
++ if (kfifo_is_empty(&mbox->fifo)) {
++ if (file->f_flags & O_NONBLOCK){
+ return -EAGAIN;
+- } else if (wait_event_interruptible(mbox->queue,
+- aspeed_mbox_inb(mbox, ASPEED_MBOX_BMC_CTRL) &
+- ASPEED_MBOX_CTRL_RECV)) {
+- return -ERESTARTSYS;
++ }
++ ret = wait_event_interruptible(mbox->queue,
++ !kfifo_is_empty(&mbox->fifo));
++ if (ret == -ERESTARTSYS){
++ return -EINTR;
++ }
+ }
++
++ spin_lock_irqsave(&mbox->lock, flags);
++ ret = kfifo_to_user(&mbox->fifo, buf, count, &copied);
++ spin_unlock_irqrestore(&mbox->lock, flags);
++ return ret ? ret : copied;
++
+ #endif
+
++reg_read:
+ mutex_lock(&mbox->mutex);
+
+ for (i = *ppos; count > 0 && i < ASPEED_MBOX_NUM_REGS; i++) {
+@@ -134,11 +172,6 @@ static ssize_t aspeed_mbox_read(struct file *file, char __user *buf,
+ p++;
+ 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:
+@@ -186,16 +219,9 @@ static ssize_t aspeed_mbox_write(struct file *file, const char __user *buf,
+ static unsigned int aspeed_mbox_poll(struct file *file, poll_table *wait)
+ {
+ struct aspeed_mbox *mbox = file_mbox(file);
+- unsigned int mask = 0;
+
+ 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;
++ return !kfifo_is_empty(&mbox->fifo) ? POLLIN : 0;
+ }
+
+ static int aspeed_mbox_release(struct inode *inode, struct file *file)
+@@ -220,19 +246,23 @@ static irqreturn_t aspeed_mbox_irq(int irq, void *arg)
+ #if MBX_USE_INTERRUPT
+ int i;
+
+-// if (!(aspeed_mbox_inb(mbox, ASPEED_MBOX_BMC_CTRL) & ASPEED_MBOX_CTRL_RECV))
+-// return IRQ_NONE;
+-
+- printk(KERN_ERR "BMC_CTRL: 0x%02x\n",
++ dev_dbg(mbox->miscdev.parent, "BMC_CTRL11: 0x%02x\n",
+ aspeed_mbox_inb(mbox, ASPEED_MBOX_BMC_CTRL));
+- printk(KERN_ERR "STATUS_0: 0x%02x\n",
++ dev_dbg(mbox->miscdev.parent, "STATUS_0: 0x%02x\n",
+ aspeed_mbox_inb(mbox, ASPEED_MBOX_STATUS_0));
+- printk(KERN_ERR "STATUS_1: 0x%02x\n",
++ dev_dbg(mbox->miscdev.parent, "STATUS_1: 0x%02x\n",
+ aspeed_mbox_inb(mbox, ASPEED_MBOX_STATUS_1));
+ for (i = 0; i < ASPEED_MBOX_NUM_REGS; i++) {
+- printk(KERN_ERR "DATA_%d: 0x%02x\n", i,
++ dev_dbg(mbox->miscdev.parent, "DATA_%d: 0x%02x\n", i,
+ aspeed_mbox_inb(mbox, ASPEED_MBOX_DATA_0 + (i * 4)));
+ }
++
++ spin_lock(&mbox->lock);
++ for (i = 0; i < ASPEED_MBOX_NUM_REGS; i++) {
++ put_fifo_with_discard(mbox,
++ aspeed_mbox_inb(mbox, ASPEED_MBOX_DATA_0 + (i * 4)));
++ }
++ spin_unlock(&mbox->lock);
+ #endif
+
+ /* Clear interrupt status */
+@@ -249,7 +279,6 @@ static int aspeed_mbox_config_irq(struct aspeed_mbox *mbox,
+ {
+ struct device *dev = &pdev->dev;
+ int rc;
+-
+ mbox->irq = platform_get_irq(pdev, 0);
+ if (!mbox->irq)
+ return -ENODEV;
+@@ -300,6 +329,7 @@ static int aspeed_mbox_probe(struct platform_device *pdev)
+ return -ENODEV;
+ }
+
++ spin_lock_init(&mbox->lock);
+ mutex_init(&mbox->mutex);
+ init_waitqueue_head(&mbox->queue);
+
+@@ -316,6 +346,11 @@ static int aspeed_mbox_probe(struct platform_device *pdev)
+ return rc;
+ }
+
++ /* Create FIFO data structure */
++ rc = kfifo_alloc(&mbox->fifo, MBOX_FIFO_SIZE, GFP_KERNEL);
++ if (rc)
++ return rc;
++
+ mbox->miscdev.minor = MISC_DYNAMIC_MINOR;
+ mbox->miscdev.name = DEVICE_NAME;
+ mbox->miscdev.fops = &aspeed_mbox_fops;
+@@ -349,6 +384,7 @@ static int aspeed_mbox_remove(struct platform_device *pdev)
+
+ misc_deregister(&mbox->miscdev);
+ clk_disable_unprepare(mbox->clk);
++ kfifo_free(&mbox->fifo);
+
+ return 0;
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0101-Add-poll-fops-in-eSPI-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0101-Add-poll-fops-in-eSPI-driver.patch
new file mode 100644
index 000000000..b4118e169
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0101-Add-poll-fops-in-eSPI-driver.patch
@@ -0,0 +1,151 @@
+From 9479d8f12efc845faca4bb1aef9b6e63799a7e5c Mon Sep 17 00:00:00 2001
+From: "Arun P. Mohanan" <arun.p.m@linux.intel.com>
+Date: Wed, 18 Mar 2020 08:34:43 +0530
+Subject: [PATCH] Add poll fops in eSPI driver
+
+Modify eSPI driver to support poll fops.
+
+Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com>
+---
+ drivers/misc/aspeed-espi-slave.c | 85 +++++++++++++++++++++++---------
+ 1 file changed, 61 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/misc/aspeed-espi-slave.c b/drivers/misc/aspeed-espi-slave.c
+index 87bc81948694..cb8ed585c69f 100644
+--- a/drivers/misc/aspeed-espi-slave.c
++++ b/drivers/misc/aspeed-espi-slave.c
+@@ -9,6 +9,7 @@
+ #include <linux/module.h>
+ #include <linux/of.h>
+ #include <linux/platform_device.h>
++#include <linux/poll.h>
+ #include <linux/regmap.h>
+ #include <linux/reset.h>
+ #include <linux/sched/signal.h>
+@@ -95,6 +96,7 @@ struct aspeed_espi {
+ spinlock_t pltrstn_lock; /* for PLTRST_N signal sampling */
+ wait_queue_head_t pltrstn_waitq;
+ char pltrstn;
++ bool pltrstn_in_avail;
+ };
+
+ static void aspeed_espi_sys_event(struct aspeed_espi *priv)
+@@ -127,7 +129,10 @@ static void aspeed_espi_sys_event(struct aspeed_espi *priv)
+ dev_dbg(priv->dev, "SYSEVT_OOB_RST_WARN: acked\n");
+ }
+ if (sts & ASPEED_ESPI_SYSEVT_PLTRSTN || priv->pltrstn == 'U') {
++ spin_lock(&priv->pltrstn_lock);
+ priv->pltrstn = (evt & ASPEED_ESPI_SYSEVT_PLTRSTN) ? '1' : '0';
++ priv->pltrstn_in_avail = true;
++ spin_unlock(&priv->pltrstn_lock);
+ wake_up_interruptible(&priv->pltrstn_waitq);
+ dev_dbg(priv->dev, "SYSEVT_PLTRSTN: %c\n", priv->pltrstn);
+ }
+@@ -269,6 +274,8 @@ static int aspeed_espi_pltrstn_open(struct inode *inode, struct file *filp)
+ {
+ if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
+ return -EACCES;
++ struct aspeed_espi *priv = to_aspeed_espi(filp);
++ priv->pltrstn_in_avail = true ; /*Setting true returns first data after file open*/
+
+ return 0;
+ }
+@@ -284,41 +291,71 @@ static ssize_t aspeed_espi_pltrstn_read(struct file *filp, char __user *buf,
+
+ spin_lock_irqsave(&priv->pltrstn_lock, flags);
+
+- add_wait_queue(&priv->pltrstn_waitq, &wait);
+- set_current_state(TASK_INTERRUPTIBLE);
+-
+- old_sample = priv->pltrstn;
+-
+- do {
+- char new_sample = priv->pltrstn;
+-
+- if (filp->f_flags & O_NONBLOCK || old_sample != new_sample) {
+- ret = put_user(new_sample, (unsigned long __user *)buf);
+- if (!ret)
+- ret = sizeof(new_sample);
+- } else if (signal_pending(current)) {
+- ret = -ERESTARTSYS;
++ if (filp->f_flags & O_NONBLOCK) {
++ if (!priv->pltrstn_in_avail) {
++ ret = -EAGAIN;
++ goto out_unlock;
+ }
+-
+- if (!ret) {
+- spin_unlock_irqrestore(&priv->pltrstn_lock, flags);
+- schedule();
+- spin_lock_irqsave(&priv->pltrstn_lock, flags);
++ char data = priv->pltrstn;
++ ret = put_user(data, (unsigned long __user *)buf);
++ if (!ret){
++ ret = sizeof(data);
++ } else{
++ ret = -EAGAIN;
+ }
+- } while (!ret);
+-
+- remove_wait_queue(&priv->pltrstn_waitq, &wait);
+- set_current_state(TASK_RUNNING);
+-
++ priv->pltrstn_in_avail = false;
++ } else {
++ add_wait_queue(&priv->pltrstn_waitq, &wait);
++ set_current_state(TASK_INTERRUPTIBLE);
++
++ old_sample = priv->pltrstn;
++
++ do {
++ char new_sample = priv->pltrstn;
++
++ if (old_sample != new_sample) {
++ ret = put_user(new_sample,
++ (unsigned long __user *)buf);
++ if (!ret)
++ ret = sizeof(new_sample);
++ } else if (signal_pending(current)) {
++ ret = -ERESTARTSYS;
++ }
++
++ if (!ret) {
++ spin_unlock_irqrestore(&priv->pltrstn_lock,
++ flags);
++ schedule();
++ spin_lock_irqsave(&priv->pltrstn_lock, flags);
++ }
++ } while (!ret);
++
++ remove_wait_queue(&priv->pltrstn_waitq, &wait);
++ set_current_state(TASK_RUNNING);
++ }
++out_unlock:
+ spin_unlock_irqrestore(&priv->pltrstn_lock, flags);
+
+ return ret;
+ }
+
++static unsigned int aspeed_espi_pltrstn_poll(struct file *file,
++ poll_table *wait)
++{
++ struct aspeed_espi *priv = to_aspeed_espi(file);
++ unsigned int mask = 0;
++ poll_wait(file, &priv->pltrstn_waitq, wait);
++
++ if (priv->pltrstn_in_avail)
++ mask |= POLLIN;
++ return mask;
++}
++
+ static const struct file_operations aspeed_espi_pltrstn_fops = {
+ .owner = THIS_MODULE,
+ .open = aspeed_espi_pltrstn_open,
+ .read = aspeed_espi_pltrstn_read,
++ .poll = aspeed_espi_pltrstn_poll,
+ };
+
+ static const struct regmap_config aspeed_espi_regmap_cfg = {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0102-Fix-for-dirty-node-in-jffs2-summary-entry.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0102-Fix-for-dirty-node-in-jffs2-summary-entry.patch
new file mode 100644
index 000000000..f3bb26a8a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0102-Fix-for-dirty-node-in-jffs2-summary-entry.patch
@@ -0,0 +1,94 @@
+From 9d4191d2702ad5a368ca79eb253de26ce94b91c7 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Mon, 30 Mar 2020 11:00:16 +0530
+Subject: [PATCH] From: Thomas Betker <thomas.betker@rohde-schwarz.com>
+
+jffs2_flash_direct_writev() always invokes jffs2_sum_add_kvec(), even
+if mtd_writev() fails. Usually, this results in an extra summary entry
+pointing to dirty node space, which should be ignored -- it is a bit of
+a waste, but harmless.
+
+When mtd_writev() returns *retlen == 0, though, the node space is not
+reserved as dirty, but re-used; the extra summary entry then points
+into the space of the next node. After the erase block has been closed,
+we get the following messages on remount:
+
+ jffs2: error: (79) jffs2_link_node_ref:
+ Adding new ref c3048d18 at (0x00ec5b88-0x00ec6bcc)
+ not immediately after previous (0x00ec5b88-0x00ec5b88)
+ ...
+ jffs2: Checked all inodes but still 0x2088 bytes of unchecked space?
+ jffs2: No space for garbage collection. Aborting GC thread
+
+The extra summary entries amount to "unchecked space", so that
+jffs2_garbage_collect_pass() returns -ENOSPC. And without garbage
+collection, the filesystem becomes unuseable over time as the erase
+blocks fill up.
+
+Fix this by skipping jffs2_sum_add_kvec() when the MTD write fails. We
+don't need the summary entry anyway, and the behaviour matches that of
+jffs2_flash_writev() in wbuf.c (with write buffering enabled).
+
+Signed-off-by: Thomas Betker <thomas.betker@rohde-schwarz.com>
+---
+ fs/jffs2/writev.c | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/fs/jffs2/writev.c b/fs/jffs2/writev.c
+index a1bda9d..eec4197 100644
+--- a/fs/jffs2/writev.c
++++ b/fs/jffs2/writev.c
+@@ -16,9 +16,18 @@
+ int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
+ unsigned long count, loff_t to, size_t *retlen)
+ {
++ int ret;
++
++ ret = mtd_writev(c->mtd, vecs, count, to, retlen);
++
+ if (!jffs2_is_writebuffered(c)) {
+ if (jffs2_sum_active()) {
+ int res;
++
++ if (ret ||
++ *retlen != iov_length((struct iovec *) vecs, count))
++ return ret;
++
+ res = jffs2_sum_add_kvec(c, vecs, count, (uint32_t) to);
+ if (res) {
+ return res;
+@@ -26,19 +35,23 @@ int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
+ }
+ }
+
+- return mtd_writev(c->mtd, vecs, count, to, retlen);
++ return ret;
+ }
+
+ int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
+ size_t *retlen, const u_char *buf)
+ {
+ int ret;
++
+ ret = mtd_write(c->mtd, ofs, len, retlen, buf);
+
+ if (jffs2_sum_active()) {
+ struct kvec vecs[1];
+ int res;
+
++ if (ret || *retlen != len)
++ return ret;
++
+ vecs[0].iov_base = (unsigned char *) buf;
+ vecs[0].iov_len = len;
+
+@@ -47,5 +60,6 @@ int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
+ return res;
+ }
+ }
++
+ return ret;
+ }
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0103-Refine-clock-settings.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0103-Refine-clock-settings.patch
new file mode 100644
index 000000000..4d7440185
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0103-Refine-clock-settings.patch
@@ -0,0 +1,191 @@
+From dd7498a847b3e908dabaed2e9a27b43a26d0dba0 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 26 Mar 2020 14:20:19 -0700
+Subject: [PATCH] Refine clock settings
+
+This commit refines clock settings with cherry picking the latest
+code from Aspeed SDK v00.05.05
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/clk/clk-ast2600.c | 104 +++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 85 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c
+index af908b2dbeb6..e5079c5f4fcf 100644
+--- a/drivers/clk/clk-ast2600.c
++++ b/drivers/clk/clk-ast2600.c
+@@ -31,6 +31,24 @@
+ #define ASPEED_G6_CLK_SELECTION1 0x300
+ #define ASPEED_G6_CLK_SELECTION2 0x304
+ #define ASPEED_G6_CLK_SELECTION4 0x310
++#define ASPEED_G6_CLK_SELECTION5 0x314
++
++#define ASPEED_G6_MAC12_CLK_CTRL0 0x340
++#define ASPEED_G6_MAC12_CLK_CTRL1 0x348
++#define ASPEED_G6_MAC12_CLK_CTRL2 0x34C
++
++#define ASPEED_G6_MAC34_CLK_CTRL0 0x350
++#define ASPEED_G6_MAC34_CLK_CTRL1 0x358
++#define ASPEED_G6_MAC34_CLK_CTRL2 0x35C
++
++#define ASPEED_G6_MAC34_DRIVING_CTRL 0x458
++
++#define ASPEED_G6_DEF_MAC12_DELAY_1G 0x0041b410
++#define ASPEED_G6_DEF_MAC12_DELAY_100M 0x00417410
++#define ASPEED_G6_DEF_MAC12_DELAY_10M 0x00417410
++#define ASPEED_G6_DEF_MAC34_DELAY_1G 0x00104208
++#define ASPEED_G6_DEF_MAC34_DELAY_100M 0x00104208
++#define ASPEED_G6_DEF_MAC34_DELAY_10M 0x00104208
+
+ #define ASPEED_HPLL_PARAM 0x200
+ #define ASPEED_APLL_PARAM 0x210
+@@ -40,9 +58,6 @@
+
+ #define ASPEED_G6_STRAP1 0x500
+
+-#define ASPEED_MAC12_CLK_DLY 0x340
+-#define ASPEED_MAC34_CLK_DLY 0x350
+-
+ #define ASPEED_G6_GEN_UART_REF 0x338
+ #define UART_192MHZ_R_N_VALUE 0x3c38e
+
+@@ -515,7 +530,7 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev)
+
+ /* RMII1 50MHz (RCLK) output enable */
+ hw = clk_hw_register_gate(dev, "mac1rclk", "mac12rclk", 0,
+- scu_g6_base + ASPEED_MAC12_CLK_DLY, 29, 0,
++ scu_g6_base + ASPEED_G6_MAC12_CLK_CTRL0, 29, 0,
+ &aspeed_g6_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+@@ -523,7 +538,7 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev)
+
+ /* RMII2 50MHz (RCLK) output enable */
+ hw = clk_hw_register_gate(dev, "mac2rclk", "mac12rclk", 0,
+- scu_g6_base + ASPEED_MAC12_CLK_DLY, 30, 0,
++ scu_g6_base + ASPEED_G6_MAC12_CLK_CTRL0, 30, 0,
+ &aspeed_g6_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+@@ -545,7 +560,7 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev)
+
+ /* RMII3 50MHz (RCLK) output enable */
+ hw = clk_hw_register_gate(dev, "mac3rclk", "mac34rclk", 0,
+- scu_g6_base + ASPEED_MAC34_CLK_DLY, 29, 0,
++ scu_g6_base + ASPEED_G6_MAC34_CLK_CTRL0, 29, 0,
+ &aspeed_g6_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+@@ -553,7 +568,7 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev)
+
+ /* RMII4 50MHz (RCLK) output enable */
+ hw = clk_hw_register_gate(dev, "mac4rclk", "mac34rclk", 0,
+- scu_g6_base + ASPEED_MAC34_CLK_DLY, 30, 0,
++ scu_g6_base + ASPEED_G6_MAC34_CLK_CTRL0, 30, 0,
+ &aspeed_g6_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+@@ -650,12 +665,20 @@ static struct platform_driver aspeed_g6_clk_driver = {
+ };
+ builtin_platform_driver(aspeed_g6_clk_driver);
+
+-static const u32 ast2600_a0_axi_ahb_div_table[] = {
+- 2, 2, 3, 5,
++static u32 ast2600_a0_axi_ahb_div_table[] = {
++ 2, 2, 3, 4,
+ };
+
+-static const u32 ast2600_a1_axi_ahb_div_table[] = {
+- 4, 6, 2, 4,
++static u32 ast2600_a1_axi_ahb_div0_table[] = {
++ 3, 2, 3, 4,
++};
++
++static u32 ast2600_a1_axi_ahb_div1_table[] = {
++ 3, 4, 6, 8,
++};
++
++static const u32 ast2600_a1_axi_ahb_default_table[] = {
++ 3, 4, 3, 4, 2, 2, 2, 2,
+ };
+
+ static void __init aspeed_g6_cc(struct regmap *map)
+@@ -686,16 +709,28 @@ static void __init aspeed_g6_cc(struct regmap *map)
+
+ /* Strap bits 12:11 define the AXI/AHB clock frequency ratio (aka HCLK)*/
+ regmap_read(map, ASPEED_G6_STRAP1, &val);
+- if (val & BIT(16))
+- axi_div = 1;
+- else
+- axi_div = 2;
+-
+ regmap_read(map, ASPEED_G6_SILICON_REV, &chip_id);
+- if (chip_id & BIT(16))
+- ahb_div = ast2600_a1_axi_ahb_div_table[(val >> 11) & 0x3];
+- else
++ if (chip_id & BIT(16)) {
++ if (val & BIT(16)) {
++ axi_div = 1;
++ ast2600_a1_axi_ahb_div1_table[0] =
++ ast2600_a1_axi_ahb_default_table[(val >> 8) &
++ 0x3];
++ ahb_div = ast2600_a1_axi_ahb_div1_table[(val >> 11) &
++ 0x3];
++ } else {
++ axi_div = 2;
++ ast2600_a1_axi_ahb_div0_table[0] =
++ ast2600_a1_axi_ahb_default_table[(val >> 8) &
++ 0x3];
++ ahb_div = ast2600_a1_axi_ahb_div0_table[(val >> 11) &
++ 0x3];
++ }
++ } else {
++ /* a0 : fix axi = hpll/2 */
++ axi_div = 2;
+ ahb_div = ast2600_a0_axi_ahb_div_table[(val >> 11) & 0x3];
++ }
+
+ hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, axi_div * ahb_div);
+ aspeed_g6_clk_data->hws[ASPEED_CLK_AHB] = hw;
+@@ -751,6 +786,37 @@ static void __init aspeed_g6_cc_init(struct device_node *np)
+ return;
+ }
+
++ /* fixed settings for RGMII/RMII clock generator */
++ /* MAC1/2 RGMII 125MHz = EPLL / 8 */
++ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION2, GENMASK(23, 20),
++ (0x7 << 20));
++
++ /* MAC3/4 RMII 50MHz = HCLK / 4 */
++ regmap_update_bits(map, ASPEED_G6_CLK_SELECTION4, GENMASK(18, 16),
++ (0x3 << 16));
++
++ /*
++ * BIT[31]: MAC1/2 RGMII 125M source = internal PLL
++ * BIT[28]: RGMIICK pad direction = output
++ */
++ regmap_write(map, ASPEED_G6_MAC12_CLK_CTRL0,
++ BIT(31) | BIT(28) | ASPEED_G6_DEF_MAC12_DELAY_1G);
++ regmap_write(map, ASPEED_G6_MAC12_CLK_CTRL1,
++ ASPEED_G6_DEF_MAC12_DELAY_100M);
++ regmap_write(map, ASPEED_G6_MAC12_CLK_CTRL2,
++ ASPEED_G6_DEF_MAC12_DELAY_10M);
++
++ /* MAC3/4 RGMII 125M source = RGMIICK pad */
++ regmap_write(map, ASPEED_G6_MAC34_CLK_CTRL0,
++ ASPEED_G6_DEF_MAC34_DELAY_1G);
++ regmap_write(map, ASPEED_G6_MAC34_CLK_CTRL1,
++ ASPEED_G6_DEF_MAC34_DELAY_100M);
++ regmap_write(map, ASPEED_G6_MAC34_CLK_CTRL2,
++ ASPEED_G6_DEF_MAC34_DELAY_10M);
++
++ /* MAC3/4 default pad driving strength */
++ regmap_write(map, ASPEED_G6_MAC34_DRIVING_CTRL, 0x0000000a);
++
+ aspeed_g6_cc(map);
+ aspeed_g6_clk_data->num = ASPEED_G6_NUM_CLKS;
+ ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, aspeed_g6_clk_data);
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0104-Add-chip-unique-id-reading-interface.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0104-Add-chip-unique-id-reading-interface.patch
new file mode 100644
index 000000000..f366287f1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0104-Add-chip-unique-id-reading-interface.patch
@@ -0,0 +1,213 @@
+From 61fd1c976a0867deec8607183849969e2d96aef7 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Fri, 27 Mar 2020 14:42:05 -0700
+Subject: [PATCH] Add chip unique id reading interface
+
+This commit adds an interface for reading chip unique id value.
+Optionally, the id can be encrypted using a dts-supplied hash data.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ drivers/soc/aspeed/aspeed-bmc-misc.c | 118 ++++++++++++++++++++++++---
+ 1 file changed, 105 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/soc/aspeed/aspeed-bmc-misc.c b/drivers/soc/aspeed/aspeed-bmc-misc.c
+index 04d97ab17274..c80b2e71f254 100644
+--- a/drivers/soc/aspeed/aspeed-bmc-misc.c
++++ b/drivers/soc/aspeed/aspeed-bmc-misc.c
+@@ -7,15 +7,18 @@
+ #include <linux/platform_device.h>
+ #include <linux/regmap.h>
+ #include <linux/mfd/syscon.h>
++#include <crypto/hash.h>
+
+ #define DEVICE_NAME "aspeed-bmc-misc"
+
+ struct aspeed_bmc_ctrl {
+ const char *name;
+ u32 offset;
+- u32 mask;
++ u64 mask;
+ u32 shift;
+ bool read_only;
++ u32 reg_width;
++ const char *hash_data;
+ struct regmap *map;
+ struct kobj_attribute attr;
+ };
+@@ -31,6 +34,7 @@ static int aspeed_bmc_misc_parse_dt_child(struct device_node *child,
+ struct aspeed_bmc_ctrl *ctrl)
+ {
+ int rc;
++ u32 mask;
+
+ /* Example child:
+ *
+@@ -38,6 +42,7 @@ static int aspeed_bmc_misc_parse_dt_child(struct device_node *child,
+ * offset = <0x80>;
+ * bit-mask = <0x1>;
+ * bit-shift = <6>;
++ * reg-width = <64>;
+ * label = "foo";
+ * }
+ */
+@@ -48,9 +53,22 @@ static int aspeed_bmc_misc_parse_dt_child(struct device_node *child,
+ if (rc < 0)
+ return rc;
+
+- rc = of_property_read_u32(child, "bit-mask", &ctrl->mask);
+- if (rc < 0)
+- return rc;
++ /* optional reg-width, default to 32 */
++ rc = of_property_read_u32(child, "reg-width", &ctrl->reg_width);
++ if (rc < 0 || ctrl->reg_width != 64)
++ ctrl->reg_width = 32;
++
++ if (ctrl->reg_width == 32) {
++ rc = of_property_read_u32(child, "bit-mask", &mask);
++ if (rc < 0)
++ return rc;
++ ctrl->mask = mask;
++ } else {
++ rc = of_property_read_u64(child, "bit-mask", &ctrl->mask);
++ if (rc < 0)
++ return rc;
++ }
++ ctrl->mask <<= ctrl->shift;
+
+ rc = of_property_read_u32(child, "bit-shift", &ctrl->shift);
+ if (rc < 0)
+@@ -58,7 +76,9 @@ static int aspeed_bmc_misc_parse_dt_child(struct device_node *child,
+
+ ctrl->read_only = of_property_read_bool(child, "read-only");
+
+- ctrl->mask <<= ctrl->shift;
++ /* optional hash_data for obfuscating reads */
++ if (of_property_read_string(child, "hash-data", &ctrl->hash_data))
++ ctrl->hash_data = NULL;
+
+ return 0;
+ }
+@@ -88,22 +108,94 @@ static int aspeed_bmc_misc_parse_dt(struct aspeed_bmc_misc *bmc,
+ return 0;
+ }
+
++#define SHA256_DIGEST_LEN 32
++static int hmac_sha256(u8 *key, u8 ksize, const char *plaintext, u8 psize,
++ u8 *output)
++{
++ struct crypto_shash *tfm;
++ struct shash_desc *shash;
++ int ret;
++
++ if (!ksize)
++ return -EINVAL;
++
++ tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
++ if (IS_ERR(tfm)) {
++ return -ENOMEM;
++ }
++
++ ret = crypto_shash_setkey(tfm, key, ksize);
++ if (ret)
++ goto failed;
++
++ shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm), GFP_KERNEL);
++ if (!shash) {
++ ret = -ENOMEM;
++ goto failed;
++ }
++
++ shash->tfm = tfm;
++ ret = crypto_shash_digest(shash, plaintext, psize, output);
++
++ kfree(shash);
++
++failed:
++ crypto_free_shash(tfm);
++ return ret;
++}
++
+ static ssize_t aspeed_bmc_misc_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+ {
+ struct aspeed_bmc_ctrl *ctrl;
+- unsigned int val;
++ u32 val;
++ u64 val64;
+ int rc;
++ u8 *binbuf;
++ size_t buf_len;
++ u8 hashbuf[SHA256_DIGEST_LEN];
+
+ ctrl = container_of(attr, struct aspeed_bmc_ctrl, attr);
++
++ if (ctrl->reg_width == 32) {
++ rc = regmap_read(ctrl->map, ctrl->offset, &val);
++ if (rc)
++ return rc;
++ val &= (u32)ctrl->mask;
++ val >>= ctrl->shift;
++
++ return sprintf(buf, "%u\n", val);
++ }
+ rc = regmap_read(ctrl->map, ctrl->offset, &val);
+ if (rc)
+ return rc;
++ val64 = val;
++ rc = regmap_read(ctrl->map, ctrl->offset + sizeof(u32), &val);
++ if (rc)
++ return rc;
++ /* aspeed puts 64-bit regs as L, H in address space */
++ val64 |= (u64)val << 32;
++ val64 &= ctrl->mask;
++ val64 >>= ctrl->shift;
++ buf_len = sizeof(val64);
++
++ if (ctrl->hash_data) {
++ rc = hmac_sha256((u8*)&val64, buf_len, ctrl->hash_data,
++ strlen(ctrl->hash_data), hashbuf);
++ if (rc)
++ return rc;
++ buf_len = SHA256_DIGEST_LEN;
++ binbuf = hashbuf;
++ } else {
++ binbuf = (u8*)&val64;
++ buf_len = sizeof(val64);
++ }
++ bin2hex(buf, binbuf, buf_len);
++ buf[buf_len * 2] = '\n';
++ rc = buf_len * 2 + 1;
+
+- val &= ctrl->mask;
+- val >>= ctrl->shift;
++ return rc;
+
+- return sprintf(buf, "%u\n", val);
+ }
+
+ static ssize_t aspeed_bmc_misc_store(struct kobject *kobj,
+@@ -114,15 +206,15 @@ static ssize_t aspeed_bmc_misc_store(struct kobject *kobj,
+ long val;
+ int rc;
+
+- rc = kstrtol(buf, 0, &val);
+- if (rc)
+- return rc;
+-
+ ctrl = container_of(attr, struct aspeed_bmc_ctrl, attr);
+
+ if (ctrl->read_only)
+ return -EROFS;
+
++ rc = kstrtol(buf, 0, &val);
++ if (rc)
++ return rc;
++
+ val <<= ctrl->shift;
+ rc = regmap_update_bits(ctrl->map, ctrl->offset, ctrl->mask, val);
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/debug.cfg b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/debug.cfg
new file mode 100644
index 000000000..bbc7fa5b6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/debug.cfg
@@ -0,0 +1,2 @@
+CONFIG_DEVMEM = y
+CONFIG_DEVMEM_BOOTPARAM = n
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..5f453510a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/intel.cfg
@@ -0,0 +1,89 @@
+CONFIG_BLK_DEV_RAM=y
+CONFIG_HWMON=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_IIO=y
+CONFIG_SENSORS_IIO_HWMON=y
+CONFIG_ASPEED_ADC=y
+CONFIG_SGPIO_ASPEED=y
+CONFIG_CRC8=y
+CONFIG_PECI=y
+CONFIG_PECI_CHARDEV=y
+CONFIG_PECI_ASPEED=y
+CONFIG_SENSORS_PECI_CPUTEMP=y
+CONFIG_SENSORS_PECI_DIMMTEMP=y
+CONFIG_SENSORS_PECI_CPUPOWER=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_MQUEUE=y
+CONFIG_I2C_SLAVE_MQUEUE_MESSAGE_SIZE=256
+CONFIG_I2C_SLAVE_MQUEUE_QUEUE_SIZE=32
+CONFIG_ASPEED_BT_IPMI_BMC=n
+CONFIG_ASPEED_LPC_CTRL=n
+CONFIG_ASPEED_LPC_MBOX=y
+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_MASS_STORAGE=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_ASPEED_VGA_SHAREDMEM=y
+CONFIG_PWM=y
+CONFIG_PWM_FTTMR010=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PWM_BEEPER=y
+CONFIG_VFAT_FS=y
+CONFIG_NLS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_UTF8=y
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_CIFS=y
+CONFIG_CIFS_XATTR=y
+CONFIG_PSTORE=y
+CONFIG_PSTORE_ZLIB_COMPRESS=y
+CONFIG_PSTORE_RAM=y
+CONFIG_FSI=n
+CONFIG_FSI_MASTER_HUB=n
+CONFIG_FSI_MASTER_ASPEED=n
+CONFIG_FSI_SCOM=n
+CONFIG_FSI_SBEFIFO=n
+CONFIG_FSI_OCC=n
+CONFIG_ASPEED_P2A_CTRL=n
+CONFIG_USB=n
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=n
+CONFIG_USB_DYNAMIC_MINORS=n
+CONFIG_USB_EHCI_HCD=n
+CONFIG_USB_EHCI_ROOT_HUB_TT=n
+CONFIG_USB_EHCI_HCD_PLATFORM=n
+CONFIG_IPMB_DEVICE_INTERFACE=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..936ea4100
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend
@@ -0,0 +1,81 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+do_compile_prepend(){
+ # device tree compiler flags
+ export DTC_FLAGS=-@
+}
+
+SRC_URI += " \
+ file://intel.cfg \
+ file://0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch \
+ file://0001-arm-dts-add-DTS-for-Intel-ast2600-platforms.patch \
+ file://0001-arm-dts-base-aspeed-g6-dtsi-fixups.patch \
+ file://0002-Enable-pass-through-on-GPIOE1-and-GPIOE3-free.patch \
+ file://0003-Enable-GPIOE0-and-GPIOE2-pass-through-by-default.patch \
+ file://0006-Allow-monitoring-of-power-control-input-GPIOs.patch \
+ file://0007-aspeed-pwm-tacho-change-default-fan-speed.patch \
+ file://0014-arm-dts-aspeed-g5-add-espi.patch \
+ file://0015-New-flash-map-for-intel.patch \
+ file://0016-Add-ASPEED-SGPIO-driver.patch \
+ file://0017-SGPIO-DT-and-pinctrl-fixup.patch \
+ file://0019-Add-I2C-IPMB-support.patch \
+ file://0020-misc-aspeed-add-lpc-mbox-driver.patch \
+ file://0021-Initial-Port-of-Aspeed-LPC-SIO-driver.patch \
+ file://0022-Add-AST2500-eSPI-driver.patch \
+ file://0028-Add-AST2500-JTAG-driver.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-aspeed-Swap-the-mac-nodes-numbering.patch \
+ file://0035-Implement-a-memory-driver-share-memory.patch \
+ file://0039-Add-Aspeed-PWM-driver-which-uses-FTTMR010-timer-IP.patch \
+ file://0040-i2c-Add-mux-hold-unhold-msg-types.patch \
+ file://0042-Add-bus-timeout-ms-and-retries-device-tree-propertie.patch \
+ file://0043-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-BT.patch \
+ file://0044-misc-Add-clock-control-logic-into-Aspeed-LPC-SNOOP-d.patch \
+ file://0045-char-ipmi-Add-clock-control-logic-into-Aspeed-LPC-KC.patch \
+ file://0047-misc-Block-error-printing-on-probe-defer-case-in-Asp.patch \
+ file://0049-Suppress-excessive-HID-gadget-error-logs.patch \
+ file://0051-Add-AST2500-JTAG-device.patch \
+ file://0052-drivers-jtag-Add-JTAG-core-driver.patch \
+ file://0053-Add-Aspeed-SoC-24xx-and-25xx-families-JTAG.patch \
+ file://0054-Documentation-jtag-Add-bindings-for-Aspeed-SoC.patch \
+ file://0055-Documentation-jtag-Add-ABI-documentation.patch \
+ file://0056-Documentation-jtag-Add-JTAG-core-driver-ioctl-number.patch \
+ file://0057-drivers-jtag-Add-JTAG-core-driver-Maintainers.patch \
+ file://0061-i2c-aspeed-add-buffer-mode-transfer-support.patch \
+ file://0062-i2c-aspeed-add-DMA-mode-transfer-support.patch \
+ file://0063-i2c-aspeed-add-general-call-support.patch \
+ file://0064-set-idle-disconnect-to-true-in-all-cases.patch \
+ file://0068-i2c-aspeed-add-H-W-timeout-support.patch \
+ file://0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch \
+ file://0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch \
+ file://0072-pmbus-add-fault-and-beep-attributes.patch \
+ file://0073-Add-IO-statistics-to-USB-Mass-storage-gadget.patch \
+ file://0075-Refine-initialization-flow-in-I2C-driver.patch \
+ file://0076-arm-ast2600-add-pwm_tacho-driver-from-aspeed.patch \
+ file://0077-soc-aspeed-Add-read-only-property-support.patch \
+ file://0078-Fix-NCSI-driver-issue-caused-by-host-shutdown.patch \
+ file://0080-i2c-aspeed-filter-garbage-interrupts-out.patch \
+ file://0084-ARM-dts-aspeed-g6-add-GFX-node.patch \
+ file://0085-drm-add-AST2600-GFX-support.patch \
+ file://0086-ADC-linux-driver-for-AST2600.patch \
+ file://0086-ARM-dts-aspeed-g6-add-video-node.patch \
+ file://0087-media-aspeed-add-aspeed-ast2600-video-engine-compati.patch \
+ file://0088-clk-ast2600-enable-ESPICLK-always.patch \
+ file://0089-ast2600-enable-high-speed-uart-in-kernel.patch \
+ file://0090-peci-cpupower-driver-1.patch \
+ file://0092-SPI-Quad-IO-driver-support-AST2600.patch \
+ file://0093-ipmi-ipmb_dev_int-add-quick-fix-for-raw-I2C-type-reg.patch \
+ file://0094-Return-link-speed-and-duplex-settings-for-the-NCSI-c.patch \
+ file://0095-pwm-and-tach-driver-changes-for-ast2600.patch \
+ file://0096-Fix-truncated-WrEndPointConfig-MMIO-command.patch \
+ file://0100-Mailbox-Enabling-interrupt-based-mailbox.patch \
+ file://0101-Add-poll-fops-in-eSPI-driver.patch \
+ file://0102-Fix-for-dirty-node-in-jffs2-summary-entry.patch \
+ file://0103-Refine-clock-settings.patch \
+ file://0104-Add-chip-unique-id-reading-interface.patch \
+ "
+
+SRC_URI += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', 'file://0005-128MB-flashmap-for-PFR.patch', '', d)}"
+SRC_URI += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'debug-tweaks', 'file://debug.cfg', '', d)}"
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch
new file mode 100644
index 000000000..05e26bedb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0003-Adding-channel-specific-privilege-to-network.patch
@@ -0,0 +1,412 @@
+From 5dfcd6c81a9f26c6c9c867a7a49f5259c3512be2 Mon Sep 17 00:00:00 2001
+From: AppaRao Puli <apparao.puli@linux.intel.com>
+Date: Thu, 2 Apr 2020 17:06:07 +0530
+Subject: [PATCH 1/2] 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 | 123 +++++++++++++++++++++++++++++++++++++++++++++++++
+ ethernet_interface.hpp | 39 +++++++++++++++-
+ network_manager.cpp | 104 +++++++++++++++++++++++++++++++++++++++++
+ network_manager.hpp | 9 ++++
+ 4 files changed, 274 insertions(+), 1 deletion(-)
+
+diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
+index ed1e1ba..fca86bd 100644
+--- a/ethernet_interface.cpp
++++ b/ethernet_interface.cpp
+@@ -37,6 +37,10 @@ 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";
++
+ struct EthernetIntfSocket
+ {
+ EthernetIntfSocket(int domain, int type, int protocol)
+@@ -86,6 +90,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
+ EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
+ EthernetInterfaceIntf::linkUp(std::get<3>(ifInfo));
+ #endif
++ getChannelPrivilege(intfName);
+
+ // Emit deferred signal.
+ if (emitSignal)
+@@ -869,5 +874,123 @@ 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 (manager.supportedPrivList.empty())
++ {
++ // Populate the supported privilege list
++ manager.initSupportedPrivilges();
++ }
++
++ 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 68668d6..058d328 100644
+--- a/ethernet_interface.hpp
++++ b/ethernet_interface.hpp
+@@ -2,11 +2,14 @@
+
+ #include "types.hpp"
+ #include "util.hpp"
++#include "xyz/openbmc_project/Channel/ChannelAccess/server.hpp"
+ #include "xyz/openbmc_project/Network/IP/Create/server.hpp"
+ #include "xyz/openbmc_project/Network/Neighbor/CreateStatic/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>
+@@ -23,7 +26,8 @@ using Ifaces = sdbusplus::server::object::object<
+ sdbusplus::xyz::openbmc_project::Network::server::MACAddress,
+ sdbusplus::xyz::openbmc_project::Network::IP::server::Create,
+ sdbusplus::xyz::openbmc_project::Network::Neighbor::server::CreateStatic,
+- 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;
+
+@@ -31,10 +35,15 @@ 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 ObjectPath = sdbusplus::message::object_path;
+
++using DbusVariant =
++ sdbusplus::message::variant<std::string, std::vector<std::string>>;
++
+ namespace fs = std::experimental::filesystem;
+
+ class Manager; // forward declaration of network manager.
+@@ -199,6 +208,14 @@ class EthernetInterface : public Ifaces
+ */
+ void deleteAll();
+
++ /** @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 EthernetInterfaceIntf::linkUp;
+@@ -296,6 +313,26 @@ class EthernetInterface : public Ifaces
+ 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 043d7a2..75f4e5f 100644
+--- a/network_manager.cpp
++++ b/network_manager.cpp
+@@ -34,6 +34,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),
+@@ -41,6 +48,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 edb341f..5fb9fe8 100644
+--- a/network_manager.hpp
++++ b/network_manager.hpp
+@@ -137,6 +137,12 @@ class Manager : public details::VLANCreateIface
+ return (interfaces.find(intf) != interfaces.end());
+ }
+
++ /** supported privilege list **/
++ std::vector<std::string> supportedPrivList;
++
++ /** @brief initializes the supportedPrivilege List */
++ void initSupportedPrivilges();
++
+ protected:
+ /** @brief Persistent sdbusplus DBus bus connection. */
+ sdbusplus::bus::bus& bus;
+@@ -159,6 +165,9 @@ class Manager : public details::VLANCreateIface
+
+ /** @brief Network Configuration directory. */
+ fs::path confDir;
++
++ /** Get the user management service name dynamically **/
++ std::string getUserServiceName();
+ };
+
+ } // namespace network
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch
new file mode 100644
index 000000000..596dfce48
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch
@@ -0,0 +1,504 @@
+From 163c1756ee676859622614996be81393eb348220 Mon Sep 17 00:00:00 2001
+From: Johnathan Mantey <johnathanx.mantey@intel.com>
+Date: Thu, 30 Jan 2020 15:07:39 -0800
+Subject: [PATCH] Enhance DHCP beyond just OFF and IPv4/IPv6 enabled.
+
+DHCP is not a binary option. The network interface can have DHCP
+disabled, IPv4 only, IPv6 only, and IPv4/IPv6.
+
+Tested:
+Using dbus-send or busctl:
+Disabled DHCP, and confirmed only link local addresses were present.
+
+Assigned only static addresses. Both with/and without the gateway set
+to 0.0.0.0
+
+Deleted static IPv4 addresses.
+Reassigned static addresses.
+
+Enabled DHCP for ipv4 only, and witnessed a DHCP server assign a valid
+address.
+
+Assigned static IPv4 address.
+Assigned static IPv6 address.
+Confirmed both IPv4 and IPv6 static addresses are active.
+
+Enabled DHCP for ipv6 only, and confirmed the static v4 address
+remains. The ipv6 address is removed, waiting for a DHCP6 server.
+
+Enabled DHCP for both ipv4 and ipv6. IPv4 address was assigned. IPv6
+address is assumed to succeed, as systemd config file enables IPv6
+DHCP.
+
+Change-Id: I2e0ff80ac3a5e88bcff28adac419bf21e37be162
+Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
+---
+ Makefile.am | 1 +
+ configure.ac | 1 +
+ ethernet_interface.cpp | 146 ++++++++++++++++++++++---------
+ ethernet_interface.hpp | 31 ++++++-
+ test/test_ethernet_interface.cpp | 3 +-
+ test/test_vlan_interface.cpp | 3 +-
+ types.hpp | 3 +
+ util.cpp | 16 +++-
+ util.hpp | 7 +-
+ vlan_interface.cpp | 2 +-
+ vlan_interface.hpp | 4 +-
+ 11 files changed, 164 insertions(+), 53 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 3bb5e7b..0bbbc8f 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -97,6 +97,7 @@ phosphor_network_manager_CXXFLAGS = \
+ $(SDEVENTPLUS_CFLAGS) \
+ $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \
+ $(PHOSPHOR_LOGGING_CFLAGS) \
++ -DBOOST_ASIO_DISABLE_THREADS \
+ -flto
+
+ if FEATURE_NIC_ETHTOOL
+diff --git a/configure.ac b/configure.ac
+index 12d6caa..fed3e09 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -36,6 +36,7 @@ AC_PATH_PROG([SDBUSPLUSPLUS], [sdbus++])
+ PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging])
+ PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces])
+ PKG_CHECK_MODULES([LIBNL], [libnl-3.0 libnl-genl-3.0])
++AC_CHECK_HEADER(boost/algorithm/string/split.hpp, [], [AC_MSG_ERROR([Could not find boost/algorithm/string/split.hpp])])
+
+ # Checks for header files.
+ AC_CHECK_HEADER(systemd/sd-bus.h, ,\
+diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
+index fca86bd..3fb0f5e 100644
+--- a/ethernet_interface.cpp
++++ b/ethernet_interface.cpp
+@@ -3,7 +3,6 @@
+ #include "ethernet_interface.hpp"
+
+ #include "config_parser.hpp"
+-#include "ipaddress.hpp"
+ #include "neighbor.hpp"
+ #include "network_manager.hpp"
+ #include "vlan_interface.hpp"
+@@ -62,10 +61,12 @@ struct EthernetIntfSocket
+
+ int sock{-1};
+ };
++std::map<std::string, std::string> mapDHCPToSystemd = {
++ {"both", "true"}, {"v4", "ipv4"}, {"v6", "ipv6"}, {"none", "false"}};
+
+ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
+ const std::string& objPath,
+- bool dhcpEnabled, Manager& parent,
++ DHCPConf dhcpEnabled, Manager& parent,
+ bool emitSignal) :
+ Ifaces(bus, objPath.c_str(), true),
+ bus(bus), manager(parent), objPath(objPath)
+@@ -112,6 +113,65 @@ static IP::Protocol convertFamily(int family)
+ throw std::invalid_argument("Bad address family");
+ }
+
++void EthernetInterface::disableDHCP(IP::Protocol protocol)
++{
++ DHCPConf dhcpState = EthernetInterfaceIntf::dHCPEnabled();
++ if (dhcpState == EthernetInterface::DHCPConf::both)
++ {
++ if (protocol == IP::Protocol::IPv4)
++ {
++ dHCPEnabled(EthernetInterface::DHCPConf::v6);
++ }
++ else if (protocol == IP::Protocol::IPv6)
++ {
++ dHCPEnabled(EthernetInterface::DHCPConf::v4);
++ }
++ }
++ else if ((dhcpState == EthernetInterface::DHCPConf::v4) &&
++ (protocol == IP::Protocol::IPv4))
++ {
++ dHCPEnabled(EthernetInterface::DHCPConf::none);
++ }
++ else if ((dhcpState == EthernetInterface::DHCPConf::v6) &&
++ (protocol == IP::Protocol::IPv6))
++ {
++ dHCPEnabled(EthernetInterface::DHCPConf::none);
++ }
++}
++
++bool EthernetInterface::dhcpIsEnabled(IP::Protocol family, bool ignoreProtocol)
++{
++ return ((EthernetInterfaceIntf::dHCPEnabled() ==
++ EthernetInterface::DHCPConf::both) ||
++ ((EthernetInterfaceIntf::dHCPEnabled() ==
++ EthernetInterface::DHCPConf::v6) &&
++ ((family == IP::Protocol::IPv6) || ignoreProtocol)) ||
++ ((EthernetInterfaceIntf::dHCPEnabled() ==
++ EthernetInterface::DHCPConf::v4) &&
++ ((family == IP::Protocol::IPv4) || ignoreProtocol)));
++}
++
++bool EthernetInterface::dhcpToBeEnabled(IP::Protocol family,
++ std::string& nextDHCPState)
++{
++ return ((nextDHCPState == "true") ||
++ ((nextDHCPState == "ipv6") && (family == IP::Protocol::IPv6)) ||
++ ((nextDHCPState == "ipv4") && (family == IP::Protocol::IPv4)));
++}
++
++bool EthernetInterface::addressIsStatic(IP::AddressOrigin origin)
++{
++ return (
++#ifdef LINK_LOCAL_AUTOCONFIGURATION
++ (origin == IP::AddressOrigin::Static)
++#else
++ (origin == IP::AddressOrigin::Static ||
++ origin == IP::AddressOrigin::LinkLocal)
++#endif
++
++ );
++}
++
+ void EthernetInterface::createIPAddressObjects()
+ {
+ addrs.clear();
+@@ -122,7 +182,7 @@ void EthernetInterface::createIPAddressObjects()
+ {
+ IP::Protocol addressType = convertFamily(addr.addrType);
+ IP::AddressOrigin origin = IP::AddressOrigin::Static;
+- if (dHCPEnabled())
++ if (dhcpIsEnabled(addressType))
+ {
+ origin = IP::AddressOrigin::DHCP;
+ }
+@@ -183,11 +243,11 @@ ObjectPath EthernetInterface::iP(IP::Protocol protType, std::string ipaddress,
+ uint8_t prefixLength, std::string gateway)
+ {
+
+- if (dHCPEnabled())
++ if (dhcpIsEnabled(protType))
+ {
+ log<level::INFO>("DHCP enabled on the interface"),
+ entry("INTERFACE=%s", interfaceName().c_str());
+- dHCPEnabled(false);
++ disableDHCP(protType);
+ }
+
+ IP::AddressOrigin origin = IP::AddressOrigin::Static;
+@@ -460,7 +520,7 @@ bool EthernetInterface::iPv6AcceptRA(bool value)
+ return value;
+ }
+
+-bool EthernetInterface::dHCPEnabled(bool value)
++EthernetInterface::DHCPConf EthernetInterface::dHCPEnabled(DHCPConf value)
+ {
+ if (value == EthernetInterfaceIntf::dHCPEnabled())
+ {
+@@ -552,7 +612,7 @@ void EthernetInterface::loadVLAN(VlanId id)
+ std::string path = objPath;
+ path += "_" + std::to_string(id);
+
+- auto dhcpEnabled =
++ DHCPConf dhcpEnabled =
+ getDHCPValue(manager.getConfDir().string(), vlanInterfaceName);
+
+ auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
+@@ -574,7 +634,8 @@ ObjectPath EthernetInterface::createVLAN(VlanId id)
+ path += "_" + std::to_string(id);
+
+ auto vlanIntf = std::make_unique<phosphor::network::VlanInterface>(
+- bus, path.c_str(), false, id, *this, manager);
++ bus, path.c_str(), EthernetInterface::DHCPConf::none, id, *this,
++ manager);
+
+ // write the device file for the vlan interface.
+ vlanIntf->writeDeviceFile();
+@@ -647,8 +708,6 @@ void EthernetInterface::writeConfigurationFile()
+ // write all the static ip address in the systemd-network conf file
+
+ using namespace std::string_literals;
+- using AddressOrigin =
+- sdbusplus::xyz::openbmc_project::Network::server::IP::AddressOrigin;
+ namespace fs = std::experimental::filesystem;
+
+ // if there is vlan interafce then write the configuration file
+@@ -717,42 +776,45 @@ void EthernetInterface::writeConfigurationFile()
+ }
+
+ // Add the DHCP entry
+- auto value = dHCPEnabled() ? "true"s : "false"s;
+- stream << "DHCP="s + value + "\n";
+-
+- // When the interface configured as dhcp, we don't need below given entries
+- // in config file.
+- if (dHCPEnabled() == false)
++ std::string value = convertForMessage(EthernetInterfaceIntf::dHCPEnabled());
++ std::string::size_type loc = value.rfind(".");
++ std::string requestedDHCPState = value.substr(loc + 1);
++ std::string mappedDHCPState = mapDHCPToSystemd[requestedDHCPState];
++ stream << "DHCP="s + mappedDHCPState + "\n";
++
++ bool dhcpv6Requested = dhcpToBeEnabled(IP::Protocol::IPv6, mappedDHCPState);
++ bool dhcpv4Requested = dhcpToBeEnabled(IP::Protocol::IPv4, mappedDHCPState);
++ // Static IP addresses
++ for (const auto& addr : addrs)
+ {
+- // Static
+- for (const auto& addr : addrs)
++ bool isValidIPv4 = isValidIP(AF_INET, addr.second->address());
++ bool isValidIPv6 = isValidIP(AF_INET6, addr.second->address());
++ if (((!dhcpv4Requested && isValidIPv4) ||
++ (!dhcpv6Requested && isValidIPv6)) &&
++ addressIsStatic(addr.second->origin()))
+ {
+- if (addr.second->origin() == AddressOrigin::Static
+-#ifndef LINK_LOCAL_AUTOCONFIGURATION
+- || addr.second->origin() == AddressOrigin::LinkLocal
+-#endif
+- )
+- {
+- std::string address =
+- addr.second->address() + "/" +
+- std::to_string(addr.second->prefixLength());
+-
+- stream << "Address=" << address << "\n";
+- }
++ // Process all static addresses
++ std::string address = addr.second->address() + "/" +
++ std::to_string(addr.second->prefixLength());
++
++ // build the address entries. Do not use [Network] shortcuts to
++ // insert address entries.
++ stream << "[Address]\n";
++ stream << "Address=" << address << "\n";
+ }
++ }
+
+- if (manager.getSystemConf())
++ if (manager.getSystemConf())
++ {
++ const auto& gateway = manager.getSystemConf()->defaultGateway();
++ if (!gateway.empty())
+ {
+- const auto& gateway = manager.getSystemConf()->defaultGateway();
+- if (!gateway.empty())
+- {
+- stream << "Gateway=" << gateway << "\n";
+- }
+- const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
+- if (!gateway6.empty())
+- {
+- stream << "Gateway=" << gateway6 << "\n";
+- }
++ stream << "Gateway=" << gateway << "\n";
++ }
++ const auto& gateway6 = manager.getSystemConf()->defaultGateway6();
++ if (!gateway6.empty())
++ {
++ stream << "Gateway=" << gateway6 << "\n";
+ }
+ }
+
+@@ -863,7 +925,7 @@ std::string EthernetInterface::mACAddress(std::string value)
+
+ void EthernetInterface::deleteAll()
+ {
+- if (EthernetInterfaceIntf::dHCPEnabled())
++ if (dhcpIsEnabled(IP::Protocol::IPv4, true))
+ {
+ log<level::INFO>("DHCP enabled on the interface"),
+ entry("INTERFACE=%s", interfaceName().c_str());
+diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp
+index 058d328..4e36ae8 100644
+--- a/ethernet_interface.hpp
++++ b/ethernet_interface.hpp
+@@ -92,7 +92,7 @@ class EthernetInterface : public Ifaces
+ * send.
+ */
+ EthernetInterface(sdbusplus::bus::bus& bus, const std::string& objPath,
+- bool dhcpEnabled, Manager& parent,
++ DHCPConf dhcpEnabled, Manager& parent,
+ bool emitSignal = true);
+
+ /** @brief Function to create ipaddress dbus object.
+@@ -158,7 +158,34 @@ class EthernetInterface : public Ifaces
+ }
+
+ /** Set value of DHCPEnabled */
+- bool dHCPEnabled(bool value) override;
++ DHCPConf dHCPEnabled(DHCPConf value) override;
++
++ /** @brief Determines if DHCP is active for the IP::Protocol supplied.
++ * @param[in] protocol - Either IPv4 or IPv6
++ * @param[in] ignoreProtocol - Allows IPv4 and IPv6 to be checked using a
++ * single call.
++ * @returns true/false value if DHCP is active for the input protocol
++ */
++ bool dhcpIsEnabled(IP::Protocol protocol, bool ignoreProtocol = false);
++
++ /** @brief Determines if DHCP will be active following next reconfig
++ * @param[in] protocol - Either IPv4 or IPv6
++ * @param[in] nextDHCPState - The new DHCP mode to take affect
++ * @returns true/false value if DHCP is active for the input protocol
++ */
++ bool dhcpToBeEnabled(IP::Protocol family, std::string& nextDHCPState);
++
++ /** @brief Determines if the address is manually assigned
++ * @param[in] origin - The origin entry of the IP::Address
++ * @returns true/false value if the address is static
++ */
++ bool addressIsStatic(IP::AddressOrigin origin);
++
++ /** @brief Selectively disables DHCP
++ * @param[in] protocol - The IPv4 or IPv6 protocol to return to static
++ * addressing mode
++ */
++ void disableDHCP(IP::Protocol protocol);
+
+ /** Retrieve Link State */
+ bool linkUp() const override;
+diff --git a/test/test_ethernet_interface.cpp b/test/test_ethernet_interface.cpp
+index 30dee8a..87fd68d 100644
+--- a/test/test_ethernet_interface.cpp
++++ b/test/test_ethernet_interface.cpp
+@@ -58,7 +58,8 @@ class TestEthernetInterface : public testing::Test
+ {
+ mock_clear();
+ mock_addIF("test0", 1, mac);
+- return {bus, "/xyz/openbmc_test/network/test0", false, manager};
++ return {bus, "/xyz/openbmc_test/network/test0",
++ EthernetInterface::DHCPConf::none, manager};
+ }
+
+ int countIPObjects()
+diff --git a/test/test_vlan_interface.cpp b/test/test_vlan_interface.cpp
+index 1dffc7e..e49b43f 100644
+--- a/test/test_vlan_interface.cpp
++++ b/test/test_vlan_interface.cpp
+@@ -50,7 +50,8 @@ class TestVlanInterface : public testing::Test
+ {
+ mock_clear();
+ mock_addIF("test0", 1);
+- return {bus, "/xyz/openbmc_test/network/test0", false, manager};
++ return {bus, "/xyz/openbmc_test/network/test0",
++ EthernetInterface::DHCPConf::none, manager};
+ }
+
+ void setConfDir()
+diff --git a/types.hpp b/types.hpp
+index 123067a..c4409fe 100644
+--- a/types.hpp
++++ b/types.hpp
+@@ -1,5 +1,7 @@
+ #pragma once
+
++#include "ipaddress.hpp"
++
+ #include <ifaddrs.h>
+ #include <netinet/in.h>
+ #include <systemd/sd-event.h>
+@@ -50,6 +52,7 @@ struct AddrInfo
+ {
+ uint8_t addrType;
+ std::string ipaddress;
++ IP::AddressOrigin origin;
+ uint16_t prefix;
+ };
+
+diff --git a/util.cpp b/util.cpp
+index 13a607f..554d7f6 100644
+--- a/util.cpp
++++ b/util.cpp
+@@ -410,9 +410,11 @@ std::optional<std::string> interfaceToUbootEthAddr(const char* intf)
+ return "eth" + std::to_string(idx) + "addr";
+ }
+
+-bool getDHCPValue(const std::string& confDir, const std::string& intf)
++EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir,
++ const std::string& intf)
+ {
+- bool dhcp = false;
++ EthernetInterfaceIntf::DHCPConf dhcp =
++ EthernetInterfaceIntf::DHCPConf::none;
+ // Get the interface mode value from systemd conf
+ // using namespace std::string_literals;
+ fs::path confPath = confDir;
+@@ -434,7 +436,15 @@ bool getDHCPValue(const std::string& confDir, const std::string& intf)
+ // There will be only single value for DHCP key.
+ if (values[0] == "true")
+ {
+- dhcp = true;
++ dhcp = EthernetInterfaceIntf::DHCPConf::both;
++ }
++ else if (values[0] == "ipv4")
++ {
++ dhcp = EthernetInterfaceIntf::DHCPConf::v4;
++ }
++ else if (values[0] == "ipv6")
++ {
++ dhcp = EthernetInterfaceIntf::DHCPConf::v6;
+ }
+ return dhcp;
+ }
+diff --git a/util.hpp b/util.hpp
+index 251aa0d..ee11f4e 100644
+--- a/util.hpp
++++ b/util.hpp
+@@ -13,12 +13,16 @@
+ #include <sdbusplus/bus.hpp>
+ #include <string>
+ #include <string_view>
++#include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
+
+ namespace phosphor
+ {
+ namespace network
+ {
+
++using EthernetInterfaceIntf =
++ sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
++
+ constexpr auto IPV4_MIN_PREFIX_LENGTH = 1;
+ constexpr auto IPV4_MAX_PREFIX_LENGTH = 32;
+ constexpr auto IPV6_MAX_PREFIX_LENGTH = 64;
+@@ -156,7 +160,8 @@ std::optional<std::string> interfaceToUbootEthAddr(const char* intf);
+ * @param[in] confDir - Network configuration directory.
+ * @param[in] intf - Interface name.
+ */
+-bool getDHCPValue(const std::string& confDir, const std::string& intf);
++EthernetInterfaceIntf::DHCPConf getDHCPValue(const std::string& confDir,
++ const std::string& intf);
+
+ namespace internal
+ {
+diff --git a/vlan_interface.cpp b/vlan_interface.cpp
+index 73de4e8..26282cb 100644
+--- a/vlan_interface.cpp
++++ b/vlan_interface.cpp
+@@ -22,7 +22,7 @@ using namespace phosphor::logging;
+ using namespace sdbusplus::xyz::openbmc_project::Common::Error;
+
+ VlanInterface::VlanInterface(sdbusplus::bus::bus& bus,
+- const std::string& objPath, bool dhcpEnabled,
++ const std::string& objPath, DHCPConf dhcpEnabled,
+ uint32_t vlanID, EthernetInterface& intf,
+ Manager& parent) :
+ VlanIface(bus, objPath.c_str()),
+diff --git a/vlan_interface.hpp b/vlan_interface.hpp
+index a994d05..37ae7ee 100644
+--- a/vlan_interface.hpp
++++ b/vlan_interface.hpp
+@@ -45,8 +45,8 @@ class VlanInterface : public VlanIface,
+ * @param[in] manager - network manager object.
+ */
+ VlanInterface(sdbusplus::bus::bus& bus, const std::string& objPath,
+- bool dhcpEnabled, uint32_t vlanID, EthernetInterface& intf,
+- Manager& manager);
++ DHCPConf dhcpEnabled, uint32_t vlanID,
++ EthernetInterface& intf, Manager& manager);
+
+ /** @brief Delete this d-bus object.
+ */
+--
+2.25.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0011-Added-enable-disable-control-of-the-Network-Interfac.patch b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0011-Added-enable-disable-control-of-the-Network-Interfac.patch
new file mode 100644
index 000000000..58dcf3f21
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network/0011-Added-enable-disable-control-of-the-Network-Interfac.patch
@@ -0,0 +1,189 @@
+From 4bfb4ad5ff795d78e06fbeaf1664df6819880f50 Mon Sep 17 00:00:00 2001
+From: Johnathan Mantey <johnathanx.mantey@intel.com>
+Date: Tue, 29 Oct 2019 16:20:28 -0700
+Subject: [PATCH] Added enable/disable control of the Network Interface Card
+
+Implemented enable/disable function to perform
+"ip link set eth(x) up"
+"ip link set eth(x) down"
+functionality from DBus.
+
+Tested:
+
+Confirmed Redfish PATCH commands on the InterfaceEnabled property
+changes the NIC state. Confirmed the NIC is DOWN/UP using "ip link".
+Confirmed "ip link" state changes can be obsserved from dbus-send
+commands, and from Redfish GET actions.
+
+Confirmed the link is inactive after a reboot.
+
+Confirmed link stays down despite assigning an IP manually.
+
+Confirmed link stays down despite enabling DHCP.
+
+Change-Id: I4152b53055e6546f7a6ca81b5a5eef6f689bcc66
+Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
+---
+ ethernet_interface.cpp | 73 ++++++++++++++++++++++++++++++++++++++++--
+ ethernet_interface.hpp | 11 ++++++-
+ 2 files changed, 81 insertions(+), 3 deletions(-)
+
+diff --git a/ethernet_interface.cpp b/ethernet_interface.cpp
+index 8b8f698..a2754a4 100644
+--- a/ethernet_interface.cpp
++++ b/ethernet_interface.cpp
+@@ -85,6 +85,7 @@ EthernetInterface::EthernetInterface(sdbusplus::bus::bus& bus,
+ EthernetInterfaceIntf::autoNeg(std::get<2>(ifInfo));
+ EthernetInterfaceIntf::speed(std::get<0>(ifInfo));
+ EthernetInterfaceIntf::linkUp(std::get<3>(ifInfo));
++ EthernetInterfaceIntf::nICEnabled(std::get<4>(ifInfo));
+ #endif
+ getChannelPrivilege(intfName);
+
+@@ -323,11 +324,12 @@ InterfaceInfo EthernetInterface::getInterfaceInfo() const
+ Autoneg autoneg{0};
+ DuplexMode duplex{0};
+ LinkUp linkState{false};
++ NICEnabled nicEnabled{false};
+ EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ if (eifSocket.sock < 0)
+ {
+- return std::make_tuple(speed, duplex, autoneg, linkState);
++ return std::make_tuple(speed, duplex, autoneg, linkState, nicEnabled);
+ }
+
+ std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
+@@ -341,9 +343,10 @@ InterfaceInfo EthernetInterface::getInterfaceInfo() const
+ autoneg = edata.autoneg;
+ }
+
++ nicEnabled = nICEnabled();
+ linkState = linkUp();
+
+- return std::make_tuple(speed, duplex, autoneg, linkState);
++ return std::make_tuple(speed, duplex, autoneg, linkState, nicEnabled);
+ }
+ #endif
+
+@@ -548,6 +551,67 @@ bool EthernetInterface::linkUp() const
+ log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
+ entry("ERROR=%s", strerror(errno)));
+ }
++ return value;
++}
++
++bool EthernetInterface::nICEnabled() const
++{
++ EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
++ bool value = EthernetInterfaceIntf::nICEnabled();
++
++ if (eifSocket.sock < 0)
++ {
++ return value;
++ }
++
++ ifreq ifr{0};
++ std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
++ if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) == 0)
++ {
++ value = static_cast<bool>(ifr.ifr_flags & IFF_UP);
++ }
++ else
++ {
++ log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
++ entry("ERROR=%s", strerror(errno)));
++ }
++ return value;
++}
++
++bool EthernetInterface::nICEnabled(bool value)
++{
++ if (value == EthernetInterfaceIntf::nICEnabled())
++ {
++ return value;
++ }
++
++ EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
++ if (eifSocket.sock < 0)
++ {
++ return EthernetInterfaceIntf::nICEnabled();
++ }
++
++ ifreq ifr{0};
++ std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
++ if (ioctl(eifSocket.sock, SIOCGIFFLAGS, &ifr) != 0)
++ {
++ log<level::ERR>("ioctl failed for SIOCGIFFLAGS:",
++ entry("ERROR=%s", strerror(errno)));
++ return EthernetInterfaceIntf::nICEnabled();
++ }
++
++ ifr.ifr_flags &= ~IFF_UP;
++ ifr.ifr_flags |= value ? IFF_UP : 0;
++
++ if (ioctl(eifSocket.sock, SIOCSIFFLAGS, &ifr) != 0)
++ {
++ log<level::ERR>("ioctl failed for SIOCSIFFLAGS:",
++ entry("ERROR=%s", strerror(errno)));
++ return EthernetInterfaceIntf::nICEnabled();
++ }
++ EthernetInterfaceIntf::nICEnabled(value);
++ writeConfigurationFile();
++ manager.restartSystemdUnit(networkdService);
+
+ return value;
+ }
+@@ -742,6 +806,11 @@ void EthernetInterface::writeConfigurationFile()
+ stream << "MACAddress=" << mac << "\n";
+ }
+
++ if (!nICEnabled())
++ {
++ stream << "Unmanaged=yes\n";
++ }
++
+ // write the network section
+ stream << "[Network]\n";
+ #ifdef LINK_LOCAL_AUTOCONFIGURATION
+diff --git a/ethernet_interface.hpp b/ethernet_interface.hpp
+index 4e36ae8..104750e 100644
+--- a/ethernet_interface.hpp
++++ b/ethernet_interface.hpp
+@@ -60,9 +60,11 @@ using LinkSpeed = uint16_t;
+ using DuplexMode = uint8_t;
+ using Autoneg = uint8_t;
+ using LinkUp = bool;
++using NICEnabled = bool;
+ using VlanId = uint32_t;
+ using InterfaceName = std::string;
+-using InterfaceInfo = std::tuple<LinkSpeed, DuplexMode, Autoneg, LinkUp>;
++using InterfaceInfo =
++ std::tuple<LinkSpeed, DuplexMode, Autoneg, LinkUp, NICEnabled>;
+ using AddressMap = std::map<std::string, std::shared_ptr<IPAddress>>;
+ using NeighborMap = std::map<std::string, std::shared_ptr<Neighbor>>;
+ using VlanInterfaceMap =
+@@ -190,6 +192,12 @@ class EthernetInterface : public Ifaces
+ /** Retrieve Link State */
+ bool linkUp() const override;
+
++ /** Retrieve NIC State */
++ bool nICEnabled() const override;
++
++ /** Set value of NICEnabled */
++ bool nICEnabled(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.
+@@ -246,6 +254,7 @@ class EthernetInterface : public Ifaces
+ using EthernetInterfaceIntf::dHCPEnabled;
+ using EthernetInterfaceIntf::interfaceName;
+ using EthernetInterfaceIntf::linkUp;
++ using EthernetInterfaceIntf::nICEnabled;
+ using MacAddressIntf::mACAddress;
+
+ /** @brief Absolute path of the resolv conf file */
+--
+2.24.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend
new file mode 100644
index 000000000..fe7f050c0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/phosphor-network_%.bbappend
@@ -0,0 +1,13 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+DEPENDS += "nlohmann-json boost"
+
+#todo: Appu, fix nobranch
+SRC_URI = "git://github.com/openbmc/phosphor-networkd;nobranch=1"
+SRC_URI += "file://0003-Adding-channel-specific-privilege-to-network.patch \
+ file://0009-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-enabled.patch \
+ file://0011-Added-enable-disable-control-of-the-Network-Interfac.patch \
+ "
+SRCREV = "ad4bf5ce1292c74ac2ecea413ff27c14cf5748fe"
+
+EXTRA_OECONF_append = " --enable-nic-ethtool=yes"
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb
new file mode 100644
index 000000000..0dab0fc1a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr.bb
@@ -0,0 +1,24 @@
+SUMMARY = "Enforce static MAC addresses"
+DESCRIPTION = "Set a priority on MAC addresses to run with: \
+ factory-specified > u-boot-specified > random"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+PV = "1.0"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SRC_URI = "\
+ file://mac-check \
+ file://${PN}.service \
+ "
+
+inherit obmc-phosphor-systemd
+
+SYSTEMD_SERVICE_${PN} += "${PN}.service"
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 ${WORKDIR}/mac-check ${D}${bindir}
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check
new file mode 100644
index 000000000..639b6c5ee
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/mac-check
@@ -0,0 +1,79 @@
+#!/bin/sh
+# 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.
+
+read_hw_mac() {
+ local iface="$1"
+ cat /sys/class/net/"$iface"/address
+}
+
+set_hw_mac() {
+ local iface="$1"
+ local mac="$2"
+ ip link show dev "$iface" | grep -q "${iface}:.*\<UP\>" 2>/dev/null
+ local up=$?
+ [[ $up -eq 0 ]] && ip link set dev "$iface" down
+ ip link set dev "$iface" address "$mac"
+ [[ $up -eq 0 ]] && ip link set dev "$iface" up
+}
+
+SOFS_MNT=/var/sofs
+read_sofs_mac() {
+ local iface="$1"
+ cat "${SOFS_MNT}/factory-settings/network/mac/${iface}" 2>/dev/null
+}
+
+read_fw_env_mac() {
+ local envname="$1"
+ fw_printenv "$envname" 2>/dev/null | sed "s/^$envname=//"
+}
+
+set_fw_env_mac() {
+ local envname="$1"
+ local mac="$2"
+ fw_setenv "$envname" "$mac"
+}
+
+mac_check() {
+ local iface="$1"
+ local envname="$2"
+
+ # read current HW MAC addr
+ local hw_mac=$(read_hw_mac "$iface")
+
+ # read saved sofs MAC addr
+ local sofs_mac=$(read_sofs_mac "$iface")
+
+ # if set and not the same as HW addr, set HW addr
+ if [ -n "$sofs_mac" ] && [ "$hw_mac" != "$sofs_mac" ]; then
+ set_hw_mac "$iface" "$sofs_mac"
+ hw_mac="$sofs_mac"
+ fi
+
+ # read saved fw_env MAC addr
+ local fw_env_mac=$(read_fw_env_mac "$envname")
+
+ # save to fw_env if not the same as HW addr
+ if [ -z "$fw_env_mac" ] || [ "$fw_env_mac" != "$hw_mac" ]; then
+ set_fw_env_mac "$envname" "$hw_mac"
+ fi
+}
+
+mkdir -p ${SOFS_MNT}/factory-settings/network/mac
+while read IFACE UBDEV; do
+ mac_check "$IFACE" "$UBDEV"
+done <<-END_CONF
+ eth0 eth1addr
+ eth1 ethaddr
+END_CONF
diff --git a/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service
new file mode 100644
index 000000000..86371db11
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-network/network/static-mac-addr/static-mac-addr.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Enforce Static MAC addr mapping
+
+[Service]
+Type=oneshot
+Restart=no
+ExecStart=/usr/bin/mac-check
+
+[Install]
+WantedBy=network.target
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb
new file mode 100644
index 000000000..1bf81d953
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/beepcode-mgr.bb
@@ -0,0 +1,25 @@
+
+SUMMARY = "Beep code manager service"
+DESCRIPTION = "The beep code manager service will provide a method for beep code"
+
+SRC_URI = "\
+ file://CMakeLists.txt \
+ file://beepcode_mgr.cpp \
+ "
+PV = "0.1"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+S = "${WORKDIR}"
+
+SYSTEMD_SERVICE_${PN} = "beepcode-mgr.service"
+
+inherit cmake
+inherit obmc-phosphor-systemd
+
+DEPENDS += " \
+ sdbusplus \
+ phosphor-logging \
+ boost \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.clang-format
new file mode 100644
index 000000000..dd2770837
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/.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/beepcode-mgr/files/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt
new file mode 100644
index 000000000..472257279
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required (VERSION 3.5 FATAL_ERROR)
+project (beepcode-mgr 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 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})
+
+add_executable (beepcode-mgr beepcode_mgr.cpp)
+
+target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})
+target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES}
+ phosphor_logging)
+
+install (TARGETS beepcode-mgr DESTINATION bin)
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service
new file mode 100644
index 000000000..8099e2541
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode-mgr.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Beep code manager
+
+[Service]
+Restart=always
+RestartSec=2
+ExecStart=/usr/bin/beepcode-mgr
+StartLimitInterval=0
+Type=simple
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp
new file mode 100644
index 000000000..2940610da
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/beepcode_mgr.cpp
@@ -0,0 +1,325 @@
+/* Copyright 2019 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 <linux/input.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <chrono>
+#include <iostream>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+static constexpr uint32_t defaultBeepFrequence = 2000;
+static constexpr uint32_t defaultBeepDurationMs = 300;
+// Duration between two beeps
+static constexpr uint32_t defaultInterBeepDurationMs = 300;
+// Duration between two 4-bit digitals
+static constexpr uint32_t defaultInterDigitBeepDurationMs = 800;
+// Duration between two patterns
+static constexpr uint32_t defaultPostBeepDurationMs = 1000;
+
+static constexpr uint8_t offBeepState = 0;
+static constexpr uint8_t onBeepState = 1;
+// finish 1 bit beep
+static constexpr uint8_t interBeepState = 2;
+// finish 4 bits beep
+static constexpr uint8_t interDigitBeepState = 3;
+// finish all bits beep
+static constexpr uint8_t postBeepState = 4;
+
+static const std::vector<uint32_t> beepDelayTable = {
+ 0, defaultBeepDurationMs, defaultInterBeepDurationMs,
+ defaultInterDigitBeepDurationMs, defaultPostBeepDurationMs};
+
+static constexpr uint32_t bpBitCount = 4;
+static constexpr uint32_t bpShiftCount = 32;
+static constexpr uint32_t bpMask = 0xf0000000;
+
+// beep code priority
+static constexpr uint8_t beepOff = 0;
+static constexpr uint8_t beepVRWatchdogTimeout = 1;
+static constexpr uint8_t beepPSUFailure = 2;
+static constexpr uint8_t beepCPUMIssing = 3;
+static constexpr uint8_t beepCPUCatError = 4;
+static constexpr uint8_t beepCPUErr2 = 5;
+static constexpr uint8_t beepVoltageMismatch = 6;
+static constexpr uint8_t beepCPUConfigError = 7;
+static constexpr uint8_t beepPowerFail = 8;
+static constexpr uint8_t beepPowerGoodTimeOut = 9;
+static constexpr uint8_t beepMax = 10;
+
+// priority, abbrev name map
+static const std::map<uint8_t, std::string> beepCodeNameList = {
+ {beepVRWatchdogTimeout, "VRWatchdogTimeout"},
+ {beepPSUFailure, "PSUFailure"},
+ {beepCPUMIssing, "CPUMissing"},
+ {beepCPUCatError, "CPUCatError"},
+ {beepCPUErr2, "CPUErr2"},
+ {beepVoltageMismatch, "VoltageMismatch"},
+ {beepCPUConfigError, "CPUConfigError"},
+ {beepPowerFail, "PowerFail"},
+ {beepPowerGoodTimeOut, "PowerGoodTimeOut"},
+};
+
+// priority, code pattern map
+static const std::map<uint8_t, std::string> beepCodePatternList = {
+ {beepVRWatchdogTimeout, "1-5-1-2"}, {beepPSUFailure, "1-5-1-4"},
+ {beepCPUMIssing, "1-5-2-1"}, {beepCPUCatError, "1-5-2-2"},
+ {beepCPUErr2, "1-5-2-3"}, {beepVoltageMismatch, "1-5-2-4"},
+ {beepCPUConfigError, "1-5-2-5"}, {beepPowerFail, "1-5-4-2"},
+ {beepPowerGoodTimeOut, "1-5-4-4"},
+};
+
+static const std::vector<uint32_t> beepCodeTable = {
+ 0, 0x1512, 0x1514, 0x1521, 0x1522, 0x1523, 0x1524, 0x1525, 0x1542, 0x1544};
+
+static constexpr char bpDevName[] = "/dev/input/event0";
+static constexpr char bpBusName[] = "xyz.openbmc_project.BeepCode";
+static constexpr char bpObjName[] = "/xyz/openbmc_project/BeepCode";
+static constexpr char bpIntfName[] = "xyz.openbmc_project.BeepCode";
+static constexpr char bpMethodName[] = "Beep";
+
+static std::shared_ptr<sdbusplus::asio::dbus_interface> bpIface;
+static boost::asio::io_service io;
+static auto conn = std::make_shared<sdbusplus::asio::connection>(io);
+
+class Beeper
+{
+ public:
+ Beeper(boost::asio::io_service& io)
+ {
+ timer = std::make_unique<boost::asio::steady_timer>(io);
+ fdBeepDev = -1;
+ currentCount = 0;
+ currentBeepCode = 0;
+ currentMask = bpMask;
+ currentShift = bpShiftCount;
+ currentState = offBeepState;
+ timerRunning = false;
+ }
+
+ ~Beeper()
+ {
+ }
+
+ void beep(const uint8_t& beepPriority)
+ {
+ if (timerRunning)
+ {
+ pendingList.push_back(beepPriority);
+ pendingList.sort(std::greater<uint8_t>());
+ return;
+ }
+
+ performBeep(beepPriority);
+ }
+
+ private:
+ void performBeep(const uint8_t& beepPriority)
+ {
+ currentBeepCode = beepCodeTable[beepPriority];
+ currentCount = 0;
+ currentMask = bpMask;
+ currentShift = bpShiftCount;
+ getCurrentCount();
+ startBeep(defaultBeepFrequence);
+ currentState = onBeepState;
+ currentCount--;
+ timerRunning = true;
+ startBeepTimer();
+ }
+
+ void startBeepTimer()
+ {
+ timer->expires_after(
+ std::chrono::milliseconds(beepDelayTable[currentState]));
+ timer->async_wait([this](const boost::system::error_code& ec) {
+ // timer timeout
+ switch (currentState)
+ {
+ case onBeepState:
+ stopBeep();
+ if (currentCount == 0)
+ {
+ // finished the current 4-bit
+ if (currentBeepCode == 0)
+ {
+ // finished all bits
+ currentState = postBeepState;
+ }
+ else
+ {
+ // start next 4-bit
+ currentState = interDigitBeepState;
+ getCurrentCount();
+ currentCount--;
+ }
+ }
+ else
+ {
+ // still in 4-bit processing
+ currentCount--;
+ currentState = interBeepState;
+ }
+ startBeepTimer();
+ break;
+
+ case interBeepState:
+ case interDigitBeepState:
+ startBeep(defaultBeepFrequence);
+ currentState = onBeepState;
+ startBeepTimer();
+ break;
+ case postBeepState:
+ if (pendingList.size() != 0)
+ {
+ // continue the next new beepcode
+ uint8_t beepPriority = pendingList.front();
+ pendingList.pop_front();
+ performBeep(beepPriority);
+ }
+ else
+ {
+ timerRunning = false;
+ }
+ break;
+
+ default:
+ std::cerr << "Incorrect beepState: "
+ << static_cast<unsigned int>(currentState)
+ << std::endl;
+ break;
+ }
+ });
+ }
+
+ void startBeep(uint32_t freq)
+ {
+ if (fdBeepDev != -1)
+ {
+ std::cerr << "beep device is opening already!" << std::endl;
+ ::close(fdBeepDev);
+ fdBeepDev = -1;
+ }
+
+ if ((fdBeepDev = ::open(bpDevName, O_RDWR | O_CLOEXEC)) < 0)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to open input device");
+ return;
+ }
+
+ struct input_event event;
+ event.type = EV_SND;
+ event.code = SND_TONE;
+ event.value = freq;
+
+ if (::write(fdBeepDev, &event, sizeof(struct input_event)) !=
+ sizeof(struct input_event))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Failed to write a tone sound event");
+ ::close(fdBeepDev);
+ fdBeepDev = -1;
+ return;
+ }
+ return;
+ }
+
+ void stopBeep()
+ {
+ if (fdBeepDev == -1)
+ {
+ std::cerr << "beep device is closed!" << std::endl;
+ return;
+ }
+
+ ::close(fdBeepDev);
+ fdBeepDev = -1;
+ }
+
+ // Split the beep code based on bpBitCount, for example 0x1544,
+ // currentCount=1, 5, 4, 4
+ void getCurrentCount()
+ {
+ while (currentCount == 0)
+ {
+ currentCount = currentMask & currentBeepCode;
+ currentShift -= bpBitCount;
+ currentCount >>= currentShift;
+ currentBeepCode = currentBeepCode & ~currentMask;
+ currentMask >>= bpBitCount;
+ if (currentMask == 0)
+ {
+ break;
+ }
+ }
+ }
+
+ int fdBeepDev;
+ bool timerRunning;
+ uint32_t currentCount;
+ uint32_t currentBeepCode;
+ uint32_t currentMask;
+ uint32_t currentShift;
+ uint8_t currentState;
+ std::unique_ptr<boost::asio::steady_timer> timer;
+ std::list<uint8_t> pendingList;
+};
+
+static Beeper beeper(io);
+
+// dbus method
+static void beep(const uint8_t& beepPriority)
+{
+ if ((beepPriority >= beepMax) || (beepPriority == beepOff))
+ {
+ std::cerr << "Incorrect input: "
+ << static_cast<unsigned int>(beepPriority) << std::endl;
+ return;
+ }
+
+ // Log into redfish event log
+ sd_journal_send("MESSAGE=BeepCode: Priority=%d", beepPriority,
+ "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
+ "OpenBMC.0.1.BeepCode", "REDFISH_MESSAGE_ARGS=%d",
+ beepPriority, NULL);
+
+ beeper.beep(beepPriority);
+
+ return;
+}
+
+int main(int argc, char** argv)
+{
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Starting BeepCode service");
+
+ conn->request_name(bpBusName);
+ sdbusplus::asio::object_server server =
+ sdbusplus::asio::object_server(conn);
+ bpIface = server.add_interface(bpObjName, bpIntfName);
+
+ bpIface->register_property("BeepCodeNameList", beepCodeNameList,
+ sdbusplus::asio::PropertyPermission::readOnly);
+ bpIface->register_property("BeepCodePatternList", beepCodePatternList,
+ sdbusplus::asio::PropertyPermission::readOnly);
+ bpIface->register_method(bpMethodName, beep);
+ bpIface->initialize();
+
+ io.run();
+ return 0;
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/cmake-format.json
new file mode 100644
index 000000000..583c255a3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/beepcode-mgr/files/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/configuration/entity-manager_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend
new file mode 100644
index 000000000..59330e8f3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/configuration/entity-manager_%.bbappend
@@ -0,0 +1,6 @@
+# this is here just to bump faster than upstream
+SRC_URI = "git://github.com/openbmc/entity-manager.git"
+SRCREV = "ff58eba9e7f06b60879db38e1be6b41c6b2b9092"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb
new file mode 100644
index 000000000..089aaf59f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync.bb
@@ -0,0 +1,26 @@
+
+SUMMARY = "PCH BMC time service"
+DESCRIPTION = "This service will read date/time from PCH device periodically, and set the BMC system time accordingly"
+
+SRC_URI = "\
+ file://CMakeLists.txt \
+ file://pch-time-sync.cpp \
+ "
+PV = "0.1"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+S = "${WORKDIR}"
+
+SYSTEMD_SERVICE_${PN} = "pch-time-sync.service"
+
+inherit cmake
+inherit obmc-phosphor-systemd
+
+DEPENDS += " \
+ sdbusplus \
+ phosphor-logging \
+ boost \
+ i2c-tools \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.clang-format
new file mode 100644
index 000000000..dd2770837
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/.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/datetime/pch-time-sync/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt
new file mode 100644
index 000000000..a4cf8155f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/CMakeLists.txt
@@ -0,0 +1,40 @@
+cmake_minimum_required (VERSION 3.5 FATAL_ERROR)
+project (pch-time-sync 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 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})
+
+add_executable (pch-time-sync pch-time-sync.cpp)
+
+target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})
+target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES}
+ phosphor_logging)
+target_link_libraries (${PROJECT_NAME} i2c)
+
+install (TARGETS pch-time-sync DESTINATION bin)
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/cmake-format.json
new file mode 100644
index 000000000..583c255a3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/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/datetime/pch-time-sync/pch-time-sync.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp
new file mode 100644
index 000000000..0c1014589
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.cpp
@@ -0,0 +1,265 @@
+/* Copyright 2019 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 <time.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <chrono>
+#include <iostream>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+extern "C" {
+#include <i2c/smbus.h>
+#include <linux/i2c-dev.h>
+}
+
+static constexpr uint32_t syncIntervalNormalMS = 60000;
+static constexpr uint32_t syncIntervalFastMS = (syncIntervalNormalMS / 2);
+
+static uint32_t syncIntervalMS = syncIntervalNormalMS;
+
+// will update bmc time if the time difference beyond this value
+static constexpr uint8_t timeDiffAllowedSecond = 1;
+
+static inline uint8_t bcd2Decimal(uint8_t hex)
+{
+ uint8_t dec = ((hex & 0xF0) >> 4) * 10 + (hex & 0x0F);
+ return dec;
+}
+
+class I2CFile
+{
+ private:
+ int fd = -1;
+
+ public:
+ I2CFile(const int& i2cBus, const int& slaveAddr, const int& flags)
+ {
+ std::string i2cDev = "/dev/i2c-" + std::to_string(i2cBus);
+
+ fd = open(i2cDev.c_str(), flags);
+ if (fd < 0)
+ {
+ throw std::runtime_error("Unable to open i2c device.");
+ }
+
+ if (ioctl(fd, I2C_SLAVE_FORCE, slaveAddr) < 0)
+ {
+ close(fd);
+ fd = -1;
+ throw std::runtime_error("Unable to set i2c slave address.");
+ }
+ }
+
+ uint8_t i2cReadByteData(const uint8_t& offset)
+ {
+ int ret = i2c_smbus_read_byte_data(fd, offset);
+
+ if (ret < 0)
+ {
+ throw std::runtime_error("i2c read failed");
+ }
+ return static_cast<uint8_t>(ret);
+ }
+
+ ~I2CFile()
+ {
+ if (!(fd < 0))
+ {
+ close(fd);
+ }
+ }
+};
+
+class PCHSync
+{
+ private:
+ bool getPCHDate(uint8_t& year, uint8_t& month, uint8_t& day, uint8_t& hour,
+ uint8_t& minute, uint8_t& second)
+ {
+ try
+ {
+ constexpr uint8_t pchDevI2CBusNumber = 0x03;
+ constexpr uint8_t pchDevI2CSlaveAddress = 0x44;
+ constexpr uint8_t pchDevRegRTCYear = 0x0f;
+ constexpr uint8_t pchDevRegRTCMonth = 0x0e;
+ constexpr uint8_t pchDevRegRTCDay = 0x0d;
+ constexpr uint8_t pchDevRegRTCHour = 0x0b;
+ constexpr uint8_t pchDevRegRTCMinute = 0x0a;
+ constexpr uint8_t pchDevRegRTCSecond = 0x09;
+ I2CFile pchDev(pchDevI2CBusNumber, pchDevI2CSlaveAddress,
+ O_RDWR | O_CLOEXEC);
+ year = pchDev.i2cReadByteData(pchDevRegRTCYear);
+ year = bcd2Decimal(year);
+ if (year > 99)
+ {
+ return false;
+ }
+
+ month = pchDev.i2cReadByteData(pchDevRegRTCMonth);
+ month = bcd2Decimal(month);
+ if ((month < 1) || (month > 12))
+ {
+ return false;
+ }
+
+ day = pchDev.i2cReadByteData(pchDevRegRTCDay);
+ day = bcd2Decimal(day);
+ if ((day < 1) || (day > 31))
+ {
+ return false;
+ }
+
+ hour = pchDev.i2cReadByteData(pchDevRegRTCHour);
+ hour = bcd2Decimal(hour);
+ if (hour >= 24)
+ {
+ return false;
+ }
+
+ minute = pchDev.i2cReadByteData(pchDevRegRTCMinute);
+ minute = bcd2Decimal(minute);
+ if (minute >= 60)
+ {
+ return false;
+ }
+
+ second = pchDev.i2cReadByteData(pchDevRegRTCSecond);
+ second = bcd2Decimal(second);
+ if (second >= 60)
+ {
+ return false;
+ }
+ }
+ catch (const std::exception& e)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ bool getSystemTime(time_t& timeSeconds)
+ {
+ struct timespec sTime = {0};
+ int ret = 0;
+
+ ret = clock_gettime(CLOCK_REALTIME, &sTime);
+
+ if (ret != 0)
+ {
+ return false;
+ }
+ timeSeconds = sTime.tv_sec;
+ return true;
+ }
+
+ bool setSystemTime(uint32_t timeSeconds)
+ {
+ struct timespec sTime = {0};
+ int ret = 0;
+
+ sTime.tv_sec = timeSeconds;
+ sTime.tv_nsec = 0;
+
+ ret = clock_settime(CLOCK_REALTIME, &sTime);
+
+ return (ret == 0);
+ }
+
+ bool updateBMCTime()
+ {
+ int ret = 0;
+ time_t BMCTimeSeconds = 0;
+ time_t PCHTimeSeconds = 0;
+ struct tm tm = {0};
+
+ // get PCH and system time
+ if (!getPCHDate(year, month, day, hour, minute, second))
+ {
+ return false;
+ };
+
+ if (!getSystemTime(BMCTimeSeconds))
+ {
+ return false;
+ }
+
+ std::string dateString =
+ "20" + std::to_string(year) + "-" + std::to_string(month) + "-" +
+ std::to_string(day) + " " + std::to_string(hour) + ":" +
+ std::to_string(minute) + ":" + std::to_string(second);
+
+ strptime(dateString.c_str(), "%Y-%m-%d %H:%M:%S", &tm);
+
+ PCHTimeSeconds = mktime(&tm);
+ if (PCHTimeSeconds == -1)
+ {
+ return false;
+ }
+
+ if (std::abs(PCHTimeSeconds - BMCTimeSeconds) > timeDiffAllowedSecond)
+ {
+ if (!setSystemTime(PCHTimeSeconds))
+ {
+ return false;
+ }
+ std::cout << "Update BMC time to " << dateString << std::endl;
+ }
+
+ return true;
+ }
+
+ void startSyncTimer()
+ {
+ if (updateBMCTime())
+ {
+ syncIntervalMS = syncIntervalNormalMS;
+ }
+ else
+ {
+ std::cout << "Update BMC time Fail" << std::endl;
+ syncIntervalMS = syncIntervalFastMS;
+ }
+
+ syncTimer->expires_after(std::chrono::milliseconds(syncIntervalMS));
+ syncTimer->async_wait(
+ [this](const boost::system::error_code& ec) { startSyncTimer(); });
+ }
+
+ std::unique_ptr<boost::asio::steady_timer> syncTimer;
+ uint8_t year, month, day, hour, minute, second;
+
+ public:
+ PCHSync(boost::asio::io_service& io)
+ {
+ syncTimer = std::make_unique<boost::asio::steady_timer>(io);
+ startSyncTimer();
+ }
+
+ ~PCHSync() = default;
+};
+
+int main(int argc, char** argv)
+{
+ boost::asio::io_service io;
+ PCHSync pchSyncer(io);
+
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Starting PCH time sync service");
+
+ io.run();
+ return 0;
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service
new file mode 100644
index 000000000..cf9c3053f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/pch-time-sync/pch-time-sync.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=PCH BMC time sync service
+Conflicts=systemd-timesyncd.service
+
+[Service]
+Restart=always
+RestartSec=10
+ExecStart=/usr/bin/pch-time-sync
+StartLimitInterval=0
+Type=simple
+
+[Install]
+WantedBy=sysinit.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/phosphor-time-manager_git.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/phosphor-time-manager_git.bbappend
new file mode 100644
index 000000000..18780dfdd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/datetime/phosphor-time-manager_git.bbappend
@@ -0,0 +1,2 @@
+RDEPENDS_${PN}_remove = "phosphor-settings-manager"
+RDEPENDS_${PN} += " settings"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0001-Reapply-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-e.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0001-Reapply-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-e.patch
new file mode 100644
index 000000000..3344c27dd
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0001-Reapply-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-e.patch
@@ -0,0 +1,47 @@
+From 3789a98fda6e3cafd377b0f4fa1c0c40bb94297e Mon Sep 17 00:00:00 2001
+From: Johnathan Mantey <jonathanx.mantey@intel.com>
+Date: Wed, 20 Nov 2019 10:56:44 -0500
+Subject: [PATCH] Reapply: "Enhance DHCP beyond just OFF and IPv4/IPv6
+ enabled."
+
+DHCP is not a binary option. The network interface can have DHCP
+disabled, IPv4 only, IPv6 only, and IPv4/IPv6.
+
+Signed-off-by: Johnathan Mantey <jonathanx.mantey@intel.com>
+
+Reapplied ->
+Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
+Change-Id: I7654116aa3962de253225271190ce4a2fe229ce9
+---
+ .../Network/EthernetInterface.interface.yaml | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/xyz/openbmc_project/Network/EthernetInterface.interface.yaml b/xyz/openbmc_project/Network/EthernetInterface.interface.yaml
+index ee54145..56285ee 100644
+--- a/xyz/openbmc_project/Network/EthernetInterface.interface.yaml
++++ b/xyz/openbmc_project/Network/EthernetInterface.interface.yaml
+@@ -23,7 +23,7 @@ properties:
+ description: >
+ Domain names of the ethernet interface.
+ - name: DHCPEnabled
+- type: boolean
++ type: enum[self.DHCPConf]
+ description: >
+ Address mode of the ethernet interface.
+ - name: Nameservers
+@@ -69,4 +69,11 @@ enumerations:
+ - name: v4
+ - name: v6
+ - name: none
+-
++ - name: DHCPConf
++ description: >
++ A list of the permitted DHCP settings used by systemd.
++ values:
++ - name: both
++ - name: v4
++ - name: v6
++ - name: none
+--
+2.21.0
+
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..4cfc4acc8
--- /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,65 @@
+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 properties Feature
+ Support: SMBIOS service interface. CPU 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 +++++++++++++++++++
+ 1 files changed, 41 insertions(+)
+
+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
+--
+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/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/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch
new file mode 100644
index 000000000..67fa59090
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch
@@ -0,0 +1,57 @@
+From 6e9a19c43acac7d4254910906329d98d7b59085a Mon Sep 17 00:00:00 2001
+From: Ren Yu <yux.ren@intel.com>
+Date: Fri, 24 May 2019 14:55:10 +0800
+Subject: [PATCH] Add the pre-timeout interrupt defined in IPMI spec
+
+The IPMI watchdog pre-timeout interrupt is used to set the different
+pre-timeout interrupt source. Add them as a dbus property,
+IPMI set/get watchdog commands will use it.
+
+Signed-off-by: Ren Yu <yux.ren@intel.com>
+---
+ xyz/openbmc_project/State/Watchdog.interface.yaml | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/xyz/openbmc_project/State/Watchdog.interface.yaml b/xyz/openbmc_project/State/Watchdog.interface.yaml
+index 2fc47d8..6dfa9b9 100644
+--- a/xyz/openbmc_project/State/Watchdog.interface.yaml
++++ b/xyz/openbmc_project/State/Watchdog.interface.yaml
+@@ -33,6 +33,11 @@ properties:
+ description: >
+ The action the watchdog should perform when it expires.
+ default: 'HardReset'
++ - name: PreTimeoutInterrupt
++ type: enum[self.PreTimeoutInterruptAction]
++ description: >
++ The BMC generates the selected interrupt before the timer expires.
++ default: 'None'
+ - name: Interval
+ type: uint64
+ description: >
+@@ -73,6 +78,23 @@ enumerations:
+ description: >
+ Perform a power cycle of the system.
+
++ - name: PreTimeoutInterruptAction
++ description: >
++ The type of PreTimeout Interrupt.
++ values:
++ - name: 'None'
++ description: >
++ Do nothing.
++ - name: 'SMI'
++ description: >
++ SMI.
++ - name: 'NMI'
++ description: >
++ NMI / Diagnostic Interrupt.
++ - name: 'MI'
++ description: >
++ Messaging Interrupt.
++
+ - name: TimerUse
+ description: >
+ The type of timer use.
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch
new file mode 100644
index 000000000..d7e66abd2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0025-Add-PreInterruptFlag-properity-in-DBUS.patch
@@ -0,0 +1,39 @@
+From b7c487750c05dcc081219ccdd4ef539beef6aa30 Mon Sep 17 00:00:00 2001
+From: Ren Yu <yux.ren@intel.com>
+Date: Mon, 29 Jul 2019 10:51:12 +0800
+Subject: [PATCH] Add PreInterruptFlag properity in DBUS.
+
+PreTimeoutInterruptOccurFlag in DBUS would be set 'true'
+when watchdog pre-timeout interrupt occurred.
+
+Tested:
+Enable command(raw 0x06 0x31) that get message flag
+can set right bit about watchdog,
+need record PreTimeoutInterruptOccurFlag
+at xyz.openbmmc_project.State.Watchdog when watchdog
+pre-timeout interrupt occurred.
+
+Signed-off-by: Ren Yu <yux.ren@intel.com>
+---
+ xyz/openbmc_project/State/Watchdog.interface.yaml | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/xyz/openbmc_project/State/Watchdog.interface.yaml b/xyz/openbmc_project/State/Watchdog.interface.yaml
+index bf4cca0..6579368 100644
+--- a/xyz/openbmc_project/State/Watchdog.interface.yaml
++++ b/xyz/openbmc_project/State/Watchdog.interface.yaml
+@@ -59,6 +59,11 @@ properties:
+ description: >
+ The timer user at the time of expiration.
+ default: 'Reserved'
++ - name: PreTimeoutInterruptOccurFlag
++ type: boolean
++ description: >
++ PreTimeoutInterruptOccurFlag that preTimeoutInterrupt action occurred.
++ default: false
+
+ enumerations:
+ - name: Action
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch
new file mode 100644
index 000000000..36c63ec58
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces/0026-Add-StandbySpare-support-for-software-inventory.patch
@@ -0,0 +1,55 @@
+From 0d6556539be9bda478a3cabb6127eace5764fa11 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Date: Wed, 15 Jan 2020 10:01:04 +0800
+Subject: [PATCH] Add StandbySpare support for software inventory
+
+Add support to allow update for active / recovery
+regions of specified firmware. This update enables
+the backend modules to advertise whether the
+software object is active or recovery (StandbySpare)
+image.
+
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+---
+ xyz/openbmc_project/Software/Activation.interface.yaml | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/xyz/openbmc_project/Software/Activation.interface.yaml b/xyz/openbmc_project/Software/Activation.interface.yaml
+index efeeeb6..6c9ce75 100644
+--- a/xyz/openbmc_project/Software/Activation.interface.yaml
++++ b/xyz/openbmc_project/Software/Activation.interface.yaml
+@@ -28,12 +28,20 @@ enumerations:
+ - name: Activating
+ description: >
+ The Software.Version is in the process of being Activated.
++ - name: ActivatingAsStandbySpare
++ description: >
++ The Software.Version is in the process of being processed
++ as StandbySpare.
+ - name: Active
+ description: >
+ The Software.Version is currently Active.
+ - name: Failed
+ description: >
+ The Software.Version failed during or after Activation.
++ - name: StandbySpare
++ description: >
++ The Software.Version is part of a redundancy set and awaits
++ a failover or external action to activate.
+ - name: Staged
+ description: >
+ The Software.Version is currently in staged flash area.
+@@ -48,6 +56,10 @@ enumerations:
+ - name: Active
+ description: >
+ The Software.Version has been requested for Activation.
++ - name: StandbySpare
++ description: >
++ The Software.Version has been requested to be enabled as
++ StandbySpare.
+ # TODO: Specify "EAGAIN" type error when requested is unable to be acted on
+ # due to current system state. Currently, sdbusplus does not support
+ # errors on properties.
+--
+2.7.4
+
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..63124074a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/dbus/phosphor-dbus-interfaces_%.bbappend
@@ -0,0 +1,15 @@
+SRC_URI = "git://github.com/openbmc/phosphor-dbus-interfaces.git"
+SRCREV = "00c8527a40650650d2826d77b6e4e6d48f68f622"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://0005-Add-DBUS-interface-of-CPU-and-Memory-s-properties.patch \
+ file://0007-ipmi-set-BIOS-id.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://0024-Add-the-pre-timeout-interrupt-defined-in-IPMI-spec.patch \
+ file://0025-Add-PreInterruptFlag-properity-in-DBUS.patch \
+ file://0001-Reapply-Enhance-DHCP-beyond-just-OFF-and-IPv4-IPv6-e.patch \
+ file://0026-Add-StandbySpare-support-for-software-inventory.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..0e80b554a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control/phosphor-pid-control.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Phosphor-Pid-Control Margin-based Fan Control Daemon
+After=xyz.openbmc_project.EntityManager.service
+After=xyz.openbmc_project.ObjectMapper.service
+
+[Service]
+Restart=always
+ExecStart={bindir}/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..2026a13b0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fans/phosphor-pid-control_%.bbappend
@@ -0,0 +1,10 @@
+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 = "298a95cbb192ecc678b1a496acc954a3b2adf450"
+
+FILES_${PN} = "${bindir}/swampd ${bindir}/setsensor"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch
new file mode 100644
index 000000000..2a4c7e9b6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0002-Redfish-firmware-activation.patch
@@ -0,0 +1,44 @@
+From b6b3051c8078267153712ed8cf514373924fd07a Mon Sep 17 00:00:00 2001
+From: Jennifer Lee <jennifer1.lee@intel.com>
+Date: Mon, 16 Jul 2018 19:15:04 -0700
+Subject: [PATCH 2/6] Redfish firmware activation -- Modified flash.cpp to
+ call to customized flash service
+
+Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com>
+Change-Id: I81c3185e9c4c2ee907feeb53620faa22723c04d4
+---
+ ubi/flash.cpp | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/ubi/flash.cpp b/ubi/flash.cpp
+index ffa9348..5af2a17 100644
+--- a/ubi/flash.cpp
++++ b/ubi/flash.cpp
+@@ -15,10 +15,13 @@ void Activation::flashWrite()
+ {
+ auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+ SYSTEMD_INTERFACE, "StartUnit");
+- method.append("obmc-flash-bmc-ubirw.service", "replace");
++ std::string rwServiceFile =
++ "obmc-flash-bmc-ubirw@" + versionId + ".service";
++ method.append(rwServiceFile, "replace");
+ bus.call_noreply(method);
+
+- auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service";
++ std::string roServiceFile =
++ "obmc-flash-bmc-ubiro@" + versionId + ".service";
+ method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+ SYSTEMD_INTERFACE, "StartUnit");
+ method.append(roServiceFile, "replace");
+@@ -37,7 +40,7 @@ void Activation::onStateChanges(sdbusplus::message::message& msg)
+ // Read the msg and populate each variable
+ msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
+
+- auto rwServiceFile = "obmc-flash-bmc-ubirw.service";
++ auto rwServiceFile = "obmc-flash-bmc-ubirw@" + versionId + ".service";
+ auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service";
+ auto ubootVarsServiceFile =
+ "obmc-flash-bmc-updateubootvars@" + versionId + ".service";
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch
new file mode 100644
index 000000000..3fc3907ba
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0004-Changed-the-condition-of-software-version-service-wa.patch
@@ -0,0 +1,41 @@
+From 1b00440d0c8fabfa2e3eda984a21c0f004ca2150 Mon Sep 17 00:00:00 2001
+From: Jennifer Lee <jennifer1.lee@intel.com>
+Date: Fri, 26 Oct 2018 11:54:05 -0700
+Subject: [PATCH 4/6] Changed the condition of software version service
+ watching deamon
+
+ Originally it watches only files that are "written" into /tmp/images directory.
+This change modified the condition to also watch files that are "moved" into this directory.
+
+Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com>
+Change-Id: I3e9cf1ffc3f5350d4649d32d3d3837991322a65b
+---
+ watch.cpp | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/watch.cpp b/watch.cpp
+index e46b8aa..eee1bc3 100644
+--- a/watch.cpp
++++ b/watch.cpp
+@@ -45,7 +45,7 @@ Watch::Watch(sd_event* loop, std::function<int(std::string&)> imageCallback) :
+ std::strerror(error));
+ }
+
+- wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE);
++ wd = inotify_add_watch(fd, IMG_UPLOAD_DIR, IN_CLOSE_WRITE | IN_MOVED_TO);
+ if (-1 == wd)
+ {
+ auto error = errno;
+@@ -96,7 +96,8 @@ int Watch::callback(sd_event_source* s, int fd, uint32_t revents,
+ while (offset < bytes)
+ {
+ auto event = reinterpret_cast<inotify_event*>(&buffer[offset]);
+- if ((event->mask & IN_CLOSE_WRITE) && !(event->mask & IN_ISDIR))
++ if ((event->mask & (IN_CLOSE_WRITE | IN_MOVED_TO)) &&
++ !(event->mask & IN_ISDIR))
+ {
+ auto tarballPath = std::string{IMG_UPLOAD_DIR} + '/' + event->name;
+ auto rc = static_cast<Watch*>(userdata)->imageCallback(tarballPath);
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch
new file mode 100644
index 000000000..aa5d900e0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch
@@ -0,0 +1,188 @@
+From 7f29c255dd2af7fa6d38b02ad63a8b8940fbce84 Mon Sep 17 00:00:00 2001
+From: Jennifer Lee <jennifer1.lee@intel.com>
+Date: Mon, 10 Dec 2018 10:36:44 -0800
+Subject: [PATCH 5/6] Modified firmware activation to launch fwupd.sh through
+ non-ubi fs code path to match more closely to the upstream design -
+ Added option FWUPD_SCRIPT to saperate intel customized code - Adopted
+ ActivationProgress from ubi fs activation code mainly for progress indicator
+ for ipmi update
+
+Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com>
+Change-Id: Id805deea75b21fab86f6bb6edbf50ddb3be42564
+---
+ activation.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ configure.ac | 7 +++++++
+ static/flash.cpp | 41 +++++++++++++++++++++++++++++++++++++++--
+ ubi/flash.cpp | 9 +++------
+ 4 files changed, 93 insertions(+), 8 deletions(-)
+
+diff --git a/activation.cpp b/activation.cpp
+index f918221..f2923ae 100644
+--- a/activation.cpp
++++ b/activation.cpp
+@@ -163,6 +163,50 @@ auto Activation::activation(Activations value) -> Activations
+ softwareServer::Activation::Activations::Active);
+ }
+ }
++#elif defined(FWUPD_SCRIPT)
++ if (!activationProgress)
++ {
++ // Enable systemd signals
++ Activation::subscribeToSystemdSignals();
++ parent.freeSpace(*this);
++
++ activationProgress =
++ std::make_unique<ActivationProgress>(bus, path);
++
++#ifdef WANT_SIGNATURE_VERIFY
++ fs::path uploadDir(IMG_UPLOAD_DIR);
++ if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
++ {
++ onVerifyFailed();
++ // Stop the activation process, if fieldMode is enabled.
++ if (parent.control::FieldMode::fieldModeEnabled())
++ {
++ return softwareServer::Activation::activation(
++ softwareServer::Activation::Activations::Failed);
++ }
++ }
++#endif
++ flashWrite();
++ activationProgress->progress(10);
++ }
++ else if (activationProgress->progress() == 100)
++ {
++ log<level::ERR>("[Jennifer] progress == 100...");
++ if (!redundancyPriority)
++ {
++ redundancyPriority =
++ std::make_unique<RedundancyPriority>(bus, path, *this, 0);
++ }
++
++ // Remove version object from image manager
++ Activation::deleteImageManagerObject();
++
++ // Create active association
++ parent.createActiveAssociation(path);
++
++ return softwareServer::Activation::activation(
++ softwareServer::Activation::Activations::Active);
++ }
+ #else // !UBIFS_LAYOUT
+
+ #ifdef WANT_SIGNATURE_VERIFY
+diff --git a/configure.ac b/configure.ac
+index 2da97ad..720e704 100755
+--- a/configure.ac
++++ b/configure.ac
+@@ -184,6 +184,13 @@ AS_IF([test "x$enable_ubifs_layout" == "xyes"], \
+ [AC_DEFINE([UBIFS_LAYOUT],[],[Enable ubifs support.])])
+ AM_CONDITIONAL([UBIFS_LAYOUT], [test "x$enable_ubifs_layout" == "xyes"])
+
++# setup fwupd script support
++AC_ARG_ENABLE([fwupd_script],
++ AS_HELP_STRING([--enable-fwupd_script], [Enable fwupd script support.]))
++AS_IF([test "x$enable_fwupd_script" == "xyes"], \
++ [AC_DEFINE([FWUPD_SCRIPT],[],[Enable fwupd script support.])])
++AM_CONDITIONAL([FWUPD_SCRIPT], [test "x$enable_fwupd_script" == "xyes"])
++
+ # Check for header files.
+ AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd development package required])])
+ AC_CHECK_HEADER(sdbusplus/server.hpp, ,[AC_MSG_ERROR([Could not find sdbusplus/server.hpp...openbmc/sdbusplus package required])])
+diff --git a/static/flash.cpp b/static/flash.cpp
+index 82c2393..1bf29d5 100644
+--- a/static/flash.cpp
++++ b/static/flash.cpp
+@@ -20,9 +20,11 @@ namespace updater
+ {
+
+ namespace fs = std::experimental::filesystem;
++namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
+
+ void Activation::flashWrite()
+ {
++#ifndef FWUPD_SCRIPT
+ // For static layout code update, just put images in /run/initramfs.
+ // It expects user to trigger a reboot and an updater script will program
+ // the image to flash during reboot.
+@@ -33,11 +35,46 @@ void Activation::flashWrite()
+ fs::copy_file(uploadDir / versionId / bmcImage, toPath / bmcImage,
+ fs::copy_options::overwrite_existing);
+ }
++
++#else
++ auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
++ SYSTEMD_INTERFACE, "StartUnit");
++ method.append("fwupd@" + versionId + ".service", "replace");
++ bus.call_noreply(method);
++#endif
+ }
+
+-void Activation::onStateChanges(sdbusplus::message::message& /*msg*/)
++void Activation::onStateChanges(sdbusplus::message::message& msg)
+ {
+- // Empty
++#ifndef FWUPD_SCRIPT
++ uint32_t newStateID{};
++ sdbusplus::message::object_path newStateObjPath;
++ std::string newStateUnit{};
++ std::string newStateResult{};
++
++ msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
++
++ auto rwServiceFile = "fwupdw@" + versionId + ".service";
++
++ if (newStateUnit == rwServiceFile && newStateResult == "done")
++ {
++ activationProgress->progress(100);
++ }
++
++ if (newStateUnit == rwServiceFile)
++ {
++ if (newStateResult == "failed" || newStateResult == "dependency")
++ {
++ Activation::activation(
++ softwareServer::Activation::Activations::Failed);
++ }
++ else
++ {
++ Activation::activation(
++ softwareServer::Activation::Activations::Activating);
++ }
++ }
++#endif
+ }
+
+ } // namespace updater
+diff --git a/ubi/flash.cpp b/ubi/flash.cpp
+index 5af2a17..ffa9348 100644
+--- a/ubi/flash.cpp
++++ b/ubi/flash.cpp
+@@ -15,13 +15,10 @@ void Activation::flashWrite()
+ {
+ auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+ SYSTEMD_INTERFACE, "StartUnit");
+- std::string rwServiceFile =
+- "obmc-flash-bmc-ubirw@" + versionId + ".service";
+- method.append(rwServiceFile, "replace");
++ method.append("obmc-flash-bmc-ubirw.service", "replace");
+ bus.call_noreply(method);
+
+- std::string roServiceFile =
+- "obmc-flash-bmc-ubiro@" + versionId + ".service";
++ auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service";
+ method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
+ SYSTEMD_INTERFACE, "StartUnit");
+ method.append(roServiceFile, "replace");
+@@ -40,7 +37,7 @@ void Activation::onStateChanges(sdbusplus::message::message& msg)
+ // Read the msg and populate each variable
+ msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
+
+- auto rwServiceFile = "obmc-flash-bmc-ubirw@" + versionId + ".service";
++ auto rwServiceFile = "obmc-flash-bmc-ubirw.service";
+ auto roServiceFile = "obmc-flash-bmc-ubiro@" + versionId + ".service";
+ auto ubootVarsServiceFile =
+ "obmc-flash-bmc-updateubootvars@" + versionId + ".service";
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch
new file mode 100644
index 000000000..2d2ac2673
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch
@@ -0,0 +1,44 @@
+From 9b3c44e9fb3d907c0152f14b967e23ab964c0e0b Mon Sep 17 00:00:00 2001
+From: Jennifer Lee <jennifer1.lee@intel.com>
+Date: Thu, 14 Feb 2019 14:54:45 -0800
+Subject: [PATCH 6/6] Modify the ID of software image updater object on DBus to
+ allow force update onto same version image
+
+In the original design of image update, it does not allow the same version of image to be flashed onto itself.
+But this blocks validation tests and in most of the cases we don't prevent user from doing such update.
+
+This patch appends a random number after the version ID hash string to unblock such limitation.
+
+Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com>
+Change-Id: I16aba4804ae1bc2e8784320f91c0419fb8b23c35
+---
+ image_manager.cpp | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/image_manager.cpp b/image_manager.cpp
+index 5b2ff49..e3d26e3 100644
+--- a/image_manager.cpp
++++ b/image_manager.cpp
+@@ -9,6 +9,7 @@
+ #include <stdlib.h>
+ #include <sys/stat.h>
+ #include <sys/wait.h>
++#include <time.h>
+ #include <unistd.h>
+
+ #include <algorithm>
+@@ -129,6 +130,11 @@ int Manager::processImage(const std::string& tarFilePath)
+ // Compute id
+ auto id = Version::getId(version);
+
++ // Append a random number after the original version hash
++ // This will allow forcing image update onto the same version
++ srand(time(NULL));
++ id = id + "_" + std::to_string(rand());
++
+ fs::path imageDirPath = std::string{IMG_UPLOAD_DIR};
+ imageDirPath /= id;
+
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch
new file mode 100644
index 000000000..b63226cce
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-Adding-StandBySpare-for-firmware-activation.patch
@@ -0,0 +1,76 @@
+From c2ae3ac444f7a5e9674a82f47086874f947bcec6 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@linux.intel.com>
+Date: Thu, 5 Dec 2019 12:38:21 +0530
+Subject: [PATCH] Adding StandBySpare for firmware activation
+
+Added new states 'StandBySpare', 'ActivatingAsStandbySpare' for
+firmware activation. If the uploaded firmware image is for
+backup/recovery, then it sets the "StandBySpare" value for
+Activations. When backup/recovery image is in activating state,
+then activations will be set to "ActivatingAsStandbySpare".
+
+Tested:
+Tested using redfish interface.
+Did the GET on "/redfish/v1/UpdateService/FirmwareInventory/<backup image>"
+Response:
+ ....
+ "Status": {
+ "Health": "OK",
+ "HealthRollup": "OK",
+ "State": "StandbySpare"
+ }
+.......
+
+Change-Id: I7f1608fac3196774a6d593b6128d58da3f5c88fc
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@linux.intel.com>
+---
+ activation.cpp | 22 ++++++++++++++++++++--
+ 1 file changed, 20 insertions(+), 2 deletions(-)
+
+diff --git a/activation.cpp b/activation.cpp
+index 2966b2f..a098784 100644
+--- a/activation.cpp
++++ b/activation.cpp
+@@ -80,12 +80,16 @@ auto Activation::activation(Activations value) -> Activations
+ {
+
+ if ((value != softwareServer::Activation::Activations::Active) &&
+- (value != softwareServer::Activation::Activations::Activating))
++ (value != softwareServer::Activation::Activations::Activating) &&
++ (value !=
++ softwareServer::Activation::Activations::ActivatingAsStandbySpare))
+ {
+ redundancyPriority.reset(nullptr);
+ }
+
+- if (value == softwareServer::Activation::Activations::Activating)
++ if (value == softwareServer::Activation::Activations::Activating ||
++ value ==
++ softwareServer::Activation::Activations::ActivatingAsStandbySpare)
+ {
+ #ifdef UBIFS_LAYOUT
+ if (rwVolumeCreated == false && roVolumeCreated == false)
+@@ -256,6 +260,20 @@ auto Activation::requestedActivation(RequestedActivations value)
+ softwareServer::Activation::Activations::Activating);
+ }
+ }
++ else if ((value ==
++ softwareServer::Activation::RequestedActivations::StandbySpare) &&
++ (softwareServer::Activation::requestedActivation() !=
++ softwareServer::Activation::RequestedActivations::StandbySpare))
++ {
++ if ((softwareServer::Activation::activation() ==
++ softwareServer::Activation::Activations::Ready) ||
++ (softwareServer::Activation::activation() ==
++ softwareServer::Activation::Activations::Failed))
++ {
++ Activation::activation(softwareServer::Activation::Activations::
++ ActivatingAsStandbySpare);
++ }
++ }
+ return softwareServer::Activation::requestedActivation(value);
+ }
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch
new file mode 100644
index 000000000..92b3ced38
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0007-PFR-images-support.patch
@@ -0,0 +1,438 @@
+From 030f918b90ea45104bccf68082c2d634c6694238 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Date: Tue, 13 Aug 2019 22:43:12 +0530
+Subject: [PATCH] PFR images support in phosphor-software-manager
+
+This commit adds support for handling the PFR images
+upload and processing.
+
+Testing:
+tested PFR image uploads and updates
+
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+---
+ Makefile.am | 18 +++-
+ activation.cpp | 2 +-
+ configure.ac | 7 ++
+ item_updater.cpp | 6 +-
+ pfr_image_manager.cpp | 217 ++++++++++++++++++++++++++++++++++++++++++
+ pfr_image_manager.hpp | 75 +++++++++++++++
+ 6 files changed, 320 insertions(+), 5 deletions(-)
+ create mode 100644 pfr_image_manager.cpp
+ create mode 100644 pfr_image_manager.hpp
+
+diff --git a/Makefile.am b/Makefile.am
+index 6c3ec16..59ebecc 100755
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -6,13 +6,20 @@ noinst_HEADERS = \
+ watch.hpp \
+ version.hpp \
+ images.hpp \
+- image_manager.hpp \
+ item_updater.hpp \
+ activation.hpp \
+ flash.hpp \
+ item_updater_helper.hpp \
+ utils.hpp
+
++if PFR_UPDATE
++noinst_HEADERS += \
++ pfr_image_manager.hpp
++else
++noinst_HEADERS += \
++ image_manager.hpp
++endif
++
+ bin_PROGRAMS = \
+ phosphor-version-software-manager \
+ phosphor-download-manager \
+@@ -24,8 +31,15 @@ dist_bin_SCRIPTS = \
+ phosphor_version_software_manager_SOURCES = \
+ image_manager_main.cpp \
+ watch.cpp \
+- version.cpp \
++ version.cpp
++
++if PFR_UPDATE
++phosphor_version_software_manager_SOURCES += \
++ pfr_image_manager.cpp
++else
++phosphor_version_software_manager_SOURCES += \
+ image_manager.cpp
++endif
+
+ BUILT_SOURCES = \
+ xyz/openbmc_project/Software/Image/error.cpp \
+diff --git a/activation.cpp b/activation.cpp
+index cea1e50..7ff4196 100644
+--- a/activation.cpp
++++ b/activation.cpp
+@@ -197,7 +197,7 @@ auto Activation::activation(Activations value) -> Activations
+ }
+ else if (activationProgress->progress() == 100)
+ {
+- log<level::ERR>("[Jennifer] progress == 100...");
++ log<level::INFO>("progress == 100...");
+ if (!redundancyPriority)
+ {
+ redundancyPriority =
+diff --git a/configure.ac b/configure.ac
+index 720e704..e527682 100755
+--- a/configure.ac
++++ b/configure.ac
+@@ -191,6 +191,13 @@ AS_IF([test "x$enable_fwupd_script" == "xyes"], \
+ [AC_DEFINE([FWUPD_SCRIPT],[],[Enable fwupd script support.])])
+ AM_CONDITIONAL([FWUPD_SCRIPT], [test "x$enable_fwupd_script" == "xyes"])
+
++# setup pfr image update support
++AC_ARG_ENABLE([pfr_update],
++ AS_HELP_STRING([--enable-pfr_update], [Enable pfr image update support.]))
++AS_IF([test "x$enable_pfr_update" == "xyes"], \
++ [AC_DEFINE([PFR_UPDATE],[],[Enable pfr image update support.])])
++AM_CONDITIONAL([PFR_UPDATE], [test "x$enable_pfr_update" == "xyes"])
++
+ # Check for header files.
+ AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd development package required])])
+ AC_CHECK_HEADER(sdbusplus/server.hpp, ,[AC_MSG_ERROR([Could not find sdbusplus/server.hpp...openbmc/sdbusplus package required])])
+diff --git a/item_updater.cpp b/item_updater.cpp
+index 21fb6e0..fd76a7f 100644
+--- a/item_updater.cpp
++++ b/item_updater.cpp
+@@ -64,10 +64,10 @@ void ItemUpdater::createActivation(sdbusplus::message::message& msg)
+ auto value = SVersion::convertVersionPurposeFromString(
+ variant_ns::get<std::string>(property.second));
+ if (value == VersionPurpose::BMC ||
+-#ifdef HOST_BIOS_UPGRADE
++#if defined(HOST_BIOS_UPGRADE) || defined(PFR_UPDATE)
+ value == VersionPurpose::Host ||
+ #endif
+- value == VersionPurpose::System)
++ value == VersionPurpose::Other)
+ {
+ purpose = value;
+ }
+@@ -356,6 +357,7 @@ void ItemUpdater::deleteAll()
+ ItemUpdater::ActivationStatus
+ ItemUpdater::validateSquashFSImage(const std::string& filePath)
+ {
++#ifndef PFR_UPDATE
+ bool invalid = false;
+
+ for (auto& bmcImage : bmcImages)
+@@ -375,7 +377,7 @@ ItemUpdater::ActivationStatus
+ {
+ return ItemUpdater::ActivationStatus::invalid;
+ }
+-
++#endif
+ return ItemUpdater::ActivationStatus::ready;
+ }
+
+diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp
+new file mode 100644
+index 0000000..242a6ca
+--- /dev/null
++++ b/pfr_image_manager.cpp
+@@ -0,0 +1,217 @@
++#include "config.h"
++
++#include "pfr_image_manager.hpp"
++
++#include "version.hpp"
++#include "watch.hpp"
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <sys/stat.h>
++#include <sys/wait.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <algorithm>
++#include <cstring>
++#include <elog-errors.hpp>
++#include <filesystem>
++#include <fstream>
++#include <iomanip>
++#include <sstream>
++#include <string>
++#include <xyz/openbmc_project/Software/Image/error.hpp>
++
++namespace phosphor
++{
++namespace software
++{
++namespace manager
++{
++
++using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error;
++namespace Software = phosphor::logging::xyz::openbmc_project::Software;
++
++static constexpr const uint32_t pfmPos = 2054;
++
++static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType,
++ std::string& version)
++{
++ struct pfrImgBlock0 block0Data;
++ uint8_t verData[2];
++
++ if (std::filesystem::exists(imgPath))
++ {
++ try
++ {
++ std::ifstream imgFile(imgPath, std::ios::binary | std::ios::in);
++
++ if (!imgFile.good())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Image file read failed");
++ return -1;
++ }
++
++ imgFile.read(reinterpret_cast<char*>(&block0Data),
++ sizeof(block0Data));
++ imgType = block0Data.pcType[0];
++ imgFile.seekg(pfmPos,
++ std::ios::beg); // Version is at 0x806 in the PFM
++ imgFile.read(reinterpret_cast<char*>(&verData), sizeof(verData));
++ imgFile.close();
++ version =
++ std::to_string(verData[0]) + "." + std::to_string(verData[1]);
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "PFR image",
++ phosphor::logging::entry("PCType=%d", block0Data.pcType[0]),
++ phosphor::logging::entry("VERSION=%s", version.c_str()));
++ }
++ catch (std::exception& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++int Manager::processImage(const std::string& imgFilePath)
++{
++ std::filesystem::path imgPath(imgFilePath);
++
++ if (!std::filesystem::exists(imgPath))
++ return -1;
++
++ uint8_t imgType;
++ int retry = 3;
++ std::string ver;
++ std::string purposeString;
++
++ if (0 != getPFRImgInfo(imgFilePath, imgType, ver))
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error reading uploaded image type and version");
++ return -1;
++ }
++
++ if (ver.empty())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Empty version from image file");
++ return -1;
++ }
++
++ if (imgType == pfrBMCUpdateCap)
++ {
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
++ }
++ else if (imgType == pfrPCHUpdateCap)
++ {
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
++ }
++ else if (imgType == pfrCPLDUpdateCap)
++ {
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.Other";
++ }
++ else
++ {
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.Unknown";
++
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unknown image type");
++ return -1;
++ }
++
++ sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose
++ purpose = Version::VersionPurpose::Unknown;
++ try
++ {
++ purpose = Version::convertVersionPurposeFromString(purposeString);
++ }
++ catch (const sdbusplus::exception::InvalidEnumString& e)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error: Failed to convert purpose to enum."
++ " Setting to Unknown.");
++ }
++
++ // Compute id
++ std::string id = Version::getId(ver);
++
++ // Append a random number after the original version hash
++ // This will allow forcing image update onto the same version
++ // with 3 retries on random number generation.
++ do
++ {
++ srand(time(NULL));
++ id = id + "_" + std::to_string(rand());
++ } while ((versions.find(id) != versions.end()) && retry--);
++
++ if (versions.find(id) != versions.end())
++ {
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "Software Object with the same version already exists, exiting "
++ "the update",
++ phosphor::logging::entry("VERSION_ID=%s", id.c_str()));
++
++ return -1;
++ }
++
++ std::filesystem::path imageDirPath(IMG_UPLOAD_DIR);
++ imageDirPath /= id;
++
++ std::filesystem::create_directory(imageDirPath);
++
++ std::filesystem::path newFileName = imageDirPath / "image-runtime";
++ std::filesystem::rename(imgFilePath, newFileName);
++
++ // Create Version object
++ std::string objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
++
++ auto versionPtr = std::make_unique<Version>(
++ bus, objPath, ver, purpose, imageDirPath.string(),
++ std::bind(&Manager::erase, this, std::placeholders::_1));
++ versionPtr->deleteObject =
++ std::make_unique<phosphor::software::manager::Delete>(bus, objPath,
++ *versionPtr);
++ versions.insert(std::make_pair(id, std::move(versionPtr)));
++
++ return 0;
++}
++
++void Manager::erase(std::string entryId)
++{
++ auto it = versions.find(entryId);
++ if (it == versions.end())
++ {
++ return;
++ }
++
++ if (it->second->isFunctional())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ ("Error: Version " + entryId +
++ " is currently running on the BMC."
++ " Unable to remove.")
++ .c_str());
++ return;
++ }
++
++ // Delete image dir
++ std::filesystem::path imageDirPath = (*(it->second)).path();
++ if (std::filesystem::exists(imageDirPath))
++ {
++ std::filesystem::remove_all(imageDirPath);
++ }
++ this->versions.erase(entryId);
++}
++
++} // namespace manager
++} // namespace software
++} // namespace phosphor
+diff --git a/pfr_image_manager.hpp b/pfr_image_manager.hpp
+new file mode 100644
+index 0000000..c6ee6a4
+--- /dev/null
++++ b/pfr_image_manager.hpp
+@@ -0,0 +1,75 @@
++#pragma once
++#include "version.hpp"
++
++#include <sdbusplus/server.hpp>
++
++namespace phosphor
++{
++namespace software
++{
++namespace manager
++{
++
++enum pfrImgPCType {
++ pfrCPLDUpdateCap = 0x00,
++ pfrPCHPFM = 0x01,
++ pfrPCHUpdateCap = 0x02,
++ pfrBMCPFM = 0x03,
++ pfrBMCUpdateCap = 0x04
++};
++
++/* PFR image block 0 - As defined in HAS */
++struct pfrImgBlock0 {
++ uint8_t tag[4];
++ uint8_t pcLength[4];
++ uint8_t pcType[4];
++ uint8_t reserved1[4];
++ uint8_t hash256[32];
++ uint8_t hash384[48];
++ uint8_t reserved2[32];
++}__attribute__((packed));
++
++/** @class Manager
++ * @brief Contains a map of Version dbus objects.
++ * @details The software image manager class that contains the Version dbus
++ * objects and their version ids.
++ */
++class Manager
++{
++ public:
++ /** @brief Constructs Manager Class
++ *
++ * @param[in] bus - The Dbus bus object
++ */
++ Manager(sdbusplus::bus::bus& bus) : bus(bus){};
++
++ /**
++ * @brief Verify the image and provide the image to updater.
++ * Create and populate the version and file path interfaces.
++ *
++ * @param[in] uploaded image.
++ * @param[out] result - 0 if successful.
++ */
++ int processImage(const std::string& imageFilePath);
++
++ /**
++ * @brief Erase specified entry d-bus object
++ * and deletes the image file.
++ *
++ * @param[in] entryId - unique identifier of the entry
++ */
++ void erase(std::string entryId);
++
++ private:
++ /** @brief Persistent map of Version dbus objects and their
++ * version id */
++ std::map<std::string, std::unique_ptr<Version>> versions;
++
++ /** @brief Persistent sdbusplus DBus bus connection. */
++ sdbusplus::bus::bus& bus;
++
++};
++
++} // namespace manager
++} // namespace software
++} // namespace phosphor
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch
new file mode 100644
index 000000000..31373104f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager/0008-PFR-image-HASH-verification.patch
@@ -0,0 +1,408 @@
+From ac6e0c217a1b136d82f93b691aff1acb40009f26 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@linux.intel.com>
+Date: Thu, 5 Dec 2019 11:55:36 +0530
+Subject: [PATCH] PFR image HASH verification
+
+This adds HASH verification on PFR images uploaded for
+firmware updates
+
+Tested: tested firmware update with good and bad HASH images.
+
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@linux.intel.com>
+---
+ pfr_image_manager.cpp | 149 ++++++++++++++++++++++++++++++++----------
+ pfr_image_manager.hpp | 112 +++++++++++++++++++++++++++++--
+ 2 files changed, 221 insertions(+), 40 deletions(-)
+
+diff --git a/pfr_image_manager.cpp b/pfr_image_manager.cpp
+index 242a6ca..1a41cbe 100644
+--- a/pfr_image_manager.cpp
++++ b/pfr_image_manager.cpp
+@@ -5,6 +5,8 @@
+ #include "version.hpp"
+ #include "watch.hpp"
+
++#include <fcntl.h>
++#include <openssl/err.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <sys/stat.h>
+@@ -15,9 +17,9 @@
+ #include <algorithm>
+ #include <cstring>
+ #include <elog-errors.hpp>
+-#include <filesystem>
+ #include <fstream>
+ #include <iomanip>
++#include <set>
+ #include <sstream>
+ #include <string>
+ #include <xyz/openbmc_project/Software/Image/error.hpp>
+@@ -33,12 +35,21 @@ using namespace sdbusplus::xyz::openbmc_project::Software::Image::Error;
+ namespace Software = phosphor::logging::xyz::openbmc_project::Software;
+
+ static constexpr const uint32_t pfmPos = 2054;
++static constexpr const uint32_t block0Magic = 0xB6EAFD19;
++static constexpr const uint32_t lengthBlk0Blk1 = 1024;
+
+-static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType,
+- std::string& version)
++int Manager::verifyPFRImage(const std::filesystem::path imgPath,
++ std::string& version, std::string& purposeString)
+ {
+- struct pfrImgBlock0 block0Data;
+- uint8_t verData[2];
++ uint8_t imgType = 0;
++ uint32_t imgMagic = 0;
++ uint8_t verData[2] = {0};
++ uint32_t hashLen = 0;
++ struct pfrImgBlock0 block0Data = {};
++
++ std::string imageName;
++
++ EVP_MD_CTX* ctx;
+
+ if (std::filesystem::exists(imgPath))
+ {
+@@ -55,17 +66,101 @@ static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType,
+
+ imgFile.read(reinterpret_cast<char*>(&block0Data),
+ sizeof(block0Data));
++
++ imgMagic = block0Data.tag;
++
++ if (imgMagic != block0Magic)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Image magic number match failed",
++ phosphor::logging::entry("IMAGEMAGIC=0x%x", imgMagic));
++ return -1;
++ }
++
+ imgType = block0Data.pcType[0];
++
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "Image Type", phosphor::logging::entry(
++ "IMAGETYPE=0x%x", static_cast<int>(imgType)));
++
++ if (imgType == pfrBMCUpdateCap || imgType == pfrBMCPFM)
++ {
++ imageName = "BMC";
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
++ }
++ else if (imgType == pfrPCHUpdateCap || imgType == pfrPCHPFM)
++ {
++ imageName = "BIOS";
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
++ }
++ else if (imgType == pfrCPLDUpdateCap)
++ {
++ imageName = "CPLD";
++ purposeString =
++ "xyz.openbmc_project.Software.Version.VersionPurpose.Other";
++ }
++ else
++ {
++ purposeString = "xyz.openbmc_project.Software.Version."
++ "VersionPurpose.Unknown";
++
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unknown image type");
++ return -1;
++ }
++
+ imgFile.seekg(pfmPos,
+ std::ios::beg); // Version is at 0x806 in the PFM
+ imgFile.read(reinterpret_cast<char*>(&verData), sizeof(verData));
+ imgFile.close();
+- version =
+- std::to_string(verData[0]) + "." + std::to_string(verData[1]);
++
++ auto size = std::filesystem::file_size(imgPath);
++
++ phosphor::logging::log<phosphor::logging::level::INFO>(
++ "Image Size", phosphor::logging::entry("IMAGESIZE=0x%x",
++ static_cast<int>(size)));
++
++ // Adds all digest algorithms to the internal table
++ OpenSSL_add_all_digests();
++
++ ctx = EVP_MD_CTX_create();
++ EVP_DigestInit(ctx, EVP_sha256());
++
++ // Hash the image file and update the digest
++ auto dataPtr = mapFile(imgPath, size);
++
++ EVP_DigestUpdate(ctx, ((uint8_t*)dataPtr() + lengthBlk0Blk1),
++ (size - lengthBlk0Blk1));
++
++ std::vector<uint8_t> digest(EVP_MD_size(EVP_sha256()));
++ std::vector<uint8_t> expectedDigest(block0Data.hash256,
++ &block0Data.hash256[0] + 32);
++
++ EVP_DigestFinal(ctx, digest.data(), &hashLen);
++ EVP_MD_CTX_destroy(ctx);
++
++ std::string redfishMsgID = "OpenBMC.0.1";
++
++ if (expectedDigest != digest)
++ {
++ redfishMsgID += ".GeneralFirmwareSecurityViolation";
++ sd_journal_send("MESSAGE=%s",
++ "Firmware image HASH verification failed",
++ "PRIORITY=%i", LOG_ERR, "REDFISH_MESSAGE_ID=%s",
++ redfishMsgID.c_str(), "REDFISH_MESSAGE_ARGS=%s",
++ "Image HASH check fail", NULL);
++ return -1;
++ }
++
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "PFR image",
+ phosphor::logging::entry("PCType=%d", block0Data.pcType[0]),
+ phosphor::logging::entry("VERSION=%s", version.c_str()));
++
++ version =
++ std::to_string(verData[0]) + "." + std::to_string(verData[1]);
+ }
+ catch (std::exception& e)
+ {
+@@ -79,20 +174,20 @@ static int getPFRImgInfo(const std::filesystem::path imgPath, uint8_t& imgType,
+
+ int Manager::processImage(const std::string& imgFilePath)
+ {
++
+ std::filesystem::path imgPath(imgFilePath);
+
+ if (!std::filesystem::exists(imgPath))
+ return -1;
+
+- uint8_t imgType;
+ int retry = 3;
+ std::string ver;
+ std::string purposeString;
+
+- if (0 != getPFRImgInfo(imgFilePath, imgType, ver))
++ if (0 != verifyPFRImage(imgFilePath, ver, purposeString))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+- "Error reading uploaded image type and version");
++ "Error verifying uploaded image");
+ return -1;
+ }
+
+@@ -103,31 +198,6 @@ int Manager::processImage(const std::string& imgFilePath)
+ return -1;
+ }
+
+- if (imgType == pfrBMCUpdateCap)
+- {
+- purposeString =
+- "xyz.openbmc_project.Software.Version.VersionPurpose.BMC";
+- }
+- else if (imgType == pfrPCHUpdateCap)
+- {
+- purposeString =
+- "xyz.openbmc_project.Software.Version.VersionPurpose.Host";
+- }
+- else if (imgType == pfrCPLDUpdateCap)
+- {
+- purposeString =
+- "xyz.openbmc_project.Software.Version.VersionPurpose.Other";
+- }
+- else
+- {
+- purposeString =
+- "xyz.openbmc_project.Software.Version.VersionPurpose.Unknown";
+-
+- phosphor::logging::log<phosphor::logging::level::ERR>(
+- "Unknown image type");
+- return -1;
+- }
+-
+ sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose
+ purpose = Version::VersionPurpose::Unknown;
+ try
+@@ -169,6 +239,7 @@ int Manager::processImage(const std::string& imgFilePath)
+ std::filesystem::create_directory(imageDirPath);
+
+ std::filesystem::path newFileName = imageDirPath / "image-runtime";
++
+ std::filesystem::rename(imgFilePath, newFileName);
+
+ // Create Version object
+@@ -212,6 +283,14 @@ void Manager::erase(std::string entryId)
+ this->versions.erase(entryId);
+ }
+
++CustomMap Manager::mapFile(const std::filesystem::path& path, size_t size)
++{
++
++ CustomFd fd(open(path.c_str(), O_RDONLY));
++
++ return CustomMap(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd(), 0),
++ size);
++}
+ } // namespace manager
+ } // namespace software
+ } // namespace phosphor
+diff --git a/pfr_image_manager.hpp b/pfr_image_manager.hpp
+index c6ee6a4..5b7b2c3 100644
+--- a/pfr_image_manager.hpp
++++ b/pfr_image_manager.hpp
+@@ -1,6 +1,13 @@
+ #pragma once
+ #include "version.hpp"
+
++#include <openssl/evp.h>
++#include <openssl/pem.h>
++#include <openssl/rsa.h>
++#include <sys/mman.h>
++#include <unistd.h>
++
++#include <filesystem>
+ #include <sdbusplus/server.hpp>
+
+ namespace phosphor
+@@ -10,7 +17,8 @@ namespace software
+ namespace manager
+ {
+
+-enum pfrImgPCType {
++enum pfrImgPCType
++{
+ pfrCPLDUpdateCap = 0x00,
+ pfrPCHPFM = 0x01,
+ pfrPCHUpdateCap = 0x02,
+@@ -19,15 +27,94 @@ enum pfrImgPCType {
+ };
+
+ /* PFR image block 0 - As defined in HAS */
+-struct pfrImgBlock0 {
+- uint8_t tag[4];
++struct pfrImgBlock0
++{
++ uint32_t tag;
+ uint8_t pcLength[4];
+ uint8_t pcType[4];
+ uint8_t reserved1[4];
+ uint8_t hash256[32];
+ uint8_t hash384[48];
+ uint8_t reserved2[32];
+-}__attribute__((packed));
++} __attribute__((packed));
++
++/** @struct CustomFd
++ *
++ * RAII wrapper for file descriptor.
++ */
++struct CustomFd
++{
++ public:
++ CustomFd() = delete;
++ CustomFd(const CustomFd&) = delete;
++ CustomFd& operator=(const CustomFd&) = delete;
++ CustomFd(CustomFd&&) = default;
++ CustomFd& operator=(CustomFd&&) = default;
++ /** @brief Saves File descriptor and uses it to do file operation
++ *
++ * @param[in] fd - File descriptor
++ */
++ CustomFd(int fd) : fd(fd)
++ {
++ }
++
++ ~CustomFd()
++ {
++ if (fd >= 0)
++ {
++ close(fd);
++ }
++ }
++
++ int operator()() const
++ {
++ return fd;
++ }
++
++ private:
++ /** @brief File descriptor */
++ int fd = -1;
++};
++
++/** @struct CustomMap
++ *
++ * RAII wrapper for mmap.
++ */
++struct CustomMap
++{
++ private:
++ /** @brief starting address of the map */
++ void* addr;
++
++ /** @brief length of the mapping */
++ size_t length;
++
++ public:
++ CustomMap() = delete;
++ CustomMap(const CustomMap&) = delete;
++ CustomMap& operator=(const CustomMap&) = delete;
++ CustomMap(CustomMap&&) = default;
++ CustomMap& operator=(CustomMap&&) = default;
++
++ /** @brief Saves starting address of the map and
++ * and length of the file.
++ * @param[in] addr - Starting address of the map
++ * @param[in] length - length of the map
++ */
++ CustomMap(void* addr, size_t length) : addr(addr), length(length)
++ {
++ }
++
++ ~CustomMap()
++ {
++ munmap(addr, length);
++ }
++
++ void* operator()() const
++ {
++ return addr;
++ }
++};
+
+ /** @class Manager
+ * @brief Contains a map of Version dbus objects.
+@@ -61,13 +148,28 @@ class Manager
+ void erase(std::string entryId);
+
+ private:
++ /**
++ * @brief Memory map the file
++ * @param[in] - file path
++ * @param[in] - file size
++ * @param[out] - Custom Mmap address
++ */
++ CustomMap mapFile(const std::filesystem::path& path, size_t size);
++
++ /**
++ * @brief Verify the PFR image and return version and purpose
++ * @param[in] - file path
++ * @param[out] - version
++ * @param[out] - purpose
++ */
++ int verifyPFRImage(const std::filesystem::path imgPath,
++ std::string& version, std::string& purposeString);
+ /** @brief Persistent map of Version dbus objects and their
+ * version id */
+ std::map<std::string, std::unique_ptr<Version>> versions;
+
+ /** @brief Persistent sdbusplus DBus bus connection. */
+ sdbusplus::bus::bus& bus;
+-
+ };
+
+ } // namespace manager
+--
+2.17.1
+
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..64d9a47a6
--- /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 %i
+SyslogIdentifier=fwupd
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..96ddfc3ca
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/flash/phosphor-software-manager_%.bbappend
@@ -0,0 +1,19 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+EXTRA_OECONF += "--enable-fwupd_script"
+
+SYSTEMD_SERVICE_${PN}-updater += "fwupd@.service"
+
+EXTRA_OECONF += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '--enable-pfr_update', '', d)}"
+
+SRC_URI += "file://0002-Redfish-firmware-activation.patch \
+ file://0004-Changed-the-condition-of-software-version-service-wa.patch \
+ file://0005-Modified-firmware-activation-to-launch-fwupd.sh-thro.patch \
+ file://0006-Modify-the-ID-of-software-image-updater-object-on-DB.patch \
+ file://0007-Adding-StandBySpare-for-firmware-activation.patch \
+ "
+
+SRC_URI_PFR = "file://0007-PFR-images-support.patch \
+ file://0008-PFR-image-HASH-verification.patch \
+ "
+
+SRC_URI += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', SRC_URI_PFR, '', d)}"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb
new file mode 100644
index 000000000..53cec437d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb
@@ -0,0 +1,30 @@
+SUMMARY = "Default Fru"
+DESCRIPTION = "Builds a default FRU file at runtime based on board ID"
+
+inherit systemd
+inherit cmake
+
+SYSTEMD_SERVICE_${PN} = "SetBaseboardFru.service"
+
+S = "${WORKDIR}"
+SRC_URI = "file://checkFru.sh \
+ file://SetBaseboardFru.service \
+ file://mkfru.cpp \
+ file://CMakeLists.txt \
+ "
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "\
+ file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658 \
+ file://mkfru.cpp;beginline=2;endline=14;md5=c451359f18a13ee69602afce1588c01a \
+ "
+
+RDEPENDS_${PN} = "bash"
+
+do_install_append() {
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/checkFru.sh ${D}/${bindir}/checkFru.sh
+
+ 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-common/recipes-phosphor/fru/default-fru/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt
new file mode 100644
index 000000000..a8e633644
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
+project(mkfru CXX)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+add_executable(mkfru mkfru.cpp)
+install(TARGETS mkfru DESTINATION bin)
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service
new file mode 100644
index 000000000..d8c2a75ac
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Check for FRU presence
+
+[Service]
+ExecStart=/usr/bin/checkFru.sh
+Type=oneshot
+
+[Install]
+WantedBy=basic.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh
new file mode 100755
index 000000000..52da21230
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh
@@ -0,0 +1,76 @@
+#!/bin/bash
+
+# this script checks the gpio id and loads the correct baseboard fru
+FRUPATH="/etc/fru"
+PRODIDPATH="/var/cache/private"
+fruFile="$FRUPATH/baseboard.fru.bin"
+prodIDFile="$PRODIDPATH/prodID"
+
+if [ -f $fruFile -a -f $prodIDFile ]; then
+ exit 0
+fi
+
+read_id() {
+ local idx=0
+ local result=0
+ local value=0
+ for ((idx=0; idx<6; idx++))
+ do
+ typeset -i value=$(gpioget $(gpiofind "FM_BMC_BOARD_SKU_ID${idx}_N"))
+ value=$((value << idx))
+ result=$((result | value))
+ done
+ echo $result
+}
+
+BOARD_ID=$(read_id)
+if grep -q 'CPU part\s*: 0xb76' /proc/cpuinfo; then
+ # AST2500
+ case $BOARD_ID in
+ 12) NAME="D50TNP1SB"
+ PRODID="0x99";;
+ 38) NAME="WilsonCity"
+ PRODID="0x91";;
+ 40) NAME="CooperCity"
+ PRODID="0x9d";;
+ 42) NAME="WilsonCity"
+ PRODID="0x91";;
+ 45) NAME="WilsonCity"
+ PRODID="0x91";;
+ 60) NAME="M50CYP2SB2U"
+ PRODID="0x98";;
+ 62) NAME="WilsonPoint"
+ PRODID="0x9a";;
+ *) NAME="S2600WFT"
+ PRODID="0x7b";;
+ esac
+
+elif grep -q 'CPU part\s*: 0xc07' /proc/cpuinfo; then
+ # AST2600
+ case $BOARD_ID in
+ 62) NAME="ArcherCity"
+ PRODID="0x9c";;
+ *) NAME="AST2600EVB"
+ PRODID="0x00";;
+ esac
+
+fi
+
+if [ -z "$NAME" ]; then
+ NAME="Unknown"
+fi
+
+if [ ! -e $prodIDFile ]
+then
+ echo $PRODID >$prodIDFile
+fi
+
+if [ ! -f $fruFile ]
+then
+ cd /tmp
+ mkdir -p $FRUPATH
+ mkfru $NAME
+ mv $NAME.fru.bin $fruFile
+fi
+
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp
new file mode 100644
index 000000000..afadbd324
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp
@@ -0,0 +1,219 @@
+/*
+// 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: default FRU generation
+//
+*/
+
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <numeric>
+#include <string>
+#include <vector>
+
+constexpr uint8_t fillChar = '.';
+constexpr uint8_t eof = 0xc1;
+const std::string intel = "Intel Corporation";
+
+// round up to nearest block size (power of 2)
+constexpr size_t blockRound(size_t len, size_t blk)
+{
+ return ((len) + (((blk) - ((len) & ((blk)-1))) & ((blk)-1)));
+}
+
+uint8_t mklen(uint8_t len)
+{
+ return static_cast<uint8_t>((0x3 << 6) | len);
+}
+
+struct FruEntry
+{
+ static constexpr size_t fruBlockSize = 8; // type, length, checksum
+ static constexpr size_t fixedBytes = 3; // type, length, checksum
+ FruEntry() = delete;
+ FruEntry(const std::vector<uint8_t>& contents)
+ {
+ constexpr size_t verOffset = 0;
+ constexpr size_t lenOffset = 1;
+ value.resize(blockRound(fixedBytes + contents.size(), fruBlockSize));
+ value[verOffset] = 1;
+ value[lenOffset] = blocks();
+ std::copy(contents.begin(), contents.end(), value.begin() + 2);
+ addChecksum();
+ }
+
+ void addChecksum()
+ {
+ int sum = std::accumulate(value.begin(), value.end(), 0);
+ value.back() = static_cast<uint8_t>(256 - sum & 0xff);
+ }
+
+ uint8_t blocks() const
+ {
+ return static_cast<uint8_t>(value.size() / 8);
+ }
+
+ std::vector<uint8_t> value;
+};
+
+size_t fillDots(std::vector<uint8_t>::iterator start, size_t count)
+{
+ *start++ = mklen(count); // prefix with (0xc0 | count)
+ auto end = start + count++;
+ std::fill(start, end, '.');
+ return count;
+}
+
+size_t fillStr(std::vector<uint8_t>::iterator start, const std::string& str)
+{
+ size_t count = str.size();
+ *start++ = mklen(count++); // prefix with (0xc0 | count)
+ std::copy(str.begin(), str.end(), start);
+ return count;
+}
+
+std::vector<uint8_t> genChassisContents()
+{
+ constexpr size_t pnSize = 18;
+ constexpr size_t snSize = 18;
+ constexpr size_t amSize = 31;
+ constexpr size_t headerSize = 1;
+ constexpr size_t contentSize = headerSize + 1 + pnSize + 1 + snSize + 1 +
+ amSize + 1 + amSize + sizeof(eof);
+ std::vector<uint8_t> data(contentSize);
+ size_t offset = 0;
+ // chassis type (main server chassis)
+ data[offset++] = 0x17;
+ // chassis part number
+ offset += fillDots(data.begin() + offset, pnSize);
+ // chassis serial number
+ offset += fillDots(data.begin() + offset, snSize);
+ // info am1
+ offset += fillDots(data.begin() + offset, amSize);
+ // info am2
+ offset += fillDots(data.begin() + offset, amSize);
+ data[offset] = eof;
+
+ return data;
+}
+
+std::vector<uint8_t> genBoardContents(const std::string& name)
+{
+ constexpr size_t headerSize = 4;
+ constexpr size_t snSize = 12;
+ constexpr size_t pnSize = 10;
+ const std::string version = "FRU Ver 0.01";
+ size_t contentSize = headerSize + 1 + name.size() + 1 + intel.size() + 1 +
+ snSize + 1 + pnSize + 1 + version.size() + sizeof(eof);
+ std::vector<uint8_t> data(contentSize);
+ size_t offset = 0;
+ // chassis type (main server chassis)
+ data[offset++] = 0; // language code
+ data[offset++] = 0; // mfg date/time
+ data[offset++] = 0; // mfg date/time
+ data[offset++] = 0; // mfg date/time
+ // manufacturer name
+ offset += fillStr(data.begin() + offset, intel);
+ // product name
+ offset += fillStr(data.begin() + offset, name);
+ // board sn
+ offset += fillDots(data.begin() + offset, snSize);
+ // board pn
+ offset += fillDots(data.begin() + offset, pnSize);
+ // fru version string
+ offset += fillStr(data.begin() + offset, version);
+ data[offset] = eof;
+
+ return data;
+}
+
+std::vector<uint8_t> genProductContents(const std::string& name)
+{
+ constexpr size_t headerSize = 1;
+ constexpr size_t pnSize = 10;
+ constexpr size_t pvSize = 20;
+ constexpr size_t snSize = 12;
+ constexpr size_t atSize = 20;
+ constexpr size_t idSize = 0;
+ const std::string version = "FRU Ver 0.01";
+ size_t contentSize = headerSize + 1 + intel.size() + 1 + name.size() + 1 +
+ pnSize + 1 + pvSize + 1 + snSize + 1 + atSize + 1 +
+ idSize + sizeof(eof);
+ std::vector<uint8_t> data(contentSize);
+ size_t offset = 0;
+ // chassis type (main server chassis)
+ data[offset++] = 0; // language code
+ // manufacturer name
+ offset += fillStr(data.begin() + offset, intel);
+ // product name
+ offset += fillStr(data.begin() + offset, name);
+ // product part number
+ offset += fillDots(data.begin() + offset, pnSize);
+ // product version
+ offset += fillDots(data.begin() + offset, pvSize);
+ // product serial number
+ offset += fillDots(data.begin() + offset, snSize);
+ // product asset tag
+ offset += fillDots(data.begin() + offset, atSize);
+ // empty fru file id
+ offset += fillDots(data.begin() + offset, idSize);
+ data[offset] = eof;
+
+ return data;
+}
+
+int createFru(const std::string& name)
+{
+ std::vector<uint8_t> internal{1, 0, 0, 0, 0, 0, 0, 1}; // fixed data
+ FruEntry chassis(genChassisContents());
+ FruEntry board(genBoardContents(name));
+ FruEntry product(genProductContents(name));
+ uint8_t offset = 1; // room for header's offset
+ FruEntry header({
+ offset += 1, // internal size
+ offset += chassis.blocks(),
+ offset += board.blocks(),
+ });
+ std::string filename = name + ".fru.bin";
+ std::ofstream output(filename);
+ std::ostream_iterator<uint8_t> outputIter(output);
+ std::copy(header.value.begin(), header.value.end(), outputIter);
+ std::copy(internal.begin(), internal.end(), outputIter);
+ std::copy(chassis.value.begin(), chassis.value.end(), outputIter);
+ std::copy(board.value.begin(), board.value.end(), outputIter);
+ std::copy(product.value.begin(), product.value.end(), outputIter);
+ constexpr size_t minFruSize = 0x1ff;
+ size_t fruSize = header.value.size() + internal.size() +
+ chassis.value.size() + board.value.size() +
+ product.value.size();
+ if (fruSize < minFruSize)
+ {
+ std::vector<uint8_t> padding(minFruSize - fruSize);
+ std::copy(padding.begin(), padding.end(), outputIter);
+ }
+ output.close();
+ return 0;
+}
+
+int main(int argc, const char* argv[])
+{
+ if (argc != 2)
+ {
+ std::cerr << "Usage: " << argv[0] << " <'Product Name'>\n";
+ return 1;
+ }
+ return createFru(argv[1]);
+}
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/0001-Firmware-update-support-for-StandBySpare.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-support-for-StandBySpare.patch
new file mode 100644
index 000000000..46e94e339
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/0001-Firmware-update-support-for-StandBySpare.patch
@@ -0,0 +1,462 @@
+From 461da7ec950704a1f5bcc7f6527ed8ca119cfaf9 Mon Sep 17 00:00:00 2001
+From: Vikram Bodireddy <vikram.bodireddy@intel.com>
+Date: Tue, 24 Mar 2020 16:05:32 +0530
+Subject: [PATCH] Firmware update support for StandBySpare
+
+Firmware update support for StandBySpare. This will
+have support for adding 'HttpPushUriTargets' and
+'HttpPushUriTargetsBusy' attributes. These attributes enables
+'HttpPushUri' to distinguish between the firmware update targets.
+
+Tested:
+ - GET on "/redfish/v1/UpdateService", got below response
+.........
+ "HttpPushUriTargets": [],
+ "HttpPushUriTargetsBusy": false
+........
+
+ - PATCH on "/redfish/v1/UpdateService" and works fine.
+{
+ "HttpPushUriTargets": ["bmc_recovery"],
+ "HttpPushUriTargetsBusy": true
+}
+
+ - Did Firmware update and verified end to end functionality
+ for both bmc active and backup images.
+
+ - Successfully ran redfish validater with no new errors.
+
+Signed-off-by: Vikram Bodireddy <vikram.bodireddy@intel.com>
+---
+ redfish-core/lib/update_service.hpp | 274 +++++++++++++++++++++++++++++++-----
+ 1 file changed, 241 insertions(+), 33 deletions(-)
+
+diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
+index e9793eb..a913bac 100644
+--- a/redfish-core/lib/update_service.hpp
++++ b/redfish-core/lib/update_service.hpp
+@@ -30,6 +30,17 @@ static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
+ static bool fwUpdateInProgress = false;
+ // Timer for software available
+ static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer;
++static constexpr const char *versionIntf =
++ "xyz.openbmc_project.Software.Version";
++static constexpr const char *activationIntf =
++ "xyz.openbmc_project.Software.Activation";
++static constexpr const char *reqActivationPropName = "RequestedActivation";
++static constexpr const char *reqActivationsActive =
++ "xyz.openbmc_project.Software.Activation.RequestedActivations.Active";
++static constexpr const char *reqActivationsStandBySpare =
++ "xyz.openbmc_project.Software.Activation.RequestedActivations.StandbySpare";
++static constexpr const char *activationsStandBySpare =
++ "xyz.openbmc_project.Software.Activation.Activations.StandbySpare";
+
+ static void cleanUp()
+ {
+@@ -37,27 +48,119 @@ static void cleanUp()
+ fwUpdateMatcher = nullptr;
+ }
+ static void activateImage(const std::string &objPath,
+- const std::string &service)
++ const std::string &service,
++ const std::vector<std::string> &imgUriTargets)
+ {
+ BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service;
++ // If targets is empty, it will apply to the active.
++ if (imgUriTargets.size() == 0)
++ {
++ crow::connections::systemBus->async_method_call(
++ [](const boost::system::error_code error_code) {
++ if (error_code)
++ {
++ BMCWEB_LOG_DEBUG
++ << "RequestedActivation failed: error_code = "
++ << error_code;
++ BMCWEB_LOG_DEBUG << "error msg = " << error_code.message();
++ }
++ },
++ service, objPath, "org.freedesktop.DBus.Properties", "Set",
++ activationIntf, reqActivationPropName,
++ std::variant<std::string>(reqActivationsActive));
++ return;
++ }
++
++ // TODO: Now we support only one target becuase software-manager
++ // code support one activation per object. It will be enhanced
++ // to multiple targets for single image in future. For now,
++ // consider first target alone.
+ crow::connections::systemBus->async_method_call(
+- [](const boost::system::error_code error_code) {
+- if (error_code)
++ [objPath, service, imgTarget{imgUriTargets[0]}](
++ const boost::system::error_code ec,
++ const crow::openbmc_mapper::GetSubTreeType &subtree) {
++ if (ec || !subtree.size())
+ {
+- BMCWEB_LOG_DEBUG << "error_code = " << error_code;
+- BMCWEB_LOG_DEBUG << "error msg = " << error_code.message();
++ return;
++ }
++
++ for (const auto &[invObjPath, invDict] : subtree)
++ {
++ std::size_t idPos = invObjPath.rfind("/");
++ if ((idPos == std::string::npos) ||
++ ((idPos + 1) >= invObjPath.size()))
++ {
++ BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!";
++ return;
++ }
++ std::string swId = invObjPath.substr(idPos + 1);
++
++ if (swId != imgTarget)
++ {
++ continue;
++ }
++
++ if (invDict.size() < 1)
++ {
++ continue;
++ }
++ BMCWEB_LOG_DEBUG << "Image target matched with object "
++ << invObjPath;
++ crow::connections::systemBus->async_method_call(
++ [objPath,
++ service](const boost::system::error_code error_code,
++ const std::variant<std::string> value) {
++ if (error_code)
++ {
++ BMCWEB_LOG_DEBUG
++ << "Error in querying activation value";
++ // not all fwtypes are updateable,
++ // this is ok
++ return;
++ }
++ std::string activationValue =
++ std::get<std::string>(value);
++ BMCWEB_LOG_DEBUG << "Activation Value: "
++ << activationValue;
++ std::string reqActivation = reqActivationsActive;
++ if (activationValue == activationsStandBySpare)
++ {
++ reqActivation = reqActivationsStandBySpare;
++ }
++ BMCWEB_LOG_DEBUG
++ << "Setting RequestedActivation value as "
++ << reqActivation << " for " << service << " "
++ << objPath;
++ crow::connections::systemBus->async_method_call(
++ [](const boost::system::error_code error_code) {
++ if (error_code)
++ {
++ BMCWEB_LOG_DEBUG
++ << "RequestedActivation failed: ec = "
++ << error_code;
++ }
++ return;
++ },
++ service, objPath, "org.freedesktop.DBus.Properties",
++ "Set", activationIntf, reqActivationPropName,
++ std::variant<std::string>(reqActivation));
++ },
++ invDict[0].first,
++ "/xyz/openbmc_project/software/" + imgTarget,
++ "org.freedesktop.DBus.Properties", "Get", activationIntf,
++ "Activation");
+ }
+ },
+- service, objPath, "org.freedesktop.DBus.Properties", "Set",
+- "xyz.openbmc_project.Software.Activation", "RequestedActivation",
+- std::variant<std::string>(
+- "xyz.openbmc_project.Software.Activation.RequestedActivations."
+- "Active"));
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
++ static_cast<int32_t>(0), std::array<const char *, 1>{versionIntf});
+ }
+
+ // Note that asyncResp can be either a valid pointer or nullptr. If nullptr
+ // then no asyncResp updates will occur
+ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp,
++ const std::vector<std::string> imgUriTargets,
+ sdbusplus::message::message &m,
+ const crow::Request &req)
+ {
+@@ -70,25 +173,27 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp,
+
+ m.read(objPath, interfacesProperties);
+
+- BMCWEB_LOG_DEBUG << "obj path = " << objPath.str;
++ BMCWEB_LOG_DEBUG << "Software Interface Added. obj path = " << objPath.str;
+ for (auto &interface : interfacesProperties)
+ {
+ BMCWEB_LOG_DEBUG << "interface = " << interface.first;
+
+- if (interface.first == "xyz.openbmc_project.Software.Activation")
++ if (interface.first == activationIntf)
+ {
+ // Found our interface, disable callbacks
+ fwUpdateMatcher = nullptr;
+
+ // Retrieve service and activate
+ crow::connections::systemBus->async_method_call(
+- [objPath, asyncResp,
++ [objPath, asyncResp, imgTargets{imgUriTargets},
+ req](const boost::system::error_code error_code,
+ const std::vector<std::pair<
+ std::string, std::vector<std::string>>> &objInfo) {
+ if (error_code)
+ {
+- BMCWEB_LOG_DEBUG << "error_code = " << error_code;
++ BMCWEB_LOG_DEBUG
++ << "GetSoftwareObject path failed: error_code = "
++ << error_code;
+ BMCWEB_LOG_DEBUG << "error msg = "
+ << error_code.message();
+ if (asyncResp)
+@@ -115,7 +220,7 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp,
+ // is added
+ fwAvailableTimer = nullptr;
+
+- activateImage(objPath.str, objInfo[0].first);
++ activateImage(objPath.str, objInfo[0].first, imgTargets);
+ if (asyncResp)
+ {
+ std::shared_ptr<task::TaskData> task =
+@@ -196,17 +301,16 @@ static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp,
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str,
+- std::array<const char *, 1>{
+- "xyz.openbmc_project.Software.Activation"});
++ std::array<const char *, 1>{activationIntf});
+ }
+ }
+ }
+
+ // Note that asyncResp can be either a valid pointer or nullptr. If nullptr
+ // then no asyncResp updates will occur
+-static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp,
+- const crow::Request &req,
+- int timeoutTimeSeconds = 5)
++static void monitorForSoftwareAvailable(
++ std::shared_ptr<AsyncResp> asyncResp, const crow::Request &req,
++ const std::vector<std::string> &imgUriTargets, int timeoutTimeSeconds = 5)
+ {
+ // Only allow one FW update at a time
+ if (fwUpdateInProgress != false)
+@@ -246,9 +350,10 @@ static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp,
+ }
+ });
+
+- auto callback = [asyncResp, req](sdbusplus::message::message &m) {
++ auto callback = [asyncResp, imgTargets{imgUriTargets},
++ req](sdbusplus::message::message &m) {
+ BMCWEB_LOG_DEBUG << "Match fired";
+- softwareInterfaceAdded(asyncResp, m, req);
++ softwareInterfaceAdded(asyncResp, imgTargets, m, req);
+ };
+
+ fwUpdateInProgress = true;
+@@ -358,9 +463,12 @@ class UpdateServiceActionsSimpleUpdate : public Node
+ std::string fwFile = imageURI.substr(separator + 1);
+ BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile;
+
++ // We will pass empty targets and its handled in activation.
++ std::vector<std::string> httpUriTargets;
++
+ // Setup callback for when new software detected
+ // Give TFTP 2 minutes to complete
+- monitorForSoftwareAvailable(nullptr, req, 120);
++ monitorForSoftwareAvailable(nullptr, req, httpUriTargets, 120);
+
+ // TFTP can take up to 2 minutes depending on image size and
+ // connection speed. Return to caller as soon as the TFTP operation
+@@ -394,7 +502,8 @@ class UpdateServiceActionsSimpleUpdate : public Node
+ class UpdateService : public Node
+ {
+ public:
+- UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/")
++ UpdateService(CrowApp &app) :
++ Node(app, "/redfish/v1/UpdateService/"), httpPushUriTargetBusy(false)
+ {
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+@@ -406,6 +515,9 @@ class UpdateService : public Node
+ }
+
+ private:
++ std::vector<std::string> httpPushUriTargets;
++ bool httpPushUriTargetBusy;
++
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+@@ -416,6 +528,8 @@ class UpdateService : public Node
+ res.jsonValue["Description"] = "Service for Software Update";
+ res.jsonValue["Name"] = "Update Service";
+ res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService";
++ res.jsonValue["HttpPushUriTargets"] = httpPushUriTargets;
++ res.jsonValue["HttpPushUriTargetsBusy"] = httpPushUriTargetBusy;
+ // UpdateService cannot be disabled
+ res.jsonValue["ServiceEnabled"] = true;
+ res.jsonValue["FirmwareInventory"] = {
+@@ -475,9 +589,14 @@ class UpdateService : public Node
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+
+ std::optional<nlohmann::json> pushUriOptions;
+- if (!json_util::readJson(req, res, "HttpPushUriOptions",
+- pushUriOptions))
++ std::optional<std::vector<std::string>> imgTargets;
++ std::optional<bool> imgTargetBusy;
++
++ if (!json_util::readJson(req, res, "HttpPushUriOptions", pushUriOptions,
++ "HttpPushUriTargets", imgTargets,
++ "HttpPushUriTargetsBusy", imgTargetBusy))
+ {
++ BMCWEB_LOG_DEBUG << "UpdateService doPatch: Invalid request body";
+ return;
+ }
+
+@@ -545,6 +664,98 @@ class UpdateService : public Node
+ }
+ }
+ }
++
++ if (imgTargetBusy)
++ {
++ if ((httpPushUriTargetBusy) && (*imgTargetBusy))
++ {
++ BMCWEB_LOG_DEBUG
++ << "Other client has reserved the HttpPushUriTargets "
++ "property for firmware updates.";
++ messages::resourceInUse(asyncResp->res);
++ return;
++ }
++
++ if (imgTargets)
++ {
++ if (!(*imgTargetBusy))
++ {
++ BMCWEB_LOG_DEBUG
++ << "UpdateService doPatch: httpPushUriTargetBusy "
++ "should be "
++ "true before setting httpPushUriTargets";
++ messages::invalidObject(asyncResp->res,
++ "HttpPushUriTargetsBusy");
++ return;
++ }
++ if ((*imgTargets).size() != 0)
++ {
++ // TODO: Now we support max one target becuase
++ // software-manager code support one activation per object.
++ // It will be enhanced to multiple targets for single image
++ // in future. For now, consider first target alone.
++ if ((*imgTargets).size() != 1)
++ {
++ messages::invalidObject(asyncResp->res,
++ "HttpPushUriTargets");
++ return;
++ }
++ crow::connections::systemBus->async_method_call(
++ [this, asyncResp, uriTargets{*imgTargets},
++ targetBusy{*imgTargetBusy}](
++ const boost::system::error_code ec,
++ const std::vector<std::string> swInvPaths) {
++ if (ec)
++ {
++ return;
++ }
++
++ bool swInvObjFound = false;
++ for (const std::string &path : swInvPaths)
++ {
++ std::size_t idPos = path.rfind("/");
++ if ((idPos == std::string::npos) ||
++ ((idPos + 1) >= path.size()))
++ {
++ messages::internalError(asyncResp->res);
++ BMCWEB_LOG_DEBUG
++ << "Can't parse firmware ID!!";
++ return;
++ }
++ std::string swId = path.substr(idPos + 1);
++
++ if (swId == uriTargets[0])
++ {
++ swInvObjFound = true;
++ break;
++ }
++ }
++ if (!swInvObjFound)
++ {
++ messages::invalidObject(asyncResp->res,
++ "HttpPushUriTargets");
++ return;
++ }
++ this->httpPushUriTargetBusy = targetBusy;
++ this->httpPushUriTargets = uriTargets;
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
++ "/", static_cast<int32_t>(0),
++ std::array<const char *, 1>{versionIntf});
++ }
++ else
++ {
++ httpPushUriTargetBusy = *imgTargetBusy;
++ httpPushUriTargets = *imgTargets;
++ }
++ }
++ else
++ {
++ httpPushUriTargetBusy = *imgTargetBusy;
++ }
++ }
+ }
+
+ void doPost(crow::Response &res, const crow::Request &req,
+@@ -555,7 +766,7 @@ class UpdateService : public Node
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+
+ // Setup callback for when new software detected
+- monitorForSoftwareAvailable(asyncResp, req);
++ monitorForSoftwareAvailable(asyncResp, req, httpPushUriTargets);
+
+ std::string filepath(
+ "/tmp/images/" +
+@@ -641,8 +852,7 @@ class SoftwareInventoryCollection : public Node
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/software", static_cast<int32_t>(0),
+- std::array<const char *, 1>{
+- "xyz.openbmc_project.Software.Version"});
++ std::array<const char *, 1>{versionIntf});
+ }
+ };
+
+@@ -825,7 +1035,7 @@ class SoftwareInventory : public Node
+ },
+ obj.second[0].first, obj.first,
+ "org.freedesktop.DBus.Properties", "GetAll",
+- "xyz.openbmc_project.Software.Version");
++ versionIntf);
+ }
+ if (!found)
+ {
+@@ -846,9 +1056,7 @@ class SoftwareInventory : public Node
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/",
+- static_cast<int32_t>(0),
+- std::array<const char *, 1>{
+- "xyz.openbmc_project.Software.Version"});
++ static_cast<int32_t>(0), std::array<const char *, 1>{versionIntf});
+ }
+ };
+
+--
+2.7.4
+
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..2e59a7b78
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb_%.bbappend
@@ -0,0 +1,27 @@
+# todo(james) remove nobranch
+SRC_URI = "git://github.com/openbmc/bmcweb.git"
+SRCREV = "e5aaf047b6b41b0837ef0846cf5356c9a6bcb030"
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+# add a user called bmcweb for the server to assume
+# bmcweb is part of group shadow for non-root pam authentication
+USERADD_PARAM_${PN} = "-r -s /usr/sbin/nologin -d /home/bmcweb -m -G shadow bmcweb"
+
+GROUPADD_PARAM_${PN} = "web; redfish "
+
+SRC_URI += "file://0001-Firmware-update-support-for-StandBySpare.patch \
+"
+
+# Enable PFR support
+EXTRA_OECMAKE += "${@bb.utils.contains('IMAGE_FSTYPES', 'intel-pfr', '-DBMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE=ON', '', d)}"
+
+# Enable NBD_PROXY
+EXTRA_OECMAKE += " -DBMCWEB_ENABLE_VM_NBDPROXY=ON"
+
+# Disable MTLS until it passes security review
+EXTRA_OECMAKE += " -DBMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION=OFF"
+
+# Enable Validation unsecure based on IMAGE_FEATURES
+EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-DBMCWEB_ENABLE_VALIDATION_UNSECURE_FEATURE=ON', '', d)}"
+
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..b02595e81
--- /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" : "RESERVED",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "reserved",
+ "protocol_type" : "na",
+ "session_supported" : "session-less",
+ "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" : "RESERVED",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "reserved",
+ "protocol_type" : "na",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "5" : {
+ "name" : "RESERVED",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "reserved",
+ "protocol_type" : "na",
+ "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" : "ipmi_kcs4",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "system-interface",
+ "protocol_type" : "kcs",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "8" : {
+ "name" : "INTRABMC",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "oem",
+ "protocol_type" : "oem",
+ "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" : "reserved",
+ "protocol_type" : "na",
+ "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" : "reserved",
+ "protocol_type" : "na",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "14" : {
+ "name" : "SELF",
+ "is_valid" : false,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "unknown",
+ "protocol_type" : "na",
+ "session_supported" : "session-less",
+ "is_ipmi" : true
+ }
+ },
+ "15" : {
+ "name" : "ipmi_kcs3",
+ "is_valid" : true,
+ "active_sessions" : 0,
+ "channel_info" : {
+ "medium_type" : "system-interface",
+ "protocol_type" : "kcs",
+ "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..6fc46f452
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-config/master_write_read_white_list.json
@@ -0,0 +1,76 @@
+{
+ "filters": [
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x01",
+ "slaveAddr": "0x4d",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x01",
+ "slaveAddr": "0x57",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x02",
+ "slaveAddr": "0x40",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x02",
+ "slaveAddr": "0x49",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x02",
+ "slaveAddr": "0x51",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x03",
+ "slaveAddr": "0x44",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x03",
+ "slaveAddr": "0x68",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x06",
+ "slaveAddr": "0x40",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ },
+ {
+ "Description": "Allow full read - ignore first byte write value",
+ "busId": "0x07",
+ "slaveAddr": "0x51",
+ "slaveAddrMask": "0x00",
+ "command": "0x00",
+ "commandMask": "0xFF"
+ }
+ ]
+}
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/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/.clang-format
new file mode 100644
index 000000000..ea71ad6e1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/.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-phosphor/ipmi/phosphor-ipmi-host/0001-Modify-Get-Lan-Configuration-IP-Address-Source-to-us.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Modify-Get-Lan-Configuration-IP-Address-Source-to-us.patch
new file mode 100644
index 000000000..7e3f92dbc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0001-Modify-Get-Lan-Configuration-IP-Address-Source-to-us.patch
@@ -0,0 +1,231 @@
+From 8e9fba263179ccc87be7212c7dbd87cd7a37ac30 Mon Sep 17 00:00:00 2001
+From: Johnathan Mantey <johnathanx.mantey@intel.com>
+Date: Thu, 14 Nov 2019 11:24:19 -0800
+Subject: [PATCH] Modify Get Lan Configuration IP Address Source to use correct
+ DBus DHCPEnabled type
+
+The Get/Set Lan Configuration "IP Address Source" subcommand got
+broken by phosphor-dbus-interfaces commit 12162be
+
+12162be changed the DBus DHCPEnabled type from boolean to enum
+type. The Get LAN Configuration IP address Source IPMI command did not
+get changed to an enum type prior to 12162be being merged. This commit
+retroactively updates the boolean type to enum type.
+
+Tested:
+
+ipmitool raw 0xc 2 3 4 0 0 # returns correct state
+ipmitool raw 0xc 1 3 4 1 # changes DCHP to Static
+ipmitool raw 0xc 1 3 4 2 # returns Static to DHCP
+
+Assigned a static address via Redfish and tested using:
+ipmitool raw 0xc 2 3 4 0 0 # returns correct state
+
+Returned the NIC to use DHCP via Redfish and tested using:
+ipmitool raw 0xc 2 3 4 0 0 # returns correct state
+
+Change-Id: Ia66f7fcf3d5ad0a383b06658b18e8ce2b282e052
+Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
+---
+ transporthandler.cpp | 97 ++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 79 insertions(+), 18 deletions(-)
+
+diff --git a/transporthandler.cpp b/transporthandler.cpp
+index 16ce2b2..ccc2a97 100644
+--- a/transporthandler.cpp
++++ b/transporthandler.cpp
+@@ -109,6 +109,18 @@ constexpr auto INTF_NEIGHBOR_CREATE_STATIC =
+ constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN";
+ constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create";
+
++static constexpr auto dhcpv4v6 =
++ "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.both";
++static constexpr auto dhcpv6 =
++ "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v6";
++static constexpr auto dhcpv4 =
++ "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.v4";
++static constexpr auto dhcpoff =
++ "xyz.openbmc_project.Network.EthernetInterface.DHCPConf.none";
++
++static std::array<const char*, 4> dhcpEnumerations = {dhcpv4v6, dhcpv4, dhcpv6,
++ dhcpoff};
++
+ /** @brief Generic paramters for different address families */
+ template <int family>
+ struct AddrFamily
+@@ -456,25 +468,63 @@ auto channelCall(uint8_t channel, Args&&... args)
+ *
+ * @param[in] bus - The bus object used for lookups
+ * @param[in] params - The parameters for the channel
+- * @return True if DHCP is enabled, false otherwise
++ * @return string containing an enumerated value
++ * constexpr's dhcpv4v6, dhcpv4, dhcpv6, and dhcpoff
+ */
+-bool getDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
++std::string getDHCPProperty(sdbusplus::bus::bus& bus,
++ const ChannelParams& params)
+ {
+- return std::get<bool>(getDbusProperty(
++ return std::get<std::string>(getDbusProperty(
+ bus, params.service, params.logicalPath, INTF_ETHERNET, "DHCPEnabled"));
+ }
+
+ /** @brief Sets the system value for DHCP on the given interface
+ *
+- * @param[in] bus - The bus object used for lookups
+- * @param[in] params - The parameters for the channel
+- * @param[in] on - Whether or not to enable DHCP
++ * @param[in] bus - The bus object used for lookups
++ * @param[in] params - The parameters for the channel
++ * @param[in] setting - DHCP state to assign (none, v4, v6, both)
+ */
+ void setDHCPProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
+- bool on)
++ const std::string& setting)
+ {
++ auto it = dhcpEnumerations.begin();
++ while (it != dhcpEnumerations.end())
++ {
++ if (*it == setting)
++ {
++ break;
++ }
++ it++;
++ }
++ if (it == dhcpEnumerations.end())
++ {
++ log<level::ERR>("Invalid DHCP setting.",
++ entry("Requested DHCP mode=%s", setting.c_str()));
++ elog<InternalFailure>();
++ }
++
++ std::string dhcp = getDHCPProperty(bus, params);
++ std::string nextDhcp{};
++
++ if (((dhcp == dhcpv4) && (setting == dhcpv6)) ||
++ ((dhcp == dhcpv6) && (setting == dhcpv4)))
++ {
++ // DHCP is enabled independently for IPv4 and IPv6. If IPv4
++ // DHCP is enabled, and a request to add IPv6 is received,
++ // change the DHCPEnabled enum to "both" active. The same
++ // logic is applied if IPV6 is already enabled, and an IPv4
++ // enable request is made.
++ nextDhcp = dhcpv4v6;
++ }
++ else
++ {
++ // "both" enabled -> ipv4 only
++ // "both" enabled -> ipv6 only
++ // "ip4v", "ipv6", or "both" enabled -> no DHCP
++ nextDhcp = setting;
++ }
+ setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
+- "DHCPEnabled", on);
++ "DHCPEnabled", nextDhcp);
+ }
+
+ /** @brief Converts a human readable MAC string into MAC bytes
+@@ -1113,7 +1163,7 @@ void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params)
+ }
+
+ // Clear out any settings on the lower physical interface
+- setDHCPProperty(bus, params, false);
++ setDHCPProperty(bus, params, dhcpoff);
+ }
+
+ /** @brief Creates a new VLAN on the specified interface
+@@ -1401,7 +1451,8 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter,
+ }
+ case LanParam::IP:
+ {
+- if (channelCall<getDHCPProperty>(channel))
++ std::string dhcpSetting = channelCall<getDHCPProperty>(channel);
++ if ((dhcpSetting == dhcpv4) || (dhcpSetting == dhcpv4v6))
+ {
+ return responseCommandNotAvailable();
+ }
+@@ -1431,7 +1482,11 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter,
+ {
+ case IPSrc::DHCP:
+ {
+- channelCall<setDHCPProperty>(channel, true);
++ // The IPSrc IPMI command is only for IPv4
++ // management. Modifying IPv6 state is done using
++ // a completely different Set LAN Configuration
++ // subcommand.
++ channelCall<setDHCPProperty>(channel, dhcpv4);
+ return responseSuccess();
+ }
+ case IPSrc::Unspecified:
+@@ -1439,7 +1494,7 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter,
+ case IPSrc::BIOS:
+ case IPSrc::BMC:
+ {
+- channelCall<setDHCPProperty>(channel, false);
++ channelCall<setDHCPProperty>(channel, dhcpoff);
+ return responseSuccess();
+ }
+ }
+@@ -1464,7 +1519,8 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter,
+ }
+ case LanParam::SubnetMask:
+ {
+- if (channelCall<getDHCPProperty>(channel))
++ std::string dhcpSetting = channelCall<getDHCPProperty>(channel);
++ if ((dhcpSetting == dhcpv4) || (dhcpSetting == dhcpv4v6))
+ {
+ return responseCommandNotAvailable();
+ }
+@@ -1481,7 +1537,8 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter,
+ }
+ case LanParam::Gateway1:
+ {
+- if (channelCall<getDHCPProperty>(channel))
++ std::string dhcpSetting = channelCall<getDHCPProperty>(channel);
++ if ((dhcpSetting == dhcpv4) || (dhcpSetting == dhcpv4v6))
+ {
+ return responseCommandNotAvailable();
+ }
+@@ -1606,7 +1663,8 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter,
+ return responseReqDataLenInvalid();
+ }
+ std::bitset<8> expected;
+- if (channelCall<getDHCPProperty>(channel))
++ std::string dhcp = channelCall<getDHCPProperty>(channel);
++ if ((dhcp == dhcpv4v6) || (dhcp == dhcpv6))
+ {
+ expected[IPv6RouterControlFlag::Dynamic] = 1;
+ }
+@@ -1756,7 +1814,8 @@ RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly,
+ case LanParam::IPSrc:
+ {
+ auto src = IPSrc::Static;
+- if (channelCall<getDHCPProperty>(channel))
++ std::string dhcp = channelCall<getDHCPProperty>(channel);
++ if ((dhcp == dhcpv4) || (dhcp == dhcpv4v6))
+ {
+ src = IPSrc::DHCP;
+ }
+@@ -1877,7 +1936,8 @@ RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly,
+ case LanParam::IPv6RouterControl:
+ {
+ std::bitset<8> control;
+- if (channelCall<getDHCPProperty>(channel))
++ std::string dhcp = channelCall<getDHCPProperty>(channel);
++ if ((dhcp == dhcpv4v6) || (dhcp == dhcpv6))
+ {
+ control[IPv6RouterControlFlag::Dynamic] = 1;
+ }
+@@ -1891,7 +1951,8 @@ RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly,
+ case LanParam::IPv6StaticRouter1IP:
+ {
+ in6_addr gateway{};
+- if (!channelCall<getDHCPProperty>(channel))
++ std::string dhcp = channelCall<getDHCPProperty>(channel);
++ if ((dhcp == dhcpv4) || (dhcp == dhcpoff))
+ {
+ gateway =
+ channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
+--
+2.24.1
+
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..ccf326a91
--- /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,41 @@
+From c1925ab965271875d4e9333be85cdfe8e1516948 Mon Sep 17 00:00:00 2001
+From: Vernon Mauery <vernon.mauery@linux.intel.com>
+Date: Fri, 14 Feb 2020 13:13:06 -0800
+Subject: [PATCH] Fix 'Get System GUID' to use settings UUID
+
+The upstream Get System GUID command looks first for a BMC interface
+and then assumes that the UUID interface is next to that. But that is
+not the case on Intel systems where the system GUID is found in the
+settings daemon.
+
+Change-Id: I924bd05e0a546f2b30288c1faf72157296ab6579
+Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
+---
+ apphandler.cpp | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/apphandler.cpp b/apphandler.cpp
+index dcfda11..780afbc 100644
+--- a/apphandler.cpp
++++ b/apphandler.cpp
+@@ -784,8 +784,6 @@ auto ipmiAppGetBtCapabilities()
+
+ auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>>
+ {
+- static constexpr auto bmcInterface =
+- "xyz.openbmc_project.Inventory.Item.Bmc";
+ static constexpr auto uuidInterface = "xyz.openbmc_project.Common.UUID";
+ static constexpr auto uuidProperty = "UUID";
+
+@@ -794,7 +792,7 @@ auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>>
+ {
+ // Get the Inventory object implementing BMC interface
+ auto busPtr = getSdBus();
+- auto objectInfo = ipmi::getDbusObject(*busPtr, bmcInterface);
++ auto objectInfo = ipmi::getDbusObject(*busPtr, uuidInterface);
+
+ // Read UUID property value from bmcObject
+ // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
+--
+2.17.1
+
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..903ae96a7
--- /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 ad93a6e17310d92ef07b8d367b23c93793562d0f 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 f3aba7f..465eb81 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 = "/xyz/openbmc_project/Ipmi/Channel/ipmi_kcs3";
++constexpr const char* IPMI_INTERFACE = "xyz.openbmc_project.Ipmi.Channel.SMS";
+
+ // For throwing exceptions
+ using namespace phosphor::logging;
+@@ -106,6 +108,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
+@@ -115,9 +131,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
+@@ -131,9 +144,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.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch
new file mode 100644
index 000000000..987e61448
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0056-add-SetInProgress-to-get-set-boot-option-cmd.patch
@@ -0,0 +1,105 @@
+From f9f260391f099b4e67999f9d4ca05cbf9b422baf Mon Sep 17 00:00:00 2001
+From: "Jia, chunhui" <chunhui.jia@linux.intel.com>
+Date: Tue, 19 Mar 2019 16:09:06 +0800
+Subject: [PATCH] add SetInProgress to get/set boot option cmd
+
+It is required by BIOS. BIOS will check setinprogress first.
+If this flag is not supported, BIOS will bypass all boot
+option flow.
+
+Change-Id: Ibb0501ea5bc36c4f1f72339efef03724dd4e613f
+Signed-off-by: Jia, chunhui <chunhui.jia@linux.intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+---
+ chassishandler.cpp | 28 +++++++++++++++++++++++++++-
+ chassishandler.hpp | 3 +++
+ 2 files changed, 30 insertions(+), 1 deletion(-)
+
+diff --git a/chassishandler.cpp b/chassishandler.cpp
+index 305897b..ee23845 100644
+--- a/chassishandler.cpp
++++ b/chassishandler.cpp
+@@ -1399,6 +1399,10 @@ static ipmi_ret_t setBootMode(const Mode::Modes& mode)
+ return IPMI_CC_OK;
+ }
+
++static constexpr uint8_t setComplete = 0x0;
++static constexpr uint8_t setInProgress = 0x1;
++static uint8_t transferStatus = setComplete;
++
+ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request,
+ ipmi_response_t response,
+@@ -1413,11 +1417,21 @@ ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ get_sys_boot_options_t* reqptr = (get_sys_boot_options_t*)request;
+ IpmiValue bootOption = ipmiDefault;
+
++ if (reqptr->parameter ==
++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS))
++ {
++ *data_len =
++ static_cast<uint8_t>(BootOptionResponseSize::SET_IN_PROGRESS);
++ resp->version = SET_PARM_VERSION;
++ resp->parm = static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS);
++ resp->data[0] = transferStatus;
++ return IPMI_CC_OK;
++ }
++
+ std::memset(resp, 0, sizeof(*resp));
+ resp->version = SET_PARM_VERSION;
+ resp->parm = 5;
+ resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME;
+-
+ /*
+ * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
+ * This is the only parameter used by petitboot.
+@@ -1553,6 +1567,18 @@ ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ // This IPMI command does not have any resposne data
+ *data_len = 0;
+
++ if (reqptr->parameter ==
++ static_cast<uint8_t>(BootOptionParameter::SET_IN_PROGRESS))
++ {
++ if ((transferStatus == setInProgress) &&
++ (reqptr->data[0] != setComplete))
++ {
++ return IPMI_CC_FAIL_SET_IN_PROGRESS;
++ }
++ transferStatus = reqptr->data[0];
++ return IPMI_CC_OK;
++ }
++
+ /* 000101
+ * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
+ * This is the only parameter used by petitboot.
+diff --git a/chassishandler.hpp b/chassishandler.hpp
+index dcaf06c..353a929 100644
+--- a/chassishandler.hpp
++++ b/chassishandler.hpp
+@@ -25,6 +25,7 @@ enum ipmi_chassis_return_codes
+ {
+ IPMI_OK = 0x0,
+ IPMI_CC_PARM_NOT_SUPPORTED = 0x80,
++ IPMI_CC_FAIL_SET_IN_PROGRESS = 0x81,
+ };
+
+ // Generic completion codes,
+@@ -46,6 +47,7 @@ enum ipmi_chassis_control_cmds : uint8_t
+ };
+ enum class BootOptionParameter : size_t
+ {
++ SET_IN_PROGRESS = 0x0,
+ BOOT_INFO = 0x4,
+ BOOT_FLAGS = 0x5,
+ OPAL_NETWORK_SETTINGS = 0x61
+@@ -53,6 +55,7 @@ enum class BootOptionParameter : size_t
+
+ enum class BootOptionResponseSize : size_t
+ {
++ SET_IN_PROGRESS = 3,
+ BOOT_FLAGS = 5,
+ OPAL_NETWORK_SETTINGS = 50
+ };
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch
new file mode 100644
index 000000000..bc8c72f13
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch
@@ -0,0 +1,356 @@
+From 1c8cb6b7c99ad85f470aa87095fcfb4de822ddb1 Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@intel.com>
+Date: Wed, 16 Oct 2019 14:24:20 +0800
+Subject: [PATCH 1/1] Move Set SOL config parameter to host-ipmid
+
+Move Set SOL config parameter command from net-ipmid to host-ipmid,
+so that BIOS in Intel platform can enable or disable SOL through KCS.
+Get SOL config parameter command will be moved later.
+
+Tested by:
+With the related change in phospher-ipmi-net and phospher-dbus-interface,
+Run commands:
+ipmitool raw 0x0c 0x21 0x0e 0x00 0x01
+ipmitool raw 0x0c 0x21 0x0e 0x01 0x00
+ipmitool raw 0x0c 0x21 0x0e 0x02 0x03
+ipmitool raw 0x0c 0x21 0x0e 0x03 0x5 0x03
+ipmitool raw 0x0c 0x21 0x0e 0x04 0x5 0x03
+All these commands have correct response and all dbus interface for
+sol command change to same value in above commands.
+After reboot BMC, "Progress" property in dbus interface change back
+to 0 and other properties will not reset to default value.
+
+Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com>
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+---
+ host-ipmid-whitelist.conf | 1 +
+ transporthandler.cpp | 294 ++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 295 insertions(+)
+
+diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
+index 5397115..c93f3b1 100644
+--- a/host-ipmid-whitelist.conf
++++ b/host-ipmid-whitelist.conf
+@@ -41,6 +41,7 @@
+ 0x0A:0x48 //<Storage>:<Get SEL Time>
+ 0x0A:0x49 //<Storage>:<Set SEL Time>
+ 0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters>
++0x0C:0x21 //<Transport>:<Set SOL Configuration Parameters>
+ 0x2C:0x00 //<Group Extension>:<Group Extension Command>
+ 0x2C:0x01 //<Group Extension>:<Get DCMI Capabilities>
+ 0x2C:0x02 //<Group Extension>:<Get Power Reading>
+diff --git a/transporthandler.cpp b/transporthandler.cpp
+index 61065ad..59e38ea 100644
+--- a/transporthandler.cpp
++++ b/transporthandler.cpp
+@@ -1469,8 +1469,298 @@ RspType<message::Payload> getLan(uint4_t channelBits, uint3_t, bool revOnly,
+ } // namespace transport
+ } // namespace ipmi
+
++constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
++constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/";
++
+ void register_netfn_transport_functions() __attribute__((constructor));
+
++static std::string
++ getSOLService(std::shared_ptr<sdbusplus::asio::connection> dbus,
++ const std::string& solPathWitheEthName)
++{
++ static std::string solService{};
++ if (solService.empty())
++ {
++ try
++ {
++ solService =
++ ipmi::getService(*dbus, solInterface, solPathWitheEthName);
++ }
++ catch (const sdbusplus::exception::SdBusError& e)
++ {
++ solService.clear();
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error: get SOL service failed");
++ return solService;
++ }
++ }
++ return solService;
++}
++
++static int setSOLParameter(const std::string& property,
++ const ipmi::Value& value, const uint8_t& channelNum)
++{
++ auto dbus = getSdBus();
++
++ std::string ethdevice = ipmi::getChannelName(channelNum);
++
++ std::string solPathWitheEthName = std::string(solPath) + ethdevice;
++
++ std::string service = getSOLService(dbus, solPathWitheEthName);
++ if (service.empty())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to get SOL service failed");
++ return -1;
++ }
++ try
++ {
++ ipmi::setDbusProperty(*dbus, service, solPathWitheEthName, solInterface,
++ property, value);
++ }
++ catch (sdbusplus::exception_t&)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error setting sol parameter");
++ return -1;
++ }
++
++ return 0;
++}
++
++static int getSOLParameter(const std::string& property, ipmi::Value& value,
++ const uint8_t& channelNum)
++{
++ auto dbus = getSdBus();
++
++ std::string ethdevice = ipmi::getChannelName(channelNum);
++
++ std::string solPathWitheEthName = std::string(solPath) + ethdevice;
++
++ std::string service = getSOLService(dbus, solPathWitheEthName);
++ if (service.empty())
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Unable to get SOL service failed");
++ return -1;
++ }
++ try
++ {
++ value = ipmi::getDbusProperty(*dbus, service, solPathWitheEthName,
++ solInterface, property);
++ }
++ catch (sdbusplus::exception_t&)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error getting sol parameter");
++ return -1;
++ }
++
++ return 0;
++}
++
++static const constexpr uint8_t encryptMask = 0x80;
++static const constexpr uint8_t encryptShift = 7;
++static const constexpr uint8_t authMask = 0x40;
++static const constexpr uint8_t authShift = 6;
++static const constexpr uint8_t privilegeMask = 0xf;
++
++namespace ipmi
++{
++constexpr Cc ccParmNotSupported = 0x80;
++constexpr Cc ccSetInProgressActive = 0x81;
++constexpr Cc ccSystemInfoParameterSetReadOnly = 0x82;
++
++static inline auto responseParmNotSupported()
++{
++ return response(ccParmNotSupported);
++}
++static inline auto responseSetInProgressActive()
++{
++ return response(ccSetInProgressActive);
++}
++static inline auto responseSystemInfoParameterSetReadOnly()
++{
++ return response(ccSystemInfoParameterSetReadOnly);
++}
++
++} // namespace ipmi
++
++namespace sol
++{
++enum class Parameter
++{
++ progress, //!< Set In Progress.
++ enable, //!< SOL Enable.
++ authentication, //!< SOL Authentication.
++ accumulate, //!< Character Accumulate Interval & Send Threshold.
++ retry, //!< SOL Retry.
++ nvbitrate, //!< SOL non-volatile bit rate.
++ vbitrate, //!< SOL volatile bit rate.
++ channel, //!< SOL payload channel.
++ port, //!< SOL payload port.
++};
++
++enum class Privilege : uint8_t
++{
++ highestPriv,
++ callbackPriv,
++ userPriv,
++ operatorPriv,
++ adminPriv,
++ oemPriv,
++};
++
++} // namespace sol
++
++constexpr uint8_t progressMask = 0x03;
++constexpr uint8_t enableMask = 0x01;
++constexpr uint8_t retryMask = 0x07;
++
++ipmi::RspType<> setSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum,
++ uint4_t reserved, uint8_t paramSelector,
++ uint8_t configParamData1,
++ std::optional<uint8_t> configParamData2)
++{
++ ipmi::ChannelInfo chInfo;
++ uint8_t channelNum = ipmi::convertCurrentChannelNum(
++ static_cast<uint8_t>(chNum), ctx->channel);
++ if (reserved != 0 ||
++ (!ipmi::isValidChannel(static_cast<uint8_t>(channelNum))))
++ {
++ return ipmi::responseInvalidFieldRequest();
++ }
++
++ ipmi_ret_t compCode =
++ ipmi::getChannelInfo(static_cast<uint8_t>(channelNum), chInfo);
++ if (compCode != IPMI_CC_OK ||
++ chInfo.mediumType !=
++ static_cast<uint8_t>(ipmi::EChannelMediumType::lan8032))
++ {
++ return ipmi::responseInvalidFieldRequest();
++ }
++
++ switch (static_cast<sol::Parameter>(paramSelector))
++ {
++ case sol::Parameter::progress:
++ {
++ if (configParamData2)
++ {
++ return ipmi::responseReqDataLenInvalid();
++ }
++ uint8_t progress = configParamData1 & progressMask;
++ ipmi::Value currentProgress = 0;
++ if (getSOLParameter("Progress", currentProgress, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++
++ if ((std::get<uint8_t>(currentProgress) == 1) && (progress == 1))
++ {
++ return ipmi::responseSetInProgressActive();
++ }
++
++ if (setSOLParameter("Progress", progress, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ break;
++ }
++ case sol::Parameter::enable:
++ {
++ if (configParamData2)
++ {
++ return ipmi::responseReqDataLenInvalid();
++ }
++ bool enable = configParamData1 & enableMask;
++ if (setSOLParameter("Enable", enable, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ break;
++ }
++ case sol::Parameter::authentication:
++ {
++ if (configParamData2)
++ {
++ return ipmi::responseReqDataLenInvalid();
++ }
++ uint8_t encrypt = (configParamData1 & encryptMask) >> encryptShift;
++ uint8_t auth = (configParamData1 & authMask) >> authShift;
++ uint8_t privilege = configParamData1 & privilegeMask;
++ // For security considering encryption and authentication must be
++ // true.
++ if (!encrypt || !auth)
++ {
++ return ipmi::responseSystemInfoParameterSetReadOnly();
++ }
++ else if (privilege <
++ static_cast<uint8_t>(sol::Privilege::userPriv) ||
++ privilege > static_cast<uint8_t>(sol::Privilege::oemPriv))
++ {
++ return ipmi::responseInvalidFieldRequest();
++ }
++
++ if (setSOLParameter("Privilege", privilege, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++
++ break;
++ }
++ case sol::Parameter::accumulate:
++ {
++ if (!configParamData2)
++ {
++ return ipmi::responseReqDataLenInvalid();
++ }
++ if (*configParamData2 == 0)
++ {
++ return ipmi::responseInvalidFieldRequest();
++ }
++ if (setSOLParameter("AccumulateIntervalMS", configParamData1,
++ channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ if (setSOLParameter("Threshold", *configParamData2, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ break;
++ }
++ case sol::Parameter::retry:
++ {
++ if (!configParamData2)
++ {
++ return ipmi::responseReqDataLenInvalid();
++ }
++ if ((setSOLParameter(
++ "RetryCount",
++ static_cast<uint8_t>(configParamData1 & retryMask),
++ channelNum) < 0) ||
++ (setSOLParameter("RetryIntervalMS", *configParamData2,
++ channelNum) < 0))
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++
++ break;
++ }
++ case sol::Parameter::port:
++ {
++ return ipmi::responseSystemInfoParameterSetReadOnly();
++ }
++ case sol::Parameter::nvbitrate:
++ case sol::Parameter::vbitrate:
++ case sol::Parameter::channel:
++ default:
++ return ipmi::responseParmNotSupported();
++ }
++
++ return ipmi::responseSuccess();
++}
++
+ void register_netfn_transport_functions()
+ {
+ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
+@@ -1479,4 +1769,8 @@ void register_netfn_transport_functions()
+ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
+ ipmi::transport::cmdGetLanConfigParameters,
+ ipmi::Privilege::Operator, ipmi::transport::getLan);
++
++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
++ ipmi::transport::cmdSetSolConfigParameters,
++ ipmi::Privilege::Admin, setSOLConfParams);
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch
new file mode 100644
index 000000000..61ac5fede
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch
@@ -0,0 +1,259 @@
+From b5400c4bc756a800fbeb4cc53117956fb59dc57d Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@intel.com>
+Date: Thu, 11 Jul 2019 00:32:58 +0800
+Subject: [PATCH 1/1] Move Get SOL config parameter to host-ipmid
+
+Move Get SOL config parameter command from net-ipmid to host-ipmid.
+
+Tested:
+Run command ipmitool sol info 1
+Set in progress : set-complete
+Enabled : true
+Force Encryption : false
+Force Authentication : false
+Privilege Level : ADMINISTRATOR
+Character Accumulate Level (ms) : 60
+Character Send Threshold : 96
+Retry Count : 6
+Retry Interval (ms) : 200
+Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting
+Non-Volatile Bit Rate (kbps) : 115.2
+Payload Channel : 1 (0x01)
+Payload Port : 623
+
+Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com>
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+---
+ host-ipmid-whitelist.conf | 1 +
+ transporthandler.cpp | 191 ++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 192 insertions(+)
+
+diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
+index c93f3b1..730437d 100644
+--- a/host-ipmid-whitelist.conf
++++ b/host-ipmid-whitelist.conf
+@@ -42,6 +42,7 @@
+ 0x0A:0x49 //<Storage>:<Set SEL Time>
+ 0x0C:0x02 //<Transport>:<Get LAN Configuration Parameters>
+ 0x0C:0x21 //<Transport>:<Set SOL Configuration Parameters>
++0x0C:0x22 //<Transport>:<Get SOL Configuration Parameters>
+ 0x2C:0x00 //<Group Extension>:<Group Extension Command>
+ 0x2C:0x01 //<Group Extension>:<Get DCMI Capabilities>
+ 0x2C:0x02 //<Group Extension>:<Get Power Reading>
+diff --git a/transporthandler.cpp b/transporthandler.cpp
+index 59e38ea..b64953f 100644
+--- a/transporthandler.cpp
++++ b/transporthandler.cpp
+@@ -1559,6 +1559,28 @@ static int getSOLParameter(const std::string& property, ipmi::Value& value,
+ return 0;
+ }
+
++constexpr const char* consoleInterface = "xyz.openbmc_project.console";
++constexpr const char* consolePath = "/xyz/openbmc_project/console";
++static int getSOLBaudRate(ipmi::Value& value)
++{
++ auto dbus = getSdBus();
++
++ try
++ {
++ value =
++ ipmi::getDbusProperty(*dbus, "xyz.openbmc_project.console",
++ consolePath, consoleInterface, "baudrate");
++ }
++ catch (sdbusplus::exception_t&)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error getting sol baud rate");
++ return -1;
++ }
++
++ return 0;
++}
++
+ static const constexpr uint8_t encryptMask = 0x80;
+ static const constexpr uint8_t encryptShift = 7;
+ static const constexpr uint8_t authMask = 0x40;
+@@ -1761,6 +1783,171 @@ ipmi::RspType<> setSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum,
+ return ipmi::responseSuccess();
+ }
+
++static const constexpr uint8_t retryCountMask = 0x07;
++static constexpr uint16_t ipmiStdPort = 623;
++static constexpr uint8_t solParameterRevision = 0x11;
++ipmi::RspType<uint8_t, std::optional<uint8_t>, std::optional<uint8_t>>
++ getSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum, uint3_t reserved,
++ bool getParamRev, uint8_t paramSelector,
++ uint8_t setSelector, uint8_t blockSelector)
++{
++ ipmi::ChannelInfo chInfo;
++ uint8_t channelNum = ipmi::convertCurrentChannelNum(
++ static_cast<uint8_t>(chNum), ctx->channel);
++ if (reserved != 0 ||
++ (!ipmi::isValidChannel(static_cast<uint8_t>(channelNum))) ||
++ (ipmi::EChannelSessSupported::none ==
++ ipmi::getChannelSessionSupport(static_cast<uint8_t>(channelNum))))
++ {
++ return ipmi::responseInvalidFieldRequest();
++ }
++ ipmi_ret_t compCode =
++ ipmi::getChannelInfo(static_cast<uint8_t>(channelNum), chInfo);
++ if (compCode != IPMI_CC_OK ||
++ chInfo.mediumType !=
++ static_cast<uint8_t>(ipmi::EChannelMediumType::lan8032))
++ {
++ return ipmi::responseInvalidFieldRequest();
++ }
++
++ if (getParamRev)
++ {
++ return ipmi::responseSuccess(solParameterRevision, std::nullopt,
++ std::nullopt);
++ }
++
++ ipmi::Value value;
++ switch (static_cast<sol::Parameter>(paramSelector))
++ {
++ case sol::Parameter::progress:
++ {
++ if (getSOLParameter("Progress", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ return ipmi::responseSuccess(
++ solParameterRevision, std::get<uint8_t>(value), std::nullopt);
++ }
++ case sol::Parameter::enable:
++ {
++ if (getSOLParameter("Enable", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ return ipmi::responseSuccess(
++ solParameterRevision,
++ static_cast<uint8_t>(std::get<bool>(value)), std::nullopt);
++ }
++ case sol::Parameter::authentication:
++ {
++ uint8_t authentication = 0;
++ if (getSOLParameter("Privilege", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ authentication = (std::get<uint8_t>(value) & 0x0f);
++
++ if (getSOLParameter("ForceAuthentication", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ authentication |=
++ (static_cast<uint8_t>(std::get<bool>(value)) << 6);
++
++ if (getSOLParameter("ForceEncryption", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ authentication |=
++ (static_cast<uint8_t>(std::get<bool>(value)) << 7);
++ return ipmi::responseSuccess(solParameterRevision, authentication,
++ std::nullopt);
++ }
++ case sol::Parameter::accumulate:
++ {
++ if (getSOLParameter("AccumulateIntervalMS", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++
++ ipmi::Value value1;
++ if (getSOLParameter("Threshold", value1, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ return ipmi::responseSuccess(solParameterRevision,
++ std::get<uint8_t>(value),
++ std::get<uint8_t>(value1));
++ }
++ case sol::Parameter::retry:
++ {
++ if (getSOLParameter("RetryCount", value, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++
++ ipmi::Value value1;
++ if (getSOLParameter("RetryIntervalMS", value1, channelNum) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ return ipmi::responseSuccess(
++ solParameterRevision, std::get<uint8_t>(value) & retryCountMask,
++ std::get<uint8_t>(value1));
++ }
++ case sol::Parameter::channel:
++ {
++ return ipmi::responseSuccess(solParameterRevision, channelNum,
++ std::nullopt);
++ }
++ case sol::Parameter::port:
++ {
++ uint16_t port = htole16(ipmiStdPort);
++ auto buffer = reinterpret_cast<const uint8_t*>(&port);
++ return ipmi::responseSuccess(solParameterRevision, buffer[0],
++ buffer[1]);
++ }
++ case sol::Parameter::nvbitrate:
++ {
++ if (getSOLBaudRate(value) < 0)
++ {
++ return ipmi::responseUnspecifiedError();
++ }
++ uint8_t bitRate = 0;
++ uint32_t* pBaudRate = std::get_if<uint32_t>(&value);
++ if (!pBaudRate)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Failed to get valid baud rate from D-Bus interface");
++ }
++ switch (*pBaudRate)
++ {
++ case 9600:
++ bitRate = 0x06;
++ break;
++ case 19200:
++ bitRate = 0x07;
++ break;
++ case 38400:
++ bitRate = 0x08;
++ break;
++ case 57600:
++ bitRate = 0x09;
++ break;
++ case 115200:
++ bitRate = 0x0a;
++ break;
++ default:
++ break;
++ }
++ return ipmi::responseSuccess(solParameterRevision, bitRate,
++ std::nullopt);
++ }
++ default:
++ return ipmi::responseParmNotSupported();
++ }
++}
++
+ void register_netfn_transport_functions()
+ {
+ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
+@@ -1773,4 +1960,8 @@ void register_netfn_transport_functions()
+ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
+ ipmi::transport::cmdSetSolConfigParameters,
+ ipmi::Privilege::Admin, setSOLConfParams);
++
++ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
++ ipmi::transport::cmdGetSolConfigParameters,
++ ipmi::Privilege::User, getSOLConfParams);
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch
new file mode 100644
index 000000000..96e45cad3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0062-Update-IPMI-Chassis-Control-command.patch
@@ -0,0 +1,291 @@
+From 92bdbcd90a445e49ba2f8e483d44ec41152d32b4 Mon Sep 17 00:00:00 2001
+From: "Jason M. Bills" <jason.m.bills@linux.intel.com>
+Date: Mon, 3 Jun 2019 17:01:47 -0700
+Subject: [PATCH] Update IPMI Chassis Control command
+
+This change updates the IPMI Chassis Control command to use the new
+host state transitions. This allows each chassis control action
+to more closely follow the behavior defined in the IPMI spec.
+
+ref: https://gerrit.openbmc-project.xyz/c/openbmc/docs/+/22358
+
+Tested:
+Ran each IPMI chassis control command to confirm the expected
+behavior:
+ipmitool power on: system is powered-on
+ipmitool power off: system is forced off
+ipmitool power cycle: system is forced off then powered-on
+ipmitool power reset: system is hard reset
+ipmitool power soft: soft power-off requested from system software
+
+Change-Id: Ic9fba3ca4abd9a758eb88f1e6ee09f7ca64ff80a
+Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
+---
+ chassishandler.cpp | 206 +++++++++++++----------------------------------------
+ 1 file changed, 50 insertions(+), 156 deletions(-)
+
+diff --git a/chassishandler.cpp b/chassishandler.cpp
+index 0326806..8bfab88 100644
+--- a/chassishandler.cpp
++++ b/chassishandler.cpp
+@@ -31,6 +31,7 @@
+ #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
+ #include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
+ #include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp>
++#include <xyz/openbmc_project/State/Chassis/server.hpp>
+ #include <xyz/openbmc_project/State/Host/server.hpp>
+ #include <xyz/openbmc_project/State/PowerOnHours/server.hpp>
+
+@@ -717,59 +718,63 @@ ipmi::RspType<> ipmiSetChassisCap(bool intrusion, bool fpLockout,
+ //------------------------------------------
+ // Calls into Host State Manager Dbus object
+ //------------------------------------------
+-int initiate_state_transition(State::Host::Transition transition)
++int initiateHostStateTransition(State::Host::Transition transition)
+ {
+ // OpenBMC Host State Manager dbus framework
+- constexpr auto HOST_STATE_MANAGER_ROOT = "/xyz/openbmc_project/state/host0";
+- constexpr auto HOST_STATE_MANAGER_IFACE = "xyz.openbmc_project.State.Host";
+- constexpr auto DBUS_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
+- constexpr auto PROPERTY = "RequestedHostTransition";
++ constexpr auto hostStatePath = "/xyz/openbmc_project/state/host0";
++ constexpr auto hostStateIntf = "xyz.openbmc_project.State.Host";
+
+- // sd_bus error
+- int rc = 0;
+- char* busname = NULL;
++ auto service = ipmi::getService(*getSdBus(), hostStateIntf, hostStatePath);
+
+- // SD Bus error report mechanism.
+- sd_bus_error bus_error = SD_BUS_ERROR_NULL;
++ // Convert to string equivalent of the passed in transition enum.
++ auto request = State::convertForMessage(transition);
+
+- // Gets a hook onto either a SYSTEM or SESSION bus
+- sd_bus* bus_type = ipmid_get_sd_bus_connection();
+- rc = mapper_get_service(bus_type, HOST_STATE_MANAGER_ROOT, &busname);
+- if (rc < 0)
++ try
++ {
++ ipmi::setDbusProperty(*getSdBus(), service, hostStatePath,
++ hostStateIntf, "RequestedHostTransition",
++ request);
++ }
++ catch (std::exception& e)
+ {
+ log<level::ERR>(
+- "Failed to get bus name",
+- entry("ERRNO=0x%X, OBJPATH=%s", -rc, HOST_STATE_MANAGER_ROOT));
+- return rc;
++ "Failed to initiate transition",
++ entry("EXCEPTION=%s, REQUEST=%s", e.what(), request.c_str()));
++ return -1;
+ }
++ return 0;
++}
++
++//------------------------------------------
++// Calls into Chassis State Manager Dbus object
++//------------------------------------------
++int initiateChassisStateTransition(State::Chassis::Transition transition)
++{
++ // OpenBMC Chassis State Manager dbus framework
++ constexpr auto chassisStatePath = "/xyz/openbmc_project/state/chassis0";
++ constexpr auto chassisStateIntf = "xyz.openbmc_project.State.Chassis";
++
++ auto service =
++ ipmi::getService(*getSdBus(), chassisStateIntf, chassisStatePath);
+
+ // Convert to string equivalent of the passed in transition enum.
+ auto request = State::convertForMessage(transition);
+
+- rc = sd_bus_call_method(bus_type, // On the system bus
+- busname, // Service to contact
+- HOST_STATE_MANAGER_ROOT, // Object path
+- DBUS_PROPERTY_IFACE, // Interface name
+- "Set", // Method to be called
+- &bus_error, // object to return error
+- nullptr, // Response buffer if any
+- "ssv", // Takes 3 arguments
+- HOST_STATE_MANAGER_IFACE, PROPERTY, "s",
+- request.c_str());
+- if (rc < 0)
+- {
+- log<level::ERR>("Failed to initiate transition",
+- entry("ERRNO=0x%X, REQUEST=%s", -rc, request.c_str()));
++ try
++ {
++ ipmi::setDbusProperty(*getSdBus(), service, chassisStatePath,
++ chassisStateIntf, "RequestedPowerTransition",
++ request);
+ }
+- else
++ catch (std::exception& e)
+ {
+- log<level::INFO>("Transition request initiated successfully");
++ log<level::ERR>(
++ "Failed to initiate transition",
++ entry("EXCEPTION=%s, REQUEST=%s", e.what(), request.c_str()));
++ return -1;
+ }
+
+- sd_bus_error_free(&bus_error);
+- free(busname);
+-
+- return rc;
++ return 0;
+ }
+
+ //------------------------------------------
+@@ -1071,76 +1076,6 @@ ipmi::RspType<bool, // Power is on
+ diagButtonDisableAllow, sleepButtonDisableAllow);
+ }
+
+-//-------------------------------------------------------------
+-// Send a command to SoftPowerOff application to stop any timer
+-//-------------------------------------------------------------
+-int stop_soft_off_timer()
+-{
+- constexpr auto iface = "org.freedesktop.DBus.Properties";
+- constexpr auto soft_off_iface = "xyz.openbmc_project.Ipmi.Internal."
+- "SoftPowerOff";
+-
+- constexpr auto property = "ResponseReceived";
+- constexpr auto value = "xyz.openbmc_project.Ipmi.Internal."
+- "SoftPowerOff.HostResponse.HostShutdown";
+-
+- // Get the system bus where most system services are provided.
+- auto bus = ipmid_get_sd_bus_connection();
+-
+- // Get the service name
+- // TODO openbmc/openbmc#1661 - Mapper refactor
+- //
+- // See openbmc/openbmc#1743 for some details but high level summary is that
+- // for now the code will directly call the soft off interface due to a
+- // race condition with mapper usage
+- //
+- // char *busname = nullptr;
+- // auto r = mapper_get_service(bus, SOFTOFF_OBJPATH, &busname);
+- // if (r < 0)
+- //{
+- // fprintf(stderr, "Failed to get %s bus name: %s\n",
+- // SOFTOFF_OBJPATH, -r);
+- // return r;
+- //}
+-
+- // No error object or reply expected.
+- int rc = sd_bus_call_method(bus, SOFTOFF_BUSNAME, SOFTOFF_OBJPATH, iface,
+- "Set", nullptr, nullptr, "ssv", soft_off_iface,
+- property, "s", value);
+- if (rc < 0)
+- {
+- log<level::ERR>("Failed to set property in SoftPowerOff object",
+- entry("ERRNO=0x%X", -rc));
+- }
+-
+- // TODO openbmc/openbmc#1661 - Mapper refactor
+- // free(busname);
+- return rc;
+-}
+-
+-//----------------------------------------------------------------------
+-// Create file to indicate there is no need for softoff notification to host
+-//----------------------------------------------------------------------
+-void indicate_no_softoff_needed()
+-{
+- fs::path path{HOST_INBAND_REQUEST_DIR};
+- if (!fs::is_directory(path))
+- {
+- fs::create_directory(path);
+- }
+-
+- // Add the host instance (default 0 for now) to the file name
+- std::string file{HOST_INBAND_REQUEST_FILE};
+- auto size = std::snprintf(nullptr, 0, file.c_str(), 0);
+- size++; // null
+- std::unique_ptr<char[]> buf(new char[size]);
+- std::snprintf(buf.get(), size, file.c_str(), 0);
+-
+- // Append file name to directory and create it
+- path /= buf.get();
+- std::ofstream(path.c_str());
+-}
+-
+ /** @brief Implementation of chassis control command
+ *
+ * @param - chassisControl command byte
+@@ -1153,63 +1088,22 @@ ipmi::RspType<> ipmiChassisControl(uint8_t chassisControl)
+ switch (chassisControl)
+ {
+ case CMD_POWER_ON:
+- rc = initiate_state_transition(State::Host::Transition::On);
++ rc = initiateHostStateTransition(State::Host::Transition::On);
+ break;
+ case CMD_POWER_OFF:
+- // This path would be hit in 2 conditions.
+- // 1: When user asks for power off using ipmi chassis command 0x04
+- // 2: Host asking for power off post shutting down.
+-
+- // If it's a host requested power off, then need to nudge Softoff
+- // application that it needs to stop the watchdog timer if running.
+- // If it is a user requested power off, then this is not really
+- // needed. But then we need to differentiate between user and host
+- // calling this same command
+-
+- // For now, we are going ahead with trying to nudge the soft off and
+- // interpret the failure to do so as a non softoff case
+- rc = stop_soft_off_timer();
+-
+- // Only request the Off transition if the soft power off
+- // application is not running
+- if (rc < 0)
+- {
+- // First create a file to indicate to the soft off application
+- // that it should not run. Not doing this will result in State
+- // manager doing a default soft power off when asked for power
+- // off.
+- indicate_no_softoff_needed();
+-
+- // Now request the shutdown
+- rc = initiate_state_transition(State::Host::Transition::Off);
+- }
+- else
+- {
+- log<level::INFO>("Soft off is running, so let shutdown target "
+- "stop the host");
+- }
++ rc =
++ initiateChassisStateTransition(State::Chassis::Transition::Off);
+ break;
+-
+ case CMD_HARD_RESET:
++ rc = initiateHostStateTransition(
++ State::Host::Transition::ForceWarmReboot);
++ break;
+ case CMD_POWER_CYCLE:
+- // SPEC has a section that says certain implementations can trigger
+- // PowerOn if power is Off when a command to power cycle is
+- // requested
+-
+- // First create a file to indicate to the soft off application
+- // that it should not run since this is a direct user initiated
+- // power reboot request (i.e. a reboot request that is not
+- // originating via a soft power off SMS request)
+- indicate_no_softoff_needed();
+-
+- rc = initiate_state_transition(State::Host::Transition::Reboot);
++ rc = initiateHostStateTransition(State::Host::Transition::Reboot);
+ break;
+-
+ case CMD_SOFT_OFF_VIA_OVER_TEMP:
+- // Request Host State Manager to do a soft power off
+- rc = initiate_state_transition(State::Host::Transition::Off);
++ rc = initiateHostStateTransition(State::Host::Transition::Off);
+ break;
+-
+ case CMD_PULSE_DIAGNOSTIC_INTR:
+ rc = setNmiProperty(true);
+ break;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch
new file mode 100644
index 000000000..aac0850ea
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch
@@ -0,0 +1,140 @@
+From d9c89943d7b0aa00ee99b7c11278ac272a47a790 Mon Sep 17 00:00:00 2001
+From: Ren Yu <yux.ren@intel.com>
+Date: Tue, 28 May 2019 17:11:17 +0800
+Subject: [PATCH] Save the pre-timeout interrupt in dbus property
+
+Get the watchdog pre-timeout interrupt value from ipmi watchdog set command,
+and store it into dbus property.
+
+Tested:
+Config IPMI watchdog: BIOS FRB2 Power Cycle after 1 seconds:
+ipmitool raw 0x06 0x24 0x01 0x13 0x0 0x2 0xa 0x00
+Start watchdog:
+Ipmitool mc watchdog reset
+Check the watchdog pre-timeout interrupt in below:
+https://BMCIP/redfish/v1/Systems/system/LogServices/EventLog/Entries
+
+Signed-off-by: Ren Yu <yux.ren@intel.com>
+---
+ app/watchdog.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ app/watchdog_service.cpp | 6 ++++++
+ app/watchdog_service.hpp | 9 +++++++++
+ 3 files changed, 62 insertions(+)
+
+diff --git a/app/watchdog.cpp b/app/watchdog.cpp
+index 2ffaae3..e9b7a9c 100644
+--- a/app/watchdog.cpp
++++ b/app/watchdog.cpp
+@@ -81,6 +81,7 @@ ipmi::RspType<> ipmiAppResetWatchdogTimer()
+
+ static constexpr uint8_t wd_dont_stop = 0x1 << 6;
+ static constexpr uint8_t wd_timeout_action_mask = 0x3;
++static constexpr uint8_t wdPreTimeoutInterruptMask = 0x3;
+
+ static constexpr uint8_t wdTimerUseMask = 0x7;
+ static constexpr uint8_t wdTimerUseResTimer1 = 0x0;
+@@ -130,6 +131,45 @@ WatchdogService::Action ipmiActionToWdAction(IpmiAction ipmi_action)
+ }
+ }
+
++enum class IpmiPreTimeoutInterrupt : uint8_t
++{
++ None = 0x0,
++ SMI = 0x1,
++ NMI = 0x2,
++ MI = 0x3,
++};
++/** @brief Converts an IPMI Watchdog PreTimeoutInterrupt to DBUS defined action
++ * @param[in] ipmi_action The IPMI Watchdog PreTimeoutInterrupt
++ * @return The Watchdog PreTimeoutInterrupt that the ipmi_action maps to
++ */
++WatchdogService::PreTimeoutInterruptAction ipmiPreTimeoutInterruptToWdAction(
++ IpmiPreTimeoutInterrupt ipmiPreTimeOutInterrupt)
++{
++ switch (ipmiPreTimeOutInterrupt)
++ {
++ case IpmiPreTimeoutInterrupt::None:
++ {
++ return WatchdogService::PreTimeoutInterruptAction::None;
++ }
++ case IpmiPreTimeoutInterrupt::SMI:
++ {
++ return WatchdogService::PreTimeoutInterruptAction::SMI;
++ }
++ case IpmiPreTimeoutInterrupt::NMI:
++ {
++ return WatchdogService::PreTimeoutInterruptAction::NMI;
++ }
++ case IpmiPreTimeoutInterrupt::MI:
++ {
++ return WatchdogService::PreTimeoutInterruptAction::MI;
++ }
++ default:
++ {
++ throw std::domain_error("IPMI PreTimeoutInterrupt is invalid");
++ }
++ }
++}
++
+ enum class IpmiTimerUse : uint8_t
+ {
+ Reserved = 0x0,
+@@ -257,6 +297,13 @@ ipmi_ret_t ipmi_app_watchdog_set(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ // Mark as initialized so that future resets behave correctly
+ wd_service.setInitialized(true);
+
++ // pretimeOutAction
++ const auto ipmiPreTimeoutInterrupt =
++ static_cast<IpmiPreTimeoutInterrupt>(wdPreTimeoutInterruptMask &
++ (static_cast<uint8_t>(preTimeoutInterrupt)));
++ wd_service.setPreTimeoutInterrupt(
++ ipmiPreTimeoutInterruptToWdAction(ipmiPreTimeoutInterrupt));
++
+ lastCallSuccessful = true;
+ return IPMI_CC_OK;
+ }
+diff --git a/app/watchdog_service.cpp b/app/watchdog_service.cpp
+index 77663b4..0c4ea28 100644
+--- a/app/watchdog_service.cpp
++++ b/app/watchdog_service.cpp
+@@ -203,3 +203,9 @@ void WatchdogService::setTimeRemaining(uint64_t timeRemaining)
+ {
+ setProperty("TimeRemaining", timeRemaining);
+ }
++
++void WatchdogService::setPreTimeoutInterrupt(
++ PreTimeoutInterruptAction preTimeoutInterrupt)
++{
++ setProperty("PreTimeoutInterrupt", convertForMessage(preTimeoutInterrupt));
++}
+\ No newline at end of file
+diff --git a/app/watchdog_service.hpp b/app/watchdog_service.hpp
+index ed64a3c..b550f37 100644
+--- a/app/watchdog_service.hpp
++++ b/app/watchdog_service.hpp
+@@ -15,6 +15,8 @@ class WatchdogService
+
+ using Action =
+ sdbusplus::xyz::openbmc_project::State::server::Watchdog::Action;
++ using PreTimeoutInterruptAction = sdbusplus::xyz::openbmc_project::State::
++ server::Watchdog::PreTimeoutInterruptAction;
+ using TimerUse =
+ sdbusplus::xyz::openbmc_project::State::server::Watchdog::TimerUse;
+
+@@ -99,6 +101,13 @@ class WatchdogService
+ */
+ void setTimeRemaining(uint64_t timeRemaining);
+
++ /** @brief Sets the value of the PreTimeoutInterrupt property on the host
++ * watchdog
++ *
++ * @param[in] PreTimeoutInterrupt - The new PreTimeoutInterrupt value
++ */
++ void setPreTimeoutInterrupt(PreTimeoutInterruptAction preTimeoutInterrupt);
++
+ private:
+ /** @brief sdbusplus handle */
+ sdbusplus::bus::bus bus;
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service
new file mode 100644
index 000000000..1e45ee6c9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/phosphor-ipmi-host.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Phosphor Inband IPMI
+
+[Service]
+Restart=always
+RestartSec=5
+StartLimitBurst=10
+ExecStart=/usr/bin/env ipmid
+SyslogIdentifier=ipmid
+RuntimeDirectory = ipmi
+RuntimeDirectoryPreserve = yes
+StateDirectory = ipmi
+
+[Install]
+WantedBy=basic.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp
new file mode 100644
index 000000000..856a80fbc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host/transporthandler_oem.cpp
@@ -0,0 +1,147 @@
+/* Copyright 2019 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 "dcmihandler.hpp"
+
+#include <cstdint>
+#include <ipmid/api-types.hpp>
+#include <ipmid/api.hpp>
+#include <ipmid/message.hpp>
+#include <ipmid/message/types.hpp>
+#include <ipmid/utils.hpp>
+#include <vector>
+
+enum class oemLanParam : uint8_t
+{
+ intelHostnameConfig = 0xc7,
+};
+
+constexpr size_t IpmiHostnameLen = 16;
+constexpr uint8_t CurrentRevision = 0x11; // Current rev per IPMI Spec 2.0
+
+constexpr ipmi::Cc ccParamNotSupported = 0x80;
+constexpr ipmi::Cc ccUnprintable = 0x90;
+
+namespace ipmi::transport
+{
+
+constexpr auto validHostnameChars =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX"
+ "YZ0123456789-";
+constexpr int lanOemHostnameLength = 64;
+
+RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
+{
+ std::vector<uint8_t> dataBytes;
+ switch (static_cast<oemLanParam>(parameter))
+ {
+ case oemLanParam::intelHostnameConfig:
+ {
+ static std::array<uint8_t, lanOemHostnameLength> blockData;
+ uint8_t block = 0;
+ uint8_t complete = 0;
+ if ((req.unpack(block, complete, dataBytes) != 0) ||
+ (!req.fullyUnpacked()))
+ {
+ return responseReqDataLenInvalid();
+ }
+
+ size_t numDataBytes = req.size() - 4;
+ if ((numDataBytes > IpmiHostnameLen) ||
+ (!complete && (numDataBytes < IpmiHostnameLen)))
+ {
+ return responseReqDataLenInvalid();
+ }
+
+ if (!((block > 0) && (block < 5)) ||
+ ((complete != 0) && (complete != 1)))
+ {
+ return responseInvalidFieldRequest();
+ }
+
+ if (block == 1)
+ {
+ blockData.fill(0);
+ }
+
+ std::copy(dataBytes.begin(), dataBytes.end(),
+ blockData.data() + ((block - 1) * IpmiHostnameLen));
+ if (complete)
+ {
+ blockData[lanOemHostnameLength - 1] = 0;
+ // check hostname, and write it
+ std::string newHostname(
+ reinterpret_cast<char*>(blockData.data()),
+ lanOemHostnameLength);
+ size_t firstNull = newHostname.find_first_of('\0');
+ if (newHostname.find_first_not_of(validHostnameChars) !=
+ firstNull)
+ {
+ return response(ccUnprintable);
+ }
+ std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
+ ipmi::setDbusProperty(*busp, ::dcmi::networkServiceName,
+ ::dcmi::networkConfigObj,
+ ::dcmi::networkConfigIntf,
+ ::dcmi::hostNameProp, newHostname);
+ }
+ return responseSuccess();
+ }
+ default:
+ return response(ccParamNotSupported);
+ }
+ return response(ccParamNotSupported);
+}
+
+RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
+ uint8_t set, uint8_t block)
+{
+ message::Payload message;
+ message.pack(CurrentRevision);
+ oemLanParam param = static_cast<oemLanParam>(parameter);
+ switch (param)
+ {
+ case oemLanParam::intelHostnameConfig:
+ {
+ if (set != 0)
+ {
+ return responseInvalidFieldRequest();
+ }
+ if ((block < 1) || (block > 4))
+ {
+ return responseInvalidFieldRequest();
+ }
+ std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
+ auto service = ipmi::getService(*busp, ::dcmi::networkConfigIntf,
+ ::dcmi::networkConfigObj);
+ auto value = ipmi::getDbusProperty(
+ *busp, service, ::dcmi::networkConfigObj,
+ ::dcmi::networkConfigIntf, ::dcmi::hostNameProp);
+ std::string hostname = std::get<std::string>(value);
+ std::array<char, IpmiHostnameLen> buf = {0};
+ size_t head = (block - 1) * IpmiHostnameLen;
+ if (head < hostname.size())
+ {
+ size_t numToCopy = hostname.size() - head;
+ numToCopy = std::min(IpmiHostnameLen, numToCopy);
+ hostname.copy(buf.data(), numToCopy, head);
+ }
+ message.pack(buf);
+ return responseSuccess(std::move(message));
+ }
+ }
+ return response(ccParamNotSupported);
+}
+} // namespace ipmi::transport
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..6f27959a2
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-host_%.bbappend
@@ -0,0 +1,44 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+PROJECT_SRC_DIR := "${THISDIR}/${PN}"
+
+# latest upstream HEAD until meta-phosphor autobumps
+SRCREV = "6ba8d31525130dbb5ef5b60336993ef7b50a8f51"
+
+SRC_URI += "file://phosphor-ipmi-host.service \
+ file://0010-fix-get-system-GUID-ipmi-command.patch \
+ file://0053-Fix-keep-looping-issue-when-entering-OS.patch \
+ file://0056-add-SetInProgress-to-get-set-boot-option-cmd.patch \
+ file://0059-Move-Set-SOL-config-parameter-to-host-ipmid.patch \
+ file://0060-Move-Get-SOL-config-parameter-to-host-ipmid.patch \
+ file://0062-Update-IPMI-Chassis-Control-command.patch \
+ file://0063-Save-the-pre-timeout-interrupt-in-dbus-property.patch \
+ file://0001-Modify-Get-Lan-Configuration-IP-Address-Source-to-us.patch \
+ "
+
+EXTRA_OECONF_append = " --disable-i2c-whitelist-check"
+EXTRA_OECONF_append = " --enable-transport-oem=yes"
+EXTRA_OECONF_append = " --disable-boot-flag-safe-mode-support"
+EXTRA_OECONF_append = " --disable-ipmi-whitelist"
+
+RDEPENDS_${PN}_remove = "clear-once"
+
+# remove the softpoweroff service since we do not need it
+SYSTEMD_SERVICE_${PN}_remove += " \
+ xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service"
+
+SYSTEMD_LINK_${PN}_remove += " \
+ ../xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service:obmc-host-shutdown@0.target.requires/xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service \
+ "
+FILES_${PN}_remove = " \
+ ${systemd_unitdir}/system/obmc-host-shutdown@0.target.requires/ \
+ ${systemd_unitdir}/system/obmc-host-shutdown@0.target.requires/xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service \
+ "
+
+do_compile_prepend(){
+ cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
+}
+
+do_install_append(){
+ rm -f ${D}/${bindir}/phosphor-softpoweroff
+ rm -f ${S}/transporthandler_oem.cpp
+}
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..69b730221
--- /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 = "a86059348fe133725f4616f3e46ff0d555db4039"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules
new file mode 100644
index 000000000..0a64b58db
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs/99-ipmi-kcs.rules
@@ -0,0 +1,2 @@
+KERNEL=="ipmi-kcs3", SYMLINK+="ipmi_kcs3"
+KERNEL=="ipmi-kcs4", SYMLINK+="ipmi_kcs4"
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..adb1cc551
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-kcs_%.bbappend
@@ -0,0 +1,21 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+#SYSTEMD_SUBSTITUTIONS_remove = "KCS_DEVICE:${KCS_DEVICE}:${DBUS_SERVICE_${PN}}"
+
+# Default kcs device is ipmi-kcs3; this is SMS.
+# Add SMM kcs device instance
+
+# Replace the '-' to '_', since Dbus object/interface names do not allow '-'.
+KCS_DEVICE = "ipmi_kcs3"
+SMM_DEVICE = "ipmi_kcs4"
+SYSTEMD_SERVICE_${PN}_append = " ${PN}@${SMM_DEVICE}.service "
+
+SRC_URI = "git://github.com/openbmc/kcsbridge.git"
+SRCREV = "46525ae48db23333493ac927c12ed13a0e663de5"
+
+SRC_URI += "file://99-ipmi-kcs.rules"
+
+do_install_append() {
+ install -d ${D}${base_libdir}/udev/rules.d
+ install -m 0644 ${WORKDIR}/99-ipmi-kcs.rules ${D}${base_libdir}/udev/rules.d/
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch
new file mode 100644
index 000000000..867b3aba6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/00010-Change-Authentication-Parameter.patch
@@ -0,0 +1,40 @@
+From 0fd38eb0a155cb11ff5a5452087f68c46d12111b Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@intel.com>
+Date: Thu, 28 Mar 2019 18:10:40 +0800
+Subject: [PATCH] Change Authentication Parameter
+
+Seprate D-bus interface Authentication to forceAuthentication,
+forceEncryption, Privilege according to the related change in
+sol-dbus-interface.
+
+Tested By:
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0x03
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0xc2
+The parameters has been changed to the request data in above command.
+
+Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com>
+---
+ sol/sol_manager.cpp | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp
+index de36723..0bd837e 100644
+--- a/sol/sol_manager.cpp
++++ b/sol/sol_manager.cpp
+@@ -195,8 +195,12 @@ void Manager::updateSOLParameter()
+
+ enable = std::get<bool>(properties["Enable"]);
+
++ forceEncrypt = std::get<bool>(properties["ForceEncryption"]);
++
++ forceAuth = std::get<bool>(properties["ForceAuthentication"]);
++
+ solMinPrivilege = static_cast<session::Privilege>(
+- std::get<uint8_t>(properties["Authentication"]));
++ std::get<uint8_t>(properties["Privilege"]));
+
+ accumulateInterval =
+ std::get<uint8_t>((properties["AccumulateIntervalMS"])) *
+--
+2.16.2
+
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..0ad625a1f
--- /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/0009-Add-dbus-interface-for-sol-commands.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch
new file mode 100644
index 000000000..dc7f7357c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0009-Add-dbus-interface-for-sol-commands.patch
@@ -0,0 +1,319 @@
+From 97c21a556702a0d65096b30c07ef23f15cb6a7d9 Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@intel.com>
+Date: Wed, 3 Jul 2019 07:39:47 +0800
+Subject: [PATCH] Add dbus interface for sol commands
+
+Add dbus interface for sol config parameters so that after move set/get
+sol config parameter command from net-ipmid to host-ipmid, the command
+can send config parameters to net-ipmid sol service through the dbus
+interface.
+
+Tested by:
+busctl introspect xyz.openbmc_project.Settings /xyz/openbmc_project
+/network/host0/sol can show correct dbus properties of sol parameters.
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x00 0x01
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x01 0x00
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x02 0x83
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x03 0x5 0x03
+ipmitool -I lanplus -H x -U x -P x raw 0x0c 0x21 0x0e 0x04 0x5 0x03
+all these commands can change the dbus properties as the value in
+above commands.
+Before and after run these commands, ipmitool -I lanplus -H x -U x
+-P x sol activate can start sol session correctly.
+After reboot BMC, "Progress" property in dbus interface change back
+to 0 and other properties will not reset to default value.
+
+Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com>
+---
+ command/payload_cmds.cpp | 3 ++
+ command/sol_cmds.cpp | 84 -------------------------------
+ sol/sol_manager.cpp | 125 +++++++++++++++++++++++++++++++++++++++++++++++
+ sol/sol_manager.hpp | 1 +
+ sol_module.cpp | 6 ---
+ 5 files changed, 129 insertions(+), 90 deletions(-)
+
+diff --git a/command/payload_cmds.cpp b/command/payload_cmds.cpp
+index c32a510..17167a7 100644
+--- a/command/payload_cmds.cpp
++++ b/command/payload_cmds.cpp
+@@ -34,6 +34,9 @@ std::vector<uint8_t> activatePayload(const std::vector<uint8_t>& inPayload,
+ return outPayload;
+ }
+
++ std::get<sol::Manager&>(singletonPool)
++ .updateSOLParameter(ipmi::convertCurrentChannelNum(
++ ipmi::currentChNum, getInterfaceIndex()));
+ if (!std::get<sol::Manager&>(singletonPool).enable)
+ {
+ response->completionCode = IPMI_CC_PAYLOAD_TYPE_DISABLED;
+diff --git a/command/sol_cmds.cpp b/command/sol_cmds.cpp
+index a8fa410..804b5ea 100644
+--- a/command/sol_cmds.cpp
++++ b/command/sol_cmds.cpp
+@@ -65,90 +65,6 @@ void activating(uint8_t payloadInstance, uint32_t sessionID)
+ outPayload);
+ }
+
+-std::vector<uint8_t> setConfParams(const std::vector<uint8_t>& inPayload,
+- const message::Handler& handler)
+-{
+- std::vector<uint8_t> outPayload(sizeof(SetConfParamsResponse));
+- auto request =
+- reinterpret_cast<const SetConfParamsRequest*>(inPayload.data());
+- auto response = reinterpret_cast<SetConfParamsResponse*>(outPayload.data());
+- response->completionCode = IPMI_CC_OK;
+-
+- switch (static_cast<Parameter>(request->paramSelector))
+- {
+- case Parameter::PROGRESS:
+- {
+- uint8_t progress = request->value & progressMask;
+- std::get<sol::Manager&>(singletonPool).progress = progress;
+- break;
+- }
+- case Parameter::ENABLE:
+- {
+- bool enable = request->value & enableMask;
+- std::get<sol::Manager&>(singletonPool).enable = enable;
+- break;
+- }
+- case Parameter::AUTHENTICATION:
+- {
+- if (!request->auth.auth || !request->auth.encrypt)
+- {
+- response->completionCode = ipmiCCWriteReadParameter;
+- }
+- else if (request->auth.privilege <
+- static_cast<uint8_t>(session::Privilege::USER) ||
+- request->auth.privilege >
+- static_cast<uint8_t>(session::Privilege::OEM))
+- {
+- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
+- }
+- else
+- {
+- std::get<sol::Manager&>(singletonPool).solMinPrivilege =
+- static_cast<session::Privilege>(request->auth.privilege);
+- }
+- break;
+- }
+- case Parameter::ACCUMULATE:
+- {
+- using namespace std::chrono_literals;
+-
+- if (request->acc.threshold == 0)
+- {
+- response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST;
+- break;
+- }
+-
+- std::get<sol::Manager&>(singletonPool).accumulateInterval =
+- request->acc.interval * sol::accIntervalFactor * 1ms;
+- std::get<sol::Manager&>(singletonPool).sendThreshold =
+- request->acc.threshold;
+- break;
+- }
+- case Parameter::RETRY:
+- {
+- using namespace std::chrono_literals;
+-
+- std::get<sol::Manager&>(singletonPool).retryCount =
+- request->retry.count;
+- std::get<sol::Manager&>(singletonPool).retryInterval =
+- request->retry.interval * sol::retryIntervalFactor * 1ms;
+- break;
+- }
+- case Parameter::PORT:
+- {
+- response->completionCode = ipmiCCWriteReadParameter;
+- break;
+- }
+- case Parameter::NVBITRATE:
+- case Parameter::VBITRATE:
+- case Parameter::CHANNEL:
+- default:
+- response->completionCode = ipmiCCParamNotSupported;
+- }
+-
+- return outPayload;
+-}
+-
+ std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload,
+ const message::Handler& handler)
+ {
+diff --git a/sol/sol_manager.cpp b/sol/sol_manager.cpp
+index 2046fe4..eedd28a 100644
+--- a/sol/sol_manager.cpp
++++ b/sol/sol_manager.cpp
+@@ -12,7 +12,13 @@
+ #include <boost/asio/write.hpp>
+ #include <chrono>
+ #include <cmath>
++#include <ipmid/utils.hpp>
+ #include <phosphor-logging/log.hpp>
++#include <sdbusplus/message/types.hpp>
++
++constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
++constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/";
++constexpr const char* PROP_INTF = "org.freedesktop.DBus.Properties";
+
+ namespace sol
+ {
+@@ -93,6 +99,125 @@ void Manager::stopHostConsole()
+ }
+ }
+
++std::string getService(sdbusplus::bus::bus& bus, const std::string& intf,
++ const std::string& path)
++{
++ auto mapperCall =
++ bus.new_method_call("xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetObject");
++
++ mapperCall.append(path);
++ mapperCall.append(std::vector<std::string>({intf}));
++
++ std::map<std::string, std::vector<std::string>> mapperResponse;
++
++ try
++ {
++ auto mapperResponseMsg = bus.call(mapperCall);
++ mapperResponseMsg.read(mapperResponse);
++ }
++ catch (sdbusplus::exception_t&)
++ {
++ throw std::runtime_error("ERROR in mapper call");
++ }
++
++ if (mapperResponse.begin() == mapperResponse.end())
++ {
++ throw std::runtime_error("ERROR in reading the mapper response");
++ }
++
++ return mapperResponse.begin()->first;
++}
++
++ipmi::PropertyMap getAllDbusProperties(sdbusplus::bus::bus& bus,
++ const std::string& service,
++ const std::string& objPath,
++ const std::string& interface)
++{
++ ipmi::PropertyMap properties;
++
++ sdbusplus::message::message method = bus.new_method_call(
++ service.c_str(), objPath.c_str(), PROP_INTF, "GetAll");
++
++ method.append(interface);
++
++ try
++ {
++ sdbusplus::message::message reply = bus.call(method);
++ reply.read(properties);
++ }
++ catch (sdbusplus::exception_t&)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Failed to get all properties",
++ phosphor::logging::entry("PATH=%s", objPath.c_str()),
++ phosphor::logging::entry("INTERFACE=%s", interface.c_str()));
++ throw std::runtime_error("ERROR in reading proerties");
++ }
++
++ return properties;
++}
++
++void Manager::updateSOLParameter(uint8_t channelNum)
++{
++ std::variant<uint8_t, bool> value;
++ sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
++ static std::string solService{};
++ ipmi::PropertyMap properties;
++ std::string ethdevice = ipmi::getChannelName(channelNum);
++ std::string solPathWitheEthName = solPath + ethdevice;
++ if (solService.empty())
++ {
++ try
++ {
++ solService = getService(dbus, solInterface, solPathWitheEthName);
++ }
++ catch (const std::runtime_error& e)
++ {
++ solService.clear();
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error: get SOL service failed");
++ return;
++ }
++ }
++ try
++ {
++ properties = getAllDbusProperties(dbus, solService, solPathWitheEthName,
++ solInterface);
++ }
++ catch (const std::runtime_error&)
++ {
++ phosphor::logging::log<phosphor::logging::level::ERR>(
++ "Error setting sol parameter");
++ return;
++ }
++
++ progress = std::get<uint8_t>(properties["Progress"]);
++
++ enable = std::get<bool>(properties["Enable"]);
++
++ forceEncrypt = std::get<bool>(properties["ForceEncryption"]);
++
++ forceAuth = std::get<bool>(properties["ForceAuthentication"]);
++
++ solMinPrivilege = static_cast<session::Privilege>(
++ std::get<uint8_t>(properties["Privilege"]));
++
++ accumulateInterval =
++ std::get<uint8_t>((properties["AccumulateIntervalMS"])) *
++ sol::accIntervalFactor * 1ms;
++
++ sendThreshold = std::get<uint8_t>(properties["Threshold"]);
++
++ retryCount = std::get<uint8_t>(properties["RetryCount"]);
++
++ retryInterval = std::get<uint8_t>(properties["RetryIntervalMS"]) *
++ sol::retryIntervalFactor * 1ms;
++
++ return;
++}
++
+ void Manager::startPayloadInstance(uint8_t payloadInstance,
+ session::SessionID sessionID)
+ {
+diff --git a/sol/sol_manager.hpp b/sol/sol_manager.hpp
+index 5d96890..00da9fb 100644
+--- a/sol/sol_manager.hpp
++++ b/sol/sol_manager.hpp
+@@ -248,6 +248,7 @@ class Manager
+ * @return 0 on success and errno on failure.
+ */
+ int writeConsoleSocket(const std::vector<uint8_t>& input) const;
++ void updateSOLParameter(uint8_t channelNum);
+
+ private:
+ SOLPayloadMap payloadMap;
+diff --git a/sol_module.cpp b/sol_module.cpp
+index 8200e74..2b1fb46 100644
+--- a/sol_module.cpp
++++ b/sol_module.cpp
+@@ -42,12 +42,6 @@ void registerCommands()
+ &getPayloadInfo,
+ session::Privilege::USER,
+ false},
+- // Set SOL Configuration Parameters
+- {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) |
+- static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x21},
+- &setConfParams,
+- session::Privilege::ADMIN,
+- false},
+ // Get SOL Configuration Parameters
+ {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) |
+ static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x22},
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch
new file mode 100644
index 000000000..da173704b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net/0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch
@@ -0,0 +1,336 @@
+From a36f181163974b2da0a954fc97a89fb2cdbd7287 Mon Sep 17 00:00:00 2001
+From: Cheng C Yang <cheng.c.yang@intel.com>
+Date: Tue, 30 Apr 2019 05:35:31 +0800
+Subject: [PATCH] Remove Get SOL Config Command from Netipmid
+
+Since Get SOL Config Parameter command already exists in host-ipmid, and
+can be shared to net channel, remove this command from net-ipmid.
+
+Tested:
+Run ipmitool -I lanplus -H xxx -U root -P 0penBmc sol info, the command
+returns the same result as ipmitool sol info as below.
+Info: SOL parameter 'Nonvolatile Bitrate (5)' not supported
+Info: SOL parameter 'Volatile Bitrate (6)' not supported
+Info: SOL parameter 'Payload Channel (7)' not supported - defaulting to 0x0e
+Set in progress : set-complete
+Enabled : true
+Force Encryption : true
+Force Authentication : true
+Privilege Level : USER
+Character Accumulate Level (ms) : 100
+Character Send Threshold : 1
+Retry Count : 3
+Retry Interval (ms) : 100
+Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting
+Non-Volatile Bit Rate (kbps) : IPMI-Over-Serial-Setting
+Payload Channel : 14 (0x0e)
+Payload Port : 623
+
+Signed-off-by: Cheng C Yang <cheng.c.yang@intel.com>
+---
+ command/sol_cmds.cpp | 91 ----------------------------
+ command/sol_cmds.hpp | 168 ---------------------------------------------------
+ sol_module.cpp | 6 --
+ 3 files changed, 265 deletions(-)
+
+diff --git a/command/sol_cmds.cpp b/command/sol_cmds.cpp
+index 804b5ea..8b2d041 100644
+--- a/command/sol_cmds.cpp
++++ b/command/sol_cmds.cpp
+@@ -65,97 +65,6 @@ void activating(uint8_t payloadInstance, uint32_t sessionID)
+ outPayload);
+ }
+
+-std::vector<uint8_t> getConfParams(const std::vector<uint8_t>& inPayload,
+- const message::Handler& handler)
+-{
+- std::vector<uint8_t> outPayload(sizeof(GetConfParamsResponse));
+- auto request =
+- reinterpret_cast<const GetConfParamsRequest*>(inPayload.data());
+- auto response = reinterpret_cast<GetConfParamsResponse*>(outPayload.data());
+- response->completionCode = IPMI_CC_OK;
+- response->paramRev = parameterRevision;
+-
+- if (request->getParamRev)
+- {
+- return outPayload;
+- }
+-
+- switch (static_cast<Parameter>(request->paramSelector))
+- {
+- case Parameter::PROGRESS:
+- {
+- outPayload.push_back(
+- std::get<sol::Manager&>(singletonPool).progress);
+- break;
+- }
+- case Parameter::ENABLE:
+- {
+- outPayload.push_back(std::get<sol::Manager&>(singletonPool).enable);
+- break;
+- }
+- case Parameter::AUTHENTICATION:
+- {
+- Auth value{0};
+-
+- value.encrypt = std::get<sol::Manager&>(singletonPool).forceEncrypt;
+- value.auth = std::get<sol::Manager&>(singletonPool).forceAuth;
+- value.privilege = static_cast<uint8_t>(
+- std::get<sol::Manager&>(singletonPool).solMinPrivilege);
+- auto buffer = reinterpret_cast<const uint8_t*>(&value);
+-
+- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload));
+- break;
+- }
+- case Parameter::ACCUMULATE:
+- {
+- Accumulate value{0};
+-
+- value.interval = std::get<sol::Manager&>(singletonPool)
+- .accumulateInterval.count() /
+- sol::accIntervalFactor;
+- value.threshold =
+- std::get<sol::Manager&>(singletonPool).sendThreshold;
+- auto buffer = reinterpret_cast<const uint8_t*>(&value);
+-
+- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload));
+- break;
+- }
+- case Parameter::RETRY:
+- {
+- Retry value{0};
+-
+- value.count = std::get<sol::Manager&>(singletonPool).retryCount;
+- value.interval =
+- std::get<sol::Manager&>(singletonPool).retryInterval.count() /
+- sol::retryIntervalFactor;
+- auto buffer = reinterpret_cast<const uint8_t*>(&value);
+-
+- std::copy_n(buffer, sizeof(value), std::back_inserter(outPayload));
+- break;
+- }
+- case Parameter::PORT:
+- {
+- auto port = endian::to_ipmi<uint16_t>(IPMI_STD_PORT);
+- auto buffer = reinterpret_cast<const uint8_t*>(&port);
+-
+- std::copy_n(buffer, sizeof(port), std::back_inserter(outPayload));
+- break;
+- }
+- case Parameter::CHANNEL:
+- {
+- outPayload.push_back(
+- std::get<sol::Manager&>(singletonPool).channel);
+- break;
+- }
+- case Parameter::NVBITRATE:
+- case Parameter::VBITRATE:
+- default:
+- response->completionCode = ipmiCCParamNotSupported;
+- }
+-
+- return outPayload;
+-}
+-
+ } // namespace command
+
+ } // namespace sol
+diff --git a/command/sol_cmds.hpp b/command/sol_cmds.hpp
+index 182b73e..10cbf25 100644
+--- a/command/sol_cmds.hpp
++++ b/command/sol_cmds.hpp
+@@ -62,174 +62,6 @@ struct ActivatingRequest
+ */
+ void activating(uint8_t payloadInstance, uint32_t sessionID);
+
+-/** @enum Parameter
+- *
+- * SOL parameters are volatile, they are initialized by the SOL manager.
+- * They can be read using Get SOL configuration parameters command and updated
+- * using Set SOL configuration parameters command.
+- */
+-enum class Parameter
+-{
+- PROGRESS, //!< Set In Progress.
+- ENABLE, //!< SOL Enable.
+- AUTHENTICATION, //!< SOL Authentication.
+- ACCUMULATE, //!< Character Accumulate Interval & Send Threshold.
+- RETRY, //!< SOL Retry.
+- NVBITRATE, //!< SOL non-volatile bit rate.
+- VBITRATE, //!< SOL volatile bit rate.
+- CHANNEL, //!< SOL payload channel.
+- PORT, //!< SOL payload port.
+-};
+-
+-constexpr uint8_t progressMask = 0x03;
+-constexpr uint8_t enableMask = 0x01;
+-
+-/** @struct Auth
+- *
+- * SOL authentication parameter.
+- */
+-struct Auth
+-{
+-#if BYTE_ORDER == LITTLE_ENDIAN
+- uint8_t privilege : 4; //!< SOL privilege level.
+- uint8_t reserved : 2; //!< Reserved.
+- uint8_t auth : 1; //!< Force SOL payload Authentication.
+- uint8_t encrypt : 1; //!< Force SOL payload encryption.
+-#endif
+-
+-#if BYTE_ORDER == BIG_ENDIAN
+- uint8_t encrypt : 1; //!< Force SOL payload encryption.
+- uint8_t auth : 1; //!< Force SOL payload Authentication.
+- uint8_t reserved : 2; //!< Reserved.
+- uint8_t privilege : 4; //!< SOL privilege level.
+-#endif
+-} __attribute__((packed));
+-
+-/** @struct Accumulate
+- *
+- * Character accumulate interval & Character send threshold.
+- */
+-struct Accumulate
+-{
+- uint8_t interval; //!< Character accumulate interval.
+- uint8_t threshold; //!< Character send threshold.
+-} __attribute__((packed));
+-
+-constexpr uint8_t retryCountMask = 0x07;
+-
+-/** @struct Retry
+- *
+- * SOL retry count and interval.
+- */
+-struct Retry
+-{
+-#if BYTE_ORDER == LITTLE_ENDIAN
+- uint8_t count : 3; //!< SOL retry count.
+- uint8_t reserved : 5; //!< Reserved.
+-#endif
+-
+-#if BYTE_ORDER == BIG_ENDIAN
+- uint8_t reserved : 5; //!< Reserved.
+- uint8_t count : 3; //!< SOL retry count.
+-#endif
+-
+- uint8_t interval; //!< SOL retry interval.
+-} __attribute__((packed));
+-
+-constexpr uint8_t ipmiCCParamNotSupported = 0x80;
+-constexpr uint8_t ipmiCCInvalidSetInProgress = 0x81;
+-constexpr uint8_t ipmiCCWriteReadParameter = 0x82;
+-constexpr uint8_t ipmiCCReadWriteParameter = 0x83;
+-constexpr uint8_t parameterRevision = 0x11;
+-
+-/** @struct SetConfParamsRequest
+- *
+- * IPMI payload for Set SOL configuration parameters command request.
+- */
+-struct SetConfParamsRequest
+-{
+-#if BYTE_ORDER == LITTLE_ENDIAN
+- uint8_t channelNumber : 4; //!< Channel number.
+- uint8_t reserved : 4; //!< Reserved.
+-#endif
+-
+-#if BYTE_ORDER == BIG_ENDIAN
+- uint8_t reserved : 4; //!< Reserved.
+- uint8_t channelNumber : 4; //!< Channel number.
+-#endif
+-
+- uint8_t paramSelector; //!< Parameter selector.
+- union
+- {
+- uint8_t value; //!< Represents one byte SOL parameters.
+- struct Accumulate acc; //!< Character accumulate values.
+- struct Retry retry; //!< Retry values.
+- struct Auth auth; //!< Authentication parameters.
+- };
+-} __attribute__((packed));
+-
+-/** @struct SetConfParamsResponse
+- *
+- * IPMI payload for Set SOL configuration parameters command response.
+- */
+-struct SetConfParamsResponse
+-{
+- uint8_t completionCode; //!< Completion code.
+-} __attribute__((packed));
+-
+-/** @brief Set SOL configuration parameters command.
+- *
+- * @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> setConfParams(const std::vector<uint8_t>& inPayload,
+- const message::Handler& handler);
+-
+-/** @struct GetConfParamsRequest
+- *
+- * IPMI payload for Get SOL configuration parameters command request.
+- */
+-struct GetConfParamsRequest
+-{
+-#if BYTE_ORDER == LITTLE_ENDIAN
+- uint8_t channelNum : 4; //!< Channel number.
+- uint8_t reserved : 3; //!< Reserved.
+- uint8_t getParamRev : 1; //!< Get parameter or Get parameter revision
+-#endif
+-
+-#if BYTE_ORDER == BIG_ENDIAN
+- uint8_t getParamRev : 1; //!< Get parameter or Get parameter revision
+- uint8_t reserved : 3; //!< Reserved.
+- uint8_t channelNum : 4; //!< Channel number.
+-#endif
+-
+- uint8_t paramSelector; //!< Parameter selector.
+- uint8_t setSelector; //!< Set selector.
+- uint8_t blockSelector; //!< Block selector.
+-} __attribute__((packed));
+-
+-/** @struct GetConfParamsResponse
+- *
+- * IPMI payload for Get SOL configuration parameters command response.
+- */
+-struct GetConfParamsResponse
+-{
+- uint8_t completionCode; //!< Completion code.
+- uint8_t paramRev; //!< Parameter revision.
+-} __attribute__((packed));
+-
+-/** @brief Get SOL configuration parameters command.
+- *
+- * @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> getConfParams(const std::vector<uint8_t>& inPayload,
+- const message::Handler& handler);
+-
+ } // namespace command
+
+ } // namespace sol
+diff --git a/sol_module.cpp b/sol_module.cpp
+index 2b1fb46..6da82c0 100644
+--- a/sol_module.cpp
++++ b/sol_module.cpp
+@@ -42,12 +42,6 @@ void registerCommands()
+ &getPayloadInfo,
+ session::Privilege::USER,
+ false},
+- // Get SOL Configuration Parameters
+- {{(static_cast<uint32_t>(message::PayloadType::IPMI) << 16) |
+- static_cast<uint16_t>(::command::NetFns::TRANSPORT) | 0x22},
+- &getConfParams,
+- session::Privilege::USER,
+- false},
+ };
+
+ for (const auto& iter : commands)
+--
+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..6ea4aa960
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-net_%.bbappend
@@ -0,0 +1,26 @@
+inherit useradd
+
+# TODO: This should be removed, once up-stream bump up
+# issue is resolved
+SRC_URI += "git://github.com/openbmc/phosphor-net-ipmid"
+SRCREV = "9979e9971e17c974f29ec9ab720f5482308c119c"
+
+USERADD_PACKAGES = "${PN}"
+# add a group called ipmi
+GROUPADD_PARAM_${PN} = "ipmi "
+
+# Default rmcpp iface is eth0; channel 1
+# Add channel 2 instance (eth1)
+RMCPP_EXTRA = "eth1"
+SYSTEMD_SERVICE_${PN} += " \
+ ${PN}@${RMCPP_EXTRA}.service \
+ ${PN}@${RMCPP_EXTRA}.socket \
+ "
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += " file://0006-Modify-dbus-namespace-of-chassis-control-for-guid.patch \
+ file://0009-Add-dbus-interface-for-sol-commands.patch \
+ file://0011-Remove-Get-SOL-Config-Command-from-Netipmid.patch \
+ "
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend
new file mode 100644
index 000000000..72d991c7e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%.bbappend
@@ -0,0 +1 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-ipmi-sensor-inventory%/config.yaml
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/ipmi/phosphor-node-manager-proxy_git.bb
new file mode 100644
index 000000000..36d65fd72
--- /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://github.com/Intel-BMC/node-manager;protocol=ssh"
+SRCREV = "de212d839bb515939bd089c66072e4fcf33b8653"
+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/id-led-off/id-led-off.service b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.service
new file mode 100644
index 000000000..51e59c614
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=turn off the ID LED when BMC is ready
+Wants=multi-user.target
+After=multi-user.target
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/id-led-off.sh
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh
new file mode 100755
index 000000000..b609fc0ea
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off/id-led-off.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+busctl set-property "xyz.openbmc_project.LED.GroupManager" \
+"/xyz/openbmc_project/led/groups/enclosure_identify" \
+"xyz.openbmc_project.Led.Group" "Asserted" b false
+
+busctl set-property "xyz.openbmc_project.LED.GroupManager" \
+"/xyz/openbmc_project/led/groups/enclosure_identify_blink" \
+"xyz.openbmc_project.Led.Group" "Asserted" b false
+
+busctl set-property "xyz.openbmc_project.LED.Controller.identify" \
+"/xyz/openbmc_project/led/physical/identify" \
+"xyz.openbmc_project.Led.Physical" "State" s "xyz.openbmc_project.Led.Physical.Action.Off"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb
new file mode 100644
index 000000000..a1d20c2bc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/id-led-off_git.bb
@@ -0,0 +1,24 @@
+SUMMARY = "Turn off the ID LED"
+DESCRIPTION = "Script to turn off the ID LED after BMC is ready"
+
+S = "${WORKDIR}"
+SRC_URI = "file://id-led-off.sh \
+ file://id-led-off.service \
+ "
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+RDEPENDS_${PN} += "bash"
+
+inherit systemd
+
+FILES_${PN} += "${systemd_system_unitdir}/id-led-off.service"
+
+do_install() {
+ install -d ${D}${systemd_system_unitdir}
+ install -m 0644 ${WORKDIR}/id-led-off.service ${D}${systemd_system_unitdir}
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/id-led-off.sh ${D}/${bindir}/id-led-off.sh
+}
+
+SYSTEMD_SERVICE_${PN} += " id-led-off.service"
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 100644
index 000000000..533df68a4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/leds/intel-led-manager-config/led.yaml
@@ -0,0 +1,48 @@
+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'
+
+enclosure_identify_blink:
+ identify:
+ Action: 'Blink'
+
+cpu0_fault:
+ cpu0fault:
+ Action: 'On'
+
+cpu1_fault:
+ cpu1fault:
+ Action: 'On'
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-manager/multi-node-manager.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-manager/multi-node-manager.bb
new file mode 100644
index 000000000..f6a6b1f1b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-manager/multi-node-manager.bb
@@ -0,0 +1,17 @@
+SUMMARY = "Multi node manager"
+DESCRIPTION = "Daemon to handle chassis level shared resources on multi-node platform"
+
+SRC_URI = "git://github.com/Intel-BMC/multi-node-manager.git;protocol=ssh"
+SRCREV = "34d959285a3ca12c4bfefa4040d82d571c78843b"
+
+S = "${WORKDIR}/git/"
+
+PV = "0.1+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SYSTEMD_SERVICE_${PN} = "multi-node-manager.service"
+
+DEPENDS = "boost sdbusplus phosphor-logging i2c-tools"
+inherit cmake systemd
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb
new file mode 100644
index 000000000..c47a581f6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl.bb
@@ -0,0 +1,27 @@
+SUMMARY = "Multi-node Non-legacy"
+DESCRIPTION = "New systemd target for non-legacy nodes on multi-node platform"
+
+inherit systemd
+
+SYSTEMD_SERVICE_${PN} = "multi-node-nl.target"
+SYSTEMD_SERVICE_${PN} += "nonLegacyNode.service"
+
+S = "${WORKDIR}"
+SRC_URI = "file://multi-node-nl.target \
+ file://nonLegacyNode.service \
+ file://nonLegacyNode.sh \
+ "
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+RDEPENDS_${PN} = "bash"
+
+do_install_append() {
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/nonLegacyNode.sh ${D}/${bindir}/nonLegacyNode.sh
+
+ install -d ${D}${base_libdir}/systemd/system
+ install -m 0644 ${S}/multi-node-nl.target ${D}${base_libdir}/systemd/system
+ install -m 0644 ${S}/nonLegacyNode.service ${D}${base_libdir}/systemd/system
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target
new file mode 100644
index 000000000..32b50532f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/multi-node-nl.target
@@ -0,0 +1,4 @@
+[Unit]
+Description=Target for non-legacy node in multi-node system
+Documentation=man:systemd.special(7)
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service
new file mode 100644
index 000000000..8e3d07ba4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Non Legacy node
+
+[Service]
+ExecStart=/usr/bin/nonLegacyNode.sh
+Type=exec
+
+[Install]
+WantedBy=multi-node-nl.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh
new file mode 100755
index 000000000..28a6bbe2a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/multi-node-nl/multi-node-nl/nonLegacyNode.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+PWM_FILE="/sys/class/hwmon/hwmon0/pwm"
+FAN_SPEED=$((255 * 80 / 100))
+
+set_fan_speed() {
+ local idx=0
+ for ((idx=1; idx<=8; idx++))
+ do
+ if [ -f $PWM_FILE$idx ]; then
+ echo $FAN_SPEED > $PWM_FILE$idx
+ fi
+ done
+}
+
+$(set_fan_speed)
+
+#Stop power control service in NL mode
+systemctl stop xyz.openbmc_project.Chassis.Control.Power.service
+
+export TERM=xterm
+# Autologin root user to serial console (ttyS4) on boot
+exec /sbin/agetty -a root -J -8 -L ttyS4 115200 $TERM
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb
new file mode 100644
index 000000000..48f740637
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/phosphor-u-boot-mgr/phosphor-u-boot-mgr_git.bb
@@ -0,0 +1,18 @@
+SUMMARY = "Phosphor U-Boot environment manager"
+DESCRIPTION = "Daemon to read or write U-Boot environment variables"
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327"
+
+SRC_URI = "git://github.com/openbmc/phosphor-u-boot-env-mgr.git;protocol=ssh"
+
+SRCREV = "7a36277b6fdf33a554a4f9e2258e39d1696b00c2"
+
+inherit cmake systemd
+SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.U_Boot.Environment.Manager.service"
+
+DEPENDS = "boost sdbusplus phosphor-logging"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb
new file mode 100644
index 000000000..f7bec2af9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/libmctp-intel_git.bb
@@ -0,0 +1,16 @@
+SUMMARY = "libmctp_intel"
+DESCRIPTION = "Implementation of MCTP(DMTF DSP0236)"
+
+SRC_URI = "git://github.com/Intel-BMC/libmctp.git;protocol=ssh"
+SRCREV = "9f0aa081fdcc1ad5a8ca9025dbd0a559a68f4005"
+
+S = "${WORKDIR}/git/"
+
+PV = "1.0+git${SRCPV}"
+
+LICENSE = "Apache-2.0 | GPLv2"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=0d30807bb7a4f16d36e96b78f9ed8fae"
+
+inherit cmake
+
+DEPENDS += "i2c-tools"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb
new file mode 100644
index 000000000..d9a2297ac
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/pmci/mctpd.bb
@@ -0,0 +1,32 @@
+SUMMARY = "MCTP Daemon"
+DESCRIPTION = "Implementation of MCTP (DTMF DSP0236)"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SRC_URI = "git://github.com/Intel-BMC/pmci.git;protocol=ssh"
+SRCREV = "34e98dc5e6bac78ccee86fb1ea1837b9ef1360a5"
+
+S = "${WORKDIR}/git/mctpd/"
+
+PV = "1.0+git${SRCPV}"
+
+inherit cmake systemd
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+DEPENDS += " \
+ libmctp-intel \
+ systemd \
+ sdbusplus \
+ phosphor-logging \
+ boost \
+ i2c-tools \
+ cli11 \
+ nlohmann-json \
+ gtest \
+ "
+SMBUS_BINDING = "smbus"
+
+FILES_${PN} += "${systemd_system_unitdir}/xyz.openbmc_project.mctpd@.service"
+SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.mctpd@${SMBUS_BINDING}.service"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend
new file mode 100644
index 000000000..dc22b3c95
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts.bbappend
@@ -0,0 +1,3 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI = "file://init" \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init
new file mode 100755
index 000000000..e954d7757
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/preinit-mounts/preinit-mounts/init
@@ -0,0 +1,258 @@
+#!/bin/sh
+
+# Copyright 2017-2019 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# provide a couple of places in the RO root filesystem
+# that can be made RW with an overlayfs
+
+log() {
+ [ -c /dev/kmsg ] && echo "init: $@" > /dev/kmsg
+ echo "init: $@"
+}
+
+# start with /proc and /tmp mounted
+[ -e /proc/mounts ] || mount -t proc proc /proc
+# FIXME: add size limits to /tmp
+grep -q /tmp /proc/mounts || mount -t tmpfs -o rw,nosuid,nodev tmp /tmp
+grep -q /sys /proc/mounts || mount -t sysfs -o rw,nosuid,nodev,noexec sys /sys
+
+# fix up /srv to be RW
+mkdir -p /tmp/srv
+mount --bind /tmp/srv /srv
+
+if grep -q debug-init /proc/cmdline; then
+ exec > /tmp/init.log 2>&1
+ set -x
+ env
+else
+ # silent bob
+ exec >/dev/null 2>&1
+fi
+
+# list of things that need to be rw at boot
+NV_OVERLAYS="/etc /var /home"
+
+# place to mount the overlay backing store
+OVERLAY_MNT=/tmp/.overlay
+OVERLAY_SIZE=16384
+# place to mount NV
+RWFS_MNT=/tmp/.rwfs
+# NV overlay storage
+OVERLAY_SYNC=${RWFS_MNT}/.overlay
+
+if grep -q "$RWFS_MNT" /proc/mounts; then
+ # quit - we have already run
+ exit 0
+fi
+mkdir -p "$OVERLAY_MNT"
+# TODO: remount the overlay with a size limit?
+# mount -t tmpfs -o rw,size=${OVERLAY_SIZE} oltmp ${OVERLAY_MNT}
+
+mtd_by_name() {
+ local name="$1"
+ local mtd="/dev/$(grep "$name" /proc/mtd | cut -d : -f 1)"
+ echo "$mtd"
+}
+
+mtdnum_by_name() {
+ local name="$1"
+ local mtdnum="$(grep "$name" /proc/mtd | cut -c 4)"
+ echo "$mtdnum"
+}
+
+NV_MTD=rwfs
+NV_MTD_DEV="$(mtd_by_name ${NV_MTD})"
+NV_MTD_NUM="$(mtdnum_by_name ${NV_MTD})"
+
+nvrw() {
+ local p="$1"
+ # Clear the work dir doing overlay mount
+ rm -rf "${OVERLAY_MNT}${p}.work"
+ mkdir -p "${OVERLAY_MNT}${p}" "${OVERLAY_MNT}${p}.work"
+ local mname=$(echo "ol${p}" | sed 's,/,,g')
+ local opts="lowerdir=${p},upperdir=${OVERLAY_MNT}${p},workdir=${OVERLAY_MNT}${p}.work,sync"
+ mount -t overlay -o "$opts" "$mname" "$p"
+}
+
+targeted_clean() {
+ log "restore-defaults: targeted_clean"
+ # Do not delete FRU info, ssh/ssl certs, or machine-id
+ (
+ cd "${OVERLAY_SYNC}/etc"
+ find . ! -regex '.*\(/ssl\|/dropbear\|/machine-id\(_bkup\)\?\|/fru\).*' -exec rm -rf {} +
+ )
+ # nothing should be in the workdir, but clear it just in case
+ rm -rf "${OVERLAY_SYNC}/etc.work"
+
+ # clean everything out of /home
+ rm -rf "${OVERLAY_SYNC}/home" "${OVERLAY_SYNC}/home.work"
+
+ # clean everything out of /var
+ rm -rf "${OVERLAY_SYNC}/var" "${OVERLAY_SYNC}/var.work"
+
+ echo "Files remaining: $(find $OVERLAY_SYNC/)"
+ sync
+}
+
+full_clean() {
+ log "restore-defaults: full_clean"
+ local OVL=''
+ for OVL in $NV_OVERLAYS; do
+ rm -rf "${OVERLAY_SYNC}${OVL}" "${OVERLAY_SYNC}${OVL}.work"
+ done
+ sync
+}
+
+reformat_jffs2_partition() {
+ local mtd_name="$1"
+ local mnt="$2"
+ # unmount the partition to reformat it
+ umount -f "$mnt"
+ flash_eraseall "$(mtd_by_name ${mtd_name})"
+ # remount the JFFS2
+ mount -t jffs2 -o sync mtd:"$mtd_name" "$mnt"
+ if [ $? -ne 0 ]; then
+ log "Failed to mount reformatted NV volume; system unstable"
+ fi
+}
+
+clear_ubenv() {
+ log "Clearing U-Boot environment"
+ flash_erase /dev/mtd/u-boot-env 0 0
+}
+
+# mount NV filesystem
+mkdir -p "$RWFS_MNT"
+mount -t jffs2 -o sync mtd:"$NV_MTD" "$RWFS_MNT"
+if [ $? -ne 0 ]; then
+ log "Failed to mount NV volume; attempting recovery"
+ reformat_jffs2_partition $NV_MTD $RWFS_MNT
+fi
+
+# check for full factory reset: if so, format $NV_MTD_DEV
+RESTORE_FLAG=$RWFS_MNT/.restore_op
+restore_op=$(cat $RESTORE_FLAG) # read from NV
+restore_op=${restore_op:-0} # set default value 0
+restore_op=$((restore_op & 3)) # mask off 2 bits
+if [ $restore_op -eq 1 ]; then
+ targeted_clean
+elif [ $restore_op -eq 2 ]; then
+ full_clean
+ clear_ubenv
+elif [ $restore_op -eq 3 ]; then
+ log "restore-defaults: reformat"
+ reformat_jffs2_partition $NV_MTD $RWFS_MNT
+ clear_ubenv
+fi
+rm -f $RESTORE_FLAG
+
+# Restore the overlay saved in the sync
+rsync -a --delete "${OVERLAY_SYNC}/" "${OVERLAY_MNT}"
+log "Restored overlay from sync location"
+
+for FS in $NV_OVERLAYS; do
+ nvrw "$FS"
+done
+
+# 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
+generate_machine_id() {
+ systemd-machine-id-setup
+ cp -pf "$MACHINE_ID" "${MACHINE_ID}_bkup"
+}
+
+if [ ! -s "$MACHINE_ID" ]; then
+ # work around - Bug: Overlay fs fails for machine-id due to
+ # origin mismatch. Clean it up, from overlay fs before re-creating
+ # the same.
+ if [ -e "$OVERLAY_MNT$MACHINE_ID" ]; then
+ umount "/etc"
+ rm -f "$OVERLAY_MNT$MACHINE_ID"
+ nvrw "/etc"
+ # Restore the machine-id from backup, else generate it.
+ if [ -s "${MACHINE_ID}_bkup" ]; then
+ cp -pf "${MACHINE_ID}_bkup" "${MACHINE_ID}"
+ else
+ generate_machine_id
+ fi
+ log "Remounted /etc for machine-id origin mismatch"
+ else
+ generate_machine_id
+ fi
+fi
+
+# mount persistent NV filesystem, where immortal settings live
+SOFS_MNT=/var/sofs
+if ! grep -q sofs /proc/mounts; then
+ mkdir -p $SOFS_MNT
+ SOFS_MTD=sofs
+ SOFS_MTD_NUM="$(mtdnum_by_name ${SOFS_MTD})"
+
+ # mount a JFFS2 on the partition
+ mount -t jffs2 -o sync mtd:"$SOFS_MTD" "$SOFS_MNT"
+ if [ $? -ne 0 ]; then
+ log "Failed to mount SOFS volume; attempting recovery"
+ reformat_jffs2_partition $SOFS_MTD $SOFS_MNT
+ fi
+fi
+
+log "Finished mounting nv and overlays"
+
+
+# Detect the non-legacy node in cooper city and boot in to special mode.
+
+readonly COOPER_CITY=40 # Board id of cooper city
+
+is_nl_node() {
+ typeset -i nid1=$(gpioget $(gpiofind "FM_NODE_ID_1"))
+ typeset -i nid2=$(gpioget $(gpiofind "FM_NODE_ID_2"))
+ echo $((nid1|nid2))
+}
+
+read_board_id() {
+ local idx=0
+ local result=0
+ local value=0
+ for ((idx=0; idx<6; idx++))
+ do
+ typeset -i value=$(gpioget $(gpiofind "FM_BMC_BOARD_SKU_ID${idx}_N"))
+ value=$((value << idx))
+ result=$((result | value))
+ done
+ echo $result
+}
+
+pfr_write() {
+ [ $# -ne 2 ] && return 1
+ local PFR_BUS=4
+ local PFR_ADDR=0x38
+ local reg=$1
+ local val=$2
+ i2cset -y $PFR_BUS $PFR_ADDR $reg $val >&/dev/null
+}
+
+board_id=$(read_board_id)
+if [ $board_id -eq $COOPER_CITY ]; then
+ if [ $(is_nl_node) -ne 0 ]; then
+ systemctl set-default multi-node-nl.target
+ PFR_BMC_CHECKPOINT_REG=0xf
+ PFR_BMC_CHECKPOINT_COMPLETE=0x9
+ pfr_write $PFR_BMC_CHECKPOINT_REG $PFR_BMC_CHECKPOINT_COMPLETE
+ fi
+fi
+
+exec /lib/systemd/systemd
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb
new file mode 100644
index 000000000..ce6cf5998
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/prov-mode-mgr/prov-mode-mgr_git.bb
@@ -0,0 +1,18 @@
+SUMMARY = "Provision mode daemon - RestrictionMode"
+DESCRIPTION = "Daemon allows to configure RestrictionMode property"
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SRC_URI = "git://github.com/Intel-BMC/provisioning-mode-manager.git;protocol=ssh"
+
+SRCREV = "8994b09bfe2eae4e3d18f3a4633e965bd945547f"
+
+inherit cmake systemd
+SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.RestrictionMode.Manager.service"
+
+DEPENDS = "boost sdbusplus phosphor-logging"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb
new file mode 100644
index 000000000..64201acc1
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/security-manager/security-manager_git.bb
@@ -0,0 +1,24 @@
+SUMMARY = "Security Manager daemon to detect the security violation- ASD/ user management"
+DESCRIPTION = "Daemon check for Remote debug enable and user account violation"
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git/security-manager"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+inherit cmake systemd
+
+SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh"
+SRCREV = "bee56d62b209088454d166d1efae4825a2b175df"
+
+SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.SecurityManager.service"
+
+DEPENDS += " \
+ systemd \
+ sdbusplus \
+ libgpiod \
+ sdbusplus-native \
+ phosphor-logging \
+ boost \
+ "
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..e80464274
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sel-logger/phosphor-sel-logger_%.bbappend
@@ -0,0 +1,4 @@
+# Enable downstream autobump
+SRC_URI = "git://github.com/openbmc/phosphor-sel-logger.git"
+SRCREV = "151b7c1fc62971b7d319146e5ea129d44eadd9d7"
+
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..f655d22e4
--- /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://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..f8ca43c3c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/sensors/dbus-sensors_%.bbappend
@@ -0,0 +1,9 @@
+SRCREV = "17aba776373e14851a04e6b9ac518622b117b2a1"
+SRC_URI = "git://github.com/openbmc/dbus-sensors.git"
+
+DEPENDS_append = " libgpiod libmctp"
+
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+
+EXTRA_OECMAKE += "-DDISABLE_NVME=OFF"
+SYSTEMD_SERVICE_${PN} += " xyz.openbmc_project.nvmesensor.service"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb
new file mode 100644
index 000000000..e49a410cb
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/settings/settings_git.bb
@@ -0,0 +1,20 @@
+SUMMARY = "Settings"
+
+SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh"
+SRCREV = "bee56d62b209088454d166d1efae4825a2b175df"
+PV = "0.1+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+SYSTEMD_SERVICE_${PN} = "xyz.openbmc_project.Settings.service"
+
+DEPENDS = "boost \
+ nlohmann-json \
+ sdbusplus"
+
+S = "${WORKDIR}/git/settings"
+inherit cmake systemd
+
+EXTRA_OECMAKE = "-DYOCTO=1"
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb
new file mode 100644
index 000000000..6f6bb860d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/special-mode-mgr/special-mode-mgr_git.bb
@@ -0,0 +1,31 @@
+SUMMARY = "Special mode manager daemon to handle manufacturing modes"
+DESCRIPTION = "Daemon exposes the manufacturing mode property"
+
+PV = "1.0+git${SRCPV}"
+
+S = "${WORKDIR}/git"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SRC_URI = "git://github.com/Intel-BMC/special-mode-manager.git;protocol=ssh"
+SRCREV = "cf2ba04cf68d76047211f66d9bb4ae1be1907323"
+
+EXTRA_OECMAKE += "${@bb.utils.contains('EXTRA_IMAGE_FEATURES', 'validation-unsecure', '-DBMC_VALIDATION_UNSECURE_FEATURE=ON', '', d)}"
+
+inherit cmake systemd
+SYSTEMD_SERVICE_${PN} = "specialmodemgr.service"
+
+DEPENDS += " \
+ systemd \
+ sdbusplus \
+ sdbusplus-native \
+ phosphor-logging \
+ boost \
+ libpam \
+ "
+RDEPENDS_${PN} += " \
+ libsystemd \
+ sdbusplus \
+ phosphor-logging \
+ "
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..b1ac1fbc1
--- /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://github.com/Intel-BMC/provingground.git;protocol=ssh"
+SRCREV = "bee56d62b209088454d166d1efae4825a2b175df"
+
+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_%.bbappend b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend
new file mode 100644
index 000000000..d23480a05
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend
@@ -0,0 +1,5 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+DEPENDS += "gtest"
+
+SYSTEMD_SERVICE_${PN}-bmc += "obmc-mapper.target"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb
new file mode 100644
index 000000000..484d6f80d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/state/post-code-manager_git.bb
@@ -0,0 +1,34 @@
+SUMMARY = "Phosphor post code manager"
+DESCRIPTION = "Post Code Manager"
+
+SRC_URI = "git://github.com/openbmc/phosphor-post-code-manager.git"
+SRCREV = "993d4dd9dc583e62a84c6056edffad957d7b7b5d"
+
+S = "${WORKDIR}/git"
+
+PV = "1.0+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=86d3f3a95c324c9479bd8986968f4327"
+
+inherit cmake pkgconfig systemd
+
+SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.State.Boot.PostCode.service"
+
+DEPENDS += " \
+ autoconf-archive-native \
+ systemd \
+ boost \
+ sdbusplus \
+ sdbusplus-native \
+ phosphor-dbus-interfaces \
+ phosphor-dbus-interfaces-native \
+ phosphor-logging \
+ "
+RDEPENDS_${PN} += " \
+ libsystemd \
+ sdbusplus \
+ phosphor-dbus-interfaces \
+ phosphor-logging \
+ "
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
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..cc84015f4
--- /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://github.com/Intel-BMC/provingground;protocol=ssh"
+
+inherit cmake systemd
+DEPENDS = "boost sdbusplus"
+
+PV = "0.1+git${SRCPV}"
+SRCREV = "bee56d62b209088454d166d1efae4825a2b175df"
+
+S = "${WORKDIR}/git/callback-manager"
+
+SYSTEMD_SERVICE_${PN} += "callback-manager.service"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENCE;md5=7becf906c8f8d03c237bad13bc3dac53"
+
+EXTRA_OECMAKE = "-DYOCTO=1"
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0005-Added-suport-for-multiple-user-manager-services.patch
new file mode 100644
index 000000000..c19f33da2
--- /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,1655 @@
+From b8a8e561d7dba48f3f0a0eb34662b2450dcad35d 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 | 786 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ user_service.hpp | 233 +++++++++++++++++
+ 6 files changed, 1144 insertions(+), 273 deletions(-)
+ create mode 100644 user_service.cpp
+ create mode 100644 user_service.hpp
+
+diff --git a/Makefile.am b/Makefile.am
+index 7c7271e..58916b0 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,11 +1,12 @@
+ bin_PROGRAMS = phosphor-user-manager
+
+-noinst_HEADERS = user_mgr.hpp users.hpp
++noinst_HEADERS = user_mgr.hpp users.hpp user_service.hpp
+
+ phosphor_user_manager_SOURCES = \
+ mainapp.cpp \
+ user_mgr.cpp \
+- users.cpp
++ users.cpp \
++ user_service.cpp
+
+ phosphor_user_manager_LDFLAGS = $(SDBUSPLUS_LIBS) \
+ $(PHOSPHOR_DBUS_INTERFACES_LIBS) \
+diff --git a/mainapp.cpp b/mainapp.cpp
+index c9da030..03c406a 100644
+--- a/mainapp.cpp
++++ b/mainapp.cpp
+@@ -14,18 +14,105 @@
+ * limitations under the License.
+ */
+ #include <string>
++#include <iostream>
++#include <getopt.h>
+ #include "user_mgr.hpp"
++#include "user_service.hpp"
+ #include "config.h"
+
+ // D-Bus root for user manager
+ constexpr auto USER_MANAGER_ROOT = "/xyz/openbmc_project/user";
+
++void printUsage()
++{
++ std::string usage =
++ R"(Usage:
++ phosphor-user-manager [OPTIONS]
++
++Backend DBUS service for OpenBMC User Management.
++If no OPTIONS are specified, shadow file will be used.
++
++Options:
++ -s, --service={shadow|sssd}
++ Specify the authentication service to use:
++ 'shadow' will use the /etc/shadow file.
++ 'sssd' will use the sssd service domains.
++ -h, --help Displays this help message.
++)";
++ std::cerr << usage;
++}
++
++void parseArgs(int argc, char** argv,
++ phosphor::user::UserService::ServiceType& srvc)
++{
++ const std::string shortOpts{"s:h"};
++ const struct option longOpts[] = {{"service", 1, nullptr, 's'},
++ {"help", 0, nullptr, 'h'},
++ {nullptr, 0, nullptr, 0}};
++
++ while (true)
++ {
++ const auto opt =
++ getopt_long(argc, argv, shortOpts.c_str(), longOpts, nullptr);
++
++ if (opt == -1)
++ {
++ if (srvc == phosphor::user::UserService::ServiceType::none)
++ {
++ srvc = phosphor::user::UserService::ServiceType::shadow;
++ }
++ break;
++ }
++
++ switch (opt)
++ {
++ case 's':
++ {
++ std::string srvcStr{optarg};
++ if (!srvcStr.compare("shadow"))
++ {
++ srvc = phosphor::user::UserService::ServiceType::shadow;
++ }
++ else if (!srvcStr.compare("sssd"))
++ {
++ srvc = phosphor::user::UserService::ServiceType::sssd;
++ }
++ else
++ {
++ std::cerr << "Error. '" << srvcStr << "' is not a valid"
++ << " authentication service." << std::endl;
++ printUsage();
++ exit(1);
++ }
++ }
++ break;
++
++ case 'h':
++ {
++ printUsage();
++ exit(0);
++ }
++
++ default:
++ {
++ printUsage();
++ exit(1);
++ }
++ }
++ }
++}
++
+ int main(int argc, char** argv)
+ {
++ // Check command line options. Exit if error.
++ phosphor::user::UserService::ServiceType srvc =
++ phosphor::user::UserService::ServiceType::none;
++ parseArgs(argc, argv, srvc);
++
+ auto bus = sdbusplus::bus::new_default();
+ sdbusplus::server::manager::manager objManager(bus, USER_MANAGER_ROOT);
+
+- phosphor::user::UserMgr userMgr(bus, USER_MANAGER_ROOT);
++ phosphor::user::UserMgr userMgr(bus, USER_MANAGER_ROOT, srvc);
+
+ // Claim the bus now
+ bus.request_name(USER_MANAGER_BUSNAME);
+diff --git a/user_mgr.cpp b/user_mgr.cpp
+index 2f22323..db6e7d5 100644
+--- a/user_mgr.cpp
++++ b/user_mgr.cpp
+@@ -14,26 +14,20 @@
+ // limitations under the License.
+ */
+
+-#include <shadow.h>
+-#include <unistd.h>
+-#include <sys/types.h>
+-#include <sys/wait.h>
++#include <cstdio>
++
+ #include <fstream>
+ #include <grp.h>
+ #include <pwd.h>
+ #include <regex>
+-#include <algorithm>
+-#include <numeric>
+-#include <boost/process/child.hpp>
+-#include <boost/process/io.hpp>
+ #include <boost/algorithm/string/split.hpp>
+ #include <xyz/openbmc_project/Common/error.hpp>
+ #include <xyz/openbmc_project/User/Common/error.hpp>
+ #include <phosphor-logging/log.hpp>
+ #include <phosphor-logging/elog.hpp>
+ #include <phosphor-logging/elog-errors.hpp>
++#include <stdexcept>
+ #include "shadowlock.hpp"
+-#include "file.hpp"
+ #include "user_mgr.hpp"
+ #include "users.hpp"
+ #include "config.h"
+@@ -43,12 +37,10 @@ namespace phosphor
+ namespace user
+ {
+
+-static constexpr const char *passwdFileName = "/etc/passwd";
+ static constexpr size_t ipmiMaxUsers = 15;
+ static constexpr size_t ipmiMaxUserNameLen = 16;
+ static constexpr size_t systemMaxUserNameLen = 30;
+ static constexpr size_t maxSystemUsers = 30;
+-static constexpr const char *grpSsh = "ssh";
+ static constexpr uint8_t minPasswdLength = 8;
+ static constexpr int success = 0;
+ static constexpr int failure = -1;
+@@ -94,79 +86,6 @@ using NoResource =
+
+ using Argument = xyz::openbmc_project::Common::InvalidArgument;
+
+-template <typename... ArgTypes>
+-static std::vector<std::string> executeCmd(const char *path,
+- ArgTypes &&... tArgs)
+-{
+- std::vector<std::string> stdOutput;
+- boost::process::ipstream stdOutStream;
+- boost::process::child execProg(path, const_cast<char *>(tArgs)...,
+- boost::process::std_out > stdOutStream);
+- std::string stdOutLine;
+-
+- while (stdOutStream && std::getline(stdOutStream, stdOutLine) &&
+- !stdOutLine.empty())
+- {
+- stdOutput.emplace_back(stdOutLine);
+- }
+-
+- execProg.wait();
+-
+- int retCode = execProg.exit_code();
+- if (retCode)
+- {
+- log<level::ERR>("Command execution failed", entry("PATH=%d", path),
+- entry("RETURN_CODE:%d", retCode));
+- elog<InternalFailure>();
+- }
+-
+- return stdOutput;
+-}
+-
+-static std::string getCSVFromVector(std::vector<std::string> vec)
+-{
+- switch (vec.size())
+- {
+- case 0:
+- {
+- return "";
+- }
+- break;
+-
+- case 1:
+- {
+- return std::string{vec[0]};
+- }
+- break;
+-
+- default:
+- {
+- return std::accumulate(
+- std::next(vec.begin()), vec.end(), vec[0],
+- [](std::string a, std::string b) { return a + ',' + b; });
+- }
+- }
+-}
+-
+-static bool removeStringFromCSV(std::string &csvStr, const std::string &delStr)
+-{
+- std::string::size_type delStrPos = csvStr.find(delStr);
+- if (delStrPos != std::string::npos)
+- {
+- // need to also delete the comma char
+- if (delStrPos == 0)
+- {
+- csvStr.erase(delStrPos, delStr.size() + 1);
+- }
+- else
+- {
+- csvStr.erase(delStrPos - 1, delStr.size() + 1);
+- }
+- return true;
+- }
+- return false;
+-}
+-
+ bool UserMgr::isUserExist(const std::string &userName)
+ {
+ if (userName.empty())
+@@ -293,39 +212,14 @@ void UserMgr::createUser(std::string userName,
+ {
+ throwForInvalidPrivilege(priv);
+ throwForInvalidGroups(groupNames);
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+ throwForUserExists(userName);
+ throwForUserNameConstraints(userName, groupNames);
+ throwForMaxGrpUserCount(groupNames);
+
+- std::string groups = getCSVFromVector(groupNames);
+- bool sshRequested = removeStringFromCSV(groups, grpSsh);
+-
+- // treat privilege as a group - This is to avoid using different file to
+- // store the same.
+- if (!priv.empty())
+- {
+- if (groups.size() != 0)
+- {
+- groups += ",";
+- }
+- groups += priv;
+- }
+- try
+- {
+- executeCmd("/usr/sbin/useradd", userName.c_str(), "-G", groups.c_str(),
+- "-m", "-N", "-s",
+- (sshRequested ? "/bin/sh" : "/bin/nologin"), "-e",
+- (enabled ? "" : "1970-01-02"));
+- }
+- catch (const InternalFailure &e)
+- {
+- log<level::ERR>("Unable to create new user");
+- elog<InternalFailure>();
+- }
++ // Tell the User Service to create a new user with the info provided.
++ userSrvc->createUser(userName, groupNames, priv, enabled);
+
+- // Add the users object before sending out the signal
++ // Add the users to the local list before sending out the signal
+ std::string userObj = std::string(usersObjPath) + "/" + userName;
+ std::sort(groupNames.begin(), groupNames.end());
+ usersList.emplace(
+@@ -339,19 +233,11 @@ void UserMgr::createUser(std::string userName,
+
+ void UserMgr::deleteUser(std::string userName)
+ {
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+ throwForUserDoesNotExist(userName);
+- try
+- {
+- executeCmd("/usr/sbin/userdel", userName.c_str(), "-r");
+- }
+- catch (const InternalFailure &e)
+- {
+- log<level::ERR>("User delete failed",
+- entry("USER_NAME=%s", userName.c_str()));
+- elog<InternalFailure>();
+- }
++
++ // Tell the User Service to delete user
++ userSrvc->deleteUser(userName);
++ // Then delete user from local list
+
+ usersList.erase(userName);
+
+@@ -362,24 +248,13 @@ void UserMgr::deleteUser(std::string userName)
+
+ void UserMgr::renameUser(std::string userName, std::string newUserName)
+ {
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+ throwForUserDoesNotExist(userName);
+ throwForUserExists(newUserName);
+ throwForUserNameConstraints(newUserName,
+ usersList[userName].get()->userGroups());
+- try
+- {
+- std::string newHomeDir = "/home/" + newUserName;
+- executeCmd("/usr/sbin/usermod", "-l", newUserName.c_str(),
+- userName.c_str(), "-d", newHomeDir.c_str(), "-m");
+- }
+- catch (const InternalFailure &e)
+- {
+- log<level::ERR>("User rename failed",
+- entry("USER_NAME=%s", userName.c_str()));
+- elog<InternalFailure>();
+- }
++ // Call The User Service to rename user on the system
++ userSrvc->renameUser(userName, newUserName);
++ // Update local list to reflect the name change
+ const auto &user = usersList[userName];
+ std::string priv = user.get()->userPrivilege();
+ std::vector<std::string> groupNames = user.get()->userGroups();
+@@ -403,8 +278,6 @@ void UserMgr::updateGroupsAndPriv(const std::string &userName,
+ {
+ throwForInvalidPrivilege(priv);
+ throwForInvalidGroups(groupNames);
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+ throwForUserDoesNotExist(userName);
+ const std::vector<std::string> &oldGroupNames =
+ usersList[userName].get()->userGroups();
+@@ -420,29 +293,8 @@ void UserMgr::updateGroupsAndPriv(const std::string &userName,
+ throwForMaxGrpUserCount(groupNames);
+ }
+
+- std::string groups = getCSVFromVector(groupNames);
+- bool sshRequested = removeStringFromCSV(groups, grpSsh);
+-
+- // treat privilege as a group - This is to avoid using different file to
+- // store the same.
+- if (!priv.empty())
+- {
+- if (groups.size() != 0)
+- {
+- groups += ",";
+- }
+- groups += priv;
+- }
+- try
+- {
+- executeCmd("/usr/sbin/usermod", userName.c_str(), "-G", groups.c_str(),
+- "-s", (sshRequested ? "/bin/sh" : "/bin/nologin"));
+- }
+- catch (const InternalFailure &e)
+- {
+- log<level::ERR>("Unable to modify user privilege / groups");
+- elog<InternalFailure>();
+- }
++ // Call The User Service to update user groups and priv on the system
++ userSrvc->updateGroupsAndPriv(userName, groupNames, priv);
+
+ log<level::INFO>("User groups / privilege updated successfully",
+ entry("USER_NAME=%s", userName.c_str()));
+@@ -638,19 +490,9 @@ int UserMgr::setPamModuleArgValue(const std::string &moduleName,
+
+ void UserMgr::userEnable(const std::string &userName, bool enabled)
+ {
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+ throwForUserDoesNotExist(userName);
+- try
+- {
+- executeCmd("/usr/sbin/usermod", userName.c_str(), "-e",
+- (enabled ? "" : "1970-01-02"));
+- }
+- catch (const InternalFailure &e)
+- {
+- log<level::ERR>("Unable to modify user enabled state");
+- elog<InternalFailure>();
+- }
++ // Call The User Service to update user groups and priv on the system
++ userSrvc->updateUserStatus(userName, enabled);
+
+ log<level::INFO>("User enabled/disabled state updated successfully",
+ entry("USER_NAME=%s", userName.c_str()),
+@@ -728,54 +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;
+- }
+-#ifdef ENABLE_ROOT_USER_MGMT
+- // 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)))
+-#else
+- // Add all users whose UID >=1000 and < 65534
+- if ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534))
+-#endif
+- {
+- 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()
+@@ -786,49 +582,14 @@ size_t UserMgr::getIpmiUsersCount()
+
+ bool UserMgr::isUserEnabled(const std::string &userName)
+ {
+- // All user management lock has to be based on /etc/shadow
+- phosphor::user::shadow::Lock lock();
+- std::array<char, 4096> buffer{};
+- struct spwd spwd;
+- struct spwd *resultPtr = nullptr;
+- int status = getspnam_r(userName.c_str(), &spwd, buffer.data(),
+- buffer.max_size(), &resultPtr);
+- if (!status && (&spwd == resultPtr))
+- {
+- if (resultPtr->sp_expire >= 0)
+- {
+- return false; // user locked out
+- }
+- return true;
+- }
+- return false; // assume user is disabled for any error.
++ // Call The User Service to verify if user is enabled
++ return userSrvc->isUserEnabled(userName);
+ }
+
+ std::vector<std::string> UserMgr::getUsersInGroup(const std::string &groupName)
+ {
+- std::vector<std::string> usersInGroup;
+- // Should be more than enough to get the pwd structure.
+- std::array<char, 4096> buffer{};
+- struct group grp;
+- struct group *resultPtr = nullptr;
+-
+- int status = getgrnam_r(groupName.c_str(), &grp, buffer.data(),
+- buffer.max_size(), &resultPtr);
+-
+- if (!status && (&grp == resultPtr))
+- {
+- for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem))
+- {
+- usersInGroup.emplace_back(*(grp.gr_mem));
+- }
+- }
+- else
+- {
+- log<level::ERR>("Group not found",
+- entry("GROUP=%s", groupName.c_str()));
+- // Don't throw error, just return empty userList - fallback
+- }
+- return usersInGroup;
++ // Call The User Service to get the users that belong to a group
++ return std::move(userSrvc->getUsersInGroup(groupName));
+ }
+
+ DbusUserObj UserMgr::getPrivilegeMapperObject(void)
+@@ -1057,11 +818,9 @@ void UserMgr::initUserObjects(void)
+ {
+ // All user management lock has to be based on /etc/shadow
+ phosphor::user::shadow::Lock lock();
+- std::vector<std::string> userNameList;
+- std::vector<std::string> sshGrpUsersList;
+ UserSSHLists userSSHLists = getUserAndSshGrpList();
+- userNameList = std::move(userSSHLists.first);
+- sshGrpUsersList = std::move(userSSHLists.second);
++ std::vector<std::string> userNameList = std::move(userSSHLists.first);
++ std::vector<std::string> sshGrpUsersList = std::move(userSSHLists.second);
+
+ if (!userNameList.empty())
+ {
+@@ -1116,7 +875,8 @@ void UserMgr::initUserObjects(void)
+ }
+ }
+
+-UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path) :
++UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path,
++ UserService::ServiceType srvc) :
+ Ifaces(bus, path, true), bus(bus), path(path)
+ {
+ UserMgrIface::allPrivileges(privMgr);
+@@ -1225,6 +985,7 @@ UserMgr::UserMgr(sdbusplus::bus::bus &bus, const char *path) :
+ }
+ AccountPolicyIface::accountUnlockTimeout(value32);
+ }
++ userSrvc = std::make_unique<UserService>(srvc, groupsMgr, privMgr);
+ initUserObjects();
+
+ // emit the signal
+diff --git a/user_mgr.hpp b/user_mgr.hpp
+index b25e9f2..c24733b 100644
+--- a/user_mgr.hpp
++++ b/user_mgr.hpp
+@@ -21,6 +21,7 @@
+ #include <unordered_map>
+ #include <variant>
+ #include "users.hpp"
++#include "user_service.hpp"
+
+ namespace phosphor
+ {
+@@ -28,8 +29,6 @@ namespace user
+ {
+
+ using UserMgrIface = sdbusplus::xyz::openbmc_project::User::server::Manager;
+-using UserSSHLists =
+- std::pair<std::vector<std::string>, std::vector<std::string>>;
+ using AccountPolicyIface =
+ sdbusplus::xyz::openbmc_project::User::server::AccountPolicy;
+
+@@ -76,8 +75,10 @@ class UserMgr : public Ifaces
+ *
+ * @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
+@@ -186,6 +187,8 @@ class UserMgr : public Ifaces
+ /** @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..c3c45bd
+--- /dev/null
++++ b/user_service.cpp
+@@ -0,0 +1,786 @@
++/*
++// 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;
++ }
++#ifdef ENABLE_ROOT_USER_MGMT
++ // 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)))
++#else
++ // Add all users whose UID >=1000 and < 65534
++ if ((pwp->pw_uid >= 1000) && (pwp->pw_uid < 65534))
++#endif
++ {
++ 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/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch
new file mode 100644
index 000000000..91087a155
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager/0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch
@@ -0,0 +1,76 @@
+From c0bf911cbc33659adddebde767029ffc23251c61 Mon Sep 17 00:00:00 2001
+From: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
+Date: Mon, 24 Feb 2020 13:37:12 +0530
+Subject: [PATCH] Use groupmems instead of getgrnam_r due to overlay
+
+With JFFS2 overlay, getgrnam_r during initial time returns the
+old group details as per the lower dir, instead of the overlay one
+but at the same time groupmems where returning proper values, which
+reads the file everytime. Hence replacing getgrnam_r with groupmems
+
+Tested:
+1. Verified that when added multiple user and then doing
+BMC reset using ipmitool raw 6 2 doesn't reproduce the issue of
+user with only ssh group. (on 38 version source + this fix)
+2. Updated using redfish to version 39 + this fix, and made sure
+issue doesn't happen.
+
+Note: For testing purpose added debug statements to dump ouput of
+both getgrnam_r & groupmems and able to see proper list only
+in groupmems when the issue is reproduced
+
+Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
+Signed-off-by: jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
+---
+ user_service.cpp | 28 +++++++++++++---------------
+ 1 file changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/user_service.cpp b/user_service.cpp
+index c3c45bd..0a6b171 100644
+--- a/user_service.cpp
++++ b/user_service.cpp
+@@ -143,28 +143,26 @@ class ShadowService : public phosphor::user::UserServiceInterface
+ 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))
++ std::vector<std::string> output;
++ try
+ {
+- for (; *(grp.gr_mem) != NULL; ++(grp.gr_mem))
+- {
+- usersInGroup.emplace_back(*(grp.gr_mem));
+- }
++ output = phosphor::user::executeCmd("/usr/sbin/groupmems", "-l",
++ "-g", groupName.c_str());
+ }
+- else
++ catch (const phosphor::user::InternalFailure &e)
+ {
+ 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;
++ }
++ if (!output.empty())
++ {
++ boost::algorithm::trim_right(output[0]);
++ boost::algorithm::split(usersInGroup, output[0],
++ boost::algorithm::is_any_of("\t "),
++ boost::token_compress_on);
+ }
+ return usersInGroup;
+ }
+--
+2.17.1
+
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..238511ed5
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/users/phosphor-user-manager_%.bbappend
@@ -0,0 +1,11 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+#SRC_URI = "git://github.com/openbmc/phosphor-user-manager;nobranch=1"
+SRCREV = "d4d655006c6179d47008d9b374debcedcc03a1c4"
+
+EXTRA_OECONF += "${@bb.utils.contains_any("IMAGE_FEATURES", [ 'debug-tweaks', 'allow-root-login' ], '', '--disable-root_user_mgmt', d)}"
+
+SRC_URI += " \
+ file://0005-Added-suport-for-multiple-user-manager-services.patch \
+ file://0006-Use-groupmems-instead-of-getgrnam_r-due-to-overlay.patch \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb
new file mode 100644
index 000000000..5b74dec5e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/virtual-media/virtual-media.bb
@@ -0,0 +1,24 @@
+SUMMARY = "Virtual Media Service"
+DESCRIPTION = "Virtual Media Service"
+
+SRC_URI = "git://github.com/Intel-BMC/provingground.git;protocol=ssh"
+SRCREV = "bee56d62b209088454d166d1efae4825a2b175df"
+
+S = "${WORKDIR}/git/virtual-media/"
+PV = "1.0+git${SRCPV}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${S}/LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SYSTEMD_SERVICE_${PN} += "xyz.openbmc_project.VirtualMedia.service"
+
+DEPENDS = "udev boost nlohmann-json systemd sdbusplus"
+
+# Temporarily not needed due to Legacy mode disabling
+# RDEPENDS_${PN} = "nbdkit"
+
+inherit cmake systemd
+
+EXTRA_OECMAKE += "-DYOCTO_DEPENDENCIES=ON"
+
+FULL_OPTIMIZATION = "-Os -pipe -flto -fno-rtti"
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..ebd795e83
--- /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://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+S = "${WORKDIR}"
+
+inherit cmake
+inherit pkgconfig pythonnative
+
+DEPENDS += " \
+ systemd \
+ sdbusplus \
+ sdbusplus-native \
+ phosphor-logging \
+ phosphor-dbus-interfaces \
+ phosphor-dbus-interfaces-native \
+ boost \
+ "
+
+RDEPENDS_${PN} += " \
+ libsystemd \
+ sdbusplus \
+ phosphor-logging \
+ phosphor-dbus-interfaces \
+ "
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format
new file mode 100644
index 000000000..dd2770837
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/.clang-format
@@ -0,0 +1,98 @@
+---
+Language: Cpp
+# BasedOnStyle: LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: true
+ AfterControlStatement: true
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: true
+ AfterObjCDeclaration: true
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: true
+ BeforeElse: true
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: AfterColon
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: true
+PointerAlignment: Left
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeBlocks: Regroup
+IncludeCategories:
+ - Regex: '^[<"](gtest|gmock)'
+ Priority: 5
+ - Regex: '^"config.h"'
+ Priority: -1
+ - Regex: '^".*\.hpp"'
+ Priority: 1
+ - Regex: '^<.*\.h>'
+ Priority: 2
+ - Regex: '^<.*'
+ Priority: 3
+ - Regex: '.*'
+ Priority: 4
+IndentCaseLabels: true
+IndentWidth: 4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Right
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 4
+UseTab: Never
+...
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt
new file mode 100644
index 000000000..bd5567d31
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/CMakeLists.txt
@@ -0,0 +1,52 @@
+cmake_minimum_required (VERSION 3.5 FATAL_ERROR)
+project (frb2-watchdog CXX)
+set (CMAKE_CXX_STANDARD 17)
+set (CMAKE_CXX_STANDARD_REQUIRED ON)
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
+set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti")
+
+include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+
+# boost support
+find_package (Boost REQUIRED)
+# pkg_check_modules(Boost boost REQUIRED)
+include_directories (${Boost_INCLUDE_DIRS})
+add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY)
+add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED)
+add_definitions (-DBOOST_ALL_NO_LIB)
+add_definitions (-DBOOST_NO_RTTI)
+add_definitions (-DBOOST_NO_TYPEID)
+add_definitions (-DBOOST_ASIO_DISABLE_THREADS)
+
+# import libsystemd
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (SYSTEMD libsystemd REQUIRED)
+include_directories (${SYSTEMD_INCLUDE_DIRS})
+link_directories (${SYSTEMD_LIBRARY_DIRS})
+
+# import sdbusplus
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (SDBUSPLUSPLUS sdbusplus REQUIRED)
+include_directories (${SDBUSPLUSPLUS_INCLUDE_DIRS})
+link_directories (${SDBUSPLUSPLUS_LIBRARY_DIRS})
+
+# import phosphor-logging
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (LOGGING phosphor-logging REQUIRED)
+include_directories (${LOGGING_INCLUDE_DIRS})
+link_directories (${LOGGING_LIBRARY_DIRS})
+
+# import phosphor-dbus-interfaces
+find_package (PkgConfig REQUIRED)
+pkg_check_modules (DBUSINTERFACE phosphor-dbus-interfaces REQUIRED)
+include_directories (${DBUSINTERFACE_INCLUDE_DIRS})
+link_directories (${DBUSINTERFACE_LIBRARY_DIRS})
+
+add_executable (frb2-watchdog frb2-watchdog.cpp)
+
+target_link_libraries (${PROJECT_NAME} systemd)
+target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})
+target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES})
+target_link_libraries (${PROJECT_NAME} ${DBUSINTERFACE_LIBRARIES}
+ phosphor_logging)
+install (TARGETS frb2-watchdog DESTINATION bin)
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json
new file mode 100644
index 000000000..583c255a3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/cmake-format.json
@@ -0,0 +1,12 @@
+{
+ "enum_char": ".",
+ "line_ending": "unix",
+ "bullet_char": "*",
+ "max_subargs_per_line": 99,
+ "command_case": "lower",
+ "tab_size": 4,
+ "line_width": 80,
+ "separate_fn_name_with_space": true,
+ "dangle_parens": true,
+ "separate_ctrl_name_with_space": true
+} \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp
new file mode 100644
index 000000000..5356e95db
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/frb2-watchdog/frb2-watchdog.cpp
@@ -0,0 +1,258 @@
+/* Copyright 2018 Intel
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <boost/container/flat_set.hpp>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <iostream>
+#include <memory>
+#include <optional>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/bus/match.hpp>
+#include <sdbusplus/message.hpp>
+#include <sdbusplus/timer.hpp>
+#include <vector>
+#include <xyz/openbmc_project/State/Watchdog/server.hpp>
+
+void handleResponse(const boost::system::error_code &err,
+ std::size_t bytes_transferred);
+
+static int mailboxDevFd = -1;
+
+static boost::asio::io_service io;
+static auto conn = std::make_shared<sdbusplus::asio::connection>(io);
+boost::asio::ip::tcp::socket mailBoxDevSocket(io);
+boost::asio::deadline_timer pollTimer(io);
+boost::asio::posix::stream_descriptor inputDevice(io);
+
+// mailbox registre data[0:0] for FRB2 enable bit
+boost::asio::streambuf readBuf(1);
+std::string dataRead;
+
+// FRB2 watchdog timeout is 6 minutes
+static constexpr unsigned int frb2TimerIntervalMs = 360 * 1000;
+
+// mailbox device polling time interval is 2 seconds
+static constexpr unsigned int pollMs = 2000;
+
+static constexpr unsigned int frb2Started = 1;
+static constexpr unsigned int frb2Stopped = 0;
+
+// FRB2 status
+static uint8_t frb2Status = frb2Stopped;
+
+static constexpr const char *mailboxDevName = "/dev/aspeed-mbox";
+
+static constexpr const char frb2Bus[] = "xyz.openbmc_project.FRB2";
+static constexpr const char frb2Obj[] = "/xyz/openbmc_project/FRB2";
+static constexpr const char frb2Intf[] = "xyz.openbmc_project.FRB2";
+
+static constexpr char powerBus[] = "xyz.openbmc_project.Chassis.Control.Power";
+static constexpr char powerPath[] =
+ "/xyz/openbmc_project/Chassis/Control/Power0";
+static constexpr char powerIntf[] = "xyz.openbmc_project.Chassis.Control.Power";
+
+static constexpr char wdBus[] = "xyz.openbmc_project.Watchdog";
+static constexpr char wdPath[] = "/xyz/openbmc_project/watchdog/host0";
+static constexpr char wdIntf[] = "xyz.openbmc_project.State.Watchdog";
+static constexpr char propIntf[] = "org.freedesktop.DBus.Properties";
+
+typedef boost::asio::buffers_iterator<boost::asio::const_buffers_1> iterator;
+
+// check if FRB2 bit is 0x1
+std::pair<iterator, bool> matchFRB2(iterator begin, iterator end)
+{
+ unsigned char ch = 0;
+ iterator i = begin;
+
+ while (i != end)
+ {
+ ch = static_cast<unsigned char>(*i);
+ if (ch & 0x1)
+ {
+ return std::make_pair(i, true);
+ }
+ i++;
+ }
+
+ return std::make_pair(i, false);
+}
+
+static void startRead()
+{
+ boost::asio::async_read_until(inputDevice, readBuf, matchFRB2,
+ [&](const boost::system::error_code &ec,
+ std::size_t bytes_transferred) {
+ handleResponse(ec, bytes_transferred);
+ });
+}
+
+template <typename T> void setProperty(const std::string &key, const T &val)
+{
+ phosphor::logging::log<phosphor::logging::level::DEBUG>(
+ "setProperty", phosphor::logging::entry("KEY=%s", key.c_str()));
+
+ try
+ {
+ conn->async_method_call(
+ [](const boost::system::error_code &err) {
+ if (err)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "async_method_call error!",
+ phosphor::logging::entry(
+ "ERROR=%s",
+ boost::system::system_error(err).what()));
+ }
+ },
+ wdBus, wdPath, propIntf, "Set", wdIntf, key,
+ sdbusplus::message::variant_ns::variant<T>(val));
+ }
+ catch (sdbusplus::exception::SdBusError &e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Dbus error!", phosphor::logging::entry("ERROR=%s", e.what()));
+ }
+}
+void handleResponse(const boost::system::error_code &err,
+ std::size_t bytes_transferred)
+{
+ std::istream responseStream(&readBuf);
+ std::string response;
+ int n = 0;
+ uint64_t interval = frb2TimerIntervalMs;
+
+ std::getline(responseStream, response);
+ responseStream.clear();
+
+ if (err == boost::system::errc::bad_file_descriptor)
+ {
+
+ phosphor::logging::log<phosphor::logging::level::DEBUG>(
+ "bad file descriptor");
+ return; // we're being destroyed
+ }
+
+ if (!err)
+ {
+ // FRB2 is set by BIOS
+ if (frb2Stopped == frb2Status)
+ {
+ // start FRB2 watchdog
+ frb2Status = frb2Started;
+ phosphor::logging::log<phosphor::logging::level::DEBUG>(
+ "FRB2 enable, start FRB2 watchdog");
+ setProperty(
+ "ExpireAction",
+ std::string(
+ "xyz.openbmc_project.State.Watchdog.Action.HardReset"));
+ setProperty("Interval", interval);
+ setProperty("TimeRemaining", interval);
+ setProperty("Initialized", true);
+ setProperty("Enabled", true);
+ }
+ }
+ else if (err == boost::asio::error::misc_errors::not_found)
+ {
+ // FRB2 is clear, stop FRB2 watchdog if it is started
+ if (frb2Started == frb2Status)
+ {
+ frb2Status = frb2Stopped;
+ phosphor::logging::log<phosphor::logging::level::DEBUG>(
+ "FRB2 is unset, stop FRB2 watchdog");
+ setProperty("Enabled", false);
+ }
+ }
+ else
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "handleResponse error!",
+ phosphor::logging::entry("ERROR=%s",
+ boost::system::system_error(err).what()));
+ }
+
+ pollTimer.expires_from_now(boost::posix_time::milliseconds(pollMs));
+ pollTimer.async_wait(
+ [](const boost::system::error_code &ec) { startRead(); });
+}
+
+int main(int argc, char **argv)
+{
+ phosphor::logging::log<phosphor::logging::level::DEBUG>(
+ "Monitor FRB2 signal");
+
+ sdbusplus::bus::match_t biosPostSignal(
+ static_cast<sdbusplus::bus::bus &>(*conn),
+ sdbusplus::bus::match::rules::type::signal() +
+ sdbusplus::bus::match::rules::member("PostCompleted") +
+ sdbusplus::bus::match::rules::path(powerPath) +
+ sdbusplus::bus::match::rules::interface(powerIntf),
+ [](sdbusplus::message::message &msg) {
+ uint8_t value = 0;
+ ssize_t rc = 0;
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "BIOS post completed signal");
+ // stop FRB2 and clean mailbox
+ value = 0;
+ rc = ::pwrite(mailboxDevFd, &value, 1, 0);
+ if (rc != 1)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "mailbox write error!");
+ }
+ setProperty("Enabled", false);
+ frb2Status = frb2Stopped;
+ return;
+ });
+
+ conn->request_name(frb2Bus);
+
+ auto server = sdbusplus::asio::object_server(conn);
+
+ std::shared_ptr<sdbusplus::asio::dbus_interface> frb2Iface =
+ server.add_interface(frb2Obj, frb2Intf);
+
+ frb2Iface->register_property("frb2Status", frb2Status);
+
+ frb2Iface->initialize();
+
+ mailboxDevFd = ::open(mailboxDevName, O_RDWR | O_CLOEXEC);
+ if (mailboxDevFd < 0)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "mailbox device open fail!");
+ return -1;
+ }
+
+ inputDevice.assign(mailboxDevFd);
+
+ startRead();
+
+ io.run();
+
+ ::close(mailboxDevFd);
+
+ return 0;
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch
new file mode 100644
index 000000000..360ba35f0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/0001-Customize-phosphor-watchdog-for-Intel-platforms.patch
@@ -0,0 +1,336 @@
+From 82f31d1e6096acd4f223f0b0fe0d814c27450022 Mon Sep 17 00:00:00 2001
+From: James Feist <james.feist@linux.intel.com>
+Date: Mon, 17 Jun 2019 12:00:58 -0700
+Subject: [PATCH] Customize phosphor-watchdog for Intel platforms
+
+This patch adds various changes to phosphor-watchdog that are
+required for compatibility with Intel platforms.
+
+ 1. Add Redfish messages for watchdog timeout and pre-interrupt
+ 2. Use dbus properties for power control insted of service files
+ 3. Use host status to enable/disable watchdog
+ 4. Set preTimeoutInterruptOccurFlag
+
+Signed-off-by: James Feist <james.feist@linux.intel.com>
+Signed-off-by: Ren Yu <yux.ren@intel.com>
+Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
+Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
+---
+ watchdog.cpp | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
+ watchdog.hpp | 23 ++++++-
+ 2 files changed, 226 insertions(+), 10 deletions(-)
+
+diff --git a/watchdog.cpp b/watchdog.cpp
+index 9090760..079d88e 100644
+--- a/watchdog.cpp
++++ b/watchdog.cpp
+@@ -1,11 +1,14 @@
+ #include "watchdog.hpp"
+
++#include <systemd/sd-journal.h>
++
+ #include <algorithm>
+ #include <chrono>
+ #include <phosphor-logging/elog.hpp>
+ #include <phosphor-logging/log.hpp>
+ #include <sdbusplus/exception.hpp>
+ #include <xyz/openbmc_project/Common/error.hpp>
++#include <xyz/openbmc_project/State/Host/server.hpp>
+
+ namespace phosphor
+ {
+@@ -18,10 +21,77 @@ using namespace phosphor::logging;
+ using sdbusplus::exception::SdBusError;
+ using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
+
+-// systemd service to kick start a target.
+-constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
+-constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1";
+-constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
++const static constexpr char* currentHostState = "CurrentHostState";
++const static constexpr char* hostStatusOff =
++ "xyz.openbmc_project.State.Host.HostState.Off";
++
++const static constexpr char* actionDescription = " due to Watchdog timeout";
++const static constexpr char* hardResetDescription = "Hard Reset - System reset";
++const static constexpr char* powerOffDescription =
++ "Power Down - System power down";
++const static constexpr char* powerCycleDescription =
++ "Power Cycle - System power cycle";
++const static constexpr char* timerExpiredDescription = "Timer expired";
++
++const static constexpr char* preInterruptActionNone =
++ "xyz.openbmc_project.State.Watchdog.PreTimeoutInterruptAction.None";
++
++const static constexpr char* preInterruptDescriptionSMI = "SMI";
++const static constexpr char* preInterruptDescriptionNMI = "NMI";
++const static constexpr char* preInterruptDescriptionMI = "Messaging Interrupt";
++
++const static constexpr char* reservedDescription = "Reserved";
++
++const static constexpr char* timerUseDescriptionBIOSFRB2 = "BIOS FRB2";
++const static constexpr char* timerUseDescriptionBIOSPOST = "BIOS/POST";
++const static constexpr char* timerUseDescriptionOSLoad = "OSLoad";
++const static constexpr char* timerUseDescriptionSMSOS = "SMS/OS";
++const static constexpr char* timerUseDescriptionOEM = "OEM";
++
++namespace restart
++{
++static constexpr const char* busName =
++ "xyz.openbmc_project.Control.Host.RestartCause";
++static constexpr const char* path =
++ "/xyz/openbmc_project/control/host0/restart_cause";
++static constexpr const char* interface =
++ "xyz.openbmc_project.Control.Host.RestartCause";
++static constexpr const char* property = "RequestedRestartCause";
++} // namespace restart
++
++// chassis state manager service
++namespace chassis
++{
++static constexpr const char* busName = "xyz.openbmc_project.State.Chassis";
++static constexpr const char* path = "/xyz/openbmc_project/state/chassis0";
++static constexpr const char* interface = "xyz.openbmc_project.State.Chassis";
++static constexpr const char* request = "RequestedPowerTransition";
++} // namespace chassis
++
++namespace host
++{
++static constexpr const char* busName = "xyz.openbmc_project.State.Host";
++static constexpr const char* path = "/xyz/openbmc_project/state/host0";
++static constexpr const char* interface = "xyz.openbmc_project.State.Host";
++static constexpr const char* request = "RequestedHostTransition";
++} // namespace host
++
++void Watchdog::powerStateChangedHandler(
++ const std::map<std::string, std::variant<std::string>>& props)
++{
++ const auto iter = props.find(currentHostState);
++ if (iter != props.end())
++ {
++ const std::string* powerState = std::get_if<std::string>(&iter->second);
++ if (powerState && (*powerState == hostStatusOff))
++ {
++ if (timerEnabled())
++ {
++ enabled(false);
++ }
++ }
++ }
++}
+
+ void Watchdog::resetTimeRemaining(bool enableWatchdog)
+ {
+@@ -102,13 +172,102 @@ uint64_t Watchdog::interval(uint64_t value)
+ // Optional callback function on timer expiration
+ void Watchdog::timeOutHandler()
+ {
++ PreTimeoutInterruptAction preTimeoutInterruptAction = preTimeoutInterrupt();
++ std::string preInterruptActionMessageArgs{};
++
+ Action action = expireAction();
++ std::string actionMessageArgs{};
++
++ expiredTimerUse(currentTimerUse());
++
++ TimerUse timeUser = expiredTimerUse();
++ std::string timeUserMessage{};
++
+ if (!this->enabled())
+ {
+ action = fallback->action;
+ }
+
+- expiredTimerUse(currentTimerUse());
++ switch (timeUser)
++ {
++ case Watchdog::TimerUse::BIOSFRB2:
++ timeUserMessage = timerUseDescriptionBIOSFRB2;
++ break;
++ case Watchdog::TimerUse::BIOSPOST:
++ timeUserMessage = timerUseDescriptionBIOSPOST;
++ break;
++ case Watchdog::TimerUse::OSLoad:
++ timeUserMessage = timerUseDescriptionOSLoad;
++ break;
++ case Watchdog::TimerUse::SMSOS:
++ timeUserMessage = timerUseDescriptionSMSOS;
++ break;
++ case Watchdog::TimerUse::OEM:
++ timeUserMessage = timerUseDescriptionOEM;
++ break;
++ default:
++ timeUserMessage = reservedDescription;
++ break;
++ }
++
++ switch (action)
++ {
++ case Watchdog::Action::HardReset:
++ actionMessageArgs = std::string(hardResetDescription) +
++ std::string(actionDescription);
++ break;
++ case Watchdog::Action::PowerOff:
++ actionMessageArgs = std::string(powerOffDescription) +
++ std::string(actionDescription);
++ break;
++ case Watchdog::Action::PowerCycle:
++ actionMessageArgs = std::string(powerCycleDescription) +
++ std::string(actionDescription);
++ break;
++ case Watchdog::Action::None:
++ actionMessageArgs = timerExpiredDescription;
++ break;
++ default:
++ actionMessageArgs = reservedDescription;
++ break;
++ }
++
++ // Log into redfish event log
++ sd_journal_send("MESSAGE=IPMIWatchdog: Timed out ACTION=%s",
++ convertForMessage(action).c_str(), "PRIORITY=%i", LOG_INFO,
++ "REDFISH_MESSAGE_ID=%s", "OpenBMC.0.1.IPMIWatchdog",
++ "REDFISH_MESSAGE_ARGS=%s. timer use: %s",
++ actionMessageArgs.c_str(), timeUserMessage.c_str(), NULL);
++
++ switch (preTimeoutInterruptAction)
++ {
++ case Watchdog::PreTimeoutInterruptAction::SMI:
++ preInterruptActionMessageArgs = preInterruptDescriptionSMI;
++ break;
++ case Watchdog::PreTimeoutInterruptAction::NMI:
++ preInterruptActionMessageArgs = preInterruptDescriptionNMI;
++ break;
++ case Watchdog::PreTimeoutInterruptAction::MI:
++ preInterruptActionMessageArgs = preInterruptDescriptionMI;
++ break;
++ default:
++ preInterruptActionMessageArgs = reservedDescription;
++ break;
++ }
++
++ if (preInterruptActionNone != convertForMessage(preTimeoutInterruptAction))
++ {
++ preTimeoutInterruptOccurFlag(true);
++
++ sd_journal_send("MESSAGE=IPMIWatchdog: Pre Timed out Interrupt=%s",
++ convertForMessage(preTimeoutInterruptAction).c_str(),
++ "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
++ "OpenBMC.0.1.IPMIWatchdog",
++ "REDFISH_MESSAGE_ARGS=Timer interrupt - %s due to "
++ "Watchdog timeout. timer use: %s",
++ preInterruptActionMessageArgs.c_str(),
++ timeUserMessage.c_str(), NULL);
++ }
+
+ auto target = actionTargetMap.find(action);
+ if (target == actionTargetMap.end())
+@@ -128,10 +287,23 @@ void Watchdog::timeOutHandler()
+
+ try
+ {
+- auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
+- SYSTEMD_INTERFACE, "StartUnit");
+- method.append(target->second);
+- method.append("replace");
++ sdbusplus::message::message method;
++ if (action == Watchdog::Action::HardReset)
++ {
++ method = bus.new_method_call(host::busName, host::path,
++ "org.freedesktop.DBus.Properties",
++ "Set");
++ method.append(host::interface, host::request,
++ std::variant<std::string>(target->second));
++ }
++ else
++ {
++ method = bus.new_method_call(chassis::busName, chassis::path,
++ "org.freedesktop.DBus.Properties",
++ "Set");
++ method.append(chassis::interface, chassis::request,
++ std::variant<std::string>(target->second));
++ }
+
+ bus.call_noreply(method);
+ }
+@@ -142,6 +314,29 @@ void Watchdog::timeOutHandler()
+ entry("ERROR=%s", e.what()));
+ commit<InternalFailure>();
+ }
++
++ // set restart cause for watchdog HardReset & PowerCycle actions
++ if ((action == Watchdog::Action::HardReset) ||
++ (action == Watchdog::Action::PowerCycle))
++ {
++ try
++ {
++ auto method = bus.new_method_call(
++ restart::busName, restart::path,
++ "org.freedesktop.DBus.Properties", "Set");
++ method.append(
++ restart::interface, restart::property,
++ std::variant<std::string>("xyz.openbmc_project.State.Host."
++ "RestartCause.WatchdogTimer"));
++ bus.call(method);
++ }
++ catch (sdbusplus::exception_t& e)
++ {
++ log<level::ERR>("Failed to set HostRestartCause property",
++ entry("ERROR=%s", e.what()));
++ commit<InternalFailure>();
++ }
++ }
+ }
+
+ tryFallbackOrDisable();
+diff --git a/watchdog.hpp b/watchdog.hpp
+index 7de9bb3..b004b7a 100644
+--- a/watchdog.hpp
++++ b/watchdog.hpp
+@@ -68,7 +68,18 @@ class Watchdog : public WatchdogInherits
+ WatchdogInherits(bus, objPath),
+ bus(bus), actionTargetMap(std::move(actionTargetMap)),
+ fallback(std::move(fallback)), minInterval(minInterval),
+- timer(event, std::bind(&Watchdog::timeOutHandler, this))
++ timer(event, std::bind(&Watchdog::timeOutHandler, this)),
++ powerStateChangedSignal(
++ bus,
++ sdbusplus::bus::match::rules::propertiesChanged(
++ "/xyz/openbmc_project/state/host0",
++ "xyz.openbmc_project.State.Host"),
++ [this](sdbusplus::message::message& msg) {
++ std::string objectName;
++ std::map<std::string, std::variant<std::string>> props;
++ msg.read(objectName, props);
++ powerStateChangedHandler(props);
++ })
+ {
+ // We set the watchdog interval with the default value.
+ interval(interval());
+@@ -77,6 +88,12 @@ class Watchdog : public WatchdogInherits
+ tryFallbackOrDisable();
+ }
+
++ /** @brief Disable watchdog when power status change meet
++ * the specific requirement
++ */
++ void powerStateChangedHandler(
++ const std::map<std::string, std::variant<std::string>>& props);
++
+ /** @brief Resets the TimeRemaining to the configured Interval
+ * Optionally enables the watchdog.
+ *
+@@ -165,6 +182,10 @@ class Watchdog : public WatchdogInherits
+ /** @brief Contained timer object */
+ sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer;
+
++ /** @brief Optional Callback handler when power status change meet
++ * the specific requirement */
++ sdbusplus::bus::match_t powerStateChangedSignal;
++
+ /** @brief Optional Callback handler on timer expirartion */
+ void timeOutHandler();
+
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service
new file mode 100644
index 000000000..007e39d8a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog/phosphor-watchdog.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=Phosphor Watchdog
+
+[Service]
+ExecStart=/usr/bin/env phosphor-watchdog --continue --service=xyz.openbmc_project.Watchdog \
+ --path=/xyz/openbmc_project/watchdog/host0 \
+ --action_target=xyz.openbmc_project.State.Watchdog.Action.HardReset=xyz.openbmc_project.State.Host.Transition.ForceWarmReboot \
+ --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerOff=xyz.openbmc_project.State.Chassis.Transition.Off \
+ --action_target=xyz.openbmc_project.State.Watchdog.Action.PowerCycle=xyz.openbmc_project.State.Chassis.Transition.PowerCycle
+
+SyslogIdentifier=phosphor-watchdog
+BusName =xyz.openbmc_project.Watchdog
+Type=dbus
+
+[Install]
+WantedBy=basic.target
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..f0b8e8f23
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/phosphor-watchdog_%.bbappend
@@ -0,0 +1,9 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+
+SRCREV = "c35135d32f9cb84b62de7b72eee3a2e87b4b3d4d"
+SRC_URI += "file://0001-Customize-phosphor-watchdog-for-Intel-platforms.patch \
+ "
+
+# Remove the override to keep service running after DC cycle
+SYSTEMD_OVERRIDE_${PN}_remove = "poweron.conf:phosphor-watchdog@poweron.service.d/poweron.conf"
+SYSTEMD_SERVICE_${PN} = "phosphor-watchdog.service"
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..45c2c5364
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog.bb
@@ -0,0 +1,24 @@
+SUMMARY = "System watchdog"
+DESCRIPTION = "BMC hardware watchdog service that is used to reset BMC \
+ when unrecoverable events occurs"
+
+inherit allarch
+inherit obmc-phosphor-systemd
+
+RDEPENDS_${PN} = "bash"
+
+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"
+
+SYSTEMD_SERVICE_${PN} += "watchdog-reset.service"
+SYSTEMD_SERVICE_${PN} += "watchdog-clear-failures.service"
+SYSTEMD_SERVICE_${PN} += "watchdog-clear-failures.timer"
+SRC_URI += "file://watchdog-reset.sh"
+
+do_install_append(){
+ install -d ${D}${bindir}
+ install -m 0755 ${WORKDIR}/watchdog-reset.sh ${D}${bindir}
+}
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/watchdog/system-watchdog/watchdog-clear-failures.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.service
new file mode 100644
index 000000000..801f4ed27
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Reset BMC Hardware Watchdog Failure Count
+
+[Service]
+ExecStart=busctl call xyz.openbmc_project.U_Boot.Environment.Manager \
+ /xyz/openbmc_project/u_boot/environment/mgr \
+ xyz.openbmc_project.U_Boot.Environment.Manager \
+ Write ss bootfailures 0
+Type=oneshot
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.timer b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.timer
new file mode 100644
index 000000000..1abac4326
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-clear-failures.timer
@@ -0,0 +1,8 @@
+[Unit]
+Description=Starts the clear watchdog serivce after 30 minutes
+
+[Timer]
+OnBootSec=30min
+
+[Install]
+WantedBy=timers.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.service b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.service
new file mode 100644
index 000000000..6a5ffb4ba
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Reset BMC Using Hardware Watchdog
+
+[Service]
+ExecStart=/usr/bin/watchdog-reset.sh
+Type=oneshot
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.sh
new file mode 100644
index 000000000..b3afd73d3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/watchdog/system-watchdog/watchdog-reset.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+if /sbin/fw_printenv bootfailures -n | grep -q 3; then
+ exit 0 # passed boot limit, user started again on purpose
+fi
+
+echo "Watchdog Failure Limit Reached, Failed Processes:" > /dev/kmsg
+systemctl --failed --no-pager | grep failed > /dev/kmsg
+echo "Log as follows:" > /dev/kmsg
+journalctl -r -n 100 | while read line; do echo $line > /dev/kmsg; done
+
+systemctl stop system-watchdog.service
+/sbin/watchdog -T 0 -F /dev/watchdog1
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json
new file mode 100644
index 000000000..348a7792d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui/config.json
@@ -0,0 +1,9 @@
+{
+ "customKeyEnable": true,
+ "keyType" : "VT100+",
+ "customConsoleDisplaySize": {
+ "width": 100,
+ "height": 32
+ },
+ "VirtualMediaEnabled" : true
+}
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..5923eb8d9
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/webui/phosphor-webui_%.bbappend
@@ -0,0 +1,4 @@
+SRC_URI = "git://github.com/Intel-BMC/phosphor-webui;protocol=ssh;branch=intel2"
+FILESEXTRAPATHS_prepend_intel := "${THISDIR}/${PN}:"
+
+SRCREV = "8dea5a0000fcf9d1daada0b92811d9f1bf308a9f"
diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh
new file mode 100644
index 000000000..176bfd7ca
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/ldb.sh
@@ -0,0 +1 @@
+export LDB_MODULES_PATH=/usr/lib/ldb
diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups
new file mode 100644
index 000000000..7c189e231
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/locked_groups
@@ -0,0 +1 @@
+sssd_locked
diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf
new file mode 100644
index 000000000..d2ffe5ddc
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/nscd.conf
@@ -0,0 +1,2 @@
+enable-cache passwd no
+enable-cache group no \ No newline at end of file
diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf
new file mode 100644
index 000000000..7a2786bee
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.conf
@@ -0,0 +1,16 @@
+[sssd]
+domains = LOCAL
+services = nss, pam
+config_file_version = 2
+
+[nss]
+enum_cache_timeout = 1
+filter_groups = root
+filter_users = root
+
+[pam]
+
+[domain/LOCAL]
+enumerate = true
+id_provider = local
+auth_provider = local
diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service
new file mode 100644
index 000000000..fe2bcf8b4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/files/sssd.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=System Security Services Daemon
+# SSSD must be running before we permit user sessions
+Before=systemd-user-sessions.service nss-user-lookup.target
+Wants=nss-user-lookup.target
+
+[Service]
+Environment=LDB_MODULES_PATH=/usr/lib/ldb DEBUG_LOGGER=-f
+ExecStart=/usr/sbin/sssd $DEBUG_LOGGER
+Type=simple
+Restart=always
+PIDFile=/var/run/sssd.pid
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend b/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend
new file mode 100644
index 000000000..03965ce72
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-security/sssd/sssd_%.bbappend
@@ -0,0 +1,26 @@
+inherit obmc-phosphor-systemd
+
+FILESEXTRAPATHS_append := "${THISDIR}/files:"
+SRC_URI += "file://sssd.conf \
+ file://nscd.conf \
+ file://locked_groups \
+ file://ldb.sh \
+ "
+
+PACKAGECONFIG += " systemd "
+SYSTEMD_AUTO_ENABLE = "enable"
+
+EXTRA_OECONF += " --enable-pammoddir=${base_libdir}/security"
+
+do_install_append() {
+ # sssd creates also the /var/run link. Need to remove it to avoid conflicts
+ # with the one created by base-files recipe.
+ rm -rf ${D}/var/run
+ install -m 600 ${WORKDIR}/locked_groups ${D}/${sysconfdir}/${BPN}
+ install -m 600 ${WORKDIR}/nscd.conf ${D}/${sysconfdir}
+ install -d ${D}${sysconfdir}/profile.d
+ install -m 0644 ${WORKDIR}/ldb.sh ${D}${sysconfdir}/profile.d
+}
+
+FILES_${PN} += " /lib/security/pam_sss.so "
+
diff --git a/meta-openbmc-mods/meta-common/recipes-support/boost/boost/0001-Fix-Issue-62.patch b/meta-openbmc-mods/meta-common/recipes-support/boost/boost/0001-Fix-Issue-62.patch
new file mode 100644
index 000000000..80dfc2725
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-support/boost/boost/0001-Fix-Issue-62.patch
@@ -0,0 +1,28 @@
+From 318439af2e77731ae2c3df5e198c1d3e8392d556 Mon Sep 17 00:00:00 2001
+From: Simon Ebner <Simon.Ebner@advertima.com>
+Date: Fri, 22 Mar 2019 15:27:35 +0100
+Subject: [PATCH 1/2] Fix Issue 62
+
+Fixes a leaking pipe. See https://github.com/boostorg/process/issues/62
+---
+ boost/process/detail/posix/executor.hpp | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/boost/process/detail/posix/executor.hpp b/boost/process/detail/posix/executor.hpp
+index 1390a58..8b86ed1 100644
+--- a/boost/process/detail/posix/executor.hpp
++++ b/boost/process/detail/posix/executor.hpp
+@@ -282,7 +282,10 @@ class executor
+ set_error(std::error_code(err, std::system_category()), "Error read pipe");
+ }
+ if (count == 0)
++ {
++ ::close(source);
+ return ;
++ }
+
+ std::error_code ec(data[0], std::system_category());
+ std::string msg(data[1], ' ');
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend b/meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend
new file mode 100644
index 000000000..f85e30b1f
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-support/boost/boost_%.bbappend
@@ -0,0 +1,3 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += "file://0001-Fix-Issue-62.patch"
diff --git a/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/default b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/default
new file mode 100644
index 000000000..b9f8e0363
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/default
@@ -0,0 +1 @@
+EXTRA_ARGS="-r /dev/hwrng"
diff --git a/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/init b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/init
new file mode 100644
index 000000000..13f0ecd37
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/init
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# This is an init script for openembedded
+# Copy it to @SYSCONFDIR@/init.d/rng-tools and type
+# > update-rc.d rng-tools defaults 60
+#
+
+rngd=@SBINDIR@/rngd
+test -x "$rngd" || exit 1
+
+[ -r @SYSCONFDIR@/default/rng-tools ] && . "@SYSCONFDIR@/default/rng-tools"
+
+case "$1" in
+ start)
+ echo -n "Starting random number generator daemon"
+ start-stop-daemon -S -q -x $rngd -- $EXTRA_ARGS
+ echo "."
+ ;;
+ stop)
+ echo -n "Stopping random number generator daemon"
+ start-stop-daemon -K -q -n rngd
+ echo "."
+ ;;
+ reload|force-reload)
+ echo -n "Signalling rng daemon restart"
+ start-stop-daemon -K -q -s 1 -x $rngd
+ start-stop-daemon -K -q -s 1 -x $rngd
+ ;;
+ restart)
+ echo -n "Stopping random number generator daemon"
+ start-stop-daemon -K -q -n rngd
+ echo "."
+ echo -n "Starting random number generator daemon"
+ start-stop-daemon -S -q -x $rngd -- $EXTRA_ARGS
+ echo "."
+ ;;
+ *)
+ echo "Usage: @SYSCONFDIR@/init.d/rng-tools {start|stop|reload|restart|force-reload}"
+ exit 1
+esac
+
+exit 0
diff --git a/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/rngd.service b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/rngd.service
new file mode 100644
index 000000000..d76e9a0c4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools/rngd.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Hardware RNG Entropy Gatherer Daemon
+
+[Service]
+EnvironmentFile=-@SYSCONFDIR@/default/rng-tools
+ExecStart=@SBINDIR@/rngd -f $EXTRA_ARGS
+Nice=15
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools_6.7.bb b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools_6.7.bb
new file mode 100644
index 000000000..b4e453f67
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-support/rng-tools/rng-tools_6.7.bb
@@ -0,0 +1,52 @@
+SUMMARY = "Random number generator daemon"
+DESCRIPTION = "Check and feed random data from hardware device to kernel"
+AUTHOR = "Philipp Rumpf, Jeff Garzik <jgarzik@pobox.com>, \
+ Henrique de Moraes Holschuh <hmh@debian.org>"
+HOMEPAGE = "https://github.com/nhorman/rng-tools"
+BUGTRACKER = "https://github.com/nhorman/rng-tools/issues"
+LICENSE = "GPLv2"
+LIC_FILES_CHKSUM = "file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263"
+DEPENDS = "sysfsutils"
+
+SRC_URI = "\
+ git://github.com/nhorman/rng-tools.git \
+ file://init \
+ file://default \
+ file://rngd.service \
+"
+SRCREV = "9fc873c5af0e392632e6b736938b811f7ca97251"
+
+S = "${WORKDIR}/git"
+
+inherit autotools update-rc.d systemd pkgconfig
+
+PACKAGECONFIG ??= "libgcrypt libjitterentropy"
+PACKAGECONFIG_libc-musl = "libargp libjitterentropy"
+
+PACKAGECONFIG[libargp] = "--with-libargp,--without-libargp,argp-standalone,"
+PACKAGECONFIG[libgcrypt] = "--with-libgcrypt,--without-libgcrypt,libgcrypt,"
+PACKAGECONFIG[libjitterentropy] = "--enable-jitterentropy,--disable-jitterentropy,libjitterentropy"
+PACKAGECONFIG[libp11] = "--with-pkcs11,--without-pkcs11,libp11 openssl"
+PACKAGECONFIG[nistbeacon] = "--with-nistbeacon,--without-nistbeacon,curl libxml2 openssl"
+
+INITSCRIPT_NAME = "rng-tools"
+INITSCRIPT_PARAMS = "start 03 2 3 4 5 . stop 30 0 6 1 ."
+
+SYSTEMD_SERVICE_${PN} = "rngd.service"
+
+# Refer autogen.sh in rng-tools
+do_configure_prepend() {
+ cp ${S}/README.md ${S}/README
+}
+
+do_install_append() {
+ install -Dm 0644 ${WORKDIR}/default ${D}${sysconfdir}/default/rng-tools
+ install -Dm 0755 ${WORKDIR}/init ${D}${sysconfdir}/init.d/rng-tools
+ install -Dm 0644 ${WORKDIR}/rngd.service \
+ ${D}${systemd_system_unitdir}/rngd.service
+ sed -i \
+ -e 's,@SYSCONFDIR@,${sysconfdir},g' \
+ -e 's,@SBINDIR@,${sbindir},g' \
+ ${D}${sysconfdir}/init.d/rng-tools \
+ ${D}${systemd_system_unitdir}/rngd.service
+}
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..38609ad5d
--- /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-ast2500.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..955674fa6
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/io-app/files/io-app.c
@@ -0,0 +1,696 @@
+/*
+// 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_AST2600,
+ 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;
+ break;
+ }
+ else if (strncmp("ASpeed SoC", v, 11) == 0)
+ {
+ if (!quiet)
+ fprintf(stderr, "Found ASpeed SoC\n");
+ this_cpu = CPU_AST2500;
+ break;
+ }
+ else if (strncmp("ServerEngines PILOT3", v, 21) == 0)
+ {
+ if (!quiet)
+ fprintf(stderr, "Found PILOT3\n");
+ this_cpu = CPU_PILOT3;
+ break;
+ }
+ }
+ }
+ else if (strncmp("CPU", cpuinfo, 4) == 0)
+ {
+ char *v = strtok_r(NULL, delim, &tmp_s);
+ if (!v || strncmp("part", v, 5) != 0)
+ {
+ continue;
+ }
+ v = strtok_r(NULL, delim, &tmp_s);
+ if (v)
+ {
+ if (strncmp("0xb76", v, 6) == 0)
+ {
+ if (!quiet)
+ fprintf(stderr, "AST2500\n");
+ this_cpu = CPU_AST2500;
+ break;
+ }
+ else if (strncmp("0xc07", v, 6) == 0)
+ {
+ if (!quiet)
+ fprintf(stderr, "AST2600\n");
+ this_cpu = CPU_AST2600;
+ 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";
+ case CPU_AST2600:
+ return "0:20000000,38000000:8000000,60000000:20000000";
+ 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..bc215f60b
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_cmds.c
@@ -0,0 +1,528 @@
+/*
+// 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);
+}
+
+static void SIOGetPFailStatus()
+{
+ 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_PFAIL_STATUS;
+
+ if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0)
+ printf("PFail status : %u\n", sio_data.data);
+
+ close(fd);
+}
+
+static void SIOSetBMCSCIEvent(unsigned short set)
+{
+ 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_BMC_SCI_EVENT;
+ sio_data.param = set;
+
+ if (ioctl(fd, SIO_IOC_COMMAND, &sio_data) == 0)
+ printf("BMC SCI event is %s\n",
+ sio_data.data ? "set" : "cleared");
+
+ 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"
+ "\tlpc_cmds sio get_pfail_status\n"
+ "\tlpc_cmds sio set_bmc_sci_event\n"
+ "\tlpc_cmds sio clear_bmc_sci_event\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(argv[2], "get_pfail_status") == 0)
+ SIOGetPFailStatus();
+ else if (strcmp(argv[2], "set_bmc_sci_event") == 0)
+ SIOSetBMCSCIEvent(1);
+ else if (strcmp(argv[2], "clear_bmc_sci_event") == 0)
+ SIOSetBMCSCIEvent(0);
+ } 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..793e8b49c
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/lpc-cmds/files/lpc_drv.h
@@ -0,0 +1,79 @@
+/*
+// 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_SET_BMC_SCI_EVENT,
+
+ 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..38489263b
--- /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://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658"
+
+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/nbdkit/nbdkit/0001-Force-nbdkit-to-send-PATCH-as-upload-method.patch b/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit/0001-Force-nbdkit-to-send-PATCH-as-upload-method.patch
new file mode 100644
index 000000000..83f015a76
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit/0001-Force-nbdkit-to-send-PATCH-as-upload-method.patch
@@ -0,0 +1,71 @@
+From ad236d3f04cb2547fea33d72aeeb695ce3035bba Mon Sep 17 00:00:00 2001
+From: Iwona Winiarska <iwona.winiarska@intel.com>
+Date: Mon, 9 Dec 2019 01:58:15 +0100
+Subject: [PATCH] Force nbdkit to send PATCH as upload method
+
+This modifies pwrite to send PATCH rather than default upload method
+used by curl.
+
+FIXME: This patch only works around lack of PATCH method support in curl.
+It's just a hack and it should be removed if/when proper PATCH support
+is implemented in curl.
+
+We've added it to nbdkit rather than curl, because currently PATCH
+support is unlikely to be accepted in upstream curl and it is easier to
+maintain this patch in nbdkit.
+
+Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com>
+---
+ plugins/curl/curl.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/plugins/curl/curl.c b/plugins/curl/curl.c
+index 0ed3984..804ad78 100644
+--- a/plugins/curl/curl.c
++++ b/plugins/curl/curl.c
+@@ -525,6 +525,7 @@ static int
+ curl_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset)
+ {
+ struct curl_handle *h = handle;
++ struct curl_slist *list = NULL;
+ CURLcode r;
+ char range[128];
+
+@@ -535,15 +536,21 @@ curl_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset)
+ h->read_count = count;
+
+ curl_easy_setopt (h->c, CURLOPT_UPLOAD, 1);
++ curl_easy_setopt (h->c, CURLOPT_CUSTOMREQUEST, "PATCH");
+
+ /* Make an HTTP range request. */
+- snprintf (range, sizeof range, "%" PRIu64 "-%" PRIu64,
++ snprintf (range, sizeof range, "Range: bytes=%" PRIu64 "-%" PRIu64,
+ offset, offset + count);
+- curl_easy_setopt (h->c, CURLOPT_RANGE, range);
++ list = curl_slist_append(list, range);
++ curl_easy_setopt(h->c, CURLOPT_HTTPHEADER, list);
+
+ /* The assumption here is that curl will look after timeouts. */
+ r = curl_easy_perform (h->c);
+ if (r != CURLE_OK) {
++ curl_easy_setopt (h->c, CURLOPT_RANGE, NULL);
++ curl_easy_setopt(h->c, CURLOPT_HTTPHEADER, NULL);
++ curl_slist_free_all(list);
++ curl_easy_setopt (h->c, CURLOPT_CUSTOMREQUEST, NULL);
+ display_curl_error (h, r, "pwrite: curl_easy_perform");
+ return -1;
+ }
+@@ -554,6 +561,10 @@ curl_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset)
+
+ /* As far as I understand the cURL API, this should never happen. */
+ assert (h->read_count == 0);
++ curl_easy_setopt (h->c, CURLOPT_RANGE, NULL);
++ curl_easy_setopt(h->c, CURLOPT_HTTPHEADER, NULL);
++ curl_slist_free_all(list);
++ curl_easy_setopt (h->c, CURLOPT_CUSTOMREQUEST, NULL);
+
+ return 0;
+ }
+--
+2.21.0
+
diff --git a/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit_git.bb b/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit_git.bb
new file mode 100644
index 000000000..d74c13427
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-utilities/nbdkit/nbdkit_git.bb
@@ -0,0 +1,35 @@
+SUMMARY = "nbdkit is a toolkit for creating NBD servers."
+DESCRIPTION = "NBD — Network Block Device — is a protocol \
+for accessing Block Devices (hard disks and disk-like things) \
+over a Network. \
+\
+nbdkit is a toolkit for creating NBD servers."
+
+HOMEPAGE = "https://github.com/libguestfs/nbdkit"
+LICENSE = "BSD"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=4332a97808994cf2133a65b6c6f33eaf"
+
+SRC_URI = "git://github.com/libguestfs/nbdkit.git;protocol=https"
+SRC_URI += "file://0001-Force-nbdkit-to-send-PATCH-as-upload-method.patch"
+
+PV = "1.17.5+git${SRCPV}"
+SRCREV = "0a76cae407aca6411af3c7db1efafc56dcd151ed"
+
+S = "${WORKDIR}/git"
+
+DEPENDS = "curl xz e2fsprogs zlib"
+
+inherit pkgconfig python3native perlnative pythonnative autotools
+inherit autotools-brokensep
+
+# Specify any options you want to pass to the configure script using EXTRA_OECONF:
+EXTRA_OECONF = "--disable-python --disable-perl --disable-ocaml \
+ --disable-rust --disable-ruby --disable-tcl \
+ --disable-lua --disable-vddk --without-libvirt \
+ --without-libguestfs"
+
+do_install_append() {
+ rm -f ${D}/usr/share/bash-completion/completions/nbdkit
+ rmdir ${D}/usr/share/bash-completion/completions
+ rmdir ${D}/usr/share/bash-completion
+}
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-common/recipes-x86/chassis/x86-power-control_%.bbappend b/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend
new file mode 100755
index 000000000..9323dc003
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-x86/chassis/x86-power-control_%.bbappend
@@ -0,0 +1,3 @@
+# Enable downstream autobump
+SRC_URI = "git://github.com/openbmc/x86-power-control.git;protocol=ssh"
+SRCREV = "fc1ecc59100d21c953501703bc5db9e02e25b333"